examples/protocols/sockets: use common network component

This commit is contained in:
Ivan Grokhotkov 2018-11-21 00:41:08 +08:00 committed by bot
parent b3a235945e
commit 28cf1c83df
25 changed files with 202 additions and 571 deletions

View file

@ -2,5 +2,9 @@
# CMakeLists in this exact order for cmake to work correctly # CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(tcp_client) project(tcp_client)

View file

@ -5,5 +5,7 @@
PROJECT_NAME := tcp_client PROJECT_NAME := tcp_client
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk

View file

@ -44,10 +44,6 @@ Set following parameter under Serial Flasher Options:
Set following parameters under Example Configuration Options: Set following parameters under Example Configuration Options:
* Set `WiFi SSID` of the Router (Access-Point).
* Set `WiFi Password` of the Router (Access-Point).
* Set `IP version` of example to be IPV4 or IPV6. * Set `IP version` of example to be IPV4 or IPV6.
* Set `IPV4 Address` in case your chose IP version IPV4 above. * Set `IPV4 Address` in case your chose IP version IPV4 above.
@ -56,6 +52,8 @@ Set following parameters under Example Configuration Options:
* Set `Port` number that represents remote port the example will connect to. * Set `Port` number that represents remote port the example will connect to.
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
## Build and Flash ## Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output: Build the project and flash it to the board, then run monitor tool to view serial output:

View file

@ -1,18 +1,5 @@
menu "Example Configuration" menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
choice EXAMPLE_IP_MODE choice EXAMPLE_IP_MODE
prompt "IP Version" prompt "IP Version"
help help

View file

@ -13,9 +13,11 @@
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event_loop.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "protocol_examples_common.h"
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
@ -23,14 +25,6 @@
#include <lwip/netdb.h> #include <lwip/netdb.h>
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR #define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#else #else
@ -39,77 +33,9 @@
#define PORT CONFIG_EXAMPLE_PORT #define PORT CONFIG_EXAMPLE_PORT
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
const int IPV4_GOTIP_BIT = BIT0;
const int IPV6_GOTIP_BIT = BIT1;
static const char *TAG = "example"; static const char *TAG = "example";
static const char *payload = "Message from ESP32 "; static const char *payload = "Message from ESP32 ";
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
break;
case SYSTEM_EVENT_STA_CONNECTED:
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
break;
case SYSTEM_EVENT_AP_STA_GOT_IP6:
xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP6");
char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip);
ESP_LOGI(TAG, "IPv6: %s", ip6);
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void wait_for_ip()
{
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT ;
ESP_LOGI(TAG, "Waiting for AP connection...");
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
}
static void tcp_client_task(void *pvParameters) static void tcp_client_task(void *pvParameters)
{ {
char rx_buffer[128]; char rx_buffer[128];
@ -120,21 +46,21 @@ static void tcp_client_task(void *pvParameters)
while (1) { while (1) {
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
struct sockaddr_in destAddr; struct sockaddr_in dest_addr;
destAddr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR); dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
destAddr.sin_family = AF_INET; dest_addr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT); dest_addr.sin_port = htons(PORT);
addr_family = AF_INET; addr_family = AF_INET;
ip_protocol = IPPROTO_IP; ip_protocol = IPPROTO_IP;
inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1); inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
#else // IPV6 #else // IPV6
struct sockaddr_in6 destAddr; struct sockaddr_in6 dest_addr;
inet6_aton(HOST_IP_ADDR, &destAddr.sin6_addr); inet6_aton(HOST_IP_ADDR, &dest_addr.sin6_addr);
destAddr.sin6_family = AF_INET6; dest_addr.sin6_family = AF_INET6;
destAddr.sin6_port = htons(PORT); dest_addr.sin6_port = htons(PORT);
addr_family = AF_INET6; addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6; ip_protocol = IPPROTO_IPV6;
inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
#endif #endif
int sock = socket(addr_family, SOCK_STREAM, ip_protocol); int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
@ -142,9 +68,9 @@ static void tcp_client_task(void *pvParameters)
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break; break;
} }
ESP_LOGI(TAG, "Socket created"); ESP_LOGI(TAG, "Socket created, connecting to %s:%d", HOST_IP_ADDR, PORT);
int err = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0) { if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno); ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break; break;
@ -154,12 +80,12 @@ static void tcp_client_task(void *pvParameters)
while (1) { while (1) {
int err = send(sock, payload, strlen(payload), 0); int err = send(sock, payload, strlen(payload), 0);
if (err < 0) { if (err < 0) {
ESP_LOGE(TAG, "Error occured during sending: errno %d", errno); ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break; break;
} }
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occured during receiving // Error occurred during receiving
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno); ESP_LOGE(TAG, "recv failed: errno %d", errno);
break; break;
@ -185,9 +111,15 @@ static void tcp_client_task(void *pvParameters)
void app_main() void app_main()
{ {
ESP_ERROR_CHECK( nvs_flash_init() ); ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi(); tcpip_adapter_init();
wait_for_ip(); ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL); xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
} }

