-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'smartuni:main' into main
- Loading branch information
Showing
15 changed files
with
1,204 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
include $(RIOTBASE)/Makefile.base |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
# add the module dependencies here | ||
# USEMODULE += random | ||
|
||
USEMODULE += gcoap | ||
USEMODULE += cord_ep_standalone | ||
USEMODULE += uri_parser | ||
USEPKG += tinycbor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Use an immediate variable to evaluate `MAKEFILE_LIST` now | ||
USEMODULE_INCLUDES_puzzle_coap_module := $(LAST_MAKEFILEDIR)/include | ||
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_puzzle_coap_module) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
/* | ||
* Copyright (C) 2022 HAW Hamburg | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
#ifndef EXTERNAL_PUZZLE_COAP_H | ||
#define EXTERNAL_PUZZLE_COAP_H | ||
|
||
#include <stdio.h> | ||
|
||
#include "uri_parser.h" | ||
#include "net/gcoap.h" | ||
#include "net/cord/common.h" | ||
#include "net/cord/ep.h" | ||
#include "net/sock/util.h" | ||
|
||
#ifdef __cplusplus | ||
extern "C" { | ||
#endif | ||
|
||
#define PUZZLE_RESOURCE_TYPE ";rt=\"puzzle\";obs" | ||
|
||
/* 119 is the max size without touching the gcoap.h */ | ||
/* the default CONFIG_GCOAP_PDU_BUF_SIZE is 128 */ | ||
#define CBOR_BUF_SIZE 100 | ||
|
||
/** | ||
* Puzzle info structure | ||
*/ | ||
typedef struct { | ||
bool (*get_solved_handler)(void); /**< bool handler thats get called to see if a puzzle is solved */ | ||
bool (*get_ready_handler)(void); /**< bool handler thats get called to see if a puzzle is ready or in maintainance */ | ||
void (*set_ready_handler)(bool maintainance);/**< void handler thats get called to set a puzzle in ready or maintainance mode*/ | ||
const char *resource_dir_uri; /**< char* URI to a CoRE RD */ | ||
const char *name; /**< char* name of the puzzle */ | ||
} puzzle_t; | ||
|
||
void puzzle_init(const puzzle_t *puzzle); | ||
void puzzle_update(void); | ||
|
||
#ifdef __cplusplus | ||
} | ||
#endif | ||
|
||
/** @} */ | ||
#endif /* EXTERNAL_PUZZLE_COAP_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
/* | ||
* Copyright (C) 2022 HAW Hamburg | ||
* | ||
* This file is subject to the terms and conditions of the GNU Lesser | ||
* General Public License v2.1. See the file LICENSE in the top level | ||
* directory for more details. | ||
*/ | ||
|
||
/** | ||
* @{ | ||
* | ||
* @file | ||
* @brief The puzzle_coap module, provides automated resource & RD handling | ||
* | ||
* @author Bennet Blischke <bennet.blischke@haw-hamburg.de> | ||
* | ||
* @} | ||
*/ | ||
|
||
#include "puzzle_coap.h" | ||
#include "cbor.h" | ||
|
||
static const puzzle_t *_puzzle_info; | ||
|
||
static ssize_t _puzzle_info_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx); | ||
static ssize_t _puzzle_ready_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx); | ||
static ssize_t _puzzle_maintainance_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx); | ||
static ssize_t _puzzle_encoder(const coap_resource_t *resource, char *buf, size_t maxlen, coap_link_encoder_ctx_t *context); | ||
|
||
|
||
/* CoAP resources. Must be sorted by path (ASCII order). */ | ||
static coap_resource_t _resources[] = { | ||
{ "/node/info", COAP_GET, _puzzle_info_handler, NULL }, | ||
{ "/node/maintainance", COAP_PUT, _puzzle_maintainance_handler, NULL }, | ||
{ "/node/ready", COAP_PUT, _puzzle_ready_handler, NULL }, | ||
}; | ||
|
||
|
||
static gcoap_listener_t _default_listener = { | ||
_resources, | ||
ARRAY_SIZE(_resources), | ||
GCOAP_SOCKET_TYPE_UDP, | ||
_puzzle_encoder, | ||
NULL, | ||
NULL | ||
}; | ||
|
||
static int _make_sock_ep(sock_udp_ep_t *ep, uri_parser_result_t *uri) | ||
{ | ||
ep->port = 0; | ||
if (sock_udp_name2ep(ep, uri->host) < 0) { | ||
return -1; | ||
} | ||
|
||
/* if netif not specified in addr */ | ||
if ((ep->netif == SOCK_ADDR_ANY_NETIF) && (gnrc_netif_numof() == 1)) { | ||
/* assign the single interface found in gnrc_netif_numof() */ | ||
ep->netif = (uint16_t)gnrc_netif_iter(NULL)->pid; | ||
} | ||
ep->family = AF_INET6; | ||
if (uri->port_len == 0) { | ||
ep->port = COAP_PORT; | ||
} else { | ||
ep->port = atoi(uri->port); // Fix me! | ||
} | ||
return 0; | ||
} | ||
|
||
static size_t _puzzle_build_cbor_buffer(uint8_t *cborbuf, size_t len) | ||
{ | ||
/* | ||
* Encode the puzzle info in cbor: | ||
* { | ||
* "name": <string>, | ||
* "nodeState": <'provisioned'|'standby'>, | ||
* "puzzleState": <'solved'|'ready'|'maintainance'>, | ||
* } | ||
*/ | ||
assert(_puzzle_info); | ||
|
||
CborEncoder encoder, mapEncoder; | ||
cbor_encoder_init(&encoder, cborbuf, len, 0); | ||
cbor_encoder_create_map(&encoder, &mapEncoder, 3); | ||
cbor_encode_text_stringz(&mapEncoder, "name"); | ||
/* Potentially dangerous! The string might not be null terminated */ | ||
cbor_encode_text_stringz(&mapEncoder, _puzzle_info->name); | ||
|
||
cbor_encode_text_stringz(&mapEncoder, "puzzleState"); | ||
/* are we ready or are we in maintainance mode? */ | ||
if (_puzzle_info->get_ready_handler()){ | ||
if (_puzzle_info->get_solved_handler()){ | ||
cbor_encode_text_stringz(&mapEncoder, "solved"); | ||
} else { | ||
cbor_encode_text_stringz(&mapEncoder, "ready"); | ||
} | ||
} else { | ||
cbor_encode_text_stringz(&mapEncoder, "maintainance"); | ||
} | ||
|
||
cbor_encode_text_stringz(&mapEncoder, "nodeState"); | ||
cbor_encode_text_stringz(&mapEncoder, "standby"); | ||
|
||
cbor_encoder_close_container(&encoder, &mapEncoder); | ||
return cbor_encoder_get_buffer_size(&encoder, cborbuf); | ||
} | ||
|
||
|
||
static ssize_t _build_cbor_coap_packet(coap_pkt_t *pdu, uint8_t *buf, size_t len) | ||
{ | ||
uint8_t cborbuf[CBOR_BUF_SIZE]; | ||
|
||
/* set the format option to CBOR */ | ||
coap_opt_add_format(pdu, COAP_FORMAT_CBOR); | ||
|
||
/* finish the options sections */ | ||
/* it is important to keep track of the amount of used bytes (resp_len) */ | ||
size_t resp_len = coap_opt_finish(pdu, COAP_OPT_FINISH_PAYLOAD); | ||
size_t cbor_len = _puzzle_build_cbor_buffer(cborbuf, sizeof(cborbuf)); | ||
|
||
|
||
if (pdu->payload_len >= cbor_len && cbor_len < sizeof(cborbuf)){ | ||
memcpy(pdu->payload, cborbuf, cbor_len); | ||
return resp_len + cbor_len; | ||
} else { | ||
/* in this case we use a simple convenience function to create the | ||
* response, it only allows to set a payload and a response code. */ | ||
puts("puzzle_coap: msg buffer too small for given puzzle cbor object"); | ||
return gcoap_response(pdu, buf, len, COAP_CODE_INTERNAL_SERVER_ERROR); | ||
} | ||
} | ||
|
||
|
||
void puzzle_init(const puzzle_t *puzzle) | ||
{ | ||
assert(puzzle); | ||
assert(puzzle->name); | ||
assert(puzzle->resource_dir_uri); | ||
assert(puzzle->get_solved_handler); | ||
assert(puzzle->get_ready_handler); | ||
assert(puzzle->set_ready_handler); | ||
_puzzle_info = puzzle; | ||
|
||
sock_udp_ep_t remote; | ||
uri_parser_result_t uri_result; | ||
assert(uri_parser_is_absolute_string(puzzle->resource_dir_uri)); | ||
assert(uri_parser_process_string(&uri_result, puzzle->resource_dir_uri) == 0); | ||
assert(_make_sock_ep(&remote, &uri_result) == 0); | ||
|
||
gcoap_register_listener(&_default_listener); | ||
|
||
puts("Registering with RD now, this may take a short while..."); | ||
if (cord_ep_register(&remote, NULL) != CORD_EP_OK) { | ||
puts("error: registration failed"); | ||
return; | ||
} else { | ||
puts("registration successfull"); | ||
} | ||
} | ||
|
||
|
||
void puzzle_update(void) | ||
{ | ||
size_t len = 0; | ||
uint8_t buf[CONFIG_GCOAP_PDU_BUF_SIZE]; | ||
coap_pkt_t pdu; | ||
|
||
switch (gcoap_obs_init(&pdu, buf, sizeof(buf), &_resources[0])) { | ||
case GCOAP_OBS_INIT_OK: | ||
len = _build_cbor_coap_packet(&pdu, buf, sizeof(buf)); | ||
if(gcoap_obs_send(buf, len, &_resources[0]) == 0) { | ||
puts("Notification failed to send"); | ||
} | ||
break; | ||
case GCOAP_OBS_INIT_ERR: | ||
puts("Notification of the observers failed"); | ||
break; | ||
case GCOAP_OBS_INIT_UNUSED: | ||
break; | ||
} | ||
} | ||
|
||
/* | ||
* Server callback for /node/info. Accepts only GET. | ||
* | ||
* GET: Returns the puzzle status in CBOR | ||
*/ | ||
static ssize_t _puzzle_info_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx) | ||
{ | ||
(void)ctx; | ||
/* since the init functions asserts all other members, | ||
* its safe to just assert the base pointer */ | ||
assert(_puzzle_info); | ||
|
||
/* initialize a new coap response */ | ||
gcoap_resp_init(pdu, buf, len, COAP_CODE_CONTENT); | ||
|
||
return _build_cbor_coap_packet(pdu, buf, len); | ||
|
||
} | ||
|
||
/* | ||
* Server callback for /node/ready. Accepts only PUT. | ||
* Sets the puzzle into the ready state | ||
* PUT: Returns the puzzle status in CBOR | ||
*/ | ||
static ssize_t _puzzle_ready_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx) | ||
{ | ||
(void)ctx; | ||
/* since the init functions asserts all other members, | ||
* its safe to just assert the base pointer */ | ||
assert(_puzzle_info); | ||
|
||
unsigned method = coap_method2flag(coap_get_code_detail(pdu)); | ||
|
||
switch (method) { | ||
case COAP_PUT: | ||
_puzzle_info->set_ready_handler(false); | ||
break; | ||
default: | ||
/* we don't care about anything else */ | ||
return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST); | ||
} | ||
|
||
|
||
/* initialize a new coap response */ | ||
gcoap_resp_init(pdu, buf, len, COAP_CODE_CHANGED); | ||
|
||
return _build_cbor_coap_packet(pdu, buf, len); | ||
|
||
} | ||
|
||
|
||
/* | ||
* Server callback for /node/maintainance. Accepts only PUT. | ||
* Sets the puzzle into the ready state | ||
* PUT: Returns the puzzle status in CBOR | ||
*/ | ||
static ssize_t _puzzle_maintainance_handler(coap_pkt_t *pdu, uint8_t *buf, size_t len, void *ctx) | ||
{ | ||
(void)ctx; | ||
/* since the init functions asserts all other members, | ||
* its safe to just assert the base pointer */ | ||
assert(_puzzle_info); | ||
|
||
unsigned method = coap_method2flag(coap_get_code_detail(pdu)); | ||
|
||
switch (method) { | ||
case COAP_PUT: | ||
_puzzle_info->set_ready_handler(true); | ||
break; | ||
default: | ||
/* we don't care about anything else */ | ||
return gcoap_response(pdu, buf, len, COAP_CODE_BAD_REQUEST); | ||
} | ||
|
||
|
||
/* initialize a new coap response */ | ||
gcoap_resp_init(pdu, buf, len, COAP_CODE_CHANGED); | ||
|
||
return _build_cbor_coap_packet(pdu, buf, len); | ||
|
||
} | ||
|
||
|
||
/* Adds link format params to resource list */ | ||
static ssize_t _puzzle_encoder(const coap_resource_t *resource, char *buf, | ||
size_t maxlen, coap_link_encoder_ctx_t *context) { | ||
ssize_t res = gcoap_encode_link(resource, buf, maxlen, context); | ||
|
||
if (res > 0) { | ||
if (strlen(PUZZLE_RESOURCE_TYPE) < (maxlen - res)){ | ||
if (buf) { | ||
memcpy(buf+res, PUZZLE_RESOURCE_TYPE, strlen(PUZZLE_RESOURCE_TYPE)); | ||
} | ||
res += strlen(PUZZLE_RESOURCE_TYPE); | ||
} | ||
} | ||
|
||
return res; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# name of the application | ||
APPLICATION = example | ||
|
||
# If no BOARD is found in the environment, use this default: | ||
BOARD ?= native | ||
|
||
# This has to be the absolute path to the RIOT base directory: | ||
RIOTBASE ?= ../RIOT | ||
|
||
# Comment this out to disable code in RIOT that does safety checking | ||
# which is not needed in a production environment but helps in the | ||
# development process: | ||
DEVELHELP ?= 1 | ||
|
||
# For the coap_client | ||
USEMODULE += od | ||
|
||
USEMODULE += netdev_default | ||
USEMODULE += auto_init_gnrc_netif | ||
USEMODULE += gnrc_ipv6_default | ||
USEMODULE += gnrc_icmpv6_echo | ||
USEMODULE += netutils | ||
|
||
USEMODULE += fmt | ||
USEMODULE += xtimer | ||
|
||
USEMODULE += puzzle_coap | ||
USEMODULE += shell | ||
USEMODULE += shell_commands | ||
USEMODULE += ps | ||
|
||
# Change this to 0 show compiler invocation lines by default: | ||
QUIET ?= 1 | ||
|
||
include ../common.mk |
Oops, something went wrong.