From d8e0dd70052213430c7551d96a10f3f16c123863 Mon Sep 17 00:00:00 2001 From: Harald Pichler Date: Wed, 19 Nov 2014 22:06:38 +0100 Subject: [PATCH] update to coap rfc --- .../osd/er-rest-example-merkurboard/Makefile | 96 +- .../osd/er-rest-example-merkurboard/README.md | 25 +- .../er-example-client.c | 100 +- .../er-example-server.c | 860 +---------- .../er-plugtest-server.c | 1270 +---------------- .../er-rest-example-merkurboard/er-plugtest.h | 66 + .../project-conf.h | 101 +- .../resources/res-b1-sep-b2.c | 111 ++ .../resources/res-battery.c | 81 ++ .../resources/res-chunks.c | 97 ++ .../resources/res-event.c | 101 ++ .../resources/res-hello.c | 81 ++ .../resources/res-leds.c | 108 ++ .../resources/res-light.c | 87 ++ .../resources/res-mirror.c | 177 +++ .../resources/res-plugtest-create1.c | 80 ++ .../resources/res-plugtest-create2.c | 60 + .../resources/res-plugtest-create3.c | 80 ++ .../resources/res-plugtest-large-create.c | 91 ++ .../resources/res-plugtest-large-update.c | 127 ++ .../resources/res-plugtest-large.c | 92 ++ .../resources/res-plugtest-links.c | 71 + .../resources/res-plugtest-locquery.c | 63 + .../resources/res-plugtest-longpath.c | 68 + .../resources/res-plugtest-multi.c | 87 ++ .../resources/res-plugtest-obs.c | 155 ++ .../resources/res-plugtest-path.c | 72 + .../resources/res-plugtest-query.c | 75 + .../resources/res-plugtest-separate.c | 133 ++ .../resources/res-plugtest-test.c | 159 +++ .../resources/res-plugtest-validate.c | 137 ++ .../resources/res-push.c | 89 ++ .../resources/res-radio.c | 102 ++ .../resources/res-separate.c | 127 ++ .../resources/res-sht11.c | 96 ++ .../resources/res-sub.c | 69 + .../resources/res-toggle.c | 63 + .../server-client-native.csc | 231 +++ .../server-client.csc | 144 +- .../server-only.csc | 122 +- 40 files changed, 3644 insertions(+), 2310 deletions(-) create mode 100644 examples/osd/er-rest-example-merkurboard/er-plugtest.h create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-b1-sep-b2.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-battery.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-chunks.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-event.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-hello.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-leds.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-light.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-mirror.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create1.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create2.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create3.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-create.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-update.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-links.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-locquery.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-longpath.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-multi.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-obs.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-path.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-query.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-separate.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-test.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-plugtest-validate.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-push.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-radio.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-separate.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-sht11.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-sub.c create mode 100644 examples/osd/er-rest-example-merkurboard/resources/res-toggle.c create mode 100644 examples/osd/er-rest-example-merkurboard/server-client-native.csc diff --git a/examples/osd/er-rest-example-merkurboard/Makefile b/examples/osd/er-rest-example-merkurboard/Makefile index 60d971598..9a1e3e242 100644 --- a/examples/osd/er-rest-example-merkurboard/Makefile +++ b/examples/osd/er-rest-example-merkurboard/Makefile @@ -1,70 +1,37 @@ all: er-example-server er-example-client -# use this target explicitly if requried: er-plugtest-server - - -# variable for this Makefile -# configure CoAP implementation (3|7|12|13) (er-coap-07 also supports CoAP draft 08) -WITH_COAP=13 - -# for some platforms -UIP_CONF_IPV6=1 -# IPv6 make config disappeared completely -CFLAGS += -DUIP_CONF_IPV6=1 +# use target "er-plugtest-server" explicitly when requried CONTIKI=../../.. + +# Contiki IPv6 configuration +WITH_UIP6=1 +UIP_CONF_IPV6=1 +CFLAGS += -DUIP_CONF_IPV6=1 +CFLAGS += -DUIP_CONF_IPV6_RPL=1 + CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" -# variable for Makefile.include -ifneq ($(TARGET), minimal-net) -CFLAGS += -DUIP_CONF_IPV6_RPL=1 +# automatically build RESTful resources +REST_RESOURCES_DIR = ./resources +ifndef TARGET +REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c')) else -# minimal-net does not support RPL under Linux and is mostly used to test CoAP only -${info INFO: compiling without RPL} -CFLAGS += -DUIP_CONF_IPV6_RPL=0 -CFLAGS += -DHARD_CODED_ADDRESS=\"fdfd::10\" -${info INFO: compiling with large buffers} -CFLAGS += -DUIP_CONF_BUFFER_SIZE=2048 -CFLAGS += -DREST_MAX_CHUNK_SIZE=1024 -CFLAGS += -DCOAP_MAX_HEADER_SIZE=640 +ifeq ($(TARGET), native) +REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c')) +else +REST_RESOURCES_FILES = $(notdir $(shell find $(REST_RESOURCES_DIR) -name '*.c' ! -name 'res-plugtest*')) endif +endif + +PROJECTDIRS += $(REST_RESOURCES_DIR) +PROJECT_SOURCEFILES += $(REST_RESOURCES_FILES) # linker optimizations SMALL=1 -# REST framework, requires WITH_COAP -ifeq ($(WITH_COAP), 13) -${info INFO: compiling with CoAP-13} -CFLAGS += -DWITH_COAP=13 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-13 -else ifeq ($(WITH_COAP), 12) -${info INFO: compiling with CoAP-12} -CFLAGS += -DWITH_COAP=12 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-12 -else ifeq ($(WITH_COAP), 7) -${info INFO: compiling with CoAP-08} -CFLAGS += -DWITH_COAP=7 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-07 -else ifeq ($(WITH_COAP), 3) -${info INFO: compiling with CoAP-03} -CFLAGS += -DWITH_COAP=3 -CFLAGS += -DREST=coap_rest_implementation -CFLAGS += -DUIP_CONF_TCP=0 -APPS += er-coap-03 -else -${info INFO: compiling with HTTP} -CFLAGS += -DWITH_HTTP -CFLAGS += -DREST=http_rest_implementation -CFLAGS += -DUIP_CONF_TCP=1 -APPS += er-http-engine -endif - -APPS += erbium +# REST Engine shall use Erbium CoAP implementation +APPS += er-coap +APPS += rest-engine # optional rules to get assembly #CUSTOM_RULE_C_TO_OBJECTDIR_O = 1 @@ -72,6 +39,16 @@ APPS += erbium include $(CONTIKI)/Makefile.include +# minimal-net target is currently broken in Contiki +ifeq ($(TARGET), minimal-net) +CFLAGS += -DHARD_CODED_ADDRESS=\"fdfd::10\" +${info INFO: er-example compiling with large buffers} +CFLAGS += -DUIP_CONF_BUFFER_SIZE=1300 +CFLAGS += -DREST_MAX_CHUNK_SIZE=1024 +CFLAGS += -DCOAP_MAX_HEADER_SIZE=176 +CFLAGS += -DUIP_CONF_IPV6_RPL=0 +endif + # optional rules to get assembly #$(OBJECTDIR)/%.o: asmdir/%.S # $(CC) $(CFLAGS) -MMD -c $< -o $@ @@ -88,7 +65,10 @@ connect-router: $(CONTIKI)/tools/tunslip6 sudo $(CONTIKI)/tools/tunslip6 aaaa::1/64 connect-router-cooja: $(CONTIKI)/tools/tunslip6 - sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 aaaa::1/64 + sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 -p 60001 aaaa::1/64 + +connect-router-native: $(CONTIKI)/examples/ipv6/native-border-router/border-router.native + sudo $(CONTIKI)/exmples/ipv6/native-border-router/border-router.native -a 127.0.0.1 -p 60001 aaaa::1/64 connect-minimal: - sudo ip address add fdfd::1/64 dev tap0 + sudo ip address add fdfd::1/64 dev tap0 diff --git a/examples/osd/er-rest-example-merkurboard/README.md b/examples/osd/er-rest-example-merkurboard/README.md index 1aa35b091..fe82ed9b5 100644 --- a/examples/osd/er-rest-example-merkurboard/README.md +++ b/examples/osd/er-rest-example-merkurboard/README.md @@ -21,6 +21,7 @@ PRELIMINARIES You can disable RDC in border-router project-conf.h (not really required as BR keeps radio turned on). #undef NETSTACK_CONF_RDC #define NETSTACK_CONF_RDC nullrdc_driver +- Alternatively, you can use the native-border-router together with the slip-radio. - For convenience, define the Cooja addresses in /etc/hosts aaaa::0212:7401:0001:0101 cooja1 aaaa::0212:7402:0002:0202 cooja2 @@ -125,10 +126,10 @@ Under Windows/Cygwin, WPCAP might need a patch in DETAILS ------- -Erbium currently implements draft 13. Central features are commented in -er-example-server.c. In general, apps/er-coap-13 supports: +Erbium implements the Proposed Standard of CoAP. Central features are commented +in er-example-server.c. In general, apps/er-coap supports: -- All draft 13 header options +- All draft-18 header options - CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS) - Blockwise Transfers (note REST_MAX_CHUNK_SIZE, see er-plugtest-server.c for Block1 uploads) @@ -138,24 +139,6 @@ er-example-server.c. In general, apps/er-coap-13 supports: - Observing Resources (see EVENT_ and PRERIODIC_RESOURCE, note COAP_MAX_OBSERVERS) -REST IMPLEMENTATIONS --------------------- - -The Makefile uses WITH_COAP to configure different implementations for the -Erbium (Er) REST Engine. - -- WITH_COAP=13 uses Erbium CoAP 13 apps/er-coap-13/. The default port for - coap-13 is 5683. -- WITH_COAP=12 uses Erbium CoAP 12 apps/er-coap-12/. The default port for - coap-12 is 5683. -- WITH_COAP=7 uses Erbium CoAP 08 apps/er-coap-07/. The default port for - coap-07/-08 is 5683. -- WITH_COAP=3 uses Erbium CoAP 03 apps/er-coap-03/. The default port for - coap-03 is 61616. er-coap-03 produces some warnings, as it not fully - maintained anymore. -- WITH_COAP=0 is a stub to link an Erbium HTTP engine that uses the same - resource abstraction (REST.x() functions and RESOURCE macros. - TODOs ----- diff --git a/examples/osd/er-rest-example-merkurboard/er-example-client.c b/examples/osd/er-rest-example-merkurboard/er-example-client.c index 14b5a291a..fa3df6a22 100644 --- a/examples/osd/er-rest-example-merkurboard/er-example-client.c +++ b/examples/osd/er-rest-example-merkurboard/er-example-client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Matthias Kovatsch + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ /** * \file - * Erbium (Er) CoAP client example + * Erbium (Er) CoAP client example. * \author * Matthias Kovatsch */ @@ -39,55 +39,46 @@ #include #include #include - #include "contiki.h" #include "contiki-net.h" - +#include "er-coap-engine.h" #include "dev/button-sensor.h" -#include "dev/leds.h" - -#if WITH_COAP == 3 -#include "er-coap-03-engine.h" -#elif WITH_COAP == 6 -#include "er-coap-06-engine.h" -#elif WITH_COAP == 7 -#include "er-coap-07-engine.h" -#elif WITH_COAP == 12 -#include "er-coap-12-engine.h" -#elif WITH_COAP == 13 -#include "er-coap-13-engine.h" -#else -#error "CoAP version defined by WITH_COAP not implemented" -#endif - #define DEBUG 0 #if DEBUG +#include #define PRINTF(...) printf(__VA_ARGS__) #define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) #else #define PRINTF(...) #define PRINT6ADDR(addr) #define PRINTLLADDR(addr) #endif -/* TODO: This server address is hard-coded for Cooja. */ -#define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0221, 0x2eff, 0xff00, 0x26e6) /* cooja2 */ +/* FIXME: This server address is hard-coded for Cooja and link-local for unconnected border router. */ +#define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xfe80, 0, 0, 0, 0x0212, 0x7402, 0x0002, 0x0202) /* cooja2 */ +/* #define SERVER_NODE(ipaddr) uip_ip6addr(ipaddr, 0xbbbb, 0, 0, 0, 0, 0, 0, 0x1) */ -#define LOCAL_PORT UIP_HTONS(COAP_DEFAULT_PORT+1) +#define LOCAL_PORT UIP_HTONS(COAP_DEFAULT_PORT + 1) #define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT) -PROCESS(coap_client_example, "COAP Client Example"); -AUTOSTART_PROCESSES(&coap_client_example); +#define TOGGLE_INTERVAL 10 +PROCESS(er_example_client, "Erbium Example Client"); +AUTOSTART_PROCESSES(&er_example_client); uip_ipaddr_t server_ipaddr; +static struct etimer et; /* Example URIs that can be queried. */ #define NUMBER_OF_URLS 4 /* leading and ending slashes only for demo purposes, get cropped automatically when setting the Uri-Path */ -char* service_urls[NUMBER_OF_URLS] = {".well-known/core", "/actuators/toggle", "battery/", "error/in//path"}; +char *service_urls[NUMBER_OF_URLS] = +{ ".well-known/core", "/actuators/toggle", "battery/", "error/in//path" }; +#if PLATFORM_HAS_BUTTON +static int uri_switch = 0; +#endif /* This function is will be passed to COAP_BLOCKING_REQUEST() to handle responses. */ void @@ -96,53 +87,72 @@ client_chunk_handler(void *response) const uint8_t *chunk; int len = coap_get_payload(response, &chunk); + printf("|%.*s", len, (char *)chunk); } - - -PROCESS_THREAD(coap_client_example, ev, data) +PROCESS_THREAD(er_example_client, ev, data) { PROCESS_BEGIN(); - leds_off(LEDS_RED); + static coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ - static coap_packet_t request[1]; /* This way the packet can be treated as pointer as usual. */ SERVER_NODE(&server_ipaddr); /* receives all CoAP messages */ - coap_receiver_init(); + coap_init_engine(); + + etimer_set(&et, TOGGLE_INTERVAL * CLOCK_SECOND); #if PLATFORM_HAS_BUTTON SENSORS_ACTIVATE(button_sensor); - PRINTF("Press a button to request %s\n", service_urls[1]); + printf("Press a button to request %s\n", service_urls[uri_switch]); #endif while(1) { PROCESS_YIELD(); -#if PLATFORM_HAS_BUTTON - if (ev == sensors_event && data == &button_sensor) { + if(etimer_expired(&et)) { + printf("--Toggle timer--\n"); - /* send a request to notify the end of the process */ - - PRINTF("--Toggle --\n"); - leds_toggle(LEDS_RED); /* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ - coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0 ); + coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0); coap_set_header_uri_path(request, service_urls[1]); const char msg[] = "Toggle!"; - coap_set_payload(request, (uint8_t *)msg, sizeof(msg)-1); + coap_set_payload(request, (uint8_t *)msg, sizeof(msg) - 1); PRINT6ADDR(&server_ipaddr); PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); - COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, client_chunk_handler); + COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, + client_chunk_handler); - PRINTF("\n--Done--\n"); - } + printf("\n--Done--\n"); + + etimer_reset(&et); + +#if PLATFORM_HAS_BUTTON + } else if(ev == sensors_event && data == &button_sensor) { + + /* send a request to notify the end of the process */ + + coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0); + coap_set_header_uri_path(request, service_urls[uri_switch]); + + printf("--Requesting %s--\n", service_urls[uri_switch]); + + PRINT6ADDR(&server_ipaddr); + PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); + + COAP_BLOCKING_REQUEST(&server_ipaddr, REMOTE_PORT, request, + client_chunk_handler); + + printf("\n--Done--\n"); + + uri_switch = (uri_switch + 1) % NUMBER_OF_URLS; #endif + } } PROCESS_END(); diff --git a/examples/osd/er-rest-example-merkurboard/er-example-server.c b/examples/osd/er-rest-example-merkurboard/er-example-server.c index 48b320f26..41a07a501 100644 --- a/examples/osd/er-rest-example-merkurboard/er-example-server.c +++ b/examples/osd/er-rest-example-merkurboard/er-example-server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Matthias Kovatsch + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ /** * \file - * Erbium (Er) REST Engine example (with CoAP-specific code) + * Erbium (Er) REST Engine example. * \author * Matthias Kovatsch */ @@ -41,763 +41,68 @@ #include #include "contiki.h" #include "contiki-net.h" +#include "rest-engine.h" - -/* Define which resources to include to meet memory constraints. */ -#define REST_RES_INFO 1 -#define REST_RES_HELLO 0 -#define REST_RES_MIRROR 0 /* causes largest code size */ -#define REST_RES_CHUNKS 1 -#define REST_RES_SEPARATE 0 -#define REST_RES_PUSHING 0 -#define REST_RES_EVENT 1 -#define REST_RES_SUB 0 -#define REST_RES_LEDS 1 -#define REST_RES_TOGGLE 1 -#define REST_RES_LIGHT 0 -#define REST_RES_BATTERY 1 -#define REST_RES_RADIO 0 - - -#include "erbium.h" - - -#if defined (PLATFORM_HAS_BUTTON) +#if PLATFORM_HAS_BUTTON #include "dev/button-sensor.h" #endif -#if defined (PLATFORM_HAS_LEDS) -#include "dev/leds.h" -#endif -#if defined (PLATFORM_HAS_LIGHT) -#include "dev/light-sensor.h" -#endif -#if defined (PLATFORM_HAS_BATTERY) -#include "dev/battery-sensor.h" -#endif -#if defined (PLATFORM_HAS_SHT11) -#include "dev/sht11-sensor.h" -#endif -#if defined (PLATFORM_HAS_RADIO) -#include "dev/radio-sensor.h" -#endif - - -/* For CoAP-specific example: not required for normal RESTful Web service. */ -#if WITH_COAP == 3 -#include "er-coap-03.h" -#elif WITH_COAP == 7 -#include "er-coap-07.h" -#elif WITH_COAP == 12 -#include "er-coap-12.h" -#elif WITH_COAP == 13 -#include "er-coap-13.h" -#else -#warning "Erbium example without CoAP-specifc functionality" -#endif /* CoAP-specific example */ #define DEBUG 0 #if DEBUG +#include #define PRINTF(...) printf(__VA_ARGS__) #define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) #else #define PRINTF(...) #define PRINT6ADDR(addr) #define PRINTLLADDR(addr) #endif -/******************************************************************************/ -#if REST_RES_HELLO /* - * Resources are defined by the RESOURCE macro. - * Signature: resource name, the RESTful methods it handles, and its URI path (omitting the leading slash). + * Resources to be activated need to be imported through the extern keyword. + * The build system automatically compiles the resources in the corresponding sub-directory. */ -RESOURCE(helloworld, METHOD_GET, "hello", "title=\"Hello world: ?len=0..\";rt=\"Text\""); - -/* - * A handler function named [resource name]_handler must be implemented for each RESOURCE. - * A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore - * preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE limit for the buffer. - * If a smaller block size is requested for CoAP, the REST framework automatically splits the data. - */ -void -helloworld_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - const char *len = NULL; - /* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */ - char const * const message = "Hello World! ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"; - int length = 12; /* |<-------->| */ - - /* The query string can be retrieved by rest_get_query() or parsed for its key-value pairs. */ - if (REST.get_query_variable(request, "len", &len)) { - length = atoi(len); - if (length<0) length = 0; - if (length>REST_MAX_CHUNK_SIZE) length = REST_MAX_CHUNK_SIZE; - memcpy(buffer, message, length); - } else { - memcpy(buffer, message, length); - } - - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ - REST.set_header_etag(response, (uint8_t *) &length, 1); - REST.set_response_payload(response, buffer, length); -} +extern resource_t + res_hello, + res_mirror, + res_chunks, + res_separate, + res_push, + res_event, + res_sub, + res_b1_sep_b2; +#if PLATFORM_HAS_LEDS +extern resource_t res_leds, res_toggle; #endif - -/******************************************************************************/ -#if REST_RES_MIRROR -/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ -RESOURCE(mirror, METHOD_GET | METHOD_POST | METHOD_PUT | METHOD_DELETE, "debug/mirror", "title=\"Returns your decoded message\";rt=\"Debug\""); - -void -mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* The ETag and Token is copied to the header. */ - uint8_t opaque[] = {0x0A, 0xBC, 0xDE}; - - /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ - static char location[] = {'/','f','/','a','?','k','&','e', 0}; - - /* Getter for the header option Content-Type. If the option is not set, text/plain is returned by default. */ - unsigned int content_type = REST.get_header_content_type(request); - - /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ - uint32_t max_age_and_size = 0; - const char *str = NULL; - uint32_t observe = 0; - const uint8_t *bytes = NULL; - uint32_t block_num = 0; - uint8_t block_more = 0; - uint16_t block_size = 0; - const char *query = ""; - int len = 0; - - /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ - - int strpos = 0; - /* snprintf() counts the terminating '\0' to the size parameter. - * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. - * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ - if (content_type!=-1) - { - strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE+1, "CT %u\n", content_type); - } - - /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. - * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ - if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &max_age_and_size)) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "MA %lu\n", max_age_and_size); - } - /* For HTTP this is the Length option, for CoAP it is the Size option. */ - if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_length(request, &max_age_and_size)) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "SZ %lu\n", max_age_and_size); - } - - if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str))) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UH %.*s\n", len, str); - } - -/* CoAP-specific example: actions not required for normal RESTful Web service. */ -#if WITH_COAP > 1 - if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_observe(request, &observe)) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Ob %lu\n", observe); - } - if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_token(request, &bytes))) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "To 0x"); - int index = 0; - for (index = 0; index 03 */ -#endif /* CoAP-specific example */ - - if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &query))) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Qu %.*s\n", len, query); - } - if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_request_payload(request, &bytes))) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s", len, bytes); - } - - if (strpos >= REST_MAX_CHUNK_SIZE) - { - buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* 'ยป' to indicate truncation */ - } - - REST.set_response_payload(response, buffer, strpos); - - PRINTF("/mirror options received: %s\n", buffer); - - /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ - REST.set_header_etag(response, opaque, 2); - REST.set_header_location(response, location); /* Initial slash is omitted by framework */ - REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */ - -/* CoAP-specific example: actions not required for normal RESTful Web service. */ -#if WITH_COAP > 1 - coap_set_header_uri_host(response, "tiki"); - coap_set_header_observe(response, 10); -#if WITH_COAP == 3 - coap_set_header_block(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ -#else - coap_set_header_proxy_uri(response, "ftp://x"); - coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ - coap_set_header_block1(response, 23, 0, 16); - coap_set_header_accept(response, TEXT_PLAIN); - coap_set_header_if_none_match(response); -#endif /* CoAP > 03 */ -#endif /* CoAP-specific example */ -} -#endif /* REST_RES_MIRROR */ - -/******************************************************************************/ -#if REST_RES_CHUNKS -/* - * For data larger than REST_MAX_CHUNK_SIZE (e.g., stored in flash) resources must be aware of the buffer limitation - * and split their responses by themselves. To transfer the complete resource through a TCP stream or CoAP's blockwise transfer, - * the byte offset where to continue is provided to the handler as int32_t pointer. - * These chunk-wise resources must set the offset value to its new position or -1 of the end is reached. - * (The offset for CoAP's blockwise transfer can go up to 2'147'481'600 = ~2047 M for block size 2048 (reduced to 1024 in observe-03.) - */ -RESOURCE(chunks, METHOD_GET, "test/chunks", "title=\"Blockwise demo\";rt=\"Data\""); - -#define CHUNKS_TOTAL 2050 - -void -chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - int32_t strpos = 0; - - /* Check the offset for boundaries of the resource data. */ - if (*offset>=CHUNKS_TOTAL) - { - REST.set_response_status(response, REST.status.BAD_OPTION); - /* A block error message should not exceed the minimum block size (16). */ - - const char *error_msg = "BlockOutOfScope"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - /* Generate data until reaching CHUNKS_TOTAL. */ - while (strpos preferred_size) - { - strpos = preferred_size; - } - - /* Truncate if above CHUNKS_TOTAL bytes. */ - if (*offset+(int32_t)strpos > CHUNKS_TOTAL) - { - strpos = CHUNKS_TOTAL - *offset; - } - - REST.set_response_payload(response, buffer, strpos); - - /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ - *offset += strpos; - - /* Signal end of resource representation. */ - if (*offset>=CHUNKS_TOTAL) - { - *offset = -1; - } -} -#endif - -/******************************************************************************/ -#if REST_RES_SEPARATE && defined (PLATFORM_HAS_BUTTON) && WITH_COAP > 3 -/* Required to manually (=not by the engine) handle the response transaction. */ -#if WITH_COAP == 7 -#include "er-coap-07-separate.h" -#include "er-coap-07-transactions.h" -#elif WITH_COAP == 12 -#include "er-coap-12-separate.h" -#include "er-coap-12-transactions.h" -#elif WITH_COAP == 13 -#include "er-coap-13-separate.h" -#include "er-coap-13-transactions.h" +#if PLATFORM_HAS_LIGHT +#include "dev/light-sensor.h" +extern resource_t res_light; #endif /* - * CoAP-specific example for separate responses. - * Note the call "rest_set_pre_handler(&resource_separate, coap_separate_handler);" in the main process. - * The pre-handler takes care of the empty ACK and updates the MID and message type for CON requests. - * The resource handler must store all information that required to finalize the response later. - */ -RESOURCE(separate, METHOD_GET, "test/separate", "title=\"Separate demo\""); - -/* A structure to store the required information */ -typedef struct application_separate_store { - /* Provided by Erbium to store generic request information such as remote address and token. */ - coap_separate_t request_metadata; - /* Add fields for addition information to be stored for finalizing, e.g.: */ - char buffer[16]; -} application_separate_store_t; - -static uint8_t separate_active = 0; -static application_separate_store_t separate_store[1]; - -void -separate_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* - * Example allows only one open separate response. - * For multiple, the application must manage the list of stores. - */ - if (separate_active) - { - coap_separate_reject(); - } - else - { - separate_active = 1; - - /* Take over and skip response by engine. */ - coap_separate_accept(request, &separate_store->request_metadata); - /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ - - /* - * At the moment, only the minimal information is stored in the store (client address, port, token, MID, type, and Block2). - * Extend the store, if the application requires additional information from this handler. - * buffer is an example field for custom information. - */ - snprintf(separate_store->buffer, sizeof(separate_store->buffer), "StoredInfo"); - } -} - -void -separate_finalize_handler() -{ - if (separate_active) - { - coap_transaction_t *transaction = NULL; - if ( (transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port)) ) - { - coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ - - /* Restore the request information for the response. */ - coap_separate_resume(response, &separate_store->request_metadata, REST.status.OK); - - coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); - - /* - * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. - * As it is a critical option, this example resource pretends to handle it for compliance. - */ - coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); - - /* Warning: No check for serialization error. */ - transaction->packet_len = coap_serialize_message(response, transaction->packet); - coap_send_transaction(transaction); - /* The engine will clear the transaction (right after send for NON, after acked for CON). */ - - separate_active = 0; - } - else - { - /* - * Set timer for retry, send error message, ... - * The example simply waits for another button press. - */ - } - } /* if (separate_active) */ -} +#if PLATFORM_HAS_BATTERY +#include "dev/battery-sensor.h" +extern resource_t res_battery; #endif - -/******************************************************************************/ -#if REST_RES_PUSHING -/* - * Example for a periodic resource. - * It takes an additional period parameter, which defines the interval to call [name]_periodic_handler(). - * A default post_handler takes care of subscriptions by managing a list of subscribers to notify. - */ -PERIODIC_RESOURCE(pushing, METHOD_GET, "test/push", "title=\"Periodic demo\";obs", 5*CLOCK_SECOND); - -void -pushing_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - - /* Usually, a CoAP server would response with the resource representation matching the periodic_handler. */ - const char *msg = "It's periodic!"; - REST.set_response_payload(response, msg, strlen(msg)); - - /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ -} - -/* - * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. - * It will be called by the REST manager process with the defined period. - */ -void -pushing_periodic_handler(resource_t *r) -{ - static uint16_t obs_counter = 0; - static char content[11]; - - ++obs_counter; - - PRINTF("TICK %u for /%s\n", obs_counter, r->url); - - /* Build notification. */ - coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ - coap_init_message(notification, COAP_TYPE_NON, REST.status.OK, 0 ); - coap_set_payload(notification, content, snprintf(content, sizeof(content), "TICK %u", obs_counter)); - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(r, obs_counter, notification); -} +#if PLATFORM_HAS_RADIO +#include "dev/radio-sensor.h" +extern resource_t res_radio; #endif - -/******************************************************************************/ -#if REST_RES_EVENT && defined (PLATFORM_HAS_BUTTON) -/* - * Example for an event resource. - * Additionally takes a period parameter that defines the interval to call [name]_periodic_handler(). - * A default post_handler takes care of subscriptions and manages a list of subscribers to notify. - */ -EVENT_RESOURCE(event, METHOD_GET, "sensors/button", "title=\"Event demo\";obs"); - -void -event_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - /* Usually, a CoAP server would response with the current resource representation. */ - const char *msg = "It's eventful!"; - REST.set_response_payload(response, (uint8_t *)msg, strlen(msg)); - - /* A post_handler that handles subscriptions/observing will be called for periodic resources by the framework. */ -} - -/* Additionally, a handler function named [resource name]_event_handler must be implemented for each PERIODIC_RESOURCE defined. - * It will be called by the REST manager process with the defined period. */ -void -event_event_handler(resource_t *r) -{ - static uint16_t event_counter = 0; - static char content[12]; - - ++event_counter; - - PRINTF("TICK %u for /%s\n", event_counter, r->url); - - /* Build notification. */ - coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ - coap_init_message(notification, COAP_TYPE_CON, REST.status.OK, 0 ); - coap_set_payload(notification, content, snprintf(content, sizeof(content), "EVENT %u", event_counter)); - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(r, event_counter, notification); -} -#endif /* PLATFORM_HAS_BUTTON */ - -/******************************************************************************/ -#if REST_RES_SUB -/* - * Example for a resource that also handles all its sub-resources. - * Use REST.get_url() to multiplex the handling of the request depending on the Uri-Path. - */ -RESOURCE(sub, METHOD_GET | HAS_SUB_RESOURCES, "test/path", "title=\"Sub-resource demo\""); - -void -sub_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - - const char *uri_path = NULL; - int len = REST.get_url(request, &uri_path); - int base_len = strlen(resource_sub.url); - - if (len==base_len) - { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "Request any sub-resource of /%s", resource_sub.url); - } - else - { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, ".%.*s", len-base_len, uri_path+base_len); - } - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); -} +#if PLATFORM_HAS_SHT11 +#include "dev/sht11/sht11-sensor.h" +extern resource_t res_sht11; #endif +*/ -/******************************************************************************/ -#if defined (PLATFORM_HAS_LEDS) -/******************************************************************************/ -#if REST_RES_LEDS -/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ -RESOURCE(leds, METHOD_POST | METHOD_PUT , "actuators/leds", "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\""); +PROCESS(er_example_server, "Erbium Example Server"); +AUTOSTART_PROCESSES(&er_example_server); -void -leds_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - size_t len = 0; - const char *color = NULL; - const char *mode = NULL; - uint8_t led = 0; - int success = 1; - - if ((len=REST.get_query_variable(request, "color", &color))) { - PRINTF("color %.*s\n", len, color); - - if (strncmp(color, "r", len)==0) { - led = LEDS_RED; - } else if(strncmp(color,"g", len)==0) { - led = LEDS_GREEN; - } else if (strncmp(color,"b", len)==0) { - led = LEDS_BLUE; - } else { - success = 0; - } - } else { - success = 0; - } - - if (success && (len=REST.get_post_variable(request, "mode", &mode))) { - PRINTF("mode %s\n", mode); - - if (strncmp(mode, "on", len)==0) { - leds_on(led); - } else if (strncmp(mode, "off", len)==0) { - leds_off(led); - } else { - success = 0; - } - } else { - success = 0; - } - - if (!success) { - REST.set_response_status(response, REST.status.BAD_REQUEST); - } -} -#endif - -/******************************************************************************/ -#if REST_RES_TOGGLE -/* A simple actuator example. Toggles the red led */ -RESOURCE(toggle, METHOD_POST, "actuators/toggle", "title=\"Red LED\";rt=\"Control\""); -void -toggle_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - leds_toggle(LEDS_RED); -} -#endif -#endif /* PLATFORM_HAS_LEDS */ - -/******************************************************************************/ -#if REST_RES_LIGHT && defined (PLATFORM_HAS_LIGHT) -/* A simple getter example. Returns the reading from light sensor with a simple etag */ -RESOURCE(light, METHOD_GET, "sensors/light", "title=\"Photosynthetic and solar light (supports JSON)\";rt=\"LightSensor\""); -void -light_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - uint16_t light_photosynthetic = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC); - uint16_t light_solar = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR); - - const uint16_t *accept = NULL; - int num = REST.get_header_accept(request, &accept); - - if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) - { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%u;%u", light_photosynthetic, light_solar); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } - else if (num && (accept[0]==REST.type.APPLICATION_XML)) - { - REST.set_header_content_type(response, REST.type.APPLICATION_XML); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "", light_photosynthetic, light_solar); - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } - else if (num && (accept[0]==REST.type.APPLICATION_JSON)) - { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'light':{'photosynthetic':%u,'solar':%u}}", light_photosynthetic, light_solar); - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } - else - { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain, application/xml, and application/json"; - REST.set_response_payload(response, msg, strlen(msg)); - } -} -#endif /* PLATFORM_HAS_LIGHT */ - -/******************************************************************************/ -#if REST_RES_BATTERY && defined (PLATFORM_HAS_BATTERY) -/* A simple getter example. Returns the reading from light sensor with a simple etag */ -RESOURCE(battery, METHOD_GET, "sensors/battery", "title=\"Battery status\";rt=\"Battery\""); -void -battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - int battery = battery_sensor.value(0); - - const uint16_t *accept = NULL; - int num = REST.get_header_accept(request, &accept); - - if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) - { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", battery); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } - else if (num && (accept[0]==REST.type.APPLICATION_JSON)) - { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d}", battery); - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } - else - { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain and application/json"; - REST.set_response_payload(response, msg, strlen(msg)); - } -} -#endif /* PLATFORM_HAS_BATTERY */ - - -#if defined (PLATFORM_HAS_RADIO) && REST_RES_RADIO -/* A simple getter example. Returns the reading of the rssi/lqi from radio sensor */ -RESOURCE(radio, METHOD_GET, "sensor/radio", "title=\"RADIO: ?p=lqi|rssi\";rt=\"RadioSensor\""); - -void -radio_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - size_t len = 0; - const char *p = NULL; - uint8_t param = 0; - int success = 1; - - const uint16_t *accept = NULL; - int num = REST.get_header_accept(request, &accept); - - if ((len=REST.get_query_variable(request, "p", &p))) { - PRINTF("p %.*s\n", len, p); - if (strncmp(p, "lqi", len)==0) { - param = RADIO_SENSOR_LAST_VALUE; - } else if(strncmp(p,"rssi", len)==0) { - param = RADIO_SENSOR_LAST_PACKET; - } else { - success = 0; - } - } else { - success = 0; - } - - if (success) { - if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) - { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", radio_sensor.value(param)); - - REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); - } - else if (num && (accept[0]==REST.type.APPLICATION_JSON)) - { - REST.set_header_content_type(response, REST.type.APPLICATION_JSON); - - if (param == RADIO_SENSOR_LAST_VALUE) { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'lqi':%d}", radio_sensor.value(param)); - } else if (param == RADIO_SENSOR_LAST_PACKET) { - snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'rssi':%d}", radio_sensor.value(param)); - } - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); - } - else - { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain and application/json"; - REST.set_response_payload(response, msg, strlen(msg)); - } - } else { - REST.set_response_status(response, REST.status.BAD_REQUEST); - } -} -#endif - -void -hw_init() -{ -#if defined (PLATFORM_HAS_LEDS) - leds_off(LEDS_RED); -#endif -} - -PROCESS(rest_server_example, "Erbium Example Server"); -AUTOSTART_PROCESSES(&rest_server_example); - -PROCESS_THREAD(rest_server_example, ev, data) +PROCESS_THREAD(er_example_server, ev, data) { PROCESS_BEGIN(); + PROCESS_PAUSE(); + PRINTF("Starting Erbium Example Server\n"); #ifdef RF_CHANNEL @@ -812,75 +117,60 @@ PROCESS_THREAD(rest_server_example, ev, data) PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); - /* Initialize the OSD Hardware. */ - hw_init(); /* Initialize the REST engine. */ rest_init_engine(); - /* Activate the application-specific resources. */ -#if REST_RES_HELLO - rest_activate_resource(&resource_helloworld); + /* + * Bind the resources to their Uri-Path. + * WARNING: Activating twice only means alternate path, not two instances! + * All static variables are the same for each URI path. + */ + rest_activate_resource(&res_hello, "test/hello"); +/* rest_activate_resource(&res_mirror, "debug/mirror"); */ +/* rest_activate_resource(&res_chunks, "test/chunks"); */ +/* rest_activate_resource(&res_separate, "test/separate"); */ + rest_activate_resource(&res_push, "test/push"); +/* rest_activate_resource(&res_event, "sensors/button"); */ +/* rest_activate_resource(&res_sub, "test/sub"); */ +/* rest_activate_resource(&res_b1_sep_b2, "test/b1sepb2"); */ +#if PLATFORM_HAS_LEDS +/* rest_activate_resource(&res_leds, "actuators/leds"); */ + rest_activate_resource(&res_toggle, "actuators/toggle"); #endif -#if REST_RES_MIRROR - rest_activate_resource(&resource_mirror); +#if PLATFORM_HAS_LIGHT + rest_activate_resource(&res_light, "sensors/light"); + SENSORS_ACTIVATE(light_sensor); #endif -#if REST_RES_CHUNKS - rest_activate_resource(&resource_chunks); +/* +#if PLATFORM_HAS_BATTERY + rest_activate_resource(&res_battery, "sensors/battery"); + SENSORS_ACTIVATE(battery_sensor); #endif -#if REST_RES_PUSHING - rest_activate_periodic_resource(&periodic_resource_pushing); +#if PLATFORM_HAS_RADIO + rest_activate_resource(&res_radio, "sensors/radio"); + SENSORS_ACTIVATE(radio_sensor); #endif -#if defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT - rest_activate_event_resource(&resource_event); -#endif -#if defined (PLATFORM_HAS_BUTTON) && REST_RES_SEPARATE && WITH_COAP > 3 - /* No pre-handler anymore, user coap_separate_accept() and coap_separate_reject(). */ - rest_activate_resource(&resource_separate); -#endif -#if defined (PLATFORM_HAS_BUTTON) && (REST_RES_EVENT || (REST_RES_SEPARATE && WITH_COAP > 3)) - SENSORS_ACTIVATE(button_sensor); -#endif -#if REST_RES_SUB - rest_activate_resource(&resource_sub); -#endif -#if defined (PLATFORM_HAS_LEDS) -#if REST_RES_LEDS - rest_activate_resource(&resource_leds); -#endif -#if REST_RES_TOGGLE - rest_activate_resource(&resource_toggle); -#endif -#endif /* PLATFORM_HAS_LEDS */ -#if defined (PLATFORM_HAS_LIGHT) && REST_RES_LIGHT - SENSORS_ACTIVATE(light_sensor); - rest_activate_resource(&resource_light); -#endif -#if defined (PLATFORM_HAS_BATTERY) && REST_RES_BATTERY - SENSORS_ACTIVATE(battery_sensor); - rest_activate_resource(&resource_battery); -#endif -#if defined (PLATFORM_HAS_RADIO) && REST_RES_RADIO - SENSORS_ACTIVATE(radio_sensor); - rest_activate_resource(&resource_radio); +#if PLATFORM_HAS_SHT11 + rest_activate_resource(&res_sht11, "sensors/sht11"); + SENSORS_ACTIVATE(sht11_sensor); #endif +*/ /* Define application-specific events here. */ while(1) { PROCESS_WAIT_EVENT(); -#if defined (PLATFORM_HAS_BUTTON) - if (ev == sensors_event && data == &button_sensor) { - PRINTF("BUTTON\n"); -#if REST_RES_EVENT +#if PLATFORM_HAS_BUTTON + if(ev == sensors_event && data == &button_sensor) { + PRINTF("*******BUTTON*******\n"); + /* Call the event_handler for this application-specific event. */ - event_event_handler(&resource_event); -#endif -#if REST_RES_SEPARATE && WITH_COAP>3 + res_event.trigger(); + /* Also call the separate response example handler. */ - separate_finalize_handler(); -#endif + res_separate.resume(); } #endif /* PLATFORM_HAS_BUTTON */ - } /* while (1) */ + } /* while (1) */ PROCESS_END(); } diff --git a/examples/osd/er-rest-example-merkurboard/er-plugtest-server.c b/examples/osd/er-rest-example-merkurboard/er-plugtest-server.c index 5a791a09c..ae637dc4c 100644 --- a/examples/osd/er-rest-example-merkurboard/er-plugtest-server.c +++ b/examples/osd/er-rest-example-merkurboard/er-plugtest-server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Matthias Kovatsch + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,7 +31,7 @@ /** * \file - * Server for the ETSI IoT CoAP Plugtests, Paris, France, 24 - 25 March 2012 + * Server for the ETSI IoT CoAP Plugtests, Las Vegas, NV, USA, Nov 2013. * \author * Matthias Kovatsch */ @@ -41,1179 +41,37 @@ #include #include "contiki.h" #include "contiki-net.h" - -#define MAX_PLUGFEST_PAYLOAD 64+1 /* +1 for the terminating zero, which is not transmitted */ -#define MAX_PLUGFEST_BODY 2048 -#define CHUNKS_TOTAL 2012 - -/* Define which resources to include to meet memory constraints. */ -#define REST_RES_TEST 1 -#define REST_RES_LONG 1 -#define REST_RES_QUERY 1 -#define REST_RES_LOC_QUERY 1 -#define REST_RES_MULTI 1 -#define REST_RES_LINKS 1 -#define REST_RES_PATH 1 -#define REST_RES_SEPARATE 1 -#define REST_RES_LARGE 1 -#define REST_RES_LARGE_UPDATE 1 -#define REST_RES_LARGE_CREATE 1 -#define REST_RES_OBS 1 - -#define REST_RES_MIRROR 1 - - - -#if !defined (CONTIKI_TARGET_MINIMAL_NET) -#warning "Should only be compiled for minimal-net!" -#endif - - - -#include "erbium.h" - -/* For CoAP-specific example: not required for normal RESTful Web service. */ -#if WITH_COAP==7 -#include "er-coap-07.h" -#elif WITH_COAP == 12 -#include "er-coap-12.h" -#elif WITH_COAP == 13 -#include "er-coap-13.h" -#else -#error "Plugtests server without CoAP" -#endif /* CoAP-specific example */ - -#define DEBUG 1 -#if DEBUG -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) -#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5]) -#else -#define PRINTF(...) -#define PRINT6ADDR(addr) -#define PRINTLLADDR(addr) -#endif - - -#if REST_RES_TEST -/* - * Default test resource - */ -RESOURCE(test, METHOD_GET|METHOD_POST|METHOD_PUT|METHOD_DELETE, "test", "title=\"Default test resource\""); - -static uint8_t test_etag[8] = {0}; -static uint8_t test_etag_len = 1; -static uint8_t test_change = 1; -static uint8_t test_none_match_okay = 1; - -static -void -test_update_etag() -{ - int i; - test_etag_len = (random_rand() % 8) + 1; - for (i=0; i0 && len==test_etag_len && memcmp(test_etag, bytes, len)==0) - { - PRINTF("validate "); - REST.set_response_status(response, REST.status.NOT_MODIFIED); - REST.set_header_etag(response, test_etag, test_etag_len); - - test_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); - } - else - { - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_etag(response, test_etag, test_etag_len); - REST.set_header_max_age(response, 30); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - } - } - else if (method & METHOD_POST) - { - PRINTF("POST "); - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "/location1/location2/location3"); - } - else if (method & METHOD_PUT) - { - PRINTF("PUT "); - - if (coap_get_header_if_none_match(request)) - { - if (test_none_match_okay) - { - REST.set_response_status(response, REST.status.CREATED); - - test_none_match_okay = 0; - PRINTF("### SERVER ACTION ### If-None-Match will FAIL\n"); - } - else - { - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - - test_none_match_okay = 1; - PRINTF("### SERVER ACTION ### If-None-Match will SUCCEED\n"); - } - } - else if (((len = coap_get_header_if_match(request, &bytes))>0 && (len==test_etag_len && memcmp(test_etag, bytes, len)==0)) || len==0) - { - test_update_etag(); - REST.set_header_etag(response, test_etag, test_etag_len); - - REST.set_response_status(response, REST.status.CHANGED); - - if (len>0) - { - test_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); - } - } - else - { - - PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", len, test_etag_len, - bytes[0], - bytes[1], - bytes[2], - bytes[3], - bytes[4], - bytes[5], - bytes[6], - bytes[7], - test_etag[0], - test_etag[1], - test_etag[2], - test_etag[3], - test_etag[4], - test_etag[5], - test_etag[6], - test_etag[7] ); - - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } - } - else if (method & METHOD_DELETE) - { - PRINTF("DELETE "); - REST.set_response_status(response, REST.status.DELETED); - } - - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); -} - - -RESOURCE(create1, METHOD_PUT|METHOD_DELETE, "create1", "title=\"Default test resource\""); - -static uint8_t create1_exists = 0; - -void -create1_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - uint8_t method = REST.get_method_type(request); - - if (test_change) - { - test_update_etag(); - } - - PRINTF("/create1 "); - - if (method & METHOD_PUT) - { - PRINTF("PUT "); - - if (coap_get_header_if_none_match(request)) - { - if (!create1_exists) - { - REST.set_response_status(response, REST.status.CREATED); - - create1_exists = 1; - } - else - { - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } - } - else - { - REST.set_response_status(response, REST.status.CHANGED); - } - } - else if (method & METHOD_DELETE) - { - PRINTF("DELETE "); - REST.set_response_status(response, REST.status.DELETED); - - create1_exists = 0; - } -} - -RESOURCE(create2, METHOD_POST, "create2", "title=\"Creates on POST\""); - -void -create2_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - if (test_change) - { - test_update_etag(); - } - - PRINTF("/create2 "); - - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "/location1/location2/location3"); -} - -RESOURCE(create3, METHOD_PUT|METHOD_DELETE, "create3", "title=\"Default test resource\""); - -static uint8_t create3_exists = 0; - -void -create3_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - uint8_t method = REST.get_method_type(request); - - if (test_change) - { - test_update_etag(); - } - - PRINTF("/create3 "); - - if (method & METHOD_PUT) - { - PRINTF("PUT "); - - if (coap_get_header_if_none_match(request)) - { - if (!create3_exists) - { - REST.set_response_status(response, REST.status.CREATED); - - create3_exists = 1; - } - else - { - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } - } - else - { - REST.set_response_status(response, REST.status.CHANGED); - } - } - else if (method & METHOD_DELETE) - { - PRINTF("DELETE "); - REST.set_response_status(response, REST.status.DELETED); - - create3_exists = 0; - } -} - - - - - -RESOURCE(validate, METHOD_GET|METHOD_PUT, "validate", "title=\"Default test resource\""); - -static uint8_t validate_etag[8] = {0}; -static uint8_t validate_etag_len = 1; -static uint8_t validate_change = 1; - -static -void -validate_update_etag() -{ - int i; - validate_etag_len = (random_rand() % 8) + 1; - for (i=0; i0 && len==validate_etag_len && memcmp(validate_etag, bytes, len)==0) - { - PRINTF("validate "); - REST.set_response_status(response, REST.status.NOT_MODIFIED); - REST.set_header_etag(response, validate_etag, validate_etag_len); - - validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); - } - else - { - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_etag(response, validate_etag, validate_etag_len); - REST.set_header_max_age(response, 30); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - } - } - else if (method & METHOD_PUT) - { - PRINTF("PUT "); - - if (((len = coap_get_header_if_match(request, &bytes))>0 && (len==validate_etag_len && memcmp(validate_etag, bytes, len)==0)) || len==0) - { - validate_update_etag(); - REST.set_header_etag(response, validate_etag, validate_etag_len); - - REST.set_response_status(response, REST.status.CHANGED); - - if (len>0) - { - validate_change = 1; - PRINTF("### SERVER ACTION ### Resouce will change\n"); - } - } - else - { - PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", len, validate_etag_len, - bytes[0], - bytes[1], - bytes[2], - bytes[3], - bytes[4], - bytes[5], - bytes[6], - bytes[7], - validate_etag[0], - validate_etag[1], - validate_etag[2], - validate_etag[3], - validate_etag[4], - validate_etag[5], - validate_etag[6], - validate_etag[7] ); - - REST.set_response_status(response, PRECONDITION_FAILED_4_12); - } - } - - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); -} -#endif - -#if REST_RES_LONG -/* - * Long path resource - */ -RESOURCE(longpath, METHOD_GET, "seg1/seg2/seg3", "title=\"Long path resource\""); - -void -longpath_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - - uint8_t method = REST.get_method_type(request); - - PRINTF("/seg1/seg2/seg3 "); - if (method & METHOD_GET) - { - PRINTF("GET "); - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); - } - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); -} -#endif - -#if REST_RES_QUERY -/* - * Resource accepting query parameters - */ -RESOURCE(query, METHOD_GET, "query", "title=\"Resource accepting query parameters\""); - -void -query_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - int len = 0; - const char *query = NULL; - - PRINTF("/query GET (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - if ((len = REST.get_query(request, &query))) - { - PRINTF("Query: %.*s\n", len, query); - } - - /* Code 2.05 CONTENT is default. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u\nQuery: %.*s", coap_req->type, coap_req->code, coap_req->mid, len, query)); -} -#endif - -#if REST_RES_LOC_QUERY -/* - * Resource accepting query parameters - */ -RESOURCE(locquery, METHOD_POST, "location-query", "title=\"Resource accepting query parameters\""); - -void -locquery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - - PRINTF("/location-query POST (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); - - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "?first=1&second=2"); -} -#endif - -#if REST_RES_MULTI -/* - * Resource providing text/plain and application/xml - */ -RESOURCE(multi, METHOD_GET, "multi-format", "title=\"Resource providing text/plain and application/xml\";ct=\"0 41\""); -void -multi_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - - const uint16_t *accept = NULL; - int num = REST.get_header_accept(request, &accept); - - PRINTF("/multi-format GET (%s %u) %d\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid, num); - - if (num==0 || (num && accept[0]==REST.type.TEXT_PLAIN)) - { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u%s", coap_req->type, coap_req->code, coap_req->mid, num ? "\nAccept: 0" : "")); -PRINTF("PLAIN\n"); - } - else if (num && (accept[0]==REST.type.APPLICATION_XML)) - { - REST.set_header_content_type(response, REST.type.APPLICATION_XML); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "", coap_req->type, coap_req->code, coap_req->mid, accept[0])); -PRINTF("XML\n"); - } - else - { - REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); - const char *msg = "Supporting content-types text/plain and application/xml"; - REST.set_response_payload(response, msg, strlen(msg)); - PRINTF("ERROR\n"); - } -} -#endif - -#if REST_RES_LINKS -/* - * Resources providing text/plain and application/xml - */ -RESOURCE(link1, METHOD_GET, "link1", "rt=\"Type1 Type2\";if=\"If1\""); -SUB_RESOURCE(link2, METHOD_GET, "link2", "rt=\"Type2 Type3\";if=\"If2\"", link1); -SUB_RESOURCE(link3, METHOD_GET, "link3", "rt=\"Type1 Type3\";if=\"foo\"", link1); - -void -link1_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - const char *msg = "Dummy link"; - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, msg, strlen(msg)); -} -#endif - -#if REST_RES_PATH -/* - * Resources providing text/plain and application/xml - */ -RESOURCE(path, METHOD_GET | HAS_SUB_RESOURCES, "path", "ct=\"40\""); - -void -path_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - - const char *uri_path = NULL; - int len = REST.get_url(request, &uri_path); - int base_len = strlen(resource_path.url); - - if (len==base_len) - { - REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT); - snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, ",,"); - } - else - { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "/%.*s", len, uri_path); - } - - REST.set_response_payload(response, buffer, strlen((char *)buffer)); -} -#endif - -#if REST_RES_SEPARATE -/* Required to manually (=not by the engine) handle the response transaction. */ -#if WITH_COAP == 7 -#include "er-coap-07-separate.h" -#include "er-coap-07-transactions.h" -#elif WITH_COAP == 12 -#include "er-coap-12-separate.h" -#include "er-coap-12-transactions.h" -#elif WITH_COAP == 13 -#include "er-coap-13-separate.h" -#include "er-coap-13-transactions.h" -#endif -/* - * Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way - */ -PERIODIC_RESOURCE(separate, METHOD_GET, "separate", "title=\"Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way\"", 3*CLOCK_SECOND); - -/* A structure to store the required information */ -typedef struct application_separate_store { - /* Provided by Erbium to store generic request information such as remote address and token. */ - coap_separate_t request_metadata; - /* Add fields for addition information to be stored for finalizing, e.g.: */ - char buffer[MAX_PLUGFEST_PAYLOAD]; -} application_separate_store_t; - -static uint8_t separate_active = 0; -static application_separate_store_t separate_store[1]; - -void -separate_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - - PRINTF("/separate "); - if (separate_active) - { - PRINTF("REJECTED "); - coap_separate_reject(); - } - else - { - PRINTF("STORED "); - separate_active = 1; - - /* Take over and skip response by engine. */ - coap_separate_accept(request, &separate_store->request_metadata); - /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ - - snprintf(separate_store->buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid); - } - - PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); -} - -void -separate_periodic_handler(resource_t *resource) -{ - if (separate_active) - { - PRINTF("/separate "); - coap_transaction_t *transaction = NULL; - if ( (transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port)) ) - { - PRINTF("RESPONSE (%s %u)\n", separate_store->request_metadata.type==COAP_TYPE_CON?"CON":"NON", separate_store->request_metadata.mid); - - coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ - - /* Restore the request information for the response. */ - coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); - - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); - - /* - * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. - * As it is a critical option, this example resource pretends to handle it for compliance. - */ - coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); - - /* Warning: No check for serialization error. */ - transaction->packet_len = coap_serialize_message(response, transaction->packet); - coap_send_transaction(transaction); - /* The engine will clear the transaction (right after send for NON, after acked for CON). */ - - separate_active = 0; - } else { - PRINTF("ERROR (transaction)\n"); - } - } /* if (separate_active) */ -} -#endif - -#if REST_RES_LARGE - -/* double expansion */ -#define TO_STRING2(x) #x -#define TO_STRING(x) TO_STRING2(x) +#include "er-coap.h" +#include "er-coap-transactions.h" +#include "er-coap-separate.h" +#include "rest-engine.h" +#include "er-plugtest.h" /* - * Large resource + * Resources to be activated need to be imported through the extern keyword. + * The build system automatically compiles the resources in the corresponding + * sub-directory. */ -RESOURCE(large, METHOD_GET, "large", "title=\"Large resource\";rt=\"block\";sz=\"" TO_STRING(CHUNKS_TOTAL) "\""); - -void -large_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - int32_t strpos = 0; - - /* Check the offset for boundaries of the resource data. */ - if (*offset>=CHUNKS_TOTAL) - { - REST.set_response_status(response, REST.status.BAD_OPTION); - /* A block error message should not exceed the minimum block size (16). */ - - const char *error_msg = "BlockOutOfScope"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - /* Generate data until reaching CHUNKS_TOTAL. */ - while (strpos preferred_size) - { - strpos = preferred_size; - } - - /* Truncate if above CHUNKS_TOTAL bytes. */ - if (*offset+(int32_t)strpos > CHUNKS_TOTAL) - { - strpos = CHUNKS_TOTAL - *offset; - } - - REST.set_response_payload(response, buffer, strpos); - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - - /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ - *offset += strpos; - - /* Signal end of resource representation. */ - if (*offset>=CHUNKS_TOTAL) - { - *offset = -1; - } -} -#endif - -#if REST_RES_LARGE_UPDATE -/* - * Large resource that can be updated using PUT method - */ -RESOURCE(large_update, METHOD_GET|METHOD_PUT, "large-update", "title=\"Large resource that can be updated using PUT method\";rt=\"block\";sz=\"" TO_STRING(MAX_PLUGFEST_BODY) "\""); - -static int32_t large_update_size = 0; -static uint8_t large_update_store[MAX_PLUGFEST_BODY] = {0}; -static unsigned int large_update_ct = -1; - -void -large_update_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - uint8_t method = REST.get_method_type(request); - - if (method & METHOD_GET) - { - /* Check the offset for boundaries of the resource data. */ - if (*offset>=large_update_size) - { - REST.set_response_status(response, REST.status.BAD_OPTION); - /* A block error message should not exceed the minimum block size (16). */ - - const char *error_msg = "BlockOutOfScope"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - REST.set_response_payload(response, large_update_store+*offset, MIN(large_update_size - *offset, preferred_size)); - REST.set_header_content_type(response, large_update_ct); - - /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ - *offset += preferred_size; - - /* Signal end of resource representation. */ - if (*offset>=large_update_size) - { - *offset = -1; - } - } else { - uint8_t *incoming = NULL; - size_t len = 0; - - unsigned int ct = REST.get_header_content_type(request); - if (ct==-1) - { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoContentType"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - if ((len = REST.get_request_payload(request, (const uint8_t **) &incoming))) - { - if (coap_req->block1_num*coap_req->block1_size+len <= sizeof(large_update_store)) - { - memcpy(large_update_store+coap_req->block1_num*coap_req->block1_size, incoming, len); - large_update_size = coap_req->block1_num*coap_req->block1_size+len; - large_update_ct = REST.get_header_content_type(request); - - REST.set_response_status(response, REST.status.CHANGED); - coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); - } - else - { - REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); - REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", sizeof(large_update_store))); - return; - } - } - else - { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoPayload"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - } -} -#endif - -#if REST_RES_LARGE_CREATE -/* - * Large resource that can be created using POST method - */ -RESOURCE(large_create, METHOD_POST, "large-create", "title=\"Large resource that can be created using POST method\";rt=\"block\""); - -void -large_create_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - coap_packet_t *const coap_req = (coap_packet_t *) request; - - uint8_t *incoming = NULL; - size_t len = 0; - - unsigned int ct = REST.get_header_content_type(request); - if (ct==-1) - { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoContentType"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - - if ((len = REST.get_request_payload(request, (const uint8_t **) &incoming))) - { - if (coap_req->block1_num*coap_req->block1_size+len <= 2048) - { - REST.set_response_status(response, REST.status.CREATED); - REST.set_header_location(response, "/nirvana"); - coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); - } - else - { - REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); - const char *error_msg = "2048B max."; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } - } - else - { - REST.set_response_status(response, REST.status.BAD_REQUEST); - const char *error_msg = "NoPayload"; - REST.set_response_payload(response, error_msg, strlen(error_msg)); - return; - } -} -#endif - -#if REST_RES_OBS - -#if WITH_COAP == 12 -#include "er-coap-12-observing.h" -#elif WITH_COAP == 13 -#include "er-coap-13-observing.h" -#endif -/* - * Observable resource which changes every 5 seconds - */ -PERIODIC_RESOURCE(obs, METHOD_GET|METHOD_PUT|METHOD_DELETE, "obs", "title=\"Observable resource which changes every 5 seconds\";obs", 5*CLOCK_SECOND); - -static uint16_t obs_counter = 0; -static char obs_content[MAX_PLUGFEST_BODY]; -static size_t obs_content_len = 0; -static unsigned int obs_format = 0; - -static char obs_status = 0; - -static -void -obs_purge_list() -{ - PRINTF("### SERVER ACTION ### Purging obs list"); - coap_remove_observer_by_url(NULL, 0, resource_obs.url); -} - -void -obs_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - uint8_t method = request==NULL ? METHOD_GET : REST.get_method_type(request); - - /* Keep server log clean from ticking events */ - if (request!=NULL) - { - PRINTF("/obs "); - } - - if (method & METHOD_GET) - { - /* Keep server log clean from ticking events */ - if (request!=NULL) - { - PRINTF("GET "); - } - - REST.set_header_content_type(response, obs_format); - REST.set_header_max_age(response, 5); - - if (obs_content_len) - { - REST.set_header_content_type(response, obs_format); - REST.set_response_payload(response, obs_content, obs_content_len); - } - else - { - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, obs_content, snprintf(obs_content, MAX_PLUGFEST_PAYLOAD, "TICK %lu", obs_counter)); - } - /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ - } - else if (method & METHOD_PUT) - { - uint8_t *incoming = NULL; - unsigned int ct = REST.get_header_content_type(request); - - PRINTF("PUT "); - - if (ct!=obs_format) - { - obs_status = 1; - - obs_format = ct; - } else { - - obs_format = ct; - obs_content_len = REST.get_request_payload(request, (const uint8_t **) &incoming); - memcpy(obs_content, incoming, obs_content_len); - obs_periodic_handler(&resource_obs); - } - - REST.set_response_status(response, REST.status.CHANGED); - } - else if (method & METHOD_DELETE) - { - PRINTF("DELETE "); - - obs_status = 2; - - REST.set_response_status(response, REST.status.DELETED); - } - - /* Keep server log clean from ticking events */ - if (request!=NULL) - { - PRINTF("\n"); - } -} - -/* - * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. - * It will be called by the REST manager process with the defined period. - */ -void -obs_periodic_handler(resource_t *r) -{ - ++obs_counter; - - //PRINTF("TICK %u for /%s\n", obs_counter, r->url); - - if (obs_status==1) - { - coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ - coap_init_message(notification, COAP_TYPE_NON, INTERNAL_SERVER_ERROR_5_00, 0 ); - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(&resource_obs, -1, notification); - - PRINTF("######### sending 5.00\n"); - - obs_purge_list(); - } - else if (obs_status==2) - { - - coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ - coap_init_message(notification, COAP_TYPE_NON, NOT_FOUND_4_04, 0 ); - - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(&resource_obs, -1, notification); - - obs_purge_list(); - - obs_counter = 0; - obs_content_len = 0; - } - else - { - /* Build notification. */ - /*TODO: REST.new_response() */ - coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ - coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0 ); - - /* Better use a generator function for both handlers that only takes *resonse. */ - obs_handler(NULL, notification, NULL, 0, NULL); - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(r, obs_counter, notification); - } - obs_status = 0; -} -#endif - -#if REST_RES_MIRROR -/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ -RESOURCE(mirror, METHOD_GET | METHOD_POST | METHOD_PUT | METHOD_DELETE, "debug/mirror", "title=\"Returns your decoded message\";rt=\"Debug\""); - -void -mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - /* The ETag and Token is copied to the header. */ - uint8_t opaque[] = {0x0A, 0xBC, 0xDE}; - - /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ - static char location[] = {'/','f','/','a','?','k','&','e', 0}; - - /* Getter for the header option Content-Type. If the option is not set, text/plain is returned by default. */ - unsigned int content_type = REST.get_header_content_type(request); - - /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ - uint32_t max_age_and_size = 0; - const char *str = NULL; - uint32_t observe = 0; - const uint8_t *bytes = NULL; - const uint16_t *words = NULL; - uint32_t block_num = 0; - uint8_t block_more = 0; - uint16_t block_size = 0; - const char *query = ""; - int len = 0; - - /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ - - int strpos = 0; - /* snprintf() counts the terminating '\0' to the size parameter. - * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. - * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ - - - if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_if_match(request, &bytes))) - { - strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "If-Match 0x"); - int index = 0; - for (index = 0; index= REST_MAX_CHUNK_SIZE) - { - buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* 'ยป' to indicate truncation */ - } - - REST.set_response_payload(response, buffer, strpos); - - PRINTF("/mirror options received: %s\n", buffer); - - /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ - REST.set_header_etag(response, opaque, 2); - REST.set_header_location(response, location); /* Initial slash is omitted by framework */ - REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */ - -/* CoAP-specific example: actions not required for normal RESTful Web service. */ - coap_set_header_uri_host(response, "Contiki"); - coap_set_header_observe(response, 10); - coap_set_header_proxy_uri(response, "ftp://x"); - //coap_set_header_block2(response, 42, 0, 64); - //coap_set_header_block1(response, 23, 0, 16); - coap_set_header_accept(response, APPLICATION_XML); - coap_set_header_accept(response, APPLICATION_ATOM_XML); - coap_set_header_if_none_match(response); -} -#endif /* REST_RES_MIRROR */ - - - - +extern resource_t + res_plugtest_test, + res_plugtest_validate, + res_plugtest_create1, + res_plugtest_create2, + res_plugtest_create3, + res_plugtest_longpath, + res_plugtest_query, + res_plugtest_locquery, + res_plugtest_multi, + res_plugtest_link1, + res_plugtest_link2, + res_plugtest_link3, + res_plugtest_path, + res_plugtest_separate, + res_plugtest_large, + res_plugtest_large_update, + res_plugtest_large_create, + res_plugtest_obs, + res_mirror; PROCESS(plugtest_server, "PlugtestServer"); AUTOSTART_PROCESSES(&plugtest_server); @@ -1240,59 +98,31 @@ PROCESS_THREAD(plugtest_server, ev, data) rest_init_engine(); /* Activate the application-specific resources. */ -#if REST_RES_TEST - rest_activate_resource(&resource_test); - rest_activate_resource(&resource_validate); - rest_activate_resource(&resource_create1); - rest_activate_resource(&resource_create2); - rest_activate_resource(&resource_create3); -#endif -#if REST_RES_LONG - rest_activate_resource(&resource_longpath); -#endif -#if REST_RES_QUERY - rest_activate_resource(&resource_query); -#endif -#if REST_RES_LOC_QUERY - rest_activate_resource(&resource_locquery); -#endif -#if REST_RES_MULTI - rest_activate_resource(&resource_multi); -#endif -#if REST_RES_LINKS - rest_activate_resource(&resource_link1); - rest_activate_resource(&resource_link2); - rest_activate_resource(&resource_link3); -#endif -#if REST_RES_PATH - rest_activate_resource(&resource_path); -#endif -#if REST_RES_SEPARATE - rest_activate_periodic_resource(&periodic_resource_separate); -#endif -#if REST_RES_LARGE - rest_activate_resource(&resource_large); -#endif -#if REST_RES_LARGE_UPDATE - large_update_ct = REST.type.APPLICATION_OCTET_STREAM; - rest_activate_resource(&resource_large_update); -#endif -#if REST_RES_LARGE_CREATE - rest_activate_resource(&resource_large_create); -#endif -#if REST_RES_OBS - rest_activate_periodic_resource(&periodic_resource_obs); -#endif + rest_activate_resource(&res_plugtest_test, "test"); + rest_activate_resource(&res_plugtest_validate, "validate"); + rest_activate_resource(&res_plugtest_create1, "create1"); + rest_activate_resource(&res_plugtest_create2, "create2"); + rest_activate_resource(&res_plugtest_create3, "create3"); + rest_activate_resource(&res_plugtest_longpath, "seg1/seg2/seg3"); + rest_activate_resource(&res_plugtest_query, "query"); + rest_activate_resource(&res_plugtest_locquery, "location-query"); + rest_activate_resource(&res_plugtest_multi, "multi-format"); + rest_activate_resource(&res_plugtest_link1, "link1"); + rest_activate_resource(&res_plugtest_link2, "link2"); + rest_activate_resource(&res_plugtest_link3, "link3"); + rest_activate_resource(&res_plugtest_path, "path"); + rest_activate_resource(&res_plugtest_separate, "separate"); + rest_activate_resource(&res_plugtest_large, "large"); + rest_activate_resource(&res_plugtest_large_update, "large-update"); + rest_activate_resource(&res_plugtest_large_create, "large-create"); + rest_activate_resource(&res_plugtest_obs, "obs"); -#if REST_RES_MIRROR - rest_activate_resource(&resource_mirror); -#endif + rest_activate_resource(&res_mirror, "mirror"); /* Define application-specific events here. */ while(1) { PROCESS_WAIT_EVENT(); - - } /* while (1) */ + } /* while (1) */ PROCESS_END(); } diff --git a/examples/osd/er-rest-example-merkurboard/er-plugtest.h b/examples/osd/er-rest-example-merkurboard/er-plugtest.h new file mode 100644 index 000000000..0b156656a --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/er-plugtest.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Erbium (Er) CoAP client example + * \author + * Matthias Kovatsch + */ + +#ifndef __ER_PLUGTEST_H__ +#define __ER_PLUGTEST_H__ + +#if !defined(CONTIKI_TARGET_NATIVE) +#warning "Should only be compiled for native!" +#endif + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +/* double expansion */ +#define TO_STRING2(x) # x +#define TO_STRING(x) TO_STRING2(x) + +#define MAX_PLUGFEST_PAYLOAD 64 + 1 /* +1 for the terminating zero, which is not transmitted */ +#define MAX_PLUGFEST_BODY 2048 +#define CHUNKS_TOTAL 2012 + +#endif /* __ER_PLUGTEST_H__ */ diff --git a/examples/osd/er-rest-example-merkurboard/project-conf.h b/examples/osd/er-rest-example-merkurboard/project-conf.h index 2187b48c7..fb631f842 100644 --- a/examples/osd/er-rest-example-merkurboard/project-conf.h +++ b/examples/osd/er-rest-example-merkurboard/project-conf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Matthias Kovatsch + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,74 +26,71 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * + * This file is part of the Contiki operating system. */ -#ifndef PROJECT_ERBIUM_CONF_H_ -#define PROJECT_ERBIUM_CONF_H_ +/** + * \file + * Erbium (Er) example project configuration. + * \author + * Matthias Kovatsch + */ -#define PLATFORM_HAS_LEDS 1 -#define PLATFORM_HAS_BUTTON 1 -#define PLATFORM_HAS_TEMPERATURE 1 -#define PLATFORM_HAS_BATTERY 1 +#ifndef __PROJECT_ERBIUM_CONF_H__ +#define __PROJECT_ERBIUM_CONF_H__ -/* Some platforms have weird includes. */ -// #undef IEEE802154_CONF_PANID -// #define IEEE802154_CONF_PANID 0xAAAA +/* Custom channel and PAN ID configuration for your project. */ +/* + #undef RF_CHANNEL + #define RF_CHANNEL 26 -/* Disabling RDC for demo purposes. Core updates often require more memory. */ -/* For projects, optimize memory and enable RDC again. */ -// #undef NETSTACK_CONF_RDC -//#define NETSTACK_CONF_RDC nullrdc_driver + #undef IEEE802154_CONF_PANID + #define IEEE802154_CONF_PANID 0xABCD + */ + +/* IP buffer size must match all other hops, in particular the border router. */ + + #undef UIP_CONF_BUFFER_SIZE + #define UIP_CONF_BUFFER_SIZE 256 + + +/* Disabling RDC and CSMA for demo purposes. Core updates often + require more memory. */ +/* For projects, optimize memory and enable RDC and CSMA again. */ +#undef NETSTACK_CONF_RDC +#define NETSTACK_CONF_RDC nullrdc_driver + +/* Disabling TCP on CoAP nodes. */ +#undef UIP_CONF_TCP +#define UIP_CONF_TCP 0 + +#undef NETSTACK_CONF_MAC +#define NETSTACK_CONF_MAC nullmac_driver /* Increase rpl-border-router IP-buffer when using more than 64. */ #undef REST_MAX_CHUNK_SIZE -#define REST_MAX_CHUNK_SIZE 64 +#define REST_MAX_CHUNK_SIZE 48 /* Estimate your header size, especially when using Proxy-Uri. */ /* -#undef COAP_MAX_HEADER_SIZE -#define COAP_MAX_HEADER_SIZE 70 -*/ - -/* The IP buffer size must fit all other hops, in particular the border router. */ - -#undef UIP_CONF_BUFFER_SIZE -#define UIP_CONF_BUFFER_SIZE 256 - + #undef COAP_MAX_HEADER_SIZE + #define COAP_MAX_HEADER_SIZE 70 + */ /* Multiplies with chunk size, be aware of memory constraints. */ #undef COAP_MAX_OPEN_TRANSACTIONS -#define COAP_MAX_OPEN_TRANSACTIONS 4 +#define COAP_MAX_OPEN_TRANSACTIONS 4 -/* Must be <= open transaction number, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ +/* Must be <= open transactions, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ /* -#undef COAP_MAX_OBSERVERS -#define COAP_MAX_OBSERVERS 2 -*/ + #undef COAP_MAX_OBSERVERS + #define COAP_MAX_OBSERVERS 2 + */ /* Filtering .well-known/core per query can be disabled to save space. */ -/* #undef COAP_LINK_FORMAT_FILTERING -#define COAP_LINK_FORMAT_FILTERING 0 -*/ +#define COAP_LINK_FORMAT_FILTERING 0 +#undef COAP_PROXY_OPTION_PROCESSING +#define COAP_PROXY_OPTION_PROCESSING 0 -/* Save some memory for the sky platform. */ -/* -#undef NBR_TABLE_CONF_MAX_NEIGHBORS -#define NBR_TABLE_CONF_MAX_NEIGHBORS 10 -#undef UIP_CONF_MAX_ROUTES -#define UIP_CONF_MAX_ROUTES 10 -*/ - -/* Reduce 802.15.4 frame queue to save RAM. */ -/* -#undef QUEUEBUF_CONF_NUM -#define QUEUEBUF_CONF_NUM 4 -*/ - -/* -#undef SICSLOWPAN_CONF_FRAG -#define SICSLOWPAN_CONF_FRAG 1 -*/ -#endif /* PROJECT_ERBIUM_CONF_H_ */ +#endif /* __PROJECT_ERBIUM_CONF_H__ */ diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-b1-sep-b2.c b/examples/osd/er-rest-example-merkurboard/resources/res-b1-sep-b2.c new file mode 100644 index 000000000..be4d8f943 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-b1-sep-b2.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Lars Schmertmann + */ + +#include +#include "rest-engine.h" +#include "er-coap-block1.h" +#include "er-coap-separate.h" +#include "er-coap-transactions.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +SEPARATE_RESOURCE(res_b1_sep_b2, "title=\"Block1 + Separate + Block2 demo\"", NULL, res_post_handler, NULL, NULL, NULL); + +#define MAX_DATA_LEN 256 + +static uint8_t big_msg[MAX_DATA_LEN]; +static size_t big_msg_len = 0; +static coap_separate_t request_metadata; + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Example allows only one request on time. There are no checks for multiply access !!! */ + if(*offset == 0) { + /* Incoming Data */ + if(coap_block1_handler(request, response, big_msg, &big_msg_len, MAX_DATA_LEN)) { + /* More Blocks will follow. Example waits for + * the last block and stores data into big_msg. + */ + return; + } + /* Last block was received. */ + coap_separate_accept(request, &request_metadata); + + /* Need Time for calculation now */ + uint32_t i; + for(i = 0; i <= 4096; i++) { + printf("\r% 4u\r", i); + } + printf("\n"); + + /* Send first block */ + coap_transaction_t *transaction = NULL; + if((transaction = coap_new_transaction(request_metadata.mid, &request_metadata.addr, request_metadata.port))) { + coap_packet_t resp[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(resp, &request_metadata, CONTENT_2_05); + + /* Set payload and block info */ + coap_set_payload(resp, big_msg, big_msg_len > request_metadata.block2_size ? request_metadata.block2_size : big_msg_len); + if(big_msg_len > request_metadata.block2_size) { + coap_set_header_block2(resp, 0, 1, request_metadata.block2_size); + } + + /* Warning: No check for serialization error. */ + transaction->packet_len = coap_serialize_message(resp, transaction->packet); + coap_send_transaction(transaction); + } + } else { + /* request for more blocks */ + if(*offset >= big_msg_len) { + coap_set_status_code(response, BAD_OPTION_4_02); + coap_set_payload(response, "BlockOutOfScope", 15); + return; + } + + memcpy(buffer, big_msg + *offset, 32); + if(big_msg_len - *offset < preferred_size) { + preferred_size = big_msg_len - *offset; + *offset = -1; + } else { + *offset += preferred_size; + } + coap_set_payload(response, buffer, preferred_size); + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-battery.c b/examples/osd/er-rest-example-merkurboard/resources/res-battery.c new file mode 100644 index 000000000..b82523594 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-battery.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_BATTERY + +#include +#include "rest-engine.h" +#include "dev/battery-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple getter example. Returns the reading from light sensor with a simple etag */ +RESOURCE(res_battery, + "title=\"Battery status\";rt=\"Battery\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int battery = battery_sensor.value(0); + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", battery); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d}", battery); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif /* PLATFORM_HAS_BATTERY */ diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-chunks.c b/examples/osd/er-rest-example-merkurboard/resources/res-chunks.c new file mode 100644 index 000000000..79ad55094 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-chunks.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * For data larger than REST_MAX_CHUNK_SIZE (e.g., when stored in flash) resources must be aware of the buffer limitation + * and split their responses by themselves. To transfer the complete resource through a TCP stream or CoAP's blockwise transfer, + * the byte offset where to continue is provided to the handler as int32_t pointer. + * These chunk-wise resources must set the offset value to its new position or -1 of the end is reached. + * (The offset for CoAP's blockwise transfer can go up to 2'147'481'600 = ~2047 M for block size 2048 (reduced to 1024 in observe-03.) + */ +RESOURCE(res_chunks, + "title=\"Blockwise demo\";rt=\"Data\"", + res_get_handler, + NULL, + NULL, + NULL); + +#define CHUNKS_TOTAL 2050 + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + + /* Check the offset for boundaries of the resource data. */ + if(*offset >= CHUNKS_TOTAL) { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while(strpos < preferred_size) { + strpos += snprintf((char *)buffer + strpos, preferred_size - strpos + 1, "|%ld|", *offset); + } + + /* snprintf() does not adjust return value if truncated by size. */ + if(strpos > preferred_size) { + strpos = preferred_size; + /* Truncate if above CHUNKS_TOTAL bytes. */ + } + if(*offset + (int32_t)strpos > CHUNKS_TOTAL) { + strpos = CHUNKS_TOTAL - *offset; + } + REST.set_response_payload(response, buffer, strpos); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if(*offset >= CHUNKS_TOTAL) { + *offset = -1; + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-event.c b/examples/osd/er-rest-example-merkurboard/resources/res-event.c new file mode 100644 index 000000000..d20f0caa9 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-event.c @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_event_handler(); + +/* + * Example for an event resource. + * Additionally takes a period parameter that defines the interval to call [name]_periodic_handler(). + * A default post_handler takes care of subscriptions and manages a list of subscribers to notify. + */ +EVENT_RESOURCE(res_event, + "title=\"Event demo\";obs", + res_get_handler, + NULL, + NULL, + NULL, + res_event_handler); + +/* + * Use local resource state that is accessed by res_get_handler() and altered by res_event_handler() or PUT or POST. + */ +static int32_t event_counter = 0; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "EVENT %lu", event_counter)); + + /* A post_handler that handles subscriptions/observing will be called for periodic resources by the framework. */ +} +/* + * Additionally, res_event_handler must be implemented for each EVENT_RESOURCE. + * It is called through .trigger(), usually from the server process. + */ +static void +res_event_handler() +{ + /* Do the update triggered by the event here, e.g., sampling a sensor. */ + ++event_counter; + + /* Usually a condition is defined under with subscribers are notified, e.g., event was above a threshold. */ + if(1) { + PRINTF("TICK %u for /%s\n", event_counter, res_event.url); + + /* Notify the registered observers which will trigger the res_get_handler to create the response. */ + REST.notify_subscribers(&res_event); + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-hello.c b/examples/osd/er-rest-example-merkurboard/resources/res-hello.c new file mode 100644 index 000000000..9208f8b74 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-hello.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include +#include "rest-engine.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * A handler function named [resource name]_handler must be implemented for each RESOURCE. + * A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore + * preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE limit for the buffer. + * If a smaller block size is requested for CoAP, the REST framework automatically splits the data. + */ +RESOURCE(res_hello, + "title=\"Hello world: ?len=0..\";rt=\"Text\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + const char *len = NULL; + /* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */ + char const *const message = "Hello World! ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy"; + int length = 12; /* |<-------->| */ + + /* The query string can be retrieved by rest_get_query() or parsed for its key-value pairs. */ + if(REST.get_query_variable(request, "len", &len)) { + length = atoi(len); + if(length < 0) { + length = 0; + } + if(length > REST_MAX_CHUNK_SIZE) { + length = REST_MAX_CHUNK_SIZE; + } + memcpy(buffer, message, length); + } else { + memcpy(buffer, message, length); + } REST.set_header_content_type(response, REST.type.TEXT_PLAIN); /* text/plain is the default, hence this option could be omitted. */ + REST.set_header_etag(response, (uint8_t *)&length, 1); + REST.set_response_payload(response, buffer, length); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-leds.c b/examples/osd/er-rest-example-merkurboard/resources/res-leds.c new file mode 100644 index 000000000..5fbcf6c77 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-leds.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_LEDS + +#include +#include "rest-engine.h" +#include "dev/leds.h" + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +static void res_post_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ +RESOURCE(res_leds, + "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\"", + NULL, + res_post_put_handler, + res_post_put_handler, + NULL); + +static void +res_post_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *color = NULL; + const char *mode = NULL; + uint8_t led = 0; + int success = 1; + + if((len = REST.get_query_variable(request, "color", &color))) { + PRINTF("color %.*s\n", len, color); + + if(strncmp(color, "r", len) == 0) { + led = LEDS_RED; + } else if(strncmp(color, "g", len) == 0) { + led = LEDS_GREEN; + } else if(strncmp(color, "b", len) == 0) { + led = LEDS_BLUE; + } else { + success = 0; + } + } else { + success = 0; + } if(success && (len = REST.get_post_variable(request, "mode", &mode))) { + PRINTF("mode %s\n", mode); + + if(strncmp(mode, "on", len) == 0) { + leds_on(led); + } else if(strncmp(mode, "off", len) == 0) { + leds_off(led); + } else { + success = 0; + } + } else { + success = 0; + } if(!success) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + } +} +#endif /* PLATFORM_HAS_LEDS */ diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-light.c b/examples/osd/er-rest-example-merkurboard/resources/res-light.c new file mode 100644 index 000000000..226d814bb --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-light.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_LIGHT + +#include +#include "rest-engine.h" +#include "dev/light-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple getter example. Returns the reading from light sensor with a simple etag */ +RESOURCE(res_light, + "title=\"Photosynthetic and solar light (supports JSON)\";rt=\"LightSensor\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + uint16_t light_photosynthetic = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC); + uint16_t light_solar = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR); + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%u;%u", light_photosynthetic, light_solar); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_XML) { + REST.set_header_content_type(response, REST.type.APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "", light_photosynthetic, light_solar); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'light':{'photosynthetic':%u,'solar':%u}}", light_photosynthetic, light_solar); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain, application/xml, and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif /* PLATFORM_HAS_LIGHT */ diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-mirror.c b/examples/osd/er-rest-example-merkurboard/resources/res-mirror.c new file mode 100644 index 000000000..e33bda6d3 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-mirror.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" + +#define DEBUG 0 +#if DEBUG +#include +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]", (lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3], (lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +static void res_any_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* This resource mirrors the incoming request. It shows how to access the options and how to set them for the response. */ +RESOURCE(res_mirror, + "title=\"Returns your decoded message\";rt=\"Debug\"", + res_any_handler, + res_any_handler, + res_any_handler, + res_any_handler); + +static void +res_any_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* The ETag and Token is copied to the header. */ + uint8_t opaque[] = { 0x0A, 0xBC, 0xDE }; + + /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ + static char location[] = { '/', 'f', '/', 'a', '?', 'k', '&', 'e', 0 }; + + /* No default my be assumed for the Content-Format. (Unsigned -1 means all bits set.) */ + unsigned int content_format = -1; + + /* The other getters copy the value (or string/array pointer) to the given pointers and return 1 for success or the length of strings/arrays. */ + uint32_t longint = 0; + const char *str = NULL; + const uint8_t *bytes = NULL; + uint32_t block_num = 0; + uint8_t block_more = 0; + uint16_t block_size = 0; + int len = 0; + + /* Mirror the received header options in the response payload. Unsupported getters (e.g., rest_get_header_observe() with HTTP) will return 0. */ + + int strpos = 0; + /* snprintf() counts the terminating '\0' to the size parameter. + * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework. + * Add +1 to fill the complete buffer, as the payload does not need a terminating '\0'. */ + if(REST.get_header_content_type(request, &content_format)) { + strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE + 1, "CF %u\n", content_format); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_header_accept(request, &content_format))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ac %u\n", content_format); + /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. + * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "MA %lu\n", longint); + /* For HTTP this is the Length option, for CoAP it is the Size option. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && REST.get_header_length(request, &longint)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "SZ %lu\n", longint); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UH %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_url(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "UQ %.*s\n", len, str); + /* Undefined request options for debugging: actions not required for normal RESTful Web service. */ + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_path(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LP %.*s\n", len, str); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = coap_get_header_location_query(request, &str))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "LQ %.*s\n", len, str); + /* CoAP-specific example: actions not required for normal RESTful Web service. */ + } + coap_packet_t *const coap_pkt = (coap_packet_t *)request; + + if(strpos <= REST_MAX_CHUNK_SIZE && coap_pkt->token_len > 0) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "To 0x"); + int index = 0; + for(index = 0; index < coap_pkt->token_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->token[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + + if(strpos <= REST_MAX_CHUNK_SIZE && IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "Ob %lu\n", coap_pkt->observe); + } + if(strpos <= REST_MAX_CHUNK_SIZE && IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "ET 0x"); + int index = 0; + for(index = 0; index < coap_pkt->etag_len; ++index) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%02X", coap_pkt->etag[index]); + } + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "\n"); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block2(request, &block_num, &block_more, &block_size, NULL)) { /* This getter allows NULL pointers to get only a subset of the block parameters. */ + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); + } + if(strpos <= REST_MAX_CHUNK_SIZE && (len = REST.get_request_payload(request, &bytes))) { + strpos += snprintf((char *)buffer + strpos, REST_MAX_CHUNK_SIZE - strpos + 1, "%.*s", len, bytes); + } + if(strpos >= REST_MAX_CHUNK_SIZE) { + buffer[REST_MAX_CHUNK_SIZE - 1] = 0xBB; /* 'ยป' to indicate truncation */ + } + REST.set_response_payload(response, buffer, strpos); + + PRINTF("/mirror options received: %s\n", buffer); + + /* Set dummy header options for response. Like getters, some setters are not implemented for HTTP and have no effect. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_max_age(response, 17); /* For HTTP, browsers will not re-request the page for 17 seconds. */ + REST.set_header_etag(response, opaque, 2); + REST.set_header_location(response, location); /* Initial slash is omitted by framework */ + REST.set_header_length(response, strpos); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */ + +/* CoAP-specific example: actions not required for normal RESTful Web service. */ + coap_set_header_uri_host(response, "tiki"); + coap_set_header_observe(response, 10); + coap_set_header_proxy_uri(response, "ftp://x"); + coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ + coap_set_header_block1(response, 23, 0, 16); + coap_set_header_accept(response, TEXT_PLAIN); + coap_set_header_if_none_match(response); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create1.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create1.c new file mode 100644 index 000000000..4ba5f6181 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create1.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_create1, + "title=\"Creates on PUT\"", + NULL, + NULL, + res_put_handler, + res_delete_handler); + +static uint8_t create1_exists = 0; + +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create1 PUT"); + + if(coap_get_header_if_none_match(request)) { + if(!create1_exists) { + REST.set_response_status(response, REST.status.CREATED); + + create1_exists = 1; + } else { + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } + } else { + REST.set_response_status(response, REST.status.CHANGED); + } +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create1 DELETE "); + REST.set_response_status(response, REST.status.DELETED); + + create1_exists = 0; +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create2.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create2.c new file mode 100644 index 000000000..25877ac70 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create2.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_create2, + "title=\"Creates on POST\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create2 "); + + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/location1/location2/location3"); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create3.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create3.c new file mode 100644 index 000000000..2498c065a --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-create3.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_create3, + "title=\"Default test resource\"", + NULL, + NULL, + res_put_handler, + res_delete_handler); + +static uint8_t create3_exists = 0; + +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create3 PUT "); + + if(coap_get_header_if_none_match(request)) { + if(!create3_exists) { + REST.set_response_status(response, REST.status.CREATED); + + create3_exists = 1; + } else { + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } + } else { + REST.set_response_status(response, REST.status.CHANGED); + } +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/create3 DELETE "); + REST.set_response_status(response, REST.status.DELETED); + + create3_exists = 0; +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-create.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-create.c new file mode 100644 index 000000000..888dfaa31 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-create.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * Large resource that can be created using POST method + */ +RESOURCE(res_plugtest_large_create, + "title=\"Large resource that can be created using POST method\";rt=\"block\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + uint8_t *incoming = NULL; + size_t len = 0; + + unsigned int ct = -1; + + if(!REST.get_header_content_type(request, &ct)) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoContentType"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + if((len = REST.get_request_payload(request, (const uint8_t **)&incoming))) { + if(coap_req->block1_num * coap_req->block1_size + len <= 2048) { + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/nirvana"); + coap_set_header_block1(response, coap_req->block1_num, 0, + coap_req->block1_size); + } else { + REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); + const char *error_msg = "2048B max."; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoPayload"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-update.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-update.c new file mode 100644 index 000000000..e48d08b5f --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large-update.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE( + res_plugtest_large_update, + "title=\"Large resource that can be updated using PUT method\";rt=\"block\";sz=\"" TO_STRING(MAX_PLUGFEST_BODY) "\"", + res_get_handler, + NULL, + res_put_handler, + NULL); + +static int32_t large_update_size = 0; +static uint8_t large_update_store[MAX_PLUGFEST_BODY] = { 0 }; +static unsigned int large_update_ct = APPLICATION_OCTET_STREAM; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Check the offset for boundaries of the resource data. */ + if(*offset >= large_update_size) { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + REST.set_response_payload(response, large_update_store + *offset, + MIN(large_update_size - *offset, preferred_size)); + REST.set_header_content_type(response, large_update_ct); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += preferred_size; + + /* Signal end of resource representation. */ + if(*offset >= large_update_size) { + *offset = -1; + } +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + uint8_t *incoming = NULL; + size_t len = 0; + + unsigned int ct = -1; + + if(!REST.get_header_content_type(request, &ct)) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoContentType"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + if((len = REST.get_request_payload(request, (const uint8_t **)&incoming))) { + if(coap_req->block1_num * coap_req->block1_size + len <= sizeof(large_update_store)) { + memcpy( + large_update_store + coap_req->block1_num * coap_req->block1_size, + incoming, len); + large_update_size = coap_req->block1_num * coap_req->block1_size + len; + large_update_ct = ct; + + REST.set_response_status(response, REST.status.CHANGED); + coap_set_header_block1(response, coap_req->block1_num, 0, + coap_req->block1_size); + } else { + REST.set_response_status(response, + REST.status.REQUEST_ENTITY_TOO_LARGE); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", + sizeof(large_update_store))); + return; + } + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoPayload"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large.c new file mode 100644 index 000000000..d997dd927 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-large.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_large, + "title=\"Large resource\";rt=\"block\";sz=\"" TO_STRING(CHUNKS_TOTAL) "\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + + /* Check the offset for boundaries of the resource data. */ + if(*offset >= CHUNKS_TOTAL) { + REST.set_response_status(response, REST.status.BAD_OPTION); + /* A block error message should not exceed the minimum block size (16). */ + + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while(strpos < preferred_size) { + strpos += snprintf((char *)buffer + strpos, preferred_size - strpos + 1, + "|%ld|", *offset); + } + + /* snprintf() does not adjust return value if truncated by size. */ + if(strpos > preferred_size) { + strpos = preferred_size; + /* Truncate if above CHUNKS_TOTAL bytes. */ + } + if(*offset + (int32_t)strpos > CHUNKS_TOTAL) { + strpos = CHUNKS_TOTAL - *offset; + } + REST.set_response_payload(response, buffer, strpos); + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if(*offset >= CHUNKS_TOTAL) { + *offset = -1; + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-links.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-links.c new file mode 100644 index 000000000..be68aadf7 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-links.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_link1, + "rt=\"Type1 Type2\";if=\"If1\"", + res_get_handler, + NULL, + NULL, + NULL); +RESOURCE(res_plugtest_link2, + "rt=\"Type2 Type3\";if=\"If2\"", + res_get_handler, + NULL, + NULL, + NULL); +RESOURCE(res_plugtest_link3, + "rt=\"Type1 Type3\";if=\"foo\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + const char *msg = "Dummy link"; + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, msg, strlen(msg)); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-locquery.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-locquery.c new file mode 100644 index 000000000..64e79ff25 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-locquery.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_locquery, + "title=\"Resource accepting query parameters\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF( + "/location-query POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "?first=1&second=2"); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-longpath.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-longpath.c new file mode 100644 index 000000000..d6c4fb855 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-longpath.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_longpath, + "title=\"Long path resource\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/seg1/seg2/seg3 GET "); + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); + + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-multi.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-multi.c new file mode 100644 index 000000000..281a2268f --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-multi.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_multi, + "title=\"Resource providing text/plain and application/xml\";ct=\"0 41\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + PRINTF("/multi-format GET (%s %u) ", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u%s", coap_req->type, coap_req->code, + coap_req->mid, accept != -1 ? "\nAccept: 0" : "")); + PRINTF("PLAIN\n"); + } else if(accept == REST.type.APPLICATION_XML) { + REST.set_header_content_type(response, REST.type.APPLICATION_XML); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "", + coap_req->type, coap_req->code, coap_req->mid, accept)); + PRINTF("XML\n"); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/xml"; + REST.set_response_payload(response, msg, strlen(msg)); + PRINTF("ERROR\n"); + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-obs.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-obs.c new file mode 100644 index 000000000..e202c2043 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-obs.c @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-coap-observe.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_periodic_handler(void); + +PERIODIC_RESOURCE(res_plugtest_obs, + "title=\"Observable resource which changes every 5 seconds\";obs", + res_get_handler, + NULL, + res_put_handler, + res_delete_handler, + 5 * CLOCK_SECOND, + res_periodic_handler); + +static int32_t obs_counter = 0; +static char obs_content[MAX_PLUGFEST_BODY]; +static size_t obs_content_len = 0; +static unsigned int obs_format = 0; + +static char obs_status = 0; + +static void +obs_purge_list() +{ + PRINTF("### SERVER ACTION ### Purging obs list"); + coap_remove_observer_by_uri(NULL, 0, res_plugtest_obs.url); +} +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Keep server log clean from ticking events */ + if(request != NULL) { + PRINTF("/obs GET\n"); + } + REST.set_header_content_type(response, obs_format); + REST.set_header_max_age(response, 5); + + if(obs_content_len) { + REST.set_header_content_type(response, obs_format); + REST.set_response_payload(response, obs_content, obs_content_len); + } else { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, obs_content, + snprintf(obs_content, MAX_PLUGFEST_PAYLOAD, "TICK %lu", obs_counter)); + } + /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + uint8_t *incoming = NULL; + unsigned int ct = -1; + + REST.get_header_content_type(request, &ct); + + PRINTF("/obs PUT\n"); + + if(ct != obs_format) { + obs_status = 1; + obs_format = ct; + } else { + obs_content_len = REST.get_request_payload(request, + (const uint8_t **)&incoming); + memcpy(obs_content, incoming, obs_content_len); + res_periodic_handler(); + } + + REST.set_response_status(response, REST.status.CHANGED); +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + PRINTF("/obs DELETE\n"); + + obs_status = 2; + + REST.set_response_status(response, REST.status.DELETED); +} +/* + * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. + * It will be called by the REST manager process with the defined period. + */ +static void +res_periodic_handler() +{ + ++obs_counter; + + /* PRINTF("TICK %u for /%s\n", obs_counter, r->url); */ + + if(obs_status == 1) { + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(&res_plugtest_obs); + + PRINTF("######### sending 5.00\n"); + + obs_purge_list(); + } else if(obs_status == 2) { + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(&res_plugtest_obs); + + obs_purge_list(); + + obs_counter = 0; + obs_content_len = 0; + } else { + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(&res_plugtest_obs); + } obs_status = 0; +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-path.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-path.c new file mode 100644 index 000000000..3566a51b9 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-path.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +PARENT_RESOURCE(res_plugtest_path, + "title=\"Path test resource\";ct=\"40\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, + uint16_t preferred_size, int32_t *offset) +{ + + const char *uri_path = NULL; + int len = REST.get_url(request, &uri_path); + int base_len = strlen(res_plugtest_path.url); + + if(len == base_len) { + REST.set_header_content_type(response, REST.type.APPLICATION_LINK_FORMAT); + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + ",,"); + } else { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "/%.*s", len, uri_path); + } + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-query.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-query.c new file mode 100644 index 000000000..538646c6e --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-query.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_query, + "title=\"Resource accepting query parameters\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + int len = 0; + const char *query = NULL; + + PRINTF( + "/query GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if((len = REST.get_query(request, &query))) { + PRINTF("Query: %.*s\n", len, query); + /* Code 2.05 CONTENT is default. */ + } + REST.set_header_content_type(response, + REST.type.TEXT_PLAIN); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u\nQuery: %.*s", coap_req->type, + coap_req->code, coap_req->mid, len, query)); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-separate.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-separate.c new file mode 100644 index 000000000..a32311bba --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-separate.c @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-coap-transactions.h" +#include "er-coap-separate.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_resume_handler(void); + +PERIODIC_RESOURCE(res_plugtest_separate, + "title=\"Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way\"", + res_get_handler, + NULL, + NULL, + NULL, + 3 * CLOCK_SECOND, + res_resume_handler); + +/* A structure to store the required information */ +typedef struct application_separate_store { + /* Provided by Erbium to store generic request information such as remote address and token. */ + coap_separate_t request_metadata; + /* Add fields for addition information to be stored for finalizing, e.g.: */ + char buffer[MAX_PLUGFEST_PAYLOAD]; +} application_separate_store_t; + +static uint8_t separate_active = 0; +static application_separate_store_t separate_store[1]; + +void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/separate "); + if(separate_active) { + PRINTF("REJECTED "); + coap_separate_reject(); + } else { + PRINTF("STORED "); + separate_active = 1; + + /* Take over and skip response by engine. */ + coap_separate_accept(request, &separate_store->request_metadata); + /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ + + snprintf(separate_store->buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, + coap_req->mid); + } + + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); +} +static void +res_resume_handler() +{ + if(separate_active) { + PRINTF("/separate "); + coap_transaction_t *transaction = NULL; + if((transaction = coap_new_transaction(separate_store->request_metadata.mid, + &separate_store->request_metadata.addr, + separate_store->request_metadata.port))) { + PRINTF( + "RESPONSE (%s %u)\n", separate_store->request_metadata.type == COAP_TYPE_CON ? "CON" : "NON", separate_store->request_metadata.mid); + + coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); + + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + coap_set_payload(response, separate_store->buffer, + strlen(separate_store->buffer)); + + /* + * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. + * As it is a critical option, this example resource pretends to handle it for compliance. + */ + coap_set_header_block2(response, + separate_store->request_metadata.block2_num, 0, + separate_store->request_metadata.block2_size); + + /* Warning: No check for serialization error. */ + transaction->packet_len = coap_serialize_message(response, + transaction->packet); + coap_send_transaction(transaction); + /* The engine will clear the transaction (right after send for NON, after acked for CON). */ + + separate_active = 0; + } else { + PRINTF("ERROR (transaction)\n"); + } + } /* if (separate_active) */ +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-test.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-test.c new file mode 100644 index 000000000..27bba1f3b --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-test.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_test, "title=\"Default test resource\"", res_get_handler, res_post_handler, res_put_handler, res_delete_handler); + +static uint8_t test_etag[8] = { 0 }; +static uint8_t test_etag_len = 1; +static uint8_t test_change = 1; +static uint8_t test_none_match_okay = 1; + +static const uint8_t *bytes = NULL; +static size_t len = 0; + +static void +test_update_etag() +{ + int i; + test_etag_len = (random_rand() % 8) + 1; + for(i = 0; i < test_etag_len; ++i) { + test_etag[i] = random_rand(); + } + test_change = 0; + + PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", test_etag_len, test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); +} +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + if(test_change) { + test_update_etag(); + } + PRINTF("/test GET (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if((len = coap_get_header_etag(request, &bytes)) > 0 + && len == test_etag_len + && memcmp(test_etag, bytes, len) == 0) { + PRINTF("validate "); + REST.set_response_status(response, REST.status.NOT_MODIFIED); + REST.set_header_etag(response, test_etag, test_etag_len); + + test_change = 1; + PRINTF("### SERVER ACTION ### Resource will change\n"); + } else { + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_etag(response, test_etag, test_etag_len); + REST.set_header_max_age(response, 30); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); + } +} +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/test POST (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/location1/location2/location3"); +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/test PUT (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if(coap_get_header_if_none_match(request)) { + if(test_none_match_okay) { + REST.set_response_status(response, REST.status.CREATED); + + test_none_match_okay = 0; + PRINTF("### SERVER ACTION ### If-None-Match will FAIL\n"); + } else { + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + + test_none_match_okay = 1; + PRINTF("### SERVER ACTION ### If-None-Match will SUCCEED\n"); + } + } else if(((len = coap_get_header_if_match(request, &bytes)) > 0 + && (len == test_etag_len + && memcmp(test_etag, bytes, len) == 0)) + || len == 0) { + test_update_etag(); + REST.set_header_etag(response, test_etag, test_etag_len); + + REST.set_response_status(response, REST.status.CHANGED); + + if(len > 0) { + test_change = 1; + PRINTF("### SERVER ACTION ### Resource will change\n"); + } + } else { + PRINTF("Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + len, + test_etag_len, + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + test_etag[0], test_etag[1], test_etag[2], test_etag[3], test_etag[4], test_etag[5], test_etag[6], test_etag[7]); + + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } +} +static void +res_delete_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/test DELETE (%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + REST.set_response_status(response, REST.status.DELETED); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-validate.c b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-validate.c new file mode 100644 index 000000000..b92ffe74d --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-plugtest-validate.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * ETSI Plugtest resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" +#include "er-plugtest.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +RESOURCE(res_plugtest_validate, + "title=\"Validation test resource\"", + res_get_handler, + NULL, + res_put_handler, + NULL); + +static uint8_t validate_etag[8] = { 0 }; +static uint8_t validate_etag_len = 1; +static uint8_t validate_change = 1; + +static const uint8_t *bytes = NULL; +static size_t len = 0; + +static void +validate_update_etag() +{ + int i; + validate_etag_len = (random_rand() % 8) + 1; + for(i = 0; i < validate_etag_len; ++i) { + validate_etag[i] = random_rand(); + } + validate_change = 0; + + PRINTF("### SERVER ACTION ### Changed ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", + validate_etag_len, validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); +} +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + if(validate_change) { + validate_update_etag(); + } + PRINTF("/validate GET"); + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if((len = coap_get_header_etag(request, &bytes)) > 0 + && len == validate_etag_len && memcmp(validate_etag, bytes, len) == 0) { + PRINTF("validate "); + REST.set_response_status(response, REST.status.NOT_MODIFIED); + REST.set_header_etag(response, validate_etag, validate_etag_len); + + validate_change = 1; + PRINTF("### SERVER ACTION ### Resouce will change\n"); + } else { + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_etag(response, validate_etag, validate_etag_len); + REST.set_header_max_age(response, 30); + REST.set_response_payload( + response, + buffer, + snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, + "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, + coap_req->mid)); + } +} +static void +res_put_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + coap_packet_t *const coap_req = (coap_packet_t *)request; + + PRINTF("/validate PUT "); + PRINTF("(%s %u)\n", coap_req->type == COAP_TYPE_CON ? "CON" : "NON", coap_req->mid); + + if(((len = coap_get_header_if_match(request, &bytes)) > 0 + && (len == validate_etag_len + && memcmp(validate_etag, bytes, len) == 0)) + || len == 0) { + validate_update_etag(); + REST.set_header_etag(response, validate_etag, validate_etag_len); + + REST.set_response_status(response, REST.status.CHANGED); + + if(len > 0) { + validate_change = 1; + PRINTF("### SERVER ACTION ### Resouce will change\n"); + } + } else { + PRINTF( + "Check %u/%u\n [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n [0x%02X%02X%02X%02X%02X%02X%02X%02X] ", + len, + validate_etag_len, + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], + validate_etag[0], validate_etag[1], validate_etag[2], validate_etag[3], validate_etag[4], validate_etag[5], validate_etag[6], validate_etag[7]); + + REST.set_response_status(response, PRECONDITION_FAILED_4_12); + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-push.c b/examples/osd/er-rest-example-merkurboard/resources/res-push.c new file mode 100644 index 000000000..c169b407c --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-push.c @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_periodic_handler(void); + +PERIODIC_RESOURCE(res_push, + "title=\"Periodic demo\";obs", + res_get_handler, + NULL, + NULL, + NULL, + 5 * CLOCK_SECOND, + res_periodic_handler); + +/* + * Use local resource state that is accessed by res_get_handler() and altered by res_periodic_handler() or PUT or POST. + */ +static int32_t event_counter = 0; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* + * For minimal complexity, request query and options should be ignored for GET on observable resources. + * Otherwise the requests must be stored with the observer list and passed by REST.notify_subscribers(). + * This would be a TODO in the corresponding files in contiki/apps/erbium/! + */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_max_age(response, res_push.periodic->period / CLOCK_SECOND); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, preferred_size, "VERY LONG EVENT %lu", event_counter)); + + /* The REST.subscription_handler() will be called for observable resources by the REST framework. */ +} +/* + * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. + * It will be called by the REST manager process with the defined period. + */ +static void +res_periodic_handler() +{ + /* Do a periodic task here, e.g., sampling a sensor. */ + ++event_counter; + + /* Usually a condition is defined under with subscribers are notified, e.g., large enough delta in sensor reading. */ + if(1) { + /* Notify the registered observers which will trigger the res_get_handler to create the response. */ + REST.notify_subscribers(&res_push); + } +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-radio.c b/examples/osd/er-rest-example-merkurboard/resources/res-radio.c new file mode 100644 index 000000000..ac09319a3 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-radio.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_RADIO + +#include +#include "rest-engine.h" +#include "dev/radio-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple getter example. Returns the reading of the rssi/lqi from radio sensor */ +RESOURCE(res_radio, + "title=\"RADIO: ?p=lqi|rssi\";rt=\"RadioSensor\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *p = NULL; + uint8_t param = 0; + int success = 1; + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if((len = REST.get_query_variable(request, "p", &p))) { + if(strncmp(p, "lqi", len) == 0) { + param = RADIO_SENSOR_LAST_VALUE; + } else if(strncmp(p, "rssi", len) == 0) { + param = RADIO_SENSOR_LAST_PACKET; + } else { + success = 0; + } + } else { + success = 0; + } if(success) { + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", radio_sensor.value(param)); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + + if(param == RADIO_SENSOR_LAST_VALUE) { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'lqi':%d}", radio_sensor.value(param)); + } else if(param == RADIO_SENSOR_LAST_PACKET) { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'rssi':%d}", radio_sensor.value(param)); + } + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + } +} +#endif /* PLATFORM_HAS_RADIO */ diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-separate.c b/examples/osd/er-rest-example-merkurboard/resources/res-separate.c new file mode 100644 index 000000000..bb2248c92 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-separate.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" +#include "er-coap-separate.h" +#include "er-coap-transactions.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); +static void res_resume_handler(void); + +SEPARATE_RESOURCE(res_separate, + "title=\"Separate demo\"", + res_get_handler, + NULL, + NULL, + NULL, + res_resume_handler); + +/* A structure to store the information required for the separate handler */ +typedef struct application_separate_store { + + /* Provided by Erbium to store generic request information such as remote address and token. */ + coap_separate_t request_metadata; + + /* Add fields for addition information to be stored for finalizing, e.g.: */ + char buffer[16]; +} application_separate_store_t; + +#define COAP_MAX_OPEN_SEPARATE 2 + +static uint8_t separate_active = 0; +static application_separate_store_t separate_store[COAP_MAX_OPEN_SEPARATE]; + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* + * Example allows only one open separate response. + * For multiple, the application must manage the list of stores. + */ + if(separate_active >= COAP_MAX_OPEN_SEPARATE) { + coap_separate_reject(); + } else { + ++separate_active; + + /* Take over and skip response by engine. */ + coap_separate_accept(request, &separate_store->request_metadata); + /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ + + /* + * At the moment, only the minimal information is stored in the store (client address, port, token, MID, type, and Block2). + * Extend the store, if the application requires additional information from this handler. + * buffer is an example field for custom information. + */ + snprintf(separate_store->buffer, sizeof(separate_store->buffer), "StoredInfo"); + } +} +static void +res_resume_handler() +{ + if(separate_active) { + coap_transaction_t *transaction = NULL; + if((transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port))) { + coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(response, &separate_store->request_metadata, REST.status.OK); + + coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); + + /* + * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. + * As it is a critical option, this example resource pretends to handle it for compliance. + */ + coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); + + /* Warning: No check for serialization error. */ + transaction->packet_len = coap_serialize_message(response, transaction->packet); + coap_send_transaction(transaction); + /* The engine will clear the transaction (right after send for NON, after acked for CON). */ + + /* FIXME there could me more! */ + separate_active = 0; + } else { + /* + * Set timer for retry, send error message, ... + * The example simply waits for another button press. + */ + } + } /* if (separate_active) */ +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-sht11.c b/examples/osd/er-rest-example-merkurboard/resources/res-sht11.c new file mode 100644 index 000000000..56ed86c01 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-sht11.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2014, Nimbus Centre for Embedded Systems Research, Cork Institute of Technology. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * SHT11 Sensor Resource + * + * This is a simple GET resource that returns the temperature in Celsius + * and the humidity reading from the SHT11. + * \author + * Pablo Corbalan + */ + +#include "contiki.h" + +#if PLATFORM_HAS_SHT11 + +#include +#include "rest-engine.h" +#include "dev/sht11/sht11-sensor.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* Get Method Example. Returns the reading from temperature and humidity sensors. */ +RESOURCE(res_sht11, + "title=\"Temperature and Humidity\";rt=\"Sht11\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + /* Temperature in Celsius (t in 14 bits resolution at 3 Volts) + * T = -39.60 + 0.01*t + */ + uint16_t temperature = ((sht11_sensor.value(SHT11_SENSOR_TEMP) / 10) - 396) / 10; + /* Relative Humidity in percent (h in 12 bits resolution) + * RH = -4 + 0.0405*h - 2.8e-6*(h*h) + */ + uint16_t rh = sht11_sensor.value(SHT11_SENSOR_HUMIDITY); + + unsigned int accept = -1; + REST.get_header_accept(request, &accept); + + if(accept == -1 || accept == REST.type.TEXT_PLAIN) { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%u;%u", temperature, rh); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_XML) { + REST.set_header_content_type(response, REST.type.APPLICATION_XML); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "", temperature, rh); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else if(accept == REST.type.APPLICATION_JSON) { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'Sht11':{'Temperature':%u,'Humidity':%u}}", temperature, rh); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain, application/xml, and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif /* PLATFORM_HAS_SHT11 */ diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-sub.c b/examples/osd/er-rest-example-merkurboard/resources/res-sub.c new file mode 100644 index 000000000..1d6f17aeb --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-sub.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include +#include "rest-engine.h" + +static void res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* + * Example for a resource that also handles all its sub-resources. + * Use REST.get_url() to multiplex the handling of the request depending on the Uri-Path. + */ +PARENT_RESOURCE(res_sub, + "title=\"Sub-resource demo\"", + res_get_handler, + NULL, + NULL, + NULL); + +static void +res_get_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + + const char *uri_path = NULL; + int len = REST.get_url(request, &uri_path); + int base_len = strlen(res_sub.url); + + if(len == base_len) { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "Request any sub-resource of /%s", res_sub.url); + } else { + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, ".%.*s", len - base_len, uri_path + base_len); + } REST.set_response_payload(response, buffer, strlen((char *)buffer)); +} diff --git a/examples/osd/er-rest-example-merkurboard/resources/res-toggle.c b/examples/osd/er-rest-example-merkurboard/resources/res-toggle.c new file mode 100644 index 000000000..d8a773306 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/resources/res-toggle.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2013, Institute for Pervasive Computing, ETH Zurich + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + */ + +/** + * \file + * Example resource + * \author + * Matthias Kovatsch + */ + +#include "contiki.h" + +#if PLATFORM_HAS_LEDS + +#include +#include "contiki.h" +#include "rest-engine.h" +#include "dev/leds.h" + +static void res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); + +/* A simple actuator example. Toggles the red led */ +RESOURCE(res_toggle, + "title=\"Red LED\";rt=\"Control\"", + NULL, + res_post_handler, + NULL, + NULL); + +static void +res_post_handler(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + leds_toggle(LEDS_RED); +} +#endif /* PLATFORM_HAS_LEDS */ diff --git a/examples/osd/er-rest-example-merkurboard/server-client-native.csc b/examples/osd/er-rest-example-merkurboard/server-client-native.csc new file mode 100644 index 000000000..71e314075 --- /dev/null +++ b/examples/osd/er-rest-example-merkurboard/server-client-native.csc @@ -0,0 +1,231 @@ + + + [APPS_DIR]/mrm + [APPS_DIR]/mspsim + [APPS_DIR]/avrora + [APPS_DIR]/serial_socket + [APPS_DIR]/collect-view + [APPS_DIR]/powertracker + + REST with RPL router + 1.0 + 123456 + 1000000 + + org.contikios.cooja.radiomediums.UDGM + 50.0 + 50.0 + 1.0 + 1.0 + + + 40000 + + + org.contikios.cooja.mspmote.SkyMoteType + slipradio + Sky SLIP radio + [CONTIKI_DIR]/examples/ipv6/slip-radio/slip-radio.c + make slip-radio.sky TARGET=sky + [CONTIKI_DIR]/examples/ipv6/slip-radio/slip-radio.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + org.contikios.cooja.mspmote.SkyMoteType + server + Erbium Server + [CONTIKI_DIR]/examples/er-rest-example/er-example-server.c + make er-example-server.sky TARGET=sky + [CONTIKI_DIR]/examples/er-rest-example/er-example-server.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + org.contikios.cooja.mspmote.SkyMoteType + client + Erbium Client + [CONTIKI_DIR]/examples/er-rest-example/er-example-client.c + make er-example-client.sky TARGET=sky + [CONTIKI_DIR]/examples/er-rest-example/er-example-client.sky + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature + + + + + org.contikios.cooja.interfaces.Position + 30.303994886410642 + 17.22128424003353 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 1 + + slipradio + + + + + org.contikios.cooja.interfaces.Position + 46.57186415376375 + 37.25589203828498 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 2 + + server + + + + + org.contikios.cooja.interfaces.Position + 18.194682268367348 + 50.210548118402656 + 0.0 + + + org.contikios.cooja.mspmote.interfaces.MspMoteID + 3 + + client + + + + org.contikios.cooja.plugins.SimControl + 259 + 0 + 179 + 1 + 2 + + + org.contikios.cooja.plugins.Visualizer + + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + org.contikios.cooja.plugins.skins.AttributeVisualizerSkin + org.contikios.cooja.plugins.skins.LEDVisualizerSkin + org.contikios.cooja.plugins.skins.AddressVisualizerSkin + 2.255467003316979 0.0 0.0 2.255467003316979 59.30641698643764 -13.478401994502008 + + 300 + 2 + 178 + 262 + 1 + + + org.contikios.cooja.plugins.LogListener + + + + + + 762 + 4 + 491 + 2 + 182 + + + org.contikios.cooja.plugins.RadioLogger + + 150 + + false + false + + + 451 + -1 + 305 + 73 + 140 + true + + + org.contikios.cooja.plugins.TimeLine + + 0 + 1 + 2 + + + + + 25.49079397896416 + + 1624 + 5 + 252 + 6 + 712 + + + org.contikios.cooja.plugins.MoteInterfaceViewer + 1 + + Serial port + 0,0 + + 853 + 3 + 491 + 765 + 182 + + + SerialSocketServer + 0 + 422 + 1 + 82 + 606 + 51 + + + diff --git a/examples/osd/er-rest-example-merkurboard/server-client.csc b/examples/osd/er-rest-example-merkurboard/server-client.csc index 0c09f41b5..470a9edfe 100644 --- a/examples/osd/er-rest-example-merkurboard/server-client.csc +++ b/examples/osd/er-rest-example-merkurboard/server-client.csc @@ -8,10 +8,11 @@ [APPS_DIR]/powertracker REST with RPL router + 1.0 123456 1000000 - se.sics.cooja.radiomediums.UDGM + org.contikios.cooja.radiomediums.UDGM 50.0 50.0 1.0 @@ -21,84 +22,84 @@ 40000 - se.sics.cooja.mspmote.SkyMoteType + org.contikios.cooja.mspmote.SkyMoteType rplroot Sky RPL Root [CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.c make border-router.sky TARGET=sky [CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.sky - se.sics.cooja.interfaces.Position - se.sics.cooja.interfaces.RimeAddress - se.sics.cooja.interfaces.IPAddress - se.sics.cooja.interfaces.Mote2MoteRelations - se.sics.cooja.interfaces.MoteAttributes - se.sics.cooja.mspmote.interfaces.MspClock - se.sics.cooja.mspmote.interfaces.MspMoteID - se.sics.cooja.mspmote.interfaces.SkyButton - se.sics.cooja.mspmote.interfaces.SkyFlash - se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem - se.sics.cooja.mspmote.interfaces.Msp802154Radio - se.sics.cooja.mspmote.interfaces.MspSerial - se.sics.cooja.mspmote.interfaces.SkyLED - se.sics.cooja.mspmote.interfaces.MspDebugOutput - se.sics.cooja.mspmote.interfaces.SkyTemperature + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature - se.sics.cooja.mspmote.SkyMoteType + org.contikios.cooja.mspmote.SkyMoteType server Erbium Server [CONTIKI_DIR]/examples/er-rest-example/er-example-server.c make er-example-server.sky TARGET=sky [CONTIKI_DIR]/examples/er-rest-example/er-example-server.sky - se.sics.cooja.interfaces.Position - se.sics.cooja.interfaces.RimeAddress - se.sics.cooja.interfaces.IPAddress - se.sics.cooja.interfaces.Mote2MoteRelations - se.sics.cooja.interfaces.MoteAttributes - se.sics.cooja.mspmote.interfaces.MspClock - se.sics.cooja.mspmote.interfaces.MspMoteID - se.sics.cooja.mspmote.interfaces.SkyButton - se.sics.cooja.mspmote.interfaces.SkyFlash - se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem - se.sics.cooja.mspmote.interfaces.Msp802154Radio - se.sics.cooja.mspmote.interfaces.MspSerial - se.sics.cooja.mspmote.interfaces.SkyLED - se.sics.cooja.mspmote.interfaces.MspDebugOutput - se.sics.cooja.mspmote.interfaces.SkyTemperature + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature - se.sics.cooja.mspmote.SkyMoteType + org.contikios.cooja.mspmote.SkyMoteType client Erbium Client [CONTIKI_DIR]/examples/er-rest-example/er-example-client.c make er-example-client.sky TARGET=sky [CONTIKI_DIR]/examples/er-rest-example/er-example-client.sky - se.sics.cooja.interfaces.Position - se.sics.cooja.interfaces.RimeAddress - se.sics.cooja.interfaces.IPAddress - se.sics.cooja.interfaces.Mote2MoteRelations - se.sics.cooja.interfaces.MoteAttributes - se.sics.cooja.mspmote.interfaces.MspClock - se.sics.cooja.mspmote.interfaces.MspMoteID - se.sics.cooja.mspmote.interfaces.SkyButton - se.sics.cooja.mspmote.interfaces.SkyFlash - se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem - se.sics.cooja.mspmote.interfaces.Msp802154Radio - se.sics.cooja.mspmote.interfaces.MspSerial - se.sics.cooja.mspmote.interfaces.SkyLED - se.sics.cooja.mspmote.interfaces.MspDebugOutput - se.sics.cooja.mspmote.interfaces.SkyTemperature + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature - se.sics.cooja.interfaces.Position + org.contikios.cooja.interfaces.Position 33.260163187353555 30.643217359962595 0.0 - se.sics.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.MspMoteID 1 rplroot @@ -106,13 +107,13 @@ - se.sics.cooja.interfaces.Position + org.contikios.cooja.interfaces.Position 46.57186415376375 40.35946215910942 0.0 - se.sics.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.MspMoteID 2 server @@ -120,35 +121,35 @@ - se.sics.cooja.interfaces.Position + org.contikios.cooja.interfaces.Position 18.638049428485125 47.55034515769599 0.0 - se.sics.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.MspMoteID 3 client - se.sics.cooja.plugins.SimControl + org.contikios.cooja.plugins.SimControl 259 0 179 - 0 - 0 + 2 + 1 - se.sics.cooja.plugins.Visualizer + org.contikios.cooja.plugins.Visualizer - se.sics.cooja.plugins.skins.IDVisualizerSkin - se.sics.cooja.plugins.skins.UDGMVisualizerSkin - se.sics.cooja.plugins.skins.MoteTypeVisualizerSkin - se.sics.cooja.plugins.skins.AttributeVisualizerSkin - se.sics.cooja.plugins.skins.LEDVisualizerSkin - se.sics.cooja.plugins.skins.AddressVisualizerSkin + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + org.contikios.cooja.plugins.skins.AttributeVisualizerSkin + org.contikios.cooja.plugins.skins.LEDVisualizerSkin + org.contikios.cooja.plugins.skins.AddressVisualizerSkin 3.61568947862321 0.0 0.0 3.61568947862321 15.610600779367 -85.92728269158351 300 @@ -158,9 +159,10 @@ 1 - se.sics.cooja.plugins.LogListener + org.contikios.cooja.plugins.LogListener + 762 @@ -170,9 +172,12 @@ 182 - se.sics.cooja.plugins.RadioLogger + org.contikios.cooja.plugins.RadioLogger 150 + + false + false 451 @@ -192,7 +197,7 @@ 18 - se.sics.cooja.plugins.TimeLine + org.contikios.cooja.plugins.TimeLine 0 1 @@ -201,7 +206,6 @@ - 125 25.49079397896416 1624 @@ -211,7 +215,7 @@ 712 - se.sics.cooja.plugins.MoteInterfaceViewer + org.contikios.cooja.plugins.MoteInterfaceViewer 2 Serial port diff --git a/examples/osd/er-rest-example-merkurboard/server-only.csc b/examples/osd/er-rest-example-merkurboard/server-only.csc index 935bd6e79..6c0bba3e0 100644 --- a/examples/osd/er-rest-example-merkurboard/server-only.csc +++ b/examples/osd/er-rest-example-merkurboard/server-only.csc @@ -8,10 +8,11 @@ [APPS_DIR]/powertracker REST with RPL router + 1.0 123456 1000000 - se.sics.cooja.radiomediums.UDGM + org.contikios.cooja.radiomediums.UDGM 50.0 50.0 1.0 @@ -21,61 +22,61 @@ 40000 - se.sics.cooja.mspmote.SkyMoteType + org.contikios.cooja.mspmote.SkyMoteType rplroot Sky RPL Root [CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.c make border-router.sky TARGET=sky [CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.sky - se.sics.cooja.interfaces.Position - se.sics.cooja.interfaces.RimeAddress - se.sics.cooja.interfaces.IPAddress - se.sics.cooja.interfaces.Mote2MoteRelations - se.sics.cooja.interfaces.MoteAttributes - se.sics.cooja.mspmote.interfaces.MspClock - se.sics.cooja.mspmote.interfaces.MspMoteID - se.sics.cooja.mspmote.interfaces.SkyButton - se.sics.cooja.mspmote.interfaces.SkyFlash - se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem - se.sics.cooja.mspmote.interfaces.Msp802154Radio - se.sics.cooja.mspmote.interfaces.MspSerial - se.sics.cooja.mspmote.interfaces.SkyLED - se.sics.cooja.mspmote.interfaces.MspDebugOutput - se.sics.cooja.mspmote.interfaces.SkyTemperature + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature - se.sics.cooja.mspmote.SkyMoteType + org.contikios.cooja.mspmote.SkyMoteType server Erbium Server [CONTIKI_DIR]/examples/er-rest-example/er-example-server.c make er-example-server.sky TARGET=sky [CONTIKI_DIR]/examples/er-rest-example/er-example-server.sky - se.sics.cooja.interfaces.Position - se.sics.cooja.interfaces.RimeAddress - se.sics.cooja.interfaces.IPAddress - se.sics.cooja.interfaces.Mote2MoteRelations - se.sics.cooja.interfaces.MoteAttributes - se.sics.cooja.mspmote.interfaces.MspClock - se.sics.cooja.mspmote.interfaces.MspMoteID - se.sics.cooja.mspmote.interfaces.SkyButton - se.sics.cooja.mspmote.interfaces.SkyFlash - se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem - se.sics.cooja.mspmote.interfaces.Msp802154Radio - se.sics.cooja.mspmote.interfaces.MspSerial - se.sics.cooja.mspmote.interfaces.SkyLED - se.sics.cooja.mspmote.interfaces.MspDebugOutput - se.sics.cooja.mspmote.interfaces.SkyTemperature + org.contikios.cooja.interfaces.Position + org.contikios.cooja.interfaces.RimeAddress + org.contikios.cooja.interfaces.IPAddress + org.contikios.cooja.interfaces.Mote2MoteRelations + org.contikios.cooja.interfaces.MoteAttributes + org.contikios.cooja.mspmote.interfaces.MspClock + org.contikios.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.SkyButton + org.contikios.cooja.mspmote.interfaces.SkyFlash + org.contikios.cooja.mspmote.interfaces.SkyCoffeeFilesystem + org.contikios.cooja.mspmote.interfaces.Msp802154Radio + org.contikios.cooja.mspmote.interfaces.MspSerial + org.contikios.cooja.mspmote.interfaces.SkyLED + org.contikios.cooja.mspmote.interfaces.MspDebugOutput + org.contikios.cooja.mspmote.interfaces.SkyTemperature - se.sics.cooja.interfaces.Position + org.contikios.cooja.interfaces.Position 33.260163187353555 30.643217359962595 0.0 - se.sics.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.MspMoteID 1 rplroot @@ -83,59 +84,63 @@ - se.sics.cooja.interfaces.Position + org.contikios.cooja.interfaces.Position 35.100895239785295 39.70574552287428 0.0 - se.sics.cooja.mspmote.interfaces.MspMoteID + org.contikios.cooja.mspmote.interfaces.MspMoteID 2 server - se.sics.cooja.plugins.SimControl + org.contikios.cooja.plugins.SimControl 259 0 179 - 0 - 0 + 2 + 1 - se.sics.cooja.plugins.Visualizer + org.contikios.cooja.plugins.Visualizer - se.sics.cooja.plugins.skins.IDVisualizerSkin - se.sics.cooja.plugins.skins.UDGMVisualizerSkin - se.sics.cooja.plugins.skins.MoteTypeVisualizerSkin - se.sics.cooja.plugins.skins.AttributeVisualizerSkin - se.sics.cooja.plugins.skins.LEDVisualizerSkin - se.sics.cooja.plugins.skins.AddressVisualizerSkin + org.contikios.cooja.plugins.skins.IDVisualizerSkin + org.contikios.cooja.plugins.skins.UDGMVisualizerSkin + org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin + org.contikios.cooja.plugins.skins.AttributeVisualizerSkin + org.contikios.cooja.plugins.skins.LEDVisualizerSkin + org.contikios.cooja.plugins.skins.AddressVisualizerSkin 7.9849281638410705 0.0 0.0 7.9849281638410705 -133.27812697619663 -225.04752569190535 300 - 5 + 1 175 - 263 - 3 + 262 + 2 - se.sics.cooja.plugins.LogListener + org.contikios.cooja.plugins.LogListener + 560 - 2 + 3 326 1 293 - se.sics.cooja.plugins.RadioLogger + org.contikios.cooja.plugins.RadioLogger 150 + + false + false 451 @@ -149,13 +154,13 @@ SerialSocketServer 0 422 - 3 + 4 74 39 199 - se.sics.cooja.plugins.TimeLine + org.contikios.cooja.plugins.TimeLine 0 1 @@ -163,24 +168,23 @@ - 125 25.49079397896416 1624 - 4 + 5 252 4 622 - se.sics.cooja.plugins.MoteInterfaceViewer + org.contikios.cooja.plugins.MoteInterfaceViewer 1 Serial port 0,0 702 - 1 + 2 646 564 2