Merge branch 'master' of ssh://contiki.git.sourceforge.net/gitroot/contiki/contiki

This commit is contained in:
nvt 2012-03-05 01:49:55 +01:00
commit 3860e798ac
76 changed files with 1689 additions and 3702 deletions

View file

@ -21,6 +21,17 @@ ifeq ($(DEFINES),)
endif endif
endif endif
ifndef HOST_OS
ifeq ($(OS),Windows_NT)
## TODO: detect more specific Windows set-ups,
## e.g. CygWin, MingW, VisualC, Watcom, Interix
$(warning Windows (NT) detected.)
HOST_OS := Windows
else
HOST_OS := $(shell uname)
endif
endif
usage: usage:
@echo "make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]" @echo "make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]"

View file

@ -206,7 +206,7 @@ handle_incoming_data(void)
} }
} else { } else {
error = MEMORY_ALLOC_ERR; error = MEMORY_ALLOCATION_ERROR;
} }
} }
else else

View file

@ -58,7 +58,7 @@ LIST(observers_list);
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
coap_observer_t * coap_observer_t *
coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len) coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len, const char *url)
{ {
coap_observer_t *o = memb_alloc(&observers_memb); coap_observer_t *o = memb_alloc(&observers_memb);
@ -173,7 +173,7 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
{ {
if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_TOKEN)) if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_TOKEN))
{ {
if (coap_add_observer(resource->url, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, ((coap_packet_t *)request)->token, ((coap_packet_t *)request)->token_len)) if (coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, ((coap_packet_t *)request)->token, ((coap_packet_t *)request)->token_len, resource->url))
{ {
coap_set_header_observe(response, 0); coap_set_header_observe(response, 0);
coap_set_payload(response, (uint8_t *)content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); coap_set_payload(response, (uint8_t *)content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS));

View file

@ -65,7 +65,7 @@ typedef struct coap_observer {
} coap_observer_t; } coap_observer_t;
list_t coap_get_observers(void); list_t coap_get_observers(void);
coap_observer_t *coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len); coap_observer_t *coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len, const char *url);
void coap_remove_observer(coap_observer_t *o); void coap_remove_observer(coap_observer_t *o);
int coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port); int coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port);
int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len); int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len);

View file

@ -191,7 +191,7 @@ coap_get_tid()
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void void
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length) coap_send_message(uip_ipaddr_t *addr, uint16_t port, const uint8_t *data, uint16_t length)
{ {
/*configure connection to reply to client*/ /*configure connection to reply to client*/
uip_ipaddr_copy(&udp_conn->ripaddr, addr); uip_ipaddr_copy(&udp_conn->ripaddr, addr);
@ -586,7 +586,7 @@ coap_get_header_etag(void *packet, const uint8_t **etag)
} }
int int
coap_set_header_etag(void *packet, uint8_t *etag, size_t etag_len) coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len)
{ {
((coap_packet_t *)packet)->etag_len = MIN(COAP_ETAG_LEN, etag_len); ((coap_packet_t *)packet)->etag_len = MIN(COAP_ETAG_LEN, etag_len);
memcpy(((coap_packet_t *)packet)->etag, etag, ((coap_packet_t *)packet)->etag_len); memcpy(((coap_packet_t *)packet)->etag, etag, ((coap_packet_t *)packet)->etag_len);
@ -605,9 +605,9 @@ coap_get_header_uri_host(void *packet, const char **host)
} }
int int
coap_set_header_uri_host(void *packet, char *host) coap_set_header_uri_host(void *packet, const char *host)
{ {
((coap_packet_t *)packet)->uri_host = (char *) host; ((coap_packet_t *)packet)->uri_host = host;
((coap_packet_t *)packet)->uri_host_len = strlen(host); ((coap_packet_t *)packet)->uri_host_len = strlen(host);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST); SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST);
@ -615,20 +615,20 @@ coap_set_header_uri_host(void *packet, char *host)
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
int int
coap_get_header_location(void *packet, const char **uri) coap_get_header_location(void *packet, const char **location)
{ {
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH)) return 0; if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH)) return 0;
*uri = ((coap_packet_t *)packet)->location_path; *location = ((coap_packet_t *)packet)->location_path;
return ((coap_packet_t *)packet)->location_path_len; return ((coap_packet_t *)packet)->location_path_len;
} }
int int
coap_set_header_location(void *packet, char *location) coap_set_header_location(void *packet, const char *location)
{ {
while (location[0]=='/') ++location; while (location[0]=='/') ++location;
((coap_packet_t *)packet)->location_path = (char *) location; ((coap_packet_t *)packet)->location_path = location;
((coap_packet_t *)packet)->location_path_len = strlen(location); ((coap_packet_t *)packet)->location_path_len = strlen(location);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH); SET_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH);
@ -645,11 +645,11 @@ coap_get_header_uri_path(void *packet, const char **path)
} }
int int
coap_set_header_uri_path(void *packet, char *path) coap_set_header_uri_path(void *packet, const char *path)
{ {
while (path[0]=='/') ++path; while (path[0]=='/') ++path;
((coap_packet_t *)packet)->uri_path = (char *) path; ((coap_packet_t *)packet)->uri_path = path;
((coap_packet_t *)packet)->uri_path_len = strlen(path); ((coap_packet_t *)packet)->uri_path_len = strlen(path);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PATH); SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PATH);
@ -683,7 +683,7 @@ coap_get_header_token(void *packet, const uint8_t **token)
} }
int int
coap_set_header_token(void *packet, uint8_t *token, size_t token_len) coap_set_header_token(void *packet, const uint8_t *token, size_t token_len)
{ {
((coap_packet_t *)packet)->token_len = MIN(COAP_TOKEN_LEN, token_len); ((coap_packet_t *)packet)->token_len = MIN(COAP_TOKEN_LEN, token_len);
memcpy(((coap_packet_t *)packet)->token, token, ((coap_packet_t *)packet)->token_len); memcpy(((coap_packet_t *)packet)->token, token, ((coap_packet_t *)packet)->token_len);
@ -731,7 +731,7 @@ coap_get_header_uri_query(void *packet, const char **query)
} }
int int
coap_set_header_uri_query(void *packet, char *query) coap_set_header_uri_query(void *packet, const char *query)
{ {
while (query[0]=='?') ++query; while (query[0]=='?') ++query;
@ -745,7 +745,7 @@ coap_set_header_uri_query(void *packet, char *query)
/*- PAYLOAD -------------------------------------------------------------------------*/ /*- PAYLOAD -------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
int int
coap_get_payload(void *packet, const uint8_t **payload) coap_get_payload(void *packet, uint8_t **payload)
{ {
if (((coap_packet_t *)packet)->payload) { if (((coap_packet_t *)packet)->payload) {
*payload = ((coap_packet_t *)packet)->payload; *payload = ((coap_packet_t *)packet)->payload;
@ -757,11 +757,11 @@ coap_get_payload(void *packet, const uint8_t **payload)
} }
int int
coap_set_payload(void *packet, uint8_t *payload, size_t length) coap_set_payload(void *packet, const void *payload, size_t length)
{ {
PRINTF("setting payload (%u/%u)\n", length, REST_MAX_CHUNK_SIZE); PRINTF("setting payload (%u/%u)\n", length, REST_MAX_CHUNK_SIZE);
((coap_packet_t *)packet)->payload = payload; ((coap_packet_t *)packet)->payload = (uint8_t *) payload;
((coap_packet_t *)packet)->payload_len = MIN(REST_MAX_CHUNK_SIZE, length); ((coap_packet_t *)packet)->payload_len = MIN(REST_MAX_CHUNK_SIZE, length);
return ((coap_packet_t *)packet)->payload_len; return ((coap_packet_t *)packet)->payload_len;

View file

@ -200,11 +200,11 @@ typedef struct {
uint8_t etag_len; uint8_t etag_len;
uint8_t etag[COAP_ETAG_LEN]; uint8_t etag[COAP_ETAG_LEN];
uint8_t uri_host_len; uint8_t uri_host_len;
char *uri_host; const char *uri_host;
uint8_t location_path_len; uint8_t location_path_len;
char *location_path; const char *location_path;
uint8_t uri_path_len; uint8_t uri_path_len;
char *uri_path; const char *uri_path;
uint32_t observe; /* 0-4 bytes for coap-03 */ uint32_t observe; /* 0-4 bytes for coap-03 */
uint8_t token_len; uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN]; uint8_t token[COAP_TOKEN_LEN];
@ -213,7 +213,7 @@ typedef struct {
uint16_t block_size; uint16_t block_size;
uint32_t block_offset; uint32_t block_offset;
uint8_t uri_query_len; uint8_t uri_query_len;
char *uri_query; const char *uri_query;
uint16_t payload_len; uint16_t payload_len;
uint8_t *payload; uint8_t *payload;
@ -226,7 +226,7 @@ typedef enum
NO_ERROR, NO_ERROR,
/* Memory errors */ /* Memory errors */
MEMORY_ALLOC_ERR, MEMORY_ALLOCATION_ERROR,
MEMORY_BOUNDARY_EXCEEDED, MEMORY_BOUNDARY_EXCEEDED,
/* CoAP errors */ /* CoAP errors */
@ -236,7 +236,7 @@ typedef enum
void coap_init_connection(uint16_t port); void coap_init_connection(uint16_t port);
uint16_t coap_get_tid(void); uint16_t coap_get_tid(void);
void coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length); void coap_send_message(uip_ipaddr_t *addr, uint16_t port, const uint8_t *data, uint16_t length);
void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t tid); void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t tid);
int coap_serialize_message(void *packet, uint8_t *buffer); int coap_serialize_message(void *packet, uint8_t *buffer);
@ -255,30 +255,30 @@ int coap_get_header_max_age(void *packet, uint32_t *age);
int coap_set_header_max_age(void *packet, uint32_t age); int coap_set_header_max_age(void *packet, uint32_t age);
int coap_get_header_etag(void *packet, const uint8_t **etag); int coap_get_header_etag(void *packet, const uint8_t **etag);
int coap_set_header_etag(void *packet, uint8_t *etag, size_t etag_len); int coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len);
int coap_get_header_uri_host(void *packet, const char **host); /*CAUTION in-place string might not be 0-terminated */ int coap_get_header_uri_host(void *packet, const char **host); /*CAUTION in-place string might not be 0-terminated */
int coap_set_header_uri_host(void *packet, char *host); int coap_set_header_uri_host(void *packet, const char *host);
int coap_get_header_location(void *packet, const char **uri); /*CAUTION in-place string might not be 0-terminated */ int coap_get_header_location(void *packet, const char **uri); /*CAUTION in-place string might not be 0-terminated */
int coap_set_header_location(void *packet, char *uri); int coap_set_header_location(void *packet, const char *uri);
int coap_get_header_uri_path(void *packet, const char **uri); /*CAUTION in-place string might not be 0-terminated */ int coap_get_header_uri_path(void *packet, const char **uri); /*CAUTION in-place string might not be 0-terminated */
int coap_set_header_uri_path(void *packet, char *uri); int coap_set_header_uri_path(void *packet, const char *uri);
int coap_get_header_observe(void *packet, uint32_t *observe); int coap_get_header_observe(void *packet, uint32_t *observe);
int coap_set_header_observe(void *packet, uint32_t observe); int coap_set_header_observe(void *packet, uint32_t observe);
int coap_get_header_token(void *packet, const uint8_t **token); int coap_get_header_token(void *packet, const uint8_t **token);
int coap_set_header_token(void *packet, uint8_t *token, size_t token_len); int coap_set_header_token(void *packet, const uint8_t *token, size_t token_len);
int coap_get_header_block(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset); int coap_get_header_block(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset);
int coap_set_header_block(void *packet, uint32_t num, uint8_t more, uint16_t size); int coap_set_header_block(void *packet, uint32_t num, uint8_t more, uint16_t size);
int coap_get_header_uri_query(void *packet, const char **query); /*CAUTION in-place string might not be 0-terminated */ int coap_get_header_uri_query(void *packet, const char **query); /*CAUTION in-place string might not be 0-terminated */
int coap_set_header_uri_query(void *packet, char *query); int coap_set_header_uri_query(void *packet, const char *query);
int coap_get_payload(void *packet, const uint8_t **payload); int coap_get_payload(void *packet, uint8_t **payload);
int coap_set_payload(void *packet, uint8_t *payload, size_t length); int coap_set_payload(void *packet, const void *payload, size_t length);
#endif /* COAP_03_H_ */ #endif /* COAP_03_H_ */

View file

@ -1 +0,0 @@
er-coap-06_src = er-coap-06-engine.c er-coap-06.c er-coap-06-transactions.c er-coap-06-observing.c er-coap-06-separate.c

View file

@ -1,561 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP implementation of the REST Engine
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "contiki.h"
#include "contiki-net.h"
#include "er-coap-06-engine.h"
#define DEBUG 0
#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])
#define PRINTBITS(buf,len) { \
int i,j=0; \
for (i=0; i<len; ++i) { \
for (j=7; j>=0; --j) { \
PRINTF("%c", (((char *)buf)[i] & 1<<j) ? '1' : '0'); \
} \
PRINTF(" "); \
} \
}
#else
#define PRINTF(...)
#define PRINT6ADDR(addr)
#define PRINTLLADDR(addr)
#define PRINTBITS(buf,len)
#endif
PROCESS(coap_receiver, "CoAP Receiver");
/*-----------------------------------------------------------------------------------*/
/*- Variables -----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
static service_callback_t service_cbk = NULL;
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
static
int
handle_incoming_data(void)
{
coap_error_code = NO_ERROR;
PRINTF("handle_incoming_data(): received uip_datalen=%u \n",(uint16_t)uip_datalen());
/* Static declaration reduces stack peaks and program code size. */
static coap_packet_t message[1]; /* This way the packet can be treated as pointer as usual. */
static coap_packet_t response[1];
static coap_transaction_t *transaction = NULL;
if (uip_newdata()) {
PRINTF("receiving UDP datagram from: ");
PRINT6ADDR(&UIP_IP_BUF->srcipaddr);
PRINTF(":%u\n Length: %u\n Data: ", uip_ntohs(UIP_UDP_BUF->srcport), uip_datalen() );
PRINTBITS(uip_appdata, uip_datalen());
PRINTF("\n");
coap_error_code = coap_parse_message(message, uip_appdata, uip_datalen());
if (coap_error_code==NO_ERROR)
{
/*TODO duplicates suppression, if required */
PRINTF(" Parsed: v %u, t %u, oc %u, c %u, tid %u\n", message->version, message->type, message->option_count, message->code, message->tid);
PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path);
PRINTF(" Payload: %.*s\n", message->payload_len, message->payload);
/* Handle requests. */
if (message->code >= COAP_GET && message->code <= COAP_DELETE)
{
/* Use transaction buffer for response to confirmable request. */
if ( (transaction = coap_new_transaction(message->tid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) )
{
static uint32_t block_num = 0;
static uint16_t block_size = REST_MAX_CHUNK_SIZE;
static uint32_t block_offset = 0;
static int32_t new_offset = 0;
/* prepare response */
if (message->type==COAP_TYPE_CON)
{
/* Reliable CON requests are answered with an ACK. */
coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->tid);
}
else
{
/* Unreliable NON requests are answered with a NON as well. */
coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_tid());
}
/* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */
if (IS_OPTION(message, COAP_OPTION_TOKEN))
{
coap_set_header_token(response, message->token, message->token_len);
SET_OPTION(response, COAP_OPTION_TOKEN);
}
/* get offset for blockwise transfers */
if (coap_get_header_block2(message, &block_num, NULL, &block_size, &block_offset))
{
PRINTF("Blockwise: block request %lu (%u/%u) @ %lu bytes\n", block_num, block_size, REST_MAX_CHUNK_SIZE, block_offset);
block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
new_offset = block_offset;
}
else
{
new_offset = 0;
}
/* Invoke resource handler. */
if (service_cbk)
{
/* Call REST framework and check if found and allowed. */
if (service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset))
{
/* Apply blockwise transfers. */
if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
{
/* unchanged new_offset indicates that resource is unaware of blockwise transfer */
if (new_offset==block_offset)
{
PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size);
if (block_offset >= response->payload_len)
{
PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n");
response->code = BAD_OPTION_4_02;
coap_set_payload(response, (uint8_t*)"Block out of scope", 18);
}
else
{
coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size);
coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size));
} /* if (valid offset) */
}
else
{
/* resource provides chunk-wise data */
PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset);
coap_set_header_block2(response, block_num, new_offset!=-1 || response->payload_len > block_size, block_size);
if (response->payload_len > block_size) coap_set_payload(response, response->payload, block_size);
} /* if (resource aware of blockwise) */
}
else if (new_offset!=0)
{
PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE);
coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
} /* if (blockwise request) */
}
}
else
{
coap_error_code = INTERNAL_SERVER_ERROR_5_00;
coap_error_message = "Service callback undefined";
} /* if (service callback) */
/* serialize Response. */
if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0)
{
coap_error_code = PACKET_SERIALIZATION_ERROR;
}
} else {
coap_error_code = MEMORY_ALLOC_ERR;
coap_error_message = "Transaction buffer allocation failed";
} /* if (transaction buffer) */
}
else
{
/* Responses */
if (message->type==COAP_TYPE_ACK)
{
PRINTF("Received ACK\n");
}
else if (message->type==COAP_TYPE_RST)
{
PRINTF("Received RST\n");
/* Cancel possible subscriptions. */
if (IS_OPTION(message, COAP_OPTION_TOKEN))
{
PRINTF(" Token 0x%02X%02X\n", message->token[0], message->token[1]);
coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->token, message->token_len);
}
}
if ( (transaction = coap_get_transaction_by_tid(message->tid)) )
{
/* Free transaction memory before callback, as it may create a new transaction. */
restful_response_handler callback = transaction->callback;
void *callback_data = transaction->callback_data;
coap_clear_transaction(transaction);
/* Check if someone registered for the response */
if (callback) {
callback(callback_data, message);
}
} /* if (ACKed transaction) */
transaction = NULL;
}
} /* if (parsed correctly) */
if (coap_error_code==NO_ERROR) {
if (transaction) coap_send_transaction(transaction);
}
else
{
PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message);
coap_clear_transaction(transaction);
/* Set to sendable error code. */
if (coap_error_code >= 192)
{
coap_error_code = INTERNAL_SERVER_ERROR_5_00;
}
/* Reuse input buffer for error message. */
coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->tid);
coap_set_payload(message, (uint8_t *) coap_error_message, strlen(coap_error_message));
coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata));
}
} /* if (new data) */
return coap_error_code;
}
/*-----------------------------------------------------------------------------------*/
void
coap_receiver_init()
{
process_start(&coap_receiver, NULL);
}
/*-----------------------------------------------------------------------------------*/
void
coap_set_service_callback(service_callback_t callback)
{
service_cbk = callback;
}
/*-----------------------------------------------------------------------------------*/
rest_resource_flags_t
coap_get_rest_method(void *packet)
{
return (rest_resource_flags_t)(1 << (((coap_packet_t *)packet)->code - 1));
}
/*-----------------------------------------------------------------------------------*/
int
coap_set_rest_status(void *packet, unsigned int code)
{
if (code <= 0xFF)
{
((coap_packet_t *)packet)->code = (uint8_t) code;
return 1;
}
else
{
return 0;
}
}
/*-----------------------------------------------------------------------------------*/
/*- Server part ---------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
/* The discover resource is automatically included for CoAP. */
RESOURCE(well_known_core, METHOD_GET, ".well-known/core", "");
void
well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{
/* Response might be NULL for non-confirmable requests. */
if (response)
{
size_t strpos = 0;
size_t bufpos = 0;
resource_t* resource = NULL;
for (resource = (resource_t*)list_head(rest_get_resources()); resource; resource = resource->next)
{
strpos += snprintf((char *) buffer + bufpos, REST_MAX_CHUNK_SIZE - bufpos + 1,
"</%s>%s%s%s",
resource->url,
resource->attributes[0] ? ";" : "",
resource->attributes,
resource->next ? "," : "" );
PRINTF("discover: %s\n", resource->url);
if (strpos <= *offset)
{
/* Discard output before current block */
PRINTF(" if %d <= %ld B\n", strpos, *offset);
PRINTF(" %s\n", buffer);
bufpos = 0;
}
else /* (strpos > *offset) */
{
/* output partly in block */
size_t len = MIN(strpos - *offset, preferred_size);
PRINTF(" el %d/%d @ %ld B\n", len, preferred_size, *offset);
/* Block might start in the middle of the output; align with buffer start. */
if (bufpos == 0)
{
memmove(buffer, buffer+strlen((char *)buffer)-strpos+*offset, len);
}
bufpos = len;
PRINTF(" %s\n", buffer);
if (bufpos >= preferred_size)
{
break;
}
}
}
if (bufpos>0) {
coap_set_payload(response, buffer, bufpos );
coap_set_header_content_type(response, APPLICATION_LINK_FORMAT);
}
else
{
PRINTF("well_known_core_handler(): bufpos<=0\n");
coap_set_rest_status(response, BAD_OPTION_4_02);
coap_set_payload(response, (uint8_t*)"Block out of scope", 18);
}
if (resource==NULL) {
*offset = -1;
}
else
{
*offset += bufpos;
}
}
}
/*-----------------------------------------------------------------------------------*/
PROCESS_THREAD(coap_receiver, ev, data)
{
PROCESS_BEGIN();
PRINTF("Starting CoAP-06 receiver...\n");
rest_activate_resource(&resource_well_known_core);
coap_register_as_transaction_handler();
coap_init_connection(SERVER_LISTEN_PORT);
while(1) {
PROCESS_YIELD();
if(ev == tcpip_event) {
handle_incoming_data();
} else if (ev == PROCESS_EVENT_TIMER) {
/* retransmissions are handled here */
coap_check_transactions();
}
} /* while (1) */
PROCESS_END();
}
/*-----------------------------------------------------------------------------------*/
/*- Client part ---------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
void blocking_request_callback(void *callback_data, void *response) {
struct request_state_t *state = (struct request_state_t *) callback_data;
state->response = (coap_packet_t*) response;
process_poll(state->process);
}
/*-----------------------------------------------------------------------------------*/
PT_THREAD(coap_blocking_request(struct request_state_t *state, process_event_t ev,
uip_ipaddr_t *remote_ipaddr, uint16_t remote_port,
coap_packet_t *request,
blocking_response_handler request_callback)) {
PT_BEGIN(&state->pt);
static uint8_t more;
static uint32_t res_block;
static uint8_t block_error;
state->block_num = 0;
state->response = NULL;
state->process = PROCESS_CURRENT();
more = 0;
res_block = 0;
block_error = 0;
do {
request->tid = coap_get_tid();
if ((state->transaction = coap_new_transaction(request->tid, remote_ipaddr, remote_port)))
{
state->transaction->callback = blocking_request_callback;
state->transaction->callback_data = state;
if (state->block_num>0)
{
coap_set_header_block2(request, state->block_num, 0, REST_MAX_CHUNK_SIZE);
}
state->transaction->packet_len = coap_serialize_message(request, state->transaction->packet);
coap_send_transaction(state->transaction);
PRINTF("Requested #%lu (TID %u)\n", state->block_num, request->tid);
PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL);
if (!state->response)
{
PRINTF("Server not responding\n");
PT_EXIT(&state->pt);
}
coap_get_header_block2(state->response, &res_block, &more, NULL, NULL);
PRINTF("Received #%lu%s (%u bytes)\n", res_block, more ? "+" : "", state->response->payload_len);
if (res_block==state->block_num)
{
request_callback(state->response);
++(state->block_num);
}
else
{
PRINTF("WRONG BLOCK %lu/%lu\n", res_block, state->block_num);
++block_error;
}
}
else
{
PRINTF("Could not allocate transaction buffer");
PT_EXIT(&state->pt);
}
} while (more && block_error<COAP_MAX_ATTEMPTS);
PT_END(&state->pt);
}
/*-----------------------------------------------------------------------------------*/
/*- Engine Interface ----------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
const struct rest_implementation coap_rest_implementation = {
"CoAP-06",
coap_receiver_init,
coap_set_service_callback,
coap_get_header_uri_path,
coap_set_header_uri_path,
coap_get_rest_method,
coap_set_rest_status,
coap_get_header_content_type,
coap_set_header_content_type,
NULL,
coap_get_header_max_age,
coap_set_header_max_age,
coap_set_header_etag,
NULL,
NULL,
coap_get_header_uri_host,
coap_set_header_location_path,
coap_get_payload,
coap_set_payload,
coap_get_header_uri_query,
coap_get_query_variable,
coap_get_post_variable,
coap_notify_observers,
(restful_post_handler) coap_observe_handler,
NULL, /* default pre-handler (set separate handler after activation if needed) */
NULL, /* default post-handler for non-observable resources */
{
CONTENT_2_05,
CREATED_2_01,
CHANGED_2_04,
DELETED_2_02,
VALID_2_03,
BAD_REQUEST_4_00,
UNAUTHORIZED_4_01,
BAD_OPTION_4_02,
FORBIDDEN_4_03,
NOT_FOUND_4_04,
METHOD_NOT_ALLOWED_4_05,
REQUEST_ENTITY_TOO_LARGE_4_13,
UNSUPPORTED_MADIA_TYPE_4_15,
INTERNAL_SERVER_ERROR_5_00,
NOT_IMPLEMENTED_5_01,
BAD_GATEWAY_5_02,
SERVICE_UNAVAILABLE_5_03,
GATEWAY_TIMEOUT_5_04,
PROXYING_NOT_SUPPORTED_5_05
},
{
TEXT_PLAIN,
TEXT_XML,
TEXT_CSV,
TEXT_HTML,
IMAGE_GIF,
IMAGE_JPEG,
IMAGE_PNG,
IMAGE_TIFF,
AUDIO_RAW,
VIDEO_RAW,
APPLICATION_LINK_FORMAT,
APPLICATION_XML,
APPLICATION_OCTET_STREAM,
APPLICATION_RDF_XML,
APPLICATION_SOAP_XML,
APPLICATION_ATOM_XML,
APPLICATION_XMPP_XML,
APPLICATION_EXI,
APPLICATION_FASTINFOSET,
APPLICATION_SOAP_FASTINFOSET,
APPLICATION_JSON,
APPLICATION_X_OBIX_BINARY
}
};

View file

@ -1,92 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP implementation of the REST Engine
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#ifndef COAP_SERVER_H_
#define COAP_SERVER_H_
#if !defined(REST)
#error "Define REST to \"coap_rest_implementation\""
#endif
#include "er-coap-06.h"
#include "er-coap-06-transactions.h"
#include "er-coap-06-observing.h"
#include "er-coap-06-separate.h"
#include "pt.h"
/* Declare server process */
PROCESS_NAME(coap_receiver);
#define SERVER_LISTEN_PORT UIP_HTONS(COAP_SERVER_PORT)
typedef coap_packet_t rest_request_t;
typedef coap_packet_t rest_response_t;
extern const struct rest_implementation coap_rest_implementation;
void coap_receiver_init(void);
/*-----------------------------------------------------------------------------------*/
/*- Client part ---------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
struct request_state_t {
struct pt pt;
struct process *process;
coap_transaction_t *transaction;
coap_packet_t *response;
uint32_t block_num;
};
typedef void (*blocking_response_handler) (void* response);
PT_THREAD(coap_blocking_request(struct request_state_t *state, process_event_t ev,
uip_ipaddr_t *remote_ipaddr, uint16_t remote_port,
coap_packet_t *request,
blocking_response_handler request_callback));
#define COAP_BLOCKING_REQUEST(server_addr, server_port, request, chunk_handler) \
static struct request_state_t request_state; \
PT_SPAWN(process_pt, &request_state.pt, \
coap_blocking_request(&request_state, ev, \
server_addr, server_port, \
request, chunk_handler) \
);
/*-----------------------------------------------------------------------------------*/
#endif /* COAP_SERVER_H_ */

View file

@ -1,201 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP module for observing resources
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#include <stdio.h>
#include <string.h>
#include "er-coap-06-observing.h"
#define DEBUG 0
#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
MEMB(observers_memb, coap_observer_t, COAP_MAX_OBSERVERS);
LIST(observers_list);
/*-----------------------------------------------------------------------------------*/
coap_observer_t *
coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len)
{
coap_observer_t *o = memb_alloc(&observers_memb);
if (o)
{
o->url = url;
uip_ipaddr_copy(&o->addr, addr);
o->port = port;
o->token_len = token_len;
memcpy(o->token, token, token_len);
stimer_set(&o->refresh_timer, COAP_OBSERVING_REFRESH_INTERVAL);
PRINTF("Adding observer for /%s [0x%02X%02X]\n", o->url, o->token[0], o->token[1]);
list_add(observers_list, o);
}
return o;
}
/*-----------------------------------------------------------------------------------*/
void
coap_remove_observer(coap_observer_t *o)
{
PRINTF("Removing observer for /%s [0x%02X%02X]\n", o->url, o->token[0], o->token[1]);
memb_free(&observers_memb, o);
list_remove(observers_list, o);
}
int
coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port)
{
int removed = 0;
coap_observer_t* obs = NULL;
for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next)
{
PRINTF("Remove check client ");
PRINT6ADDR(addr);
PRINTF(":%u\n", port);
if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port)
{
coap_remove_observer(obs);
removed++;
}
}
return removed;
}
int
coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len)
{
int removed = 0;
coap_observer_t* obs = NULL;
for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next)
{
PRINTF("Remove check Token 0x%02X%02X\n", token[0], token[1]);
if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port && memcmp(obs->token, token, token_len)==0)
{
coap_remove_observer(obs);
removed++;
}
}
return removed;
}
/*-----------------------------------------------------------------------------------*/
void
coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len)
{
coap_observer_t* obs = NULL;
for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next)
{
if (obs->url==url) /* using RESOURCE url pointer as handle */
{
coap_transaction_t *transaction = NULL;
/*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */
if ( (transaction = coap_new_transaction(coap_get_tid(), &obs->addr, obs->port)) )
{
/* Use CON to check whether client is still there/interested after COAP_OBSERVING_REFRESH_INTERVAL. */
if (stimer_expired(&obs->refresh_timer))
{
PRINTF("Observing: Refresh client with CON\n");
type = COAP_TYPE_CON;
stimer_restart(&obs->refresh_timer);
}
/* prepare response */
coap_packet_t push[1]; /* This way the packet can be treated as pointer as usual. */
coap_init_message(push, (coap_message_type_t)type, CONTENT_2_05, transaction->tid );
coap_set_header_observe(push, observe);
coap_set_header_token(push, obs->token, obs->token_len);
coap_set_payload(push, payload, payload_len);
transaction->packet_len = coap_serialize_message(push, transaction->packet);
PRINTF("Observing: Notify from /%s for ", url);
PRINT6ADDR(&obs->addr);
PRINTF(":%u\n", obs->port);
PRINTF(" %.*s\n", payload_len, payload);
coap_send_transaction(transaction);
}
}
}
}
/*-----------------------------------------------------------------------------------*/
void
coap_observe_handler(resource_t *resource, void *request, void *response)
{
static char content[26];
if (response && ((coap_packet_t *)response)->code<128) /* response without error code */
{
if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_OBSERVE))
{
if (!IS_OPTION((coap_packet_t *)request, COAP_OPTION_TOKEN))
{
/* Set default token. */
coap_set_header_token(request, (uint8_t *)"", 1);
}
if (coap_add_observer(resource->url, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, ((coap_packet_t *)request)->token, ((coap_packet_t *)request)->token_len))
{
coap_set_header_observe(response, 0);
coap_set_payload(response, (uint8_t *)content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS));
}
else
{
((coap_packet_t *)response)->code = SERVICE_UNAVAILABLE_5_03;
coap_set_payload(response, (uint8_t *)"Too many observers", 18);
} /* if (added observer) */
}
else /* if (observe) */
{
/* Remove client if it is currently observing. */
coap_remove_observer_by_client(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport);
} /* if (observe) */
}
}

View file

@ -1,76 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP module for observing resources
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#ifndef COAP_OBSERVING_H_
#define COAP_OBSERVING_H_
#include "er-coap-06.h"
#include "er-coap-06-transactions.h"
#ifndef COAP_MAX_OBSERVERS
#define COAP_MAX_OBSERVERS 4
#endif /* COAP_MAX_OBSERVERS */
/* Interval in seconds in which NON notifies are changed to CON notifies to check client. */
#define COAP_OBSERVING_REFRESH_INTERVAL 60
#if COAP_MAX_OPEN_TRANSACTIONS<COAP_MAX_OBSERVERS
#warning "COAP_MAX_OPEN_TRANSACTIONS smaller than COAP_MAX_OBSERVERS: cannot handle CON notifications"
#endif
typedef struct coap_observer {
struct coap_observer *next; /* for LIST */
const char *url;
uip_ipaddr_t addr;
uint16_t port;
uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN];
struct stimer refresh_timer;
} coap_observer_t;
list_t coap_get_observers(void);
coap_observer_t *coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len);
void coap_remove_observer(coap_observer_t *o);
int coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port);
int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len);
void coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len);
void coap_observe_handler(resource_t *resource, void *request, void *response);
#endif /* COAP_OBSERVING_H_ */

