diff --git a/examples/microcoap_server/Makefile b/examples/microcoap_server/Makefile new file mode 100644 index 0000000000..ea269df925 --- /dev/null +++ b/examples/microcoap_server/Makefile @@ -0,0 +1,58 @@ +# name of your application +APPLICATION = microcoap_server + +# 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 ?= $(CURDIR)/../.. + +BOARD_INSUFFICIENT_MEMORY := airfy-beacon chronos msb-430 msb-430h nrf51dongle \ + nrf6310 pca10000 pca10005 spark-core \ + stm32f0discovery telosb weio wsn430-v1_3b wsn430-v1_4 \ + yunjia-nrf51822 z1 + +# Include packages that pull up and auto-init the link layer. +# NOTE: 6LoWPAN will be included if IEEE802.15.4 devices are present +USEMODULE += gnrc_netif_default +USEMODULE += auto_init_gnrc_netif +# Specify the mandatory networking modules for IPv6 and UDP +USEMODULE += gnrc_ipv6_router_default +USEMODULE += gnrc_udp +# Add a routing protocol +USEMODULE += gnrc_rpl +# Additional networking modules that can be dropped if not needed +USEMODULE += gnrc_icmpv6_echo + +# +USEMODULE += gnrc_conn_udp + +USEPKG += microcoap +CFLAGS += -DMICROCOAP_DEBUG + +# include this for printing IP addresses +USEMODULE += shell_commands + +# 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: +#CFLAGS += -DDEVELHELP + +# Use different settings when compiling for one of the following (low-memory) +# boards +LOW_MEMORY_BOARDS := nucleo-f334 + +ifneq (,$(filter $(BOARD),$(LOW_MEMORY_BOARDS))) +$(info Using low-memory configuration for microcoap_server.) +## low-memory tuning values +# lower pktbuf buffer size +CFLAGS += -DGNRC_PKTBUF_SIZE=1000 +# disable fib, rpl +DISABLE_MODULE += fib gnrc_rpl +USEMODULE += prng_minstd +endif + +# Change this to 0 show compiler invocation lines by default: +QUIET ?= 1 + +include $(RIOTBASE)/Makefile.include diff --git a/examples/microcoap_server/README.md b/examples/microcoap_server/README.md new file mode 100644 index 0000000000..7f1d9f8441 --- /dev/null +++ b/examples/microcoap_server/README.md @@ -0,0 +1,62 @@ +microcoap server example +======================== + +This application is meant to get you started with impementing a CoAP server on RIOT. +It uses the gnrc network stack through RIOT's conn socket API. + + +Usage +===== + +To try on native, compile with + +``` +# make all +``` + +Then run the resulting binary, e.g., + +``` +# make term +``` + +The application is now listening on all it's configured IP addresses. + +Now find out it's link\_layer address: + + +``` +$ make term +/home/kaspar/src/riot/examples/microcoap_server/bin/native/microcoap_server.elf tap0 +RIOT native interrupts/signals initialized. +LED_GREEN_OFF +LED_RED_ON +RIOT native board initialized. +RIOT native hardware initialization complete. + +main(): This is RIOT! (Version: 2015.12-devel-632-g8f451-booze-add_conn_coap_example) +RIOT microcoap example application +Configured network interfaces: +Iface 5 HWaddr: fa:bf:2b:01:9e:a3 + MTU:1280 HL:64 + Source address length: 6 + Link type: wired + inet6 addr: ff02::1/128 scope: local [multicast] + inet6 addr: fe80::f8bf:2bff:fe01:9ea3/64 scope: local + inet6 addr: ff02::1:ff01:9ea3/128 scope: local [multicast] + inet6 addr: ff02::2/128 scope: local [multicast] + +Waiting for incoming UDP packet... +``` + +The link-layer address in this case is "fe80::f8bf:2bff:fe01:9ea3", the only +"scope: local" address set. + +Connect using libcoap CLI +========================= + +(replace "fe80::f8bf:2bff:fe01:9ea3" with your link-layer address) + +``` +# coap-client coap://[fe80::f8bf:2bff:fe01:9ea3%tap0]/riot/board +``` diff --git a/examples/microcoap_server/coap.c b/examples/microcoap_server/coap.c new file mode 100644 index 0000000000..5fe8a0a505 --- /dev/null +++ b/examples/microcoap_server/coap.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * + * 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. + */ + +#include +#include + +#define MAX_RESPONSE_LEN 500 +static uint8_t response[MAX_RESPONSE_LEN] = { 0 }; + +static int handle_get_well_known_core(coap_rw_buffer_t *scratch, + const coap_packet_t *inpkt, + coap_packet_t *outpkt, + uint8_t id_hi, uint8_t id_lo); + +static int handle_get_riot_board(coap_rw_buffer_t *scratch, + const coap_packet_t *inpkt, + coap_packet_t *outpkt, + uint8_t id_hi, uint8_t id_lo); + +static const coap_endpoint_path_t path_well_known_core = + { 2, { ".well-known", "core" } }; + +static const coap_endpoint_path_t path_riot_board = + { 2, { "riot", "board" } }; + +const coap_endpoint_t endpoints[] = +{ + { COAP_METHOD_GET, handle_get_well_known_core, + &path_well_known_core, "ct=40" }, + { COAP_METHOD_GET, handle_get_riot_board, + &path_riot_board, "ct=0" }, + /* marks the end of the endpoints array: */ + { (coap_method_t)0, NULL, NULL, NULL } +}; + +static int handle_get_well_known_core(coap_rw_buffer_t *scratch, + const coap_packet_t *inpkt, coap_packet_t *outpkt, + uint8_t id_hi, uint8_t id_lo) +{ + char *rsp = (char *)response; + int len = sizeof(response); + const coap_endpoint_t *ep = endpoints; + int i; + + len--; // Null-terminated string + + while (NULL != ep->handler) { + if (NULL == ep->core_attr) { + ep++; + continue; + } + + if (0 < strlen(rsp)) { + strncat(rsp, ",", len); + len--; + } + + strncat(rsp, "<", len); + len--; + + for (i = 0; i < ep->path->count; i++) { + strncat(rsp, "/", len); + len--; + + strncat(rsp, ep->path->elems[i], len); + len -= strlen(ep->path->elems[i]); + } + + strncat(rsp, ">;", len); + len -= 2; + + strncat(rsp, ep->core_attr, len); + len -= strlen(ep->core_attr); + + ep++; + } + + return coap_make_response(scratch, outpkt, (const uint8_t *)rsp, + strlen(rsp), id_hi, id_lo, &inpkt->tok, + COAP_RSPCODE_CONTENT, + COAP_CONTENTTYPE_APPLICATION_LINKFORMAT); +} + +static int handle_get_riot_board(coap_rw_buffer_t *scratch, + const coap_packet_t *inpkt, coap_packet_t *outpkt, + uint8_t id_hi, uint8_t id_lo) +{ + const char *riot_name = RIOT_BOARD; + int len = strlen(RIOT_BOARD); + + memcpy(response, riot_name, len); + + return coap_make_response(scratch, outpkt, (const uint8_t *)response, len, + id_hi, id_lo, &inpkt->tok, COAP_RSPCODE_CONTENT, + COAP_CONTENTTYPE_TEXT_PLAIN); +} diff --git a/examples/microcoap_server/main.c b/examples/microcoap_server/main.c new file mode 100644 index 0000000000..c790da2a2a --- /dev/null +++ b/examples/microcoap_server/main.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * + * 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. + */ + +/** + * @ingroup examples + * @{ + * + * @file + * @brief CoAP example server application (using microcoap) + * + * @author Kaspar Schleiser + * @} + */ + +#include +#include "msg.h" + +#define MAIN_QUEUE_SIZE (8) +static msg_t _main_msg_queue[MAIN_QUEUE_SIZE]; + +void microcoap_server_loop(void); + +/* import "ifconfig" shell command, used for printing addresses */ +extern int _netif_config(int argc, char **argv); + +int main(void) +{ + puts("RIOT microcoap example application"); + + /* microcoap_server uses conn which uses gnrc which needs a msg queue */ + msg_init_queue(_main_msg_queue, MAIN_QUEUE_SIZE); + + /* print network addresses */ + puts("Configured network interfaces:"); + _netif_config(0, NULL); + + /* start coap server loop */ + microcoap_server_loop(); + + /* should be never reached */ + return 0; +} diff --git a/examples/microcoap_server/microcoap_conn.c b/examples/microcoap_server/microcoap_conn.c new file mode 100644 index 0000000000..8fb9a51d78 --- /dev/null +++ b/examples/microcoap_server/microcoap_conn.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 Kaspar Schleiser + * + * 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. + */ + +#include "net/af.h" +#include "net/conn/udp.h" + +#ifdef MICROCOAP_DEBUG +#define ENABLE_DEBUG (1) +#else +#define ENABLE_DEBUG (0) +#endif +#include "debug.h" + +#include "coap.h" + +static uint8_t _udp_buf[512]; /* udp read buffer (max udp payload size) */ +uint8_t scratch_raw[1024]; /* microcoap scratch buffer */ + +coap_rw_buffer_t scratch_buf = { scratch_raw, sizeof(scratch_raw) }; + +#define COAP_SERVER_PORT (5683) + +/* + * Starts a blocking and never-returning loop dispatching CoAP requests. + * + * When using gnrc, make sure the calling thread has an initialized msg queue. + */ +void microcoap_server_loop(void) +{ + + uint8_t laddr[16] = { 0 }; + uint8_t raddr[16] = { 0 }; + size_t raddr_len; + uint16_t rport; + + conn_udp_t conn; + + int rc = conn_udp_create(&conn, laddr, sizeof(laddr), AF_INET6, COAP_SERVER_PORT); + + while (1) { + DEBUG("Waiting for incoming UDP packet...\n"); + rc = conn_udp_recvfrom(&conn, (char *)_udp_buf, sizeof(_udp_buf), raddr, &raddr_len, &rport); + if (rc < 0) { + DEBUG("Error in conn_udp_recvfrom(). rc=%u\n", rc); + continue; + } + + size_t n = rc; + + coap_packet_t pkt; + DEBUG("Received packet: "); + coap_dump(_udp_buf, n, true); + DEBUG("\n"); + + /* parse UDP packet to CoAP */ + if (0 != (rc = coap_parse(&pkt, _udp_buf, n))) { + DEBUG("Bad packet rc=%d\n", rc); + } + else { + coap_packet_t rsppkt; + DEBUG("content:\n"); + coap_dumpPacket(&pkt); + + /* handle CoAP request */ + coap_handle_req(&scratch_buf, &pkt, &rsppkt); + + /* build reply */ + size_t rsplen = sizeof(_udp_buf); + if ((rc = coap_build(_udp_buf, &rsplen, &rsppkt)) != 0) { + DEBUG("coap_build failed rc=%d\n", rc); + } + else { + DEBUG("Sending packet: "); + coap_dump(_udp_buf, rsplen, true); + DEBUG("\n"); + DEBUG("content:\n"); + coap_dumpPacket(&rsppkt); + + /* send reply via UDP */ + rc = conn_udp_sendto(_udp_buf, rsplen, NULL, 0, raddr, raddr_len, AF_INET6, COAP_SERVER_PORT, rport); + if (rc < 0) { + DEBUG("Error sending CoAP reply via udp; %u\n", rc); + } + } + } + } +} diff --git a/pkg/microcoap/0005-fix-uninitialized-variable.patch b/pkg/microcoap/0005-fix-uninitialized-variable.patch new file mode 100644 index 0000000000..278723a3b5 Binary files /dev/null and b/pkg/microcoap/0005-fix-uninitialized-variable.patch differ