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:
parent
74db066941
commit
1f63c32c03
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
3
samples/net/sockets/coap_server/boards/native_posix.conf
Normal file
3
samples/net/sockets/coap_server/boards/native_posix.conf
Normal 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
|
|
@ -0,0 +1,3 @@
|
|||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_NATIVE_POSIX_SLOWDOWN_TO_REAL_TIME=y
|
||||
CONFIG_NATIVE_UART_0_ON_STDINOUT=y
|
|
@ -0,0 +1,4 @@
|
|||
CONFIG_NET_L2_ETHERNET=y
|
||||
CONFIG_ETH_DRIVER=y
|
||||
CONFIG_ETH_STELLARIS=y
|
||||
CONFIG_NET_QEMU_ETHERNET=y
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
5
samples/net/sockets/coap_server/sections-ram.ld
Normal file
5
samples/net/sockets/coap_server/sections-ram.ld
Normal 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
81
samples/net/sockets/coap_server/src/core.c
Normal file
81
samples/net/sockets/coap_server/src/core.c
Normal 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,
|
||||
}),
|
||||
});
|
266
samples/net/sockets/coap_server/src/large.c
Normal file
266
samples/net/sockets/coap_server/src/large.c
Normal 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,
|
||||
});
|
72
samples/net/sockets/coap_server/src/location_query.c
Normal file
72
samples/net/sockets/coap_server/src/location_query.c
Normal 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,
|
||||
});
|
85
samples/net/sockets/coap_server/src/main.c
Normal file
85
samples/net/sockets/coap_server/src/main.c
Normal 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);
|
153
samples/net/sockets/coap_server/src/observer.c
Normal file
153
samples/net/sockets/coap_server/src/observer.c
Normal 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));
|
||||
}
|
102
samples/net/sockets/coap_server/src/query.c
Normal file
102
samples/net/sockets/coap_server/src/query.c
Normal 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,
|
||||
});
|
99
samples/net/sockets/coap_server/src/separate.c
Normal file
99
samples/net/sockets/coap_server/src/separate.c
Normal 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,
|
||||
});
|
262
samples/net/sockets/coap_server/src/test.c
Normal file
262
samples/net/sockets/coap_server/src/test.c
Normal 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
|
Loading…
Reference in a new issue