View file

@ -1,72 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP module for separate responses
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#include <stdio.h>
#include <string.h>
#include "er-coap-06-separate.h"
#define DEBUG 0
#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
/*-----------------------------------------------------------------------------------*/
void coap_separate_handler(resource_t *resource, void *request, void *response)
{
if (resource->benchmark > COAP_SEPARATE_THRESHOLD)
{
PRINTF("Separate response for /%s \n", resource->url);
/* send separate ACK. */
coap_packet_t ack[1];
/* ACK with empty code (0) */
coap_init_message(ack, COAP_TYPE_ACK, 0, ((coap_packet_t *)request)->tid);
/* Should only overwrite Header which is already parsed to request. */
coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, (uip_appdata + uip_ext_len), coap_serialize_message(ack, (uip_appdata + uip_ext_len)));
/* Change response to separate response. */
((coap_packet_t *)response)->type = COAP_TYPE_CON;
((coap_packet_t *)response)->tid = coap_get_tid();
}
}

View file

@ -1,50 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP module for separate responses
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#ifndef COAP_SEPARATE_H_
#define COAP_SEPARATE_H_
#include "er-coap-06.h"
#ifndef COAP_SEPARATE_THRESHOLD
#define COAP_SEPARATE_THRESHOLD 42
#endif
void coap_separate_handler(resource_t *resource, void *request, void *response);
#endif /* COAP_SEPARATE_H_ */

View file

@ -1,194 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP module for reliable transport
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#include "contiki.h"
#include "contiki-net.h"
#include "er-coap-06-transactions.h"
/*
* Modulo mask (+1 and +0.5 for rounding) for a random number to get the tick number for the random
* retransmission time between COAP_RESPONSE_TIMEOUT and COAP_RESPONSE_TIMEOUT*COAP_RESPONSE_RANDOM_FACTOR.
*/
#define COAP_RESPONSE_TIMEOUT_TICKS (CLOCK_SECOND * COAP_RESPONSE_TIMEOUT)
#define COAP_RESPONSE_TIMEOUT_BACKOFF_MASK ((CLOCK_SECOND * COAP_RESPONSE_TIMEOUT * (COAP_RESPONSE_RANDOM_FACTOR - 1)) + 1.5)
#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
MEMB(transactions_memb, coap_transaction_t, COAP_MAX_OPEN_TRANSACTIONS);
LIST(transactions_list);
static struct process *transaction_handler_process = NULL;
void
coap_register_as_transaction_handler()
{
transaction_handler_process = PROCESS_CURRENT();
}
coap_transaction_t *
coap_new_transaction(uint16_t tid, uip_ipaddr_t *addr, uint16_t port)
{
coap_transaction_t *t = memb_alloc(&transactions_memb);
if (t)
{
t->tid = tid;
t->retrans_counter = 0;
/* save client address */
uip_ipaddr_copy(&t->addr, addr);
t->port = port;
}
return t;
}
void
coap_send_transaction(coap_transaction_t *t)
{
PRINTF("Sending transaction %u\n", t->tid);
coap_send_message(&t->addr, t->port, t->packet, t->packet_len);
if (COAP_TYPE_CON==((COAP_HEADER_TYPE_MASK & t->packet[0])>>COAP_HEADER_TYPE_POSITION))
{
if (t->retrans_counter<COAP_MAX_RETRANSMIT)
{
PRINTF("Keeping transaction %u\n", t->tid);
if (t->retrans_counter==0)
{
t->retrans_timer.timer.interval = COAP_RESPONSE_TIMEOUT_TICKS + (random_rand() % (clock_time_t) COAP_RESPONSE_TIMEOUT_BACKOFF_MASK);
PRINTF("Initial interval %f\n", (float)t->retrans_timer.timer.interval/CLOCK_SECOND);
}
else
{
t->retrans_timer.timer.interval <<= 1; /* double */
PRINTF("Doubled (%u) interval %f\n", t->retrans_counter, (float)t->retrans_timer.timer.interval/CLOCK_SECOND);
}
/*FIXME hack, maybe there is a better way, but avoid posting everything to the process */
struct process *process_actual = PROCESS_CURRENT();
process_current = transaction_handler_process;
etimer_restart(&t->retrans_timer); /* interval updated above */
process_current = process_actual;
list_add(transactions_list, t); /* List itself makes sure same element is not added twice. */
t = NULL;
}
else
{
/* timeout */
PRINTF("Timeout\n");
restful_response_handler callback = t->callback;
void *callback_data = t->callback_data;
/* handle observers */
coap_remove_observer_by_client(&t->addr, t->port);
coap_clear_transaction(t);
if (callback) {
callback(callback_data, NULL);
}
}
}
else
{
coap_clear_transaction(t);
}
}
void
coap_clear_transaction(coap_transaction_t *t)
{
if (t)
{
PRINTF("Freeing transaction %u: %p\n", t->tid, t);
etimer_stop(&t->retrans_timer);
list_remove(transactions_list, t);
memb_free(&transactions_memb, t);
}
}
coap_transaction_t *
coap_get_transaction_by_tid(uint16_t tid)
{
coap_transaction_t *t = NULL;
for (t = (coap_transaction_t*)list_head(transactions_list); t; t = t->next)
{
if (t->tid==tid)
{
PRINTF("Found transaction for TID %u: %p\n", t->tid, t);
return t;
}
}
return NULL;
}
void
coap_check_transactions()
{
coap_transaction_t *t = NULL;
for (t = (coap_transaction_t*)list_head(transactions_list); t; t = t->next)
{
if (etimer_expired(&t->retrans_timer))
{
++(t->retrans_counter);
PRINTF("Retransmitting %u (%u)\n", t->tid, t->retrans_counter);
coap_send_transaction(t);
}
}
}

View file

@ -1,79 +0,0 @@
/*
* Copyright (c) 2011, 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
* CoAP module for reliable transport
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#ifndef COAP_TRANSACTIONS_H_
#define COAP_TRANSACTIONS_H_
#include "er-coap-06.h"
#include "er-coap-06-observing.h"
/*
* The number of concurrent messages that can be stored for retransmission in the transaction layer.
*/
#ifndef COAP_MAX_OPEN_TRANSACTIONS
#define COAP_MAX_OPEN_TRANSACTIONS 4
#endif /* COAP_MAX_OPEN_TRANSACTIONS */
/* container for transactions with message buffer and retransmission info */
typedef struct coap_transaction {
struct coap_transaction *next; /* for LIST */
uint16_t tid;
struct etimer retrans_timer;
uint8_t retrans_counter;
uip_ipaddr_t addr;
uint16_t port;
restful_response_handler callback;
void *callback_data;
uint16_t packet_len;
uint8_t packet[COAP_MAX_PACKET_SIZE+1]; /* +1 for the terminating '\0' to simply and savely use snprintf(buf, len+1, "", ...) in the resource handler. */
} coap_transaction_t;
void coap_register_as_transaction_handler();
coap_transaction_t *coap_new_transaction(uint16_t tid, uip_ipaddr_t *addr, uint16_t port);
void coap_send_transaction(coap_transaction_t *t);
void coap_clear_transaction(coap_transaction_t *t);
coap_transaction_t *coap_get_transaction_by_tid(uint16_t tid);
void coap_check_transactions();
#endif /* COAP_TRANSACTIONS_H_ */

View file

@ -1,986 +0,0 @@
/*
* Copyright (c) 2011, 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
* An implementation of the Constrained Application Protocol (draft 06)
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#include "contiki.h"
#include "contiki-net.h"
#include <string.h>
#include <stdio.h>
#include "er-coap-06.h"
#include "er-coap-06-transactions.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
/*-----------------------------------------------------------------------------------*/
/*- Variables -----------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
static struct uip_udp_conn *udp_conn = NULL;
static uint16_t current_tid = 0;
coap_status_t coap_error_code = NO_ERROR;
char *coap_error_message = "";
/*-----------------------------------------------------------------------------------*/
/*- LOCAL HELP FUNCTIONS ------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
static
uint16_t
log_2(uint16_t value)
{
uint16_t result = 0;
do {
value = value >> 1;
result++;
} while (value);
return result ? result - 1 : result;
}
/*-----------------------------------------------------------------------------------*/
static
uint32_t
parse_int_option(uint8_t *bytes, uint16_t length)
{
uint32_t var = 0;
int i = 0;
while (i<length)
{
var <<= 8;
var |= 0xFF & bytes[i++];
}
return var;
}
static
size_t
set_option_header(int delta, size_t length, uint8_t *buffer)
{
if (length<15)
{
buffer[0] = (0x0F & length) | (0xF0 & delta<<4);
return 1;
}
else
{
buffer[0] = 0x0F | (0xF0 & delta<<4);
buffer[1] = 0xFF & (length - 15);
return 2;
}
}
/*-----------------------------------------------------------------------------------*/
static
size_t
insert_option_fence_posts(int number, int *current_number, uint8_t *buffer)
{
size_t i = 0;
while (number-*current_number > 15)
{
uint8_t delta = COAP_OPTION_FENCE_POST - (*current_number%COAP_OPTION_FENCE_POST);
set_option_header(delta, 0, &buffer[i++]);
*current_number += delta;
PRINTF("OPTION FENCE POST delta %u\n", delta);
}
return i;
}
/*-----------------------------------------------------------------------------------*/
static
size_t
serialize_int_option(int number, int current_number, uint8_t *buffer, uint32_t value)
{
/* Insert fence-posts for large deltas */
size_t i = insert_option_fence_posts(number, &current_number, buffer);
size_t start_i = i;
uint8_t *option = &buffer[i];
if (0xFF000000 & value) buffer[++i] = (uint8_t) (0xFF & value>>24);
if (0xFFFF0000 & value) buffer[++i] = (uint8_t) (0xFF & value>>16);
if (0xFFFFFF00 & value) buffer[++i] = (uint8_t) (0xFF & value>>8);
if ( value) buffer[++i] = (uint8_t) (0xFF & value);
i += set_option_header(number - current_number, i-start_i, option);
PRINTF("OPTION type %u, delta %u, len %u\n", number, number - current_number, i-start_i);
return i;
}
/*-----------------------------------------------------------------------------------*/
static
size_t
serialize_array_option(int number, int current_number, uint8_t *buffer, uint8_t *array, size_t length, uint8_t *split_option)
{
/* Insert fence-posts for large deltas */
size_t i = insert_option_fence_posts(number, &current_number, buffer);
if (split_option!=NULL)
{
int j;
uint8_t *part_start = array;
uint8_t *part_end = NULL;
size_t temp_length;
char split_char = *split_option;
*split_option = 0; /* Ensure reflecting the created option count */
for (j = 0; j<=length; ++j)
{
if (array[j]==split_char || j==length)
{
part_end = array + j;
temp_length = part_end-part_start;
i += set_option_header(number - current_number, temp_length, &buffer[i]);
memcpy(&buffer[i], part_start, temp_length);
i += temp_length;
PRINTF("OPTION type %u, delta %u, len %u, part [%.*s]\n", number, number - current_number, i, temp_length, part_start);
++(*split_option);
++j; /* skip the slash */
current_number = number;
while( array[j]=='/') ++j;
part_start = array + j;
}
} /* for */
}
else
{
i += set_option_header(number - current_number, length, &buffer[i]);
memcpy(&buffer[i], array, length);
i += length;
PRINTF("OPTION type %u, delta %u, len %u\n", number, number - current_number, i);
}
return i;
}
/*-----------------------------------------------------------------------------------*/
static
void
coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option, size_t option_len, char separator)
{
/* Merge multiple options. */
if (*dst_len > 0)
{
(*dst)[*dst_len] = separator;
*dst_len += 1;
/* memmove handles 2-byte option headers */
memmove((*dst)+(*dst_len), option, option_len);
*dst_len += option_len;
}
else
{
*dst = (char *) option; /* thus pointer pointer */
*dst_len = option_len;
}
}
/*-----------------------------------------------------------------------------------*/
static
int
coap_get_variable(const char *buffer, size_t length, const char *name, const char **output)
{
const char *start = NULL;
const char *end = NULL;
const char *value_end = NULL;
size_t name_len = 0;
/*initialize the output buffer first*/
*output = 0;
name_len = strlen(name);
end = buffer + length;
for (start = buffer; start + name_len < end; ++start){
if ((start == buffer || start[-1] == '&') && start[name_len] == '=' &&
strncmp(name, start, name_len)==0) {
/* Point start to variable value */
start += name_len + 1;
/* Point end to the end of the value */
value_end = (const char *) memchr(start, '&', end - start);
if (value_end == NULL) {
value_end = end;
}
*output = start;
return (value_end - start);
}
}
return 0;
}
/*-----------------------------------------------------------------------------------*/
/*- MEASSAGE SENDING ----------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
void
coap_init_connection(uint16_t port)
{
/* new connection with remote host */
udp_conn = udp_new(NULL, 0, NULL);
udp_bind(udp_conn, port);
PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport));
/* Initialize transaction ID. */
current_tid = random_rand();
}
/*-----------------------------------------------------------------------------------*/
uint16_t
coap_get_tid()
{
return ++current_tid;
}
/*-----------------------------------------------------------------------------------*/
/*- MEASSAGE PROCESSING -------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
void
coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t tid)
{
/* Important thing */
memset(packet, 0, sizeof(coap_packet_t));
((coap_packet_t *)packet)->type = type;
((coap_packet_t *)packet)->code = code;
((coap_packet_t *)packet)->tid = tid;
}
/*-----------------------------------------------------------------------------------*/
size_t
coap_serialize_message(void *packet, uint8_t *buffer)
{
/* Initialize */
((coap_packet_t *)packet)->buffer = buffer;
((coap_packet_t *)packet)->version = 1;
((coap_packet_t *)packet)->option_count = 0;
/* serialize options */
uint8_t *option = ((coap_packet_t *)packet)->buffer + COAP_HEADER_LEN;
int current_number = 0;
PRINTF("-Serializing options-\n");
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_CONTENT_TYPE)) {
PRINTF("Content-Type [%u]\n", ((coap_packet_t *)packet)->content_type);
option += serialize_int_option(COAP_OPTION_CONTENT_TYPE, current_number, option, ((coap_packet_t *)packet)->content_type);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_CONTENT_TYPE;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_MAX_AGE)) {
PRINTF("Max-Age [%lu]\n", ((coap_packet_t *)packet)->max_age);
option += serialize_int_option(COAP_OPTION_MAX_AGE, current_number, option, ((coap_packet_t *)packet)->max_age);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_MAX_AGE;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_PROXY_URI)) {
PRINTF("Proxy-Uri [%.*s]\n", ((coap_packet_t *)packet)->proxy_uri_len, ((coap_packet_t *)packet)->proxy_uri);
int length = ((coap_packet_t *)packet)->proxy_uri_len;
int j = 0;
while (length>0)
{
option += serialize_array_option(COAP_OPTION_PROXY_URI, current_number, option, (uint8_t *) ((coap_packet_t *)packet)->proxy_uri + j*270, MIN(270, length), NULL);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_PROXY_URI;
++j;
length -= 270;
}
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_ETAG)) {
PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", ((coap_packet_t *)packet)->etag_len,
((coap_packet_t *)packet)->etag[0],
((coap_packet_t *)packet)->etag[1],
((coap_packet_t *)packet)->etag[2],
((coap_packet_t *)packet)->etag[3],
((coap_packet_t *)packet)->etag[4],
((coap_packet_t *)packet)->etag[5],
((coap_packet_t *)packet)->etag[6],
((coap_packet_t *)packet)->etag[7]
); /*FIXME always prints 8 bytes */
option += serialize_array_option(COAP_OPTION_ETAG, current_number, option, ((coap_packet_t *)packet)->etag, ((coap_packet_t *)packet)->etag_len, NULL);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_ETAG;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST)) {
PRINTF("Uri-Host [%.*s]\n", ((coap_packet_t *)packet)->uri_host_len, ((coap_packet_t *)packet)->uri_host);
option += serialize_array_option(COAP_OPTION_URI_HOST, current_number, option, (uint8_t *) ((coap_packet_t *)packet)->uri_host, ((coap_packet_t *)packet)->uri_host_len, NULL);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_URI_HOST;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH)) {
PRINTF("Location [%.*s]\n", ((coap_packet_t *)packet)->location_path_len, ((coap_packet_t *)packet)->location_path);
uint8_t split_options = '/';
option += serialize_array_option(COAP_OPTION_LOCATION_PATH, current_number, option, (uint8_t *) ((coap_packet_t *)packet)->location_path, ((coap_packet_t *)packet)->location_path_len, &split_options);
((coap_packet_t *)packet)->option_count += split_options;
current_number = COAP_OPTION_LOCATION_PATH;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PORT)) {
PRINTF("Uri-Port [%u]\n", ((coap_packet_t *)packet)->uri_port);
option += serialize_int_option(COAP_OPTION_URI_PORT, current_number, option, ((coap_packet_t *)packet)->uri_port);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_URI_PORT;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_QUERY)) {
PRINTF("Location-Query [%.*s]\n", ((coap_packet_t *)packet)->location_query_len, ((coap_packet_t *)packet)->location_query);
uint8_t split_options = '&';
option += serialize_array_option(COAP_OPTION_LOCATION_QUERY, current_number, option, (uint8_t *) ((coap_packet_t *)packet)->location_query, ((coap_packet_t *)packet)->location_query_len, &split_options);
((coap_packet_t *)packet)->option_count += split_options;
current_number = COAP_OPTION_LOCATION_QUERY;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PATH)) {
PRINTF("Uri-Path [%.*s]\n", ((coap_packet_t *)packet)->uri_path_len, ((coap_packet_t *)packet)->uri_path);
uint8_t split_options = '/';
option += serialize_array_option(COAP_OPTION_URI_PATH, current_number, option, (uint8_t *) ((coap_packet_t *)packet)->uri_path, ((coap_packet_t *)packet)->uri_path_len, &split_options);
((coap_packet_t *)packet)->option_count += split_options;
current_number = COAP_OPTION_URI_PATH;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_OBSERVE)) {
PRINTF("Observe [%u]\n", ((coap_packet_t *)packet)->observe);
option += serialize_int_option(COAP_OPTION_OBSERVE, current_number, option, ((coap_packet_t *)packet)->observe);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_OBSERVE;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_TOKEN)) {
PRINTF("Token %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", ((coap_packet_t *)packet)->token_len,
((coap_packet_t *)packet)->token[0],
((coap_packet_t *)packet)->token[1],
((coap_packet_t *)packet)->token[2],
((coap_packet_t *)packet)->token[3],
((coap_packet_t *)packet)->token[4],
((coap_packet_t *)packet)->token[5],
((coap_packet_t *)packet)->token[6],
((coap_packet_t *)packet)->token[7]
); /*FIXME always prints 8 bytes */
option += serialize_array_option(COAP_OPTION_TOKEN, current_number, option, ((coap_packet_t *)packet)->token, ((coap_packet_t *)packet)->token_len, NULL);
((coap_packet_t *)packet)->option_count += 1;
current_number = COAP_OPTION_TOKEN;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_QUERY)) {
PRINTF("Uri-Query [%.*s]\n", ((coap_packet_t *)packet)->uri_query_len, ((coap_packet_t *)packet)->uri_query);
uint8_t split_options = '&';
option += serialize_array_option(COAP_OPTION_URI_QUERY, current_number, option, (uint8_t *) ((coap_packet_t *)packet)->uri_query, ((coap_packet_t *)packet)->uri_query_len, &split_options);
((coap_packet_t *)packet)->option_count += split_options + (COAP_OPTION_URI_QUERY-current_number)/COAP_OPTION_FENCE_POST;
current_number = COAP_OPTION_URI_QUERY;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK2))
{
PRINTF("Block2 [%lu%s (%u B/blk)]\n", ((coap_packet_t *)packet)->block2_num, ((coap_packet_t *)packet)->block2_more ? "+" : "", ((coap_packet_t *)packet)->block2_size);
uint32_t block = ((coap_packet_t *)packet)->block2_num << 4;
if (((coap_packet_t *)packet)->block2_more) block |= 0x8;
block |= 0xF & log_2(((coap_packet_t *)packet)->block2_size/16);
PRINTF("Block2 encoded: 0x%lX\n", block);
option += serialize_int_option(COAP_OPTION_BLOCK2, current_number, option, block);
((coap_packet_t *)packet)->option_count += 1 + (COAP_OPTION_BLOCK2-current_number)/COAP_OPTION_FENCE_POST;
current_number = COAP_OPTION_BLOCK2;
}
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK1))
{
PRINTF("Block1 [%lu%s (%u B/blk)]\n", ((coap_packet_t *)packet)->block1_num, ((coap_packet_t *)packet)->block1_more ? "+" : "", ((coap_packet_t *)packet)->block1_size);
uint32_t block = ((coap_packet_t *)packet)->block1_num << 4;
if (((coap_packet_t *)packet)->block1_more) block |= 0x8;
block |= 0xF & log_2(((coap_packet_t *)packet)->block1_size/16);
PRINTF("Block1 encoded: 0x%lX\n", block);
option += serialize_int_option(COAP_OPTION_BLOCK1, current_number, option, block);
((coap_packet_t *)packet)->option_count += 1 + (COAP_OPTION_BLOCK1-current_number)/COAP_OPTION_FENCE_POST;
current_number = COAP_OPTION_BLOCK1;
}
/* pack payload */
if ((option - ((coap_packet_t *)packet)->buffer)<=COAP_MAX_HEADER_SIZE)
{
memmove(option, ((coap_packet_t *)packet)->payload, ((coap_packet_t *)packet)->payload_len);
}
else
{
/* An error occured. Caller must check for !=0. */
((coap_packet_t *)packet)->buffer = NULL;
coap_error_message = "Serialized header exceeds COAP_MAX_HEADER_SIZE";
return 0;
}
/* set header fields */
((coap_packet_t *)packet)->buffer[0] = 0x00;
((coap_packet_t *)packet)->buffer[0] |= COAP_HEADER_VERSION_MASK & (((coap_packet_t *)packet)->version)<<COAP_HEADER_VERSION_POSITION;
((coap_packet_t *)packet)->buffer[0] |= COAP_HEADER_TYPE_MASK & (((coap_packet_t *)packet)->type)<<COAP_HEADER_TYPE_POSITION;
((coap_packet_t *)packet)->buffer[0] |= COAP_HEADER_OPTION_COUNT_MASK & (((coap_packet_t *)packet)->option_count)<<COAP_HEADER_OPTION_COUNT_POSITION;
((coap_packet_t *)packet)->buffer[1] = ((coap_packet_t *)packet)->code;
((coap_packet_t *)packet)->buffer[2] = 0xFF & (((coap_packet_t *)packet)->tid)>>8;
((coap_packet_t *)packet)->buffer[3] = 0xFF & ((coap_packet_t *)packet)->tid;
PRINTF("-Done %u options, header len %u, payload len %u-\n", ((coap_packet_t *)packet)->option_count, option - buffer, ((coap_packet_t *)packet)->payload_len);
return (option - buffer) + ((coap_packet_t *)packet)->payload_len; /* packet length */
}
/*-----------------------------------------------------------------------------------*/
void
coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length)
{
/*configure connection to reply to client*/
uip_ipaddr_copy(&udp_conn->ripaddr, addr);
udp_conn->rport = port;
uip_udp_packet_send(udp_conn, data, length);
PRINTF("-sent UDP datagram (%u)-\n", length);
/* Restore server connection to allow data from any node */
memset(&udp_conn->ripaddr, 0, sizeof(udp_conn->ripaddr));
udp_conn->rport = 0;
}
/*-----------------------------------------------------------------------------------*/
coap_status_t
coap_parse_message(void *packet, uint8_t *data, uint16_t data_len)
{
/* Initialize packet */
memset(packet, 0, sizeof(coap_packet_t));
/* pointer to packet bytes */
((coap_packet_t *)packet)->buffer = data;
/* parse header fields */
((coap_packet_t *)packet)->version = (COAP_HEADER_VERSION_MASK & ((coap_packet_t *)packet)->buffer[0])>>COAP_HEADER_VERSION_POSITION;
((coap_packet_t *)packet)->type = (COAP_HEADER_TYPE_MASK & ((coap_packet_t *)packet)->buffer[0])>>COAP_HEADER_TYPE_POSITION;
((coap_packet_t *)packet)->option_count = (COAP_HEADER_OPTION_COUNT_MASK & ((coap_packet_t *)packet)->buffer[0])>>COAP_HEADER_OPTION_COUNT_POSITION;
((coap_packet_t *)packet)->code = ((coap_packet_t *)packet)->buffer[1];
((coap_packet_t *)packet)->tid = ((coap_packet_t *)packet)->buffer[2]<<8 | ((coap_packet_t *)packet)->buffer[3];
if (((coap_packet_t *)packet)->version != 1)
{
coap_error_message = "CoAP version must be 1";
return BAD_REQUEST_4_00;
}
/* parse options */
((coap_packet_t *)packet)->options = 0x0000;
uint8_t *current_option = data + COAP_HEADER_LEN;
if (((coap_packet_t *)packet)->option_count)
{
uint8_t option_index = 0;
uint8_t current_number = 0;
size_t option_len = 0;
PRINTF("-Parsing %u options-\n", ((coap_packet_t *)packet)->option_count);
for (option_index=0; option_index < ((coap_packet_t *)packet)->option_count; ++option_index) {
current_number += current_option[0]>>4;
PRINTF("OPTION %u (type %u, delta %u, len %u): ", option_index, current_number, current_option[0]>>4, (0x0F & current_option[0]) < 15 ? (0x0F & current_option[0]) : current_option[1] + 15);
if ((0x0F & current_option[0]) < 15) {
option_len = 0x0F & current_option[0];
current_option += 1;
} else {
option_len = current_option[1] + 15;
current_option += 2;
}
SET_OPTION((coap_packet_t *)packet, current_number);
switch (current_number) {
case COAP_OPTION_CONTENT_TYPE:
((coap_packet_t *)packet)->content_type = parse_int_option(current_option, option_len);
PRINTF("Content-Type [%u]\n", ((coap_packet_t *)packet)->content_type);
break;
case COAP_OPTION_MAX_AGE:
((coap_packet_t *)packet)->max_age = parse_int_option(current_option, option_len);
PRINTF("Max-Age [%lu]\n", ((coap_packet_t *)packet)->max_age);
break;
case COAP_OPTION_PROXY_URI:
/*FIXME check for own end-point */
((coap_packet_t *)packet)->proxy_uri = (char *) current_option;
((coap_packet_t *)packet)->proxy_uri_len = option_len;
/*TODO length > 270 not implemented (actually not required) */
PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", ((coap_packet_t *)packet)->proxy_uri_len, ((coap_packet_t *)packet)->proxy_uri);
coap_error_message = "This is a constrained server (Contiki)";
return PROXYING_NOT_SUPPORTED_5_05;
break;
case COAP_OPTION_ETAG:
((coap_packet_t *)packet)->etag_len = MIN(COAP_ETAG_LEN, option_len);
memcpy(((coap_packet_t *)packet)->etag, current_option, ((coap_packet_t *)packet)->etag_len);
PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", ((coap_packet_t *)packet)->etag_len,
((coap_packet_t *)packet)->etag[0],
((coap_packet_t *)packet)->etag[1],
((coap_packet_t *)packet)->etag[2],
((coap_packet_t *)packet)->etag[3],
((coap_packet_t *)packet)->etag[4],
((coap_packet_t *)packet)->etag[5],
((coap_packet_t *)packet)->etag[6],
((coap_packet_t *)packet)->etag[7]
); /*FIXME always prints 8 bytes */
break;
case COAP_OPTION_URI_HOST:
((coap_packet_t *)packet)->uri_host = (char *) current_option;
((coap_packet_t *)packet)->uri_host_len = option_len;
PRINTF("Uri-Host [%.*s]\n", ((coap_packet_t *)packet)->uri_host_len, ((coap_packet_t *)packet)->uri_host);
break;
case COAP_OPTION_LOCATION_PATH:
coap_merge_multi_option(&(((coap_packet_t *)packet)->location_path), &(((coap_packet_t *)packet)->location_path_len), current_option, option_len, '/');
PRINTF("Location-Path [%.*s]\n", ((coap_packet_t *)packet)->location_path_len, ((coap_packet_t *)packet)->location_path);
break;
case COAP_OPTION_URI_PORT:
((coap_packet_t *)packet)->uri_port = parse_int_option(current_option, option_len);
PRINTF("Uri-Port [%u]\n", ((coap_packet_t *)packet)->uri_port);
break;
case COAP_OPTION_LOCATION_QUERY:
coap_merge_multi_option(&(((coap_packet_t *)packet)->location_query), &(((coap_packet_t *)packet)->location_query_len), current_option, option_len, '&');
PRINTF("Location-Query [%.*s]\n", ((coap_packet_t *)packet)->location_query_len, ((coap_packet_t *)packet)->location_query);
break;
case COAP_OPTION_URI_PATH:
coap_merge_multi_option(&(((coap_packet_t *)packet)->uri_path), &(((coap_packet_t *)packet)->uri_path_len), current_option, option_len, '/');
PRINTF("Uri-Path [%.*s]\n", ((coap_packet_t *)packet)->uri_path_len, ((coap_packet_t *)packet)->uri_path);
break;
case COAP_OPTION_OBSERVE:
((coap_packet_t *)packet)->observe = parse_int_option(current_option, option_len);
PRINTF("Observe [%u]\n", ((coap_packet_t *)packet)->observe);
break;
case COAP_OPTION_TOKEN:
((coap_packet_t *)packet)->token_len = MIN(COAP_TOKEN_LEN, option_len);
memcpy(((coap_packet_t *)packet)->token, current_option, ((coap_packet_t *)packet)->token_len);
PRINTF("Token %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", ((coap_packet_t *)packet)->token_len,
((coap_packet_t *)packet)->token[0],
((coap_packet_t *)packet)->token[1],
((coap_packet_t *)packet)->token[2],
((coap_packet_t *)packet)->token[3],
((coap_packet_t *)packet)->token[4],
((coap_packet_t *)packet)->token[5],
((coap_packet_t *)packet)->token[6],
((coap_packet_t *)packet)->token[7]
); /*FIXME always prints 8 bytes */
break;
case COAP_OPTION_FENCE_POST:
PRINTF("Fence-Post\n");
break;
case COAP_OPTION_URI_QUERY:
coap_merge_multi_option(&(((coap_packet_t *)packet)->uri_query), &(((coap_packet_t *)packet)->uri_query_len), current_option, option_len, '&');
PRINTF("Uri-Query [%.*s]\n", ((coap_packet_t *)packet)->uri_query_len, ((coap_packet_t *)packet)->uri_query);
break;
case COAP_OPTION_BLOCK2:
((coap_packet_t *)packet)->block2_num = parse_int_option(current_option, option_len);
((coap_packet_t *)packet)->block2_more = (((coap_packet_t *)packet)->block2_num & 0x08)>>3;
((coap_packet_t *)packet)->block2_size = 16 << (((coap_packet_t *)packet)->block2_num & 0x07);
((coap_packet_t *)packet)->block2_offset = (((coap_packet_t *)packet)->block2_num & ~0x0F)<<(((coap_packet_t *)packet)->block2_num & 0x07);
((coap_packet_t *)packet)->block2_num >>= 4;
PRINTF("Block2 [%lu%s (%u B/blk)]\n", ((coap_packet_t *)packet)->block2_num, ((coap_packet_t *)packet)->block2_more ? "+" : "", ((coap_packet_t *)packet)->block2_size);
break;
case COAP_OPTION_BLOCK1:
PRINTF("Block1 NOT IMPLEMENTED\n");
/*TODO implement */
coap_error_message = "Blockwise POST/PUT not supported";
return NOT_IMPLEMENTED_5_01;
break;
default:
PRINTF("unknown (%u)\n", current_number);
/* Check if critical (odd) */
if (current_number & 1)
{
coap_error_message = "Unsupported critical option";
return BAD_OPTION_4_02;
}
}
current_option += option_len;
} /* for */
PRINTF("-Done parsing-------\n");
} /* if (oc) */
((coap_packet_t *)packet)->payload = current_option;
((coap_packet_t *)packet)->payload_len = data_len - (((coap_packet_t *)packet)->payload - data);
return NO_ERROR;
}
/*-----------------------------------------------------------------------------------*/
/*- REST FRAMEWORK FUNCTIONS --------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
int
coap_get_query_variable(void *packet, const char *name, const char **output)
{
if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_QUERY)) {
return coap_get_variable(((coap_packet_t *)packet)->uri_query, ((coap_packet_t *)packet)->uri_query_len, name, output);
}
return 0;
}
int
coap_get_post_variable(void *packet, const char *name, const char **output)
{
if (((coap_packet_t *)packet)->payload_len) {
return coap_get_variable((const char *)((coap_packet_t *)packet)->payload, ((coap_packet_t *)packet)->payload_len, name, output);
}
return 0;
}
/*-----------------------------------------------------------------------------------*/
/*- HEADER OPTION GETTERS AND SETTERS -----------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
unsigned int
coap_get_header_content_type(void *packet)
{
return ((coap_packet_t *)packet)->content_type;
}
int
coap_set_header_content_type(void *packet, unsigned int content_type)
{
((coap_packet_t *)packet)->content_type = (coap_content_type_t) content_type;
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_CONTENT_TYPE);
return 1;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_max_age(void *packet, uint32_t *age)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_MAX_AGE)) {
*age = COAP_DEFAULT_MAX_AGE;
} else {
*age = ((coap_packet_t *)packet)->max_age;
}
return 1;
}
int
coap_set_header_max_age(void *packet, uint32_t age)
{
((coap_packet_t *)packet)->max_age = age;
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_MAX_AGE);
return 1;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_etag(void *packet, const uint8_t **etag)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_ETAG)) return 0;
*etag = ((coap_packet_t *)packet)->etag;
return ((coap_packet_t *)packet)->etag_len;
}
int
coap_set_header_etag(void *packet, uint8_t *etag, size_t etag_len)
{
((coap_packet_t *)packet)->etag_len = MIN(COAP_ETAG_LEN, etag_len);
memcpy(((coap_packet_t *)packet)->etag, etag, ((coap_packet_t *)packet)->etag_len);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_ETAG);
return ((coap_packet_t *)packet)->etag_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_token(void *packet, const uint8_t **token)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_TOKEN)) return 0;
*token = ((coap_packet_t *)packet)->token;
return ((coap_packet_t *)packet)->token_len;
}
int
coap_set_header_token(void *packet, uint8_t *token, size_t token_len)
{
((coap_packet_t *)packet)->token_len = MIN(COAP_TOKEN_LEN, token_len);
memcpy(((coap_packet_t *)packet)->token, token, ((coap_packet_t *)packet)->token_len);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_TOKEN);
return ((coap_packet_t *)packet)->token_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_proxy_uri(void *packet, const char **uri)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_PROXY_URI)) return 0;
*uri = ((coap_packet_t *)packet)->proxy_uri;
return ((coap_packet_t *)packet)->proxy_uri_len;
}
int
coap_set_header_proxy_uri(void *packet, char *uri)
{
((coap_packet_t *)packet)->proxy_uri = uri;
((coap_packet_t *)packet)->proxy_uri_len = strlen(uri);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_PROXY_URI);
return ((coap_packet_t *)packet)->proxy_uri_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_uri_host(void *packet, const char **host)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST)) return 0;
*host = ((coap_packet_t *)packet)->uri_host;
return ((coap_packet_t *)packet)->uri_host_len;
}
int
coap_set_header_uri_host(void *packet, char *host)
{
((coap_packet_t *)packet)->uri_host = host;
((coap_packet_t *)packet)->uri_host_len = strlen(host);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST);
return ((coap_packet_t *)packet)->uri_host_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_uri_path(void *packet, const char **path)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PATH)) return 0;
*path = ((coap_packet_t *)packet)->uri_path;
return ((coap_packet_t *)packet)->uri_path_len;
}
int
coap_set_header_uri_path(void *packet, char *path)
{
while (path[0]=='/') ++path;
((coap_packet_t *)packet)->uri_path = path;
((coap_packet_t *)packet)->uri_path_len = strlen(path);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PATH);
return ((coap_packet_t *)packet)->uri_path_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_uri_query(void *packet, const char **query)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_QUERY)) return 0;
*query = ((coap_packet_t *)packet)->uri_query;
return ((coap_packet_t *)packet)->uri_query_len;
}
int
coap_set_header_uri_query(void *packet, char *query)
{
while (query[0]=='?') ++query;
((coap_packet_t *)packet)->uri_query = query;
((coap_packet_t *)packet)->uri_query_len = strlen(query);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_QUERY);
return ((coap_packet_t *)packet)->uri_query_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_location_path(void *packet, const char **path)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH)) return 0;
*path = ((coap_packet_t *)packet)->location_path;
return ((coap_packet_t *)packet)->location_path_len;
}
int
coap_set_header_location_path(void *packet, char *path)
{
char *query;
while (path[0]=='/') ++path;
if ((query = strchr(path, '?')))
{
coap_set_header_location_query(packet, query+1);
((coap_packet_t *)packet)->location_path_len = query - path;
}
else
{
((coap_packet_t *)packet)->location_path_len = strlen(path);
}
((coap_packet_t *)packet)->location_path = path;
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH);
return ((coap_packet_t *)packet)->location_path_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_location_query(void *packet, const char **query)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_QUERY)) return 0;
*query = ((coap_packet_t *)packet)->location_query;
return ((coap_packet_t *)packet)->location_query_len;
}
int
coap_set_header_location_query(void *packet, char *query)
{
while (query[0]=='?') ++query;
((coap_packet_t *)packet)->location_query = query;
((coap_packet_t *)packet)->location_query_len = strlen(query);
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_QUERY);
return ((coap_packet_t *)packet)->location_query_len;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_observe(void *packet, uint32_t *observe)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_OBSERVE)) return 0;
*observe = ((coap_packet_t *)packet)->observe;
return 1;
}
int
coap_set_header_observe(void *packet, uint32_t observe)
{
((coap_packet_t *)packet)->observe = observe;
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_OBSERVE);
return 1;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK2)) return 0;
/* pointers may be NULL to get only specific block parameters */
if (num!=NULL) *num = ((coap_packet_t *)packet)->block2_num;
if (more!=NULL) *more = ((coap_packet_t *)packet)->block2_more;
if (size!=NULL) *size = ((coap_packet_t *)packet)->block2_size;
if (offset!=NULL) *offset = ((coap_packet_t *)packet)->block2_offset;
return 1;
}
int
coap_set_header_block2(void *packet, uint32_t num, uint8_t more, uint16_t size)
{
if (size<16) return 0;
if (size>2048) return 0;
if (num>0x0FFFFF) return 0;
((coap_packet_t *)packet)->block2_num = num;
((coap_packet_t *)packet)->block2_more = more;
((coap_packet_t *)packet)->block2_size = size;
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK2);
return 1;
}
/*-----------------------------------------------------------------------------------*/
int
coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset)
{
if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK1)) return 0;
/* pointers may be NULL to get only specific block parameters */
if (num!=NULL) *num = ((coap_packet_t *)packet)->block1_num;
if (more!=NULL) *more = ((coap_packet_t *)packet)->block1_more;
if (size!=NULL) *size = ((coap_packet_t *)packet)->block1_size;
if (offset!=NULL) *offset = ((coap_packet_t *)packet)->block1_offset;
return 1;
}
int
coap_set_header_block1(void *packet, uint32_t num, uint8_t more, uint16_t size)
{
if (size<16) return 0;
if (size>2048) return 0;
if (num>0x0FFFFF) return 0;
((coap_packet_t *)packet)->block1_num = num;
((coap_packet_t *)packet)->block1_more = more;
((coap_packet_t *)packet)->block1_size = size;
SET_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK1);
return 1;
}
/*-----------------------------------------------------------------------------------*/
/*- PAYLOAD -------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/
int
coap_get_payload(void *packet, const uint8_t **payload)
{
if (((coap_packet_t *)packet)->payload) {
*payload = ((coap_packet_t *)packet)->payload;
return ((coap_packet_t *)packet)->payload_len;
} else {
*payload = NULL;
return 0;
}
}
int
coap_set_payload(void *packet, uint8_t *payload, size_t length)
{
PRINTF("setting payload (%u/%u)\n", length, REST_MAX_CHUNK_SIZE);
((coap_packet_t *)packet)->payload = payload;
((coap_packet_t *)packet)->payload_len = MIN(REST_MAX_CHUNK_SIZE, length);
return ((coap_packet_t *)packet)->payload_len;
}
/*-----------------------------------------------------------------------------------*/