View file

@ -2,5 +2,9 @@
# CMakeLists in this exact order for cmake to work correctly # CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(tcp_server) project(tcp_server)

View file

@ -5,5 +5,7 @@
PROJECT_NAME := tcp_server PROJECT_NAME := tcp_server
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk

View file

@ -46,14 +46,12 @@ Set following parameter under Serial Flasher Options:
Set following parameters under Example Configuration Options: Set following parameters under Example Configuration Options:
* Set `WiFi SSID` of the Router (Access-Point).
* Set `WiFi Password` of the Router (Access-Point).
* Set `IP version` of the example to be IPV4 or IPV6. * Set `IP version` of the example to be IPV4 or IPV6.
* Set `Port` number of the socket, that server example will create. * Set `Port` number of the socket, that server example will create.
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
## Build and Flash ## Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output: Build the project and flash it to the board, then run monitor tool to view serial output:

View file

@ -1,18 +1,5 @@
menu "Example Configuration" menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
choice EXAMPLE_IP_MODE choice EXAMPLE_IP_MODE
prompt "IP Version" prompt "IP Version"
help help
@ -23,6 +10,7 @@ menu "Example Configuration"
config EXAMPLE_IPV6 config EXAMPLE_IPV6
bool "IPV6" bool "IPV6"
select EXAMPLE_CONNECT_IPV6
endchoice endchoice

View file

