You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
10 KiB
303 lines
10 KiB
/* BSD Socket API Example
|
|
|
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
|
|
|
Unless required by applicable law or agreed to in writing, this
|
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
CONDITIONS OF ANY KIND, either express or implied.
|
|
*/
|
|
#include "platform.h"
|
|
#if PL_CONFIG_USE_UDP_CLIENT
|
|
#include <string.h>
|
|
#include <sys/param.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 <lwip/netdb.h>
|
|
|
|
#include "udp_client.h"
|
|
#include "McuShell.h"
|
|
#include "McuUtility.h"
|
|
|
|
#define CONFIG_EXAMPLE_IPV4
|
|
|
|
#ifdef CONFIG_EXAMPLE_IPV4
|
|
#define HOST_IP_ADDR "192.168.0.146"
|
|
#else
|
|
#define HOST_IP_ADDR "FE80::30AD:E57B:C212:68AD" /*CONFIG_EXAMPLE_IPV6_ADDR*/
|
|
#endif
|
|
#define PORT 3333
|
|
|
|
static uint16_t udp_client_destination_port = PORT;
|
|
static unsigned char udp_client_destination_host[24] = HOST_IP_ADDR;
|
|
|
|
#define TAG "udp_client" /* tag for logging with ESP_LOG */
|
|
static TaskHandle_t taskHandle = NULL; /* udp client task handle */
|
|
|
|
#if 0
|
|
static const char *payload = "Message from ESP32 ";
|
|
|
|
static void udp_client_task(void *pvParameters) {
|
|
char rx_buffer[128];
|
|
char addr_str[128];
|
|
int addr_family;
|
|
int ip_protocol;
|
|
|
|
vTaskSuspend(NULL); /* UDP_Client_Start() will wake me up */
|
|
for(;;) {
|
|
#ifdef CONFIG_EXAMPLE_IPV4
|
|
struct sockaddr_in dest_addr;
|
|
dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
|
|
dest_addr.sin_family = AF_INET;
|
|
dest_addr.sin_port = htons(PORT);
|
|
addr_family = AF_INET;
|
|
ip_protocol = IPPROTO_IP;
|
|
inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
|
|
#else /* IPV6 */
|
|
struct sockaddr_in6 dest_addr;
|
|
inet6_aton(HOST_IP_ADDR, &dest_addr.sin6_addr);
|
|
dest_addr.sin6_family = AF_INET6;
|
|
dest_addr.sin6_port = htons(PORT);
|
|
addr_family = AF_INET6;
|
|
ip_protocol = IPPROTO_IPV6;
|
|
inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
|
|
#endif
|
|
|
|
int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
|
|
if (sock < 0) {
|
|
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
|
break;
|
|
}
|
|
ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, PORT);
|
|
while (1) {
|
|
int err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
|
if (err < 0) {
|
|
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
|
|
break;
|
|
}
|
|
ESP_LOGI(TAG, "Message sent");
|
|
|
|
struct timeval to;
|
|
|
|
to.tv_sec = 1;
|
|
to.tv_usec = 0;
|
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)) < 0) {
|
|
ESP_LOGE(TAG, "setting socket timeout failed");
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Waiting for response");
|
|
struct sockaddr_in source_addr; /* Large enough for both IPv4 or IPv6 */
|
|
socklen_t socklen = sizeof(source_addr);
|
|
int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
|
|
|
|
/* Error occurred during receiving */
|
|
if (len < 0) {
|
|
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
|
|
break;
|
|
} else { /* Data received */
|
|
rx_buffer[len] = 0; /* Null-terminate whatever we received and treat like a string */
|
|
ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str);
|
|
ESP_LOGI(TAG, "%s", rx_buffer);
|
|
}
|
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
|
}
|
|
if (sock != -1) {
|
|
ESP_LOGE(TAG, "Shutting down socket and restarting...");
|
|
shutdown(sock, 0);
|
|
close(sock);
|
|
}
|
|
} /* for */
|
|
vTaskDelete(NULL);
|
|
}
|
|
#endif
|
|
|
|
static uint8_t udp_client_send(const unsigned char *host, uint16_t port, const unsigned char *msg, unsigned char *rxBuffer, size_t rxBufferSize) {
|
|
char addr_str[128];
|
|
int addr_family;
|
|
int ip_protocol;
|
|
uint8_t res = ERR_OK;
|
|
|
|
#ifdef CONFIG_EXAMPLE_IPV4
|
|
struct sockaddr_in dest_addr;
|
|
dest_addr.sin_addr.s_addr = inet_addr((const char*)host);
|
|
dest_addr.sin_family = AF_INET;
|
|
dest_addr.sin_port = htons(port);
|
|
addr_family = AF_INET;
|
|
ip_protocol = IPPROTO_IP;
|
|
inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
|
|
#else /* IPV6 */
|
|
struct sockaddr_in6 dest_addr;
|
|
inet6_aton(host, &dest_addr.sin6_addr);
|
|
dest_addr.sin6_family = AF_INET6;
|
|
dest_addr.sin6_port = htons(port);
|
|
addr_family = AF_INET6;
|
|
ip_protocol = IPPROTO_IPV6;
|
|
inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
|
|
#endif
|
|
|
|
int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
|
|
for(;;) { /* breaks in in case of error */
|
|
if (sock < 0) {
|
|
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
|
|
res = ERR_FAILED;
|
|
break;
|
|
}
|
|
ESP_LOGI(TAG, "Socket created, sending to %s:%d", host, port);
|
|
|
|
int err = sendto(sock, msg, strlen((char*)msg), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
|
if (err < 0) {
|
|
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
|
|
res = ERR_FAILED;
|
|
break;
|
|
}
|
|
ESP_LOGI(TAG, "Message sent");
|
|
|
|
struct timeval to;
|
|
|
|
to.tv_sec = 1;
|
|
to.tv_usec = 0;
|
|
if (setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)) < 0) {
|
|
ESP_LOGE(TAG, "setting socket timeout failed");
|
|
res = ERR_FAILED;
|
|
break;
|
|
}
|
|
|
|
ESP_LOGI(TAG, "Waiting for response");
|
|
struct sockaddr_in source_addr; /* Large enough for both IPv4 or IPv6 */
|
|
socklen_t socklen = sizeof(source_addr);
|
|
int len = recvfrom(sock, rxBuffer, rxBufferSize-1, 0, (struct sockaddr *)&source_addr, &socklen);
|
|
|
|
/* Error occurred during receiving */
|
|
if (len < 0) {
|
|
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
|
|
res = ERR_FAILED;
|
|
break;
|
|
} else { /* Data received */
|
|
rxBuffer[len] = '\0'; /* Null-terminate whatever we received and treat like a string */
|
|
ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str);
|
|
ESP_LOGI(TAG, "%s", rxBuffer);
|
|
}
|
|
break;
|
|
} /* for */
|
|
if (sock != -1) {
|
|
ESP_LOGE(TAG, "Shutting down socket");
|
|
shutdown(sock, 0);
|
|
close(sock);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
void UDP_Client_Start(void) {
|
|
if (taskHandle!=NULL) {
|
|
vTaskResume(taskHandle);
|
|
}
|
|
}
|
|
|
|
void UDP_Client_Stop(void) {
|
|
if (taskHandle!=NULL) {
|
|
vTaskSuspend(taskHandle);
|
|
}
|
|
}
|
|
|
|
void UDP_Client_Init(void) {
|
|
#if 0
|
|
BaseType_t res;
|
|
|
|
res = xTaskCreate(udp_client_task, "udp_client", 16*1024/sizeof(StackType_t), NULL, 5, &taskHandle);
|
|
if (res==pdPASS) {
|
|
ESP_LOGI(TAG, "created UDP client task");
|
|
} else {
|
|
ESP_LOGE(TAG, "failed creating UDP client task!");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if PL_CONFIG_USE_SHELL
|
|
static uint8_t PrintStatus(const McuShell_StdIOType *io) {
|
|
unsigned char buf[64];
|
|
|
|
McuShell_SendStatusStr((unsigned char*)"udpc", (unsigned char*)"UDP client status\r\n", io->stdOut);
|
|
|
|
McuUtility_strcpy(buf, sizeof(buf), udp_client_destination_host);
|
|
McuUtility_chcat(buf, sizeof(buf), ':');
|
|
McuUtility_strcatNum16u(buf, sizeof(buf), udp_client_destination_port);
|
|
McuUtility_strcat(buf, sizeof(buf), (unsigned char*)"\r\n");
|
|
McuShell_SendStatusStr((unsigned char*)" host", buf, io->stdOut);
|
|
return ERR_OK;
|
|
}
|
|
|
|
static uint8_t PrintHelp(const McuShell_StdIOType *io) {
|
|
McuShell_SendHelpStr((unsigned char*)"udpc", (unsigned char*)"Group of UDP client commands\r\n", io->stdOut);
|
|
McuShell_SendHelpStr((unsigned char*)" help|status", (unsigned char*)"Shows motor help or status\r\n", io->stdOut);
|
|
McuShell_SendHelpStr((unsigned char*)" host <string>", (unsigned char*)"Set default host destination IP address (double quoted)\r\n", io->stdOut);
|
|
McuShell_SendHelpStr((unsigned char*)" port <number>", (unsigned char*)"Set default host destination port number\r\n", io->stdOut);
|
|
McuShell_SendHelpStr((unsigned char*)" send default <msg>", (unsigned char*)"Send message (double quoted) to default host and port\r\n", io->stdOut);
|
|
McuShell_SendHelpStr((unsigned char*)" send <ip> <port> <msg>", (unsigned char*)"Send message (double quoted) to ip (double quoted) and port\r\n", io->stdOut);
|
|
return ERR_OK;
|
|
}
|
|
|
|
uint8_t UDP_Client_ParseCommand(const unsigned char* cmd, bool *handled, const McuShell_StdIOType *io) {
|
|
const unsigned char *p;
|
|
unsigned char msgBuf[64];
|
|
unsigned char rxBuf[64];
|
|
unsigned char ip[24];
|
|
uint16_t port;
|
|
|
|
if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_HELP)==0 || McuUtility_strcmp((char*)cmd, (char*)"udpc help")==0) {
|
|
*handled = TRUE;
|
|
return PrintHelp(io);
|
|
} else if (McuUtility_strcmp((char*)cmd, (char*)McuShell_CMD_STATUS)==0 || McuUtility_strcmp((char*)cmd, (char*)"udpc status")==0) {
|
|
*handled = TRUE;
|
|
return PrintStatus(io);
|
|
} else if (McuUtility_strncmp((char*)cmd, (char*)"udpc host ", sizeof("udpc host ")-1)==0) {
|
|
*handled = TRUE;
|
|
p = cmd + sizeof("udpc host ")-1;
|
|
return McuUtility_ScanDoubleQuotedString(&p, udp_client_destination_host, sizeof(udp_client_destination_host));
|
|
} else if (McuUtility_strncmp((char*)cmd, (char*)"udpc port ", sizeof("udpc port ")-1)==0) {
|
|
*handled = TRUE;
|
|
p = cmd + sizeof("udpc port ")-1;
|
|
return McuUtility_ScanDecimal16uNumber(&p, &udp_client_destination_port);
|
|
} else if (McuUtility_strncmp((char*)cmd, (char*)"udpc send default ", sizeof("udpc send default ")-1)==0) {
|
|
*handled = TRUE;
|
|
p = cmd + sizeof("udpc send default ")-1;
|
|
if (McuUtility_ScanDoubleQuotedString(&p, msgBuf, sizeof(msgBuf))!=ERR_OK) {
|
|
return ERR_FAILED;
|
|
}
|
|
if (udp_client_send(udp_client_destination_host, udp_client_destination_port, msgBuf, rxBuf, sizeof(rxBuf))!=ERR_OK) {
|
|
return ERR_FAILED;
|
|
}
|
|
McuShell_SendStr(rxBuf, io->stdOut);
|
|
return ERR_OK;
|
|
} else if (McuUtility_strncmp((char*)cmd, (char*)"udpc send ", sizeof("udpc send ")-1)==0) {
|
|
*handled = TRUE;
|
|
p = cmd + sizeof("udpc send ")-1;
|
|
if (McuUtility_ScanDoubleQuotedString(&p, ip, sizeof(ip))!=ERR_OK) {
|
|
return ERR_FAILED;
|
|
}
|
|
if (McuUtility_ScanDecimal16uNumber(&p, &port)!=ERR_OK) {
|
|
return ERR_FAILED;
|
|
}
|
|
if (McuUtility_ScanDoubleQuotedString(&p, msgBuf, sizeof(msgBuf))!=ERR_OK) {
|
|
return ERR_FAILED;
|
|
}
|
|
if (udp_client_send(ip, port, msgBuf, rxBuf, sizeof(rxBuf))!=ERR_OK) {
|
|
return ERR_FAILED;
|
|
}
|
|
McuShell_SendStr(rxBuf, io->stdOut);
|
|
return ERR_OK;
|
|
}
|
|
return ERR_OK;
|
|
}
|
|
|
|
#endif /* PL_CONFIG_USE_SHELL */
|
|
|
|
#endif /* PL_CONFIG_USE_UDP_CLIENT */
|
|
|