View file

@ -1,300 +0,0 @@
/*
* Copyright (c) 2011, 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
* An implementation of the Constrained Application Protocol (draft 06)
* \author
* Matthias Kovatsch <kovatsch@inf.ethz.ch>
*/
#ifndef COAP_06_H_
#define COAP_06_H_
#include <stddef.h> /* for size_t */
#include "contiki-net.h"
#include "erbium.h"
#define COAP_DEFAULT_PORT 5683
#ifndef COAP_SERVER_PORT
#define COAP_SERVER_PORT COAP_DEFAULT_PORT
#endif
#define COAP_DEFAULT_MAX_AGE 60
#define COAP_RESPONSE_TIMEOUT 2
#define COAP_RESPONSE_RANDOM_FACTOR 1.5
#define COAP_MAX_RETRANSMIT 4
#define COAP_HEADER_LEN 4 /* | oc:0xF0 type:0x0C version:0x03 | code | tid:0x00FF | tid:0xFF00 | */
#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */
#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */
#define COAP_HEADER_VERSION_MASK 0xC0
#define COAP_HEADER_VERSION_POSITION 6
#define COAP_HEADER_TYPE_MASK 0x30
#define COAP_HEADER_TYPE_POSITION 4
#define COAP_HEADER_OPTION_COUNT_MASK 0x0F
#define COAP_HEADER_OPTION_COUNT_POSITION 0
#define COAP_HEADER_OPTION_DELTA_MASK 0xF0
#define COAP_HEADER_OPTION_SHORT_LENGTH_MASK 0x0F
/*
* Conservative size limit, as not all options have to be set at the same time.
*/
/* Hdr CoT Age Tag Obs Tok Blo strings */
#define COAP_MAX_HEADER_SIZE (4 + 3 + 5 + 1+COAP_ETAG_LEN + 3 + 1+COAP_TOKEN_LEN + 4 + 10) /* 50 */
#define COAP_MAX_PACKET_SIZE (COAP_MAX_HEADER_SIZE + REST_MAX_CHUNK_SIZE)
/* 0/14 48 for IPv6 (28 for IPv4) */
#if COAP_MAX_PACKET_SIZE > (UIP_BUFSIZE - UIP_LLH_LEN - UIP_IPUDPH_LEN)
#error "UIP_CONF_BUFFER_SIZE too small for REST_MAX_CHUNK_SIZE"
#endif
/*
* Maximum number of failed request attempts before action
*/
#ifndef COAP_MAX_ATTEMPTS
#define COAP_MAX_ATTEMPTS 4
#endif /* COAP_MAX_ATTEMPTS */
#define UIP_IP_BUF ((struct uip_ip_hdr *)&uip_buf[UIP_LLH_LEN])
#define UIP_UDP_BUF ((struct uip_udp_hdr *)&uip_buf[uip_l2_l3_hdr_len])
#define SET_OPTION(packet, opt) ((packet)->options |= 1L<<opt)
#define IS_OPTION(packet, opt) ((packet)->options & 1L<<opt)
#ifndef MIN
#define MIN(a, b) ((a) < (b)? (a) : (b))
#endif /* MIN */
/* CoAP message types */
typedef enum {
COAP_TYPE_CON, /* confirmables */
COAP_TYPE_NON, /* non-confirmables */
COAP_TYPE_ACK, /* acknowledgements */
COAP_TYPE_RST /* reset */
} coap_message_type_t;
/* CoAP request method codes */
typedef enum {
COAP_GET = 1,
COAP_POST,
COAP_PUT,
COAP_DELETE
} coap_method_t;
/* CoAP response codes */
typedef enum {
NO_ERROR = 0,
CREATED_2_01 = 65, /* CREATED */
DELETED_2_02 = 66, /* DELETED */
VALID_2_03 = 67, /* NOT_MODIFIED */
CHANGED_2_04 = 68, /* CHANGED */
CONTENT_2_05 = 69, /* OK */
BAD_REQUEST_4_00 = 128, /* BAD_REQUEST */
UNAUTHORIZED_4_01 = 129, /* UNAUTHORIZED */
BAD_OPTION_4_02 = 130, /* BAD_OPTION */
FORBIDDEN_4_03 = 131, /* FORBIDDEN */
NOT_FOUND_4_04 = 132, /* NOT_FOUND */
METHOD_NOT_ALLOWED_4_05 = 133, /* METHOD_NOT_ALLOWED */
REQUEST_ENTITY_TOO_LARGE_4_13 = 141, /* REQUEST_ENTITY_TOO_LARGE */
UNSUPPORTED_MADIA_TYPE_4_15 = 143, /* UNSUPPORTED_MADIA_TYPE */
INTERNAL_SERVER_ERROR_5_00 = 160, /* INTERNAL_SERVER_ERROR */
NOT_IMPLEMENTED_5_01 = 161, /* NOT_IMPLEMENTED */
BAD_GATEWAY_5_02 = 162, /* BAD_GATEWAY */
SERVICE_UNAVAILABLE_5_03 = 163, /* SERVICE_UNAVAILABLE */
GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */
PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */
/* Memory errors */
IMPLEMENTATION_ERROR = 192,
MEMORY_ALLOC_ERR = 193,
MEMORY_BOUNDARY_EXCEEDED = 194,
/* CoAP errors */
UNIMPLEMENTED_CRITICAL_OPTION,
UNKNOWN_CRITICAL_OPTION,
PACKET_SERIALIZATION_ERROR
} coap_status_t;
/* CoAP header options */
typedef enum {
COAP_OPTION_CONTENT_TYPE = 1, /* 1-2 B */
COAP_OPTION_MAX_AGE = 2, /* 0-4 B */
COAP_OPTION_PROXY_URI = 3, /* 1-270 B */
COAP_OPTION_ETAG = 4, /* 1-8 B */
COAP_OPTION_URI_HOST = 5, /* 1-270 B */
COAP_OPTION_LOCATION_PATH = 6, /* 1-270 B */
COAP_OPTION_URI_PORT = 7, /* 0-2 B */
COAP_OPTION_LOCATION_QUERY = 8, /* 1-270 B */
COAP_OPTION_URI_PATH = 9, /* 1-270 B */
COAP_OPTION_OBSERVE = 10, /* 0-2 B */
COAP_OPTION_TOKEN = 11, /* 1-8 B */
COAP_OPTION_FENCE_POST = 14, /* 0 B */
COAP_OPTION_URI_QUERY = 15, /* 1-270 B */
COAP_OPTION_BLOCK2 = 17, /* 1-3 B */
COAP_OPTION_BLOCK1 = 19, /* 1-3 B */
} coap_option_t;
/* CoAP content-types */
typedef enum {
TEXT_PLAIN = 0,
TEXT_XML = 1, /* Intented types are not in the initial registry. */
TEXT_CSV = 2,
TEXT_HTML = 3,
IMAGE_GIF = 21,
IMAGE_JPEG = 22,
IMAGE_PNG = 23,
IMAGE_TIFF = 24,
AUDIO_RAW = 25,
VIDEO_RAW = 26,
APPLICATION_LINK_FORMAT = 40, /* Actually not in registry!? */
APPLICATION_XML = 41,
APPLICATION_OCTET_STREAM = 42,
APPLICATION_RDF_XML = 43,
APPLICATION_SOAP_XML = 44,
APPLICATION_ATOM_XML = 45,
APPLICATION_XMPP_XML = 46,
APPLICATION_EXI = 47,
APPLICATION_FASTINFOSET = 48,
APPLICATION_SOAP_FASTINFOSET = 49,
APPLICATION_JSON = 50,
APPLICATION_X_OBIX_BINARY = 51
} coap_content_type_t;
typedef struct {
uint8_t *buffer; /* pointer to CoAP header / incoming packet buffer / memory to serialize packet */
uint8_t version;
coap_message_type_t type;
uint8_t option_count;
uint8_t code;
uint16_t tid;
uint32_t options; /* Bitmap to check if option is set */
coap_content_type_t content_type; /* Parse options once and store; allows setting options in random order */
uint32_t max_age;
size_t proxy_uri_len;
char *proxy_uri;
uint8_t etag_len;
uint8_t etag[COAP_ETAG_LEN];
size_t uri_host_len;
char *uri_host;
size_t location_path_len;
char *location_path;
uint16_t uri_port;
size_t location_query_len;
char *location_query;
size_t uri_path_len;
char *uri_path;
uint16_t observe;
uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN];
uint32_t block2_num;
uint8_t block2_more;
uint16_t block2_size;
uint32_t block2_offset;
uint32_t block1_num;
uint8_t block1_more;
uint16_t block1_size;
uint32_t block1_offset;
size_t uri_query_len;
char *uri_query;
uint16_t payload_len;
uint8_t *payload;
} coap_packet_t;
/* To store error code and human-readable payload */
extern coap_status_t coap_error_code;
extern char *coap_error_message;
void coap_init_connection(uint16_t port);
uint16_t coap_get_tid(void);
void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t tid);
size_t coap_serialize_message(void *packet, uint8_t *buffer);
void coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length);
coap_status_t coap_parse_message(void *request, uint8_t *data, uint16_t data_len);
int coap_get_query_variable(void *packet, const char *name, const char **output);
int coap_get_post_variable(void *packet, const char *name, const char **output);
unsigned int coap_get_header_content_type(void *packet);
int coap_set_header_content_type(void *packet, unsigned int content_type);
int coap_get_header_max_age(void *packet, uint32_t *age);
int coap_set_header_max_age(void *packet, uint32_t age);
int coap_get_header_etag(void *packet, const uint8_t **etag);
int coap_set_header_etag(void *packet, uint8_t *etag, size_t etag_len);
int coap_get_header_token(void *packet, const uint8_t **token);
int coap_set_header_token(void *packet, uint8_t *token, size_t token_len);
int coap_get_header_proxy_uri(void *packet, const char **uri); /* In-place string might not be 0-terminated. */
int coap_set_header_proxy_uri(void *packet, char *uri);
int coap_get_header_uri_host(void *packet, const char **host); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_host(void *packet, char *host);
int coap_get_header_uri_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_path(void *packet, char *path);
int coap_get_header_uri_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_query(void *packet, char *query);
int coap_get_header_location_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */
int coap_set_header_location_path(void *packet, char *path); /* Also splits optional query into Location-Query option. */
int coap_get_header_location_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */
int coap_set_header_location_query(void *packet, char *query);
int coap_get_header_observe(void *packet, uint32_t *observe);
int coap_set_header_observe(void *packet, uint32_t observe);
int coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset);
int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, uint16_t size);
int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset);
int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, uint16_t size);
int coap_get_payload(void *packet, const uint8_t **payload);
int coap_set_payload(void *packet, uint8_t *payload, size_t length);
#endif /* COAP_06_H_ */

View file

@ -100,9 +100,9 @@ handle_incoming_data(void)
if (coap_error_code==NO_ERROR) if (coap_error_code==NO_ERROR)
{ {
/*TODO duplicates suppression, if required */ /*TODO duplicates suppression, if required by application */
PRINTF(" Parsed: v %u, t %u, oc %u, c %u, tid %u\n", message->version, message->type, message->option_count, message->code, message->tid); PRINTF(" Parsed: v %u, t %u, oc %u, c %u, mid %u\n", message->version, message->type, message->option_count, message->code, message->mid);
PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path); PRINTF(" URL: %.*s\n", message->uri_path_len, message->uri_path);
PRINTF(" Payload: %.*s\n", message->payload_len, message->payload); PRINTF(" Payload: %.*s\n", message->payload_len, message->payload);
@ -110,23 +110,23 @@ handle_incoming_data(void)
if (message->code >= COAP_GET && message->code <= COAP_DELETE) if (message->code >= COAP_GET && message->code <= COAP_DELETE)
{ {
/* Use transaction buffer for response to confirmable request. */ /* Use transaction buffer for response to confirmable request. */
if ( (transaction = coap_new_transaction(message->tid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) ) if ( (transaction = coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) )
{ {
static uint32_t block_num = 0; uint32_t block_num = 0;
static uint16_t block_size = REST_MAX_CHUNK_SIZE; uint16_t block_size = REST_MAX_CHUNK_SIZE;
static uint32_t block_offset = 0; uint32_t block_offset = 0;
static int32_t new_offset = 0; int32_t new_offset = 0;
/* prepare response */ /* prepare response */
if (message->type==COAP_TYPE_CON) if (message->type==COAP_TYPE_CON)
{ {
/* Reliable CON requests are answered with an ACK. */ /* Reliable CON requests are answered with an ACK. */
coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->tid); coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid);
} }
else else
{ {
/* Unreliable NON requests are answered with a NON as well. */ /* Unreliable NON requests are answered with a NON as well. */
coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_tid()); coap_init_message(response, COAP_TYPE_NON, CONTENT_2_05, coap_get_mid());
} }
/* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */ /* resource handlers must take care of different handling (e.g., TOKEN_OPTION_REQUIRED_240) */
@ -143,17 +143,14 @@ handle_incoming_data(void)
block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); block_size = MIN(block_size, REST_MAX_CHUNK_SIZE);
new_offset = block_offset; new_offset = block_offset;
} }
else
{
block_size = REST_MAX_CHUNK_SIZE;
new_offset = 0;
}
/* Invoke resource handler. */ /* Invoke resource handler. */
if (service_cbk) if (service_cbk)
{ {
/* Call REST framework and check if found and allowed. */ /* Call REST framework and check if found and allowed. */
if (service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset)) if (service_cbk(message, response, transaction->packet+COAP_MAX_HEADER_SIZE, block_size, &new_offset))
{
if (coap_error_code==NO_ERROR)
{ {
/* Apply blockwise transfers. */ /* Apply blockwise transfers. */
if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
@ -167,7 +164,7 @@ handle_incoming_data(void)
PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n"); PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n");
response->code = BAD_OPTION_4_02; response->code = BAD_OPTION_4_02;
coap_set_payload(response, (uint8_t*)"BlockOutOfScope", 15); coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
} }
else else
{ {
@ -190,22 +187,27 @@ handle_incoming_data(void)
coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE); coap_set_header_block2(response, 0, new_offset!=-1, REST_MAX_CHUNK_SIZE);
coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE)); coap_set_payload(response, response->payload, MIN(response->payload_len, REST_MAX_CHUNK_SIZE));
} /* if (blockwise request) */ } /* if (blockwise request) */
} /* no errors/hooks */
} /* successful service callback */
/* Serialize response. */
if (coap_error_code==NO_ERROR)
{
if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0)
{
coap_error_code = PACKET_SERIALIZATION_ERROR;
} }
} }
}
else else
{ {
coap_error_code = INTERNAL_SERVER_ERROR_5_00; coap_error_code = INTERNAL_SERVER_ERROR_5_00;
coap_error_message = "Service callback undefined"; coap_error_message = "Service callback undefined";
} /* if (service callback) */ } /* if (service callback) */
/* serialize Response. */
if ((transaction->packet_len = coap_serialize_message(response, transaction->packet))==0)
{
coap_error_code = PACKET_SERIALIZATION_ERROR;
}
} else { } else {
coap_error_code = MEMORY_ALLOC_ERR; coap_error_code = MEMORY_ALLOCATION_ERROR;
coap_error_message = "Transaction buffer allocation failed"; coap_error_message = "Transaction buffer allocation failed";
} /* if (transaction buffer) */ } /* if (transaction buffer) */
} }
@ -221,14 +223,10 @@ handle_incoming_data(void)
{ {
PRINTF("Received RST\n"); PRINTF("Received RST\n");
/* Cancel possible subscriptions. */ /* Cancel possible subscriptions. */
if (IS_OPTION(message, COAP_OPTION_TOKEN)) coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid);
{
PRINTF(" Token 0x%02X%02X\n", message->token[0], message->token[1]);
coap_remove_observer_by_token(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->token, message->token_len);
}
} }
if ( (transaction = coap_get_transaction_by_tid(message->tid)) ) if ( (transaction = coap_get_transaction_by_mid(message->mid)) )
{ {
/* Free transaction memory before callback, as it may create a new transaction. */ /* Free transaction memory before callback, as it may create a new transaction. */
restful_response_handler callback = transaction->callback; restful_response_handler callback = transaction->callback;
@ -241,12 +239,20 @@ handle_incoming_data(void)
} }
} /* if (ACKed transaction) */ } /* if (ACKed transaction) */
transaction = NULL; transaction = NULL;
}
} /* Request or Response */
} /* if (parsed correctly) */ } /* if (parsed correctly) */
if (coap_error_code==NO_ERROR) { if (coap_error_code==NO_ERROR)
{
if (transaction) coap_send_transaction(transaction); if (transaction) coap_send_transaction(transaction);
} }
else if (coap_error_code==MANUAL_RESPONSE)
{
PRINTF("Clearing transaction for manual response");
coap_clear_transaction(transaction);
}
else else
{ {
PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message); PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message);
@ -258,8 +264,8 @@ handle_incoming_data(void)
coap_error_code = INTERNAL_SERVER_ERROR_5_00; coap_error_code = INTERNAL_SERVER_ERROR_5_00;
} }
/* Reuse input buffer for error message. */ /* Reuse input buffer for error message. */
coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->tid); coap_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid);
coap_set_payload(message, (uint8_t *) coap_error_message, strlen(coap_error_message)); coap_set_payload(message, coap_error_message, strlen(coap_error_message));
coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata)); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, uip_appdata, coap_serialize_message(message, uip_appdata));
} }
} /* if (new data) */ } /* if (new data) */
@ -285,29 +291,16 @@ coap_get_rest_method(void *packet)
return (rest_resource_flags_t)(1 << (((coap_packet_t *)packet)->code - 1)); return (rest_resource_flags_t)(1 << (((coap_packet_t *)packet)->code - 1));
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
int
coap_set_rest_status(void *packet, unsigned int code)
{
if (code <= 0xFF)
{
((coap_packet_t *)packet)->code = (uint8_t) code;
return 1;
}
else
{
return 0;
}
}
/*-----------------------------------------------------------------------------------*/
/*- Server part ---------------------------------------------------------------------*/ /*- Server part ---------------------------------------------------------------------*/
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
/* The discover resource is automatically included for CoAP. */ /* The discover resource is automatically included for CoAP. */
RESOURCE(well_known_core, METHOD_GET, ".well-known/core", "ct=40"); RESOURCE(well_known_core, METHOD_GET, ".well-known/core", "ct=40");
void void
well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset)
{ {
size_t strpos = 0; size_t strpos = 0; /* position in overall string (which is larger than the buffer) */
size_t bufpos = 0; size_t bufpos = 0; /* position within buffer (bytes written) */
size_t tmplen = 0; size_t tmplen = 0;
resource_t* resource = NULL; resource_t* resource = NULL;
@ -333,6 +326,10 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t
bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1,
"%s", resource->url + ((*offset-(int32_t)strpos > 0) ? (*offset-(int32_t)strpos) : 0)); "%s", resource->url + ((*offset-(int32_t)strpos > 0) ? (*offset-(int32_t)strpos) : 0));
/* minimal-net requires these casts */ /* minimal-net requires these casts */
if (bufpos >= preferred_size)
{
break;
}
} }
strpos += tmplen; strpos += tmplen;
@ -355,6 +352,10 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t
{ {
bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1,
"%s", resource->attributes + (*offset-(int32_t)strpos > 0 ? *offset-(int32_t)strpos : 0)); "%s", resource->attributes + (*offset-(int32_t)strpos > 0 ? *offset-(int32_t)strpos : 0));
if (bufpos >= preferred_size)
{
break;
}
} }
strpos += tmplen; strpos += tmplen;
} }
@ -386,8 +387,8 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t
{ {
PRINTF("well_known_core_handler(): bufpos<=0\n"); PRINTF("well_known_core_handler(): bufpos<=0\n");
coap_set_rest_status(response, BAD_OPTION_4_02); coap_set_status_code(response, BAD_OPTION_4_02);
coap_set_payload(response, (uint8_t*)"BlockOutOfScope", 15); coap_set_payload(response, "BlockOutOfScope", 15);
} }
if (resource==NULL) { if (resource==NULL) {
@ -397,7 +398,7 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t
else else
{ {
PRINTF("res: MORE at %s (%p)\n", resource->url, resource); PRINTF("res: MORE at %s (%p)\n", resource->url, resource);
*offset += bufpos; *offset += preferred_size;
} }
} }
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -453,8 +454,8 @@ PT_THREAD(coap_blocking_request(struct request_state_t *state, process_event_t e
block_error = 0; block_error = 0;
do { do {
request->tid = coap_get_tid(); request->mid = coap_get_mid();
if ((state->transaction = coap_new_transaction(request->tid, remote_ipaddr, remote_port))) if ((state->transaction = coap_new_transaction(request->mid, remote_ipaddr, remote_port)))
{ {
state->transaction->callback = blocking_request_callback; state->transaction->callback = blocking_request_callback;
state->transaction->callback_data = state; state->transaction->callback_data = state;
@ -467,7 +468,7 @@ PT_THREAD(coap_blocking_request(struct request_state_t *state, process_event_t e
state->transaction->packet_len = coap_serialize_message(request, state->transaction->packet); state->transaction->packet_len = coap_serialize_message(request, state->transaction->packet);
coap_send_transaction(state->transaction); coap_send_transaction(state->transaction);
PRINTF("Requested #%lu (TID %u)\n", state->block_num, request->tid); PRINTF("Requested #%lu (MID %u)\n", state->block_num, request->mid);
PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL); PT_YIELD_UNTIL(&state->pt, ev == PROCESS_EVENT_POLL);
@ -513,7 +514,7 @@ const struct rest_implementation coap_rest_implementation = {
coap_get_header_uri_path, coap_get_header_uri_path,
coap_set_header_uri_path, coap_set_header_uri_path,
coap_get_rest_method, coap_get_rest_method,
coap_set_rest_status, coap_set_status_code,
coap_get_header_content_type, coap_get_header_content_type,
coap_set_header_content_type, coap_set_header_content_type,

View file

@ -58,7 +58,7 @@ LIST(observers_list);
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
coap_observer_t * coap_observer_t *
coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len) coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len, const char *url)
{ {
coap_observer_t *o = memb_alloc(&observers_memb); coap_observer_t *o = memb_alloc(&observers_memb);
@ -69,6 +69,7 @@ coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint
o->port = port; o->port = port;
o->token_len = token_len; o->token_len = token_len;
memcpy(o->token, token, token_len); memcpy(o->token, token, token_len);
o->last_mid = 0;
stimer_set(&o->refresh_timer, COAP_OBSERVING_REFRESH_INTERVAL); stimer_set(&o->refresh_timer, COAP_OBSERVING_REFRESH_INTERVAL);
@ -107,6 +108,7 @@ coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port)
} }
return removed; return removed;
} }
int int
coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len) coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len)
{ {
@ -116,7 +118,7 @@ coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token,
for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next)
{ {
PRINTF("Remove check Token 0x%02X%02X\n", token[0], token[1]); PRINTF("Remove check Token 0x%02X%02X\n", token[0], token[1]);
if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port && memcmp(obs->token, token, token_len)==0) if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port && obs->token_len==token_len && memcmp(obs->token, token, token_len)==0)
{ {
coap_remove_observer(obs); coap_remove_observer(obs);
removed++; removed++;
@ -124,8 +126,9 @@ coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token,
} }
return removed; return removed;
} }
int int
coap_remove_observer_by_url(const char *url) coap_remove_observer_by_url(uip_ipaddr_t *addr, uint16_t port, const char *url)
{ {
int removed = 0; int removed = 0;
coap_observer_t* obs = NULL; coap_observer_t* obs = NULL;
@ -133,7 +136,25 @@ coap_remove_observer_by_url(const char *url)
for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next)
{ {
PRINTF("Remove check URL %p\n", url); PRINTF("Remove check URL %p\n", url);
if (obs->url==url || memcmp(obs->url, url, strlen(obs->url))==0) if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port && (obs->url==url || memcmp(obs->url, url, strlen(obs->url))==0))
{
coap_remove_observer(obs);
removed++;
}
}
return removed;
}
int
coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid)
{
int removed = 0;
coap_observer_t* obs = NULL;
for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next)
{
PRINTF("Remove check MID %u\n", mid);
if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port && obs->last_mid==mid)
{ {
coap_remove_observer(obs); coap_remove_observer(obs);
removed++; removed++;
@ -154,7 +175,7 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl
/*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */ /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers */
if ( (transaction = coap_new_transaction(coap_get_tid(), &obs->addr, obs->port)) ) if ( (transaction = coap_new_transaction(coap_get_mid(), &obs->addr, obs->port)) )
{ {
/* Use CON to check whether client is still there/interested after COAP_OBSERVING_REFRESH_INTERVAL. */ /* Use CON to check whether client is still there/interested after COAP_OBSERVING_REFRESH_INTERVAL. */
if (stimer_expired(&obs->refresh_timer)) if (stimer_expired(&obs->refresh_timer))
@ -166,7 +187,7 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl
/* prepare response */ /* prepare response */
coap_packet_t push[1]; /* This way the packet can be treated as pointer as usual. */ coap_packet_t push[1]; /* This way the packet can be treated as pointer as usual. */
coap_init_message(push, (coap_message_type_t)type, CONTENT_2_05, transaction->tid ); coap_init_message(push, (coap_message_type_t)type, CONTENT_2_05, transaction->mid );
coap_set_header_observe(push, observe); coap_set_header_observe(push, observe);
coap_set_header_token(push, obs->token, obs->token_len); coap_set_header_token(push, obs->token, obs->token_len);
coap_set_payload(push, payload, payload_len); coap_set_payload(push, payload, payload_len);
@ -177,6 +198,9 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl
PRINTF(":%u\n", obs->port); PRINTF(":%u\n", obs->port);
PRINTF(" %.*s\n", payload_len, payload); PRINTF(" %.*s\n", payload_len, payload);
/* Update last MID for RST matching. */
obs->last_mid = transaction->mid;
coap_send_transaction(transaction); coap_send_transaction(transaction);
} }
} }
@ -186,33 +210,35 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl
void void
coap_observe_handler(resource_t *resource, void *request, void *response) coap_observe_handler(resource_t *resource, void *request, void *response)
{ {
static char content[26]; coap_packet_t *const coap_req = (coap_packet_t *) request;
coap_packet_t *const coap_res = (coap_packet_t *) response;
if (response && ((coap_packet_t *)response)->code<128) /* response without error code */ static char content[16];
{
if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_OBSERVE))
{
if (!IS_OPTION((coap_packet_t *)request, COAP_OPTION_TOKEN))
{
/* Set default token. */
coap_set_header_token(request, (uint8_t *)"", 1);
}
if (coap_add_observer(resource->url, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, ((coap_packet_t *)request)->token, ((coap_packet_t *)request)->token_len)) if (coap_req->code==COAP_GET && coap_res->code<128) /* GET request and response without error code */
{ {
coap_set_header_observe(response, 0); if (IS_OPTION(coap_req, COAP_OPTION_OBSERVE))
coap_set_payload(response, (uint8_t *)content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); {
if (coap_add_observer(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, coap_req->token, coap_req->token_len, resource->url))
{
coap_set_header_observe(coap_res, 0);
/*
* For demonstration purposes only. A subscription should return the same representation as a normal GET.
* TODO: Comment the following line for any real application.
*/
coap_set_payload(coap_res, content, snprintf(content, sizeof(content), "Added %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS));
} }
else else
{ {
((coap_packet_t *)response)->code = SERVICE_UNAVAILABLE_5_03; coap_res->code = SERVICE_UNAVAILABLE_5_03;
coap_set_payload(response, (uint8_t *)"Too many observers", 18); coap_set_payload(coap_res, "TooManyObservers", 16);
} /* if (added observer) */ } /* if (added observer) */
} }
else /* if (observe) */ else /* if (observe) */
{ {
/* Remove client if it is currently observing. */ /* Remove client if it is currently observing. */
coap_remove_observer_by_client(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport); coap_remove_observer_by_url(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, resource->url);
} /* if (observe) */ } /* if (observe) */
} }
} }