@ -10,12 +10,13 @@
#include <sys/param.h> #include <sys/param.h>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event_loop.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "protocol_examples_common.h"
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
@ -23,85 +24,10 @@
#include <lwip/netdb.h> #include <lwip/netdb.h>
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define PORT CONFIG_EXAMPLE_PORT #define PORT CONFIG_EXAMPLE_PORT
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
const int IPV4_GOTIP_BIT = BIT0;
const int IPV6_GOTIP_BIT = BIT1;
static const char *TAG = "example"; static const char *TAG = "example";
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
break;
case SYSTEM_EVENT_STA_CONNECTED:
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
break;
case SYSTEM_EVENT_AP_STA_GOT_IP6:
xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP6");
char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip);
ESP_LOGI(TAG, "IPv6: %s", ip6);
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void wait_for_ip()
{
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT ;
ESP_LOGI(TAG, "Waiting for AP connection...");
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
}
static void tcp_server_task(void *pvParameters) static void tcp_server_task(void *pvParameters)
{ {
@ -113,21 +39,21 @@ static void tcp_server_task(void *pvParameters)
while (1) { while (1) {
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
struct sockaddr_in destAddr; struct sockaddr_in dest_addr;
destAddr.sin_addr.s_addr = htonl(INADDR_ANY); dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
destAddr.sin_family = AF_INET; dest_addr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT); dest_addr.sin_port = htons(PORT);
addr_family = AF_INET; addr_family = AF_INET;
ip_protocol = IPPROTO_IP; ip_protocol = IPPROTO_IP;
inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1); inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
#else // IPV6 #else // IPV6
struct sockaddr_in6 destAddr; struct sockaddr_in6 dest_addr;
bzero(&destAddr.sin6_addr.un, sizeof(destAddr.sin6_addr.un)); bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
destAddr.sin6_family = AF_INET6; dest_addr.sin6_family = AF_INET6;
destAddr.sin6_port = htons(PORT); dest_addr.sin6_port = htons(PORT);
addr_family = AF_INET6; addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6; ip_protocol = IPPROTO_IPV6;
inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
#endif #endif
int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol); int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
@ -137,23 +63,23 @@ static void tcp_server_task(void *pvParameters)
} }
ESP_LOGI(TAG, "Socket created"); ESP_LOGI(TAG, "Socket created");
int err = bind(listen_sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); int err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0) { if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
break; break;
} }
ESP_LOGI(TAG, "Socket binded"); ESP_LOGI(TAG, "Socket bound, port %d", PORT);
err = listen(listen_sock, 1); err = listen(listen_sock, 1);
if (err != 0) { if (err != 0) {
ESP_LOGE(TAG, "Error occured during listen: errno %d", errno); ESP_LOGE(TAG, "Error occurred during listen: errno %d", errno);
break; break;
} }
ESP_LOGI(TAG, "Socket listening"); ESP_LOGI(TAG, "Socket listening");
struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6 struct sockaddr_in6 source_addr; // Large enough for both IPv4 or IPv6
uint addrLen = sizeof(sourceAddr); uint addr_len = sizeof(source_addr);
int sock = accept(listen_sock, (struct sockaddr *)&sourceAddr, &addrLen); int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (sock < 0) { if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno); ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
break; break;
@ -162,7 +88,7 @@ static void tcp_server_task(void *pvParameters)
while (1) { while (1) {
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0); int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occured during receiving // Error occurred during receiving
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno); ESP_LOGE(TAG, "recv failed: errno %d", errno);
break; break;
@ -175,10 +101,10 @@ static void tcp_server_task(void *pvParameters)
// Data received // Data received
else { else {
// Get the sender's ip address as string // Get the sender's ip address as string
if (sourceAddr.sin6_family == PF_INET) { if (source_addr.sin6_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
} else if (sourceAddr.sin6_family == PF_INET6) { } else if (source_addr.sin6_family == PF_INET6) {
inet6_ntoa_r(sourceAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
} }
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
@ -187,7 +113,7 @@ static void tcp_server_task(void *pvParameters)
int err = send(sock, rx_buffer, len, 0); int err = send(sock, rx_buffer, len, 0);
if (err < 0) { if (err < 0) {
ESP_LOGE(TAG, "Error occured during sending: errno %d", errno); ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break; break;
} }
} }
@ -204,9 +130,15 @@ static void tcp_server_task(void *pvParameters)
void app_main() void app_main()
{ {
ESP_ERROR_CHECK( nvs_flash_init() ); ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi(); tcpip_adapter_init();
wait_for_ip(); ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL); xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
} }

View file

@ -2,5 +2,9 @@
# CMakeLists in this exact order for cmake to work correctly # CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(udp_client) project(udp_client)

View file

@ -5,5 +5,7 @@
PROJECT_NAME := udp_client PROJECT_NAME := udp_client
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk

View file

@ -54,10 +54,6 @@ Set following parameter under Serial Flasher Options:
Set following parameters under Example Configuration Options: Set following parameters under Example Configuration Options:
* Set `WiFi SSID` of the Router (Access-Point).
* Set `WiFi Password` of the Router (Access-Point).
* Set `IP version` of example to be IPV4 or IPV6. * Set `IP version` of example to be IPV4 or IPV6.
* Set `IPV4 Address` in case your chose IP version IPV4 above. * Set `IPV4 Address` in case your chose IP version IPV4 above.
@ -66,6 +62,9 @@ Set following parameters under Example Configuration Options:
* Set `Port` number that represents remote port the example will send data and receive data from. * Set `Port` number that represents remote port the example will send data and receive data from.
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
## Build and Flash ## Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output: Build the project and flash it to the board, then run monitor tool to view serial output:

View file

@ -1,18 +1,5 @@
menu "Example Configuration" menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
choice EXAMPLE_IP_MODE choice EXAMPLE_IP_MODE
prompt "IP Version" prompt "IP Version"
help help
@ -23,6 +10,7 @@ menu "Example Configuration"
config EXAMPLE_IPV6 config EXAMPLE_IPV6
bool "IPV6" bool "IPV6"
select EXAMPLE_CONNECT_IPV6
endchoice endchoice

View file

