Merge branch 'feature/update_coap_from_idf' into 'master'

Feature/update coap from idf

See merge request sdk/ESP8266_RTOS_SDK!1318
This commit is contained in:
Dong Heng
2020-09-18 15:35:33 +08:00
126 changed files with 1861 additions and 25214 deletions

View File

@ -1,4 +1,4 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# The following 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)

View File

@ -16,7 +16,7 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf)
### Configure the project
```
make menuconfig
idf.py menuconfig
```
* Set serial port under Serial Flasher config
@ -29,7 +29,7 @@ make menuconfig
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 flash monitor
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
@ -37,7 +37,8 @@ make -j4 flash monitor
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
Prerequisite: we startup a CoAP server on coap server example.
Prerequisite: we startup a CoAP server on coap server example,
or use the default of coap://californium.eclipse.org.
and you could receive data from CoAP server if succeed,
such as the following log:
@ -54,12 +55,26 @@ I (1692) wifi: pm start, type: 1
I (2582) event: sta ip: 192.168.3.89, mask: 255.255.255.0, gw: 192.168.3.1
I (2582) CoAP_client: Connected to AP
I (2582) CoAP_client: DNS lookup succeeded. IP=192.168.3.84
Received: Hello World!
E (8102) CoAP_client: select timeout
E (13102) CoAP_client: select timeout
I (2582) CoAP_client: DNS lookup succeeded. IP=104.196.15.150
Received:
************************************************************
CoAP RFC 7252 Cf 2.0.0-SNAPSHOT
************************************************************
This server is using the Eclipse Californium (Cf) CoAP framework
published under EPL+EDL: http://www.eclipse.org/californium/
(c) 2014, 2015, 2016 Institute for Pervasive Computing, ETH Zurich and others
************************************************************
...
```
## libcoap Documentation
This can be found at https://libcoap.net/doc/reference/4.2.0/
## Troubleshooting
* Please make sure Target Url includes valid `host`, `port`, `path`, and begins with `coap://`
* Please make sure Target Url includes valid `host`, optional `port`, optional `path`, and begins
with `coap://` or `coap+tcp://` for a coap server that supports TCP
(not all do including coap+tcp://californium.eclipse.org).
* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0`
to `#define COAP_LOGGING_LEVEL 9`

View File

@ -1,4 +1,2 @@
set(COMPONENT_SRCS "coap_client_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
idf_component_register(SRCS "coap_client_example_main.c"
INCLUDE_DIRS ".")

View File

@ -1,9 +1,9 @@
menu "Example Configuration"
config TARGET_DOMAIN_URI
string "Target Uri"
default "coap://californium.eclipse.org"
help
Target uri for the example to use.
config TARGET_DOMAIN_URI
string "Target Uri"
default "coap://californium.eclipse.org"
help
Target uri for the example to use.
endmenu
endmenu

View File

@ -13,21 +13,25 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "coap.h"
#define COAP_DEFAULT_TIME_SEC 5
#define COAP_DEFAULT_TIME_USEC 0
/* Set this to 9 to get verbose logging from within libcoap */
#define COAP_LOGGING_LEVEL 0
/* The examples use uri "coap://californium.eclipse.org" that
you can set via 'make menuconfig'.
you can set via the project configuration (idf.py menuconfig)
If you'd rather not, just change the below entries to strings with
the config you want - ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org"
@ -36,17 +40,88 @@
const static char *TAG = "CoAP_client";
static void message_handler(struct coap_context_t *ctx, const coap_endpoint_t *local_interface, const coap_address_t *remote,
static int resp_wait = 1;
static coap_optlist_t *optlist = NULL;
static int wait_ms;
static void message_handler(coap_context_t *ctx, coap_session_t *session,
coap_pdu_t *sent, coap_pdu_t *received,
const coap_tid_t id)
{
unsigned char* data = NULL;
size_t data_len;
if (COAP_RESPONSE_CLASS(received->hdr->code) == 2) {
if (coap_get_data(received, &data_len, &data)) {
printf("Received: %s\n", data);
coap_pdu_t *pdu = NULL;
coap_opt_t *block_opt;
coap_opt_iterator_t opt_iter;
unsigned char buf[4];
coap_optlist_t *option;
coap_tid_t tid;
if (COAP_RESPONSE_CLASS(received->code) == 2) {
/* Need to see if blocked response */
block_opt = coap_check_option(received, COAP_OPTION_BLOCK2, &opt_iter);
if (block_opt) {
uint16_t blktype = opt_iter.type;
if (coap_opt_block_num(block_opt) == 0) {
printf("Received:\n");
}
if (coap_get_data(received, &data_len, &data)) {
printf("%.*s", (int)data_len, data);
}
if (COAP_OPT_BLOCK_MORE(block_opt)) {
/* more bit is set */
/* create pdu with request for next block */
pdu = coap_new_pdu(session);
if (!pdu) {
ESP_LOGE(TAG, "coap_new_pdu() failed");
goto clean_up;
}
pdu->type = COAP_MESSAGE_CON;
pdu->tid = coap_new_message_id(session);
pdu->code = COAP_REQUEST_GET;
/* add URI components from optlist */
for (option = optlist; option; option = option->next ) {
switch (option->number) {
case COAP_OPTION_URI_HOST :
case COAP_OPTION_URI_PORT :
case COAP_OPTION_URI_PATH :
case COAP_OPTION_URI_QUERY :
coap_add_option(pdu, option->number, option->length,
option->data);
break;
default:
; /* skip other options */
}
}
/* finally add updated block option from response, clear M bit */
/* blocknr = (blocknr & 0xfffffff7) + 0x10; */
coap_add_option(pdu,
blktype,
coap_encode_var_safe(buf, sizeof(buf),
((coap_opt_block_num(block_opt) + 1) << 4) |
COAP_OPT_BLOCK_SZX(block_opt)), buf);
tid = coap_send(session, pdu);
if (tid != COAP_INVALID_TID) {
resp_wait = 1;
wait_ms = COAP_DEFAULT_TIME_SEC * 1000;
return;
}
}
printf("\n");
} else {
if (coap_get_data(received, &data_len, &data)) {
printf("Received: %.*s\n", (int)data_len, data);
}
}
}
clean_up:
resp_wait = 0;
}
static void coap_example_task(void *p)
@ -54,27 +129,49 @@ static void coap_example_task(void *p)
struct hostent *hp;
struct ip4_addr *ip4_addr;
coap_context_t* ctx = NULL;
coap_address_t dst_addr, src_addr;
static coap_uri_t uri;
fd_set readfds;
struct timeval tv;
int flags, result;
coap_pdu_t* request = NULL;
const char* server_uri = COAP_DEFAULT_DEMO_URI;
uint8_t get_method = 1;
char* phostname = NULL;
coap_set_log_level(COAP_LOGGING_LEVEL);
while (1) {
#define BUFSIZE 40
unsigned char _buf[BUFSIZE];
unsigned char *buf;
size_t buflen;
int res;
coap_context_t *ctx = NULL;
coap_session_t *session = NULL;
coap_pdu_t *request = NULL;
optlist = NULL;
if (coap_split_uri((const uint8_t *)server_uri, strlen(server_uri), &uri) == -1) {
ESP_LOGE(TAG, "CoAP server uri error");
break;
}
hp = gethostbyname((const char *)uri.host.s);
if ((uri.scheme==COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) ||
(uri.scheme==COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) {
ESP_LOGE(TAG, "CoAP server uri scheme error");
break;
}
phostname = (char *)calloc(1, uri.host.length + 1);
if (phostname == NULL) {
ESP_LOGE(TAG, "calloc failed");
continue;
}
memcpy(phostname, uri.host.s, uri.host.length);
hp = gethostbyname(phostname);
free(phostname);
if (hp == NULL) {
ESP_LOGE(TAG, "DNS lookup failed");
vTaskDelay(1000 / portTICK_PERIOD_MS);
free(phostname);
continue;
}
@ -89,46 +186,94 @@ static void coap_example_task(void *p)
src_addr.addr.sin.sin_port = htons(0);
src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
ctx = coap_new_context(&src_addr);
if (ctx) {
coap_address_init(&dst_addr);
dst_addr.addr.sin.sin_family = AF_INET;
dst_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
if (uri.path.length) {
buflen = BUFSIZE;
buf = _buf;
res = coap_split_path(uri.path.s, uri.path.length, buf, &buflen);
request = coap_new_pdu();
if (request){
request->hdr->type = COAP_MESSAGE_CON;
request->hdr->id = coap_new_message_id(ctx);
request->hdr->code = get_method;
coap_add_option(request, COAP_OPTION_URI_PATH, uri.path.length, uri.path.s);
while (res--) {
coap_insert_optlist(&optlist,
coap_new_optlist(COAP_OPTION_URI_PATH,
coap_opt_length(buf),
coap_opt_value(buf)));
coap_register_response_handler(ctx, message_handler);
coap_send_confirmed(ctx, ctx->endpoint, &dst_addr, request);
flags = fcntl(ctx->sockfd, F_GETFL, 0);
fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK);
tv.tv_usec = COAP_DEFAULT_TIME_USEC;
tv.tv_sec = COAP_DEFAULT_TIME_SEC;
for(;;) {
FD_ZERO(&readfds);
FD_CLR( ctx->sockfd, &readfds );
FD_SET( ctx->sockfd, &readfds );
result = select( ctx->sockfd+1, &readfds, 0, 0, &tv );
if (result > 0) {
if (FD_ISSET( ctx->sockfd, &readfds ))
coap_read(ctx);
} else if (result < 0) {
break;
} else {
ESP_LOGE(TAG, "select timeout");
}
}
buf += coap_opt_size(buf);
}
coap_free_context(ctx);
}
if (uri.query.length) {
buflen = BUFSIZE;
buf = _buf;
res = coap_split_query(uri.query.s, uri.query.length, buf, &buflen);
while (res--) {
coap_insert_optlist(&optlist,
coap_new_optlist(COAP_OPTION_URI_QUERY,
coap_opt_length(buf),
coap_opt_value(buf)));
buf += coap_opt_size(buf);
}
}
ctx = coap_new_context(NULL);
if (!ctx) {
ESP_LOGE(TAG, "coap_new_context() failed");
goto clean_up;
}
coap_address_init(&dst_addr);
dst_addr.addr.sin.sin_family = AF_INET;
dst_addr.addr.sin.sin_port = htons(uri.port);
dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
session = coap_new_client_session(ctx, &src_addr, &dst_addr,
uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
uri.scheme==COAP_URI_SCHEME_COAPS_TCP ? COAP_PROTO_TLS :
uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_UDP);
if (!session) {
ESP_LOGE(TAG, "coap_new_client_session() failed");
goto clean_up;
}
coap_register_response_handler(ctx, message_handler);
request = coap_new_pdu(session);
if (!request) {
ESP_LOGE(TAG, "coap_new_pdu() failed");
goto clean_up;
}
request->type = COAP_MESSAGE_CON;
request->tid = coap_new_message_id(session);
request->code = COAP_REQUEST_GET;
coap_add_optlist_pdu(request, &optlist);
resp_wait = 1;
coap_send(session, request);
wait_ms = COAP_DEFAULT_TIME_SEC * 1000;
while (resp_wait) {
int result = coap_run_once(ctx, wait_ms > 1000 ? 1000 : wait_ms);
if (result >= 0) {
if (result >= wait_ms) {
ESP_LOGE(TAG, "select timeout");
break;
} else {
wait_ms -= result;
}
}
}
clean_up:
if (optlist) {
coap_delete_optlist(optlist);
optlist = NULL;
}
if (session) coap_session_release(session);
if (ctx) coap_free_context(ctx);
coap_cleanup();
/* Only send the request off once */
break;
}
vTaskDelete(NULL);
@ -136,12 +281,15 @@ static void coap_example_task(void *p)
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_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(coap_example_task, "coap", 2048, NULL, 5, NULL);
xTaskCreate(coap_example_task, "coap", 5 * 1024, NULL, 5, NULL);
}

View File

@ -0,0 +1 @@
CONFIG_ENABLE_COAP=y

View File

@ -1,4 +1,4 @@
# The following four lines of boilerplate have to be in your project's CMakeLists
# The following 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)

View File

@ -16,7 +16,7 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf)
### Configure the project
```
make menuconfig
idf.py menuconfig
```
* Set default serial port under Serial Flasher config
@ -28,7 +28,7 @@ make menuconfig
Build the project and flash it to the board, then run monitor tool to view serial output:
```
make -j4 flash monitor
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
@ -51,13 +51,18 @@ I (1692) wifi: pm start, type: 1
I (2622) event: sta ip: 192.168.3.84, mask: 255.255.255.0, gw: 192.168.3.1
I (2622) CoAP_server: Connected to AP
E (7622) CoAP_server: select timeout
E (12622) CoAP_server: select timeout
E (17622) CoAP_server: select timeout
...
```
if a CoAP client query `/Espressif` resource, CoAP server would return `"Hello World!"`
if a CoAP client query `/Espressif` resource, CoAP server would return `"no data"`
until a CoAP client does a PUT with some data.
## libcoap Documentation
This can be found at https://libcoap.net/doc/reference/4.2.0/
## Troubleshooting
* Please make sure CoAP client fetchs data under path: `/Espressif`
* Please make sure CoAP client fetchs or puts data under path: `/Espressif` or
fetches `/.well-known/core`
* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0`
to `#define COAP_LOGGING_LEVEL 9`