View file

@ -61,17 +61,19 @@ typedef struct coap_observer {
uint16_t port; uint16_t port;
uint8_t token_len; uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN]; uint8_t token[COAP_TOKEN_LEN];
uint16_t last_mid;
struct stimer refresh_timer; struct stimer refresh_timer;
} coap_observer_t; } coap_observer_t;
list_t coap_get_observers(void); list_t coap_get_observers(void);
coap_observer_t *coap_add_observer(const char *url, uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len); coap_observer_t *coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_t token_len, const char *url);
void coap_remove_observer(coap_observer_t *o);
void coap_remove_observer(coap_observer_t *o);
int coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port); int coap_remove_observer_by_client(uip_ipaddr_t *addr, uint16_t port);
int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len); int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len);
int coap_remove_observer_by_url(const char *url); int coap_remove_observer_by_url(uip_ipaddr_t *addr, uint16_t port, const char *url);
int coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid);
void coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len); void coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len);

View file

@ -40,6 +40,7 @@
#include <string.h> #include <string.h>
#include "er-coap-07-separate.h" #include "er-coap-07-separate.h"
#include "er-coap-07-transactions.h"
#define DEBUG 0 #define DEBUG 0
#if DEBUG #if DEBUG
@ -53,17 +54,66 @@
#endif #endif
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
void coap_separate_handler(resource_t *resource, void *request, void *response) int coap_separate_handler(resource_t *resource, void *request, void *response)
{ {
PRINTF("Separate response for /%s \n", resource->url); coap_packet_t *const coap_req = (coap_packet_t *) request;
coap_packet_t *const coap_res = (coap_packet_t *) response;
PRINTF("Separate response for /%s MID %u\n", resource->url, coap_res->mid);
/* Only ack CON requests. */
if (coap_req->type==COAP_TYPE_CON)
{
coap_transaction_t *const t = coap_get_transaction_by_mid(coap_res->mid);
/* send separate ACK. */ /* send separate ACK. */
coap_packet_t ack[1]; coap_packet_t ack[1];
/* ACK with empty code (0) */ /* ACK with empty code (0) */
coap_init_message(ack, COAP_TYPE_ACK, 0, ((coap_packet_t *)request)->tid); coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->mid);
/* Should only overwrite Header which is already parsed to request. */ /* Serializing into IPBUF: Only overwrites header parts that are already parsed into the request struct. */
coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, (uip_appdata + uip_ext_len), coap_serialize_message(ack, (uip_appdata + uip_ext_len))); coap_send_message(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, (uip_appdata), coap_serialize_message(ack, uip_appdata));
/* Change response to separate response. */ /* Change response to separate response. */
((coap_packet_t *)response)->type = COAP_TYPE_CON; coap_res->type = COAP_TYPE_CON;
((coap_packet_t *)response)->tid = coap_get_tid(); coap_res->mid = coap_get_mid();
/* Update MID in transaction for identification. */
t->mid = coap_res->mid;
}
/* Pre-handlers could skip the handling by returning 0. */
return 1;
}
int
coap_separate_response(void *response, coap_separate_t *separate_store)
{
coap_packet_t *const coap_res = (coap_packet_t *) response;
coap_transaction_t *const t = coap_get_transaction_by_mid(coap_res->mid);
if (t)
{
uip_ipaddr_copy(&separate_store->addr, &t->addr);
separate_store->port = t->port;
separate_store->mid = coap_res->mid;
separate_store->type = coap_res->type;
memcpy(separate_store->token, coap_res->token, coap_res->token_len);
separate_store->token_len = coap_res->token_len;
separate_store->block2_num = coap_res->block2_num;
separate_store->block2_more = coap_res->block2_more;
separate_store->block2_size = coap_res->block2_size;
separate_store->block2_offset = coap_res->block2_offset;
/* Signal the engine to skip automatic response and clear transaction by engine. */
coap_error_code = MANUAL_RESPONSE;
return 1;
}
else
{
return 0;
}
} }

View file

@ -41,6 +41,28 @@
#include "er-coap-07.h" #include "er-coap-07.h"
void coap_separate_handler(resource_t *resource, void *request, void *response); typedef struct coap_separate {
uip_ipaddr_t addr;
uint16_t port;
coap_message_type_t type;
uint16_t mid;
uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN];
uint32_t block2_num;
uint8_t block2_more;
uint16_t block2_size;
uint32_t block2_offset;
/* Add fields for addition information to be saved here, e.g.: */
char buffer[17];
} coap_separate_t;
int coap_separate_handler(resource_t *resource, void *request, void *response);
int coap_separate_response(void *response, coap_separate_t *separate_store);
#endif /* COAP_SEPARATE_H_ */ #endif /* COAP_SEPARATE_H_ */

View file

@ -75,18 +75,20 @@ coap_register_as_transaction_handler()
} }
coap_transaction_t * coap_transaction_t *
coap_new_transaction(uint16_t tid, uip_ipaddr_t *addr, uint16_t port) coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr, uint16_t port)
{ {
coap_transaction_t *t = memb_alloc(&transactions_memb); coap_transaction_t *t = memb_alloc(&transactions_memb);
if (t) if (t)
{ {
t->tid = tid; t->mid = mid;
t->retrans_counter = 0; t->retrans_counter = 0;
/* save client address */ /* save client address */
uip_ipaddr_copy(&t->addr, addr); uip_ipaddr_copy(&t->addr, addr);
t->port = port; t->port = port;
list_add(transactions_list, t); /* List itself makes sure same element is not added twice. */
} }
return t; return t;
@ -95,7 +97,7 @@ coap_new_transaction(uint16_t tid, uip_ipaddr_t *addr, uint16_t port)
void void
coap_send_transaction(coap_transaction_t *t) coap_send_transaction(coap_transaction_t *t)
{ {
PRINTF("Sending transaction %u\n", t->tid); PRINTF("Sending transaction %u\n", t->mid);
coap_send_message(&t->addr, t->port, t->packet, t->packet_len); coap_send_message(&t->addr, t->port, t->packet, t->packet_len);
@ -103,7 +105,7 @@ coap_send_transaction(coap_transaction_t *t)
{ {
if (t->retrans_counter<COAP_MAX_RETRANSMIT) if (t->retrans_counter<COAP_MAX_RETRANSMIT)
{ {
PRINTF("Keeping transaction %u\n", t->tid); PRINTF("Keeping transaction %u\n", t->mid);
if (t->retrans_counter==0) if (t->retrans_counter==0)
{ {
@ -122,8 +124,6 @@ coap_send_transaction(coap_transaction_t *t)
etimer_restart(&t->retrans_timer); /* interval updated above */ etimer_restart(&t->retrans_timer); /* interval updated above */
process_current = process_actual; process_current = process_actual;
list_add(transactions_list, t); /* List itself makes sure same element is not added twice. */
t = NULL; t = NULL;
} }
else else
@ -154,7 +154,7 @@ coap_clear_transaction(coap_transaction_t *t)
{ {
if (t) if (t)
{ {
PRINTF("Freeing transaction %u: %p\n", t->tid, t); PRINTF("Freeing transaction %u: %p\n", t->mid, t);
etimer_stop(&t->retrans_timer); etimer_stop(&t->retrans_timer);
list_remove(transactions_list, t); list_remove(transactions_list, t);
@ -163,15 +163,15 @@ coap_clear_transaction(coap_transaction_t *t)
} }
coap_transaction_t * coap_transaction_t *
coap_get_transaction_by_tid(uint16_t tid) coap_get_transaction_by_mid(uint16_t mid)
{ {
coap_transaction_t *t = NULL; coap_transaction_t *t = NULL;
for (t = (coap_transaction_t*)list_head(transactions_list); t; t = t->next) for (t = (coap_transaction_t*)list_head(transactions_list); t; t = t->next)
{ {
if (t->tid==tid) if (t->mid==mid)
{ {
PRINTF("Found transaction for TID %u: %p\n", t->tid, t); PRINTF("Found transaction for MID %u: %p\n", t->mid, t);
return t; return t;
} }
} }
@ -188,7 +188,7 @@ coap_check_transactions()
if (etimer_expired(&t->retrans_timer)) if (etimer_expired(&t->retrans_timer))
{ {
++(t->retrans_counter); ++(t->retrans_counter);
PRINTF("Retransmitting %u (%u)\n", t->tid, t->retrans_counter); PRINTF("Retransmitting %u (%u)\n", t->mid, t->retrans_counter);
coap_send_transaction(t); coap_send_transaction(t);
} }
} }

View file

@ -52,7 +52,7 @@
typedef struct coap_transaction { typedef struct coap_transaction {
struct coap_transaction *next; /* for LIST */ struct coap_transaction *next; /* for LIST */
uint16_t tid; uint16_t mid;
struct etimer retrans_timer; struct etimer retrans_timer;
uint8_t retrans_counter; uint8_t retrans_counter;
@ -68,10 +68,10 @@ typedef struct coap_transaction {
void coap_register_as_transaction_handler(); void coap_register_as_transaction_handler();
coap_transaction_t *coap_new_transaction(uint16_t tid, uip_ipaddr_t *addr, uint16_t port); coap_transaction_t *coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr, uint16_t port);
void coap_send_transaction(coap_transaction_t *t); void coap_send_transaction(coap_transaction_t *t);
void coap_clear_transaction(coap_transaction_t *t); void coap_clear_transaction(coap_transaction_t *t);
coap_transaction_t *coap_get_transaction_by_tid(uint16_t tid); coap_transaction_t *coap_get_transaction_by_mid(uint16_t mid);
void coap_check_transactions(); void coap_check_transactions();

File diff suppressed because it is too large Load diff

View file

@ -54,7 +54,7 @@
#define COAP_RESPONSE_RANDOM_FACTOR 1.5 #define COAP_RESPONSE_RANDOM_FACTOR 1.5
#define COAP_MAX_RETRANSMIT 4 #define COAP_MAX_RETRANSMIT 4
#define COAP_HEADER_LEN 4 /* | oc:0xF0 type:0x0C version:0x03 | code | tid:0x00FF | tid:0xFF00 | */ #define COAP_HEADER_LEN 4 /* | oc:0xF0 type:0x0C version:0x03 | code | mid:0x00FF | mid:0xFF00 | */
#define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */ #define COAP_ETAG_LEN 8 /* The maximum number of bytes for the ETag */
#define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */ #define COAP_TOKEN_LEN 8 /* The maximum number of bytes for the Token */
#define COAP_MAX_ACCEPT_NUM 2 /* The maximum number of accept preferences to parse/store */ #define COAP_MAX_ACCEPT_NUM 2 /* The maximum number of accept preferences to parse/store */
@ -140,15 +140,13 @@ typedef enum {
GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */ GATEWAY_TIMEOUT_5_04 = 164, /* GATEWAY_TIMEOUT */
PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */ PROXYING_NOT_SUPPORTED_5_05 = 165, /* PROXYING_NOT_SUPPORTED */
/* Memory errors */ /* Erbium errors */
IMPLEMENTATION_ERROR = 192, MEMORY_ALLOCATION_ERROR = 192,
MEMORY_ALLOC_ERR = 193, PACKET_SERIALIZATION_ERROR,
MEMORY_BOUNDARY_EXCEEDED = 194,
/* Erbium hooks */
MANUAL_RESPONSE
/* CoAP errors */
UNIMPLEMENTED_CRITICAL_OPTION,
UNKNOWN_CRITICAL_OPTION,
PACKET_SERIALIZATION_ERROR
} coap_status_t; } coap_status_t;
/* CoAP header options */ /* CoAP header options */
@ -206,25 +204,25 @@ typedef struct {
coap_message_type_t type; coap_message_type_t type;
uint8_t option_count; uint8_t option_count;
uint8_t code; uint8_t code;
uint16_t tid; uint16_t mid;
uint32_t options; /* Bitmap to check if option is set */ uint32_t options; /* Bitmap to check if option is set */
coap_content_type_t content_type; /* Parse options once and store; allows setting options in random order */ coap_content_type_t content_type; /* Parse options once and store; allows setting options in random order */
uint32_t max_age; uint32_t max_age;
size_t proxy_uri_len; size_t proxy_uri_len;
char *proxy_uri; const char *proxy_uri;
uint8_t etag_len; uint8_t etag_len;
uint8_t etag[COAP_ETAG_LEN]; uint8_t etag[COAP_ETAG_LEN];
size_t uri_host_len; size_t uri_host_len;
char *uri_host; const char *uri_host;
size_t location_path_len; size_t location_path_len;
char *location_path; const char *location_path;
uint16_t uri_port; uint16_t uri_port;
size_t location_query_len; size_t location_query_len;
char *location_query; const char *location_query;
size_t uri_path_len; size_t uri_path_len;
char *uri_path; const char *uri_path;
uint16_t observe; uint16_t observe;
uint8_t token_len; uint8_t token_len;
uint8_t token[COAP_TOKEN_LEN]; uint8_t token[COAP_TOKEN_LEN];
@ -241,7 +239,7 @@ typedef struct {
uint16_t block1_size; uint16_t block1_size;
uint32_t block1_offset; uint32_t block1_offset;
size_t uri_query_len; size_t uri_query_len;
char *uri_query; const char *uri_query;
uint8_t if_none_match; uint8_t if_none_match;
uint16_t payload_len; uint16_t payload_len;
@ -255,9 +253,9 @@ extern coap_status_t coap_error_code;
extern char *coap_error_message; extern char *coap_error_message;
void coap_init_connection(uint16_t port); void coap_init_connection(uint16_t port);
uint16_t coap_get_tid(void); uint16_t coap_get_mid(void);
void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t tid); void coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t mid);
size_t coap_serialize_message(void *packet, uint8_t *buffer); size_t coap_serialize_message(void *packet, uint8_t *buffer);
void coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length); void coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t length);
coap_status_t coap_parse_message(void *request, uint8_t *data, uint16_t data_len); coap_status_t coap_parse_message(void *request, uint8_t *data, uint16_t data_len);
@ -265,44 +263,48 @@ coap_status_t coap_parse_message(void *request, uint8_t *data, uint16_t data_len
int coap_get_query_variable(void *packet, const char *name, const char **output); int coap_get_query_variable(void *packet, const char *name, const char **output);
int coap_get_post_variable(void *packet, const char *name, const char **output); int coap_get_post_variable(void *packet, const char *name, const char **output);
/*-----------------------------------------------------------------------------------*/
int coap_set_status_code(void *packet, unsigned int code);
unsigned int coap_get_header_content_type(void *packet); unsigned int coap_get_header_content_type(void *packet);
int coap_set_header_content_type(void *packet, unsigned int content_type); int coap_set_header_content_type(void *packet, unsigned int content_type);
int coap_get_header_accept(void *packet, uint16_t **accept); int coap_get_header_accept(void *packet, const uint16_t **accept);
int coap_set_header_accept(void *packet, uint16_t accept); int coap_set_header_accept(void *packet, uint16_t accept);
int coap_get_header_max_age(void *packet, uint32_t *age); int coap_get_header_max_age(void *packet, uint32_t *age);
int coap_set_header_max_age(void *packet, uint32_t age); int coap_set_header_max_age(void *packet, uint32_t age);
int coap_get_header_etag(void *packet, const uint8_t **etag); int coap_get_header_etag(void *packet, const uint8_t **etag);
int coap_set_header_etag(void *packet, uint8_t *etag, size_t etag_len); int coap_set_header_etag(void *packet, const uint8_t *etag, size_t etag_len);
int coap_get_header_if_match(void *packet, const uint8_t **etag); int coap_get_header_if_match(void *packet, const uint8_t **etag);
int coap_set_header_if_match(void *packet, uint8_t *etag, size_t etag_len); int coap_set_header_if_match(void *packet, const uint8_t *etag, size_t etag_len);
int coap_get_header_if_none_match(void *packet); int coap_get_header_if_none_match(void *packet);
int coap_set_header_if_none_match(void *packet); int coap_set_header_if_none_match(void *packet);
int coap_get_header_token(void *packet, const uint8_t **token); int coap_get_header_token(void *packet, const uint8_t **token);
int coap_set_header_token(void *packet, uint8_t *token, size_t token_len); int coap_set_header_token(void *packet, const uint8_t *token, size_t token_len);
int coap_get_header_proxy_uri(void *packet, const char **uri); /* In-place string might not be 0-terminated. */ int coap_get_header_proxy_uri(void *packet, const char **uri); /* In-place string might not be 0-terminated. */
int coap_set_header_proxy_uri(void *packet, char *uri); int coap_set_header_proxy_uri(void *packet, const char *uri);
int coap_get_header_uri_host(void *packet, const char **host); /* In-place string might not be 0-terminated. */ int coap_get_header_uri_host(void *packet, const char **host); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_host(void *packet, char *host); int coap_set_header_uri_host(void *packet, const char *host);
int coap_get_header_uri_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */ int coap_get_header_uri_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_path(void *packet, char *path); int coap_set_header_uri_path(void *packet, const char *path);
int coap_get_header_uri_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */ int coap_get_header_uri_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */
int coap_set_header_uri_query(void *packet, char *query); int coap_set_header_uri_query(void *packet, const char *query);
int coap_get_header_location_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */ int coap_get_header_location_path(void *packet, const char **path); /* In-place string might not be 0-terminated. */
int coap_set_header_location_path(void *packet, char *path); /* Also splits optional query into Location-Query option. */ int coap_set_header_location_path(void *packet, const char *path); /* Also splits optional query into Location-Query option. */
int coap_get_header_location_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */ int coap_get_header_location_query(void *packet, const char **query); /* In-place string might not be 0-terminated. */
int coap_set_header_location_query(void *packet, char *query); int coap_set_header_location_query(void *packet, const char *query);
int coap_get_header_observe(void *packet, uint32_t *observe); int coap_get_header_observe(void *packet, uint32_t *observe);
int coap_set_header_observe(void *packet, uint32_t observe); int coap_set_header_observe(void *packet, uint32_t observe);
@ -313,7 +315,7 @@ int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, uint16_t si
int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset); int coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, uint16_t *size, uint32_t *offset);
int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, uint16_t size); int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, uint16_t size);
int coap_get_payload(void *packet, const uint8_t **payload); int coap_get_payload(void *packet, uint8_t **payload);
int coap_set_payload(void *packet, uint8_t *payload, size_t length); int coap_set_payload(void *packet, const void *payload, size_t length);
#endif /* COAP_07_H_ */ #endif /* COAP_07_H_ */

View file

@ -59,35 +59,8 @@ LIST(restful_services);
LIST(restful_periodic_services); LIST(restful_periodic_services);
#ifdef WITH_HTTP
char *
rest_to_http_max_age(uint32_t age)
{
/* Cache-Control: max-age=age for HTTP */
static char temp_age[19];
snprintf(temp_age, sizeof(temp_age), "max-age=%lu", age);
return temp_age;
}
char *
rest_to_http_etag(uint8_t *etag, uint8_t etag_len)
{
static char temp_etag[17];
int index = 0;
for (index = 0; index<sizeof(temp_etag) && index<etag_len; ++index) {
snprintf(temp_etag+2*index, sizeof(temp_etag), "%02x", etag[index]);
}
temp_etag[2*index] = '\0';
return temp_etag;
}
#endif /*WITH_COAP*/
void void
rest_init_framework(void) rest_init_engine(void)
{ {
list_init(restful_services); list_init(restful_services);

View file

@ -146,7 +146,7 @@ struct rest_implementation {
/** Get request URI path */ /** Get request URI path */
int (* get_url)(void *request, const char **url); int (* get_url)(void *request, const char **url);
int (* set_url)(void *request, char *url); int (* set_url)(void *request, const char *url);
/** Get the method of a request. */ /** Get the method of a request. */
rest_resource_flags_t (* get_method_type)(void *request); rest_resource_flags_t (* get_method_type)(void *request);
@ -160,7 +160,7 @@ struct rest_implementation {
/** Set the content-type of a response. */ /** Set the content-type of a response. */
int (* set_header_content_type)(void *response, unsigned int content_type); int (* set_header_content_type)(void *response, unsigned int content_type);
int (* get_header_accept)(void *request, uint16_t **accept); int (* get_header_accept)(void *request, const uint16_t **accept);
/** Get the Max-Age option of a request. */ /** Get the Max-Age option of a request. */
int (* get_header_max_age)(void *request, uint32_t *age); int (* get_header_max_age)(void *request, uint32_t *age);
@ -169,7 +169,7 @@ struct rest_implementation {
int (* set_header_max_age)(void *response, uint32_t age); int (* set_header_max_age)(void *response, uint32_t age);
/** Set the ETag option of a response. */ /** Set the ETag option of a response. */
int (* set_header_etag)(void *response, uint8_t *etag, size_t length); int (* set_header_etag)(void *response, const uint8_t *etag, size_t length);
/** Get the If-Match option of a request. */ /** Get the If-Match option of a request. */
int (* get_header_if_match)(void *request, const uint8_t **etag); int (* get_header_if_match)(void *request, const uint8_t **etag);
@ -181,13 +181,13 @@ struct rest_implementation {
int (* get_header_host)(void *request, const char **host); int (* get_header_host)(void *request, const char **host);
/** Set the location option of a response. */ /** Set the location option of a response. */
int (* set_header_location)(void *response, char *location); int (* set_header_location)(void *response, const char *location);
/** Get the payload option of a request. */ /** Get the payload option of a request. */
int (* get_request_payload)(void *request, const uint8_t **payload); int (* get_request_payload)(void *request, uint8_t **payload);
/** Set the payload option of a response. */ /** Set the payload option of a response. */
int (* set_response_payload)(void *response, uint8_t *payload, size_t length); int (* set_response_payload)(void *response, const void *payload, size_t length);
/** Get the query string of a request. */ /** Get the query string of a request. */
int (* get_query)(void *request, const char **value); int (* get_query)(void *request, const char **value);
@ -282,7 +282,7 @@ periodic_resource_t periodic_resource_##name = {NULL, &resource_##name, period,
/* /*
* Initializes REST framework and starts HTTP or COAP process * Initializes REST framework and starts HTTP or COAP process
*/ */
void rest_init_framework(void); void rest_init_engine(void);
/* /*
* Resources wanted to be accessible should be activated with the following code. * Resources wanted to be accessible should be activated with the following code.

View file

@ -283,7 +283,7 @@ generate_file_stats(void *arg)
{ {
struct httpd_state *s = (struct httpd_state *)arg; struct httpd_state *s = (struct httpd_state *)arg;
#if WEBSERVER_CONF_LOADTIME #if WEBSERVER_CONF_LOADTIME
static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "<p align=\"right\"><br><br><i>This page has been sent %u times (%1u.%u sec)</i></body></html>"; static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "<p align=\"right\"><br><br><i>This page has been sent %u times (%1u.%02u sec)</i></body></html>";
#else #else
static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "<p align=\"right\"><br><br><i>This page has been sent %u times</i></body></html>"; static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "<p align=\"right\"><br><br><i>This page has been sent %u times</i></body></html>";
#endif #endif
@ -301,7 +301,7 @@ generate_file_stats(void *arg)
#if WEBSERVER_CONF_LOADTIME #if WEBSERVER_CONF_LOADTIME
s->pagetime = clock_time() - s->pagetime; s->pagetime = clock_time() - s->pagetime;
numprinted=httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_filestat1, httpd_fs_open(s->filename, 0), numprinted=httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_filestat1, httpd_fs_open(s->filename, 0),
(unsigned int)s->pagetime/CLOCK_SECOND,(unsigned int)s->pagetime%CLOCK_SECOND); (unsigned int)s->pagetime/CLOCK_SECOND,(100*((unsigned int)s->pagetime%CLOCK_SECOND))/CLOCK_SECOND);
#else #else
numprinted=httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_filestat1, httpd_fs_open(s->filename, 0)); numprinted=httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_filestat1, httpd_fs_open(s->filename, 0));
#endif #endif
@ -433,10 +433,12 @@ PT_THREAD(processes(struct httpd_state *s, char *ptr))
#endif /* WEBSERVER_CONF_PROCESSES */ #endif /* WEBSERVER_CONF_PROCESSES */
#if WEBSERVER_CONF_ADDRESSES || WEBSERVER_CONF_NEIGHBORS || WEBSERVER_CONF_ROUTES #if WEBSERVER_CONF_ADDRESSES || WEBSERVER_CONF_NEIGHBORS || WEBSERVER_CONF_ROUTES
static const char httpd_cgi_addrh[] HTTPD_STRING_ATTR = "<code>"; #if WEBSERVER_CONF_SHOW_ROOM
static const char httpd_cgi_addrf[] HTTPD_STRING_ATTR = "</code>[Room for %u more]"; static const char httpd_cgi_addrf[] HTTPD_STRING_ATTR = "[Room for %u more]\n";
static const char httpd_cgi_addrb[] HTTPD_STRING_ATTR = "<br>"; #else
static const char httpd_cgi_addrn[] HTTPD_STRING_ATTR = "(none)<br>"; static const char httpd_cgi_addrf[] HTTPD_STRING_ATTR = "[Table is full]\n";
#endif
static const char httpd_cgi_addrn[] HTTPD_STRING_ATTR = "[None]\n";
#endif #endif
#if WEBSERVER_CONF_ADDRESSES #if WEBSERVER_CONF_ADDRESSES
@ -447,16 +449,21 @@ static unsigned short
make_addresses(void *p) make_addresses(void *p)
{ {
uint8_t i,j=0; uint8_t i,j=0;
uint16_t numprinted; uint16_t numprinted = 0;
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh);
for (i=0; i<UIP_DS6_ADDR_NB;i++) { for (i=0; i<UIP_DS6_ADDR_NB;i++) {
if (uip_ds6_if.addr_list[i].isused) { if (uip_ds6_if.addr_list[i].isused) {
j++; j++;
numprinted += httpd_cgi_sprint_ip6(uip_ds6_if.addr_list[i].ipaddr, uip_appdata + numprinted); numprinted += httpd_cgi_sprint_ip6(uip_ds6_if.addr_list[i].ipaddr, uip_appdata + numprinted);
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrb); *((char *)uip_appdata+numprinted++) = '\n';
} }
} }
#if WEBSERVER_CONF_SHOW_ROOM
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf, UIP_DS6_ADDR_NB-j); numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf, UIP_DS6_ADDR_NB-j);
#else
if(UIP_DS6_ADDR_NB == j) {
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf);
}
#endif
return numprinted; return numprinted;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -477,17 +484,55 @@ extern uip_ds6_nbr_t uip_ds6_nbr_cache[];
static unsigned short static unsigned short
make_neighbors(void *p) make_neighbors(void *p)
{ {
uint8_t i,j=0; uint8_t i,j;
uint16_t numprinted; uint16_t numprinted=0;
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh); struct httpd_state *s=p;
for (i=0; i<UIP_DS6_NBR_NB;i++) { /* Span generator calls over tcp segments */
/* Note retransmissions will execute thise code multiple times for a segment */
i=s->starti;j=s->startj;
for (;i<UIP_DS6_NBR_NB;i++) {
if (uip_ds6_nbr_cache[i].isused) { if (uip_ds6_nbr_cache[i].isused) {
j++; j++;
#if WEBSERVER_CONF_NEIGHBOR_STATUS
static const char httpd_cgi_nbrs1[] HTTPD_STRING_ATTR = " INCOMPLETE";
static const char httpd_cgi_nbrs2[] HTTPD_STRING_ATTR = " REACHABLE";
static const char httpd_cgi_nbrs3[] HTTPD_STRING_ATTR = " STALE";
static const char httpd_cgi_nbrs4[] HTTPD_STRING_ATTR = " DELAY";
static const char httpd_cgi_nbrs5[] HTTPD_STRING_ATTR = " NBR_PROBE";
{uint16_t k=numprinted+25;
numprinted += httpd_cgi_sprint_ip6(uip_ds6_nbr_cache[i].ipaddr, uip_appdata + numprinted); numprinted += httpd_cgi_sprint_ip6(uip_ds6_nbr_cache[i].ipaddr, uip_appdata + numprinted);
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrb); while (numprinted < k) {*((char *)uip_appdata+numprinted++) = ' ';}
switch (uip_ds6_nbr_cache[i].state) {
case NBR_INCOMPLETE: numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_nbrs1);break;
case NBR_REACHABLE: numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_nbrs2);break;
case NBR_STALE: numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_nbrs3);break;
case NBR_DELAY: numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_nbrs4);break;
case NBR_PROBE: numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_nbrs5);break;
}
}
#else
numprinted += httpd_cgi_sprint_ip6(uip_ds6_nbr_cache[i].ipaddr, uip_appdata + numprinted);
#endif
*((char *)uip_appdata+numprinted++) = '\n';
/* If buffer near full, send it and wait for the next call. Could be a retransmission, or the next segment */
if(numprinted > (uip_mss() - 50)) {
s->savei=i;s->savej=j;
return numprinted;
} }
} }
}
#if WEBSERVER_CONF_SHOW_ROOM
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_NBR_NB-j); numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_NBR_NB-j);
#else
if(UIP_DS6_NBR_NB == j) {
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf);
}
#endif
/* Signal that this was the last segment */
s->savei = 0;
return numprinted; return numprinted;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -496,7 +541,13 @@ PT_THREAD(neighbors(struct httpd_state *s, char *ptr))
{ {
PSOCK_BEGIN(&s->sout); PSOCK_BEGIN(&s->sout);
PSOCK_GENERATOR_SEND(&s->sout, make_neighbors, s->u.ptr); /* Send as many TCP segments as needed for the neighbor table */
/* Move to next seqment after each successful transmission */
s->starti=s->startj=0;
do {
PSOCK_GENERATOR_SEND(&s->sout, make_neighbors, (void *)s);
s->starti=s->savei+1;s->startj=s->savej;
} while(s->savei);
PSOCK_END(&s->sout); PSOCK_END(&s->sout);
} }
@ -508,27 +559,57 @@ extern uip_ds6_route_t uip_ds6_routing_table[];
static unsigned short static unsigned short
make_routes(void *p) make_routes(void *p)
{ {
static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via "; static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "/%u (via ";
static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus<br>"; static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus\n";
static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")<br>"; static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")\n";
uint8_t i,j=0; uint8_t i,j;
uint16_t numprinted; uint16_t numprinted=0;
numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh); struct httpd_state *s=p;
for (i=0; i<UIP_DS6_ROUTE_NB;i++) { /* Span generator calls over tcp segments */
/* Note retransmissions will execute thise code multiple times for a segment */
i=s->starti;j=s->startj;
for (;i<UIP_DS6_ROUTE_NB;i++) {
if (uip_ds6_routing_table[i].isused) { if (uip_ds6_routing_table[i].isused) {
j++; j++;
#if WEBSERVER_CONF_ROUTE_LINKS
static const char httpd_cgi_rtesl1[] HTTPD_STRING_ATTR = "<a href=http://[";
static const char httpd_cgi_rtesl2[] HTTPD_STRING_ATTR = "]/status.shtml>";
static const char httpd_cgi_rtesl3[] HTTPD_STRING_ATTR = "</a>";
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtesl1);
numprinted += httpd_cgi_sprint_ip6(uip_ds6_routing_table[i].ipaddr, uip_appdata + numprinted); numprinted += httpd_cgi_sprint_ip6(uip_ds6_routing_table[i].ipaddr, uip_appdata + numprinted);
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtesl2);
numprinted += httpd_cgi_sprint_ip6(uip_ds6_routing_table[i].ipaddr, uip_appdata + numprinted);
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtesl3);
#else
numprinted += httpd_cgi_sprint_ip6(uip_ds6_routing_table[i].ipaddr, uip_appdata + numprinted);
#endif
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, uip_ds6_routing_table[i].length); numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes1, uip_ds6_routing_table[i].length);
numprinted += httpd_cgi_sprint_ip6(uip_ds6_routing_table[i].nexthop, uip_appdata + numprinted); numprinted += httpd_cgi_sprint_ip6(uip_ds6_routing_table[i].nexthop, uip_appdata + numprinted);
if(uip_ds6_routing_table[i].state.lifetime < 3600) { if(1 || uip_ds6_routing_table[i].state.lifetime < 3600) {
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, (long unsigned int)uip_ds6_routing_table[i].state.lifetime); numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes2, (long unsigned int)uip_ds6_routing_table[i].state.lifetime);
} else { } else {
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes3); numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_rtes3);
} }
/* If buffer nearly full, send it and wait for the next call. Could be a retransmission, or the next segment */
if(numprinted > (uip_mss() - 200)) {
s->savei=i;s->savej=j;
return numprinted;
}
} }
} }
if (j==0) numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrn); if (j==0) numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrn);
#if WEBSERVER_CONF_SHOW_ROOM
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_ROUTE_NB-j); numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_ROUTE_NB-j);
#else
if(UIP_DS6_ROUTE_NB == j) {
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf);
}
#endif
/* Signal that this was the last segment */
s->savei = 0;
return numprinted; return numprinted;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -537,7 +618,13 @@ PT_THREAD(routes(struct httpd_state *s, char *ptr))
{ {
PSOCK_BEGIN(&s->sout); PSOCK_BEGIN(&s->sout);
PSOCK_GENERATOR_SEND(&s->sout, make_routes, s->u.ptr); /* Send as many TCP segments as needed for the route table */
/* Move to next seqment after each successful transmission */
s->starti=s->startj=0;
do {
PSOCK_GENERATOR_SEND(&s->sout, make_routes, s);
s->starti=s->savei+1;s->startj=s->savej;
} while(s->savei);
PSOCK_END(&s->sout); PSOCK_END(&s->sout);
} }
@ -548,18 +635,15 @@ PT_THREAD(routes(struct httpd_state *s, char *ptr))
static unsigned short static unsigned short
generate_sensor_readings(void *arg) generate_sensor_readings(void *arg)
{ {
uint16_t numprinted; uint16_t numprinted=0;
uint16_t days,h,m,s; uint16_t days,h,m,s;
unsigned long seconds=clock_seconds(); unsigned long seconds=clock_seconds();
static const char httpd_cgi_sensor0[] HTTPD_STRING_ATTR = "[Updated %d seconds ago]<br><br>"; static const char httpd_cgi_sensor0[] HTTPD_STRING_ATTR = "[Updated %d seconds ago]\n";
static const char httpd_cgi_sensor1[] HTTPD_STRING_ATTR = "<pre><em>Temperature:</em> %s\n"; static const char httpd_cgi_sensor1[] HTTPD_STRING_ATTR = "<em>Temperature:</em> %s\n";
static const char httpd_cgi_sensor2[] HTTPD_STRING_ATTR = "<em>Battery :</em> %s\n"; static const char httpd_cgi_sensor2[] HTTPD_STRING_ATTR = "<em>Battery :</em> %s\n";
// static const char httpd_cgi_sensr12[] HTTPD_STRING_ATTR = "<em>Temperature:</em> %s <em>Battery:</em> %s<br>";
static const char httpd_cgi_sensor3[] HTTPD_STRING_ATTR = "<em>Uptime :</em> %02d:%02d:%02d\n"; static const char httpd_cgi_sensor3[] HTTPD_STRING_ATTR = "<em>Uptime :</em> %02d:%02d:%02d\n";
static const char httpd_cgi_sensor3d[] HTTPD_STRING_ATTR = "<em>Uptime :</em> %u days %02u:%02u:%02u\n"; static const char httpd_cgi_sensor3d[] HTTPD_STRING_ATTR = "<em>Uptime :</em> %u days %02u:%02u:%02u\n";
// static const char httpd_cgi_sensor4[] HTTPD_STRING_ATTR = "<em>Sleeping time :</em> %02d:%02d:%02d (%d%%)<br>";
numprinted=0;
/* Generate temperature and voltage strings for each platform */ /* Generate temperature and voltage strings for each platform */
#if CONTIKI_TARGET_AVR_ATMEGA128RFA1 #if CONTIKI_TARGET_AVR_ATMEGA128RFA1
{uint8_t i; {uint8_t i;
@ -623,12 +707,16 @@ generate_sensor_readings(void *arg)
#elif CONTIKI_TARGET_REDBEE_ECONOTAG #elif CONTIKI_TARGET_REDBEE_ECONOTAG
//#include "adc.h" //#include "adc.h"
{ {
#if 0
/* Scan ADC channels if not already being done elsewhere */
uint8_t c; uint8_t c;
adc_reading[8]=0; adc_reading[8]=0;
adc_init(); adc_init();
while (adc_reading[8]==0) adc_service(); while (adc_reading[8]==0) adc_service();
// for (c=0; c<NUM_ADC_CHAN; c++) printf("%u %04u\r\n", c, adc_reading[c]); //for (c=0; c<NUM_ADC_CHAN; c++) printf("%u %04u\r\n", c, adc_reading[c]);
adc_disable(); adc_disable();
#endif
snprintf(sensor_extvoltage, sizeof(sensor_extvoltage),"%u mV",1200*0xfff/adc_reading[8]); snprintf(sensor_extvoltage, sizeof(sensor_extvoltage),"%u mV",1200*0xfff/adc_reading[8]);
static const char httpd_cgi_sensorv[] HTTPD_STRING_ATTR = "<em>ADC chans :</em> %u %u %u %u %u %u %u %u \n"; static const char httpd_cgi_sensorv[] HTTPD_STRING_ATTR = "<em>ADC chans :</em> %u %u %u %u %u %u %u %u \n";
@ -641,11 +729,14 @@ uint8_t c;
if (last_tempupdate) { if (last_tempupdate) {
numprinted =httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_sensor0,(unsigned int) (seconds-last_tempupdate)); numprinted =httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_sensor0,(unsigned int) (seconds-last_tempupdate));
} }
if (sensor_temperature[0]!='N') {
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor1, sensor_temperature); numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor1, sensor_temperature);
}
#if CONTIKI_TARGET_REDBEE_ECONOTAG #if CONTIKI_TARGET_REDBEE_ECONOTAG
/* Econotag at 3v55 with 10 ohms to LiFePO4 battery: 3680mv usb 3106 battery (meter 3.08). Take 3500 as breakpoint for USB connected */ /* Econotag at 3v55 with 10 ohms to LiFePO4 battery: 3680mv usb 3573 2 Fresh alkaline AAs. Take 3590 as threshold for USB connected */
static const char httpd_cgi_sensor2u[] HTTPD_STRING_ATTR = "<em>Vcc (USB) :</em> %s\n"; static const char httpd_cgi_sensor2u[] HTTPD_STRING_ATTR = "<em>Vcc (USB) :</em> %s\n";
if(adc_reading[8]<1404) { if(adc_reading[8]<1368) {
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor2u, sensor_extvoltage); numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor2u, sensor_extvoltage);
} else { } else {
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor2, sensor_extvoltage); numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor2, sensor_extvoltage);
@ -653,7 +744,6 @@ uint8_t c;
#else #else
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor2, sensor_extvoltage); numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor2, sensor_extvoltage);
#endif #endif
// numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensr12, sensor_temperature,sensor_extvoltage);
#if RADIOSTATS #if RADIOSTATS
/* Remember radioontime for display below - slow connection might make it report longer than cpu ontime! */ /* Remember radioontime for display below - slow connection might make it report longer than cpu ontime! */
@ -667,14 +757,20 @@ uint8_t c;
h=h-days*24; h=h-days*24;
numprinted+=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_sensor3d, days,h,m,s); numprinted+=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_sensor3d, days,h,m,s);
} }
return numprinted;
}
#if WEBSERVER_CONF_STATISTICS
/*---------------------------------------------------------------------------*/
static unsigned short
generate_stats(void *arg)
{
uint16_t numprinted;
uint16_t h,m,s;
uint8_t p1,p2;
uint32_t seconds=clock_seconds();
#if 0 static const char httpd_cgi_stats[] HTTPD_STRING_ATTR = "\n<big><b>Statistics</b></big>\n";
if (sleepseconds) { numprinted=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_stats);
uint8_t p1;
p1=100UL*sleepseconds/seconds;h=sleepseconds/3600;s=sleepseconds-h*3600;m=s/60;s=s-m*60;
numprinted+=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_sensor4, h,m,s,p1);
}
#endif
#if ENERGEST_CONF_ON #if ENERGEST_CONF_ON
{uint8_t p1,p2; {uint8_t p1,p2;
@ -733,23 +829,11 @@ uint8_t c;
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor21, numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor21,
rimestats.tx,rimestats.rx,rimestats.lltx-rimestats.tx,rimestats.llrx-rimestats.rx); rimestats.tx,rimestats.rx,rimestats.lltx-rimestats.tx,rimestats.llrx-rimestats.rx);
#endif #endif
static const char httpd_cgi_sensor99[] HTTPD_STRING_ATTR = "</pre>";
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor99);
return numprinted;
}
#if RADIOSTATS #if RADIOSTATS
/*---------------------------------------------------------------------------*/ /* From RF230 statistics */
static unsigned short static const char httpd_cgi_sensor10[] HTTPD_STRING_ATTR = "<em>Radio on (RF230BB) :</em> %02d:%02d:%02d (%d.%02d%%)\n";
generate_radio_stats(void *arg) static const char httpd_cgi_sensor11[] HTTPD_STRING_ATTR = "<em>Packets: (RF230BB) :</em> Tx=%5d Rx=%5d TxL=%5d RxL=%5d RSSI=%2ddBm\n";
{
uint16_t numprinted;
uint16_t h,m,s;
uint8_t p1,p2;
unsigned long seconds=clock_seconds();
static const char httpd_cgi_sensor10[] HTTPD_STRING_ATTR = "<em>Radio on time :</em> %02d:%02d:%02d (%d.%02d%%)<br>";
static const char httpd_cgi_sensor11[] HTTPD_STRING_ATTR = "<em>Packets:</em> Tx=%5d Rx=%5d TxL=%5d RxL=%5d RSSI=%2ddBm\n";
s=(10000UL*savedradioontime)/seconds; s=(10000UL*savedradioontime)/seconds;
p1=s/100; p1=s/100;
@ -772,7 +856,7 @@ generate_radio_stats(void *arg)
numprinted+=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_sensor11,\ numprinted+=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_sensor11,\
RF230_sendpackets,RF230_receivepackets,RF230_sendfail,RF230_receivefail,p1); RF230_sendpackets,RF230_receivepackets,RF230_sendfail,RF230_receivefail,p1);
#endif #endif
#endif /* RADIOSTATS */
return numprinted; return numprinted;
} }
#endif #endif
@ -783,8 +867,8 @@ PT_THREAD(sensor_readings(struct httpd_state *s, char *ptr))
PSOCK_BEGIN(&s->sout); PSOCK_BEGIN(&s->sout);
PSOCK_GENERATOR_SEND(&s->sout, generate_sensor_readings, s); PSOCK_GENERATOR_SEND(&s->sout, generate_sensor_readings, s);
#if RADIOSTATS #if WEBSERVER_CONF_STATISTICS
PSOCK_GENERATOR_SEND(&s->sout, generate_radio_stats, s); PSOCK_GENERATOR_SEND(&s->sout, generate_stats, s);
#endif #endif
PSOCK_END(&s->sout); PSOCK_END(&s->sout);
@ -971,15 +1055,40 @@ PT_THREAD(ajax_call(struct httpd_state *s, char *ptr))
SENSORS_DEACTIVATE(acc_sensor); SENSORS_DEACTIVATE(acc_sensor);
#elif CONTIKI_TARGET_REDBEE_ECONOTAG #elif CONTIKI_TARGET_REDBEE_ECONOTAG
#if 0
/* Scan ADC channels if not already done elsewhere */
{ uint8_t c; { uint8_t c;
adc_reading[8]=0; adc_reading[8]=0;
adc_init(); adc_init();
while (adc_reading[8]==0) adc_service(); while (adc_reading[8]==0) adc_service();
adc_disable(); adc_disable();
#endif
#if 0
numprinted = snprintf(buf, sizeof(buf),"b(%u);adc(%u,%u,%u,%u,%u,%u,%u,%u);", numprinted = snprintf(buf, sizeof(buf),"b(%u);adc(%u,%u,%u,%u,%u,%u,%u,%u);",
1200*0xfff/adc_reading[8],adc_reading[0],adc_reading[1],adc_reading[2],adc_reading[3],adc_reading[4],adc_reading[5],adc_reading[6],adc_reading[7]); 1200*0xfff/adc_reading[8],adc_reading[0],adc_reading[1],adc_reading[2],adc_reading[3],adc_reading[4],adc_reading[5],adc_reading[6],adc_reading[7]);
#else
// numprinted = snprintf(buf, sizeof(buf),"b(%u);",1200*0xfff/adc_reading[8]);
numprinted = snprintf(buf, sizeof(buf),"b(%u);adc(%u,%u,%u);",1200*0xfff/adc_reading[8],adc_reading[1],adc_reading[7],adc_reading[8]);
#endif
} }
if (iter<3) {
static const char httpd_cgi_ajax11[] HTTPD_STRING_ATTR = "wt('Econtag [";
static const char httpd_cgi_ajax12[] HTTPD_STRING_ATTR = "]');";
numprinted += httpd_snprintf(buf+numprinted, sizeof(buf)-numprinted,httpd_cgi_ajax11);
#if WEBSERVER_CONF_PRINTADDR
/* Note address table is filled from the end down */
{int i;
for (i=0; i<UIP_DS6_ADDR_NB;i++) {
if (uip_ds6_if.addr_list[i].isused) {
numprinted += httpd_cgi_sprint_ip6(uip_ds6_if.addr_list[i].ipaddr, buf + numprinted);
break;
}
}
}
#endif
numprinted += httpd_snprintf(buf+numprinted, sizeof(buf)-numprinted,httpd_cgi_ajax12);
}
#elif CONTIKI_TARGET_MINIMAL_NET #elif CONTIKI_TARGET_MINIMAL_NET
static uint16_t c0=0x3ff,c1=0x3ff,c2=0x3ff,c3=0x3ff,c4=0x3ff,c5=0x3ff,c6=0x3ff,c7=0x3ff; static uint16_t c0=0x3ff,c1=0x3ff,c2=0x3ff,c3=0x3ff,c4=0x3ff,c5=0x3ff,c6=0x3ff,c7=0x3ff;
numprinted = snprintf(buf, sizeof(buf), "t(%d);b(%u);v(%u);",273+(rand()&0x3f),3300-iter/10,iter); numprinted = snprintf(buf, sizeof(buf), "t(%d);b(%u);v(%u);",273+(rand()&0x3f),3300-iter/10,iter);

