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

This commit is contained in:
Fredrik Osterlind 2012-03-06 09:25:03 +01:00
commit 485ef0cd79
27 changed files with 745 additions and 232 deletions

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

@ -745,7 +745,7 @@ coap_set_header_uri_query(void *packet, const 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

@ -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 */
@ -278,7 +278,7 @@ int coap_set_header_block(void *packet, uint32_t num, uint8_t more, uint16_t siz
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, const 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

@ -100,7 +100,7 @@ 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, mid %u\n", message->version, message->type, message->option_count, message->code, message->mid); 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);
@ -112,10 +112,10 @@ handle_incoming_data(void)
/* Use transaction buffer for response to confirmable request. */ /* Use transaction buffer for response to confirmable request. */
if ( (transaction = coap_new_transaction(message->mid, &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)
@ -143,11 +143,6 @@ 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)
@ -155,42 +150,55 @@ handle_incoming_data(void)
/* 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))
{ {
/* Apply blockwise transfers. */ if (coap_error_code==NO_ERROR)
if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
{ {
/* unchanged new_offset indicates that resource is unaware of blockwise transfer */ /* Apply blockwise transfers. */
if (new_offset==block_offset) if ( IS_OPTION(message, COAP_OPTION_BLOCK2) )
{ {
PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); /* unchanged new_offset indicates that resource is unaware of blockwise transfer */
if (block_offset >= response->payload_len) if (new_offset==block_offset)
{ {
PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n"); 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; response->code = BAD_OPTION_4_02;
coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */
}
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 else
{ {
coap_set_header_block2(response, block_num, response->payload_len - block_offset > block_size, block_size); /* resource provides chunk-wise data */
coap_set_payload(response, response->payload+block_offset, MIN(response->payload_len - block_offset, block_size)); PRINTF("Blockwise: blockwise resource, new offset %ld\n", new_offset);
} /* if (valid 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 else if (new_offset!=0)
{ {
/* resource provides chunk-wise data */ PRINTF("Blockwise: no block option for blockwise resource, using block size %u\n", REST_MAX_CHUNK_SIZE);
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_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
{ {
@ -198,14 +206,8 @@ handle_incoming_data(void)
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,11 +223,7 @@ 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_mid(message->mid)) ) if ( (transaction = coap_get_transaction_by_mid(message->mid)) )
@ -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);

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++;
@ -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);
} }
} }
@ -189,17 +213,21 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
coap_packet_t *const coap_req = (coap_packet_t *) request; coap_packet_t *const coap_req = (coap_packet_t *) request;
coap_packet_t *const coap_res = (coap_packet_t *) response; coap_packet_t *const coap_res = (coap_packet_t *) response;
static char content[26]; static char content[16];
if (coap_res && coap_res->code<128) /* response without error code */ if (coap_req->code==COAP_GET && coap_res->code<128) /* GET request and response without error code */
{ {
if (IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) if (IS_OPTION(coap_req, COAP_OPTION_OBSERVE))
{ {
if (coap_add_observer(resource->url, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, coap_req->token, coap_req->token_len)) 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); coap_set_header_observe(coap_res, 0);
coap_set_payload(coap_res, content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); /*
* 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
{ {
@ -210,7 +238,7 @@ coap_observe_handler(resource_t *resource, void *request, void *response)
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,20 +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)
{ {
coap_packet_t *const coap_req = (coap_packet_t *) request; coap_packet_t *const coap_req = (coap_packet_t *) request;
coap_packet_t *const coap_res = (coap_packet_t *) response; coap_packet_t *const coap_res = (coap_packet_t *) response;
PRINTF("Separate response for /%s \n", resource->url); PRINTF("Separate response for /%s MID %u\n", resource->url, coap_res->mid);
/* send separate ACK. */
coap_packet_t ack[1];
/* ACK with empty code (0) */
coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->mid);
/* 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. */ /* Only ack CON requests. */
coap_res->type = COAP_TYPE_CON; if (coap_req->type==COAP_TYPE_CON)
coap_res->mid = coap_get_mid(); {
coap_transaction_t *const t = coap_get_transaction_by_mid(coap_res->mid);
/* send separate ACK. */
coap_packet_t ack[1];
/* ACK with empty code (0) */
coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->mid);
/* 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), coap_serialize_message(ack, uip_appdata));
/* Change response to separate response. */
coap_res->type = COAP_TYPE_CON;
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

@ -87,6 +87,8 @@ coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr, uint16_t port)
/* 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;
@ -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

View File

@ -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 */

View File

@ -60,7 +60,7 @@ LIST(restful_periodic_services);
void void
rest_init_framework(void) rest_init_engine(void)
{ {
list_init(restful_services); list_init(restful_services);

View File

@ -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';
} }
} }
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf, UIP_DS6_ADDR_NB-j); #if WEBSERVER_CONF_SHOW_ROOM
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;
}
} }
} }
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_NBR_NB-j); #if WEBSERVER_CONF_SHOW_ROOM
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);
numprinted += httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_addrf,UIP_DS6_ROUTE_NB-j); #if WEBSERVER_CONF_SHOW_ROOM
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;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
@ -536,8 +617,14 @@ static
PT_THREAD(routes(struct httpd_state *s, char *ptr)) 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,29 +707,36 @@ 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();
snprintf(sensor_extvoltage, sizeof(sensor_extvoltage),"%u mV",1200*0xfff/adc_reading[8]); #endif
static const char httpd_cgi_sensorv[] HTTPD_STRING_ATTR = "<em>ADC chans :</em> %u %u %u %u %u %u %u %u \n"; snprintf(sensor_extvoltage, sizeof(sensor_extvoltage),"%u mV",1200*0xfff/adc_reading[8]);
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensorv,
adc_reading[0],adc_reading[1],adc_reading[2],adc_reading[3],adc_reading[4],adc_reading[5],adc_reading[6],adc_reading[7]); static const char httpd_cgi_sensorv[] HTTPD_STRING_ATTR = "<em>ADC chans :</em> %u %u %u %u %u %u %u %u \n";
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensorv,
adc_reading[0],adc_reading[1],adc_reading[2],adc_reading[3],adc_reading[4],adc_reading[5],adc_reading[6],adc_reading[7]);
} }
#endif #endif
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));
} }
numprinted+=httpd_snprintf((char *)uip_appdata+numprinted, uip_mss()-numprinted, httpd_cgi_sensor1, sensor_temperature); if (sensor_temperature[0]!='N') {
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 0 }
if (sleepseconds) { #if WEBSERVER_CONF_STATISTICS
uint8_t p1; /*---------------------------------------------------------------------------*/
p1=100UL*sleepseconds/seconds;h=sleepseconds/3600;s=sleepseconds-h*3600;m=s/60;s=s-m*60; static unsigned short
numprinted+=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_sensor4, h,m,s,p1); generate_stats(void *arg)
} {
#endif uint16_t numprinted;
uint16_t h,m,s;
uint8_t p1,p2;
uint32_t seconds=clock_seconds();
static const char httpd_cgi_stats[] HTTPD_STRING_ATTR = "\n<big><b>Statistics</b></big>\n";
numprinted=httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_stats);
#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
{ uint8_t c; #if 0
adc_reading[8]=0; /* Scan ADC channels if not already done elsewhere */
adc_init(); { uint8_t c;
while (adc_reading[8]==0) adc_service(); adc_reading[8]=0;
adc_disable(); adc_init();
numprinted = snprintf(buf, sizeof(buf),"b(%u);adc(%u,%u,%u,%u,%u,%u,%u,%u);", while (adc_reading[8]==0) adc_service();
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]); adc_disable();
#endif
#if 0
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]);
#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