@ -13,9 +13,11 @@
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event_loop.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "protocol_examples_common.h"
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
@ -23,14 +25,6 @@
#include <lwip/netdb.h> #include <lwip/netdb.h>
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR #define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#else #else
@ -39,76 +33,9 @@
#define PORT CONFIG_EXAMPLE_PORT #define PORT CONFIG_EXAMPLE_PORT
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
const int IPV4_GOTIP_BIT = BIT0;
const int IPV6_GOTIP_BIT = BIT1;
static const char *TAG = "example"; static const char *TAG = "example";
static const char *payload = "Message from ESP32 "; static const char *payload = "Message from ESP32 ";
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
break;
case SYSTEM_EVENT_STA_CONNECTED:
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
break;
case SYSTEM_EVENT_AP_STA_GOT_IP6:
xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP6");
char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip);
ESP_LOGI(TAG, "IPv6: %s", ip6);
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void wait_for_ip()
{
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT ;
ESP_LOGI(TAG, "Waiting for AP connection...");
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
}
static void udp_client_task(void *pvParameters) static void udp_client_task(void *pvParameters)
{ {
@ -120,21 +47,21 @@ static void udp_client_task(void *pvParameters)
while (1) { while (1) {
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
struct sockaddr_in destAddr; struct sockaddr_in dest_addr;
destAddr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR); dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
destAddr.sin_family = AF_INET; dest_addr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT); dest_addr.sin_port = htons(PORT);
addr_family = AF_INET; addr_family = AF_INET;
ip_protocol = IPPROTO_IP; ip_protocol = IPPROTO_IP;
inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1); inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
#else // IPV6 #else // IPV6
struct sockaddr_in6 destAddr; struct sockaddr_in6 dest_addr;
inet6_aton(HOST_IP_ADDR, &destAddr.sin6_addr); inet6_aton(HOST_IP_ADDR, &dest_addr.sin6_addr);
destAddr.sin6_family = AF_INET6; dest_addr.sin6_family = AF_INET6;
destAddr.sin6_port = htons(PORT); dest_addr.sin6_port = htons(PORT);
addr_family = AF_INET6; addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6; ip_protocol = IPPROTO_IPV6;
inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
#endif #endif
int sock = socket(addr_family, SOCK_DGRAM, ip_protocol); int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
@ -142,22 +69,22 @@ static void udp_client_task(void *pvParameters)
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno); ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break; break;
} }
ESP_LOGI(TAG, "Socket created"); ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, PORT);
while (1) { while (1) {
int err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&destAddr, sizeof(destAddr)); int err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err < 0) { if (err < 0) {
ESP_LOGE(TAG, "Error occured during sending: errno %d", errno); ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break; break;
} }
ESP_LOGI(TAG, "Message sent"); ESP_LOGI(TAG, "Message sent");
struct sockaddr_in sourceAddr; // Large enough for both IPv4 or IPv6 struct sockaddr_in source_addr; // Large enough for both IPv4 or IPv6
socklen_t socklen = sizeof(sourceAddr); socklen_t socklen = sizeof(source_addr);
int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&sourceAddr, &socklen); int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
// Error occured during receiving // Error occurred during receiving
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno); ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
break; break;
@ -183,9 +110,15 @@ static void udp_client_task(void *pvParameters)
void app_main() void app_main()
{ {
ESP_ERROR_CHECK( nvs_flash_init() ); ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi(); tcpip_adapter_init();
wait_for_ip(); ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL); xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL);
} }

View file

@ -2,5 +2,9 @@
# in this exact order for cmake to work correctly # in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(udp-multicast) project(udp-multicast)

View file

@ -5,5 +5,7 @@
PROJECT_NAME := udp-multicast PROJECT_NAME := udp-multicast
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk

View file

@ -12,9 +12,12 @@ The behaviour of the example is:
## Configuration ## Configuration
The "Example Configuration" menu "make menuconfig" allows you to configure the details of the example: Run `make menuconfig` (or `idf.py menuconfig` if using CMake build system).
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
The "Example Configuration" menu allows you to configure the details of the example:
* WiFi SSD & Password
* IP Mode: IPV4 & IPV6 dual, IPV4 only, or IPv6 only. * IP Mode: IPV4 & IPV6 dual, IPV4 only, or IPv6 only.
* Multicast addresses for IPV4 and/or IPV6. * Multicast addresses for IPV4 and/or IPV6.
* Enable multicast socket loopback (ie should the socket receive its own multicast transmissions.) * Enable multicast socket loopback (ie should the socket receive its own multicast transmissions.)

View file