View file

@ -93,8 +93,11 @@
#define WEBSERVER_CONF_PROCESSES 0 #define WEBSERVER_CONF_PROCESSES 0
#define WEBSERVER_CONF_ADDRESSES 1 #define WEBSERVER_CONF_ADDRESSES 1
#define WEBSERVER_CONF_NEIGHBORS 1 #define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_ROUTES 1 #define WEBSERVER_CONF_NEIGHBOR_STATUS 0
#define WEBSERVER_CONF_ROUTES 0
#define WEBSERVER_CONF_ROUTE_LINKS 0
#define WEBSERVER_CONF_SENSORS 0 #define WEBSERVER_CONF_SENSORS 0
#define WEBSERVER_CONF_STATISTICS 0
#define WEBSERVER_CONF_TICTACTOE 0 //Needs passquery of at least 10 chars #define WEBSERVER_CONF_TICTACTOE 0 //Needs passquery of at least 10 chars
#define WEBSERVER_CONF_AJAX 0 #define WEBSERVER_CONF_AJAX 0
//#define WEBSERVER_CONF_PASSQUERY 10 //#define WEBSERVER_CONF_PASSQUERY 10
@ -114,6 +117,7 @@ extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
/* Include referrer in log */ /* Include referrer in log */
#define WEBSERVER_CONF_REFERER 0 #define WEBSERVER_CONF_REFERER 0
/*-----------------------------------------------------------------------------*/
#elif WEBSERVER_CONF_NANO==2 #elif WEBSERVER_CONF_NANO==2
/* webserver-mini having more content */ /* webserver-mini having more content */
#define WEBSERVER_CONF_CONNS 2 #define WEBSERVER_CONF_CONNS 2
@ -136,28 +140,32 @@ extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
#define WEBSERVER_CONF_PROCESSES 1 #define WEBSERVER_CONF_PROCESSES 1
#define WEBSERVER_CONF_ADDRESSES 1 #define WEBSERVER_CONF_ADDRESSES 1
#define WEBSERVER_CONF_NEIGHBORS 1 #define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_NEIGHBOR_STATUS 1
#define WEBSERVER_CONF_ROUTES 1 #define WEBSERVER_CONF_ROUTES 1
#define WEBSERVER_CONF_ROUTE_LINKS 1
#define WEBSERVER_CONF_SENSORS 1 #define WEBSERVER_CONF_SENSORS 1
#define WEBSERVER_CONF_STATISTICS 1
//#define WEBSERVER_CONF_TICTACTOE 1 //Needs passquery of at least 10 chars //#define WEBSERVER_CONF_TICTACTOE 1 //Needs passquery of at least 10 chars
#define WEBSERVER_CONF_AJAX 1 #define WEBSERVER_CONF_AJAX 1
#define WEBSERVER_CONF_SHOW_ROOM 0
//#define WEBSERVER_CONF_PASSQUERY 10 //#define WEBSERVER_CONF_PASSQUERY 10
#if WEBSERVER_CONF_PASSQUERY #if WEBSERVER_CONF_PASSQUERY
extern char httpd_query[WEBSERVER_CONF_PASSQUERY]; extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
#endif #endif
/* Enable specific file types */ /* Enable specific file types */
#define WEBSERVER_CONF_JPG 1 #define WEBSERVER_CONF_JPG 0
#define WEBSERVER_CONF_PNG 1 #define WEBSERVER_CONF_PNG 0
#define WEBSERVER_CONF_GIF 1 #define WEBSERVER_CONF_GIF 0
#define WEBSERVER_CONF_TXT 1 #define WEBSERVER_CONF_TXT 1
#define WEBSERVER_CONF_CSS 1 #define WEBSERVER_CONF_CSS 0
#define WEBSERVER_CONF_BIN 1 #define WEBSERVER_CONF_BIN 0
/* Log page accesses */ /* Log page accesses */
#define WEBSERVER_CONF_LOG 1 #define WEBSERVER_CONF_LOG 0
/* Include referrer in log */ /* Include referrer in log */
#define WEBSERVER_CONF_REFERER 1 #define WEBSERVER_CONF_REFERER 1
/*-----------------------------------------------------------------------------*/
#elif WEBSERVER_CONF_NANO==3 #elif WEBSERVER_CONF_NANO==3
/* webserver-mini having all content */ /* webserver-mini having all content */
#define WEBSERVER_CONF_CONNS 6 #define WEBSERVER_CONF_CONNS 6
@ -181,7 +189,12 @@ extern char httpd_query[WEBSERVER_CONF_PASSQUERY];
#define WEBSERVER_CONF_ADDRESSES 1 #define WEBSERVER_CONF_ADDRESSES 1
#define WEBSERVER_CONF_NEIGHBORS 1 #define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_ROUTES 1 #define WEBSERVER_CONF_ROUTES 1
#define WEBSERVER_CONF_NEIGHBORS 1
#define WEBSERVER_CONF_NEIGHBOR_STATUS 1
#define WEBSERVER_CONF_ROUTES 1
#define WEBSERVER_CONF_ROUTE_LINKS 1
#define WEBSERVER_CONF_SENSORS 1 #define WEBSERVER_CONF_SENSORS 1
#define WEBSERVER_CONF_STATISTICS 1
#define WEBSERVER_CONF_TICTACTOE 1 //Needs passquery of at least 10 chars #define WEBSERVER_CONF_TICTACTOE 1 //Needs passquery of at least 10 chars
#define WEBSERVER_CONF_AJAX 1 #define WEBSERVER_CONF_AJAX 1
#define WEBSERVER_CONF_PASSQUERY 10 #define WEBSERVER_CONF_PASSQUERY 10
@ -272,6 +285,9 @@ struct httpd_state {
#if WEBSERVER_CONF_LOADTIME #if WEBSERVER_CONF_LOADTIME
clock_time_t pagetime; clock_time_t pagetime;
#endif #endif
#if WEBSERVER_CONF_NEIGHBORS || WEBSERVER_CONF_ROUTES
uint8_t starti,savei,startj,savej;
#endif
#if WEBSERVER_CONF_CGI #if WEBSERVER_CONF_CGI
union { union {
unsigned short count; unsigned short count;

View file

@ -535,6 +535,12 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_
struct hdr *chdr; struct hdr *chdr;
#endif /* WITH_CONTIKIMAC_HEADER */ #endif /* WITH_CONTIKIMAC_HEADER */
/* Exit if RDC and radio were explicitly turned off */
if (!contikimac_is_on && !contikimac_keep_radio_on) {
PRINTF("contikimac: radio is turned off\n");
return MAC_TX_ERR_FATAL;
}
if(packetbuf_totlen() == 0) { if(packetbuf_totlen() == 0) {
PRINTF("contikimac: send_packet data len 0\n"); PRINTF("contikimac: send_packet data len 0\n");
return MAC_TX_ERR_FATAL; return MAC_TX_ERR_FATAL;

View file

@ -62,11 +62,11 @@ extern rpl_of_t RPL_OF;
static rpl_of_t * const objective_functions[] = {&RPL_OF}; static rpl_of_t * const objective_functions[] = {&RPL_OF};
/************************************************************************/ /************************************************************************/
#ifndef RPL_CONF_MAX_PARENTS_PER_DODAG #ifndef RPL_CONF_MAX_PARENTS_PER_DAG
#define RPL_MAX_PARENTS_PER_DODAG 8 #define RPL_MAX_PARENTS_PER_DAG 8
#else #else
#define RPL_MAX_PARENTS_PER_DODAG RPL_CONF_MAX_PARENTS_PER_DODAG #define RPL_MAX_PARENTS_PER_DAG RPL_CONF_MAX_PARENTS_PER_DAG
#endif /* !RPL_CONF_MAX_PARENTS */ #endif /* !RPL_CONF_MAX_PARENTS_PER_DAG */
/************************************************************************/ /************************************************************************/
/* RPL definitions. */ /* RPL definitions. */
@ -77,30 +77,16 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF};
#define RPL_GROUNDED RPL_CONF_GROUNDED #define RPL_GROUNDED RPL_CONF_GROUNDED
#endif /* !RPL_CONF_GROUNDED */ #endif /* !RPL_CONF_GROUNDED */
#ifndef RPL_CONF_DIO_INTERVAL_MIN
#define RPL_DIO_INTERVAL_MIN DEFAULT_DIO_INTERVAL_MIN
#else
#define RPL_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN
#endif /* !RPL_CONF_DIO_INTERVAL_MIN */
#ifndef RPL_CONF_DIO_INTERVAL_DOUBLINGS
#define RPL_DIO_INTERVAL_DOUBLINGS DEFAULT_DIO_INTERVAL_DOUBLINGS
#else
#define RPL_DIO_INTERVAL_DOUBLINGS RPL_CONF_DIO_INTERVAL_DOUBLINGS
#endif /* !RPL_CONF_DIO_INTERVAL_DOUBLINGS */
/************************************************************************/ /************************************************************************/
/* Allocate parents from the same static MEMB chunk to reduce memory waste. */ /* Allocate parents from the same static MEMB chunk to reduce memory waste. */
MEMB(parent_memb, struct rpl_parent, MEMB(parent_memb, struct rpl_parent,
RPL_MAX_PARENTS_PER_DODAG * RPL_MAX_INSTANCES * RPL_MAX_DODAG_PER_INSTANCE); RPL_MAX_PARENTS_PER_DAG * RPL_MAX_INSTANCES * RPL_MAX_DAG_PER_INSTANCE);
/************************************************************************/ /************************************************************************/
/* Allocate instance table. */ /* Allocate instance table. */
rpl_instance_t instance_table[RPL_MAX_INSTANCES]; rpl_instance_t instance_table[RPL_MAX_INSTANCES];
rpl_instance_t *default_instance; rpl_instance_t *default_instance;
/************************************************************************/ /************************************************************************/
/* lollipop greater than function. */ /* Greater-than function for the lollipop counter. */
/************************************************************************/ /************************************************************************/
int rpl_lollipop_greater_than(int a, int b) { int rpl_lollipop_greater_than(int a, int b) {
/* Check if we are comparing an initial value with an old value */ /* Check if we are comparing an initial value with an old value */
@ -113,7 +99,6 @@ int rpl_lollipop_greater_than(int a, int b) {
(a < b && (b - a) > (RPL_LOLLIPOP_CIRCULAR_REGION + 1- (a < b && (b - a) > (RPL_LOLLIPOP_CIRCULAR_REGION + 1-
RPL_LOLLIPOP_SEQUENCE_WINDOWS)); RPL_LOLLIPOP_SEQUENCE_WINDOWS));
} }
/************************************************************************/ /************************************************************************/
/* Remove DAG parents with a rank that is at least the same as minimum_rank. */ /* Remove DAG parents with a rank that is at least the same as minimum_rank. */
static void static void
@ -225,15 +210,15 @@ rpl_set_root(uint8_t instance_id, uip_ipaddr_t *dag_id)
memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id)); memcpy(&dag->dag_id, dag_id, sizeof(dag->dag_id));
instance->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS; instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
instance->dio_intmin = DEFAULT_DIO_INTERVAL_MIN; instance->dio_intmin = RPL_DIO_INTERVAL_MIN;
/* The current interval must differ from the minimum interval in order to /* The current interval must differ from the minimum interval in order to
trigger a DIO timer reset. */ trigger a DIO timer reset. */
instance->dio_intcurrent = DEFAULT_DIO_INTERVAL_MIN + instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN +
DEFAULT_DIO_INTERVAL_DOUBLINGS; RPL_DIO_INTERVAL_DOUBLINGS;
instance->dio_redundancy = DEFAULT_DIO_REDUNDANCY; instance->dio_redundancy = RPL_DIO_REDUNDANCY;
instance->max_rankinc = DEFAULT_MAX_RANKINC; instance->max_rankinc = RPL_MAX_RANKINC;
instance->min_hoprankinc = DEFAULT_MIN_HOPRANKINC; instance->min_hoprankinc = RPL_MIN_HOPRANKINC;
instance->default_lifetime = RPL_DEFAULT_LIFETIME; instance->default_lifetime = RPL_DEFAULT_LIFETIME;
instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT; instance->lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
@ -409,7 +394,7 @@ rpl_alloc_dodag(uint8_t instance_id, uip_ipaddr_t *dag_id)
return dag; return dag;
} }
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(!dag->used) { if(!dag->used) {
memset(dag, 0, sizeof(*dag)); memset(dag, 0, sizeof(*dag));
dag->parents = &dag->parent_list; dag->parents = &dag->parent_list;
@ -438,8 +423,8 @@ rpl_free_instance(rpl_instance_t *instance)
PRINTF("RPL: Leaving the instance %u\n", instance->instance_id); PRINTF("RPL: Leaving the instance %u\n", instance->instance_id);
/* Remove any DODAG inside this instance */ /* Remove any DAG inside this instance */
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used) { if(dag->used) {
rpl_free_dodag(dag); rpl_free_dodag(dag);
} }
@ -519,7 +504,7 @@ find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
rpl_parent_t *p; rpl_parent_t *p;
rpl_dag_t *dag, *end; rpl_dag_t *dag, *end;
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used) { if(dag->used) {
for(p = list_head(dag->parents); p != NULL; p = p->next) { for(p = list_head(dag->parents); p != NULL; p = p->next) {
if(uip_ipaddr_cmp(&p->addr, addr)) { if(uip_ipaddr_cmp(&p->addr, addr)) {
@ -537,7 +522,7 @@ rpl_find_parent_any_dag(rpl_instance_t *instance, uip_ipaddr_t *addr)
rpl_parent_t *p; rpl_parent_t *p;
rpl_dag_t *dag, *end; rpl_dag_t *dag, *end;
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used) { if(dag->used) {
for(p = list_head(dag->parents); p != NULL; p = p->next) { for(p = list_head(dag->parents); p != NULL; p = p->next) {
if(uip_ipaddr_cmp(&p->addr, addr)) { if(uip_ipaddr_cmp(&p->addr, addr)) {
@ -567,7 +552,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p)
} }
} else if(p->dag == best_dag) { } else if(p->dag == best_dag) {
best_dag = NULL; best_dag = NULL;
for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) {
if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) { if(dag->used && dag->preferred_parent != NULL && dag->preferred_parent->rank != INFINITE_RANK) {
if(best_dag == NULL) { if(best_dag == NULL) {
best_dag = dag; best_dag = dag;
@ -588,7 +573,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p)
/* Remove routes installed by DAOs. */ /* Remove routes installed by DAOs. */
rpl_remove_routes(instance->current_dag); rpl_remove_routes(instance->current_dag);
PRINTF("RPL: New preferred DODAG: "); PRINTF("RPL: New preferred DAG: ");
PRINT6ADDR(&best_dag->dag_id); PRINT6ADDR(&best_dag->dag_id);
PRINTF("\n"); PRINTF("\n");
@ -613,7 +598,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p)
instance->current_dag->preferred_parent = NULL; instance->current_dag->preferred_parent = NULL;
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) { if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) {
/* Send a No-Path DAO to the removed preferred parent. */ /* Send a No-Path DAO to the removed preferred parent. */
dao_output(last_parent, ZERO_LIFETIME); dao_output(last_parent, RPL_ZERO_LIFETIME);
} }
return NULL; return NULL;
} }
@ -626,7 +611,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p)
if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) {
if(last_parent != NULL) { if(last_parent != NULL) {
/* Send a No-Path DAO to the removed preferred parent. */ /* Send a No-Path DAO to the removed preferred parent. */
dao_output(last_parent, ZERO_LIFETIME); dao_output(last_parent, RPL_ZERO_LIFETIME);
} }
/* The DAO parent set changed - schedule a DAO transmission. */ /* The DAO parent set changed - schedule a DAO transmission. */
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
@ -692,7 +677,7 @@ rpl_nullify_parent(rpl_dag_t *dag, rpl_parent_t *parent)
} }
dag->instance->def_route = NULL; dag->instance->def_route = NULL;
} }
dao_output(parent, ZERO_LIFETIME); dao_output(parent, RPL_ZERO_LIFETIME);
} }
} }
@ -768,7 +753,7 @@ rpl_get_dodag(uint8_t instance_id, uip_ipaddr_t *dag_id)
return NULL; return NULL;
} }
for(i = 0; i < RPL_MAX_DODAG_PER_INSTANCE; ++i) { for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; ++i) {
dag = &instance->dag_table[i]; dag = &instance->dag_table[i];
if(dag->used && uip_ipaddr_cmp(&dag->dag_id, dag_id)) { if(dag->used && uip_ipaddr_cmp(&dag->dag_id, dag_id)) {
return dag; return dag;
@ -1003,7 +988,7 @@ rpl_local_repair(rpl_instance_t *instance)
int i; int i;
PRINTF("RPL: Starting a local instance repair\n"); PRINTF("RPL: Starting a local instance repair\n");
for(i = 0; i < RPL_MAX_DODAG_PER_INSTANCE; i++) { for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
if(instance->dag_table[i].used) { if(instance->dag_table[i].used) {
instance->dag_table[i].rank = INFINITE_RANK; instance->dag_table[i].rank = INFINITE_RANK;
nullify_parents(&instance->dag_table[i], 0); nullify_parents(&instance->dag_table[i], 0);
@ -1029,7 +1014,7 @@ rpl_recalculate_ranks(void)
*/ */
for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) { for(instance = &instance_table[0], end = instance + RPL_MAX_INSTANCES; instance < end; ++instance) {
if(instance->used) { if(instance->used) {
for(i = 0; i < RPL_MAX_DODAG_PER_INSTANCE; i++) { for(i = 0; i < RPL_MAX_DAG_PER_INSTANCE; i++) {
if(instance->dag_table[i].used) { if(instance->dag_table[i].used) {
for(p = list_head(instance->dag_table[i].parents); p != NULL; p = p->next) { for(p = list_head(instance->dag_table[i].parents); p != NULL; p = p->next) {
if(p->updated) { if(p->updated) {
@ -1190,7 +1175,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
if(p == NULL) { if(p == NULL) {
previous_dag = find_parent_dag(instance, from); previous_dag = find_parent_dag(instance, from);
if(previous_dag == NULL) { if(previous_dag == NULL) {
if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DODAG) { if(RPL_PARENT_COUNT(dag) == RPL_MAX_PARENTS_PER_DAG) {
/* Make room for a new parent. */ /* Make room for a new parent. */
remove_worst_parent(dag, dio->rank); remove_worst_parent(dag, dio->rank);
} }
@ -1222,7 +1207,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio)
} }
} }
PRINTF("RPL: preferred DODAG "); PRINTF("RPL: preferred DAG ");
PRINT6ADDR(&instance->current_dag->dag_id); PRINT6ADDR(&instance->current_dag->dag_id);
PRINTF(", rank %u, min_rank %u, ", PRINTF(", rank %u, min_rank %u, ",
instance->current_dag->rank, instance->current_dag->min_rank); instance->current_dag->rank, instance->current_dag->min_rank);

View file

@ -92,6 +92,8 @@ void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *);
void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *);
#endif #endif
extern rpl_of_t RPL_OF;
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static int static int
get_global_addr(uip_ipaddr_t *addr) get_global_addr(uip_ipaddr_t *addr)
@ -209,9 +211,15 @@ dio_input(void)
memset(&dio, 0, sizeof(dio)); memset(&dio, 0, sizeof(dio));
dio.dag_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS; /* Set default values in case the DIO configuration option is missing. */
dio.dag_intmin = DEFAULT_DIO_INTERVAL_MIN; dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS;
dio.dag_redund = DEFAULT_DIO_REDUNDANCY; dio.dag_intmin = RPL_DIO_INTERVAL_MIN;
dio.dag_redund = RPL_DIO_REDUNDANCY;
dio.dag_min_hoprankinc = RPL_MIN_HOPRANKINC;
dio.dag_max_rankinc = RPL_MAX_RANKINC;
dio.ocp = RPL_OF.ocp;
dio.default_lifetime = RPL_DEFAULT_LIFETIME;
dio.lifetime_unit = RPL_DEFAULT_LIFETIME_UNIT;
uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr); uip_ipaddr_copy(&from, &UIP_IP_BUF->srcipaddr);
@ -251,8 +259,10 @@ dio_input(void)
dio.rank = get16(buffer, i); dio.rank = get16(buffer, i);
i += 2; i += 2;
PRINTF("RPL: Incoming DIO InstanceID-Version %u-%u\n", (unsigned)dio.instance_id,(unsigned)dio.version); PRINTF("RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n",
PRINTF("RPL: Incoming DIO rank %u\n", (unsigned)dio.rank); (unsigned)dio.instance_id,
(unsigned)dio.version,
(unsigned)dio.rank);
dio.grounded = buffer[i] & RPL_DIO_GROUNDED; dio.grounded = buffer[i] & RPL_DIO_GROUNDED;
dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT; dio.mop = (buffer[i]& RPL_DIO_MOP_MASK) >> RPL_DIO_MOP_SHIFT;
@ -265,9 +275,9 @@ dio_input(void)
memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id)); memcpy(&dio.dag_id, buffer + i, sizeof(dio.dag_id));
i += sizeof(dio.dag_id); i += sizeof(dio.dag_id);
PRINTF("RPL: Incoming DIO DODAG "); PRINTF("RPL: Incoming DIO (dag_id, pref) = (");
PRINT6ADDR(&dio.dag_id); PRINT6ADDR(&dio.dag_id);
PRINTF(", preference: %u\n", dio.preference); PRINTF(", %u)\n", dio.preference);
/* Check if there are any DIO suboptions. */ /* Check if there are any DIO suboptions. */
for(; i < buffer_length; i += len) { for(; i < buffer_length; i += len) {
@ -326,7 +336,7 @@ dio_input(void)
return; return;
} }
/* flags is both preference and flags for now */ /* The flags field includes the preference value. */
dio.destination_prefix.length = buffer[i + 2]; dio.destination_prefix.length = buffer[i + 2];
dio.destination_prefix.flags = buffer[i + 3]; dio.destination_prefix.flags = buffer[i + 3];
dio.destination_prefix.lifetime = get32(buffer, i + 4); dio.destination_prefix.lifetime = get32(buffer, i + 4);
@ -337,7 +347,7 @@ dio_input(void)
memcpy(&dio.destination_prefix.prefix, &buffer[i + 8], memcpy(&dio.destination_prefix.prefix, &buffer[i + 8],
(dio.destination_prefix.length + 7) / 8); (dio.destination_prefix.length + 7) / 8);
} else { } else {
PRINTF("RPL: Invalid route infoprefix option, len = %d\n", len); PRINTF("RPL: Invalid route info option, len = %d\n", len);
RPL_STAT(rpl_stats.malformed_msgs++); RPL_STAT(rpl_stats.malformed_msgs++);
return; return;
} }
@ -360,14 +370,14 @@ dio_input(void)
/* buffer + 12 is reserved */ /* buffer + 12 is reserved */
dio.default_lifetime = buffer[i + 13]; dio.default_lifetime = buffer[i + 13];
dio.lifetime_unit = get16(buffer, i + 14); dio.lifetime_unit = get16(buffer, i + 14);
PRINTF("RPL: DIO Conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n", PRINTF("RPL: DAG conf:dbl=%d, min=%d red=%d maxinc=%d mininc=%d ocp=%d d_l=%u l_u=%u\n",
dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund, dio.dag_intdoubl, dio.dag_intmin, dio.dag_redund,
dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp, dio.dag_max_rankinc, dio.dag_min_hoprankinc, dio.ocp,
dio.default_lifetime, dio.lifetime_unit); dio.default_lifetime, dio.lifetime_unit);
break; break;
case RPL_OPTION_PREFIX_INFO: case RPL_OPTION_PREFIX_INFO:
if(len != 32) { if(len != 32) {
PRINTF("RPL: DAG Prefix info not ok, len != 32\n"); PRINTF("RPL: DAG prefix info not ok, len != 32\n");
RPL_STAT(rpl_stats.malformed_msgs++); RPL_STAT(rpl_stats.malformed_msgs++);
return; return;
} }
@ -398,6 +408,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
{ {
unsigned char *buffer; unsigned char *buffer;
int pos; int pos;
rpl_dag_t *dag = instance->current_dag;
#if !RPL_LEAF_ONLY #if !RPL_LEAF_ONLY
uip_ipaddr_t addr; uip_ipaddr_t addr;
#endif /* !RPL_LEAF_ONLY */ #endif /* !RPL_LEAF_ONLY */
@ -409,8 +420,6 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
} }
#endif /* RPL_LEAF_ONLY */ #endif /* RPL_LEAF_ONLY */
rpl_dag_t *dag = instance->current_dag;
/* DAG Information Object */ /* DAG Information Object */
pos = 0; pos = 0;
@ -436,9 +445,8 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr)
buffer[pos++] = instance->dtsn_out; buffer[pos++] = instance->dtsn_out;
if(RPL_LOLLIPOP_IS_INIT(instance->dtsn_out)) { /* always request new DAO to refresh route */
RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); RPL_LOLLIPOP_INCREMENT(instance->dtsn_out);
}
/* reserved 2 bytes */ /* reserved 2 bytes */
buffer[pos++] = 0; /* flags */ buffer[pos++] = 0; /* flags */
@ -597,7 +605,7 @@ dao_input(void)
/* Is the DAGID present? */ /* Is the DAGID present? */
if(flags & RPL_DAO_D_FLAG) { if(flags & RPL_DAO_D_FLAG) {
if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) { if(memcmp(&dag->dag_id, &buffer[pos], sizeof(dag->dag_id))) {
PRINTF("RPL: Ignoring a DAO for a DODAG different from ours\n"); PRINTF("RPL: Ignoring a DAO for a DAG different from ours\n");
return; return;
} }
pos += 16; pos += 16;
@ -640,7 +648,7 @@ dao_input(void)
rep = uip_ds6_route_lookup(&prefix); rep = uip_ds6_route_lookup(&prefix);
if(lifetime == ZERO_LIFETIME) { if(lifetime == RPL_ZERO_LIFETIME) {
/* No-Path DAO received; invoke the route purging routine. */ /* No-Path DAO received; invoke the route purging routine. */
if(rep != NULL && rep->state.saved_lifetime == 0 && rep->length == prefixlen) { if(rep != NULL && rep->state.saved_lifetime == 0 && rep->length == prefixlen) {
PRINTF("RPL: Setting expiration timer for prefix "); PRINTF("RPL: Setting expiration timer for prefix ");
@ -733,19 +741,19 @@ dao_output(rpl_parent_t *n, uint8_t lifetime)
buffer[pos++] = instance->instance_id; buffer[pos++] = instance->instance_id;
buffer[pos] = 0; buffer[pos] = 0;
#if RPL_DAO_SPECIFY_DODAG #if RPL_DAO_SPECIFY_DAG
buffer[pos] |= RPL_DAO_D_FLAG; buffer[pos] |= RPL_DAO_D_FLAG;
#endif /* RPL_DAO_SPECIFY_DODAG */ #endif /* RPL_DAO_SPECIFY_DAG */
#if RPL_CONF_DAO_ACK #if RPL_CONF_DAO_ACK
buffer[pos] |= RPL_DAO_K_FLAG; buffer[pos] |= RPL_DAO_K_FLAG;
#endif /* RPL_CONF_DAO_ACK */ #endif /* RPL_CONF_DAO_ACK */
++pos; ++pos;
buffer[pos++] = 0; /* reserved */ buffer[pos++] = 0; /* reserved */
buffer[pos++] = dao_sequence; buffer[pos++] = dao_sequence;
#if RPL_DAO_SPECIFY_DODAG #if RPL_DAO_SPECIFY_DAG
memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id)); memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id));
pos+=sizeof(dag->dag_id); pos+=sizeof(dag->dag_id);
#endif /* RPL_DAO_SPECIFY_DODAG */ #endif /* RPL_DAO_SPECIFY_DAG */
/* create target subopt */ /* create target subopt */
prefixlen = sizeof(prefix) * CHAR_BIT; prefixlen = sizeof(prefix) * CHAR_BIT;

View file

@ -112,7 +112,7 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
if(base_rank == 0) { if(base_rank == 0) {
return INFINITE_RANK; return INFINITE_RANK;
} }
rank_increase = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) * DEFAULT_MIN_HOPRANKINC; rank_increase = NEIGHBOR_INFO_FIX2ETX(INITIAL_LINK_METRIC) * RPL_MIN_HOPRANKINC;
} else { } else {
/* multiply first, then scale down to avoid truncation effects */ /* multiply first, then scale down to avoid truncation effects */
rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric * p->dag->instance->min_hoprankinc); rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric * p->dag->instance->min_hoprankinc);

View file

@ -50,7 +50,7 @@ static void reset(rpl_dag_t *);
static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *); static rpl_parent_t *best_parent(rpl_parent_t *, rpl_parent_t *);
static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *); static rpl_dag_t *best_dag(rpl_dag_t *, rpl_dag_t *);
static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t); static rpl_rank_t calculate_rank(rpl_parent_t *, rpl_rank_t);
static void update_metric_container(rpl_dag_t *); static void update_metric_container(rpl_instance_t *);
rpl_of_t rpl_of0 = { rpl_of_t rpl_of0 = {
reset, reset,
@ -62,7 +62,7 @@ rpl_of_t rpl_of0 = {
0 0
}; };
#define DEFAULT_RANK_INCREMENT DEFAULT_MIN_HOPRANKINC #define DEFAULT_RANK_INCREMENT RPL_MIN_HOPRANKINC
#define MIN_DIFFERENCE (NEIGHBOR_INFO_ETX_DIVISOR + NEIGHBOR_INFO_ETX_DIVISOR / 2) #define MIN_DIFFERENCE (NEIGHBOR_INFO_ETX_DIVISOR + NEIGHBOR_INFO_ETX_DIVISOR / 2)
@ -83,7 +83,9 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank)
base_rank = p->rank; base_rank = p->rank;
} }
increment = p != NULL ? p->dag->min_hoprankinc : DEFAULT_RANK_INCREMENT; increment = p != NULL ?
p->dag->instance->min_hoprankinc :
DEFAULT_RANK_INCREMENT;
if((rpl_rank_t)(base_rank + increment) < base_rank) { if((rpl_rank_t)(base_rank + increment) < base_rank) {
PRINTF("RPL: OF0 rank %d incremented to infinite rank due to wrapping\n", PRINTF("RPL: OF0 rank %d incremented to infinite rank due to wrapping\n",
@ -135,9 +137,9 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2)
p2->link_metric, p2->rank); p2->link_metric, p2->rank);
r1 = DAG_RANK(p1->rank, (rpl_dag_t *)p1->dag) * NEIGHBOR_INFO_ETX_DIVISOR + r1 = DAG_RANK(p1->rank, p1->dag->instance) * NEIGHBOR_INFO_ETX_DIVISOR +
p1->link_metric; p1->link_metric;
r2 = DAG_RANK(p2->rank, (rpl_dag_t *)p1->dag) * NEIGHBOR_INFO_ETX_DIVISOR + r2 = DAG_RANK(p2->rank, p1->dag->instance) * NEIGHBOR_INFO_ETX_DIVISOR +
p2->link_metric; p2->link_metric;
/* Compare two parents by looking both and their rank and at the ETX /* Compare two parents by looking both and their rank and at the ETX
for that parent. We choose the parent that has the most for that parent. We choose the parent that has the most

View file

@ -110,10 +110,10 @@
/* Default values for RPL constants and variables. */ /* Default values for RPL constants and variables. */
/* The default value for the DAO timer. */ /* The default value for the DAO timer. */
#define DEFAULT_DAO_LATENCY (CLOCK_SECOND * 8) #define RPL_DAO_LATENCY (CLOCK_SECOND * 4)
/* Special value indicating immediate removal. */ /* Special value indicating immediate removal. */
#define ZERO_LIFETIME 0 #define RPL_ZERO_LIFETIME 0
/* Default route lifetime unit. */ /* Default route lifetime unit. */
#define RPL_DEFAULT_LIFETIME_UNIT 0xffff #define RPL_DEFAULT_LIFETIME_UNIT 0xffff
@ -125,13 +125,14 @@
((unsigned long)(instance)->lifetime_unit * (lifetime)) ((unsigned long)(instance)->lifetime_unit * (lifetime))
#ifndef RPL_CONF_MIN_HOPRANKINC #ifndef RPL_CONF_MIN_HOPRANKINC
#define DEFAULT_MIN_HOPRANKINC 256 #define RPL_MIN_HOPRANKINC 256
#else #else
#define DEFAULT_MIN_HOPRANKINC RPL_CONF_MIN_HOPRANKINC #define RPL_MIN_HOPRANKINC RPL_CONF_MIN_HOPRANKINC
#endif #endif
#define DEFAULT_MAX_RANKINC (7 * DEFAULT_MIN_HOPRANKINC) #define RPL_MAX_RANKINC (7 * RPL_MIN_HOPRANKINC)
#define DAG_RANK(fixpt_rank, instance) ((fixpt_rank) / (instance)->min_hoprankinc) #define DAG_RANK(fixpt_rank, instance) \
((fixpt_rank) / (instance)->min_hoprankinc)
/* Rank of a virtual root node that coordinates DAG root nodes. */ /* Rank of a virtual root node that coordinates DAG root nodes. */
#define BASE_RANK 0 #define BASE_RANK 0
@ -148,23 +149,23 @@
means 8 milliseconds, but that is an unreasonable value if means 8 milliseconds, but that is an unreasonable value if
using power-saving / duty-cycling */ using power-saving / duty-cycling */
#ifdef RPL_CONF_DIO_INTERVAL_MIN #ifdef RPL_CONF_DIO_INTERVAL_MIN
#define DEFAULT_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN #define RPL_DIO_INTERVAL_MIN RPL_CONF_DIO_INTERVAL_MIN
#else #else
#define DEFAULT_DIO_INTERVAL_MIN 12 #define RPL_DIO_INTERVAL_MIN 12
#endif #endif
/* Maximum amount of timer doublings. */ /* Maximum amount of timer doublings. */
#ifdef RPL_CONF_DIO_INTERVAL_DOUBLINGS #ifdef RPL_CONF_DIO_INTERVAL_DOUBLINGS
#define DEFAULT_DIO_INTERVAL_DOUBLINGS RPL_CONF_DIO_INTERVAL_DOUBLINGS #define RPL_DIO_INTERVAL_DOUBLINGS RPL_CONF_DIO_INTERVAL_DOUBLINGS
#else #else
#define DEFAULT_DIO_INTERVAL_DOUBLINGS 8 #define RPL_DIO_INTERVAL_DOUBLINGS 8
#endif #endif
/* Default DIO redundancy. */ /* Default DIO redundancy. */
#ifdef RPL_CONF_DIO_REDUNDANCY #ifdef RPL_CONF_DIO_REDUNDANCY
#define DEFAULT_DIO_REDUNDANCY RPL_CONF_DIO_REDUNDANCY #define RPL_DIO_REDUNDANCY RPL_CONF_DIO_REDUNDANCY
#else #else
#define DEFAULT_DIO_REDUNDANCY 10 #define RPL_DIO_REDUNDANCY 10
#endif #endif
/* Expire DAOs from neighbors that do not respond in this time. (seconds) */ /* Expire DAOs from neighbors that do not respond in this time. (seconds) */
@ -207,6 +208,20 @@
#endif #endif
#define RPL_DIS_START_DELAY 5 #define RPL_DIS_START_DELAY 5
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* Lollipop counters */
#define RPL_LOLLIPOP_MAX_VALUE 255
#define RPL_LOLLIPOP_CIRCULAR_REGION 127
#define RPL_LOLLIPOP_SEQUENCE_WINDOWS 16
#define RPL_LOLLIPOP_INIT (RPL_LOLLIPOP_MAX_VALUE - RPL_LOLLIPOP_SEQUENCE_WINDOWS + 1)
#define RPL_LOLLIPOP_INCREMENT(counter) \
((counter) > RPL_LOLLIPOP_CIRCULAR_REGION ? \
++(counter) & RPL_LOLLIPOP_MAX_VALUE : \
++(counter) & RPL_LOLLIPOP_CIRCULAR_REGION)
#define RPL_LOLLIPOP_IS_INIT(counter) \
((counter) > RPL_LOLLIPOP_CIRCULAR_REGION)
/*---------------------------------------------------------------------------*/
/* Logical representation of a DAG Information Object (DIO.) */ /* Logical representation of a DAG Information Object (DIO.) */
struct rpl_dio { struct rpl_dio {
uip_ipaddr_t dag_id; uip_ipaddr_t dag_id;

View file

@ -225,8 +225,8 @@ rpl_schedule_dao(rpl_instance_t *instance)
if(!etimer_expired(&instance->dao_timer.etimer)) { if(!etimer_expired(&instance->dao_timer.etimer)) {
PRINTF("RPL: DAO timer already scheduled\n"); PRINTF("RPL: DAO timer already scheduled\n");
} else { } else {
expiration_time = DEFAULT_DAO_LATENCY / 2 + expiration_time = RPL_DAO_LATENCY / 2 +
(random_rand() % (DEFAULT_DAO_LATENCY)); (random_rand() % (RPL_DAO_LATENCY));
PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n", PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n",
(unsigned)expiration_time); (unsigned)expiration_time);
ctimer_set(&instance->dao_timer, expiration_time, ctimer_set(&instance->dao_timer, expiration_time,

View file

@ -97,24 +97,24 @@
/* /*
* Maximum of concurent dodag inside an instance * Maximum of concurent dodag inside an instance
*/ */
#ifndef RPL_CONF_MAX_DODAG_PER_INSTANCE #ifndef RPL_CONF_MAX_DAG_PER_INSTANCE
#define RPL_MAX_DODAG_PER_INSTANCE 2 #define RPL_MAX_DAG_PER_INSTANCE 2
#else #else
#define RPL_MAX_DODAG_PER_INSTANCE RPL_CONF_MAX_DODAG_PER_INSTANCE #define RPL_MAX_DAG_PER_INSTANCE RPL_CONF_MAX_DAG_PER_INSTANCE
#endif /* !RPL_CONF_MAX_DODAG_PER_INSTANCE */ #endif /* !RPL_CONF_MAX_DAG_PER_INSTANCE */
/* /*
* *
*/ */
#ifndef RPL_CONF_DAO_SPECIFY_DODAG #ifndef RPL_CONF_DAO_SPECIFY_DAG
#if RPL_MAX_DODAG_PER_INSTANCE > 1 #if RPL_MAX_DAG_PER_INSTANCE > 1
#define RPL_DAO_SPECIFY_DODAG 1 #define RPL_DAO_SPECIFY_DAG 1
#else /* RPL_MAX_DODAG_PER_INSTANCE > 1*/ #else /* RPL_MAX_DAG_PER_INSTANCE > 1*/
#define RPL_DAO_SPECIFY_DODAG 0 #define RPL_DAO_SPECIFY_DAG 0
#endif /* RPL_MAX_DODAG_PER_INSTANCE > 1 */ #endif /* RPL_MAX_DAG_PER_INSTANCE > 1 */
#else /* RPL_CONF_DAO_SPECIFY_DODAG */ #else /* RPL_CONF_DAO_SPECIFY_DAG */
#define RPL_DAO_SPECIFY_DODAG RPL_CONF_DAO_SPECIFY_DODAG #define RPL_DAO_SPECIFY_DAG RPL_CONF_DAO_SPECIFY_DAG
#endif /* RPL_CONF_DAO_SPECIFY_DODAG */ #endif /* RPL_CONF_DAO_SPECIFY_DAG */
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -123,20 +123,6 @@
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
typedef uint16_t rpl_rank_t; typedef uint16_t rpl_rank_t;
typedef uint16_t rpl_ocp_t; typedef uint16_t rpl_ocp_t;
/*---------------------------------------------------------------------------*/
/* Lollipop counters */
#define RPL_LOLLIPOP_MAX_VALUE 255
#define RPL_LOLLIPOP_CIRCULAR_REGION 127
#define RPL_LOLLIPOP_SEQUENCE_WINDOWS 16
#define RPL_LOLLIPOP_INIT RPL_LOLLIPOP_MAX_VALUE - RPL_LOLLIPOP_SEQUENCE_WINDOWS + 1
#define RPL_LOLLIPOP_INCREMENT(ctr) (ctr > RPL_LOLLIPOP_CIRCULAR_REGION ? \
++ctr & RPL_LOLLIPOP_MAX_VALUE : \
++ctr & RPL_LOLLIPOP_CIRCULAR_REGION)
#define RPL_LOLLIPOP_IS_INIT(counter) (counter > RPL_LOLLIPOP_CIRCULAR_REGION)
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
/* DAG Metric Container Object Types, to be confirmed by IANA. */ /* DAG Metric Container Object Types, to be confirmed by IANA. */
#define RPL_DAG_MC_NONE 0 /* Local identifier for empty MC */ #define RPL_DAG_MC_NONE 0 /* Local identifier for empty MC */
@ -217,7 +203,7 @@ typedef struct rpl_prefix rpl_prefix_t;
/* Directed Acyclic Graph */ /* Directed Acyclic Graph */
struct rpl_dag { struct rpl_dag {
uip_ipaddr_t dag_id; uip_ipaddr_t dag_id;
rpl_rank_t min_rank; /* should be reset per DODAG iteration! */ rpl_rank_t min_rank; /* should be reset per DAG iteration! */
uint8_t version; uint8_t version;
uint8_t grounded; uint8_t grounded;
uint8_t preference; uint8_t preference;
@ -286,7 +272,7 @@ struct rpl_instance {
rpl_metric_container_t mc; rpl_metric_container_t mc;
rpl_of_t *of; rpl_of_t *of;
rpl_dag_t *current_dag; rpl_dag_t *current_dag;
rpl_dag_t dag_table[RPL_MAX_DODAG_PER_INSTANCE]; rpl_dag_t dag_table[RPL_MAX_DAG_PER_INSTANCE];
/* The current default router - used for routing "upwards" */ /* The current default router - used for routing "upwards" */
uip_ds6_defrt_t *def_route; uip_ds6_defrt_t *def_route;
uint8_t instance_id; uint8_t instance_id;

View file

@ -1,15 +1,5 @@
# $Id: Makefile.avr,v 1.27 2010/12/22 21:13:09 dak664 Exp $ # $Id: Makefile.avr,v 1.27 2010/12/22 21:13:09 dak664 Exp $
### Check if we are running under Windows
ifndef WINDIR
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif
.SUFFIXES: .SUFFIXES:
### Optimization setting. $make OPTI=0 for easier debugging of changed source file(s) ### Optimization setting. $make OPTI=0 for easier debugging of changed source file(s)

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* @(#)$Id: spi.c,v 1.1 2007/01/25 18:22:55 bg- Exp $
*/ */
#include <avr/io.h> #include <avr/io.h>
@ -48,11 +47,6 @@ unsigned char spi_busy = 0;
void void
spi_init(void) spi_init(void)
{ {
static unsigned char spi_inited = 0;
if (spi_inited)
return;
/* Initalize ports for communication with SPI units. */ /* Initalize ports for communication with SPI units. */
/* CSN=SS and must be output when master! */ /* CSN=SS and must be output when master! */
DDRB |= BV(MOSI) | BV(SCK) | BV(CSN); DDRB |= BV(MOSI) | BV(SCK) | BV(CSN);

View file

@ -72,8 +72,7 @@ CUSTOM_RULE_C_TO_O=yes
CFLAGS += -I$(OBJECTDIR) -I$(CONTIKI_CPU)/board -DBOARD=$(TARGET) CFLAGS += -I$(OBJECTDIR) -I$(CONTIKI_CPU)/board -DBOARD=$(TARGET)
$(OBJECTDIR)/board.h: $(OBJECTDIR) $(OBJECTDIR)/board.h: $(OBJECTDIR)
ifneq (,$(findstring Windows,$(OS))) ifeq ($(HOST_OS),Windows)
${info Cygwin detected.}
ln -f $(CONTIKI_CPU)/board/board.h $(OBJECTDIR)/board.h ln -f $(CONTIKI_CPU)/board/board.h $(OBJECTDIR)/board.h
else else
ln -sf ../$(CONTIKI_CPU)/board/board.h $(OBJECTDIR)/board.h ln -sf ../$(CONTIKI_CPU)/board/board.h $(OBJECTDIR)/board.h

View file

@ -26,7 +26,6 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* @(#)$Id: spi.c,v 1.1 2006/06/17 22:41:21 adamdunkels Exp $
*/ */
#include "contiki-conf.h" #include "contiki-conf.h"
@ -46,11 +45,12 @@ unsigned char spi_busy = 0;
void void
spi_init(void) spi_init(void)
{ {
/*
static unsigned char spi_inited = 0; static unsigned char spi_inited = 0;
if (spi_inited) if (spi_inited)
return; return;
*/
/* Initalize ports for communication with SPI units. */ /* Initalize ports for communication with SPI units. */
U0CTL = CHAR + SYNC + MM + SWRST; /* SW reset,8-bit transfer, SPI master */ U0CTL = CHAR + SYNC + MM + SWRST; /* SW reset,8-bit transfer, SPI master */

View file

@ -14,7 +14,11 @@ CFLAGSWERROR=-Werror -pedantic -std=c99 -Werror
endif endif
CFLAGSNO = -Wall -g -I/usr/local/include $(CFLAGSWERROR) CFLAGSNO = -Wall -g -I/usr/local/include $(CFLAGSWERROR)
CFLAGS += $(CFLAGSNO) -O CFLAGS += $(CFLAGSNO) -O
LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic ifeq ($(HOST_OS),Linux)
LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic
else
LDFLAGS = -Wl
endif
### Compilation rules ### Compilation rules

View file

@ -40,7 +40,12 @@
static void *main_fiber; static void *main_fiber;
#elif defined(__linux) #elif defined(__linux) || defined(__APPLE__)
#ifdef __APPLE__
/* Avoid deprecated error on Darwin */
#define _XOPEN_SOURCE
#endif
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>

View file

@ -166,10 +166,8 @@ endif
FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher
# Check if we are running under Windows # Check if we are running under Windows
ifdef OS ifeq ($(HOST_OS),Windows)
ifneq (,$(findstring Windows,$(OS)))
FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher.exe FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher.exe
endif
endif endif

View file

@ -10,7 +10,11 @@ OBJCOPY = objcopy
STRIP = strip STRIP = strip
CFLAGSNO = -Wall -g -I/usr/local/include CFLAGSNO = -Wall -g -I/usr/local/include
CFLAGS += $(CFLAGSNO) CFLAGS += $(CFLAGSNO)
LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic ifeq ($(HOST_OS),Linux)
LDFLAGS = -Wl,-Map=contiki-$(TARGET).map,-export-dynamic
else
LDFLAGS = -Wl
endif
### Compilation rules ### Compilation rules

View file

@ -13,12 +13,12 @@ export doclatex := NO
export docroot := ../ export docroot := ../
# Get appropriate root for doxygen path cutoff # Get appropriate root for doxygen path cutoff
ifneq (,$(findstring Windows,$(OS))) ifeq ($(HOST_OS),Windows)
# on windows need to convert cygwin path to windows path for doxygen # on windows need to convert cygwin path to windows path for doxygen
ifneq (,$(findstring cygdrive,$(pwd))) ifneq (,$(findstring cygdrive,$(pwd)))
cygroot = $(subst /,$(space),$(patsubst /cygdrive/%,%,$(pwd))) cygroot = $(subst /,$(space),$(patsubst /cygdrive/%,%,$(pwd)))
export docroot = $(firstword $(cygroot)):/$(subst $(space),/,$(wordlist 2,$(words $(cygroot)),$(cygroot))) export docroot = $(firstword $(cygroot)):/$(subst $(space),/,$(wordlist 2,$(words $(cygroot)),$(cygroot)))
endif endif
endif endif
.PHONY: clean html pdf upload .PHONY: clean html pdf upload

View file

@ -14,7 +14,7 @@ WITH_UIP6=1
UIP_CONF_IPV6=1 UIP_CONF_IPV6=1
# variable for this Makefile # variable for this Makefile
# configure CoAP implementation (3|6|7) # configure CoAP implementation (3|7)
WITH_COAP=7 WITH_COAP=7
# must be CFLAGS not variables # must be CFLAGS not variables
@ -33,12 +33,6 @@ CFLAGS += -DWITH_COAP=7
CFLAGS += -DREST=coap_rest_implementation CFLAGS += -DREST=coap_rest_implementation
CFLAGS += -DUIP_CONF_TCP=0 CFLAGS += -DUIP_CONF_TCP=0
APPS += er-coap-07 APPS += er-coap-07
else ifeq ($(WITH_COAP), 6)
${info INFO: compiling with CoAP-06}
CFLAGS += -DWITH_COAP=6
CFLAGS += -DREST=coap_rest_implementation
CFLAGS += -DUIP_CONF_TCP=0
APPS += er-coap-06
else ifeq ($(WITH_COAP), 3) else ifeq ($(WITH_COAP), 3)
${info INFO: compiling with CoAP-03} ${info INFO: compiling with CoAP-03}
CFLAGS += -DWITH_COAP=3 CFLAGS += -DWITH_COAP=3
@ -50,14 +44,28 @@ ${info INFO: compiling with HTTP}
CFLAGS += -DWITH_HTTP CFLAGS += -DWITH_HTTP
CFLAGS += -DREST=http_rest_implementation CFLAGS += -DREST=http_rest_implementation
CFLAGS += -DUIP_CONF_TCP=1 CFLAGS += -DUIP_CONF_TCP=1
APPS += rest-http-engine APPS += er-http-engine
endif endif
APPS += erbium APPS += erbium
#CUSTOM_RULE_C_TO_OBJECTDIR_O = 1
#CUSTOM_RULE_S_TO_OBJECTDIR_O = 1
include $(CONTIKI)/Makefile.include include $(CONTIKI)/Makefile.include
#$(OBJECTDIR)/%.o: asmdir/%.S
# $(CC) $(CFLAGS) -MMD -c $< -o $@
# @$(FINALIZE_DEPENDENCY)
#
#asmdir/%.S: %.c
# $(CC) $(CFLAGS) -MMD -S $< -o $@
$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c $(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c
(cd $(CONTIKI)/tools && $(MAKE) tunslip6) (cd $(CONTIKI)/tools && $(MAKE) tunslip6)

View file

@ -8,12 +8,16 @@ coap-client-example.c: A CoAP client that polls the /toggle resource every 10 se
PRELIMINARIES PRELIMINARIES
------------- -------------
a) For convenience, define the Cooja addresses in /etc/hosts a) Make sure rpl-border-router has the same stack and fits into mote memory:
Disable RDC in border-router project-conf.h
#undef NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
b) For convenience, define the Cooja addresses in /etc/hosts
aaaa::0212:7401:0001:0101 cooja1 aaaa::0212:7401:0001:0101 cooja1
aaaa::0212:7402:0002:0202 cooja2 aaaa::0212:7402:0002:0202 cooja2
... ...
b) Get the Copper CoAP browser from https://addons.mozilla.org/en-US/firefox/addon/copper-270430/ c) Get the Copper CoAP browser from https://addons.mozilla.org/en-US/firefox/addon/copper-270430/
c) Optional: Save Tmotes as default target d) Optional: Save your target as default target
$ make TARGET=sky savetarget $ make TARGET=sky savetarget
COOJA HOWTO COOJA HOWTO
@ -26,8 +30,10 @@ Server only:
With client: With client:
1) $ make TARGET=cooja coap-client-server-example.csc 1) $ make TARGET=cooja coap-client-server-example.csc
2) Wait until red LED toggles on mote 2 (server) 2) Open new terminal
3) Choose "Click button on Sky 3" from the context menu of mote 3 (client) and watch serial output 3) $ make connect-router-cooja
4) Wait until red LED toggles on mote 2 (server)
5) Choose "Click button on Sky 3" from the context menu of mote 3 (client) and watch serial output
TMOTES HOWTO TMOTES HOWTO
------------ ------------
@ -50,16 +56,26 @@ Add a client:
DETAILS DETAILS
------- -------
The Erbium CoAP currently implements draft 07. The Erbium CoAP currently implements draft 08 (name "er-coap-07" stems from last technical draft changes).
Central features are commented in rest-server-example.c. Central features are commented in rest-server-example.c.
In general, apps/er-coap-07 supports: In general, apps/er-coap-07 supports:
* All CoAP-07 header options * All draft 08 header options
* CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS) * CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS)
* Blockwise Transfers (note REST_MAX_CHUNK_SIZE) * Blockwise Transfers (note REST_MAX_CHUNK_SIZE)
* Separate Responses (see rest_set_pre_handler() and coap_separate_handler()) * Separate Responses (see rest_set_pre_handler() and coap_separate_handler())
* Resource discovery * Resource discovery
* Observing Resources (see EVENT_ and PRERIODIC_RESOURCE, note COAP_MAX_OBSERVERS) * 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 REST Engine.
* WITH_COAP=7 uses Erbium CoAP 07 apps/er-coap-07/.
The default port for coap-07 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 TODOs
----- -----
* Blockwise uploads (for POST/PUT payload) * Blockwise uploads (for POST/PUT payload)