View File

@ -1,4 +1,2 @@
set(COMPONENT_SRCS "coap_server_example_main.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
idf_component_register(SRCS "coap_server_example_main.c"
INCLUDE_DIRS ".")

View File

@ -12,122 +12,164 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "nvs_flash.h"
#include "protocol_examples_common.h"
#include "coap.h"
#define COAP_DEFAULT_TIME_SEC 5
#define COAP_DEFAULT_TIME_USEC 0
/* Set this to 9 to get verbose logging from within libcoap */
#define COAP_LOGGING_LEVEL 0
const static char *TAG = "CoAP_server";
static coap_async_state_t *async = NULL;
static void
send_async_response(coap_context_t *ctx, const coap_endpoint_t *local_if)
{
coap_pdu_t *response;
unsigned char buf[3];
const char* response_data = "Hello World!";
size_t size = sizeof(coap_hdr_t) + 20;
response = coap_pdu_init(async->flags & COAP_MESSAGE_CON, COAP_RESPONSE_CODE(205), 0, size);
response->hdr->id = coap_new_message_id(ctx);
if (async->tokenlen)
coap_add_token(response, async->tokenlen, async->token);
coap_add_option(response, COAP_OPTION_CONTENT_TYPE, coap_encode_var_bytes(buf, COAP_MEDIATYPE_TEXT_PLAIN), buf);
coap_add_data (response, strlen(response_data), (unsigned char *)response_data);
if (coap_send(ctx, local_if, &async->peer, response) == COAP_INVALID_TID) {
}
coap_delete_pdu(response);
coap_async_state_t *tmp;
coap_remove_async(ctx, async->id, &tmp);
coap_free_async(async);
async = NULL;
}
static char espressif_data[100];
static int espressif_data_len = 0;
/*
* The resource handler
*/
static void
async_handler(coap_context_t *ctx, struct coap_resource_t *resource,
const coap_endpoint_t *local_interface, coap_address_t *peer,
coap_pdu_t *request, str *token, coap_pdu_t *response)
hnd_espressif_get(coap_context_t *ctx, coap_resource_t *resource,
coap_session_t *session,
coap_pdu_t *request, coap_binary_t *token,
coap_string_t *query, coap_pdu_t *response)
{
async = coap_register_async(ctx, peer, request, COAP_ASYNC_SEPARATE | COAP_ASYNC_CONFIRM, (void*)"no data");
coap_add_data_blocked_response(resource, session, request, response, token,
COAP_MEDIATYPE_TEXT_PLAIN, 0,
(size_t)espressif_data_len,
(const u_char *)espressif_data);
}
static void
hnd_espressif_put(coap_context_t *ctx,
coap_resource_t *resource,
coap_session_t *session,
coap_pdu_t *request,
coap_binary_t *token,
coap_string_t *query,
coap_pdu_t *response)
{
size_t size;
unsigned char *data;
coap_resource_notify_observers(resource, NULL);
if (strcmp (espressif_data, "no data") == 0) {
response->code = COAP_RESPONSE_CODE(201);
}
else {
response->code = COAP_RESPONSE_CODE(204);
}
/* coap_get_data() sets size to 0 on error */
(void)coap_get_data(request, &size, &data);
if (size == 0) { /* re-init */
snprintf(espressif_data, sizeof(espressif_data), "no data");
espressif_data_len = strlen(espressif_data);
} else {
espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size;
memcpy (espressif_data, data, espressif_data_len);
}
}
static void
hnd_espressif_delete(coap_context_t *ctx,
coap_resource_t *resource,
coap_session_t *session,
coap_pdu_t *request,
coap_binary_t *token,
coap_string_t *query,
coap_pdu_t *response)
{
coap_resource_notify_observers(resource, NULL);
snprintf(espressif_data, sizeof(espressif_data), "no data");
espressif_data_len = strlen(espressif_data);
response->code = COAP_RESPONSE_CODE(202);
}
static void coap_example_thread(void *p)
{
coap_context_t* ctx = NULL;
coap_context_t *ctx = NULL;
coap_address_t serv_addr;
coap_resource_t* resource = NULL;
fd_set readfds;
struct timeval tv;
int flags = 0;
coap_resource_t *resource = NULL;
snprintf(espressif_data, sizeof(espressif_data), "no data");
espressif_data_len = strlen(espressif_data);
coap_set_log_level(COAP_LOGGING_LEVEL);
while (1) {
coap_endpoint_t *ep_udp = NULL;
coap_endpoint_t *ep_tcp = NULL;
unsigned wait_ms;
/* Prepare the CoAP server socket */
coap_address_init(&serv_addr);
serv_addr.addr.sin.sin_family = AF_INET;
serv_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
serv_addr.addr.sin.sin_port = htons(COAP_DEFAULT_PORT);
ctx = coap_new_context(&serv_addr);
if (ctx) {
flags = fcntl(ctx->sockfd, F_GETFL, 0);
fcntl(ctx->sockfd, F_SETFL, flags|O_NONBLOCK);
tv.tv_usec = COAP_DEFAULT_TIME_USEC;
tv.tv_sec = COAP_DEFAULT_TIME_SEC;
/* Initialize the resource */
resource = coap_resource_init((unsigned char *)"Espressif", 9, 0);
if (resource){
coap_register_handler(resource, COAP_REQUEST_GET, async_handler);
coap_add_resource(ctx, resource);
/*For incoming connections*/
for (;;) {
FD_ZERO(&readfds);
FD_CLR( ctx->sockfd, &readfds);
FD_SET( ctx->sockfd, &readfds);
ctx = coap_new_context(NULL);
if (!ctx) {
continue;
}
ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
if (!ep_udp) {
goto clean_up;
}
ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
if (!ep_tcp) {
goto clean_up;
}
resource = coap_resource_init(coap_make_str_const("Espressif"), 0);
if (!resource) {
goto clean_up;
}
coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get);
coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put);
coap_register_handler(resource, COAP_REQUEST_DELETE, hnd_espressif_delete);
/* We possibly want to Observe the GETs */
coap_resource_set_get_observable(resource, 1);
coap_add_resource(ctx, resource);
int result = select( ctx->sockfd+1, &readfds, 0, 0, &tv );
if (result > 0){
if (FD_ISSET( ctx->sockfd, &readfds ))
coap_read(ctx);
} else if (result < 0){
break;
} else {
ESP_LOGE(TAG, "select timeout");
}
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
if (async) {
send_async_response(ctx, ctx->endpoint);
}
}
while (1) {
int result = coap_run_once(ctx, wait_ms);
if (result < 0) {
break;
} else if (result && (unsigned)result < wait_ms) {
/* decrement if there is a result wait time returned */
wait_ms -= result;
}
if (result) {
/* result must have been >= wait_ms, so reset wait_ms */
wait_ms = COAP_RESOURCE_CHECK_TIME * 1000;
}
coap_free_context(ctx);
}
}
clean_up:
coap_free_context(ctx);
coap_cleanup();
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK( nvs_flash_init() );
ESP_ERROR_CHECK(esp_netif_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(coap_example_thread, "coap", 2048, NULL, 5, NULL);
xTaskCreate(coap_example_thread, "coap", 1024 * 5, NULL, 5, NULL);
}

View File

@ -0,0 +1 @@
CONFIG_ENABLE_COAP=y