mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'example/ot_tcp_socket' into 'master'
openthread: add ot tcp/udp socket example See merge request espressif/esp-idf!13730
This commit is contained in:
commit
eae45bb41e
@ -3,4 +3,4 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ot_esp_cli)
|
||||
project(esp_ot_cli)
|
||||
|
@ -84,3 +84,162 @@ leader
|
||||
Done
|
||||
```
|
||||
|
||||
## Example1: TCP/UDP server and client
|
||||
|
||||
### Step 1 Configure the project
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Enable the operation: Example Configuration -> Enable custom command in ot-cli -> Enable openthread tcp/udp socket
|
||||
|
||||
### Step 2 Build, Flash, and Run
|
||||
You need to prepare two ESP devices each connected to a 15.4 RCP and flashed with this example.
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
### Step 3 Set up network
|
||||
|
||||
On the first device, run:
|
||||
```bash
|
||||
> extaddr 166e0a0000000001
|
||||
Done
|
||||
> dataset channel 17
|
||||
Done
|
||||
> dataset panid 0xface
|
||||
Done
|
||||
> dataset extpanid 000db80000000000
|
||||
Done
|
||||
> dataset networkname GRL
|
||||
Done
|
||||
> dataset masterkey 00112233445566778899aabbccddeeff
|
||||
Done
|
||||
> dataset meshlocalprefix FD00:0DB8:0000:0000::
|
||||
Done
|
||||
> dataset pskc 00000000000000000000000000000000
|
||||
Done
|
||||
> dataset activetimestamp 1
|
||||
Done
|
||||
> dataset commit active
|
||||
Done
|
||||
> ifconfig up
|
||||
Done
|
||||
> thread start
|
||||
Done
|
||||
|
||||
# After some seconds
|
||||
|
||||
> state
|
||||
leader
|
||||
Done
|
||||
```
|
||||
|
||||
Now the first device has formed a Thread network, on the second device run:
|
||||
|
||||
```bash
|
||||
> extaddr 166e0a0000000002
|
||||
Done
|
||||
> dataset channel 17
|
||||
Done
|
||||
> dataset panid 0xface
|
||||
Done
|
||||
> dataset extpanid 000db80000000000
|
||||
Done
|
||||
> dataset networkname GRL
|
||||
Done
|
||||
> dataset masterkey 00112233445566778899aabbccddeeff
|
||||
Done
|
||||
> dataset meshlocalprefix FD00:0DB8:0000:0000::
|
||||
Done
|
||||
> dataset pskc 00000000000000000000000000000000
|
||||
Done
|
||||
> dataset activetimestamp 1
|
||||
Done
|
||||
> dataset commit active
|
||||
Done
|
||||
> ifconfig up
|
||||
Done
|
||||
> thread start
|
||||
Done
|
||||
|
||||
# After some seconds
|
||||
|
||||
> state
|
||||
router # child is also a valid state
|
||||
Done
|
||||
```
|
||||
|
||||
Now the second device has joined the Thread network and acting as a router (or a child).
|
||||
|
||||
### Step 4 Set up tcp/udp socket server and client
|
||||
|
||||
In leader device, run this command in command line shell.
|
||||
|
||||
```bash
|
||||
# for setup a tcp server
|
||||
> tcpsockserver
|
||||
|
||||
# for setup an udp server
|
||||
> udpsockserver
|
||||
```
|
||||
|
||||
Then run this command to get the leader IPv6 address.
|
||||
|
||||
```bash
|
||||
> ipaddr
|
||||
fd00:db8:0:0:0:ff:fe00:fc00
|
||||
fd00:db8:0:0:0:ff:fe00:ac00
|
||||
fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
fe80:0:0:0:146e:a00:0:1
|
||||
```
|
||||
|
||||
In router device, run this command to set up a socket client in command line shell.
|
||||
|
||||
```bash
|
||||
# for setup a tcp client
|
||||
> tcpsockclient fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
|
||||
# for setup an udp client
|
||||
> udpsockclient fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
```
|
||||
|
||||
You will get
|
||||
|
||||
```bash
|
||||
# in leader device
|
||||
|
||||
> tcpsockserver
|
||||
I(173437) OPENTHREAD:[INFO]-CLI-----: execute command: tcpsockserver
|
||||
> I (173437) ot_secket: Socket created
|
||||
I (173437) ot_secket: Socket bound, port 12345
|
||||
I (173457) ot_secket: Socket listening, timeout is 30 seconds
|
||||
I(175007) OPENTHREAD:[INFO]-MLE-----: Send Advertisement (ff02:0:0:0:0:0:0:1)
|
||||
|
||||
......
|
||||
|
||||
I (182187) ot_secket: Received 28 bytes from client:
|
||||
I (182187) ot_secket: This message is from client
|
||||
I (182187) ot_secket: Socket accepted ip address: FD00:DB8::498:DDB:EC7:49DC
|
||||
I (182189) ot_secket: Socket server is closed.
|
||||
|
||||
# in router device
|
||||
|
||||
> tcpsockclient fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
I(37731) OPENTHREAD:[INFO]-CLI-----: execute command: tcpsockclient fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
> I (37741) ot_secket: Socket created, connecting to b80d00fd:0:4acb4a28:422a3bcb:12345
|
||||
I(37751) OPENTHREAD:[INFO]-ARP-----: Sending address query for fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
|
||||
......
|
||||
|
||||
I (38171) ot_secket: Successfully connected
|
||||
|
||||
......
|
||||
|
||||
I (38321) ot_secket: Received 28 bytes from fd00:db8:0:0:284a:cb4a:cb3b:2a42
|
||||
I (38321) ot_secket: This message is from server
|
||||
I (38323) ot_secket: Socket client is closed.
|
||||
```
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
idf_component_register(SRCS "ot_esp_cli.c"
|
||||
idf_component_register(SRCS "esp_ot_udp_socket.c" "esp_ot_tcp_socket.c" "esp_ot_cli_extension.c" "esp_ot_cli.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
31
examples/openthread/ot_cli/main/Kconfig.projbuild
Normal file
31
examples/openthread/ot_cli/main/Kconfig.projbuild
Normal file
@ -0,0 +1,31 @@
|
||||
menu "Openthread"
|
||||
|
||||
menuconfig OPENTHREAD_CUSTOM_COMMAND
|
||||
bool "Enable custom command in ot-cli"
|
||||
default n
|
||||
|
||||
config OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
bool "Enable openthread tcp socket"
|
||||
depends on OPENTHREAD_CUSTOM_COMMAND
|
||||
default n
|
||||
|
||||
config OPENTHEAD_EXAMPLE_TCP_SERVER_PORT
|
||||
int "the port of TCP server"
|
||||
default 12345
|
||||
depends on OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
help
|
||||
Set the connect port of socket
|
||||
|
||||
config OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
bool "Enable openthread udp socket"
|
||||
depends on OPENTHREAD_CUSTOM_COMMAND
|
||||
default n
|
||||
|
||||
config OPENTHEAD_EXAMPLE_UDP_SERVER_PORT
|
||||
int "the port of UDP server"
|
||||
default 54321
|
||||
depends on OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
help
|
||||
Set the connect port of socket
|
||||
|
||||
endmenu
|
@ -33,6 +33,10 @@
|
||||
#include "openthread/instance.h"
|
||||
#include "openthread/tasklet.h"
|
||||
|
||||
#if CONFIG_OPENTHREAD_CUSTOM_COMMAND
|
||||
#include "esp_ot_cli_extension.h"
|
||||
#endif // CONFIG_OPENTHREAD_CUSTOM_COMMAND
|
||||
|
||||
#define TAG "ot_esp_cli"
|
||||
|
||||
extern void otAppCliInit(otInstance *instance);
|
||||
@ -100,6 +104,9 @@ static void ot_task_worker(void *aContext)
|
||||
esp_openthread_lock_acquire(portMAX_DELAY);
|
||||
otAppCliInit(instance);
|
||||
esp_openthread_lock_release();
|
||||
#if CONFIG_OPENTHREAD_CUSTOM_COMMAND
|
||||
esp_cli_custom_command_init();
|
||||
#endif // CONFIG_OPENTHREAD_CUSTOM_COMMAND
|
||||
|
||||
while (true) {
|
||||
FD_ZERO(&mainloop.read_fds);
|
39
examples/openthread/ot_cli/main/esp_ot_cli_extension.c
Normal file
39
examples/openthread/ot_cli/main/esp_ot_cli_extension.c
Normal file
@ -0,0 +1,39 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp_openthread.h"
|
||||
#include "esp_ot_cli_extension.h"
|
||||
#include "esp_ot_tcp_socket.h"
|
||||
#include "esp_ot_udp_socket.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
#include "freertos/task.h"
|
||||
#include "openthread/cli.h"
|
||||
|
||||
static const otCliCommand kCommands[] = {
|
||||
#if CONFIG_OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
{"tcpsockserver", esp_ot_process_tcp_server},
|
||||
{"tcpsockclient", esp_ot_process_tcp_client},
|
||||
#endif // CONFIG_OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
#if CONFIG_OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
{"udpsockserver", esp_ot_process_udp_server},
|
||||
{"udpsockclient", esp_ot_process_udp_client},
|
||||
#endif // CONFIG_OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
};
|
||||
|
||||
void esp_cli_custom_command_init()
|
||||
{
|
||||
otInstance *instance = esp_openthread_get_instance();
|
||||
otCliSetUserCommands(kCommands, (sizeof(kCommands) / sizeof(kCommands[0])), instance);
|
||||
}
|
28
examples/openthread/ot_cli/main/esp_ot_cli_extension.h
Normal file
28
examples/openthread/ot_cli/main/esp_ot_cli_extension.h
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Init the custom command.
|
||||
*
|
||||
*/
|
||||
void esp_cli_custom_command_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
165
examples/openthread/ot_cli/main/esp_ot_tcp_socket.c
Normal file
165
examples/openthread/ot_cli/main/esp_ot_tcp_socket.c
Normal file
@ -0,0 +1,165 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_ot_tcp_socket.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#if CONFIG_OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
#define TAG "ot_socket"
|
||||
|
||||
static void tcp_socket_server_task(void *pvParameters)
|
||||
{
|
||||
char addr_str[128];
|
||||
char payload[] = "This message is from server\n";
|
||||
char rx_buffer[128];
|
||||
esp_err_t ret = ESP_OK;
|
||||
int err = 0;
|
||||
int len = 0;
|
||||
int listen_sock;
|
||||
int opt = 1;
|
||||
int port = CONFIG_OPENTHEAD_EXAMPLE_TCP_SERVER_PORT;
|
||||
int client_sock = 0;
|
||||
struct timeval timeout;
|
||||
struct sockaddr_storage source_addr; // Large enough for both IPv6
|
||||
struct sockaddr_in6 listen_addr = { 0 };
|
||||
// The TCP server listen at the address "::", which means all addresses can be listened to.
|
||||
inet6_aton("::", &listen_addr.sin6_addr);
|
||||
listen_addr.sin6_family = AF_INET6;
|
||||
listen_addr.sin6_port = htons(port);
|
||||
|
||||
listen_sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
|
||||
ESP_GOTO_ON_FALSE((listen_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
|
||||
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
// Note that by default IPV6 binds to both protocols, it is must be disabled
|
||||
// if both protocols used at the same time (used in CI)
|
||||
setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
|
||||
|
||||
ESP_LOGI(TAG, "Socket created");
|
||||
|
||||
err = bind(listen_sock, (struct sockaddr *)&listen_addr, sizeof(struct sockaddr_in6) );
|
||||
ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d, IPPROTO: %d", errno, AF_INET6);
|
||||
ESP_LOGI(TAG, "Socket bound, port %d", port);
|
||||
|
||||
err = listen(listen_sock, 1);
|
||||
ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Error occurred during listen: errno %d", errno);
|
||||
|
||||
//blocking-mode accept, set timeout 30 seconds
|
||||
timeout.tv_sec = 30;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
ESP_LOGI(TAG, "Socket listening, timeout is 30 seconds");
|
||||
|
||||
socklen_t addr_len = sizeof(source_addr);
|
||||
client_sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
|
||||
ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_FAIL, exit, TAG, "Unable to accept connection: errno %d", errno);
|
||||
|
||||
ESP_GOTO_ON_FALSE((err >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
|
||||
|
||||
//blocking-mode receive, set timeout 30 seconds
|
||||
timeout.tv_sec = 30;
|
||||
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
len = recv(client_sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
|
||||
// Error occurred during receiving
|
||||
ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recv failed: errno %d", errno);
|
||||
// Data received
|
||||
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
|
||||
ESP_LOGI(TAG, "Received %d bytes from client:", len);
|
||||
ESP_LOGI(TAG, "%s", rx_buffer);
|
||||
|
||||
// Convert ip address to string
|
||||
inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);
|
||||
ESP_LOGI(TAG, "Socket accepted ip address: %s", addr_str);
|
||||
exit:
|
||||
if (ret != ESP_OK || listen_sock != -1) {
|
||||
shutdown(listen_sock, 0);
|
||||
close(listen_sock);
|
||||
}
|
||||
if (client_sock != -1) {
|
||||
shutdown(client_sock, 0);
|
||||
close(client_sock);
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket server is closed.");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void tcp_socket_client_task(void *pvParameters)
|
||||
{
|
||||
char *host_ip = (char *)pvParameters;
|
||||
char *payload = "This message is from client\n";
|
||||
char rx_buffer[128];
|
||||
esp_err_t ret = ESP_OK;
|
||||
int client_sock;
|
||||
int err = 0;
|
||||
int len = 0;
|
||||
int port = CONFIG_OPENTHEAD_EXAMPLE_TCP_SERVER_PORT;
|
||||
struct sockaddr_in6 dest_addr = { 0 };
|
||||
|
||||
inet6_aton(host_ip, &dest_addr.sin6_addr);
|
||||
dest_addr.sin6_family = AF_INET6;
|
||||
dest_addr.sin6_port = htons(port);
|
||||
|
||||
client_sock = socket(AF_INET6, SOCK_STREAM, IPPROTO_IPV6);
|
||||
ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
|
||||
|
||||
ESP_LOGI(TAG, "Socket created, connecting to %x:%x:%x:%x:%d", dest_addr.sin6_addr.un.u32_addr[0], dest_addr.sin6_addr.un.u32_addr[1], dest_addr.sin6_addr.un.u32_addr[2], dest_addr.sin6_addr.un.u32_addr[3], port);
|
||||
|
||||
err = connect(client_sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
|
||||
ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to connect: errno %d", errno);
|
||||
ESP_LOGI(TAG, "Successfully connected");
|
||||
|
||||
len = send(client_sock, payload, strlen(payload), 0);
|
||||
ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
|
||||
|
||||
len = recv(client_sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
|
||||
// Error occurred during receiving
|
||||
ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recv failed: errno %d", errno);
|
||||
// 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, host_ip);
|
||||
ESP_LOGI(TAG, "%s", rx_buffer);
|
||||
|
||||
exit:
|
||||
if (ret != ESP_OK || client_sock != -1) {
|
||||
shutdown(client_sock, 0);
|
||||
close(client_sock);
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket client is closed.");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void esp_ot_process_tcp_server(void *aContext, uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
(void)(aContext);
|
||||
(void)(aArgsLength);
|
||||
(void)(*aArgs);
|
||||
xTaskCreate(tcp_socket_server_task, "ot_tcp_scoket_server", 4096, xTaskGetCurrentTaskHandle(), 4, NULL);
|
||||
}
|
||||
|
||||
void esp_ot_process_tcp_client(void *aContext, uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
(void)(aContext);
|
||||
(void)(aArgsLength);
|
||||
if (aArgs[0] == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid arguments.");
|
||||
} else {
|
||||
xTaskCreate(tcp_socket_client_task, "ot_tcp_socket_client", 4096, aArgs[0], 4, NULL);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
37
examples/openthread/ot_cli/main/esp_ot_tcp_socket.h
Normal file
37
examples/openthread/ot_cli/main/esp_ot_tcp_socket.h
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
/**
|
||||
* @brief User command "tcpsockserver" process.
|
||||
*
|
||||
*/
|
||||
void esp_ot_process_tcp_server(void *aContext, uint8_t aArgsLength, char *aArgs[]);
|
||||
|
||||
/**
|
||||
* @brief User command "tcpsockclient" process.
|
||||
*
|
||||
*/
|
||||
void esp_ot_process_tcp_client(void *aContext, uint8_t aArgsLength, char *aArgs[]);
|
||||
|
||||
#endif // CONFIG_OPENTHREAD_ENABLE_TCP_SOCKET_EXAMPLE
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
145
examples/openthread/ot_cli/main/esp_ot_udp_socket.c
Normal file
145
examples/openthread/ot_cli/main/esp_ot_udp_socket.c
Normal file
@ -0,0 +1,145 @@
|
||||
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp_check.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_ot_udp_socket.h"
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#if CONFIG_OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
#define TAG "ot_socket"
|
||||
|
||||
static void udp_socket_server_task(void *pvParameters)
|
||||
{
|
||||
char addr_str[128];
|
||||
char *payload = "This message is from server\n";
|
||||
char rx_buffer[128];
|
||||
esp_err_t ret = ESP_OK;
|
||||
int err = 0;
|
||||
int len;
|
||||
int listen_sock;
|
||||
int port = CONFIG_OPENTHEAD_EXAMPLE_UDP_SERVER_PORT;
|
||||
struct timeval timeout;
|
||||
struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
|
||||
struct sockaddr_in6 listen_addr;
|
||||
|
||||
inet6_aton("::", &listen_addr.sin6_addr);
|
||||
listen_addr.sin6_family = AF_INET6;
|
||||
listen_addr.sin6_port = htons(port);
|
||||
|
||||
listen_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
|
||||
ESP_GOTO_ON_FALSE((listen_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
|
||||
ESP_LOGI(TAG, "Socket created");
|
||||
|
||||
// Note that by default IPV6 binds to both protocols, it is must be disabled
|
||||
// if both protocols used at the same time (used in CI)
|
||||
int opt = 1;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
||||
setsockopt(listen_sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));
|
||||
|
||||
err = bind(listen_sock, (struct sockaddr *)&listen_addr, sizeof(listen_addr));
|
||||
ESP_GOTO_ON_FALSE((err == 0), ESP_FAIL, exit, TAG, "Socket unable to bind: errno %d", errno);
|
||||
ESP_LOGI(TAG, "Socket bound, port %d", port);
|
||||
|
||||
timeout.tv_sec = 30;
|
||||
setsockopt(listen_sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
|
||||
ESP_LOGI(TAG, "Waiting for data, timeout is 30 seconds");
|
||||
socklen_t socklen = sizeof(source_addr);
|
||||
len = recvfrom(listen_sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
|
||||
|
||||
// Error occurred during receiving
|
||||
ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recvfrom failed: errno %d", errno);
|
||||
// Data received
|
||||
// Get the sender's ip address as string
|
||||
inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);
|
||||
|
||||
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);
|
||||
|
||||
err = sendto(listen_sock, payload, strlen(payload), 0, (struct sockaddr *)&source_addr, sizeof(source_addr));
|
||||
ESP_GOTO_ON_FALSE((err >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
|
||||
exit:
|
||||
if (ret != ESP_OK || listen_sock != -1) {
|
||||
shutdown(listen_sock, 0);
|
||||
close(listen_sock);
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket server is closed.");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
static void udp_socket_client_task(void *pvParameters)
|
||||
{
|
||||
char rx_buffer[128];
|
||||
char *host_ip = (char *)pvParameters;
|
||||
char *payload = "This message is from client\n";
|
||||
int client_sock;
|
||||
int port = CONFIG_OPENTHEAD_EXAMPLE_UDP_SERVER_PORT;
|
||||
int err = 0;
|
||||
int len;
|
||||
esp_err_t ret = ESP_OK;
|
||||
struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
|
||||
struct sockaddr_in6 dest_addr = { 0 };
|
||||
|
||||
inet6_aton(host_ip, &dest_addr.sin6_addr);
|
||||
dest_addr.sin6_family = AF_INET6;
|
||||
dest_addr.sin6_port = htons(port);
|
||||
|
||||
client_sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_IPV6);
|
||||
ESP_GOTO_ON_FALSE((client_sock >= 0), ESP_OK, exit, TAG, "Unable to create socket: errno %d", errno);
|
||||
ESP_LOGI(TAG, "Socket created, sending to %s:%d", host_ip, port);
|
||||
|
||||
err = sendto(client_sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
|
||||
ESP_GOTO_ON_FALSE((err >= 0), ESP_FAIL, exit, TAG, "Error occurred during sending: errno %d", errno);
|
||||
ESP_LOGI(TAG, "Message sent");
|
||||
|
||||
socklen_t socklen = sizeof(source_addr);
|
||||
len = recvfrom(client_sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
|
||||
|
||||
// Error occurred during receiving
|
||||
ESP_GOTO_ON_FALSE((len >= 0), ESP_FAIL, exit, TAG, "recvfrom failed: errno %d", errno);
|
||||
// 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, host_ip);
|
||||
ESP_LOGI(TAG, "%s", rx_buffer);
|
||||
exit:
|
||||
if (ret != ESP_OK || client_sock != -1) {
|
||||
shutdown(client_sock, 0);
|
||||
close(client_sock);
|
||||
}
|
||||
ESP_LOGI(TAG, "Socket client is closed");
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void esp_ot_process_udp_server(void *aContext, uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
(void)(aContext);
|
||||
(void)(aArgsLength);
|
||||
xTaskCreate(udp_socket_server_task, "ot_udp_scoket_server", 4096, xTaskGetCurrentTaskHandle(), 4, NULL);
|
||||
}
|
||||
|
||||
void esp_ot_process_udp_client(void *aContext, uint8_t aArgsLength, char *aArgs[])
|
||||
{
|
||||
(void)(aContext);
|
||||
(void)(aArgsLength);
|
||||
if (aArgs[0] == NULL) {
|
||||
ESP_LOGE(TAG, "Invalid arguments.");
|
||||
} else {
|
||||
xTaskCreate(udp_socket_client_task, "ot_udp_socket_client", 4096, aArgs[0], 4, NULL);
|
||||
}
|
||||
}
|
||||
#endif // CONFIG_OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
37
examples/openthread/ot_cli/main/esp_ot_udp_socket.h
Normal file
37
examples/openthread/ot_cli/main/esp_ot_udp_socket.h
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if CONFIG_OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
/**
|
||||
* @brief User command "udpsockserver" process.
|
||||
*
|
||||
*/
|
||||
void esp_ot_process_udp_server(void *aContext, uint8_t aArgsLength, char *aArgs[]);
|
||||
|
||||
/**
|
||||
* @brief Yser command "udpsockserver" process.
|
||||
*
|
||||
*/
|
||||
void esp_ot_process_udp_client(void *aContext, uint8_t aArgsLength, char *aArgs[]);
|
||||
#endif // CONFIG_OPENTHREAD_ENABLE_UDP_SOCKET_EXAMPLE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user