@ -1,19 +1,5 @@
menu "Example Configuration" menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
choice EXAMPLE_IP_MODE choice EXAMPLE_IP_MODE
prompt "Multicast IP type" prompt "Multicast IP type"
help help
@ -38,6 +24,7 @@ menu "Example Configuration"
bool bool
config EXAMPLE_IPV6 config EXAMPLE_IPV6
bool bool
select EXAMPLE_CONNECT_IPV6
config EXAMPLE_MULTICAST_IPV4_ADDR config EXAMPLE_MULTICAST_IPV4_ADDR
string "Multicast IPV4 Address (send & receive)" string "Multicast IPV4 Address (send & receive)"
@ -53,8 +40,9 @@ menu "Example Configuration"
help help
IPV6 multicast address. Example will both send to and listen to this address. IPV6 multicast address. Example will both send to and listen to this address.
The default FF02::FC address is a link-local multicast address. Consult IPV6 specifications or The default FF02::FC address is a link-local multicast address.
documentation for information about meaning of different IPV6 multicast ranges. Consult IPV6 specifications or documentation for information about
meaning of different IPV6 multicast ranges.
config EXAMPLE_PORT config EXAMPLE_PORT
int "Multicast port (send & receive)" int "Multicast port (send & receive)"
@ -78,15 +66,16 @@ menu "Example Configuration"
choice EXAMPLE_MULTICAST_IF choice EXAMPLE_MULTICAST_IF
prompt "Multicast Interface" prompt "Multicast Interface"
default EXAMPLE_MULTICAST_LISTEN_DEFAULT_IF
help help
Multicast socket can bind to default interface, or all interfaces. Multicast socket can bind to default interface, or all interfaces.
config EXAMPLE_MULTICAST_LISTEN_ALL_IF
bool "All interfaces"
config EXAMPLE_MULTICAST_LISTEN_DEFAULT_IF config EXAMPLE_MULTICAST_LISTEN_DEFAULT_IF
bool "Default interface" bool "Default interface"
config EXAMPLE_MULTICAST_LISTEN_STA_IF
bool "WiFi STA interface"
endchoice endchoice
endmenu endmenu

View file

