samples: net: sockets: Add CoAP service example

Replaced the CoAP server example with CoAP services.

Signed-off-by: Pieter De Gendt <pieter.degendt@basalte.be>
This commit is contained in:
Pieter De Gendt 2023-10-04 12:29:04 +02:00 committed by Carles Cufí
parent 74db066941
commit 1f63c32c03
17 changed files with 1155 additions and 1476 deletions

View file

@ -7,3 +7,5 @@ project(coap_server)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})
target_include_directories(app PRIVATE ${ZEPHYR_BASE}/subsys/net/ip)
zephyr_linker_sources(DATA_SECTIONS sections-ram.ld)

View file

@ -1,13 +1,18 @@
.. zephyr:code-sample:: coap-server
:name: CoAP server
:relevant-api: coap udp
:name: CoAP service
:relevant-api: coap coap_service udp
Use the CoAP library to implement a server that exposes CoAP resources.
Use the CoAP server subsystem to register CoAP resources.
Overview
********
This sample is a simple CoAP server showing how to expose a simple resource.
This sample shows how to register CoAP resources to a main CoAP service.
The CoAP server implementation expects all services and resources to be
available at compile time, as they are put into dedicated sections.
The resource is placed into the correct linker section based on the owning
service's name. A linker file is required, see ``sections-ram.ld`` for an example.
This demo assumes that the platform of choice has networking support,
some adjustments to the configuration may be needed.

View file

@ -0,0 +1,3 @@
CONFIG_NET_L2_ETHERNET=y
CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y
CONFIG_NATIVE_UART_0_ON_STDINOUT=y

View file

@ -0,0 +1,3 @@
CONFIG_NET_L2_ETHERNET=y
CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y
CONFIG_NATIVE_UART_0_ON_STDINOUT=y

View file

@ -0,0 +1,4 @@
CONFIG_NET_L2_ETHERNET=y
CONFIG_ETH_DRIVER=y
CONFIG_ETH_STELLARIS=y
CONFIG_NET_QEMU_ETHERNET=y

View file

@ -10,7 +10,10 @@ CONFIG_NET_SOCKETS_POLL_MAX=4
# CoAP
CONFIG_COAP=y
CONFIG_COAP_SERVER=y
CONFIG_COAP_SERVER_WELL_KNOWN_CORE=y
CONFIG_COAP_WELL_KNOWN_BLOCK_WISE=n
CONFIG_COAP_OBSERVER_EVENTS=y
# Kernel options
CONFIG_ENTROPY_GENERATOR=y
@ -22,9 +25,7 @@ CONFIG_NET_LOG=y
# Network Shell
CONFIG_NET_SHELL=y
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_COAP_SERVER_SHELL=y
# Configuration
CONFIG_NET_CONFIG_SETTINGS=y

View file

@ -1,12 +1,14 @@
common:
filter: CONFIG_FULL_LIBC_SUPPORTED and not CONFIG_NATIVE_LIBC
sample:
description: TBD
name: TBD
description: BSD Sockets API CoAP server example
name: socket_coap_server
tests:
sample.net.sockets.coap_server:
harness: net
tags:
- net
- socket
platform_allow: qemu_x86
platform_allow:
- native_posix
- qemu_x86

View file

@ -0,0 +1,5 @@
/* SPDX-License-Identifier: Apache-2.0 */
#include <zephyr/linker/iterable_sections.h>
ITERABLE_SECTION_RAM(coap_resource_coap_server, 4)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
#include <zephyr/net/coap_link_format.h>
static int core_get(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
static const char dummy_str[] = "Just a test\n";
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_packet response;
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint8_t tkl;
int r;
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, COAP_TYPE_ACK, tkl, token,
COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return r;
}
r = coap_packet_append_payload_marker(&response);
if (r < 0) {
return r;
}
r = coap_packet_append_payload(&response, (uint8_t *)dummy_str,
sizeof(dummy_str));
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static const char * const core_1_path[] = { "core1", NULL };
static const char * const core_1_attributes[] = {
"title=\"Core 1\"",
"rt=core1",
NULL,
};
COAP_RESOURCE_DEFINE(core_1, coap_server,
{
.get = core_get,
.path = core_1_path,
.user_data = &((struct coap_core_metadata) {
.attributes = core_1_attributes,
}),
});
static const char * const core_2_path[] = { "core2", NULL };
static const char * const core_2_attributes[] = {
"title=\"Core 2\"",
"rt=core2",
NULL,
};
COAP_RESOURCE_DEFINE(core_2, coap_server,
{
.get = core_get,
.path = core_2_path,
.user_data = &((struct coap_core_metadata) {
.attributes = core_2_attributes,
}),
});

