#include #include #include "sdkconfig.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/event_groups.h" #include "esp_system.h" #include "esp_wifi.h" #include "esp_event.h" #include "esp_log.h" #include "nvs_flash.h" #include "esp_netif.h" #include "lwip/err.h" #include "lwip/sockets.h" #include "lwip/sys.h" #include #include "udp_client.h" #include "wifi.h" #include "nexaTransmit.h" /********************************************************************************** * For sending and receiving UDP-Data from the Debian-server use these commands: * echo "" | nc -uv 192.168.1.164 53000 * nc -lu -p 53000 **********************************************************************************/ #ifdef WIFI_ENABLED static QueueHandle_t udpTxQueue = NULL; // Queue for transmitting UDP-Data to back-end server static QueueHandle_t udpForwardQueue = NULL; // Queue for forwarding NEXA-UDP-Data to next transceiver static int socket_fd; static struct sockaddr_in backEndAddress; // Address to back-end server static struct sockaddr_in backEndAddressSensorData; // Address to back-end server (sensor) static struct sockaddr_in forwardAddress; // Address to next transceiver for NEXA-code-forwarding static void setupConnection() { struct sockaddr_in recvFromAddress; closesocket(socket_fd); // This Address is used for sending to the back-end server backEndAddress.sin_addr.s_addr = inet_addr(CONFIG_BACK_END_SERVER_IP_ADDRESS); backEndAddress.sin_family = AF_INET; backEndAddress.sin_port = htons(CONFIG_UDP_PORT_NO); // This Address is used for sending to the back-end server for sensor-data (different port) backEndAddressSensorData.sin_addr.s_addr = inet_addr(CONFIG_BACK_END_SERVER_IP_ADDRESS); backEndAddressSensorData.sin_family = AF_INET; backEndAddressSensorData.sin_port = htons(CONFIG_UDP_PORT_NO_FOR_SENSOR_DATA); // This Address is used for forwaring NEXA codes to next transceiver forwardAddress.sin_addr.s_addr = inet_addr(CONFIG_NEXT_FORWARD_IP_ADDRESS); forwardAddress.sin_family = AF_INET; forwardAddress.sin_port = htons(CONFIG_UDP_PORT_NO); // Wait for WiFi to be connected first while( commIsUpAndRunning == 0 ) vTaskDelay(500 / portTICK_PERIOD_MS); socket_fd = socket(AF_INET, SOCK_DGRAM, 0); if (socket_fd < 0) ESP_LOGE("UDP","Socket error"); // Bind our server socket to a port. // We listen on this port from ANY other host. It could be the // back-end server, or it could be another Transceiver that forwards recvFromAddress.sin_addr.s_addr = htonl(INADDR_ANY); recvFromAddress.sin_family = AF_INET; recvFromAddress.sin_port = htons(CONFIG_UDP_PORT_NO); if( (bind(socket_fd, (const struct sockaddr *)&recvFromAddress, sizeof(struct sockaddr_in))) == -1 ) ESP_LOGE("UDP","Bind error"); else ESP_LOGI("UDP","UDP Rx Bind."); } void udp_client_task(void *pvParameter) { int recv_len; char dataBuff[UDP_QUEUE_OBJ_LENGTH]; setupConnection(); while(1) { memset(dataBuff,0,UDP_QUEUE_OBJ_LENGTH); // Receive if( (recv_len = recvfrom(socket_fd, dataBuff, UDP_QUEUE_OBJ_LENGTH,MSG_DONTWAIT, NULL, NULL)) > 0 ) { if( dataBuff[recv_len-1] == '\n' ) dataBuff[recv_len-1] = '\0'; sendNexaCodeStr(dataBuff); ESP_LOGI("UDP","UDP Task: Data: %s -- %d" , dataBuff, recv_len); } else if( recv_len == -1 && errno != 11 ) { ESP_LOGE("UDP", "Error occurred during recvfrom: errno %d", errno); } // Transmit while( xQueueReceive( udpTxQueue, &dataBuff, 0 ) == pdTRUE ) { // Last byte contains type of data const uint8_t dataType = dataBuff[UDP_QUEUE_OBJ_LENGTH-1]; ESP_LOGI("UDP","Send data:%s Type:%u",dataBuff,dataType); if( dataType == 0 ) { sendto(socket_fd, dataBuff, strlen(dataBuff), 0, (struct sockaddr *)&backEndAddress, sizeof(backEndAddress)); } else if( dataType == 1 ) { sendto(socket_fd, dataBuff, strlen(dataBuff), 0, (struct sockaddr *)&backEndAddressSensorData, sizeof(backEndAddressSensorData)); } else { ESP_LOGE("UDP","Wrong dataType:%u",dataType); } } // Forward NEXT Codes to next transceiver while( xQueueReceive( udpForwardQueue, &dataBuff, 0 ) == pdTRUE ) { ESP_LOGI("UDP","Forward NEXA-data:%s",dataBuff); sendto(socket_fd, dataBuff, strlen(dataBuff), 0, (struct sockaddr *)&forwardAddress, sizeof(forwardAddress)); } vTaskDelay(50 / portTICK_RATE_MS); } vTaskDelete(NULL); } // Public interface for sending a UDP Message to the back-end server. // Argument #1 must be UDP_QUEUE_OBJ_LENGTH chars in length. // In the last data byte transfered, the type of data is specified void sendUDPMessage(char *p, bool sensorData) { char data[UDP_QUEUE_OBJ_LENGTH]; data[0] = '<'; data[1] = CONFIG_UNIT_ID + 'A'; // Source data[2] = 'A'; // Destination if( p[0] == '<') { strncpy(data+3, p+1, UDP_QUEUE_OBJ_LENGTH-4); if( strchr(data,'>') != NULL ) { if( sensorData == true ) data[UDP_QUEUE_OBJ_LENGTH-1] = 1; // Sensor data else data[UDP_QUEUE_OBJ_LENGTH-1] = 0; // NEXA if( udpTxQueue != NULL ) xQueueSend( udpTxQueue, data, 0 ); } } } // Public interface for forwaring a NEXA code to the next transceiver. void forwardNEXAMessage(char *p) { if( udpForwardQueue != NULL ) xQueueSend( udpForwardQueue, p, 0 ); } void udpClientInit() { ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); udpTxQueue = xQueueCreate( 5, UDP_QUEUE_OBJ_LENGTH ); udpForwardQueue = xQueueCreate( 5, UDP_QUEUE_OBJ_LENGTH ); xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL); } #endif