@ -13,24 +13,23 @@
#include "freertos/event_groups.h" #include "freertos/event_groups.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event_loop.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "protocol_examples_common.h"
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
#include "lwip/sys.h" #include "lwip/sys.h"
#include <lwip/netdb.h> #include <lwip/netdb.h>
/* The examples use simple WiFi configuration that you can set via /* The examples use simple configuration that you can set via
'make menuconfig'. 'make menuconfig'.
If you'd rather not, just change the below entries to strings with If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" the config you want - ie #define UDP_PORT 3333
*/ */
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define UDP_PORT CONFIG_EXAMPLE_PORT #define UDP_PORT CONFIG_EXAMPLE_PORT
#define MULTICAST_LOOPBACK CONFIG_EXAMPLE_LOOPBACK #define MULTICAST_LOOPBACK CONFIG_EXAMPLE_LOOPBACK
@ -40,16 +39,7 @@
#define MULTICAST_IPV4_ADDR CONFIG_EXAMPLE_MULTICAST_IPV4_ADDR #define MULTICAST_IPV4_ADDR CONFIG_EXAMPLE_MULTICAST_IPV4_ADDR
#define MULTICAST_IPV6_ADDR CONFIG_EXAMPLE_MULTICAST_IPV6_ADDR #define MULTICAST_IPV6_ADDR CONFIG_EXAMPLE_MULTICAST_IPV6_ADDR
#define LISTEN_DEFAULT_IF CONFIG_EXAMPLE_LISTEN_DEFAULT_IF #define LISTEN_ALL_IF EXAMPLE_MULTICAST_LISTEN_ALL_IF
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
/* The event group allows multiple bits for each event,
we use two - one for IPv4 "got ip", and
one for IPv6 "got ip". */
const int IPV4_GOTIP_BIT = BIT0;
const int IPV6_GOTIP_BIT = BIT1;
static const char *TAG = "multicast"; static const char *TAG = "multicast";
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
@ -59,53 +49,6 @@ static const char *V4TAG = "mcast-ipv4";
static const char *V6TAG = "mcast-ipv6"; static const char *V6TAG = "mcast-ipv6";
#endif #endif
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch(event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
break;
case SYSTEM_EVENT_STA_CONNECTED:
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT);
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
break;
case SYSTEM_EVENT_AP_STA_GOT_IP6:
xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT);
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
/* Add a socket, either IPV4-only or IPV6 dual mode, to the IPV4 /* Add a socket, either IPV4-only or IPV6 dual mode, to the IPV4
@ -116,17 +59,17 @@ static int socket_add_ipv4_multicast_group(int sock, bool assign_source_if)
struct in_addr iaddr = { 0 }; struct in_addr iaddr = { 0 };
int err = 0; int err = 0;
// Configure source interface // Configure source interface
#if USE_DEFAULT_IF #if LISTEN_ALL_IF
imreq.imr_interface.s_addr = IPADDR_ANY; imreq.imr_interface.s_addr = IPADDR_ANY;
#else #else
tcpip_adapter_ip_info_t ip_info = { 0 }; tcpip_adapter_ip_info_t ip_info = { 0 };
err = tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info); err = tcpip_adapter_get_ip_info(EXAMPLE_INTERFACE, &ip_info);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(V4TAG, "Failed to get IP address info. Error 0x%x", err); ESP_LOGE(V4TAG, "Failed to get IP address info. Error 0x%x", err);
goto err; goto err;
} }
inet_addr_from_ip4addr(&iaddr, &ip_info.ip); inet_addr_from_ip4addr(&iaddr, &ip_info.ip);
#endif #endif // LISTEN_ALL_IF
// Configure multicast address to listen to // Configure multicast address to listen to
err = inet_aton(MULTICAST_IPV4_ADDR, &imreq.imr_multiaddr.s_addr); err = inet_aton(MULTICAST_IPV4_ADDR, &imreq.imr_multiaddr.s_addr);
if (err != 1) { if (err != 1) {
@ -248,7 +191,7 @@ static int create_multicast_ipv6_socket()
} }
// Selct the interface to use as multicast source for this socket. // Selct the interface to use as multicast source for this socket.
#if USE_DEFAULT_IF #if LISTEN_ALL_IF
bzero(&if_inaddr.un, sizeof(if_inaddr.un)); bzero(&if_inaddr.un, sizeof(if_inaddr.un));
#else #else
// Read interface adapter link-local address and use it // Read interface adapter link-local address and use it
@ -257,13 +200,13 @@ static int create_multicast_ipv6_socket()
// (Note the interface may have other non-LL IPV6 addresses as well, // (Note the interface may have other non-LL IPV6 addresses as well,
// but it doesn't matter in this context as the address is only // but it doesn't matter in this context as the address is only
// used to identify the interface.) // used to identify the interface.)
err = tcpip_adapter_get_ip6_linklocal(TCPIP_ADAPTER_IF_STA, &if_ipaddr); err = tcpip_adapter_get_ip6_linklocal(EXAMPLE_INTERFACE, &if_ipaddr);
inet6_addr_from_ip6addr(&if_inaddr, &if_ipaddr); inet6_addr_from_ip6addr(&if_inaddr, &if_ipaddr);
if (err != ESP_OK) { if (err != ESP_OK) {
ESP_LOGE(V6TAG, "Failed to get IPV6 LL address. Error 0x%x", err); ESP_LOGE(V6TAG, "Failed to get IPV6 LL address. Error 0x%x", err);
goto err; goto err;
} }
#endif #endif // LISTEN_ALL_IF
// Assign the multicast source interface, via its IP // Assign the multicast source interface, via its IP
err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_inaddr, err = setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, &if_inaddr,
@ -297,11 +240,11 @@ static int create_multicast_ipv6_socket()
// group for listening... // group for listening...
// Configure source interface // Configure source interface
#if USE_DEFAULT_IF #if LISTEN_ALL_IF
v6imreq.imr_interface.s_addr = IPADDR_ANY; v6imreq.imr_interface.s_addr = IPADDR_ANY;
#else #else
inet6_addr_from_ip6addr(&v6imreq.ipv6mr_interface, &if_ipaddr); inet6_addr_from_ip6addr(&v6imreq.ipv6mr_interface, &if_ipaddr);
#endif #endif // LISTEN_ALL_IF
#ifdef CONFIG_EXAMPLE_IPV6 #ifdef CONFIG_EXAMPLE_IPV6
// Configure multicast address to listen to // Configure multicast address to listen to
err = inet6_aton(MULTICAST_IPV6_ADDR, &v6imreq.ipv6mr_multiaddr); err = inet6_aton(MULTICAST_IPV6_ADDR, &v6imreq.ipv6mr_multiaddr);
@ -356,19 +299,6 @@ err:
static void mcast_example_task(void *pvParameters) static void mcast_example_task(void *pvParameters)
{ {
while (1) { while (1) {
/* Wait for all the IPs we care about to be set
*/
uint32_t bits = 0;
#ifdef CONFIG_EXAMPLE_IPV4
bits |= IPV4_GOTIP_BIT;
#endif
#ifdef CONFIG_EXAMPLE_IPV6
bits |= IPV6_GOTIP_BIT;
#endif
ESP_LOGI(TAG, "Waiting for AP connection...");
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
int sock; int sock;
#ifdef CONFIG_EXAMPLE_IPV4_ONLY #ifdef CONFIG_EXAMPLE_IPV4_ONLY
@ -547,7 +477,15 @@ static void mcast_example_task(void *pvParameters)
void app_main() void app_main()
{ {
ESP_ERROR_CHECK( nvs_flash_init() ); ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi(); tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(&mcast_example_task, "mcast_task", 4096, NULL, 5, NULL); xTaskCreate(&mcast_example_task, "mcast_task", 4096, NULL, 5, NULL);
} }