@ -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

@ -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

@ -47,11 +47,12 @@
#define REST_RES_HELLO 1 #define REST_RES_HELLO 1
#define REST_RES_MIRROR 0 /* causes largest code size */ #define REST_RES_MIRROR 0 /* causes largest code size */
#define REST_RES_CHUNKS 1 #define REST_RES_CHUNKS 1
#define REST_RES_POLLING 1 #define REST_RES_SEPARATE 1
#define REST_RES_PUSHING 1
#define REST_RES_EVENT 1 #define REST_RES_EVENT 1
#define REST_RES_LEDS 1 #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 1 #define REST_RES_BATTERY 1
@ -149,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. */
@ -313,8 +313,8 @@ 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). */
const char error_msg[] = "BlockOutOfScope"; const char *error_msg = "BlockOutOfScope";
REST.set_response_payload(response, (uint8_t *)error_msg, sizeof(error_msg)-1); REST.set_response_payload(response, error_msg, strlen(error_msg));
return; return;
} }
@ -349,22 +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);
/* Usually, a CoAP server would response with the current resource representation. */ /* Usually, a CoAP server would response with the resource representation matching the periodic_handler. */
const char msg[] = "It's periodic!"; const char *msg = "It's periodic!";
REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); 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. */
} }
@ -374,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];
@ -402,10 +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);
/* Usually, a CoAP server would response with the current resource representation. */ /* Usually, a CoAP server would response with the current resource representation. */
const char msg[] = "It's eventful!"; const char *msg = "It's eventful!";
REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); 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. */
} }
@ -527,8 +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);
const char msg[] = "Supporting content-types text/plain, application/xml, and application/json"; const char *msg = "Supporting content-types text/plain, application/xml, and application/json";
REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); REST.set_response_payload(response, msg, strlen(msg));
} }
} }
#endif /* PLATFORM_HAS_LIGHT */ #endif /* PLATFORM_HAS_LIGHT */
@ -561,8 +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);
const char msg[] = "Supporting content-types text/plain and application/json"; const char *msg = "Supporting content-types text/plain and application/json";
REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); REST.set_response_payload(response, msg, strlen(msg));
} }
} }
#endif /* PLATFORM_HAS_BATTERY */ #endif /* PLATFORM_HAS_BATTERY */
@ -594,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
@ -607,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);
@ -634,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

@ -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

@ -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
CONTIKI_TARGET_DIRS = . CONTIKI_TARGET_DIRS = .
CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o}

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

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,54 @@ 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 +731,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 +780,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;