View file

@ -99,7 +99,8 @@ static int uri_switch = 0;
void void
client_chunk_handler(void *response) client_chunk_handler(void *response)
{ {
const uint8_t *chunk; uint8_t *chunk;
int len = coap_get_payload(response, &chunk); int len = coap_get_payload(response, &chunk);
printf("|%.*s", len, (char *)chunk); printf("|%.*s", len, (char *)chunk);
} }
@ -128,16 +129,13 @@ PROCESS_THREAD(coap_client_example, ev, data)
if (etimer_expired(&et)) { if (etimer_expired(&et)) {
printf("--Toggle timer--\n"); printf("--Toggle timer--\n");
#if PLATFORM_HAS_LEDS
/* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ /* 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]); coap_set_header_uri_path(request, service_urls[1]);
coap_set_payload(request, (uint8_t *)"Toggle!", 8);
#else const char msg[] = "Toggle!";
/* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ coap_set_payload(request, (uint8_t *)msg, sizeof(msg)-1);
coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0 );
coap_set_header_uri_path(request, "hello");
#endif
PRINT6ADDR(&server_ipaddr); PRINT6ADDR(&server_ipaddr);
PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT));

View file

@ -57,7 +57,7 @@
/* Must be <= open transaction number. */ /* Must be <= open transaction number. */
#ifndef COAP_MAX_OBSERVERS #ifndef COAP_MAX_OBSERVERS
#define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS #define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS-1
#endif #endif

View file

@ -45,14 +45,15 @@
/* Define which resources to include to meet memory constraints. */ /* Define which resources to include to meet memory constraints. */
#define REST_RES_HELLO 1 #define REST_RES_HELLO 1
#define REST_RES_MIRROR 0 #define REST_RES_MIRROR 0 /* causes largest code size */
#define REST_RES_CHUNKS 1 #define REST_RES_CHUNKS 1
#define REST_RES_POLLING 0 #define REST_RES_SEPARATE 1
#define REST_RES_PUSHING 1
#define REST_RES_EVENT 1 #define REST_RES_EVENT 1
#define REST_RES_LEDS 0 #define REST_RES_LEDS 1
#define REST_RES_TOGGLE 1 #define REST_RES_TOGGLE 1
#define REST_RES_LIGHT 1 #define REST_RES_LIGHT 0
#define REST_RES_BATTERY 0 #define REST_RES_BATTERY 1
@ -84,8 +85,6 @@
/* For CoAP-specific example: not required for normal RESTful Web service. */ /* For CoAP-specific example: not required for normal RESTful Web service. */
#if WITH_COAP == 3 #if WITH_COAP == 3
#include "er-coap-03.h" #include "er-coap-03.h"
#elif WITH_COAP == 6
#include "er-coap-06.h"
#elif WITH_COAP == 7 #elif WITH_COAP == 7
#include "er-coap-07.h" #include "er-coap-07.h"
#else #else
@ -151,8 +150,7 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
/* The ETag and Token is copied to the header. */ /* The ETag and Token is copied to the header. */
uint8_t opaque[] = {0x0A, 0xBC, 0xDE}; uint8_t opaque[] = {0x0A, 0xBC, 0xDE};
/* Strings are not copied and should be static or in program memory (char *str = "string in .text";). /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */
* They must be '\0'-terminated as the setters use strlen(). */
static char location[] = {'/','f','/','a','?','k','&','e', 0}; 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. */ /* Getter for the header option Content-Type. If the option is not set, text/plain is returned by default. */
@ -160,7 +158,7 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
/* 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. */ /* 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 = 0;
const char *str = ""; const char *str = NULL;
uint32_t observe = 0; uint32_t observe = 0;
const uint8_t *bytes = NULL; const uint8_t *bytes = NULL;
uint32_t block_num = 0; uint32_t block_num = 0;
@ -173,28 +171,29 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
int strpos = 0; int strpos = 0;
/* snprintf() counts the terminating '\0' to the size parameter. /* snprintf() counts the terminating '\0' to the size parameter.
* Add +1 to fill the complete buffer. * The additional byte is taken care of by allocating REST_MAX_CHUNK_SIZE+1 bytes in the REST framework.
* 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); 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. /* 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. */ * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */
if (REST.get_header_max_age(request, &max_age)) if (strpos<=REST_MAX_CHUNK_SIZE && REST.get_header_max_age(request, &max_age))
{ {
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);
} }
if ((len = REST.get_header_host(request, &str)))
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); 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. */ /* CoAP-specific example: actions not required for normal RESTful Web service. */
#if WITH_COAP > 1 #if WITH_COAP > 1
if (coap_get_header_observe(request, &observe)) 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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Ob %lu\n", observe);
} }
if ((len = coap_get_header_token(request, &bytes))) 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"); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "To 0x");
int index = 0; int index = 0;
@ -203,7 +202,7 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
} }
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n"); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
} }
if ((len = coap_get_header_etag(request, &bytes))) if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_etag(request, &bytes)))
{ {
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "ET 0x"); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "ET 0x");
int index = 0; int index = 0;
@ -212,54 +211,54 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
} }
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n"); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "\n");
} }
if ((len = coap_get_header_uri_path(request, &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, "UP "); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "UP ");
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s\n", len, str); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s\n", len, str);
} }
#if WITH_COAP == 3 #if WITH_COAP == 3
if ((len = coap_get_header_location(request, &str))) if (strpos<=REST_MAX_CHUNK_SIZE && (len = coap_get_header_location(request, &str)))
{ {
strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Lo %.*s\n", len, str); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Lo %.*s\n", len, str);
} }
if (coap_get_header_block(request, &block_num, &block_more, &block_size, NULL)) /* This getter allows NULL pointers to get only a subset of the block parameters. */ if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block(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, "Bl %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Bl %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
} }
#elif WITH_COAP >= 5 #else
if ((len = coap_get_header_location_path(request, &str))) 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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LP %.*s\n", len, str);
} }
if ((len = coap_get_header_location_query(request, &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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "LQ %.*s\n", len, str);
} }
if (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. */ 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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
} }
if (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. */ /*
* Critical Block1 option is currently rejected by engine.
*
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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size);
} }
#if WITH_COAP >= 7 */
#endif /* CoAP > 03 */
#endif
#endif
#endif /* CoAP-specific example */ #endif /* CoAP-specific example */
if ((len = REST.get_query(request, &query))) 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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "Qu %.*s\n", len, query);
} }
if ((len = REST.get_request_payload(request, &bytes))) 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); strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "%.*s", len, bytes);
} }
if (strpos == REST_MAX_CHUNK_SIZE) if (strpos >= REST_MAX_CHUNK_SIZE)
{ {
buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* '»' to indicate truncation */ buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* '»' to indicate truncation */
} }
@ -280,16 +279,13 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
coap_set_header_observe(response, 10); coap_set_header_observe(response, 10);
#if WITH_COAP == 3 #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. */ coap_set_header_block(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */
#elif WITH_COAP >= 5 #else
coap_set_header_proxy_uri(response, "ftp://x"); 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_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_block1(response, 23, 0, 16);
#if WITH_COAP >= 7
coap_set_header_accept(response, TEXT_PLAIN); coap_set_header_accept(response, TEXT_PLAIN);
coap_set_header_if_none_match(response); coap_set_header_if_none_match(response);
#endif #endif /* CoAP > 03 */
#endif
#endif /* CoAP-specific example */ #endif /* CoAP-specific example */
} }
#endif /* REST_RES_MIRROR */ #endif /* REST_RES_MIRROR */
@ -316,7 +312,9 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
{ {
REST.set_response_status(response, REST.status.BAD_OPTION); REST.set_response_status(response, REST.status.BAD_OPTION);
/* A block error message should not exceed the minimum block size (16). */ /* A block error message should not exceed the minimum block size (16). */
REST.set_response_payload(response, (uint8_t*)"BlockOutOfScope", 15);
const char *error_msg = "BlockOutOfScope";
REST.set_response_payload(response, error_msg, strlen(error_msg));
return; return;
} }
@ -332,7 +330,7 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
strpos = preferred_size; strpos = preferred_size;
} }
/* Truncate if above total size. */ /* Truncate if above CHUNKS_TOTAL bytes. */
if (*offset+(int32_t)strpos > CHUNKS_TOTAL) if (*offset+(int32_t)strpos > CHUNKS_TOTAL)
{ {
strpos = CHUNKS_TOTAL - *offset; strpos = CHUNKS_TOTAL - *offset;
@ -351,19 +349,95 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre
} }
#endif #endif
#if REST_RES_POLLING #if REST_RES_SEPARATE && WITH_COAP > 3
/* Required to manually (=not by the engine) handle the response transaction. */
#include "er-coap-07-separate.h"
#include "er-coap-07-transactions.h"
/*
* CoAP-specific example for separate responses.
* This resource is .
*/
RESOURCE(separate, METHOD_GET, "debug/separate", "title=\"Separate demo\"");
static uint8_t separate_active = 0;
static coap_separate_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)
{
REST.set_response_status(response, REST.status.SERVICE_UNAVAILABLE);
const char *msg = "AlreadyInUse";
REST.set_response_payload(response, msg, strlen(msg));
}
else
{
separate_active = 1;
/* Take over and skip response by engine. */
coap_separate_response(response, separate_store);
/*
* 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->mid, &separate_store->addr, separate_store->port)) )
{
coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */
coap_init_message(response, separate_store->type, CONTENT_2_05, separate_store->mid);
coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer));
/* 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) */
}
#endif
#if REST_RES_PUSHING
/* /*
* Example for a periodic resource. * Example for a periodic resource.
* It takes an additional period parameter, which defines the interval to call [name]_periodic_handler(). * 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. * A default post_handler takes care of subscriptions by managing a list of subscribers to notify.
*/ */
PERIODIC_RESOURCE(polling, METHOD_GET, "debug/poll", "title=\"Periodic demo\";rt=\"Observable\"", 5*CLOCK_SECOND); PERIODIC_RESOURCE(pushing, METHOD_GET, "debug/push", "title=\"Periodic demo\";rt=\"Observable\"", 5*CLOCK_SECOND);
void void
polling_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) 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); REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
REST.set_response_payload(response, (uint8_t *)"It's periodic!", 14);
/* 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. */ /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */
} }
@ -373,7 +447,7 @@ polling_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr
* It will be called by the REST manager process with the defined period. * It will be called by the REST manager process with the defined period.
*/ */
int int
polling_periodic_handler(resource_t *r) pushing_periodic_handler(resource_t *r)
{ {
static uint32_t periodic_i = 0; static uint32_t periodic_i = 0;
static char content[16]; static char content[16];
@ -401,7 +475,9 @@ void
event_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) 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); REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
REST.set_response_payload(response, (uint8_t *)"It's eventful!", 14); /* 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. */ /* A post_handler that handles subscriptions/observing will be called for periodic resources by the framework. */
} }
@ -496,7 +572,7 @@ light_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
uint16_t light_photosynthetic = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC); uint16_t light_photosynthetic = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC);
uint16_t light_solar = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR); uint16_t light_solar = light_sensor.value(LIGHT_SENSOR_TOTAL_SOLAR);
uint16_t *accept = NULL; const uint16_t *accept = NULL;
int num = REST.get_header_accept(request, &accept); int num = REST.get_header_accept(request, &accept);
if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN))
@ -523,7 +599,8 @@ light_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred
else else
{ {
REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE); REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE);
REST.set_response_payload(response, (uint8_t *)"Supporting content-types text/plain, application/xml, and application/json", 74); 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 */ #endif /* PLATFORM_HAS_LIGHT */
@ -536,7 +613,7 @@ battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr
{ {
int battery = battery_sensor.value(0); int battery = battery_sensor.value(0);
uint16_t *accept = NULL; const uint16_t *accept = NULL;
int num = REST.get_header_accept(request, &accept); int num = REST.get_header_accept(request, &accept);
if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN))
@ -556,7 +633,8 @@ battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr
else else
{ {
REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE); 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); const char *msg = "Supporting content-types text/plain and application/json";
REST.set_response_payload(response, msg, strlen(msg));
} }
} }
#endif /* PLATFORM_HAS_BATTERY */ #endif /* PLATFORM_HAS_BATTERY */
@ -588,8 +666,8 @@ PROCESS_THREAD(rest_server_example, ev, data)
configure_routing(); configure_routing();
#endif #endif
/* Initialize the REST framework. */ /* Initialize the REST engine. */
rest_init_framework(); rest_init_engine();
/* Activate the application-specific resources. */ /* Activate the application-specific resources. */
#if REST_RES_HELLO #if REST_RES_HELLO
@ -601,9 +679,14 @@ PROCESS_THREAD(rest_server_example, ev, data)
#if REST_RES_CHUNKS #if REST_RES_CHUNKS
rest_activate_resource(&resource_chunks); rest_activate_resource(&resource_chunks);
#endif #endif
#if REST_RES_POLLING #if REST_RES_PUSHING
rest_activate_periodic_resource(&periodic_resource_polling); rest_activate_periodic_resource(&periodic_resource_pushing);
#endif #endif
#if REST_RES_SEPARATE && WITH_COAP > 3
rest_set_pre_handler(&resource_separate, coap_separate_handler);
rest_activate_resource(&resource_separate);
#endif
#if defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT #if defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT
SENSORS_ACTIVATE(button_sensor); SENSORS_ACTIVATE(button_sensor);
rest_activate_event_resource(&resource_event); rest_activate_event_resource(&resource_event);
@ -628,11 +711,17 @@ PROCESS_THREAD(rest_server_example, ev, data)
/* Define application-specific events here. */ /* Define application-specific events here. */
while(1) { while(1) {
PROCESS_WAIT_EVENT(); PROCESS_WAIT_EVENT();
#if defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT #if defined (PLATFORM_HAS_BUTTON)
if (ev == sensors_event && data == &button_sensor) { if (ev == sensors_event && data == &button_sensor) {
PRINTF("BUTTON\n"); PRINTF("BUTTON\n");
#if REST_RES_EVENT
/* Call the event_handler for this application-specific event. */ /* Call the event_handler for this application-specific event. */
event_event_handler(&resource_event); event_event_handler(&resource_event);
#endif
#if REST_RES_SEPARATE && WITH_COAP>3
/* Also call the separate response example handler. */
separate_finalize_handler();
#endif
} }
#endif /* PLATFORM_HAS_BUTTON */ #endif /* PLATFORM_HAS_BUTTON */
} /* while (1) */ } /* while (1) */

