BSD Socket examples

This commit is contained in:
MartinValik
2018-10-02 16:33:16 +02:00
parent 4faa2a8e52
commit 5a76f1af19
40 changed files with 1669 additions and 0 deletions
@@ -0,0 +1,6 @@
# The following five lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(tcp_client)
@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := tcp_client
include $(IDF_PATH)/make/project.mk
@@ -0,0 +1,74 @@
# TCP Client example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
The application creates a TCP socket and tries to connect to the server with predefined IP address and port number. When a connection is successfully established, the application sends message and waits for the answer. After the server's reply, application prints received reply as ASCII text, waits for 2 seconds and sends another message.
## How to use example
In order to create TCP server that communicates with TCP Client example, choose one of the following options.
There are many host-side tools which can be used to interact with the UDP/TCP server/client.
One command line tool is [netcat](http://netcat.sourceforge.net) which can send and receive many kinds of packets.
Note: please replace `192.168.0.167 3333` with desired IPV4/IPV6 address (displayed in monitor console) and port number in the following command.
In addition to those tools, simple Python scripts can be found under sockets/scripts directory. Every script is designed to interact with one of the examples.
### TCP server using netcat
```
nc -l 192.168.0.167 -p 3333
```
### Python scripts
Script tcpserver.py contains configuration for port number and IP version (IPv4 or IPv6) that has to be altered to match the values used by the application. Example:
```
IP_VERSION = 'IPv4'
PORT = 3333;
```
## Hardware Required
This example can be run on any commonly available ESP32 development board.
## Configure the project
```
make menuconfig
```
Set following parameter under Serial Flasher Options:
* Set `Default serial port`.
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 `IPV4 Address` in case your chose IP version IPV4 above.
* Set `IPV6 Address` in case your chose IP version IPV6 above.
* Set `Port` number that represents remote port the example will connect to.
## Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Troubleshooting
Start server first, to receive data sent from the client (application).
@@ -0,0 +1,4 @@
set(COMPONENT_SRCS "tcp_client.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
@@ -0,0 +1,50 @@
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
prompt "IP Version"
help
Example can use either IPV4 or IPV6.
config EXAMPLE_IPV4
bool "IPV4"
config EXAMPLE_IPV6
bool "IPV6"
endchoice
config EXAMPLE_IPV4_ADDR
string "IPV4 Address"
default "192.168.0.165"
depends on EXAMPLE_IPV4
help
The example will connect to this IPV4 address.
config EXAMPLE_IPV6_ADDR
string "IPV6 Address"
default "FE80::30AD:E57B:C212:68AD"
depends on EXAMPLE_IPV6
help
The example will connect to this IPV6 address.
config EXAMPLE_PORT
int "Port"
range 0 65535
default 3333
help
The remote port to which the client example will connect to.
endmenu
@@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
@@ -0,0 +1,192 @@
/* 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 <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_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.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
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#else
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#endif
#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 *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)
{
char rx_buffer[128];
char addr_str[128];
int addr_family;
int ip_protocol;
while (1) {
#ifdef CONFIG_EXAMPLE_IPV4
struct sockaddr_in destAddr;
destAddr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1);
#else // IPV6
struct sockaddr_in6 destAddr;
inet6_aton(HOST_IP_ADDR, &destAddr.sin6_addr);
destAddr.sin6_family = AF_INET6;
destAddr.sin6_port = htons(PORT);
addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6;
inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1);
#endif
int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created");
int err = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
}
ESP_LOGI(TAG, "Successfully connected");
while (1) {
int err = send(sock, payload, strlen(payload), 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occured during sending: errno %d", errno);
break;
}
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occured during receiving
if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno);
break;
}
// Data received
else {
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(2000 / portTICK_PERIOD_MS);
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
vTaskDelete(NULL);
}
void app_main()
{
ESP_ERROR_CHECK( nvs_flash_init() );
initialise_wifi();
wait_for_ip();
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}