/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @attention * *

© Copyright (c) 2021 STMicroelectronics. * All rights reserved.

* * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" #include #include "ethernetif.h" #include "lwip/api.h" #include "lwip/tcpip.h" #include "lwip/ip4_addr.h" #include "snmp_core.h" #include "usbd_cdc_if.h" #include "my_snmp.h" #include "Time.h" #include "lwip.h" #include "AT45DB.h" #include "usart.h" #include "plc.h" #include "ff.h" #include "spi.h" #include "fatfs.h" #include "TFTP.h" #include "api.h" #include "rng.h" #include "log_and_debug.h" #include "sntp.h" #include "temp.h" #include "xml.h" #define ADDR_VERSION 0x080FFFF8 #define START_ADDR_OTP_REG_MAC 0x1FFF7800 #define END_ADDR_OTP_REG_MAC 0x1FFF78FF #define START_ADDR_OTP_REG_SN 0x1FFF7900 #define END_ADDR_OTP_REG_SN 0x1FFF79FF extern ETH_HandleTypeDef heth; extern I2C_HandleTypeDef hi2c1; extern UART_HandleTypeDef huart2; extern struct eth_addr MACAddr; extern plc_common_typeDef plc_common; extern RealTimeClock_typeDef RealTimeClock; network_settings table_network[MAX_IP] = {0}; enum linkState{ LINK_DOWN, LINK_UP } ETH_linkState = LINK_DOWN; enum speedState{ SPEED_10half = 1, SPEED_100half = 2, SPEED_10full = 5, SPEED_100full = 6 }ETH_speedState = SPEED_10half; struct dev { uint8_t num_dev; struct board board[1]; }; struct { struct dev dev; // [0] - 3v device, [1] - 12v device, [2] - 5v device }device_info[3] = {{{0, {{0, "uncknown"}}}}, {{1, {{16, "MC04-PLC"}}}}, {{0, {{0, "uncknown"}}}}}; struct board *curr_device; char *StringCause[5] = {"Unknown", "Watchdog reset", "Software reset", "Hardware reset", "Pin NRST reset"}; uint8_t NumCauseReset; _Bool ClearPassword = 0; BYTE work[_MAX_SS]; uint32_t FW_Version[2] = {0}; uint8_t SN[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; extern FATFS USERFatFS; extern FIL USERFile; extern char USERPath[4]; //char list[1024] = {0}; uint32_t timeTest = 0; xSemaphoreHandle MutexAccessFlash; SemaphoreHandle_t SemaphoreIRQ_PHY, SemaphorePolling; static void vPLCTask(void *param); static void vEthernetTask(void *param); extern void vClockTask(void *param); static void WebServer_task(void *param); void StartDefaultTask(void *argument); extern void MX_FATFS_Init(void); extern void MX_USB_DEVICE_Init(void); void MX_FREERTOS_Init(void); void __logWrite(const char * format, ...); void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ); static StaticTask_t xIdleTaskTCBBuffer; static StackType_t xIdleStack[configMINIMAL_STACK_SIZE]; void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize ) { *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer; *ppxIdleTaskStackBuffer = &xIdleStack[0]; *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; } void HW_init_DWT(void) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; DWT->CYCCNT = 0; } void MX_FREERTOS_Init(void) { wdt_init(2000); MX_USB_DEVICE_Init(); MutexAccessFlash = xSemaphoreCreateMutex(); SemaphoreIRQ_PHY = xSemaphoreCreateBinary(); SemaphorePolling = xSemaphoreCreateBinary(); __debug_init(); xTaskCreate(StartDefaultTask, "defaultTask", 512, NULL, osPriorityNormal, NULL); } /* ######################################################################################### */ /* DEFAULT TASK --------------------------------------------------------------------------- */ void StartDefaultTask(void * argument) { wdt_reset(); HAL_GPIO_WritePin(PHY_LEDy_GPIO_Port, PHY_LEDy_Pin, GPIO_PIN_SET); uint8_t Flash_ID[4] = {0}; FRESULT res; /* вычитываем версию и подверсию платы */ FW_Version[1] = (*(__IO uint32_t*) ADDR_VERSION); FW_Version[0] = (*(__IO uint32_t*) (ADDR_VERSION + 4)); /* вычитываем SN адресс с OTP регистра */ uint8_t CurrSN[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; uint32_t TmpSN, Offset = 0; do{ TmpSN = (*(__IO uint32_t*) (START_ADDR_OTP_REG_SN + Offset)); /* читаем SN с OTP регистра */ CurrSN[5] = TmpSN; CurrSN[4] = TmpSN >> 8; CurrSN[3] = TmpSN >> 16; CurrSN[2] = TmpSN >> 24; TmpSN = (*(__IO uint32_t*) (START_ADDR_OTP_REG_SN + (Offset + 4))); /* читаем SN с OTP регистра */ CurrSN[1] = TmpSN; CurrSN[0] = TmpSN >> 8; if((CurrSN[0] != 0xFF) && (CurrSN[1] != 0xFF) && (CurrSN[2] != 0xFF) && (CurrSN[3] != 0xFF) && (CurrSN[4] != 0xFF) && (CurrSN[5] != 0xFF)) { memcpy(SN, CurrSN, 6); if(END_ADDR_OTP_REG_SN - (START_ADDR_OTP_REG_SN + Offset) >= 6)Offset += 6; else break; } else break; }while(1); osDelay(800); __debug(DEBUG_SERVSE, "\r\n%s\r\nS-port: Firmware v%d.%d, ", StringCause[NumCauseReset], FW_Version[1], FW_Version[0]); if((SN[0] == 0xFF) && (SN[1] == 0xFF) && (SN[2] == 0xFF) && (SN[3] == 0xFF) && (SN[4] == 0xFF) && (SN[5] == 0xFF))__debug(DEBUG_SERVSE, "S-port SN: n/a\r\n"); else __debug(DEBUG_SERVSE, "Serial number: %s\r\n", SN); clock_init(); osDelay(200); MX_SPI3_Init(); HAL_GPIO_WritePin(FL_RES_GPIO_Port, FL_RES_Pin, GPIO_PIN_SET); Flash_Read_ID(Flash_ID); __debug(DEBUG_SERVSE, "Flash device: Manufacturer ID: 0x%02X, Device ID: 0x%02X%02X\r\n", Flash_ID[0], Flash_ID[1], Flash_ID[2]); MX_FATFS_Init(); res = f_mount(&USERFatFS,(TCHAR const*)USERPath, 1); taskENTER_CRITICAL(); if(res == FR_NO_FILESYSTEM){ __debug(DEBUG_SERVSE,"NO Filesystem\r\n"); if(!(ReadStatusFlash() & (1 << 0)))Flash_SetPage512(); res = f_mkfs((TCHAR const*)USERPath, FM_ANY, 0, work, sizeof work); __debug(DEBUG_SERVSE,"f_mkfs result - %d\r\n", res); if(res == FR_OK) f_mount(&USERFatFS,(TCHAR const*)USERPath, 1); } if(res == FR_OK) __debug(DEBUG_SERVSE,"Filesystem: OK\r\n"); else __debug(DEBUG_SERVSE,"f_mount result - %d\r\n", res); taskEXIT_CRITICAL(); __logWrite("%s\n", StringCause[NumCauseReset]); __logWrite("Flash device: Manufacturer ID: 0x%02X, Device ID: 0x%02X%02X\n", Flash_ID[0], Flash_ID[1], Flash_ID[2]); uint8_t execution = ((~EXECUTION_GPIO_Port->IDR >> 3) & 0x07) >> 1; if(execution < 0x04) { uint8_t type = (~VERSION_GPIO_Port->IDR >> 9) & 0x1F; for(uint8_t i = 0; i < device_info[execution].dev.num_dev; i++){ if(type == device_info[execution].dev.board[i].type){ curr_device =& device_info[execution].dev.board[i]; // берем указатель на найденный девайс break; } } } if(curr_device == NULL){ __debug(DEBUG_SERVSE,"Uncknown device\r\n"); __logWrite("Uncknown device\n"); while(1){ wdt_reset(); osDelay(5000); } } __debug(DEBUG_SERVSE,"S-Port SNMP device: %s\r\n", curr_device->Name); __logWrite("S-Port SNMP device: %s\n", curr_device->Name); HW_init_DWT(); RNG_init(); xTaskCreate(vEthernetTask, "EthTask", 2048, NULL, osPriorityNormal, NULL); // priority: above normal temp_sensor_init(); HAL_GPIO_WritePin(PHY_LEDy_GPIO_Port, PHY_LEDy_Pin, GPIO_PIN_RESET); for(;;) { wdt_reset(); // vTaskList(list); //HAL_GPIO_TogglePin(PHY_LEDy_GPIO_Port, PHY_LEDy_Pin); osDelay(500); } } /* ######################################################################################### */ /* ETHERNET TASK --------------------------------------------------------------------------- */ static void vEthernetTask(void *param) { __logWrite("ETH daemon started\n"); uint32_t PHY_ReadData = 0; char ip[17] = {0}, nm[17] = {0}, gw[17] = {0}, ip_ntp[17] = {0}; HAL_GPIO_WritePin(PHY_nRST_GPIO_Port, PHY_nRST_Pin, GPIO_PIN_SET); osDelay(50); /*вычитываем MAC адресс с OTP регистра*/ uint32_t CurrMAC = 0xFFFFFFFF, TmpMAC = 0xFFFFFFFF, offset = 0; do{ CurrMAC = (*(__IO uint32_t*) (START_ADDR_OTP_REG_MAC + offset)) & 0x00FFFFFF; // если тут 000001 - записанный MAC, то проверить следующие три байта, если они FFFFFF, то передыдущий был нужный MAC if(END_ADDR_OTP_REG_MAC - (START_ADDR_OTP_REG_MAC + offset) >= 3)offset += 3; else break; TmpMAC = (*(__IO uint32_t*) (START_ADDR_OTP_REG_MAC + offset)) & 0x00FFFFFF; if(TmpMAC == 0x00FFFFFF){ // значит предыдущие три ячейки это нужный мас MACAddr.addr[3] = CurrMAC >> 16; MACAddr.addr[4] = CurrMAC >> 8; MACAddr.addr[5] = CurrMAC; break; } }while(1); __debug(DEBUG_SERVSE, "S-port MAC: %02X:%02X:%02X:%02X:%02X:%02X\r\n", MACAddr.addr[0], MACAddr.addr[1], MACAddr.addr[2], MACAddr.addr[3], MACAddr.addr[4], MACAddr.addr[5]); if(xml_get_tag("config.xml", "net", NULL, "ip", ip) != XML_OK) memcpy(ip, "192.168.0.254", 13); if(xml_get_tag("config.xml", "net", NULL, "netmask", nm) != XML_OK) memcpy(nm, "255.255.255.0", 13); if(xml_get_tag("config.xml", "net", NULL, "gateway", gw) != XML_OK) memcpy(gw, "192.168.0.1", 11); tcpip_init(NULL, NULL); LWIP_SetNetSettings(&table_network[0], ip, nm, gw); // тут происходит запись в таблицу и в netif MX_LWIP_Init(&table_network[0]); // netif добавляется в netiflist if(curr_device->type == 16){ // если девайс у нас PLC, то поднимаем еще 3 интерфейса в lwip for(int8_t i = MAX_IP - 1; i > 0; i--) { LWIP_SetNetSettings(&table_network[i], "192.168.0.254", "255.255.255.0", "192.168.0.1"); MX_LWIP_Init(&table_network[i]); } } if(HAL_GPIO_ReadPin(RES_IP_GPIO_Port, RES_IP_Pin) == GPIO_PIN_RESET){ LWIP_resetIP(&table_network[0]); // только запись в netif memcpy(table_network[0].ipv4_addr, ip, strlen(ip)); memcpy(table_network[0].ipv4_nm, nm, strlen(nm)); memcpy(table_network[0].ipv4_gw, gw, strlen(gw)); __debug(DEBUG_SERVSE, "Default IP is set\r\nS-port IP:192.168.0.254, mask:255.255.255.0, gw:192.168.0.1\r\n"); __logWrite("Default IP is set\n"); ClearPassword = 1; // выставляем флаг, что очистка пароля } else __debug(DEBUG_SERVSE, "S-port IP:%s, mask:%s, gw:%s\r\n", table_network[0].ipv4_addr, table_network[0].ipv4_nm, table_network[0].ipv4_gw); mac_init(); netif_set_default(&table_network[0].netif); /* считаем link принудительно */ HAL_ETH_ReadPHYRegister(&heth, 0x01, &PHY_ReadData); ETH_linkState = (enum linkState)((PHY_ReadData & (1 << 2)) >> 2); if(ETH_linkState == LINK_UP) netif_set_up(&table_network[0].netif); else netif_set_down(&table_network[0].netif); /* link interrupt enable */ HAL_ETH_WritePHYRegister(&heth, 0x1B, 0x500); xTaskCreate(WebServer_task, "WebServer", 4096, NULL, osPriorityRealtime + 1, NULL); if(xml_get_tag("config.xml", "net", NULL, "ntp", ip_ntp) == XML_OK){ ip_addr_t sntp_addr; ip4addr_aton(ip_ntp, &sntp_addr); sntp_setserver(0, &sntp_addr); sntp_init(); __debug(DEBUG_SERVSE, "NTP server started: ip:%s\r\n", ip_ntp); } else sntp_setserver(0, NULL); tftpServer_init(); // пока что запускаем потом будем делать через консоль if(curr_device->type == 16){ // device PLC SnmpPrepare(PLC); // snmp agent start xTaskCreate(vPLCTask, "PLCTask", 2048, NULL, osPriorityNormal, NULL); //priority: high } else {} // другие девайсы for(;;){ if(xSemaphoreTake(SemaphoreIRQ_PHY, portMAX_DELAY) == pdPASS){ HAL_ETH_ReadPHYRegister(&heth, 0x01, &PHY_ReadData); ETH_linkState = (enum linkState)((PHY_ReadData & (1 << 2)) >> 2); if(ETH_linkState == LINK_UP) { netif_set_up(&table_network[0].netif); __debug(DEBUG_ETH,"ETH LINK UP\r\n"); } else { netif_set_down(&table_network[0].netif); __debug(DEBUG_ETH, "ETH LINK DOWN\r\n"); } HAL_ETH_ReadPHYRegister(&heth, 0x1E, &PHY_ReadData); ETH_speedState = (enum speedState)(PHY_ReadData & 0x07); if((ETH_speedState == SPEED_10full) || (ETH_speedState == SPEED_10half)) HAL_GPIO_WritePin(PHY_LEDy_GPIO_Port, PHY_LEDy_Pin, GPIO_PIN_SET); else HAL_GPIO_WritePin(PHY_LEDy_GPIO_Port, PHY_LEDy_Pin, GPIO_PIN_RESET); HAL_ETH_ReadPHYRegister(&heth, 0x1B, &PHY_ReadData); } vTaskDelay(1); } } /* ----------------------------------------------------------------------------------------- */ /* ######################################################################################### */ /* PLC TIMER POLLING ----------------------------------------------------------------------- */ xQueueHandle QueueCmdTxPLC, QueueCmdRxPLC; extern plc_data_typeDef PLC_Data[AMOUNT_BLOCK_PLC]; void TimerPolling_Callback(void const *argument) { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(SemaphorePolling, &xHigherPriorityTaskWoken); } #define UDP_RECORD_LIVE_TIME 180; // секунд = 3 минуты #define UDP_MAX_RECORDS 3 // максимум три записи в таблице struct table_records_UDP{ unsigned short port; // адрес на который отправлять ip_addr_t addr; // порт на который отправлять uint32_t time; // время когда запись протухнет struct { volatile _Bool valid; }flags; }table_records_UDP[UDP_MAX_RECORDS] = {0}; /* ----------------------------------------------------------------------------------------- */ /* PLC TASK -------------------------------------------------------------------------------- */ static void vPLCTask(void *param) { #define AMOUNT_BOARD_CMD 9 #define MAX_ELEMENTS_TX 16 __debug(DEBUG_SERVSE,"PLC daemon started\r\n"); __logWrite("PLC daemon started\n"); plc_TxData_typeDef PLCTxData = {0}; plc_RxData_typeDef PLCRxData = {0}; QueueCmdTxPLC = xQueueCreate(MAX_ELEMENTS_TX, sizeof(plc_TxData_typeDef)); QueueCmdRxPLC = xQueueCreate(16, sizeof(plc_RxData_typeDef)); osTimerId TimerPolling; osTimerDef(Timer_Polling, TimerPolling_Callback); TimerPolling = osTimerCreate(osTimer(Timer_Polling), osTimerPeriodic, NULL); err_t err; ip_addr_t *addr; volatile _Bool bindUDP = 0, record_find = 0; uint8_t *UDP_PLCData; uint16_t UDP_LenData; uint8_t ID_Unit = 0; unsigned short port; struct netbuf *nbufRX, *nbufTX; struct netconn *connUDP; plc_buff_typeDef buffUDP_send = {0}; struct { uint8_t shift; uint8_t mask; uint8_t byte; _Bool isID : 1; _Bool end : 1; _Bool add : 1; _Bool nextID : 1; _Bool noCopy : 1; }UDP_flag; volatile uint16_t sBuffCnt = 0; char sBuffer[2048] = {0}; char ip[16] = {0}, nm[16] = {0}, gw[16] = {0}, str_xml[25] = {0}; uint8_t cntByte = 0; plc_data_typeDef *PointPLCData =& PLC_Data[0]; uint32_t TimerCounter = 0; uint8_t board = 0; const uint8_t Kosh_sigMass[10] = {10, 13, 16, 20, 25, 32, 40, 50, 63, 79}; // 10^0.0, 10^0.1 и тд. умноженное на 10 struct { _Bool all_en; const uint16_t BoardCmd[AMOUNT_BOARD_CMD]; // в старшем байте адрес платы, младший байт команда uint8_t CurrentIndexBlock; uint8_t CurrentIndexUM; struct { _Bool En; uint8_t PointBoardCmd; // по колл-ву блоков(у каждого блока свой указатель на команду которую передаем) uint32_t NewTime; uint8_t Timeout; uint8_t RequestCnt; // счетчик запросов, когда блок отвечает, то его сбрасываем uint8_t Alarm; _Bool Presece; _Bool FirstRequest; struct { _Bool Presence; uint8_t RequestCnt; // счетчик для перезапроса отстутсвующей платы УМ }UM[2]; }Block[AMOUNT_BLOCK_PLC]; }Common = {0, {0x0401, 0x0411, 0x0412, 0x0413, 0x0415, 0x0416, 0x0417, 0x0A01, 0x0C01}, 0x00, 0xFF, {{0, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 1, {{1, 0x00},{1, 0x00}}}, {0, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 1, {{1, 0x00},{1, 0x00}}}, {0, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 1, {{1, 0x00},{1, 0x00}}}, {0, 0x00, 0x00, 0x00, 0x00, 0x00, 0, 1, {{1, 0x00},{1, 0x00}}}}}; sprintf(PLC_Data[0].NameBlock, ""); sprintf(PLC_Data[1].NameBlock, ""); sprintf(PLC_Data[2].NameBlock, ""); sprintf(PLC_Data[3].NameBlock, ""); if(xml_get_attr("config.xml", "blocks", NULL, "num", str_xml) == XML_OK) plc_common.num = atoi(str_xml); else plc_common.num = 1; PLC_Data[1].PollingTimeout = 5; PLC_Data[2].PollingTimeout = 5; PLC_Data[3].PollingTimeout = 5; for(uint8_t i = 0; i < plc_common.num; i++){ PLC_Data[i].EnablePoll = 1; sprintf(sBuffer, (const char*)"id=\"%d\"", i); if(xml_get_attr("config.xml", "block", sBuffer, "name", str_xml) == XML_OK) memcpy(PLC_Data[i].NameBlock, str_xml, strlen(str_xml)); else sprintf(PLC_Data[i].NameBlock, ""); if(xml_get_tag("config.xml", "block", sBuffer, "poll", str_xml) == XML_OK)PLC_Data[i].PollingTimeout = atoi(str_xml); else PLC_Data[i].PollingTimeout = (i == 0) ? 3 : 5; if(xml_get_tag("config.xml", "block", sBuffer, "filter", str_xml) == XML_OK){ PLC_Data[i].Type_Filter = (TypeFilter_typeDef)atoi(&str_xml[0]); PLC_Data[i].FilterATT = (FilterATT_typeDef)atoi(&str_xml[2]); } if(i > 0){ if(xml_get_tag("config.xml", "block", sBuffer, "route", str_xml) == XML_OK) for(uint8_t q = 0; q < sizeof(PLC_Data[i].Route); q++)PLC_Data[i].Route[q] = atoi(&str_xml[q * 2]); else for(uint8_t q = 0; q < sizeof(PLC_Data[i].Route); q++)PLC_Data[i].Route[q] = 0x00; if(xml_get_tag("config.xml", "block", sBuffer, "ip", ip) != XML_OK) sprintf(ip, ""); if(xml_get_tag("config.xml", "block", sBuffer, "netmask", nm) != XML_OK) sprintf(nm, ""); if(xml_get_tag("config.xml", "block", sBuffer, "gateway", gw) != XML_OK) sprintf(gw, ""); LWIP_SetNetSettings(&table_network[i], ip, nm, gw); netif_set_up(&table_network[i].netif); } } MX_USART2_UART_Init(); connUDP = netconn_new(NETCONN_UDP); if (connUDP!= NULL){ err = netconn_bind(connUDP, IP_ADDR_ANY, 12348); if (err == ERR_OK) { bindUDP = 1; netconn_set_recvtimeout(connUDP, 10); } else netconn_delete(connUDP); } osTimerStart(TimerPolling, 1000); // каждую секунду срабатывает таймер for(;;){ if((!Common.all_en) && (plc_common.enable_all_pool)){ __debug(DEBUG_SERVSE, "Block polling disabled\r\n"); osTimerStop(TimerPolling); xQueueReset(QueueCmdTxPLC); Common.all_en = 1; } else if((Common.all_en) && (!plc_common.enable_all_pool)){ __debug(DEBUG_SERVSE, "Block polling enabled\r\n"); osTimerStart(TimerPolling, 1000); Common.all_en = 0; } for(uint8_t i = 0; i < UDP_MAX_RECORDS; i++){/*смотрим протухла ли таблица*/ if(table_records_UDP[i].flags.valid){ if(TimerCounter >= table_records_UDP[i].time) table_records_UDP[i].flags.valid = 0; // запись протухла } } if(bindUDP) { // если UDP сервер забиндился err = netconn_recv(connUDP, &nbufRX); if (err == ERR_OK){ // пришли данные с UDP порта addr = netbuf_fromaddr(nbufRX); port = netbuf_fromport(nbufRX); for(uint8_t i = 0; i < UDP_MAX_RECORDS; i++){ //ищем запись if(table_records_UDP[i].flags.valid){ if((table_records_UDP[i].addr.addr == addr->addr) && (table_records_UDP[i].port == port)) { table_records_UDP[i].time = TimerCounter + UDP_RECORD_LIVE_TIME; record_find = 1; break; } } } if(!record_find){ // если такой записи нет, то добавляем ее for(uint8_t i = 0; i < UDP_MAX_RECORDS; i++){ if(!table_records_UDP[i].flags.valid){ // ищем свободное место под запись table_records_UDP[i].addr.addr = addr->addr; table_records_UDP[i].port = port; table_records_UDP[i].flags.valid = 1; // занимаем запись table_records_UDP[i].time = TimerCounter + UDP_RECORD_LIVE_TIME; break; } } } else record_find = 0; netbuf_data(nbufRX, (void**)&UDP_PLCData, &UDP_LenData); PLCTxData.LenBuff = 0; PLCTxData.Pointer = 0x01; // увеличиваем указатель PLCTxData.Buff[PLCTxData.LenBuff++] = (PLC_ADDR_BOARD << 4) & 0xF0; // пишем свой адрес UDP_LenData--; // вычитаем первый байт, это указатель для нас он безполезен if(UDP_PLCData[1] == 0x0F){// это широковещательное сообщение для ближнего блока формируем 0x0E 0xF0 0x00 PLCTxData.Buff[PLCTxData.LenBuff++] = 0xF0; PLCTxData.Buff[PLCTxData.LenBuff++] = 0x00; } else { if(((UDP_PLCData[1] & 0x0F) > 1) && ((UDP_PLCData[1] & 0x0F) < 0x0F)) { // тут всегда будет ID блока ID_Unit = UDP_PLCData[1] & 0x0F;// запоминием наш ID для ответа if((UDP_PLCData[1] & 0xF0) == 0x00){ PLCTxData.Buff[PLCTxData.LenBuff++] = (ID_Unit << 4); PLCTxData.Buff[PLCTxData.LenBuff++] = 0x00; if(UDP_LenData > 0x02) { UDP_LenData--; memcpy(&PLCTxData.Buff[PLCTxData.LenBuff], &UDP_PLCData[2], UDP_LenData - 1); PLCTxData.LenBuff += (UDP_LenData - 1); } } else if(((UDP_PLCData[1] & 0xF0) >> 4) >= 4){ // тут может быть и плата и канал PLCTxData.Buff[PLCTxData.LenBuff++] = ((UDP_PLCData[1] & 0xF0) >> 4); // это плата ближнего блока UDP_LenData--; // вычитаем второй байт так как мы его развернули memcpy(&PLCTxData.Buff[PLCTxData.LenBuff], &UDP_PLCData[PLCTxData.LenBuff], UDP_LenData - 1); //копируем на один байт меньше так как там контрольная сумма PLCTxData.LenBuff += (UDP_LenData - 1); } else { // это канал UDP_flag.add = 0; UDP_flag.end = 0; UDP_flag.isID = 0; UDP_flag.nextID = 0; for(uint8_t ptr = 1;; ptr++){ UDP_flag.mask = 0x0F; UDP_flag.shift = 0; for(uint8_t i = 0; i < 2; i++){ // так как две тетрады в байте if((ptr != 0x01) || ((ptr == 0x01) && (i != 0x00))) UDP_flag.byte = (UDP_PLCData[ptr] & UDP_flag.mask) >> UDP_flag.shift; // пропускаем младщую тетраду первого просматриваемого байта else { UDP_flag.mask = 0xF0; UDP_flag.shift = 4; continue; } if(ptr != 0x01){ if(UDP_flag.byte == 0x00) { UDP_flag.nextID = 1; // сообщаем что следующая тетрада это ID if(UDP_flag.isID) UDP_flag.end = 1; // значит конец } else if(UDP_flag.byte >= 0x04) { if(UDP_flag.nextID){ // это ID if(UDP_flag.byte == 0x0F){ if(UDP_flag.shift == 0x00) UDP_flag.add = 1; UDP_flag.noCopy = 1; UDP_flag.end = 1; } else UDP_flag.isID = 1; UDP_flag.nextID = 0; } else UDP_flag.end = 1; } else UDP_flag.isID = 0;// канал } if(i == 0x00) PLCTxData.Buff[PLCTxData.LenBuff++] |= UDP_flag.byte << 4; else PLCTxData.Buff[PLCTxData.LenBuff] = UDP_flag.byte; if(UDP_flag.end) { if(i == 0x01)PLCTxData.LenBuff++; break; } UDP_flag.mask = 0xF0; UDP_flag.shift = 4; } if(UDP_flag.end){ if(UDP_flag.add) PLCTxData.Buff[PLCTxData.LenBuff++] = 0x00; if(!UDP_flag.noCopy){ memcpy(&PLCTxData.Buff[PLCTxData.LenBuff], &UDP_PLCData[ptr + 1], UDP_LenData - ptr - 1); PLCTxData.LenBuff += (UDP_LenData - ptr - 1); } else UDP_flag.noCopy = 0; break; } } } } } if(__debug(DEBUG_PLC_TRANSIT,"********* UDP RX *********\r\n")){ sBuffCnt = 0; sBuffCnt += sprintf(&sBuffer[sBuffCnt], "pointer:%02X\r\ndata [%d]:", PLCTxData.Pointer, PLCTxData.LenBuff); for(uint16_t i = 0; i < PLCTxData.LenBuff; i++)sBuffCnt += sprintf(&sBuffer[sBuffCnt], "%02X", PLCTxData.Buff[i]); __debug(DEBUG_PLC_TRANSIT,"%s\r\n***************************************\r\n", sBuffer); } xQueueSend(QueueCmdTxPLC, &PLCTxData, portMAX_DELAY); netbuf_delete(nbufRX); } } /******************************** РЕЖИМ РАБОТЫ "ОПРОС БЛОКОВ" ******************************/ if(plc_common.change_block > 0){ uint8_t up = 0; up = plc_common.num - plc_common.change_block; if(up != 0) { for(uint8_t i = 0; i < up; i++){ memcpy(&Common.Block[plc_common.change_block], &Common.Block[plc_common.change_block + 1], sizeof(Common.Block[plc_common.change_block + 1])); plc_common.change_block++; } } plc_common.change_block = 0; } if(xQueueReceive(QueueCmdRxPLC, &PLCRxData, 0) == pdTRUE){ // получаем данные всегда if(PLCRxData.Valid){ // данные валидные и готовы к дальнейшей обработке if(PLCRxData.Query) __debug(DEBUG_PLC_CROSS,"Request me\r\n"); if(__debug(DEBUG_PLC_CROSS | DEBUG_PLC_TRANSIT,"********* RX CROSS *********\r\n")){ // выводим дебаг sBuffCnt = 0; sBuffCnt += sprintf(&sBuffer[sBuffCnt], "pointer:%02X\r\ndata [%d]:", PLCRxData.Pointer, PLCRxData.LenBuff); for(uint16_t i = 0; i < PLCRxData.LenBuff; i++)sBuffCnt += sprintf(&sBuffer[sBuffCnt], "%02X", PLCRxData.Buff[i]); __debug(DEBUG_PLC_CROSS | DEBUG_PLC_TRANSIT,"%s\r\n***************************************\r\n", sBuffer); } Common.CurrentIndexBlock = 0; if((PLCRxData.Pointer & 0x80) && (PLCRxData.Pointer & 0x01)){ // ответ на запрос (указатель должен быть 1) if((PLCRxData.Buff[0] & 0xF0) == (PLC_ADDR_BOARD << 4)){// команда для меня /*************************** PLC->UDP *************************/ volatile uint8_t offset; uint16_t tmpLenBuff = PLCRxData.LenBuff; uint8_t pointer = 1; buffUDP_send.len = 0; buffUDP_send.data[buffUDP_send.len++] = PLCRxData.Pointer & 0x80; tmpLenBuff--; //вычитаем первый байт так как в нем наша плата if((PLCRxData.Buff[1] & 0x0F) == 0x00) { // ответ ID блока ближнего buffUDP_send.data[buffUDP_send.len++] = ((PLCRxData.Buff[pointer] & 0xF0) >> 4) | ((PLCRxData.Buff[pointer] & 0x0F) << 4); // рвзвернул данные так как ответ ID блока tmpLenBuff -= 2; pointer += 2; } else if((PLCRxData.Buff[1] & 0x0F) >= 0x04){ // тут может быть и плата и канал buffUDP_send.data[buffUDP_send.len++] = ((PLCRxData.Buff[pointer++] & 0x0F) << 4) | ID_Unit;// это ближняя плата tmpLenBuff--; } else { // это канал UDP_flag.add = 0; UDP_flag.end = 0; UDP_flag.isID = 0; UDP_flag.nextID = 0; for(uint8_t ptr = 1;; ptr++){ UDP_flag.mask = 0x0F; UDP_flag.shift = 0; for(uint8_t i = 0; i < 2; i++){ UDP_flag.byte = (PLCRxData.Buff[ptr] & UDP_flag.mask) >> UDP_flag.shift; if((ptr == 1) && (i == 0)) buffUDP_send.data[buffUDP_send.len] = ID_Unit; if(UDP_flag.byte == 0x00) { if(UDP_flag.nextID) UDP_flag.end = 1; if(UDP_flag.isID){ if(UDP_flag.shift == 0x04) UDP_flag.add = 1; UDP_flag.end = 1; } else UDP_flag.nextID = 1; // сообщаем что следующая тетрада это ID } else if(UDP_flag.byte >= 0x04) { if(UDP_flag.nextID){ UDP_flag.isID = 1; UDP_flag.nextID = 0; } else UDP_flag.end = 1; } else UDP_flag.isID = 0;// канал if(i == 0x00) buffUDP_send.data[buffUDP_send.len++] |= UDP_flag.byte << 4; else buffUDP_send.data[buffUDP_send.len] = UDP_flag.byte; if(UDP_flag.end) { if((i == 0x01) && (!UDP_flag.add)) buffUDP_send.len++; break; } UDP_flag.mask = 0xF0; UDP_flag.shift = 4; } if(UDP_flag.end){ if(UDP_flag.add) buffUDP_send.data[buffUDP_send.len++] = 0x00; pointer += ptr; tmpLenBuff -= ptr; break; } } } memcpy(&buffUDP_send.data[buffUDP_send.len], &PLCRxData.Buff[pointer], tmpLenBuff); buffUDP_send.len += tmpLenBuff; buffUDP_send.data[buffUDP_send.len++] = ~((uint8_t)plc_calc_cs(buffUDP_send.data, buffUDP_send.len));// данные в UDP for(uint8_t i = 0; i < UDP_MAX_RECORDS; i++){ if(table_records_UDP[i].flags.valid){ // есть валидная запись, то отправляем netconn_connect(connUDP, &table_records_UDP[i].addr, table_records_UDP[i].port); nbufTX = netbuf_new(); if(nbufTX != NULL){ netbuf_alloc(nbufTX, buffUDP_send.len); pbuf_take(nbufTX->p, (void *) &buffUDP_send.data, buffUDP_send.len); netconn_send(connUDP, nbufTX); netbuf_free(nbufTX); netbuf_delete(nbufTX); netconn_disconnect(connUDP); } } } /*****************************************************/ /*********** обработка моих пакетов из PLC ***********/ PointPLCData = NULL; PLCRxData.LenBuff -= 1; // вычтем первый байт, так как там лежит 0xE0 if((PLCRxData.Buff[1] & 0x0F) >= 0x04) {// значит это плата и это ближний блок board = PLCRxData.Buff[1] & 0x0F; PLCRxData.LenBuff -= 1; // вычитаем байт платы offset = 2; PointPLCData =& PLC_Data[0]; // берем указатель ближнего блока } else{ // это при приходит от дальнего блока for(Common.CurrentIndexBlock = 1; /*(offset <= cntByte) || */(Common.CurrentIndexBlock < AMOUNT_BLOCK_PLC); ){ if(PLC_Data[Common.CurrentIndexBlock].Route[0] > 0){ cntByte = (PLC_Data[Common.CurrentIndexBlock].Route[0] + 1) / 2; // вычисляем сколько байт if((PLC_Data[Common.CurrentIndexBlock].Route[0] % 2) == 0){ // если четное коллво ниблов board = (PLCRxData.Buff[cntByte + 1] & 0x0F); if(board < 4){ Common.CurrentIndexBlock++; continue;} if(memcmp(&PLCRxData.Buff[1], &PLC_Data[Common.CurrentIndexBlock].Route[1], cntByte) == 0x00){ PLCRxData.LenBuff = PLCRxData.LenBuff - cntByte - 1; offset = cntByte + 2; PointPLCData =& PLC_Data[Common.CurrentIndexBlock]; break; } Common.CurrentIndexBlock++; } else { // если коллво ниблов нечетное board = (PLCRxData.Buff[cntByte] & 0xF0) >> 4; if(board < 4){ Common.CurrentIndexBlock++; continue;} uint8_t tmp = PLCRxData.Buff[cntByte]; PLCRxData.Buff[cntByte] &= 0x0F; // тут не надо убирать адресс платы if(memcmp(&PLCRxData.Buff[1], &PLC_Data[Common.CurrentIndexBlock].Route[1], cntByte) == 0x00){ PLCRxData.LenBuff -= cntByte; offset = cntByte + 1; PointPLCData =& PLC_Data[Common.CurrentIndexBlock]; break; } PLCRxData.Buff[cntByte] = tmp; Common.CurrentIndexBlock++; } } else Common.CurrentIndexBlock++; } } // есть указатель, то значит можно обрабатывать ответ if(PointPLCData != NULL) { memmove(&PLCRxData.Buff[0], &PLCRxData.Buff[offset], PLCRxData.LenBuff); if(board == 0x04){ // ответ от MD uint8_t ch; Common.Block[Common.CurrentIndexBlock].Presece = 1;// выставляем флаг что блок ответил Common.Block[Common.CurrentIndexBlock].RequestCnt = 0; // сбрасываем счетчик запросов if(PLCRxData.Buff[0] == 0x01) { sprintf(PointPLCData->Version, "%d", PLCRxData.Buff[1]); PointPLCData->VersionMD = atoi(PointPLCData->Version); Common.Block[Common.CurrentIndexBlock].FirstRequest = 0; } else if((PLCRxData.Buff[0] == 0x11) || (PLCRxData.Buff[0] == 0x12) || (PLCRxData.Buff[0] == 0x13)){ ch = (PLCRxData.Buff[0] & (0x0F)) - 1; PointPLCData->HF_Channel[ch].En = (PLCRxData.Buff[2] & 0x80); if(PointPLCData->HF_Channel[ch].En){ PointPLCData->HF_Channel[ch].Frequency_Transmitter = PLCRxData.Buff[1] | ((PLCRxData.Buff[2] & 0x03) << 8); PointPLCData->HF_Channel[ch].Frequency_Receiver = PLCRxData.Buff[3] | ((PLCRxData.Buff[4] & 0x03) << 8); PointPLCData->HF_Channel[ch].Mode = (ModeChannel_typeDef)((PLCRxData.Buff[5] & 0xC0) >> 6); } } else if((PLCRxData.Buff[0] == 0x15) || (PLCRxData.Buff[0] == 0x16) || (PLCRxData.Buff[0] == 0x17)){ ch = (PLCRxData.Buff[0] & (0x0F)) - 5; if(PointPLCData->HF_Channel[ch].En){ if(PLCRxData.Buff[1] & 0xE0){ if((PLCRxData.Buff[1] & 0x60) == 0x60) PointPLCData->HF_Channel[ch].Status_Receiver = RECEIVING; else if(PLCRxData.Buff[1] & 0x40) PointPLCData->HF_Channel[ch].Status_Receiver = ACTIVATION; else if(PLCRxData.Buff[1] & 0x80)PointPLCData->HF_Channel[ch].Status_Receiver = OVERLOAD; } else PointPLCData->HF_Channel[ch].Status_Receiver = NO_SIGNAL; if(PLCRxData.LenBuff >= 9) { // если цифровой режим работы if(PLCRxData.Buff[3] > 128)PointPLCData->HF_Channel[ch].Rate_Transmitter = ((PLCRxData.Buff[3] - 128) * 2) + 128; // rate 12.7kB/s -> 127 // *0.2 else PointPLCData->HF_Channel[ch].Rate_Transmitter = PLCRxData.Buff[3] * 1; // *0.1 // передаем число умноженное на 10 if(PLCRxData.Buff[4] > 128)PointPLCData->HF_Channel[ch].Rate_Receiver = ((PLCRxData.Buff[4] - 128) * 2) + 128; // rate 12.7kB/s -> 127 // *0.2 else PointPLCData->HF_Channel[ch].Rate_Receiver = PLCRxData.Buff[4] * 1; // *0.1 // передаем число умноженное на 10 PointPLCData->HF_Channel[ch].QualityNoise_Receiver = PLCRxData.Buff[5] * 10 / 8; // передаем число умноженное на 10 if(PointPLCData->HF_Channel[ch].QualityNoise_Receiver > 0)PointPLCData->HF_Channel[ch].SNR_Receiver = PointPLCData->HF_Channel[ch].Rate_Receiver + PointPLCData->HF_Channel[ch].QualityNoise_Receiver - 20; // передаем число умноженное на 10 else PointPLCData->HF_Channel[ch].SNR_Receiver = 0; PointPLCData->HF_Channel[ch].CounterError = (PLCRxData.Buff[7] << 8) | PLCRxData.Buff[6]; PLCRxData.Buff[8] &= ~(1 << 7); // кОш обнуляем 7 бит, так как он недействительный PointPLCData->HF_Channel[ch].Kosh_raw = PLCRxData.Buff[8]; uint8_t k = (PLCRxData.Buff[8] / 10) + 1; // это будет степень, без минуса uint8_t i = 10 - (PLCRxData.Buff[8] % 10); // (0,2) 2 ->10-2=8 -> надо получить 10^0.8 if(i == 10){ i = 0; k -= 1; } uint8_t tmp = Kosh_sigMass[i] * 3; if((tmp / 100) != 0){ tmp /= 10; k -= 1; } PointPLCData->HF_Channel[ch].Kosh_sig = tmp;// * 3; // умножаем на 3 так как ошибки не битовые а символьные, примерно ода символьная ошибка это 3 битовых PointPLCData->HF_Channel[ch].Kosh_exp = k * (-1); } else { PointPLCData->HF_Channel[ch].QualityNoise_Receiver = 0; PointPLCData->HF_Channel[ch].Rate_Transmitter = 0; PointPLCData->HF_Channel[ch].Rate_Receiver = 0; PointPLCData->HF_Channel[ch].SNR_Receiver = 0; PointPLCData->HF_Channel[ch].Kosh_sig = 0; PointPLCData->HF_Channel[ch].Kosh_exp = 0; } PointPLCData->HF_Channel[ch].Level_InputSignal = PLCRxData.Buff[2] * (-2); // передаем число умноженное на 10 отрицательное число if(PointPLCData->Power_PRD != P_NONE){ float tmp = (PLCRxData.Buff[2] * -0.2) + (0.007 * PointPLCData->HF_Channel[ch].Frequency_Receiver) + 9 + (2 * (PointPLCData->Power_PRD - 1)) + (2 * PointPLCData->Type_Filter) + (PointPLCData->FilterATT * 6); PointPLCData->HF_Channel[ch].Level_Receiver = (int16_t)(tmp * 10); // передаем число умноженное на 10 отрицательное число } else PointPLCData->HF_Channel[ch].Level_Receiver = 0; if(PointPLCData->HF_Channel[ch].Status_Receiver != RECEIVING) Common.Block[Common.CurrentIndexBlock].Alarm |= (1 << ch); else Common.Block[Common.CurrentIndexBlock].Alarm &= ~(1 << ch); } else Common.Block[Common.CurrentIndexBlock].Alarm &= ~(1 << ch); } }// end ответ от MD else { // ответ от любой платы Common.CurrentIndexUM = 0xFF; if(board == 0x0A) Common.CurrentIndexUM = 0;// ответ от UM02 первая плата else if(board == 0X0C) Common.CurrentIndexUM = 1;// ответ от UM02 вторая плата if(Common.CurrentIndexUM != 0xFF){ if(PLCRxData.Buff[0] == 0x01){ PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Version = PLCRxData.Buff[1]; if(PLCRxData.Buff[2] & 0x1E){ if(PLCRxData.Buff[2] & 0x02) PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Alarm = LINE_BREAK; else if(PLCRxData.Buff[2] & 0x04) PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Alarm = FAILURE_PRD; else if(PLCRxData.Buff[2] & 0x08) PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Alarm = NO_SIGNAL_PWR_AMP; else if(PLCRxData.Buff[2] & 0x16) PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Alarm = HIGH_TEMPERATURE; Common.Block[Common.CurrentIndexBlock].Alarm |= (1 << (Common.CurrentIndexUM + 4)); } else { PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Alarm = NO_ALARM; Common.Block[Common.CurrentIndexBlock].Alarm &= ~(1 << (Common.CurrentIndexUM + 4)); } PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Level_Transmitter = PLCRxData.Buff[3]; PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Temp = PLCRxData.Buff[4]; if(PLCRxData.LenBuff == 7)PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Voltage = PLCRxData.Buff[6]; else PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Voltage = 0x00; PointPLCData->PowerAmplifier[Common.CurrentIndexUM].Presence = 1; Common.Block[Common.CurrentIndexBlock].UM[Common.CurrentIndexUM].Presence = 1; // выставляем флаг что UM ответил Common.Block[Common.CurrentIndexBlock].UM[Common.CurrentIndexUM].RequestCnt = 0; } } if((PointPLCData->PowerAmplifier[0].Presence) && (PointPLCData->PowerAmplifier[1].Presence)) PointPLCData->Power_PRD = P_40W; else if((PointPLCData->PowerAmplifier[0].Presence) || (PointPLCData->PowerAmplifier[1].Presence)) PointPLCData->Power_PRD = P_20W; else PointPLCData->Power_PRD = P_NONE; } } } // end cmd для меня } else if(PLCRxData.Query){ // был запрос данных у нас(если нужно) __debug(DEBUG_SERVSE, "my pack\r\n"); my_cmd_plc(&PLCRxData, &PLCTxData); } } } /* коммон аларм обновляем всегда*/ for(uint8_t i = 0; i < AMOUNT_BLOCK_PLC; i++){ if(PLC_Data[i].EnablePoll){ if(PLC_Data[i].ChangeSettings){ // если было изменение настроек маршрута, говорим что блок отсутствует Common.Block[i].Presece = 0; Common.Block[i].FirstRequest = 1; // скидываем для отправки только первой команды Common.Block[i].RequestCnt = 0; PLC_Data[i].ChangeSettings = 0; } if(Common.Block[i].Presece){ if(Common.Block[i].Alarm) PLC_Data[i].CommonAlarm = 2; else PLC_Data[i].CommonAlarm = 0; } else { PLC_Data[i].CommonAlarm = 1;// блок отсутствует PLC_Data[i].VersionMD = 0; for(uint8_t q = 0; q < 3; q++)PLC_Data[i].HF_Channel[q].En = 0; // фиксируем что канал выключен for(uint8_t q = 0; q < 2; q++)PLC_Data[i].PowerAmplifier[q].Presence = 0; // фиксируем что УМ отсутствует } } } /************************ Формирование команд и отправка в блоки *******************************/ if(xSemaphoreTake(SemaphorePolling, 0) == pdTRUE){ // семафор для подготовки данных для отправки uint8_t indexPoll = 0; for(uint8_t i = 0; i < AMOUNT_BLOCK_PLC; i++){ // проходим по все 4 блокам if((Common.Block[i].NewTime == TimerCounter) || ((Common.Block[i].En != PLC_Data[i].EnablePoll) && (PLC_Data[i].EnablePoll))){ // пришло время опроса или если добавили блок для опроса if(PLC_Data[i].EnablePoll) {// у всех блоков смотрим этот параметр if(i != 0x00){ if(Common.Block[i].PointBoardCmd == 0x00) Common.Block[i].Timeout = 1; //выставляем время между командами 1 сек, так как мы начинаем новый цикл опросов дальних блоков } else Common.Block[i].Timeout = PLC_Data[i].PollingTimeout; if((PLC_Data[i].Route[0] > 0) || (i == 0)) indexPoll |= (1 << i); } // else Common.Block[i].Timeout = PLC_Data[i].PollingTimeout; // если нам запрещено опрашивать какой то дальний блок, то каждые n секунд проверяем флаг enable poll Common.Block[i].NewTime = TimerCounter + Common.Block[i].Timeout; // вычисляем время следующего опроса } Common.Block[i].En = PLC_Data[i].EnablePoll; } for(uint8_t i = 0; (indexPoll != 0) || (i < AMOUNT_BLOCK_PLC);){ if(indexPoll & (1 << i)){ // есть флаг для передачи _Bool Send = 0; uint8_t routeByte = 0; PLCTxData.Pointer = 0x01; PLCTxData.LenBuff = 0; if((!Common.Block[i].FirstRequest) && (Common.Block[i].PointBoardCmd == 0x00)) Common.Block[i].PointBoardCmd++; // пропускаем первую команду, так как версию запрашивать не нужно if((uint8_t)(Common.BoardCmd[Common.Block[i].PointBoardCmd] >> 8) == 0x0A) Common.CurrentIndexUM = 0;// первый УМ02 else if((uint8_t)(Common.BoardCmd[Common.Block[i].PointBoardCmd] >> 8) == 0x0C) Common.CurrentIndexUM = 1;// второй УМ02 else Common.CurrentIndexUM = 0xFF; PLCTxData.Buff[PLCTxData.LenBuff++] = (PLC_ADDR_BOARD << 4); if(i != 0){ routeByte = (PLC_Data[i].Route[0] + 1) / 2; // вычисляем с какого байта берем данные memcpy(&PLCTxData.Buff[PLCTxData.LenBuff], &PLC_Data[i].Route[1], routeByte); PLCTxData.LenBuff += routeByte; if((PLC_Data[i].Route[0] % 2) == 0) PLCTxData.Buff[PLCTxData.LenBuff++] = (uint8_t)(Common.BoardCmd[Common.Block[i].PointBoardCmd] >> 8);// четное, поставляем в младшую else PLCTxData.Buff[routeByte] |= (uint8_t)((Common.BoardCmd[Common.Block[i].PointBoardCmd] >> 8) << 4); } else PLCTxData.Buff[PLCTxData.LenBuff++] = (uint8_t)(Common.BoardCmd[Common.Block[i].PointBoardCmd] >> 8); PLCTxData.Buff[PLCTxData.LenBuff++] = (uint8_t)Common.BoardCmd[Common.Block[i].PointBoardCmd++]; if(Common.CurrentIndexUM != 0xFF){ // передача команды ум 02 if(Common.Block[i].UM[Common.CurrentIndexUM].Presence){ // ум присутствует if(Common.Block[i].UM[Common.CurrentIndexUM].RequestCnt++ == 10){ //__debug(DEBUG_SERVSE, "block %d, UM no answer\r\n", i); PLC_Data[i].PowerAmplifier[Common.CurrentIndexUM].Presence = 0; // тут мы фиксируем что УМ отсутствует PLC_Data[i].PowerAmplifier[Common.CurrentIndexUM].Level_Transmitter = 0; PLC_Data[i].PowerAmplifier[Common.CurrentIndexUM].Temp = 0; PLC_Data[i].PowerAmplifier[Common.CurrentIndexUM].Voltage = 0; Common.Block[i].UM[Common.CurrentIndexUM].Presence = 0; Common.Block[i].UM[Common.CurrentIndexUM].RequestCnt = 0; } else if(Common.Block[i].UM[Common.CurrentIndexUM].RequestCnt == 1) Send = 1; // отправить нужно один раз!!! зачем????? } else{ // ум отсутствует if(Common.Block[i].UM[Common.CurrentIndexUM].RequestCnt++ == 10){ // сделать бы адаптивно зависящее от времени поллинга //__debug(DEBUG_SERVSE, "block %d, UM re-request\r\n", i); Common.Block[i].UM[Common.CurrentIndexUM].Presence = 1; Common.Block[i].UM[Common.CurrentIndexUM].RequestCnt = 0; Send = 1; } } } else Send = 1; // ето не UM отправляем полюбому if(Send) { if(__debug(DEBUG_PLC_CROSS,"********* TX CROSS *********\r\n")){ // выводим дебаг sBuffCnt = 0; sBuffCnt += sprintf(&sBuffer[sBuffCnt], "pointer:%02X\r\ndata [%d]:", PLCTxData.Pointer, PLCTxData.LenBuff); for(uint16_t i = 0; i < PLCTxData.LenBuff; i++)sBuffCnt += sprintf(&sBuffer[sBuffCnt],"%02X", PLCTxData.Buff[i]); __debug(DEBUG_PLC_CROSS,"%s\r\n***************************************\r\n", sBuffer); } if(uxQueueMessagesWaiting(QueueCmdTxPLC) == MAX_ELEMENTS_TX){ // если очередь полная на передачу!! if(xQueueSend(QueueCmdTxPLC, &PLCTxData, 3000) == errQUEUE_FULL) xQueueReset(QueueCmdTxPLC);// если через 3 сек очередь не опустела то сбрасываем ее сами } else xQueueSend(QueueCmdTxPLC, &PLCTxData, portMAX_DELAY); } if(Common.Block[i].PointBoardCmd >= AMOUNT_BOARD_CMD) { // значит было 9 или больше и этим самым мы понимаем что отправили все Common.Block[i].PointBoardCmd = 0; if(Common.Block[i].RequestCnt++ == 5){ // было отправлено 5 запросов, но без ответа Common.Block[i].Presece = 0; // сообщаем что блок отсутствует Common.Block[i].FirstRequest = 1; // скидываем для отправки только первой команды Common.Block[i].RequestCnt = 0; Common.Block[i].UM[0].Presence = 1; // для следующих запросов Common.Block[i].UM[0].RequestCnt = 0; Common.Block[i].UM[1].Presence = 1; // для следующих запросов Common.Block[i].UM[1].RequestCnt = 0; } if(i != 0x00) Common.Block[i].NewTime = TimerCounter + PLC_Data[i].PollingTimeout;// если передача дальних блоков и передали все, то ждем установленный timeout; indexPoll &= ~(1 << i); i++; } else { if(Common.Block[i].FirstRequest){ // если блоки еще не отвечали Common.Block[i].PointBoardCmd = 0; if(i == 0x00) Common.Block[i].NewTime = TimerCounter + 10;// ближний блок else Common.Block[i].NewTime = TimerCounter + 30; indexPoll &= ~(1 << i); i++; } else if((i != 0x00) && (Send)){ // дальний блок, и передали не все indexPoll &= ~(1 << i); i++; } } Send = 0; } else i++; } TimerCounter++; } /*********************************************************************************************************/ osDelay(1); } } /* ----------------------------------------------------------------------------------------- */ /* ######################################################################################### */ void GetContentType(char *FileName, char *ContentType); int32_t substr_len(char *str, char symbol, char addSymbol); /* WEB SERVER TASK ------------------------------------------------------------------------- */ #include "cookie.h" static void WebServer_task(void *param) { __logWrite("HTTP daemon started\n"); enum { STATE_WAIT_ETH_TASK, STATE_CONNECT_NEW, STATE_BIND, STATE_LISTEN }FSM_State = STATE_WAIT_ETH_TASK; struct netbuf *nbuf; ip_addr_t remote_addr; uint16_t remoute_port; uint16_t TCPlenData = 0; char *TCPdata = NULL; volatile _Bool notFountPage = 0, noMemory = 0; uint16_t LenContent = 0; uint16_t cnt_timeout = 0; //ip_addr_t *addr; /**************/ char ContentType[32], CodeResponse[16], HeaderHTTP[1024]; char *FileNameHTTP = NULL; uint8_t *FileHTTP; uint32_t FileSizeHTTP; FIL FSFileHTTP; // DIR dirFAT; /**************/ request_typDef request = {0}; char *Cookie = NULL;/* ищем куки в хедере */ char *str = NULL; char response_json[512] = {0}, response_cookie[512] = {0}; char *JSON_Request = NULL; struct netconn *serv_conn, *conn; err_t conn_err; for(;;) { switch(FSM_State){ case STATE_WAIT_ETH_TASK: if(ETH_linkState == LINK_UP) FSM_State = STATE_CONNECT_NEW; vTaskDelay(1); break; case STATE_CONNECT_NEW: serv_conn = netconn_new(NETCONN_TCP); if(serv_conn != NULL) FSM_State = STATE_BIND; vTaskDelay(1); break; case STATE_BIND: conn_err = netconn_bind(serv_conn, IP_ADDR_ANY, 80); if(conn_err == ERR_OK) { netconn_listen(serv_conn); __debug(DEBUG_WEB_SERVER, "Web server listen port 80\r\n"); FSM_State = STATE_LISTEN; } vTaskDelay(1); break; case STATE_LISTEN: conn_err = netconn_accept(serv_conn, &conn); if(conn_err == ERR_OK){ wdt_reset(); __debug(DEBUG_WEB_SERVER, "Connection\r\n"); TCPlenData = 0; FileSizeHTTP = 0; notFountPage = 0; noMemory = 0; LenContent = 0; request.cookie->len = 0; request.cookie->tokenCount = 0; request.json_len = 0; netconn_set_recvtimeout(conn, 200); conn_err = netconn_recv(conn, &nbuf); if(conn_err == ERR_OK){ wdt_reset(); netconn_getaddr(conn, &remote_addr, &remoute_port, 0); // получаем адресс удаленный netbuf_data(nbuf, (void**)&TCPdata, &TCPlenData); TCPdata[TCPlenData] = 0; if(strncmp(TCPdata, "GET /", 5) == 0){ int16_t lenNameFile = substr_len(&TCPdata[5], ' ', NULL); if(lenNameFile == 0){ FileNameHTTP = pvPortMalloc(15); if(FileNameHTTP != NULL){ strcpy(FileNameHTTP, "web/index.html"); FileNameHTTP[14] = 0; } else noMemory = 1; } else if(lenNameFile > 0){ FileNameHTTP = pvPortMalloc(lenNameFile + 5); if(FileNameHTTP != NULL){ if((strncmp(&TCPdata[5], "config.xml", 10) == 0) || (strncmp(&TCPdata[5], "mibs/", 5) == 0))memcpy(FileNameHTTP, &TCPdata[5], lenNameFile); else { sprintf(FileNameHTTP, "web/"); memcpy(&FileNameHTTP[4], &TCPdata[5], lenNameFile); lenNameFile += 4; } FileNameHTTP[lenNameFile] = 0; } else noMemory = 1; } if(noMemory){ __debug(DEBUG_WEB_SERVER, "No memory\r\n", nbuf->addr.addr); netconn_close(conn); netbuf_delete(nbuf); netconn_delete(conn); continue; } if(xSemaphoreTake(MutexAccessFlash, portMAX_DELAY) == pdTRUE){ //struct dirpath *dir = f_get_path((char*)FileNameHTTP); //if(dir != NULL){ //if(dir->dirname != NULL){ // if(f_opendir(&dirFAT, dir->dirname) == FR_NO_PATH) { // f_closedir(&dirFAT); // f_dir_path_free(dir); // notFountPage = 1; // } //else dir->statedir = OPEN_DIR; //} //if(dir->fname != NULL) { if(f_open(&FSFileHTTP, FileNameHTTP/*dir->fname*/, FA_READ) == FR_OK){ // есть файл, то отдаем его FileSizeHTTP = f_size(&FSFileHTTP); strcpy(CodeResponse, "200 OK"); GetContentType(FileNameHTTP/*dir->fname*/, ContentType); sprintf(HeaderHTTP, "HTTP/1.1 %s\r\nContent-Type: %s; charset=utf-8\r\nConnection: close\r\nContent-Length: %d\r\n\r\n", CodeResponse, ContentType, FileSizeHTTP); netconn_write(conn, HeaderHTTP, strlen(HeaderHTTP), FileSizeHTTP ? (NETCONN_NOCOPY | NETCONN_MORE) : NETCONN_NOCOPY); if(FileSizeHTTP > 0){ uint32_t ByteCountRead = 0, ByteRead = 0, ByteWritten = 0; uint8_t TCP_Flag = NETCONN_COPY | NETCONN_MORE; if(FileSizeHTTP > TCP_MSS) FileHTTP = pvPortMalloc(TCP_MSS); else FileHTTP = pvPortMalloc(FileSizeHTTP); if(FileHTTP != NULL){ while(1){ if((FileSizeHTTP - ByteRead) > TCP_MSS) ByteCountRead = TCP_MSS; else { TCP_Flag &= ~NETCONN_MORE; ByteCountRead = FileSizeHTTP - ByteRead; } f_lseek(&FSFileHTTP, ByteRead); f_read(&FSFileHTTP, FileHTTP, (UINT)ByteCountRead, (UINT*)&ByteWritten); netconn_write(conn, FileHTTP, ByteCountRead, TCP_Flag); ByteRead += ByteCountRead; if(ByteRead >= FileSizeHTTP)break; } vPortFree(FileHTTP); } else notFountPage = 1; } f_close(&FSFileHTTP); } else notFountPage = 1; //if(dir->statedir == OPEN_DIR)f_closedir(&dirFAT); //f_dir_path_free(dir); //} //else notFountPage = 1; //} //else notFountPage = 1; if(notFountPage){ strcpy(CodeResponse, "404 Not Found"); strcpy(ContentType, "text/html"); sprintf(HeaderHTTP, "HTTP/1.1 %s\r\nContent-Type: %s; charset=utf-8\r\nConnection: close\r\nContent-Length: %d\r\n\r\n", CodeResponse, ContentType, FileSizeHTTP); netconn_write(conn, HeaderHTTP, strlen(HeaderHTTP), NETCONN_NOCOPY); } } vPortFree(FileNameHTTP); xSemaphoreGive(MutexAccessFlash); } else if(strncmp(TCPdata, "POST /api.c", 11) == 0){ //POST /config /* ищем длину контента */ str = strstr(TCPdata, "Content-Length:"); if(str != NULL){ str += 16; // сдвигаем указатель на 16 символов перед LenContent = atoi(str); } /* ************************ */ str = strstr(TCPdata, "Cookie:"); // сдвигаем указатель на 8 символов перед if(str != NULL) {// есть куки str += 8; uint16_t LenCookie = substr_len(str, '\r', '\n'); if(LenCookie > 0){ Cookie = pvPortMalloc(LenCookie); if(Cookie != NULL){ memcpy(Cookie, str, LenCookie); cookie_token_typDef cookie_token[8] = {0}; cookie_token_data_typDef cookie_data = {0}; cookie_data.data = Cookie; cookie_data.len = LenCookie; cookie_data.tokens = cookie_token; cookie_parse_tokens(&cookie_data); request.cookie = &cookie_data; } else request.cookie = NULL; } else request.cookie = NULL; } else request.cookie = NULL; //if(Cookie == NULL) request.cookie = NULL; /* ************************ */ if(LenContent > 0){ JSON_Request = pvPortMalloc(LenContent + 1); // выделяем память под полнзные данные, + ноль завершающий if(JSON_Request != NULL){ memcpy(JSON_Request, &TCPdata[TCPlenData - LenContent], LenContent); JSON_Request[LenContent] = 0; request.json_data = JSON_Request; request.json_len = LenContent; request.remote_addr = &remote_addr; __debug(DEBUG_WEB_SERVER, "\r\nrequest json %s\r\n", JSON_Request); json_parse(&request, response_json, sizeof(response_json), response_cookie); // вернуть еще куки/ еще вернем результат выполнения команды vPortFree(JSON_Request); __debug(DEBUG_WEB_SERVER, "response json %s\r\n\r\n", response_json); // ответ для отправки strcpy(CodeResponse, "200 OK"); GetContentType(".json", ContentType); sprintf(HeaderHTTP, "HTTP/1.1 %s\r\nContent-Type: %s; charset=utf-8\r\nConnection: close\r\nContent-Length: %d\r\n%s\r\n", CodeResponse, ContentType, strlen(response_json), response_cookie); netconn_write(conn, HeaderHTTP, strlen(HeaderHTTP), NETCONN_COPY | NETCONN_MORE); netconn_write(conn, response_json, strlen(response_json), NETCONN_COPY); } } vPortFree(Cookie); } } else __debug(DEBUG_WEB_SERVER, "Receive timeout\r\n"); while(conn->state & NETCONN_WRITE){ wdt_reset(); if(cnt_timeout++ == 500) { __debug(DEBUG_WEB_SERVER, "500ms receive timeout\r\n"); break; // принудительный таймаут на 500ms } else vTaskDelay(1); } cnt_timeout = 0; __debug(DEBUG_WEB_SERVER, "Connection close\r\n"); netconn_close(conn); netbuf_delete(nbuf); netconn_delete(conn); } else vTaskDelay(1); break; } } } /* ----------------------------------------------------------------------------------------- */ /* ######################################################################################### */ /* OTHER FUNCTION -------------------------------------------------------------------------- */ void GetContentType(char *FileName, char *ContentType) { uint8_t i = 0; for(; FileName[i] != '.'; i++); if(strncmp(&FileName[i], ".html", 5) == 0) strcpy(ContentType, "text/html"); else if(strncmp(&FileName[i], ".css", 4) == 0) strcpy(ContentType, "text/css"); else if(strncmp(&FileName[i], ".json", 5) == 0) strcpy(ContentType, "application/json"); else if(strncmp(&FileName[i], ".js", 3) == 0) strcpy(ContentType, "text/javascript"); else if(strncmp(&FileName[i], ".gif", 4) == 0) strcpy(ContentType, "image/gif"); else if(strncmp(&FileName[i], ".jpeg", 5) == 0) strcpy(ContentType, "image/jpeg"); else if(strncmp(&FileName[i], ".png", 4) == 0) strcpy(ContentType, "image/png"); else if(strncmp(&FileName[i], ".ico", 4) == 0) strcpy(ContentType, "image/vnd.microsoft.icon"); else strcpy(ContentType, "text/plain"); } int32_t substr_len(char *str, char symbol, char addSymbol) // возвращает длину подстроки, 0 если нет конечного символа { if(str == NULL) return -1; uint16_t len = 0; uint16_t PosEnd = 0; uint16_t strLen = strlen(str); if(strLen == 0) return -1; if(addSymbol == NULL){ for(; str[PosEnd] != symbol; PosEnd++) { len++; if(strLen == len) return -1; } } else { for(;; PosEnd++) { if((str[PosEnd] == symbol) || (str[PosEnd] == addSymbol)) break; else len++; if(strLen == len) return -1; } } return len; } /* ----------------------------------------------------------------------------------------- */ /* ######################################################################################### */ /* GPIO CALLBACK --------------------------------------------------------------------------- */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == PHY_INT_Pin) // interrupt PHY { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; xSemaphoreGiveFromISR(SemaphoreIRQ_PHY, &xHigherPriorityTaskWoken); } } /* USER CODE END Application */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/