View file

@ -37,7 +37,7 @@
#define QUEUEBUF_CONF_NUM 4 #define QUEUEBUF_CONF_NUM 4
#undef UIP_CONF_BUFFER_SIZE #undef UIP_CONF_BUFFER_SIZE
#define UIP_CONF_BUFFER_SIZE 140 #define UIP_CONF_BUFFER_SIZE 1280
#undef UIP_CONF_RECEIVE_WINDOW #undef UIP_CONF_RECEIVE_WINDOW
#define UIP_CONF_RECEIVE_WINDOW 60 #define UIP_CONF_RECEIVE_WINDOW 60

View file

@ -127,7 +127,11 @@ slip_config_handle_arguments(int argc, char **argv)
fprintf(stderr,"usage: %s [options] ipaddress\n", prog); fprintf(stderr,"usage: %s [options] ipaddress\n", prog);
fprintf(stderr,"example: border-router.native -L -v2 -s ttyUSB1 aaaa::1/64\n"); fprintf(stderr,"example: border-router.native -L -v2 -s ttyUSB1 aaaa::1/64\n");
fprintf(stderr,"Options are:\n"); fprintf(stderr,"Options are:\n");
#ifdef linux
fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200,921600 (default 115200)\n"); fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200,921600 (default 115200)\n");
#else
fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200 (default 115200)\n");
#endif
fprintf(stderr," -H Hardware CTS/RTS flow control (default disabled)\n"); fprintf(stderr," -H Hardware CTS/RTS flow control (default disabled)\n");
fprintf(stderr," -L Log output format (adds time stamps)\n"); fprintf(stderr," -L Log output format (adds time stamps)\n");
fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n"); fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n");
@ -175,9 +179,11 @@ exit(1);
case 115200: case 115200:
slip_config_b_rate = B115200; slip_config_b_rate = B115200;
break; break;
#ifdef linux
case 921600: case 921600:
slip_config_b_rate = B921600; slip_config_b_rate = B921600;
break; break;
#endif
default: default:
err(1, "unknown baudrate %d", baudrate); err(1, "unknown baudrate %d", baudrate);
break; break;

View file

@ -125,13 +125,17 @@ void
ifconf(const char *tundev, const char *ipaddr) ifconf(const char *tundev, const char *ipaddr)
{ {
#ifdef linux #ifdef linux
ssystem("ifconfig %s inet `hostname` up", tundev); ssystem("ifconfig %s inet6 `hostname` up", tundev);
ssystem("ifconfig %s add %s", tundev, ipaddr); ssystem("ifconfig %s add %s", tundev, ipaddr);
#elif defined(__APPLE__)
ssystem("ifconfig %s inet6 %s up", tundev, ipaddr);
ssystem("sysctl -w net.inet.ip.forwarding=1");
#else #else
ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr); ssystem("ifconfig %s inet6 `hostname` %s up", tundev, ipaddr);
ssystem("sysctl -w net.inet.ip.forwarding=1"); ssystem("sysctl -w net.inet.ip.forwarding=1");
#endif /* !linux */ #endif /* !linux */
/* Print the configuration to the console. */
ssystem("ifconfig %s\n", tundev); ssystem("ifconfig %s\n", tundev);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/

View file

@ -74,6 +74,13 @@ AUTOSTART_PROCESSES(&border_router_process,&webserver_nogui_process);
#else #else
/* Use simple webserver with only one page */ /* Use simple webserver with only one page */
#include "httpd-simple.h" #include "httpd-simple.h"
#define WEBSERVER_CONF_LOADTIME 0
#define WEBSERVER_CONF_FILESTATS 0
#define WEBSERVER_CONF_NEIGHBOR_STATUS 0
#define WEBSERVER_CONF_ROUTE_LINKS 0
#define BUF_USES_STACK 1
PROCESS(webserver_nogui_process, "Web server"); PROCESS(webserver_nogui_process, "Web server");
PROCESS_THREAD(webserver_nogui_process, ev, data) PROCESS_THREAD(webserver_nogui_process, ev, data)
{ {
@ -92,11 +99,19 @@ AUTOSTART_PROCESSES(&border_router_process,&webserver_nogui_process);
static const char *TOP = "<html><head><title>ContikiRPL</title></head><body>\n"; static const char *TOP = "<html><head><title>ContikiRPL</title></head><body>\n";
static const char *BOTTOM = "</body></html>\n"; static const char *BOTTOM = "</body></html>\n";
static char buf[128]; #if BUF_USES_STACK
static char *bufptr, *bufend;
#define ADD(...) do { \
bufptr += snprintf(bufptr, bufend - bufptr, __VA_ARGS__); \
} while(0)
#else
static char buf[256];
static int blen; static int blen;
#define ADD(...) do { \ #define ADD(...) do { \
blen += snprintf(&buf[blen], sizeof(buf) - blen, __VA_ARGS__); \ blen += snprintf(&buf[blen], sizeof(buf) - blen, __VA_ARGS__); \
} while(0) } while(0)
#endif
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
ipaddr_add(const uip_ipaddr_t *addr) ipaddr_add(const uip_ipaddr_t *addr)
@ -106,15 +121,12 @@ ipaddr_add(const uip_ipaddr_t *addr)
for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) { for(i = 0, f = 0; i < sizeof(uip_ipaddr_t); i += 2) {
a = (addr->u8[i] << 8) + addr->u8[i + 1]; a = (addr->u8[i] << 8) + addr->u8[i + 1];
if(a == 0 && f >= 0) { if(a == 0 && f >= 0) {
if(f++ == 0 && sizeof(buf) - blen >= 2) { if(f++ == 0) ADD("::");
buf[blen++] = ':';
buf[blen++] = ':';
}
} else { } else {
if(f > 0) { if(f > 0) {
f = -1; f = -1;
} else if(i > 0 && blen < sizeof(buf)) { } else if(i > 0) {
buf[blen++] = ':'; ADD(":");
} }
ADD("%x", a); ADD("%x", a);
} }
@ -125,46 +137,130 @@ static
PT_THREAD(generate_routes(struct httpd_state *s)) PT_THREAD(generate_routes(struct httpd_state *s))
{ {
static int i; static int i;
#if BUF_USES_STACK
char buf[256];
#endif
#if WEBSERVER_CONF_LOADTIME
static clock_time_t numticks;
numticks = clock_time();
#endif
PSOCK_BEGIN(&s->sout); PSOCK_BEGIN(&s->sout);
SEND_STRING(&s->sout, TOP); SEND_STRING(&s->sout, TOP);
#if BUF_USES_STACK
bufptr = buf;bufend=bufptr+sizeof(buf);
#else
blen = 0; blen = 0;
#endif
ADD("Neighbors<pre>"); ADD("Neighbors<pre>");
for(i = 0; i < UIP_DS6_NBR_NB; i++) { for(i = 0; i < UIP_DS6_NBR_NB; i++) {
if(uip_ds6_nbr_cache[i].isused) { if(uip_ds6_nbr_cache[i].isused) {
#if WEBSERVER_CONF_NEIGHBOR_STATUS
#if BUF_USES_STACK
{char* j=bufptr+25;
ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr); ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
while (bufptr < j) ADD(" ");
switch (uip_ds6_nbr_cache[i].state) {
case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
case NBR_REACHABLE: ADD(" REACHABLE");break;
case NBR_STALE: ADD(" STALE");break;
case NBR_DELAY: ADD(" DELAY");break;
case NBR_PROBE: ADD(" NBR_PROBE");break;
}
}
#else
{uint8_t j=blen+25;
ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
while (blen < j) ADD(" ");
switch (uip_ds6_nbr_cache[i].state) {
case NBR_INCOMPLETE: ADD(" INCOMPLETE");break;
case NBR_REACHABLE: ADD(" REACHABLE");break;
case NBR_STALE: ADD(" STALE");break;
case NBR_DELAY: ADD(" DELAY");break;
case NBR_PROBE: ADD(" NBR_PROBE");break;
}
}
#endif
#else
ipaddr_add(&uip_ds6_nbr_cache[i].ipaddr);
#endif
ADD("\n"); ADD("\n");
#if BUF_USES_STACK
if(bufptr > bufend - 45) {
SEND_STRING(&s->sout, buf);
bufptr = buf; bufend = bufptr + sizeof(buf);
}
#else
if(blen > sizeof(buf) - 45) { if(blen > sizeof(buf) - 45) {
SEND_STRING(&s->sout, buf); SEND_STRING(&s->sout, buf);
blen = 0; blen = 0;
} }
#endif
} }
} }
ADD("</pre>Routes<pre>"); ADD("</pre>Routes<pre>");
SEND_STRING(&s->sout, buf); SEND_STRING(&s->sout, buf);
#if BUF_USES_STACK
bufptr = buf; bufend = bufptr + sizeof(buf);
#else
blen = 0; blen = 0;
#endif
for(i = 0; i < UIP_DS6_ROUTE_NB; i++) { for(i = 0; i < UIP_DS6_ROUTE_NB; i++) {
if(uip_ds6_routing_table[i].isused) { if(uip_ds6_routing_table[i].isused) {
#if BUF_USES_STACK
#if WEBSERVER_CONF_ROUTE_LINKS
ADD("<a href=http://[");
ipaddr_add(&uip_ds6_routing_table[i].ipaddr); ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
ADD("]/status.shtml>");
ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
ADD("</a>");
#else
ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
#endif
#else
#if WEBSERVER_CONF_ROUTE_LINKS
ADD("<a href=http://[");
ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
ADD("]/status.shtml>");
SEND_STRING(&s->sout, buf); //TODO: why tunslip6 needs an output here, wpcapslip does not
blen = 0;
ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
ADD("</a>");
#else
ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
#endif
#endif
ADD("/%u (via ", uip_ds6_routing_table[i].length); ADD("/%u (via ", uip_ds6_routing_table[i].length);
ipaddr_add(&uip_ds6_routing_table[i].nexthop); ipaddr_add(&uip_ds6_routing_table[i].nexthop);
if(uip_ds6_routing_table[i].state.lifetime < 600) { if(1 || (uip_ds6_routing_table[i].state.lifetime < 600)) {
ADD(") %lus\n", uip_ds6_routing_table[i].state.lifetime); ADD(") %lus\n", uip_ds6_routing_table[i].state.lifetime);
} else { } else {
ADD(")\n"); ADD(")\n");
} }
SEND_STRING(&s->sout, buf); SEND_STRING(&s->sout, buf);
#if BUF_USES_STACK
bufptr = buf; bufend = bufptr + sizeof(buf);
#else
blen = 0; blen = 0;
#endif
} }
} }
ADD("</pre>"); ADD("</pre>");
//if(blen > 0) {
SEND_STRING(&s->sout, buf);
// blen = 0;
//}
#if WEBSERVER_CONF_FILESTATS
static uint16_t numtimes;
ADD("<br><i>This page sent %u times</i>",++numtimes);
#endif
#if WEBSERVER_CONF_LOADTIME
numticks = clock_time() - numticks + 1;
ADD(" <i>(%u.%02u sec)</i>",numticks/CLOCK_SECOND,(100*(numticks%CLOCK_SECOND))/CLOCK_SECOND));
#endif
SEND_STRING(&s->sout, buf);
SEND_STRING(&s->sout, BOTTOM); SEND_STRING(&s->sout, BOTTOM);
PSOCK_END(&s->sout); PSOCK_END(&s->sout);
@ -173,6 +269,7 @@ PT_THREAD(generate_routes(struct httpd_state *s))
httpd_simple_script_t httpd_simple_script_t
httpd_simple_get_script(const char *name) httpd_simple_get_script(const char *name)
{ {
return generate_routes; return generate_routes;
} }
@ -226,19 +323,26 @@ PROCESS_THREAD(border_router_process, ev, data)
PROCESS_BEGIN(); PROCESS_BEGIN();
/* While waiting for the prefix to be sent through the SLIP connection, the future
* border router can join an existing DAG as a parent or child, or acquire a default
* router that will later take precedence over the SLIP fallback interface.
* Prevent that by turning the radio off until we are initialized as a DAG root.
*/
prefix_set = 0; prefix_set = 0;
NETSTACK_MAC.off(0);
PROCESS_PAUSE(); PROCESS_PAUSE();
SENSORS_ACTIVATE(button_sensor); SENSORS_ACTIVATE(button_sensor);
PRINTF("RPL-Border router started\n"); PRINTF("RPL-Border router started\n");
#if 0
/* The border router runs with a 100% duty cycle in order to ensure high /* The border router runs with a 100% duty cycle in order to ensure high
packet reception rates. packet reception rates.
Note if the MAC RDC is not turned off now, aggressive power management of the Note if the MAC RDC is not turned off now, aggressive power management of the
cpu will interfere with establishing the SLIP connection */ cpu will interfere with establishing the SLIP connection */
NETSTACK_MAC.off(1); NETSTACK_MAC.off(1);
#endif
/* Request prefix until it has been received */ /* Request prefix until it has been received */
while(!prefix_set) { while(!prefix_set) {
@ -253,6 +357,11 @@ PROCESS_THREAD(border_router_process, ev, data)
PRINTF("created a new RPL dag\n"); PRINTF("created a new RPL dag\n");
} }
/* Now turn the radio on, but disable radio duty cycling.
* Since we are the DAG root, reception delays would constrain mesh throughbut.
*/
NETSTACK_MAC.off(1);
#if DEBUG || 1 #if DEBUG || 1
print_local_addresses(); print_local_addresses();
#endif #endif

View file

@ -11,14 +11,6 @@ ifndef CONTIKI
$(error CONTIKI not defined!) $(error CONTIKI not defined!)
endif endif
ifndef WINDIR
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif
### Assuming simulator quickstart if no JNI library name set from Cooja ### Assuming simulator quickstart if no JNI library name set from Cooja
ifndef LIBNAME ifndef LIBNAME
QUICKSTART=1 QUICKSTART=1

View file

@ -68,23 +68,15 @@ send: $(CONTIKI)/tools/codeprop.c
### System dependent Makefile ### System dependent Makefile
ifndef WINDIR ifeq ($(HOST_OS),FreeBSD)
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif
ifeq (${HOSTTYPE},FreeBSD)
# settings for FreeBSD # settings for FreeBSD
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.freebsd -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.freebsd
else else
ifndef WINDIR ifeq ($(HOST_OS),Windows)
# settings for unix # settings for Windows
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix
else
# settings for windows
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win
endif else
# settings for an arbitary unix-like platform
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix
endif
endif endif

View file

@ -31,23 +31,15 @@ include $(CONTIKIAVR)/Makefile.avr
avr-objdump -zhD $< > $@ avr-objdump -zhD $< > $@
ifndef WINDIR
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif
ifeq ($(PRGBOARD), ) ifeq ($(PRGBOARD), )
PRGBOARD = mib510 PRGBOARD = mib510
endif endif
ifeq ($(PORT), ) ifeq ($(PORT), )
ifndef WINDIR ifeq ($(HOST_OS), Windows)
PORT = /dev/ttyUSB0
else
PORT = COM1 PORT = COM1
else
PORT = /dev/ttyUSB0
endif endif
endif endif

View file

@ -19,10 +19,8 @@ include $(CONTIKI)/cpu/stm32w108/Makefile.stm32w108
SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux
ifdef OS ifeq ($(HOST_OS),Windows)
ifneq (,$(findstring Windows,$(OS)))
SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows
endif
endif endif

View file

@ -18,10 +18,8 @@ include $(CONTIKI)/cpu/stm32w108/Makefile.stm32w108
SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux
ifdef OS ifeq ($(HOST_OS),Windows)
ifneq (,$(findstring Windows,$(OS)))
SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows
endif
endif endif

View file

@ -26,23 +26,15 @@ include $(CONTIKIAVR)/Makefile.avr
avr-objdump -zhD $< > $@ avr-objdump -zhD $< > $@
ifndef WINDIR
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif
ifeq ($(PRGBOARD), ) ifeq ($(PRGBOARD), )
PRGBOARD = mib510 PRGBOARD = mib510
endif endif
ifeq ($(PORT), ) ifeq ($(PORT), )
ifndef WINDIR ifeq ($(HOST_OS),Windows)
PORT = /dev/ttyS0
else
PORT = COM1 PORT = COM1
else
PORT = /dev/ttyS0
endif endif
endif endif

View file

@ -2,12 +2,16 @@ ifndef CONTIKI
$(error CONTIKI not defined! You must specify where CONTIKI resides!) $(error CONTIKI not defined! You must specify where CONTIKI resides!)
endif endif
ifeq ($(HOST_OS),Darwin)
AROPTS = rc
endif
CONTIKI_TARGET_DIRS = . CONTIKI_TARGET_DIRS = .
CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o}
CONTIKI_TARGET_SOURCEFILES = contiki-main.c clock.c leds.c leds-arch.c cfs-posix.c cfs-posix-dir.c dlloader.c CONTIKI_TARGET_SOURCEFILES = contiki-main.c clock.c leds.c leds-arch.c cfs-posix.c cfs-posix-dir.c dlloader.c
ifeq ($(OS),Windows_NT) ifeq ($(HOST_OS),Windows)
CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c
else else
CONTIKI_TARGET_SOURCEFILES += tapdev-drv.c CONTIKI_TARGET_SOURCEFILES += tapdev-drv.c
@ -21,7 +25,7 @@ endif
CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES)
ifeq ($(OS),Windows_NT) ifeq ($(HOST_OS),Windows)
TARGET_LIBFILES = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a TARGET_LIBFILES = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a
endif endif