View file

@ -2,5 +2,9 @@
# CMakeLists in this exact order for cmake to work correctly # CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake) include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(udp_server) project(udp_server)

View file

@ -5,5 +5,7 @@
PROJECT_NAME := udp_server PROJECT_NAME := udp_server
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk include $(IDF_PATH)/make/project.mk

View file

@ -56,14 +56,12 @@ Set following parameter under Serial Flasher Options:
Set following parameters under Example Configuration Options: Set following parameters under Example Configuration Options:
* Set `WiFi SSID` of the Router (Access-Point).
* Set `WiFi Password` of the Router (Access-Point).
* Set `IP version` of the example to be IPV4 or IPV6. * Set `IP version` of the example to be IPV4 or IPV6.
* Set `Port` number that represents remote port the example will create. * Set `Port` number that represents remote port the example will create.
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
## Build and Flash ## Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output: Build the project and flash it to the board, then run monitor tool to view serial output:

View file

@ -1,18 +1,5 @@
menu "Example Configuration" menu "Example Configuration"
config WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) for the example to connect to.
config WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) for the example to use.
Can be left blank if the network has no security set.
choice EXAMPLE_IP_MODE choice EXAMPLE_IP_MODE
prompt "IP Version" prompt "IP Version"
help help
@ -23,6 +10,7 @@ menu "Example Configuration"
config EXAMPLE_IPV6 config EXAMPLE_IPV6
bool "IPV6" bool "IPV6"
select EXAMPLE_CONNECT_IPV6
endchoice endchoice

View file

