From 4c4161eee50881d8f0107522bcebc2763a5e169f Mon Sep 17 00:00:00 2001 From: 1998-felix Date: Fri, 8 Sep 2023 15:30:35 +0300 Subject: [PATCH 1/3] Initial commit for zephyr coap Signed-off-by: 1998-felix --- targets/zephyr_targets/coap/CMakeLists.txt | 7 + targets/zephyr_targets/coap/prj.conf | 29 + targets/zephyr_targets/coap/src/main.c | 661 +++++++++++++++++++++ 3 files changed, 697 insertions(+) create mode 100644 targets/zephyr_targets/coap/CMakeLists.txt create mode 100644 targets/zephyr_targets/coap/prj.conf create mode 100644 targets/zephyr_targets/coap/src/main.c diff --git a/targets/zephyr_targets/coap/CMakeLists.txt b/targets/zephyr_targets/coap/CMakeLists.txt new file mode 100644 index 0000000..1fb3ccb --- /dev/null +++ b/targets/zephyr_targets/coap/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 3.20.0) +find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) +project(coap_client) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip) \ No newline at end of file diff --git a/targets/zephyr_targets/coap/prj.conf b/targets/zephyr_targets/coap/prj.conf new file mode 100644 index 0000000..19084da --- /dev/null +++ b/targets/zephyr_targets/coap/prj.conf @@ -0,0 +1,29 @@ +# Generic networking options +CONFIG_NETWORKING=y +CONFIG_NEWLIB_LIBC=y +CONFIG_NET_IPV6=y +CONFIG_NET_UDP=y + +CONFIG_NET_SOCKETS=y +CONFIG_NET_SOCKETS_POSIX_NAMES=y +CONFIG_NET_SOCKETS_POLL_MAX=4 + +CONFIG_COAP=y + +# Kernel options +CONFIG_ENTROPY_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y + +# Logging +CONFIG_PRINTK=y +CONFIG_NET_LOG=y + +# Network Shell +CONFIG_NET_SHELL=y + +CONFIG_NET_CONFIG_SETTINGS=y +CONFIG_NET_CONFIG_NEED_IPV6=y +CONFIG_NET_CONFIG_MY_IPV6_ADDR="2001:db8::2" +CONFIG_NET_CONFIG_PEER_IPV6_ADDR="2001:db8::1" + +CONFIG_HEAP_MEM_POOL_SIZE=2048 \ No newline at end of file diff --git a/targets/zephyr_targets/coap/src/main.c b/targets/zephyr_targets/coap/src/main.c new file mode 100644 index 0000000..91b1f78 --- /dev/null +++ b/targets/zephyr_targets/coap/src/main.c @@ -0,0 +1,661 @@ +#include +LOG_MODULE_REGISTER(net_coap_client_sample, LOG_LEVEL_DBG); + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "net_private.h" + +#define PEER_PORT 5683 +#define MAX_COAP_MSG_LEN 256 + +/* CoAP socket fd */ +static int sock; + +struct pollfd fds[1]; +static int nfds; + +/* CoAP Options */ +static const char * const test_path[] = { "test", NULL }; + +static const char * const large_path[] = { "large", NULL }; + +static const char * const obs_path[] = { "obs", NULL }; + +#define BLOCK_WISE_TRANSFER_SIZE_GET 2048 + +static struct coap_block_context blk_ctx; + +static void wait(void) +{ + if (poll(fds, nfds, -1) < 0) { + LOG_ERR("Error in poll:%d", errno); + } +} + +static void prepare_fds(void) +{ + fds[nfds].fd = sock; + fds[nfds].events = POLLIN; + nfds++; +} + +static int start_coap_client(void) +{ + int ret = 0; + struct sockaddr_in6 addr6; + + addr6.sin6_family = AF_INET6; + addr6.sin6_port = htons(PEER_PORT); + addr6.sin6_scope_id = 0U; + + inet_pton(AF_INET6, CONFIG_NET_CONFIG_PEER_IPV6_ADDR, + &addr6.sin6_addr); + + sock = socket(addr6.sin6_family, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + LOG_ERR("Failed to create UDP socket %d", errno); + return -errno; + } + + ret = connect(sock, (struct sockaddr *)&addr6, sizeof(addr6)); + if (ret < 0) { + LOG_ERR("Cannot connect to UDP remote : %d", errno); + return -errno; + } + + prepare_fds(); + + return 0; +} + +static int process_simple_coap_reply(void) +{ + struct coap_packet reply; + uint8_t *data; + int rcvd; + int ret; + + wait(); + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + rcvd = recv(sock, data, MAX_COAP_MSG_LEN, MSG_DONTWAIT); + if (rcvd == 0) { + ret = -EIO; + goto end; + } + + if (rcvd < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + ret = 0; + } else { + ret = -errno; + } + + goto end; + } + + net_hexdump("Response", data, rcvd); + + ret = coap_packet_parse(&reply, data, rcvd, NULL, 0); + if (ret < 0) { + LOG_ERR("Invalid data received"); + } + +end: + k_free(data); + + return ret; +} + +static int send_simple_coap_request(uint8_t method) +{ + uint8_t payload[] = "payload"; + struct coap_packet request; + const char * const *p; + uint8_t *data; + int r; + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN, + COAP_VERSION_1, COAP_TYPE_CON, + COAP_TOKEN_MAX_LEN, coap_next_token(), + method, coap_next_id()); + if (r < 0) { + LOG_ERR("Failed to init CoAP message"); + goto end; + } + + for (p = test_path; p && *p; p++) { + r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, + *p, strlen(*p)); + if (r < 0) { + LOG_ERR("Unable add option to request"); + goto end; + } + } + + switch (method) { + case COAP_METHOD_GET: + case COAP_METHOD_DELETE: + break; + + case COAP_METHOD_PUT: + case COAP_METHOD_POST: + r = coap_packet_append_payload_marker(&request); + if (r < 0) { + LOG_ERR("Unable to append payload marker"); + goto end; + } + + r = coap_packet_append_payload(&request, (uint8_t *)payload, + sizeof(payload) - 1); + if (r < 0) { + LOG_ERR("Not able to append payload"); + goto end; + } + + break; + default: + r = -EINVAL; + goto end; + } + + net_hexdump("Request", request.data, request.offset); + + r = send(sock, request.data, request.offset, 0); + +end: + k_free(data); + + return r; +} + +static int send_simple_coap_msgs_and_wait_for_reply(void) +{ + uint8_t test_type = 0U; + int r; + + while (1) { + switch (test_type) { + case 0: + /* Test CoAP GET method */ + printk("\nCoAP client GET\n"); + r = send_simple_coap_request(COAP_METHOD_GET); + if (r < 0) { + return r; + } + + break; + case 1: + /* Test CoAP PUT method */ + printk("\nCoAP client PUT\n"); + r = send_simple_coap_request(COAP_METHOD_PUT); + if (r < 0) { + return r; + } + + break; + case 2: + /* Test CoAP POST method*/ + printk("\nCoAP client POST\n"); + r = send_simple_coap_request(COAP_METHOD_POST); + if (r < 0) { + return r; + } + + break; + case 3: + /* Test CoAP DELETE method*/ + printk("\nCoAP client DELETE\n"); + r = send_simple_coap_request(COAP_METHOD_DELETE); + if (r < 0) { + return r; + } + + break; + default: + return 0; + } + + r = process_simple_coap_reply(); + if (r < 0) { + return r; + } + + test_type++; + } + + return 0; +} + +static int process_large_coap_reply(void) +{ + struct coap_packet reply; + uint8_t *data; + bool last_block; + int rcvd; + int ret; + + wait(); + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + rcvd = recv(sock, data, MAX_COAP_MSG_LEN, MSG_DONTWAIT); + if (rcvd == 0) { + ret = -EIO; + goto end; + } + + if (rcvd < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + ret = 0; + } else { + ret = -errno; + } + + goto end; + } + + net_hexdump("Response", data, rcvd); + + ret = coap_packet_parse(&reply, data, rcvd, NULL, 0); + if (ret < 0) { + LOG_ERR("Invalid data received"); + goto end; + } + + ret = coap_update_from_block(&reply, &blk_ctx); + if (ret < 0) { + goto end; + } + + last_block = coap_next_block(&reply, &blk_ctx); + if (!last_block) { + ret = 1; + goto end; + } + + ret = 0; + +end: + k_free(data); + + return ret; +} + +static int send_large_coap_request(void) +{ + struct coap_packet request; + const char * const *p; + uint8_t *data; + int r; + + if (blk_ctx.total_size == 0) { + coap_block_transfer_init(&blk_ctx, COAP_BLOCK_64, + BLOCK_WISE_TRANSFER_SIZE_GET); + } + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN, + COAP_VERSION_1, COAP_TYPE_CON, + COAP_TOKEN_MAX_LEN, coap_next_token(), + COAP_METHOD_GET, coap_next_id()); + if (r < 0) { + LOG_ERR("Failed to init CoAP message"); + goto end; + } + + for (p = large_path; p && *p; p++) { + r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, + *p, strlen(*p)); + if (r < 0) { + LOG_ERR("Unable add option to request"); + goto end; + } + } + + r = coap_append_block2_option(&request, &blk_ctx); + if (r < 0) { + LOG_ERR("Unable to add block2 option."); + goto end; + } + + net_hexdump("Request", request.data, request.offset); + + r = send(sock, request.data, request.offset, 0); + +end: + k_free(data); + + return r; +} + +static int get_large_coap_msgs(void) +{ + int r; + + while (1) { + /* Test CoAP Large GET method */ + printk("\nCoAP client Large GET (block %zd)\n", + blk_ctx.current / 64 /*COAP_BLOCK_64*/); + r = send_large_coap_request(); + if (r < 0) { + return r; + } + + r = process_large_coap_reply(); + if (r < 0) { + return r; + } + + /* Received last block */ + if (r == 1) { + memset(&blk_ctx, 0, sizeof(blk_ctx)); + return 0; + } + } + + return 0; +} + +static void send_obs_reply_ack(uint16_t id) +{ + struct coap_packet request; + uint8_t *data; + int r; + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return; + } + + r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN, + COAP_VERSION_1, COAP_TYPE_ACK, 0, NULL, 0, id); + if (r < 0) { + LOG_ERR("Failed to init CoAP message"); + goto end; + } + + net_hexdump("ACK", request.data, request.offset); + + r = send(sock, request.data, request.offset, 0); + if (r < 0) { + LOG_ERR("Failed to send CoAP ACK"); + } +end: + k_free(data); +} + + +static int obs_notification_cb(const struct coap_packet *response, + struct coap_reply *reply, + const struct sockaddr *from) +{ + uint16_t id = coap_header_get_id(response); + uint8_t type = coap_header_get_type(response); + uint8_t *counter = (uint8_t *)reply->user_data; + + ARG_UNUSED(from); + + printk("\nCoAP OBS Notification\n"); + + (*counter)++; + + if (type == COAP_TYPE_CON) { + send_obs_reply_ack(id); + } + + return 0; +} + +static int process_obs_coap_reply(struct coap_reply *reply) +{ + struct coap_packet reply_msg; + uint8_t *data; + int rcvd; + int ret; + + wait(); + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + rcvd = recv(sock, data, MAX_COAP_MSG_LEN, MSG_DONTWAIT); + if (rcvd == 0) { + ret = -EIO; + goto end; + } + + if (rcvd < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { + ret = 0; + } else { + ret = -errno; + } + + goto end; + } + + net_hexdump("Response", data, rcvd); + + ret = coap_packet_parse(&reply_msg, data, rcvd, NULL, 0); + if (ret < 0) { + LOG_ERR("Invalid data received"); + goto end; + } + + if (coap_response_received(&reply_msg, NULL, reply, 1) == NULL) { + printk("\nOther response received\n"); + } + +end: + k_free(data); + + return ret; +} + +static int send_obs_coap_request(struct coap_reply *reply, void *user_data) +{ + struct coap_packet request; + const char * const *p; + uint8_t *data; + int r; + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN, + COAP_VERSION_1, COAP_TYPE_CON, + COAP_TOKEN_MAX_LEN, coap_next_token(), + COAP_METHOD_GET, coap_next_id()); + if (r < 0) { + LOG_ERR("Failed to init CoAP message"); + goto end; + } + + r = coap_append_option_int(&request, COAP_OPTION_OBSERVE, 0); + if (r < 0) { + LOG_ERR("Failed to append Observe option"); + goto end; + } + + for (p = obs_path; p && *p; p++) { + r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, + *p, strlen(*p)); + if (r < 0) { + LOG_ERR("Unable add option to request"); + goto end; + } + } + + net_hexdump("Request", request.data, request.offset); + + coap_reply_init(reply, &request); + reply->reply = obs_notification_cb; + reply->user_data = user_data; + + r = send(sock, request.data, request.offset, 0); + +end: + k_free(data); + + return r; +} + +static int send_obs_reset_coap_request(struct coap_reply *reply) +{ + struct coap_packet request; + const char * const *p; + uint8_t *data; + int r; + + data = (uint8_t *)k_malloc(MAX_COAP_MSG_LEN); + if (!data) { + return -ENOMEM; + } + + r = coap_packet_init(&request, data, MAX_COAP_MSG_LEN, + COAP_VERSION_1, COAP_TYPE_CON, + reply->tkl, reply->token, + COAP_METHOD_GET, coap_next_id()); + if (r < 0) { + LOG_ERR("Failed to init CoAP message"); + goto end; + } + + r = coap_append_option_int(&request, COAP_OPTION_OBSERVE, 1); + if (r < 0) { + LOG_ERR("Failed to append Observe option"); + goto end; + } + + for (p = obs_path; p && *p; p++) { + r = coap_packet_append_option(&request, COAP_OPTION_URI_PATH, + *p, strlen(*p)); + if (r < 0) { + LOG_ERR("Unable add option to request"); + goto end; + } + } + + net_hexdump("Request", request.data, request.offset); + + r = send(sock, request.data, request.offset, 0); + +end: + k_free(data); + + return r; +} + +static int register_observer(void) +{ + struct coap_reply reply; + uint8_t counter = 0; + int r; + + printk("\nCoAP client OBS GET\n"); + r = send_obs_coap_request(&reply, &counter); + if (r < 0) { + return r; + } + + while (1) { + r = process_obs_coap_reply(&reply); + if (r < 0) { + return r; + } + + if (counter >= 5) { + /* TODO: Functionality can be verified byt waiting for + * some time and make sure client shouldn't receive + * any notifications. If client still receives + * notifications means, Observer is not removed. + */ + r = send_obs_reset_coap_request(&reply); + if (r < 0) { + return r; + } + + /* Wait for the final ACK */ + r = process_obs_coap_reply(&reply); + if (r < 0) { + return r; + } + + break; + } + } + + return 0; +} + +int main(void) +{ + int r; + + LOG_DBG("Start CoAP-client sample"); + r = start_coap_client(); + if (r < 0) { + goto quit; + } + + /* GET, PUT, POST, DELETE */ + r = send_simple_coap_msgs_and_wait_for_reply(); + if (r < 0) { + goto quit; + } + + /* Block-wise transfer */ + r = get_large_coap_msgs(); + if (r < 0) { + goto quit; + } + + /* Register observer, get notifications and unregister */ + r = register_observer(); + if (r < 0) { + goto quit; + } + + /* Close the socket */ + (void)close(sock); + + LOG_DBG("Done"); + + return 0; + +quit: + (void)close(sock); + + LOG_ERR("quit"); + return 0; +} \ No newline at end of file From 98656d1949297025eb86df5dbe56ffed861ab49d Mon Sep 17 00:00:00 2001 From: 1998-felix Date: Fri, 8 Sep 2023 15:32:12 +0300 Subject: [PATCH 2/3] Initial commit for zephyr coap Signed-off-by: 1998-felix --- targets/zephyr_targets/coap/src/main.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/targets/zephyr_targets/coap/src/main.c b/targets/zephyr_targets/coap/src/main.c index 91b1f78..c392333 100644 --- a/targets/zephyr_targets/coap/src/main.c +++ b/targets/zephyr_targets/coap/src/main.c @@ -17,13 +17,11 @@ LOG_MODULE_REGISTER(net_coap_client_sample, LOG_LEVEL_DBG); #define PEER_PORT 5683 #define MAX_COAP_MSG_LEN 256 -/* CoAP socket fd */ static int sock; struct pollfd fds[1]; static int nfds; -/* CoAP Options */ static const char * const test_path[] = { "test", NULL }; static const char * const large_path[] = { "large", NULL }; @@ -195,7 +193,6 @@ static int send_simple_coap_msgs_and_wait_for_reply(void) while (1) { switch (test_type) { case 0: - /* Test CoAP GET method */ printk("\nCoAP client GET\n"); r = send_simple_coap_request(COAP_METHOD_GET); if (r < 0) { @@ -204,7 +201,6 @@ static int send_simple_coap_msgs_and_wait_for_reply(void) break; case 1: - /* Test CoAP PUT method */ printk("\nCoAP client PUT\n"); r = send_simple_coap_request(COAP_METHOD_PUT); if (r < 0) { @@ -213,7 +209,6 @@ static int send_simple_coap_msgs_and_wait_for_reply(void) break; case 2: - /* Test CoAP POST method*/ printk("\nCoAP client POST\n"); r = send_simple_coap_request(COAP_METHOD_POST); if (r < 0) { @@ -222,7 +217,6 @@ static int send_simple_coap_msgs_and_wait_for_reply(void) break; case 3: - /* Test CoAP DELETE method*/ printk("\nCoAP client DELETE\n"); r = send_simple_coap_request(COAP_METHOD_DELETE); if (r < 0) { @@ -359,7 +353,6 @@ static int get_large_coap_msgs(void) int r; while (1) { - /* Test CoAP Large GET method */ printk("\nCoAP client Large GET (block %zd)\n", blk_ctx.current / 64 /*COAP_BLOCK_64*/); r = send_large_coap_request(); @@ -371,8 +364,6 @@ static int get_large_coap_msgs(void) if (r < 0) { return r; } - - /* Received last block */ if (r == 1) { memset(&blk_ctx, 0, sizeof(blk_ctx)); return 0; From b25128ff8f7901cabdaeea8a126d212820eee5ed Mon Sep 17 00:00:00 2001 From: 1998-felix Date: Thu, 14 Sep 2023 13:31:44 +0300 Subject: [PATCH 3/3] Add README.md Signed-off-by: 1998-felix --- targets/zephyr_targets/coap/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 targets/zephyr_targets/coap/README.md diff --git a/targets/zephyr_targets/coap/README.md b/targets/zephyr_targets/coap/README.md new file mode 100644 index 0000000..634c534 --- /dev/null +++ b/targets/zephyr_targets/coap/README.md @@ -0,0 +1,20 @@ +MQTTS- esp32 target +## Requirements +1. Mainflux broker details including: hostname, ThingID, Thing Credentials and Channel ID +2. [Zephyr](https://www.zephyrproject.org/) + + +## Configure +1. Edit the [config file](include/config.h) with your broker details. + +## Build +The project can be built by utilising the make file within the target directory + +```bash +west build -p always -b mqtt +``` +## Flash +Platform io generate a build directory with the fimware.bin within it. Use the make command to flash to board +```bash +west flash +``` \ No newline at end of file