View file

@ -24,25 +24,17 @@ endif
### System dependent Makefile ### System dependent Makefile
ifndef WINDIR ifeq ($(HOST_OS),FreeBSD)
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif
ifeq (${HOSTTYPE},FreeBSD)
# settings for FreeBSD # settings for FreeBSD
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.freebsd -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.freebsd
else else
ifndef WINDIR ifeq ($(HOST_OS),Windows)
# settings for unix # settings for Windows
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix
else
# settings for windows
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win
endif else
# settings for an arbitary unix-like platform
-include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix
endif
endif endif
# If we are not running under Windows, we assume Linux # If we are not running under Windows, we assume Linux

View file

@ -2,6 +2,10 @@ ifndef CONTIKI
$(error CONTIKI not defined! You must specify where CONTIKI resides!) $(error CONTIKI not defined! You must specify where CONTIKI resides!)
endif endif
ifeq ($(HOST_OS),Darwin)
AROPTS = rc
endif
ifdef UIP_CONF_IPV6 ifdef UIP_CONF_IPV6
CFLAGS += -DWITH_UIP6=1 CFLAGS += -DWITH_UIP6=1
endif endif
@ -13,7 +17,7 @@ CONTIKI_TARGET_SOURCEFILES = contiki-main.c clock.c leds.c leds-arch.c \
button-sensor.c pir-sensor.c vib-sensor.c xmem.c \ button-sensor.c pir-sensor.c vib-sensor.c xmem.c \
sensors.c irq.c cfs-posix.c cfs-posix-dir.c sensors.c irq.c cfs-posix.c cfs-posix-dir.c
ifeq ($(OS),Windows_NT) ifeq ($(HOST_OS),Windows)
CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c
TARGET_LIBFILES = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a TARGET_LIBFILES = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a
else else

View file

@ -227,7 +227,7 @@ typedef unsigned long rtimer_clock_t;
#define UIP_CONF_DHCP_LIGHT #define UIP_CONF_DHCP_LIGHT
#define UIP_CONF_LLH_LEN 0 #define UIP_CONF_LLH_LEN 0
#define UIP_CONF_RECEIVE_WINDOW 48 #define UIP_CONF_RECEIVE_WINDOW 300
#define UIP_CONF_TCP_MSS 48 #define UIP_CONF_TCP_MSS 48
#define UIP_CONF_MAX_CONNECTIONS 4 #define UIP_CONF_MAX_CONNECTIONS 4
#define UIP_CONF_MAX_LISTENPORTS 8 #define UIP_CONF_MAX_LISTENPORTS 8

View file

@ -43,8 +43,7 @@ NUMPAR=20
IHEXFILE=tmpimage.ihex IHEXFILE=tmpimage.ihex
# Check if we are running under Windows # Check if we are running under Windows
ifdef OS ifeq ($(HOST_OS),Windows)
ifneq (,$(findstring Windows,$(OS)))
USBDEVPREFIX=/dev/com USBDEVPREFIX=/dev/com
SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-windows SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-windows
MOTELIST = $(CONTIKI)/tools/sky/motelist-windows MOTELIST = $(CONTIKI)/tools/sky/motelist-windows
@ -65,7 +64,6 @@ ifdef OS
CMOTES = $(shell $(MOTELIST) | grep COM | \ CMOTES = $(shell $(MOTELIST) | grep COM | \
cut -f 4 -d \ | \ cut -f 4 -d \ | \
perl -ne 'print $$1 . " " if(/COM(\d+)/);') perl -ne 'print $$1 . " " if(/COM(\d+)/);')
endif
endif endif
# If we are not running under Windows, we assume Linux # If we are not running under Windows, we assume Linux

View file

@ -27,12 +27,3 @@ ifndef BASE_IP
BASE_IP := 172.16.1.1 BASE_IP := 172.16.1.1
endif endif
### System dependent Makefile
ifndef WINDIR
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif

View file

@ -24,12 +24,3 @@ ifndef BASE_IP
BASE_IP := 172.16.1.1 BASE_IP := 172.16.1.1
endif endif
### System dependent Makefile
ifndef WINDIR
ifdef OS
ifneq (,$(findstring Windows,$(OS)))
WINDIR := Windows
endif
endif
endif

View file

@ -59,6 +59,7 @@ import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin;
import se.sics.cooja.mspmote.plugins.MspBreakpointContainer; import se.sics.cooja.mspmote.plugins.MspBreakpointContainer;
import se.sics.cooja.plugins.BufferListener.BufferAccess; import se.sics.cooja.plugins.BufferListener.BufferAccess;
import se.sics.cooja.plugins.Visualizer; import se.sics.cooja.plugins.Visualizer;
import se.sics.mspsim.cli.CommandContext;
import se.sics.mspsim.cli.CommandHandler; import se.sics.mspsim.cli.CommandHandler;
import se.sics.mspsim.cli.LineListener; import se.sics.mspsim.cli.LineListener;
import se.sics.mspsim.cli.LineOutputStream; import se.sics.mspsim.cli.LineOutputStream;
@ -74,6 +75,7 @@ import se.sics.mspsim.util.DebugInfo;
import se.sics.mspsim.util.ELF; import se.sics.mspsim.util.ELF;
import se.sics.mspsim.util.MapEntry; import se.sics.mspsim.util.MapEntry;
import se.sics.mspsim.util.MapTable; import se.sics.mspsim.util.MapTable;
import se.sics.mspsim.util.SimpleProfiler;
/** /**
* @author Fredrik Osterlind * @author Fredrik Osterlind
@ -88,7 +90,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
} }
private CommandHandler commandHandler; private CommandHandler commandHandler;
private ArrayList<LineListener> commandListeners = new ArrayList<LineListener>();
private MSP430 myCpu = null; private MSP430 myCpu = null;
private MspMoteType myMoteType = null; private MspMoteType myMoteType = null;
private MspMoteMemory myMemory = null; private MspMoteMemory myMemory = null;
@ -150,24 +151,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
return new MoteInterfaceHandler(this, getType().getMoteInterfaceClasses()); return new MoteInterfaceHandler(this, getType().getMoteInterfaceClasses());
} }
public void sendCLICommand(String line) {
if (commandHandler != null) {
commandHandler.lineRead(line);
}
}
public boolean hasCLIListener() {
return !commandListeners.isEmpty();
}
public void addCLIListener(LineListener listener) {
commandListeners.add(listener);
}
public void removeCLIListener(LineListener listener) {
commandListeners.remove(listener);
}
/** /**
* @return MSP430 CPU * @return MSP430 CPU
*/ */
@ -234,17 +217,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
* @throws IOException Preparing mote failed * @throws IOException Preparing mote failed
*/ */
protected void prepareMote(File fileELF, GenericNode node) throws IOException { protected void prepareMote(File fileELF, GenericNode node) throws IOException {
LineOutputStream lout = new LineOutputStream(new LineListener() { this.commandHandler = new CommandHandler(System.out, System.err);
public void lineRead(String line) {
for (LineListener l: commandListeners.toArray(new LineListener[0])) {
if (l == null) {
continue;
}
l.lineRead(line);
}
}});
PrintStream out = new PrintStream(lout);
this.commandHandler = new CommandHandler(out, out);
node.setCommandHandler(commandHandler); node.setCommandHandler(commandHandler);
ConfigManager config = new ConfigManager(); ConfigManager config = new ConfigManager();
@ -271,6 +244,10 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
myCpu.reset(); myCpu.reset();
} }
public CommandHandler getCLICommandHandler() {
return commandHandler;
}
/* called when moteID is updated */ /* called when moteID is updated */
public void idUpdated(int newID) { public void idUpdated(int newID) {
} }
@ -344,13 +321,9 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
myCpu.stepMicros(t - lastExecute, duration); myCpu.stepMicros(t - lastExecute, duration);
lastExecute = t; lastExecute = t;
} catch (EmulationException e) { } catch (EmulationException e) {
String stackTraceOutput = sendCLICommandAndPrint("stacktrace"); String trace = e.getMessage() + "\n\n" + getStackTrace();
if (stackTraceOutput == null) {
stackTraceOutput = "";
}
stackTraceOutput = e.getMessage() + "\n\n" + stackTraceOutput;
throw (ContikiError) throw (ContikiError)
new ContikiError(stackTraceOutput).initCause(e); new ContikiError(trace).initCause(e);
} }
/* Schedule wakeup */ /* Schedule wakeup */
@ -377,22 +350,29 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
}*/ }*/
} }
public String sendCLICommandAndPrint(String cmd) { public String getStackTrace() {
String response = executeCLICommand(cmd); return executeCLICommand("stacktrace");
logger.fatal(response); }
return response;
public int executeCLICommand(String cmd, CommandContext context) {
return commandHandler.executeCommand(cmd, context);
} }
public String executeCLICommand(String cmd) { public String executeCLICommand(String cmd) {
final StringBuilder sb = new StringBuilder(); final StringBuilder sb = new StringBuilder();
LineListener tmp = new LineListener() { LineListener ll = new LineListener() {
public void lineRead(String line) { public void lineRead(String line) {
sb.append(line + "\n"); sb.append(line).append("\n");
} }
}; };
commandListeners.add(tmp); PrintStream po = new PrintStream(new LineOutputStream(ll));
sendCLICommand(cmd); CommandContext c = new CommandContext(commandHandler, null, "", new String[0], 1, null);
commandListeners.remove(tmp); c.out = po;
c.err = po;
if (0 != executeCLICommand(cmd, c)) {
sb.append("\nWarning: command failed");
}
return sb.toString(); return sb.toString();
} }
@ -507,7 +487,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
} }
public String getPCString() { public String getPCString() {
int pc = myCpu.reg[MSP430Constants.PC]; int pc = myCpu.getPC();
ELF elf = (ELF)myCpu.getRegistry().getComponent(ELF.class); ELF elf = (ELF)myCpu.getRegistry().getComponent(ELF.class);
DebugInfo di = elf.getDebugInfo(pc); DebugInfo di = elf.getDebugInfo(pc);
@ -517,6 +497,17 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
} }
if (di == null) { if (di == null) {
/* Return PC value */ /* Return PC value */
MapEntry mapEntry = ((SimpleProfiler)myCpu.getProfiler()).getCallMapEntry(0);
if (mapEntry != null) {
String file = mapEntry.getFile();
if (file != null) {
if (file.indexOf('/') >= 0) {
file = file.substring(file.lastIndexOf('/')+1);
}
}
String name = mapEntry.getName();
return file + ":?:" + name;
}
return String.format("*%02x", myCpu.reg[MSP430Constants.PC]); return String.format("*%02x", myCpu.reg[MSP430Constants.PC]);
} }
@ -527,15 +518,19 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc
/* strip path */ /* strip path */
file = file.substring(file.lastIndexOf('/')+1, file.length()); file = file.substring(file.lastIndexOf('/')+1, file.length());
} }
String function = di.getFunction(); String function = di.getFunction();
function = function==null?"?":function; function = function==null?"":function;
if (function.contains(":")) { if (function.contains(":")) {
/* strip arguments */ /* strip arguments */
function = function.substring(0, function.lastIndexOf(':')); function = function.substring(0, function.lastIndexOf(':'));
} }
return file + ":" + function + ":" + lineNo; if (function.equals("* not available")) {
function = "?";
}
return file + ":" + lineNo + ":" + function;
/*return executeCLICommand("line " + myCpu.reg[MSP430Constants.PC]);*/ /*return executeCLICommand("line " + myCpu.getPC());*/
} }
public MemoryMonitor createMemoryMonitor(final MemoryEventHandler meh) { public MemoryMonitor createMemoryMonitor(final MemoryEventHandler meh) {

View file

@ -36,6 +36,8 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter; import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.io.PrintStream;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
@ -43,6 +45,7 @@ import javax.swing.JScrollPane;
import javax.swing.JTextArea; import javax.swing.JTextArea;
import javax.swing.JTextField; import javax.swing.JTextField;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import se.sics.cooja.ClassDescription; import se.sics.cooja.ClassDescription;
import se.sics.cooja.GUI; import se.sics.cooja.GUI;
import se.sics.cooja.Mote; import se.sics.cooja.Mote;
@ -51,7 +54,9 @@ import se.sics.cooja.PluginType;
import se.sics.cooja.Simulation; import se.sics.cooja.Simulation;
import se.sics.cooja.VisPlugin; import se.sics.cooja.VisPlugin;
import se.sics.cooja.mspmote.MspMote; import se.sics.cooja.mspmote.MspMote;
import se.sics.mspsim.cli.CommandContext;
import se.sics.mspsim.cli.LineListener; import se.sics.mspsim.cli.LineListener;
import se.sics.mspsim.cli.LineOutputStream;
@ClassDescription("Msp CLI") @ClassDescription("Msp CLI")
@PluginType(PluginType.MOTE_PLUGIN) @PluginType(PluginType.MOTE_PLUGIN)
@ -66,8 +71,6 @@ public class MspCLI extends VisPlugin implements MotePlugin {
private int historyPos = 0; private int historyPos = 0;
private int historyCount = 0; private int historyCount = 0;
private LineListener myListener;
public MspCLI(Mote mote, Simulation simulationToVisualize, GUI gui) { public MspCLI(Mote mote, Simulation simulationToVisualize, GUI gui) {
super("Msp CLI (" + mote.getID() + ')', gui); super("Msp CLI (" + mote.getID() + ')', gui);
this.mspMote = (MspMote) mote; this.mspMote = (MspMote) mote;
@ -79,20 +82,27 @@ public class MspCLI extends VisPlugin implements MotePlugin {
logArea.setEditable(false); logArea.setEditable(false);
panel.add(new JScrollPane(logArea), BorderLayout.CENTER); panel.add(new JScrollPane(logArea), BorderLayout.CENTER);
LineListener lineListener = new LineListener() {
public void lineRead(String line) {
addCLIData(line);
}
};
PrintStream po = new PrintStream(new LineOutputStream(lineListener));
final CommandContext commandContext = new CommandContext(mspMote.getCLICommandHandler(), null, "", new String[0], 1, null);
commandContext.out = po;
commandContext.err = po;
JPopupMenu popupMenu = new JPopupMenu(); JPopupMenu popupMenu = new JPopupMenu();
JMenuItem clearItem = new JMenuItem("Clear"); JMenuItem clearItem = new JMenuItem("Clear");
clearItem.addActionListener(new ActionListener() { clearItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
logArea.setText(""); logArea.setText("");
} }
}); });
popupMenu.add(clearItem); popupMenu.add(clearItem);
logArea.setComponentPopupMenu(popupMenu); logArea.setComponentPopupMenu(popupMenu);
ActionListener action = new ActionListener() { ActionListener action = new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String command = trim(commandField.getText()); String command = trim(commandField.getText());
if (command != null) { if (command != null) {
@ -107,7 +117,8 @@ public class MspCLI extends VisPlugin implements MotePlugin {
} }
historyPos = historyCount; historyPos = historyCount;
addCLIData("> " + command); addCLIData("> " + command);
mspMote.sendCLICommand(command);
mspMote.executeCLICommand(command, commandContext);
commandField.setText(""); commandField.setText("");
} catch (Exception ex) { } catch (Exception ex) {
System.err.println("could not send '" + command + "':"); System.err.println("could not send '" + command + "':");
@ -166,19 +177,9 @@ public class MspCLI extends VisPlugin implements MotePlugin {
}); });
panel.add(commandField, BorderLayout.SOUTH); panel.add(commandField, BorderLayout.SOUTH);
myListener = new LineListener() {
public void lineRead(String line) {
addCLIData(line);
}
};
mspMote.addCLIListener(myListener);
} }
public void closePlugin() { public void closePlugin() {
if (myListener != null) {
mspMote.addCLIListener(null);
}
} }
public void addCLIData(final String text) { public void addCLIData(final String text) {

View file

@ -40,6 +40,8 @@ package se.sics.cooja.dialogs;
import java.awt.Component; import java.awt.Component;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.Arrays;
import javax.swing.JTable; import javax.swing.JTable;
import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener; import javax.swing.event.TableModelListener;
@ -68,16 +70,23 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi
this(table, 6); this(table, 6);
} }
private boolean[] adjustColumns;
/* /*
* Specify the table and spacing * Specify the table and spacing
*/ */
public TableColumnAdjuster(JTable table, int spacing) { public TableColumnAdjuster(JTable table, int spacing) {
this.table = table; this.table = table;
this.spacing = spacing; this.spacing = spacing;
TableColumnModel tcm = table.getColumnModel();
adjustColumns = new boolean[tcm.getColumnCount()];
Arrays.fill(adjustColumns, true);
setColumnHeaderIncluded(true); setColumnHeaderIncluded(true);
setColumnDataIncluded(true); setColumnDataIncluded(true);
setOnlyAdjustLarger(true); setOnlyAdjustLarger(true);
setDynamicAdjustment(false); setDynamicAdjustment(false);
} }
public void packColumns() { public void packColumns() {
@ -97,9 +106,15 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi
public void adjustColumns() { public void adjustColumns() {
TableColumnModel tcm = table.getColumnModel(); TableColumnModel tcm = table.getColumnModel();
for (int i = 0, n = tcm.getColumnCount(); i < n; i++) { for (int i = 0, n = tcm.getColumnCount(); i < n; i++) {
if (adjustColumns[i]) {
adjustColumn(i, isOnlyAdjustLarger); adjustColumn(i, isOnlyAdjustLarger);
} }
} }
}
public void setAdjustColumn(int i, boolean adjust) {
adjustColumns[i] = adjust;
}
/* /*
* Adjust the width of the specified column in the table * Adjust the width of the specified column in the table
@ -109,6 +124,9 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi
} }
private void adjustColumn(int column, boolean onlyAdjustLarger) { private void adjustColumn(int column, boolean onlyAdjustLarger) {
if (!adjustColumns[column]) {
return;
}
int viewColumn = table.convertColumnIndexToView(column); int viewColumn = table.convertColumnIndexToView(column);
if (viewColumn < 0) { if (viewColumn < 0) {
return; return;
@ -194,6 +212,9 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi
private void adjustColumnsForNewRows(int firstRow, int lastRow) { private void adjustColumnsForNewRows(int firstRow, int lastRow) {
TableColumnModel tcm = table.getColumnModel(); TableColumnModel tcm = table.getColumnModel();
for (int column = 0, n = tcm.getColumnCount(); column < n; column++) { for (int column = 0, n = tcm.getColumnCount(); column < n; column++) {
if (!adjustColumns[column]) {
continue;
}
int viewColumn = table.convertColumnIndexToView(column); int viewColumn = table.convertColumnIndexToView(column);
if (viewColumn < 0) { if (viewColumn < 0) {
continue; continue;
@ -302,6 +323,9 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi
} else if (isOnlyAdjustLarger) { } else if (isOnlyAdjustLarger) {
// Only need to worry about an increase in width for these cells // Only need to worry about an increase in width for these cells
if (!adjustColumns[column]) {
return;
}
int viewColumn = table.convertColumnIndexToView(column); int viewColumn = table.convertColumnIndexToView(column);
if (viewColumn < 0) { if (viewColumn < 0) {
// Column is not visible // Column is not visible

View file

@ -61,6 +61,10 @@ public abstract class AbstractEmulatedMote extends AbstractWakeupMote implements
return null; return null;
} }
public String getStackTrace() {
return null;
}
public interface MemoryMonitor { public interface MemoryMonitor {
public boolean start(int address, int size); public boolean start(int address, int size);
public void stop(); public void stop();

View file

@ -198,6 +198,9 @@ public class BufferListener extends VisPlugin {
private boolean hideReads = true; private boolean hideReads = true;
private JCheckBoxMenuItem hideReadsCheckbox; private JCheckBoxMenuItem hideReadsCheckbox;
private boolean withStackTrace = false;
private JCheckBoxMenuItem withStackTraceCheckbox;
private JMenu parserMenu = new JMenu("Parser"); private JMenu parserMenu = new JMenu("Parser");
private JMenu bufferMenu = new JMenu("Buffer"); private JMenu bufferMenu = new JMenu("Buffer");
@ -332,29 +335,44 @@ public class BufferListener extends VisPlugin {
java.awt.Point p = e.getPoint(); java.awt.Point p = e.getPoint();
int rowIndex = rowAtPoint(p); int rowIndex = rowAtPoint(p);
int colIndex = columnAtPoint(p); int colIndex = columnAtPoint(p);
int columnIndex = convertColumnIndexToModel(colIndex); if (rowIndex < 0 || colIndex < 0) {
if (rowIndex < 0 || columnIndex < 0) {
return super.getToolTipText(e); return super.getToolTipText(e);
} }
Object v = getValueAt(rowIndex, columnIndex); int row = convertRowIndexToModel(rowIndex);
if (v instanceof BufferAccess && parser instanceof GraphicalParser) { int column = convertColumnIndexToModel(colIndex);
return if (row < 0 || column < 0) {
"<html><font face=\"Verdana\">" + return super.getToolTipText(e);
StringUtils.hexDump(((BufferAccess)v).mem, 4, 4).replaceAll("\n", "<br>") +
"</html>";
} }
if (v != null) {
String t = v.toString(); if (column == COLUMN_SOURCE) {
if (t.length() > 60) { BufferAccess ba = logs.get(row);
if (ba.stackTrace != null) {
return
"<html><pre>" +
ba.stackTrace +
"</pre></html>";
}
return "No stack trace (enable in popup menu)";
}
if (column == COLUMN_DATA) {
BufferAccess ba = logs.get(row);
if (parser instanceof GraphicalParser) {
return
"<html><pre>" +
StringUtils.hexDump(ba.mem, 4, 4) +
"</pre></html>";
}
String baString = ba.getParsedString();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append("<html>"); sb.append("<html>");
do { while (baString.length() > 60) {
sb.append(t.substring(0, 60)).append("<br>"); sb.append(baString.substring(0, 60)).append("<br>");
t = t.substring(60); baString = baString.substring(60);
} while (t.length() > 60); };
return sb.append(t).append("</html>").toString(); return sb.append(baString).append("</html>").toString();
}
} }
return super.getToolTipText(e); return super.getToolTipText(e);
} }
}; };
@ -493,6 +511,7 @@ public class BufferListener extends VisPlugin {
/* Automatically update column widths */ /* Automatically update column widths */
final TableColumnAdjuster adjuster = new TableColumnAdjuster(logTable, 0); final TableColumnAdjuster adjuster = new TableColumnAdjuster(logTable, 0);
adjuster.packColumns(); adjuster.packColumns();
logTable.getColumnModel().getColumn(COLUMN_DATA).setWidth(400);
/* Popup menu */ /* Popup menu */
JPopupMenu popupMenu = new JPopupMenu(); JPopupMenu popupMenu = new JPopupMenu();
@ -555,7 +574,7 @@ public class BufferListener extends VisPlugin {
repaint(); repaint();
} }
}); });
hideReadsCheckbox = new JCheckBoxMenuItem("Hide READs", true); hideReadsCheckbox = new JCheckBoxMenuItem("Hide READs", hideReads);
popupMenu.add(hideReadsCheckbox); popupMenu.add(hideReadsCheckbox);
hideReadsCheckbox.addActionListener(new ActionListener() { hideReadsCheckbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
@ -565,6 +584,15 @@ public class BufferListener extends VisPlugin {
} }
}); });
withStackTraceCheckbox = new JCheckBoxMenuItem("Capture stack traces", withStackTrace);
popupMenu.add(withStackTraceCheckbox);
withStackTraceCheckbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
withStackTrace = withStackTraceCheckbox.isSelected();
setFilter(getFilter());
repaint();
}
});
logTable.setComponentPopupMenu(popupMenu); logTable.setComponentPopupMenu(popupMenu);
@ -573,6 +601,7 @@ public class BufferListener extends VisPlugin {
public void run() { public void run() {
/* Make sure this happens *after* adding history */ /* Make sure this happens *after* adding history */
adjuster.setDynamicAdjustment(true); adjuster.setDynamicAdjustment(true);
adjuster.setAdjustColumn(COLUMN_DATA, false);
} }
}); });
@ -775,6 +804,10 @@ public class BufferListener extends VisPlugin {
element = new Element("showreads"); element = new Element("showreads");
config.add(element); config.add(element);
} }
if (withStackTrace) {
element = new Element("stacktrace");
config.add(element);
}
element = new Element("parser"); element = new Element("parser");
element.setText(parser.getClass().getName()); element.setText(parser.getClass().getName());
config.add(element); config.add(element);
@ -815,6 +848,9 @@ public class BufferListener extends VisPlugin {
} else if ("showreads".equals(name)) { } else if ("showreads".equals(name)) {
hideReads = false; hideReads = false;
hideReadsCheckbox.setSelected(false); hideReadsCheckbox.setSelected(false);
} else if ("stacktrace".equals(name)) {
withStackTrace = true;
withStackTraceCheckbox.setSelected(true);
} else if ("formatted_time".equals(name)) { } else if ("formatted_time".equals(name)) {
formatTimeString = true; formatTimeString = true;
repaintTimeColumn(); repaintTimeColumn();
@ -928,6 +964,7 @@ public class BufferListener extends VisPlugin {
public final String typeStr; public final String typeStr;
public final String sourceStr; public final String sourceStr;
public final String stackTrace;
public final byte[] mem; public final byte[] mem;
private boolean[] accessedBitpattern = null; private boolean[] accessedBitpattern = null;
@ -970,6 +1007,11 @@ public class BufferListener extends VisPlugin {
typeStr = type.toString(); typeStr = type.toString();
String s = mote.getPCString(); String s = mote.getPCString();
sourceStr = s==null?"[unknown]":s; sourceStr = s==null?"[unknown]":s;
if (withStackTrace) {
this.stackTrace = mote.getStackTrace();
} else {
this.stackTrace = null;
}
} }
public Object getParsedData() { public Object getParsedData() {
@ -1285,8 +1327,7 @@ public class BufferListener extends VisPlugin {
} }
parser = bp; parser = bp;
logTable.getColumnModel().getColumn(COLUMN_DATA).setHeaderValue( logTable.getColumnModel().getColumn(COLUMN_DATA).setHeaderValue(GUI.getDescriptionOf(bp));
GUI.getDescriptionOf(bp));
repaint(); repaint();
} }

Binary file not shown.

View file

@ -29,7 +29,6 @@
* *
* This file is part of the uIP TCP/IP stack. * This file is part of the uIP TCP/IP stack.
* *
* $Id: tunslip6.c,v 1.6 2010/11/29 18:14:54 joxe Exp $
* *
*/ */
@ -596,6 +595,49 @@ ifconf(const char *tundev, const char *ipaddr)
ssystem("ifconfig %s inet `hostname` up", tundev); ssystem("ifconfig %s inet `hostname` up", tundev);
if (timestamp) stamptime(); if (timestamp) stamptime();
ssystem("ifconfig %s add %s", tundev, ipaddr); ssystem("ifconfig %s add %s", tundev, ipaddr);
/* radvd needs a link local address for routing */
#if 0
/* fe80::1/64 is good enough */
ssystem("ifconfig %s add fe80::1/64", tundev);
#elif 1
/* Generate a link local address a la sixxs/aiccu */
/* First a full parse, stripping off the prefix length */
{
char lladdr[40];
char c,*ptr=(char *)ipaddr;
uint16_t digit,ai,a[8],cc,scc,i;
for(ai=0;ai<8;ai++) a[ai]=0;
ai=0;cc=scc=0;
while(c=*ptr++) {
if(c=='/') break;
if(c==':') {
if(cc) scc = ai;
cc = 1;
if (++ai>7) break;
} else {
cc=0;
digit = c-'0'; if (digit > 9) digit = 10 + (c & 0xdf) - 'A';
a[ai] = (a[ai] << 4) + digit;
}
}
/* Get # elided and shift what's after to the end */
cc=8-ai;
for(i=0;i<cc;i++) {
if ((8-i-cc) <= scc) {
a[7-i] = 0;
} else {
a[7-i] = a[8-i-cc];
a[8-i-cc]=0;
}
}
sprintf(lladdr,"fe80::%x:%x:%x:%x",a[1]&0xfefd,a[2],a[3],a[7]);
if (timestamp) stamptime();
ssystem("ifconfig %s add %s/64", tundev, lladdr);
#endif /* link local */
#else #else
if (timestamp) stamptime(); if (timestamp) stamptime();
ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr); ssystem("ifconfig %s inet `hostname` %s up", tundev, ipaddr);
@ -684,7 +726,7 @@ main(int argc, char **argv)
fprintf(stderr,"usage: %s [options] ipaddress\n", prog); fprintf(stderr,"usage: %s [options] ipaddress\n", prog);
fprintf(stderr,"example: tunslip6 -L -v2 -s ttyUSB1 aaaa::1/64\n"); fprintf(stderr,"example: tunslip6 -L -v2 -s ttyUSB1 aaaa::1/64\n");
fprintf(stderr,"Options are:\n"); fprintf(stderr,"Options are:\n");
fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200 (default)\n"); fprintf(stderr," -B baudrate 9600,19200,38400,57600,115200 default),230400,460800,921600\n");
fprintf(stderr," -H Hardware CTS/RTS flow control (default disabled)\n"); fprintf(stderr," -H Hardware CTS/RTS flow control (default disabled)\n");
fprintf(stderr," -L Log output format (adds time stamps)\n"); fprintf(stderr," -L Log output format (adds time stamps)\n");
fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n"); fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n");
@ -733,6 +775,15 @@ exit(1);
case 115200: case 115200:
b_rate = B115200; b_rate = B115200;
break; break;
case 230400:
b_rate = B230400;
break;
case 460800:
b_rate = B460800;
break;
case 921600:
b_rate = B921600;
break;
default: default:
err(1, "unknown baudrate %d", baudrate); err(1, "unknown baudrate %d", baudrate);
break; break;