View file

@ -0,0 +1,266 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
#define BLOCK_WISE_TRANSFER_SIZE_GET 2048
static int large_get(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
static struct coap_block_context ctx;
struct coap_packet response;
uint8_t payload[64];
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t size;
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
if (ctx.total_size == 0) {
coap_block_transfer_init(&ctx, COAP_BLOCK_64, BLOCK_WISE_TRANSFER_SIZE_GET);
}
r = coap_update_from_block(request, &ctx);
if (r < 0) {
return -EINVAL;
}
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, COAP_TYPE_ACK, tkl, token,
COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return -EINVAL;
}
r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
COAP_CONTENT_FORMAT_TEXT_PLAIN);
if (r < 0) {
return r;
}
r = coap_append_block2_option(&response, &ctx);
if (r < 0) {
return r;
}
r = coap_packet_append_payload_marker(&response);
if (r < 0) {
return r;
}
size = MIN(coap_block_size_to_bytes(ctx.block_size),
ctx.total_size - ctx.current);
memset(payload, 'A', MIN(size, sizeof(payload)));
r = coap_packet_append_payload(&response, (uint8_t *)payload, size);
if (r < 0) {
return r;
}
r = coap_next_block(&response, &ctx);
if (!r) {
/* Will return 0 when it's the last block. */
memset(&ctx, 0, sizeof(ctx));
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static int large_update_put(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
static struct coap_block_context ctx;
struct coap_packet response;
const uint8_t *payload;
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint16_t len;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
bool last_block;
r = coap_get_option_int(request, COAP_OPTION_BLOCK1);
if (r < 0) {
return -EINVAL;
}
last_block = !GET_MORE(r);
/* initialize block context upon the arrival of first block */
if (!GET_BLOCK_NUM(r)) {
coap_block_transfer_init(&ctx, COAP_BLOCK_64, 0);
}
r = coap_update_from_block(request, &ctx);
if (r < 0) {
LOG_ERR("Invalid block size option from request");
return -EINVAL;
}
payload = coap_packet_get_payload(request, &len);
if (!last_block && payload == NULL) {
LOG_ERR("Packet without payload");
return -EINVAL;
}
LOG_INF("**************");
LOG_INF("[ctx] current %zu block_size %u total_size %zu",
ctx.current, coap_block_size_to_bytes(ctx.block_size),
ctx.total_size);
LOG_INF("**************");
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
/* Do something with the payload */
if (!last_block) {
code = COAP_RESPONSE_CODE_CONTINUE;
} else {
code = COAP_RESPONSE_CODE_CHANGED;
}
r = coap_ack_init(&response, request, data, sizeof(data), code);
if (r < 0) {
return r;
}
r = coap_append_block1_option(&response, &ctx);
if (r < 0) {
LOG_ERR("Could not add Block1 option to response");
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static int large_create_post(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
static struct coap_block_context ctx;
struct coap_packet response;
const uint8_t *payload;
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t len;
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
bool last_block;
r = coap_get_option_int(request, COAP_OPTION_BLOCK1);
if (r < 0) {
return -EINVAL;
}
last_block = !GET_MORE(r);
/* initialize block context upon the arrival of first block */
if (!GET_BLOCK_NUM(r)) {
coap_block_transfer_init(&ctx, COAP_BLOCK_32, 0);
}
r = coap_update_from_block(request, &ctx);
if (r < 0) {
LOG_ERR("Invalid block size option from request");
return -EINVAL;
}
payload = coap_packet_get_payload(request, &len);
if (!last_block && payload) {
LOG_ERR("Packet without payload");
return -EINVAL;
}
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
if (!last_block) {
code = COAP_RESPONSE_CODE_CONTINUE;
} else {
code = COAP_RESPONSE_CODE_CREATED;
}
r = coap_ack_init(&response, request, data, sizeof(data), code);
if (r < 0) {
return r;
}
r = coap_append_block1_option(&response, &ctx);
if (r < 0) {
LOG_ERR("Could not add Block1 option to response");
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static const char * const large_path[] = { "large", NULL };
COAP_RESOURCE_DEFINE(large, coap_server,
{
.get = large_get,
.path = large_path,
});
static const char * const large_update_path[] = { "large-update", NULL };
COAP_RESOURCE_DEFINE(large_update, coap_server,
{
.put = large_update_put,
.path = large_update_path,
});
static const char * const large_create_path[] = { "large-create", NULL };
COAP_RESOURCE_DEFINE(large_create, coap_server,
{
.post = large_create_post,
.path = large_create_path,
});

View file

@ -0,0 +1,72 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
static int location_query_post(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
static const char *const location_query[] = { "first=1",
"second=2",
NULL };
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
const char * const *p;
struct coap_packet response;
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
if (type == COAP_TYPE_CON) {
type = COAP_TYPE_ACK;
} else {
type = COAP_TYPE_NON_CON;
}
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_CREATED, id);
if (r < 0) {
return r;
}
for (p = location_query; *p; p++) {
r = coap_packet_append_option(&response,
COAP_OPTION_LOCATION_QUERY,
*p, strlen(*p));
if (r < 0) {
return r;
}
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static const char * const location_query_path[] = { "location-query", NULL };
COAP_RESOURCE_DEFINE(location_query, coap_server,
{
.post = location_query_post,
.path = location_query_path,
});

View file

@ -0,0 +1,85 @@
/*
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_coap_service_sample, LOG_LEVEL_DBG);
#include <zephyr/net/coap_service.h>
#ifdef CONFIG_NET_IPV6
#include "net_private.h"
#include "ipv6.h"
#endif
static const uint16_t coap_port = 5683;
#ifdef CONFIG_NET_IPV6
#define ALL_NODES_LOCAL_COAP_MCAST \
{ { { 0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xfd } } }
#define MY_IP6ADDR \
{ { { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1 } } }
static int join_coap_multicast_group(void)
{
static struct in6_addr my_addr = MY_IP6ADDR;
static struct sockaddr_in6 mcast_addr = {
.sin6_family = AF_INET6,
.sin6_addr = ALL_NODES_LOCAL_COAP_MCAST,
.sin6_port = htons(coap_port) };
struct net_if_addr *ifaddr;
struct net_if *iface;
int ret;
iface = net_if_get_default();
if (!iface) {
LOG_ERR("Could not get the default interface");
return -ENOENT;
}
#if defined(CONFIG_NET_CONFIG_SETTINGS)
if (net_addr_pton(AF_INET6,
CONFIG_NET_CONFIG_MY_IPV6_ADDR,
&my_addr) < 0) {
LOG_ERR("Invalid IPv6 address %s",
CONFIG_NET_CONFIG_MY_IPV6_ADDR);
}
#endif
ifaddr = net_if_ipv6_addr_add(iface, &my_addr, NET_ADDR_MANUAL, 0);
if (!ifaddr) {
LOG_ERR("Could not add unicast address to interface");
return -EINVAL;
}
ifaddr->addr_state = NET_ADDR_PREFERRED;
ret = net_ipv6_mld_join(iface, &mcast_addr.sin6_addr);
if (ret < 0) {
LOG_ERR("Cannot join %s IPv6 multicast group (%d)",
net_sprint_ipv6_addr(&mcast_addr.sin6_addr), ret);
return ret;
}
return 0;
}
int main(void)
{
return join_coap_multicast_group();
}
#else /* CONFIG_NET_IPV6 */
int main(void)
{
return 0;
}
#endif /* CONFIG_NET_IPV6 */
COAP_SERVICE_DEFINE(coap_server, NULL, &coap_port, COAP_SERVICE_AUTOSTART);

View file

@ -0,0 +1,153 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
static int obs_counter;
static void update_counter(struct k_work *work);
K_WORK_DELAYABLE_DEFINE(obs_work, update_counter);
#ifdef CONFIG_COAP_OBSERVER_EVENTS
static void observer_event(struct coap_resource *resource, struct coap_observer *observer,
enum coap_observer_event event)
{
LOG_INF("Observer %s", event == COAP_OBSERVER_ADDED ? "added" : "removed");
}
#endif
static int send_notification_packet(struct coap_resource *resource,
const struct sockaddr *addr,
socklen_t addr_len,
uint16_t age, uint16_t id,
const uint8_t *token, uint8_t tkl,
bool is_response)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_packet response;
char payload[14];
uint8_t type;
int r;
if (is_response) {
type = COAP_TYPE_ACK;
} else {
type = COAP_TYPE_CON;
}
if (!is_response) {
id = coap_next_id();
}
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return r;
}
if (age >= 2U) {
r = coap_append_option_int(&response, COAP_OPTION_OBSERVE, age);
if (r < 0) {
return r;
}
}
r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
COAP_CONTENT_FORMAT_TEXT_PLAIN);
if (r < 0) {
return r;
}
r = coap_packet_append_payload_marker(&response);
if (r < 0) {
return r;
}
/* The response that coap-client expects */
r = snprintk((char *) payload, sizeof(payload),
"Counter: %d\n", obs_counter);
if (r < 0) {
return r;
}
r = coap_packet_append_payload(&response, (uint8_t *)payload,
strlen(payload));
if (r < 0) {
return r;
}
k_work_reschedule(&obs_work, K_SECONDS(5));
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static int obs_get(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
r = coap_resource_parse_observe(resource, request, addr);
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
return send_notification_packet(resource, addr, addr_len,
r == 0 ? resource->age : 0,
id, token, tkl, true);
}
static void obs_notify(struct coap_resource *resource,
struct coap_observer *observer)
{
send_notification_packet(resource,
&observer->addr,
sizeof(observer->addr),
resource->age, 0,
observer->token, observer->tkl, false);
}
static const char * const obs_path[] = { "obs", NULL };
COAP_RESOURCE_DEFINE(obs, coap_server,
{
.get = obs_get,
.path = obs_path,
.notify = obs_notify,
#ifdef CONFIG_COAP_OBSERVER_EVENTS
.observer_event_handler = observer_event,
#endif
});
static void update_counter(struct k_work *work)
{
obs_counter++;
coap_resource_notify(&obs);
k_work_reschedule(&obs_work, K_SECONDS(5));
}

View file

@ -0,0 +1,102 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
static int query_get(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_option options[4];
struct coap_packet response;
uint8_t payload[40];
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int i, r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
r = coap_find_options(request, COAP_OPTION_URI_QUERY, options, 4);
if (r < 0) {
return -EINVAL;
}
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("num queries: %d", r);
for (i = 0; i < r; i++) {
char str[16];
if (options[i].len + 1 > sizeof(str)) {
LOG_INF("Unexpected length of query: "
"%d (expected %zu)",
options[i].len, sizeof(str));
break;
}
memcpy(str, options[i].value, options[i].len);
str[options[i].len] = '\0';
LOG_INF("query[%d]: %s", i + 1, str);
}
LOG_INF("*******");
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, COAP_TYPE_ACK, tkl, token,
COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return r;
}
r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
COAP_CONTENT_FORMAT_TEXT_PLAIN);
if (r < 0) {
return r;
}
r = coap_packet_append_payload_marker(&response);
if (r < 0) {
return r;
}
/* The response that coap-client expects */
r = snprintk((char *) payload, sizeof(payload),
"Type: %u\nCode: %u\nMID: %u\n", type, code, id);
if (r < 0) {
return r;
}
r = coap_packet_append_payload(&response, (uint8_t *)payload,
strlen(payload));
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static const char * const query_path[] = { "query", NULL };
COAP_RESOURCE_DEFINE(query, coap_server,
{
.get = query_get,
.path = query_path,
});

View file

@ -0,0 +1,99 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
static int separate_get(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_packet response;
uint8_t payload[40];
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
if (type == COAP_TYPE_ACK) {
return 0;
}
r = coap_ack_init(&response, request, data, sizeof(data), 0);
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
if (r < 0) {
return r;
}
if (type == COAP_TYPE_CON) {
type = COAP_TYPE_CON;
} else {
type = COAP_TYPE_NON_CON;
}
/* Re-use the buffer */
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return r;
}
r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
COAP_CONTENT_FORMAT_TEXT_PLAIN);
if (r < 0) {
return r;
}
r = coap_packet_append_payload_marker(&response);
if (r < 0) {
return r;
}
/* The response that coap-client expects */
r = snprintk((char *) payload, sizeof(payload),
"Type: %u\nCode: %u\nMID: %u\n", type, code, id);
if (r < 0) {
return r;
}
r = coap_packet_append_payload(&response, (uint8_t *)payload,
strlen(payload));
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static const char * const separate_path[] = { "separate", NULL };
COAP_RESOURCE_DEFINE(separate, coap_server,
{
.get = separate_get,
.path = separate_path,
});

View file

@ -0,0 +1,262 @@
/*
* Copyright (c) 2018 Intel Corporation
* Copyright (c) 2023 Basalte bv
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_DECLARE(net_coap_service_sample);
#include <zephyr/sys/printk.h>
#include <zephyr/net/coap_service.h>
#include "net_private.h"
static int piggyback_get(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_packet response;
uint8_t payload[40];
uint8_t token[COAP_TOKEN_MAX_LEN];
uint16_t id;
uint8_t code;
uint8_t type;
uint8_t tkl;
int r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
if (type == COAP_TYPE_CON) {
type = COAP_TYPE_ACK;
} else {
type = COAP_TYPE_NON_CON;
}
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_CONTENT, id);
if (r < 0) {
return r;
}
r = coap_append_option_int(&response, COAP_OPTION_CONTENT_FORMAT,
COAP_CONTENT_FORMAT_TEXT_PLAIN);
if (r < 0) {
return r;
}
r = coap_packet_append_payload_marker(&response);
if (r < 0) {
return r;
}
/* The response that coap-client expects */
r = snprintk((char *) payload, sizeof(payload),
"Type: %u\nCode: %u\nMID: %u\n", type, code, id);
if (r < 0) {
return r;
}
r = coap_packet_append_payload(&response, (uint8_t *)payload,
strlen(payload));
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static int test_del(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_packet response;
uint8_t token[COAP_TOKEN_MAX_LEN];
uint8_t tkl;
uint8_t code;
uint8_t type;
uint16_t id;
int r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
if (type == COAP_TYPE_CON) {
type = COAP_TYPE_ACK;
} else {
type = COAP_TYPE_NON_CON;
}
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_DELETED, id);
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static int test_put(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
struct coap_packet response;
uint8_t token[COAP_TOKEN_MAX_LEN];
const uint8_t *payload;
uint16_t payload_len;
uint8_t code;
uint8_t type;
uint8_t tkl;
uint16_t id;
int r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
payload = coap_packet_get_payload(request, &payload_len);
if (payload) {
net_hexdump("PUT Payload", payload, payload_len);
}
if (type == COAP_TYPE_CON) {
type = COAP_TYPE_ACK;
} else {
type = COAP_TYPE_NON_CON;
}
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_CHANGED, id);
if (r < 0) {
return r;
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static int test_post(struct coap_resource *resource,
struct coap_packet *request,
struct sockaddr *addr, socklen_t addr_len)
{
static const char * const location_path[] = { "location1",
"location2",
"location3",
NULL };
uint8_t data[CONFIG_COAP_SERVER_MESSAGE_SIZE];
const char * const *p;
struct coap_packet response;
uint8_t token[COAP_TOKEN_MAX_LEN];
const uint8_t *payload;
uint16_t payload_len;
uint8_t code;
uint8_t type;
uint8_t tkl;
uint16_t id;
int r;
code = coap_header_get_code(request);
type = coap_header_get_type(request);
id = coap_header_get_id(request);
tkl = coap_header_get_token(request, token);
LOG_INF("*******");
LOG_INF("type: %u code %u id %u", type, code, id);
LOG_INF("*******");
payload = coap_packet_get_payload(request, &payload_len);
if (payload) {
net_hexdump("POST Payload", payload, payload_len);
}
if (type == COAP_TYPE_CON) {
type = COAP_TYPE_ACK;
} else {
type = COAP_TYPE_NON_CON;
}
r = coap_packet_init(&response, data, sizeof(data),
COAP_VERSION_1, type, tkl, token,
COAP_RESPONSE_CODE_CREATED, id);
if (r < 0) {
return r;
}
for (p = location_path; *p; p++) {
r = coap_packet_append_option(&response,
COAP_OPTION_LOCATION_PATH,
*p, strlen(*p));
if (r < 0) {
return r;
}
}
r = coap_resource_send(resource, &response, addr, addr_len);
return r;
}
static const char * const test_path[] = { "test", NULL };
COAP_RESOURCE_DEFINE(test, coap_server,
{
.get = piggyback_get,
.post = test_post,
.del = test_del,
.put = test_put,
.path = test_path,
});
static const char * const segments_path[] = { "seg1", "seg2", "seg3", NULL };
COAP_RESOURCE_DEFINE(segments, coap_server,
{
.get = piggyback_get,
.path = segments_path,
});
#if defined(CONFIG_COAP_URI_WILDCARD)
static const char * const wildcard1_path[] = { "wild1", "+", "wild3", NULL };
COAP_RESOURCE_DEFINE(wildcard1, coap_server,
{
.get = piggyback_get,
.path = wildcard1_path,
});
static const char * const wildcard2_path[] = { "wild2", "#", NULL };
COAP_RESOURCE_DEFINE(wildcard2, coap_server,
{
.get = piggyback_get,
.path = wildcard2_path,
});
#endif