@ -10,99 +10,23 @@
#include <sys/param.h> #include <sys/param.h>
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h" #include "esp_system.h"
#include "esp_wifi.h" #include "esp_wifi.h"
#include "esp_event_loop.h" #include "esp_event.h"
#include "esp_log.h" #include "esp_log.h"
#include "nvs_flash.h" #include "nvs_flash.h"
#include "tcpip_adapter.h"
#include "protocol_examples_common.h"
#include "lwip/err.h" #include "lwip/err.h"
#include "lwip/sockets.h" #include "lwip/sockets.h"
#include "lwip/sys.h" #include "lwip/sys.h"
#include <lwip/netdb.h> #include <lwip/netdb.h>
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define PORT CONFIG_EXAMPLE_PORT #define PORT CONFIG_EXAMPLE_PORT
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
const int IPV4_GOTIP_BIT = BIT0;
const int IPV6_GOTIP_BIT = BIT1;
static const char *TAG = "example"; static const char *TAG = "example";
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
break;
case SYSTEM_EVENT_STA_CONNECTED:
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
/* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
break;
case SYSTEM_EVENT_AP_STA_GOT_IP6:
xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP6");
char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip);
ESP_LOGI(TAG, "IPv6: %s", ip6);
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void wait_for_ip()
{
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT ;
ESP_LOGI(TAG, "Waiting for AP connection...");
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
}
static void udp_server_task(void *pvParameters) static void udp_server_task(void *pvParameters)
{ {
char rx_buffer[128]; char rx_buffer[128];
@ -113,21 +37,21 @@ static void udp_server_task(void *pvParameters)
while (1) { while (1) {
#ifdef CONFIG_EXAMPLE_IPV4 #ifdef CONFIG_EXAMPLE_IPV4
struct sockaddr_in destAddr; struct sockaddr_in dest_addr;
destAddr.sin_addr.s_addr = htonl(INADDR_ANY); dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);
destAddr.sin_family = AF_INET; dest_addr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT); dest_addr.sin_port = htons(PORT);
addr_family = AF_INET; addr_family = AF_INET;
ip_protocol = IPPROTO_IP; ip_protocol = IPPROTO_IP;
inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1); inet_ntoa_r(dest_addr.sin_addr, addr_str, sizeof(addr_str) - 1);
#else // IPV6 #else // IPV6
struct sockaddr_in6 destAddr; struct sockaddr_in6 dest_addr;
bzero(&destAddr.sin6_addr.un, sizeof(destAddr.sin6_addr.un)); bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));
destAddr.sin6_family = AF_INET6; dest_addr.sin6_family = AF_INET6;
destAddr.sin6_port = htons(PORT); dest_addr.sin6_port = htons(PORT);
addr_family = AF_INET6; addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6; ip_protocol = IPPROTO_IPV6;
inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); inet6_ntoa_r(dest_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
#endif #endif
int sock = socket(addr_family, SOCK_DGRAM, ip_protocol); int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
@ -137,20 +61,20 @@ static void udp_server_task(void *pvParameters)
} }
ESP_LOGI(TAG, "Socket created"); ESP_LOGI(TAG, "Socket created");
int err = bind(sock, (struct sockaddr *)&destAddr, sizeof(destAddr)); int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err < 0) { if (err < 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno); ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
} }
ESP_LOGI(TAG, "Socket binded"); ESP_LOGI(TAG, "Socket bound, port %d", PORT);
while (1) { while (1) {
ESP_LOGI(TAG, "Waiting for data"); ESP_LOGI(TAG, "Waiting for data");
struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6 struct sockaddr_in6 source_addr; // Large enough for both IPv4 or IPv6
socklen_t socklen = sizeof(sourceAddr); socklen_t socklen = sizeof(source_addr);
int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&sourceAddr, &socklen); int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
// Error occured during receiving // Error occurred during receiving
if (len < 0) { if (len < 0) {
ESP_LOGE(TAG, "recvfrom failed: errno %d", errno); ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);
break; break;
@ -158,19 +82,19 @@ static void udp_server_task(void *pvParameters)
// Data received // Data received
else { else {
// Get the sender's ip address as string // Get the sender's ip address as string
if (sourceAddr.sin6_family == PF_INET) { if (source_addr.sin6_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1); inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
} else if (sourceAddr.sin6_family == PF_INET6) { } else if (source_addr.sin6_family == PF_INET6) {
inet6_ntoa_r(sourceAddr.sin6_addr, addr_str, sizeof(addr_str) - 1); inet6_ntoa_r(source_addr.sin6_addr, addr_str, sizeof(addr_str) - 1);
} }
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string... 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, "Received %d bytes from %s:", len, addr_str);
ESP_LOGI(TAG, "%s", rx_buffer); ESP_LOGI(TAG, "%s", rx_buffer);
int err = sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&sourceAddr, sizeof(sourceAddr)); int err = sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&source_addr, sizeof(source_addr));
if (err < 0) { if (err < 0) {
ESP_LOGE(TAG, "Error occured during sending: errno %d", errno); ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break; break;
} }
} }
@ -187,9 +111,15 @@ static void udp_server_task(void *pvParameters)
void app_main() void app_main()
{ {
ESP_ERROR_CHECK( nvs_flash_init() ); ESP_ERROR_CHECK(nvs_flash_init());
initialise_wifi(); tcpip_adapter_init();
wait_for_ip(); ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(udp_server_task, "udp_server", 4096, NULL, 5, NULL); xTaskCreate(udp_server_task, "udp_server", 4096, NULL, 5, NULL);
} }