update to caop 13

This commit is contained in:
Harald Pichler 2013-07-30 17:46:44 +02:00
parent 48fff35bd9
commit ba2e08aebf
11 changed files with 1101 additions and 529 deletions

View file

@ -1,44 +1,53 @@
all: er-example-server er-example-client
# Use this target explicitly if requried: er-plugtest-server
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
# variable for Makefile.include
WITH_UIP6=1
# for some platforms
UIP_CONF_IPV6=1
# IPv6 make config disappeared completely
CFLAGS += -DUIP_CONF_IPV6=1
CONTIKI=../../..
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
# for static routing, if enabled
# variable for Makefile.include
ifneq ($(TARGET), minimal-net)
ifneq ($(TARGET), native)
ifneq ($(findstring avr,$(TARGET)), avr)
PROJECT_SOURCEFILES += static-routing.c
endif
endif
endif
# variable for root Makefile.include
WITH_UIP6=1
# for some platforms
UIP_CONF_IPV6=1
# variable for this Makefile
# configure CoAP implementation (3|7) (er-coap-07 also supports CoAP draft 08)
WITH_COAP=7
# new variable since slip-radio
ifneq ($(TARGET), minimal-net)
UIP_CONF_RPL=1
CFLAGS += -DUIP_CONF_IPV6_RPL=1
else
# minimal-net does not support RPL under Linux and is mostly used to test CoAP only
${info INFO: compiling without RPL}
UIP_CONF_RPL=0
CFLAGS += -DUIP_CONF_ND6_DEF_MAXDADNS=0
CFLAGS += -DUIP_CONF_IPV6_RPL=0
CFLAGS += -DHARD_CODED_ADDRESS=\"fdfd::10\"
CFLAGS += -DUIP_CONF_BUFFER_SIZE=1280
${info INFO: compiling with large buffers}
CFLAGS += -DUIP_CONF_BUFFER_SIZE=2048
CFLAGS += -DREST_MAX_CHUNK_SIZE=1024
CFLAGS += -DCOAP_MAX_HEADER_SIZE=640
endif
# linker optimizations
SMALL=1
# REST framework, requires WITH_COAP
ifeq ($(WITH_COAP), 7)
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
@ -84,5 +93,5 @@ connect-router: $(CONTIKI)/tools/tunslip6
connect-router-cooja: $(CONTIKI)/tools/tunslip6
sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 aaaa::1/64
tap0up:
connect-minimal:
sudo ip address add fdfd::1/64 dev tap0

View file

@ -0,0 +1,166 @@
A Quick Introduction to the Erbium (Er) REST Engine
===================================================
EXAMPLE FILES
-------------
- er-example-server.c: A RESTful server example showing how to use the REST
layer to develop server-side applications (at the moment only CoAP is
implemented for the REST Engine).
- er-example-client.c: A CoAP client that polls the /actuators/toggle resource
every 10 seconds and cycles through 4 resources on button press (target
address is hard-coded).
- er-plugtest-server.c: The server used for draft compliance testing at ETSI
IoT CoAP Plugtests. Erbium (Er) participated in Paris, France, March 2012 and
Sophia-Antipolis, France, November 2012 (configured for minimal-net).
PRELIMINARIES
-------------
- Make sure rpl-border-router has the same stack and fits into mote memory:
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
- For convenience, define the Cooja addresses in /etc/hosts
aaaa::0212:7401:0001:0101 cooja1
aaaa::0212:7402:0002:0202 cooja2
...
- Get the Copper (Cu) CoAP user-agent from
[https://addons.mozilla.org/en-US/firefox/addon/copper-270430](https://addons.mozilla.org/en-US/firefox/addon/copper-270430)
- Optional: Save your target as default target
make TARGET=sky savetarget
COOJA HOWTO
-----------
###Server only:
make TARGET=cooja server-only.csc
Open new terminal
make connect-router-cooja
- Start Copper and discover resources at coap://cooja2:5683/
- Choose "Click button on Sky 2" from the context menu of mote 2 (server) after
requesting /test/separate
- Do the same when observing /test/event
###With client:
make TARGET=cooja server-client.csc
Open new terminal
make connect-router-cooja
- Wait until red LED toggles on mote 2 (server)
- Choose "Click button on Sky 3" from the context menu of mote 3 (client) and
watch serial output
TMOTES HOWTO
------------
###Server:
1. Connect two Tmote Skys (check with $ make TARGET=sky sky-motelist)
make TARGET=sky er-example-server.upload MOTE=2
make TARGET=sky login MOTE=2
2. Press reset button, get address, abort with Ctrl+C:
Line: "Tentative link-local IPv6 address fe80:0000:0000:0000:____:____:____:____"
cd ../ipv6/rpl-border-router/
make TARGET=sky border-router.upload MOTE=1
make connect-router
For a BR tty other than USB0:
make connect-router-port PORT=X
3. Start Copper and discover resources at:
coap://[aaaa::____:____:____:____]:5683/
### Add a client:
1. Change the hard-coded server address in er-example-client.c to aaaa::____:____:____:____
2. Connect a third Tmote Sky
make TARGET=sky er-example-client.upload MOTE=3
MINIMAL-NET HOWTO
-----------------
With the target minimal-net you can test your CoAP applications without
constraints, i.e., with large buffers, debug output, memory protection, etc.
The er-plugtest-server is thought for the minimal-net platform, as it requires
an 1280-byte IP buffer and 1024-byte blocks.
make TARGET=minimal-net er-plugtest-server
sudo ./er-plugtest-server.minimal-net
Open new terminal
make connect-minimal
- Start Copper and discover resources at coap://[fdfd::ff:fe00:10]:5683/
- You can enable the ETSI Plugtest menu in Copper's preferences
Under Windows/Cygwin, WPCAP might need a patch in
<cygwin>\usr\include\w32api\in6addr.h:
21,23c21
< #ifdef __INSIDE_CYGWIN__
< uint32_t __s6_addr32[4];
< #endif
---
> u_int __s6_addr32[4];
36d33
< #ifdef __INSIDE_CYGWIN__
39d35
< #endif
DETAILS
-------
Erbium currently implements draft 13. Central features are commented in
er-example-server.c. In general, apps/er-coap-13 supports:
- All draft 13 header options
- CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS)
- Blockwise Transfers (note REST_MAX_CHUNK_SIZE, see er-plugtest-server.c for
Block1 uploads)
- Separate Responses (no rest_set_pre_handler() required anymore, note
coap_separate_accept(), _reject(), and _resume())
- Resource Discovery
- 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
-----
- Dedicated Observe buffers
- Optimize message struct variable access (directly access struct without copying)
- Observe client
- Multiple If-Match ETags
- (Message deduplication)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Matthias Kovatsch and other contributors.
* Copyright (c) 2013, Matthias Kovatsch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,11 +43,6 @@
#include "contiki.h"
#include "contiki-net.h"
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE)
#warning "Compiling with static routing!"
#include "static-routing.h"
#endif
#include "dev/button-sensor.h"
#include "dev/leds.h"
@ -57,6 +52,10 @@
#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
@ -94,7 +93,7 @@ char* service_urls[NUMBER_OF_URLS] = {".well-known/core", "/actuators/toggle", "
void
client_chunk_handler(void *response)
{
uint8_t *chunk;
const uint8_t *chunk;
int len = coap_get_payload(response, &chunk);
printf("|%.*s", len, (char *)chunk);
@ -129,7 +128,6 @@ PROCESS_THREAD(coap_client_example, ev, data)
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_set_header_uri_path(request, service_urls[1]);

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Matthias Kovatsch and other contributors.
* Copyright (c) 2013, Matthias Kovatsch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -44,34 +44,24 @@
/* Define which resources to include to meet memory constraints. */
#define REST_RES_INFO 1
#define REST_RES_DS1820 0
#define REST_RES_HELLO 0
#define REST_RES_MIRROR 0 /* causes largest code size */
#define REST_RES_CHUNKS 0
#define REST_RES_SEPARATE 0
#define REST_RES_PUSHING 0
#define REST_RES_CHUNKS 1
#define REST_RES_SEPARATE 1
#define REST_RES_PUSHING 1
#define REST_RES_EVENT 1
#define REST_RES_SUB 0
#define REST_RES_LEDS 1
#define REST_RES_SUB 1
#define REST_RES_LEDS 0
#define REST_RES_TOGGLE 1
#define REST_RES_LIGHT 0
#define REST_RES_BATTERY 1
#define REST_RES_BATTERY 0
#define REST_RES_RADIO 0
#define REST_RES_MIRROR 0 /* causes largest code size */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE)
#warning "Compiling with static routing!"
#include "static-routing.h"
#endif
#include "erbium.h"
#if REST_RES_DS1820
#include "dev/ds1820.h"
#endif
#if defined (PLATFORM_HAS_BUTTON)
#include "dev/button-sensor.h"
#endif
@ -97,6 +87,10 @@
#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 */
@ -113,159 +107,6 @@
#endif
/******************************************************************************/
#if REST_RES_INFO
/*
* Resources are defined by the RESOURCE macro.
* Signature: resource name, the RESTful methods it handles, and its URI path (omitting the leading slash).
*/
RESOURCE(info, METHOD_GET, "info", "title=\"Info\";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
info_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
char message[100];
int index = 0;
int length = 0; /* |<-------->| */
/* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */
// jSON Format
index += sprintf(message + index,"{\n \"version\" : \"V0.4\",\n");
index += sprintf(message + index," \"name\" : \"Button,LED\"\n");
index += sprintf(message + index,"}\n");
length = strlen(message);
memcpy(buffer, message,length );
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
REST.set_response_payload(response, buffer, length);
}
#endif
/*A simple actuator example, post variable mode, relay is activated or deactivated*/
/*
RESOURCE(led1, METHOD_GET | METHOD_PUT , "led1", "title=\"Led1\";rt=\"Text\"");
void
led1_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
char mode[10];
static uint8_t led1 = 0;
static char name[17]="led1";
int success = 1;
char temp[100];
int index = 0;
size_t len = 0;
const char *pmode = NULL;
const char *pname = NULL;
switch(REST.get_method_type(request)){
case METHOD_GET:
// jSON Format
index += sprintf(temp + index,"{\n \"name\" : \"%s\",\n",name);
if(led1 == 0)
index += sprintf(temp + index," \"mode\" : \"off\"\n");
if(led1 == 1)
index += sprintf(temp + index," \"mode\" : \"on\"\n");
index += sprintf(temp + index,"}\n");
len = strlen(temp);
memcpy(buffer, temp,len );
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
REST.set_response_payload(response, buffer, len);
break;
case METHOD_POST:
success = 0;
break;
case METHOD_PUT:
if (success && (len=REST.get_post_variable(request, "mode", &pmode))) {
PRINTF("name %s\n", mode);
memcpy(mode, pmode,len);
mode[len]=0;
if (!strcmp(mode, "on")) {
led1_on();
led1 = 1;
} else if (!strcmp(mode, "off")) {
led1_off();
led1 = 0;
} else {
success = 0;
}
} else if (success && (len=REST.get_post_variable(request, "name", &pname))) {
PRINTF("name %s\n", name);
memcpy(name, pname,len);
name[len]=0;
} else {
success = 0;
}
break;
default:
success = 0;
}
if (!success) {
REST.set_response_status(response, REST.status.BAD_REQUEST);
}
}
*/
#if REST_RES_DS1820
/*A simple getter example. Returns the reading from ds1820 sensor*/
RESOURCE(ds1820, METHOD_GET, "DS1820", "title=\"Temperatur\";rt=\"Temperatur\"");
void
ds1820_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
char message[100];
int length = 0; /* |<-------->| */
int ret=0;
int grad=0;
int kgrad=0;
// ret=ds1820_temp();
if(ds1820_ok[0] & 0x01){
kgrad=5;
}
grad = (int)((ds1820_ok[1] << 8) | (ds1820_ok[0])) >> 1;
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(message, REST_MAX_CHUNK_SIZE, "%2d.%d °C",grad,kgrad);
length = strlen(message);
memcpy(buffer, message,length );
REST.set_response_payload(response, buffer, length);
}
else if (num && (accept[0]==REST.type.APPLICATION_JSON))
{
REST.set_header_content_type(response, REST.type.APPLICATION_JSON);
snprintf(message, REST_MAX_CHUNK_SIZE, "{\"temp\":\"%d.%d °C\"}",grad,kgrad);
length = strlen(message);
memcpy(buffer, message,length );
REST.set_response_payload(response, buffer, length);
}
else
{
REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE);
REST.set_response_payload(response, (uint8_t *)"Supporting content-types text/plain and application/json", 56);
}
}
#endif //REST_RES_DS1820
#if REST_RES_HELLO
/*
* Resources are defined by the RESOURCE macro.
@ -321,7 +162,7 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
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 = 0;
uint32_t max_age_and_size = 0;
const char *str = NULL;
uint32_t observe = 0;
const uint8_t *bytes = NULL;
@ -336,14 +177,22 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
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. */
strpos += snprintf((char *)buffer, REST_MAX_CHUNK_SIZE+1, "CT %u\n", content_type);
* 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))
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);
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)))
@ -433,9 +282,10 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
/* 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, 10); /* For HTTP, browsers will not re-request the page for 10 seconds. CoAP action depends on the client. */
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
@ -517,8 +367,16 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
/******************************************************************************/
#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"
#endif
/*
* CoAP-specific example for separate responses.
* Note the call "rest_set_pre_handler(&resource_separate, coap_separate_handler);" in the main process.
@ -577,7 +435,7 @@ separate_finalize_handler()
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);
coap_separate_resume(response, &separate_store->request_metadata, REST.status.OK);
coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer));
@ -642,7 +500,7 @@ pushing_periodic_handler(resource_t *r)
/* 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, CONTENT_2_05, 0 );
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. */
@ -684,7 +542,7 @@ event_event_handler(resource_t *r)
/* 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, CONTENT_2_05, 0 );
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. */
@ -715,7 +573,7 @@ sub_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_s
}
else
{
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, ".%s", uri_path+base_len);
snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, ".%.*s", len-base_len, uri_path+base_len);
}
REST.set_response_payload(response, buffer, strlen((char *)buffer));
@ -777,7 +635,7 @@ leds_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_
/******************************************************************************/
#if REST_RES_TOGGLE
/* A simple actuator example. Toggles the red led */
RESOURCE(toggle, METHOD_GET | METHOD_PUT | METHOD_POST, "actuators/toggle", "title=\"Red LED\";rt=\"Control\"");
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)
{
@ -822,7 +680,7 @@ light_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
}
else
{
REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE);
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));
}
@ -857,7 +715,7 @@ battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr
}
else
{
REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE);
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));
}
@ -915,7 +773,7 @@ radio_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
}
else
{
REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE);
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));
}
@ -925,29 +783,13 @@ radio_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
}
#endif
void
hw_init()
{
#if defined (PLATFORM_HAS_LEDS)
leds_off(LEDS_RED);
#endif
#if REST_RES_DS1820
ds1820_temp();
#endif
}
#define MESURE_INTERVAL (10 * CLOCK_SECOND)
#define READ_TIME ( 2 * CLOCK_SECOND)
PROCESS(rest_server_example, "Erbium Example Server");
AUTOSTART_PROCESSES(&rest_server_example);
PROCESS_THREAD(rest_server_example, ev, data)
{
#if REST_RES_DS1820
static struct etimer ds_periodic_timer;
static struct etimer ds_read_timer;
#endif
PROCESS_BEGIN();
PRINTF("Starting Erbium Example Server\n");
@ -964,25 +806,10 @@ 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);
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE)
set_global_address();
configure_routing();
#endif
/* Initialize the OSD Hardware. */
hw_init();
/* Initialize the REST engine. */
rest_init_engine();
/* Activate the application-specific resources. */
#if REST_RES_DS1820
rest_activate_resource(&resource_ds1820);
#endif
#if REST_RES_INFO
rest_activate_resource(&resource_info);
#endif
#if REST_RES_HELLO
rest_activate_resource(&resource_helloworld);
#endif
@ -1030,9 +857,6 @@ PROCESS_THREAD(rest_server_example, ev, data)
#endif
/* Define application-specific events here. */
#if REST_RES_DS1820
etimer_set(&ds_periodic_timer, MESURE_INTERVAL);
#endif
while(1) {
PROCESS_WAIT_EVENT();
#if defined (PLATFORM_HAS_BUTTON)
@ -1048,19 +872,6 @@ PROCESS_THREAD(rest_server_example, ev, data)
#endif
}
#endif /* PLATFORM_HAS_BUTTON */
#if REST_RES_DS1820
if(etimer_expired(&ds_periodic_timer)) {
PRINTF("DS1820_Periodic\n");
etimer_reset(&ds_periodic_timer);
if(ds1820_convert()){
etimer_set(&ds_read_timer, READ_TIME);
}
}
if(etimer_expired(&ds_read_timer)) {
PRINTF("DS1820_Read\n");
ds1820_read();
}
#endif
} /* while (1) */
PROCESS_END();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, Matthias Kovatsch and other contributors.
* Copyright (c) 2013, Matthias Kovatsch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -43,33 +43,42 @@
#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
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE)
#warning "Compiling with static routing!"
#include "static-routing.h"
#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 */
@ -92,31 +101,136 @@
*/
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; 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]
);
}
void
test_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);
const uint8_t *bytes = NULL;
size_t len = 0;
if (test_change)
{
test_update_etag();
}
PRINTF("/test ");
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));
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 ### 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, "/nirvana");
REST.set_header_location(response, "/location1/location2/location3");
}
else if (method & METHOD_PUT)
{
PRINTF("PUT ");
REST.set_response_status(response, REST.status.CHANGED);
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)
{
@ -126,6 +240,233 @@ test_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_
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; 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]
);
}
void
validate_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);
const uint8_t *bytes = NULL;
size_t len = 0;
if (validate_change)
{
validate_update_etag();
}
PRINTF("/validate ");
if (method & METHOD_GET)
{
PRINTF("GET ");
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));
}
}
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
@ -179,10 +520,119 @@ query_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
}
#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, "<status type=\"%u\" code=\"%u\" mid=\"%u\" accept=\"%u\"/>", 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, "</path/sub1>,</path/sub2>,</path/sub3>");
}
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
*/
@ -264,12 +714,15 @@ separate_periodic_handler(resource_t *resource)
#endif
#if REST_RES_LARGE
/* double expansion */
#define TO_STRING2(x) #x
#define TO_STRING(x) TO_STRING2(x)
/*
* Large resource
*/
RESOURCE(large, METHOD_GET, "large", "title=\"Large resource\";rt=\"block\"");
#define CHUNKS_TOTAL 1280
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)
@ -323,10 +776,10 @@ large_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
/*
* 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\"");
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 = 1280;
static uint8_t large_update_store[2048] = {0};
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
@ -348,7 +801,7 @@ large_update_handler(void* request, void* response, uint8_t *buffer, uint16_t pr
return;
}
REST.set_response_payload(response, large_update_store+*offset, preferred_size);
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. */
@ -372,7 +825,7 @@ large_update_handler(void* request, void* response, uint8_t *buffer, uint16_t pr
return;
}
if ((len = REST.get_request_payload(request, &incoming)))
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))
{
@ -424,7 +877,7 @@ large_create_handler(void* request, void* response, uint8_t *buffer, uint16_t pr
return;
}
if ((len = REST.get_request_payload(request, &incoming)))
if ((len = REST.get_request_payload(request, (const uint8_t **) &incoming)))
{
if (coap_req->block1_num*coap_req->block1_size+len <= 2048)
{
@ -451,23 +904,102 @@ large_create_handler(void* request, void* response, uint8_t *buffer, uint16_t pr
#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, "obs", "title=\"Observable resource which changes every 5 seconds\";obs;rt=\"observe\"", 5*CLOCK_SECOND);
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[16];
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)
{
REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
REST.set_header_max_age(response, 5);
uint8_t method = request==NULL ? METHOD_GET : REST.get_method_type(request);
REST.set_response_payload(response, obs_content, snprintf(obs_content, MAX_PLUGFEST_PAYLOAD, "TICK %lu", obs_counter));
/* 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;
/* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */
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");
}
}
/*
@ -479,8 +1011,37 @@ obs_periodic_handler(resource_t *r)
{
++obs_counter;
PRINTF("TICK %u for /%s\n", obs_counter, r->url);
//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. */
@ -491,9 +1052,169 @@ obs_periodic_handler(resource_t *r)
/* 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<len; ++index) {
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]);
}
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
}
if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_host(request, &str)))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Uri-Host %.*s\n", len, str);
}
if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_etag(request, &bytes)))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "ETag 0x");
int index = 0;
for (index = 0; index<len; ++index) {
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]);
}
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
}
if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_if_none_match(request))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "If-None-Match\n");
}
if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_observe(request, &observe))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Observe %lu\n", observe);
}
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, "Location-Path %.*s\n", len, str);
}
if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_uri_path(request, &str)))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Uri-Path %.*s\n", len, str);
}
if (strpos<=REST_MAX_CHUNK_SIZE && content_type!=-1)
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Content-Format %u\n", content_type);
}
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, "Max-Age %lu\n", max_age_and_size);
}
if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &query)))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Uri-Query %.*s\n", len, query);
}
if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_header_accept(request, &words)))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Accept ");
int index = 0;
for (index = 0; index<len; ++index) {
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%u", words[index]);
}
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
}
if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_token(request, &bytes)))
{
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Token 0x");
int index = 0;
for (index = 0; index<len; ++index) {
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%02X", bytes[index]);
}
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
}
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, "Location-Query %.*s\n", len, str);
}
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, "Block2 %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)) /* 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, "Block1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
}
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, "Size %lu\n", max_age_and_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, "\n%.*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, "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 */
PROCESS(plugtest_server, "PlugtestServer");
AUTOSTART_PROCESSES(&plugtest_server);
@ -515,18 +1236,16 @@ PROCESS_THREAD(plugtest_server, ev, data)
PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN);
PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE);
/* if static routes are used rather than RPL */
#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET)
set_global_address();
configure_routing();
#endif
/* Initialize the REST engine. */
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);
@ -534,6 +1253,20 @@ PROCESS_THREAD(plugtest_server, ev, data)
#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
@ -551,6 +1284,10 @@ PROCESS_THREAD(plugtest_server, ev, data)
rest_activate_periodic_resource(&periodic_resource_obs);
#endif
#if REST_RES_MIRROR
rest_activate_resource(&resource_mirror);
#endif
/* Define application-specific events here. */
while(1) {
PROCESS_WAIT_EVENT();

View file

@ -0,0 +1,10 @@
21,23c21
< #ifdef __INSIDE_CYGWIN__
< uint32_t __s6_addr32[4];
< #endif
---
> u_int __s6_addr32[4];
36d33
< #ifdef __INSIDE_CYGWIN__
39d35
< #endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, Swedish Institute of Computer Science.
* Copyright (c) 2013, Matthias Kovatsch
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -29,44 +29,60 @@
*
*/
#ifndef __PROJECT_RPL_WEB_CONF_H__
#define __PROJECT_RPL_WEB_CONF_H__
#ifndef __PROJECT_ERBIUM_CONF_H__
#define __PROJECT_ERBIUM_CONF_H__
#define PLATFORM_HAS_LEDS 1
#define PLATFORM_HAS_BUTTON 1
#define PLATFORM_HAS_TEMPERATURE 1
#define PLATFORM_HAS_BATTERY 1
#define SICSLOWPAN_CONF_FRAG 1
/* Some platforms have weird includes. */
#undef IEEE802154_CONF_PANID
/* 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 NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
/* Increase rpl-border-router IP-buffer when using more than 64. */
#undef REST_MAX_CHUNK_SIZE
#define REST_MAX_CHUNK_SIZE 64
/* 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 1280
*/
/* Multiplies with chunk size, be aware of memory constraints. */
#undef COAP_MAX_OPEN_TRANSACTIONS
#define COAP_MAX_OPEN_TRANSACTIONS 4
/* Must be <= open transaction number, default is COAP_MAX_OPEN_TRANSACTIONS-1. */
/*
#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
*/
/* Save some memory for the sky platform. */
#undef UIP_CONF_DS6_NBR_NBU
#define UIP_CONF_DS6_NBR_NBU 10
#undef UIP_CONF_DS6_ROUTE_NBU
#define UIP_CONF_DS6_ROUTE_NBU 10
/* Increase rpl-border-router IP-buffer when using 128. */
#ifndef REST_MAX_CHUNK_SIZE
#define REST_MAX_CHUNK_SIZE 64
#endif
/* Multiplies with chunk size, be aware of memory constraints. */
#ifndef COAP_MAX_OPEN_TRANSACTIONS
#define COAP_MAX_OPEN_TRANSACTIONS 2
#endif
/* Must be <= open transaction number. */
#ifndef COAP_MAX_OBSERVERS
#define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS-1
#endif
#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
#define QUEUEBUF_CONF_NUM 4
#endif /* __PROJECT_RPL_WEB_CONF_H__ */
#undef SICSLOWPAN_CONF_FRAG
#define SICSLOWPAN_CONF_FRAG 1
#endif /* __PROJECT_ERBIUM_CONF_H__ */

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>REST with RPL router</title>
<delaytime>-2147483648</delaytime>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
@ -37,7 +37,7 @@
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
@ -60,7 +60,7 @@
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
@ -83,7 +83,7 @@
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>

View file

@ -1,13 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mrm</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/mspsim</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/avrora</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/serial_socket</project>
<project EXPORT="discard">[CONTIKI_DIR]/tools/cooja/apps/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>REST with RPL router</title>
<delaytime>-2147483648</delaytime>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
@ -37,7 +37,7 @@
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
@ -60,7 +60,7 @@
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyButton</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyFlash</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyByteRadio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspSerial</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.SkyLED</moteinterface>
<moteinterface>se.sics.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
@ -98,7 +98,7 @@
<plugin>
se.sics.cooja.plugins.SimControl
<width>259</width>
<z>5</z>
<z>0</z>
<height>179</height>
<location_x>0</location_x>
<location_y>0</location_y>
@ -115,7 +115,7 @@
<viewport>7.9849281638410705 0.0 0.0 7.9849281638410705 -133.27812697619663 -225.04752569190535</viewport>
</plugin_config>
<width>300</width>
<z>4</z>
<z>5</z>
<height>175</height>
<location_x>263</location_x>
<location_y>3</location_y>
@ -127,7 +127,7 @@
<coloring />
</plugin_config>
<width>560</width>
<z>1</z>
<z>2</z>
<height>326</height>
<location_x>1</location_x>
<location_y>293</location_y>
@ -149,7 +149,7 @@
SerialSocketServer
<mote_arg>0</mote_arg>
<width>422</width>
<z>2</z>
<z>3</z>
<height>74</height>
<location_x>39</location_x>
<location_y>199</location_y>
@ -167,7 +167,7 @@
<zoomfactor>25.49079397896416</zoomfactor>
</plugin_config>
<width>1624</width>
<z>3</z>
<z>4</z>
<height>252</height>
<location_x>4</location_x>
<location_y>622</location_y>
@ -180,7 +180,7 @@
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>702</width>
<z>0</z>
<z>1</z>
<height>646</height>
<location_x>564</location_x>
<location_y>2</location_y>

View file

@ -1,155 +0,0 @@
/*
* static-routing.c
*
* Created on: Oct 12, 2010
* Author: simonduq
*/
#include <stdio.h>
#include "static-routing.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#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
#include "contiki-net.h"
#include "node-id.h"
int node_rank;
struct id_to_addrs {
int id;
uint32_t addr;
};
const struct id_to_addrs motes_addrs[] = {
/*
* Static routing requires a map nodeid => address.
* The nodeid can be programmed with the sky-shell.
* The addresses should also be added to /etc/hosts.
*
* aaaa::212:7400:1160:f62d sky1
* aaaa::212:7400:0da0:d748 sky2
* aaaa::212:7400:116e:c325 sky3
* aaaa::212:7400:116e:c444 sky4
* aaaa::212:7400:115e:b717 sky5
*
* Add the nodeid and last 4 bytes of the address to the map.
*/
{1, 0x1160f62d},
{2, 0x0da0d748},
{3, 0x116ec325},
{4, 0x116ec444},
{5, 0x115eb717},
};
/* Define the size of the map. */
#define NODES_IN_MAP 5
uint32_t get_mote_suffix(int rank) {
if(--rank >=0 && rank<(sizeof(motes_addrs)/sizeof(struct id_to_addrs))) {
return motes_addrs[rank].addr;
}
return 0;
}
int get_mote_id(uint32_t suffix) {
#if IN_COOJA
return suffix & 0xff;
#else
int i;
for(i=0; i<(sizeof(motes_addrs)/sizeof(struct id_to_addrs)); i++) {
if(suffix == motes_addrs[i].addr) {
return motes_addrs[i].id;
}
}
return 0;
#endif
}
void set_global_address(void) {
uip_ipaddr_t ipaddr;
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF);
}
static void add_route_ext(int dest, int next) {
PRINTF("add route ext %d %d\n", dest, next);
uip_ipaddr_t ipaddr_dest, ipaddr_next;
uip_ip6addr(&ipaddr_dest, 0xaaaa, 0, 0, 0, 0, 0, 0, dest);
#if IN_COOJA
uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400 | next, next, next<<8 | next);
#else
uint32_t next_suffix = get_mote_suffix(next);
uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400, (next_suffix >> 16) & 0xffff, next_suffix & 0xffff);
#endif
uip_ds6_route_add(&ipaddr_dest, 128, &ipaddr_next, 0);
}
void add_route(int dest, int next) {
PRINTF("add route %d %d\n", dest, next);
uip_ipaddr_t ipaddr_dest, ipaddr_next;
#if IN_COOJA
uip_ip6addr(&ipaddr_dest, 0xaaaa, 0, 0, 0, 0x0212, 0x7400 | dest, dest, dest<<8 | dest);
uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400 | next, next, next<<8 | next);
#else
uint32_t dest_suffix = get_mote_suffix(dest);
uint32_t next_suffix = get_mote_suffix(next);
uip_ip6addr(&ipaddr_dest, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, (dest_suffix >> 16) & 0xffff, dest_suffix & 0xffff);
uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400, (next_suffix >> 16) & 0xffff, next_suffix & 0xffff);
#endif
uip_ds6_route_add(&ipaddr_dest, 128, &ipaddr_next, 0);
}
void configure_routing(void) {
int i;
#if IN_COOJA
node_rank = node_id;
#else
node_rank = -1;
for(i=0; i<(sizeof(motes_addrs)/sizeof(struct id_to_addrs)); ++i) {
if(node_id == motes_addrs[i].id) {
node_rank = i+1;
break;
}
}
if(node_rank == -1) {
printf("unable to configure routing, node_id=%d\n", node_id);
return;
}
#endif
printf("configure_routing, node_id=%d, node_rank %d\n", node_id, node_rank);
if (node_rank == 1) { /* border router #1 */
add_route_ext(2, 2);
for(i=2; i<=NODES_IN_MAP; ++i) {
add_route(i, 2);
}
} else if (node_rank < NODES_IN_MAP) { /* other node */
add_route_ext(1, node_rank-1);
add_route_ext(2, node_rank+1);
for(i=1; i<=NODES_IN_MAP; ++i) {
if(i<node_rank) {
add_route(i, node_rank-1);
} else if(i>node_rank) {
add_route(i, node_rank+1);
}
}
} else if (node_rank == NODES_IN_MAP) { /* 2nd border router */
add_route_ext(1, NODES_IN_MAP-1);
for(i=1; i<=NODES_IN_MAP-1; ++i) {
add_route(i, NODES_IN_MAP-1);
}
}
}

View file

@ -1,20 +0,0 @@
/*
* static-routing.h
*
* Created on: Oct 12, 2010
* Author: simonduq
*/
#ifndef STATICROUTING_H_
#define STATICROUTING_H_
#include "contiki.h"
extern int node_rank;
extern uint32_t get_mote_suffix(int id);
extern int get_mote_id(uint32_t suffix);
extern void add_route(int dest, int next);
extern void set_global_address(void);
extern void configure_routing(void);
#endif /* STATICROUTING_H_ */