From 690e03a8a76c125c2140479b13e7a0a50083ab11 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Fri, 20 Jan 2012 16:08:24 +0100 Subject: [PATCH 01/37] Removed Erbium CoAP draft-06. --- apps/er-coap-06/Makefile.er-coap-06 | 1 - apps/er-coap-06/er-coap-06-engine.c | 561 ------------ apps/er-coap-06/er-coap-06-engine.h | 92 -- apps/er-coap-06/er-coap-06-observing.c | 201 ----- apps/er-coap-06/er-coap-06-observing.h | 76 -- apps/er-coap-06/er-coap-06-separate.c | 72 -- apps/er-coap-06/er-coap-06-separate.h | 50 -- apps/er-coap-06/er-coap-06-transactions.c | 194 ----- apps/er-coap-06/er-coap-06-transactions.h | 79 -- apps/er-coap-06/er-coap-06.c | 986 ---------------------- apps/er-coap-06/er-coap-06.h | 300 ------- 11 files changed, 2612 deletions(-) delete mode 100644 apps/er-coap-06/Makefile.er-coap-06 delete mode 100644 apps/er-coap-06/er-coap-06-engine.c delete mode 100644 apps/er-coap-06/er-coap-06-engine.h delete mode 100644 apps/er-coap-06/er-coap-06-observing.c delete mode 100644 apps/er-coap-06/er-coap-06-observing.h delete mode 100644 apps/er-coap-06/er-coap-06-separate.c delete mode 100644 apps/er-coap-06/er-coap-06-separate.h delete mode 100644 apps/er-coap-06/er-coap-06-transactions.c delete mode 100644 apps/er-coap-06/er-coap-06-transactions.h delete mode 100644 apps/er-coap-06/er-coap-06.c delete mode 100644 apps/er-coap-06/er-coap-06.h diff --git a/apps/er-coap-06/Makefile.er-coap-06 b/apps/er-coap-06/Makefile.er-coap-06 deleted file mode 100644 index ea6f4e9f4..000000000 --- a/apps/er-coap-06/Makefile.er-coap-06 +++ /dev/null @@ -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 diff --git a/apps/er-coap-06/er-coap-06-engine.c b/apps/er-coap-06/er-coap-06-engine.c deleted file mode 100644 index ff1c3a4f4..000000000 --- a/apps/er-coap-06/er-coap-06-engine.c +++ /dev/null @@ -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 - */ - -#include -#include -#include -#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]", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_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=0; --j) { \ - PRINTF("%c", (((char *)buf)[i] & 1<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", - 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_errorpt); -} -/*-----------------------------------------------------------------------------------*/ -/*- 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 - } -}; diff --git a/apps/er-coap-06/er-coap-06-engine.h b/apps/er-coap-06/er-coap-06-engine.h deleted file mode 100644 index c8c907d40..000000000 --- a/apps/er-coap-06/er-coap-06-engine.h +++ /dev/null @@ -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 - */ - -#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_ */ diff --git a/apps/er-coap-06/er-coap-06-observing.c b/apps/er-coap-06/er-coap-06-observing.c deleted file mode 100644 index 43f5fff49..000000000 --- a/apps/er-coap-06/er-coap-06-observing.c +++ /dev/null @@ -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 - */ - -#include -#include - -#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]", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_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) */ - } -} diff --git a/apps/er-coap-06/er-coap-06-observing.h b/apps/er-coap-06/er-coap-06-observing.h deleted file mode 100644 index b3f266dd0..000000000 --- a/apps/er-coap-06/er-coap-06-observing.h +++ /dev/null @@ -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 - */ - -#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 - */ - -#include -#include - -#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]", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_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(); - } -} diff --git a/apps/er-coap-06/er-coap-06-separate.h b/apps/er-coap-06/er-coap-06-separate.h deleted file mode 100644 index 079384f0c..000000000 --- a/apps/er-coap-06/er-coap-06-separate.h +++ /dev/null @@ -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 - */ - -#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_ */ diff --git a/apps/er-coap-06/er-coap-06-transactions.c b/apps/er-coap-06/er-coap-06-transactions.c deleted file mode 100644 index 980fad7f3..000000000 --- a/apps/er-coap-06/er-coap-06-transactions.c +++ /dev/null @@ -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 - */ - -#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 -#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]", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_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_countertid); - - 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); - } - } -} diff --git a/apps/er-coap-06/er-coap-06-transactions.h b/apps/er-coap-06/er-coap-06-transactions.h deleted file mode 100644 index f5e97454f..000000000 --- a/apps/er-coap-06/er-coap-06-transactions.h +++ /dev/null @@ -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 - */ - -#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_ */ diff --git a/apps/er-coap-06/er-coap-06.c b/apps/er-coap-06/er-coap-06.c deleted file mode 100644 index 013001c48..000000000 --- a/apps/er-coap-06/er-coap-06.c +++ /dev/null @@ -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 - */ - -#include "contiki.h" -#include "contiki-net.h" -#include -#include - -#include "er-coap-06.h" -#include "er-coap-06-transactions.h" - -#define DEBUG 0 -#if DEBUG -#include -#define PRINTF(...) printf(__VA_ARGS__) -#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((u8_t *)addr)[0], ((u8_t *)addr)[1], ((u8_t *)addr)[2], ((u8_t *)addr)[3], ((u8_t *)addr)[4], ((u8_t *)addr)[5], ((u8_t *)addr)[6], ((u8_t *)addr)[7], ((u8_t *)addr)[8], ((u8_t *)addr)[9], ((u8_t *)addr)[10], ((u8_t *)addr)[11], ((u8_t *)addr)[12], ((u8_t *)addr)[13], ((u8_t *)addr)[14], ((u8_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 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, ¤t_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, ¤t_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)<buffer[0] |= COAP_HEADER_TYPE_MASK & (((coap_packet_t *)packet)->type)<buffer[0] |= COAP_HEADER_OPTION_COUNT_MASK & (((coap_packet_t *)packet)->option_count)<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; -} -/*-----------------------------------------------------------------------------------*/ diff --git a/apps/er-coap-06/er-coap-06.h b/apps/er-coap-06/er-coap-06.h deleted file mode 100644 index a5ad954e6..000000000 --- a/apps/er-coap-06/er-coap-06.h +++ /dev/null @@ -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 - */ - -#ifndef COAP_06_H_ -#define COAP_06_H_ - -#include /* 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<options & 1L< Date: Fri, 20 Jan 2012 16:11:45 +0100 Subject: [PATCH 02/37] Fixed snprintf() return value handling. --- apps/er-coap-07/er-coap-07-engine.c | 15 +++++-- .../er-rest-example/rest-server-example.c | 45 ++++++++++--------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index 245072b8e..d2e4f9b63 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -301,13 +301,14 @@ coap_set_rest_status(void *packet, unsigned int code) /*-----------------------------------------------------------------------------------*/ /*- Server part ---------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ + /* The discover resource is automatically included for CoAP. */ RESOURCE(well_known_core, METHOD_GET, ".well-known/core", "ct=40"); void well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { - size_t strpos = 0; - size_t bufpos = 0; + size_t strpos = 0; /* position in overall string (which is larger than the buffer) */ + size_t bufpos = 0; /* position within buffer (bytes written) */ size_t tmplen = 0; resource_t* resource = NULL; @@ -333,6 +334,10 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->url + ((*offset-(int32_t)strpos > 0) ? (*offset-(int32_t)strpos) : 0)); /* minimal-net requires these casts */ + if (bufpos >= preferred_size) + { + break; + } } strpos += tmplen; @@ -355,6 +360,10 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t { bufpos += snprintf((char *) buffer + bufpos, preferred_size - bufpos + 1, "%s", resource->attributes + (*offset-(int32_t)strpos > 0 ? *offset-(int32_t)strpos : 0)); + if (bufpos >= preferred_size) + { + break; + } } strpos += tmplen; } @@ -397,7 +406,7 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t else { PRINTF("res: MORE at %s (%p)\n", resource->url, resource); - *offset += bufpos; + *offset += preferred_size; } } /*-----------------------------------------------------------------------------------*/ diff --git a/examples/er-rest-example/rest-server-example.c b/examples/er-rest-example/rest-server-example.c index 8373d9917..d76b622c1 100644 --- a/examples/er-rest-example/rest-server-example.c +++ b/examples/er-rest-example/rest-server-example.c @@ -45,14 +45,14 @@ /* Define which resources to include to meet memory constraints. */ #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_POLLING 0 +#define REST_RES_POLLING 1 #define REST_RES_EVENT 1 -#define REST_RES_LEDS 0 +#define REST_RES_LEDS 1 #define REST_RES_TOGGLE 1 #define REST_RES_LIGHT 1 -#define REST_RES_BATTERY 0 +#define REST_RES_BATTERY 1 @@ -173,28 +173,29 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre int strpos = 0; /* 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); /* Some getters such as for ETag or Location are omitted, as these options should not appear in a request. * Max-Age might appear in HTTP requests or used for special purposes in CoAP. */ - if (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); } - 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); } /* CoAP-specific example: actions not required for normal RESTful Web service. */ #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); } - 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"); int index = 0; @@ -203,7 +204,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"); } - 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"); int index = 0; @@ -212,34 +213,34 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre } 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, "%.*s\n", len, str); } #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); } - 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); } #elif WITH_COAP >= 5 - 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); } - 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); } - 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); } - 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. */ + if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) /* This getter allows NULL pointers to get only a subset of the block parameters. */ { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B1 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); } @@ -250,16 +251,16 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre #endif #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); } - 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); } - if (strpos == REST_MAX_CHUNK_SIZE) + if (strpos >= REST_MAX_CHUNK_SIZE) { buffer[REST_MAX_CHUNK_SIZE-1] = 0xBB; /* '»' to indicate truncation */ } @@ -332,7 +333,7 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre strpos = preferred_size; } - /* Truncate if above total size. */ + /* Truncate if above CHUNKS_TOTAL bytes. */ if (*offset+(int32_t)strpos > CHUNKS_TOTAL) { strpos = CHUNKS_TOTAL - *offset; From 4c3e858df5bebbb6413ae47d1fc06e4499e2cb69 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Fri, 20 Jan 2012 18:30:12 +0100 Subject: [PATCH 03/37] Made Erbium function parameters const where applicable.\nMinor clean-up. --- apps/er-coap-03/er-coap-03.c | 24 ++++++------- apps/er-coap-03/er-coap-03.h | 22 ++++++------ apps/er-coap-07/er-coap-07.c | 36 +++++++++++-------- apps/er-coap-07/er-coap-07.h | 32 ++++++++--------- apps/erbium/erbium.c | 27 -------------- apps/erbium/erbium.h | 8 ++--- examples/er-rest-example/Makefile | 10 ++---- examples/er-rest-example/README | 27 ++++++++++---- examples/er-rest-example/project-conf.h | 2 +- .../er-rest-example/rest-server-example.c | 27 ++++++-------- 10 files changed, 99 insertions(+), 116 deletions(-) diff --git a/apps/er-coap-03/er-coap-03.c b/apps/er-coap-03/er-coap-03.c index b02227ba2..af20f0b5c 100644 --- a/apps/er-coap-03/er-coap-03.c +++ b/apps/er-coap-03/er-coap-03.c @@ -191,7 +191,7 @@ coap_get_tid() } /*-----------------------------------------------------------------------------------*/ 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*/ uip_ipaddr_copy(&udp_conn->ripaddr, addr); @@ -586,7 +586,7 @@ coap_get_header_etag(void *packet, const uint8_t **etag) } 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); 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 -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); SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST); @@ -615,20 +615,20 @@ coap_set_header_uri_host(void *packet, char *host) } /*-----------------------------------------------------------------------------------*/ 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; - *uri = ((coap_packet_t *)packet)->location_path; + *location = ((coap_packet_t *)packet)->location_path; return ((coap_packet_t *)packet)->location_path_len; } int -coap_set_header_location(void *packet, char *location) +coap_set_header_location(void *packet, const char *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); 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 -coap_set_header_uri_path(void *packet, char *path) +coap_set_header_uri_path(void *packet, const char *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); 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 -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); 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 -coap_set_header_uri_query(void *packet, char *query) +coap_set_header_uri_query(void *packet, const char *query) { while (query[0]=='?') ++query; diff --git a/apps/er-coap-03/er-coap-03.h b/apps/er-coap-03/er-coap-03.h index 169188aab..9b5f3a887 100644 --- a/apps/er-coap-03/er-coap-03.h +++ b/apps/er-coap-03/er-coap-03.h @@ -200,11 +200,11 @@ typedef struct { uint8_t etag_len; uint8_t etag[COAP_ETAG_LEN]; uint8_t uri_host_len; - char *uri_host; + const char *uri_host; uint8_t location_path_len; - char *location_path; + const char *location_path; uint8_t uri_path_len; - char *uri_path; + const char *uri_path; uint32_t observe; /* 0-4 bytes for coap-03 */ uint8_t token_len; uint8_t token[COAP_TOKEN_LEN]; @@ -213,7 +213,7 @@ typedef struct { uint16_t block_size; uint32_t block_offset; uint8_t uri_query_len; - char *uri_query; + const char *uri_query; uint16_t payload_len; uint8_t *payload; @@ -236,7 +236,7 @@ typedef enum void coap_init_connection(uint16_t port); 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); int coap_serialize_message(void *packet, uint8_t *buffer); @@ -255,28 +255,28 @@ 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_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_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_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_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_set_header_observe(void *packet, uint32_t observe); 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_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_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_set_payload(void *packet, uint8_t *payload, size_t length); diff --git a/apps/er-coap-07/er-coap-07.c b/apps/er-coap-07/er-coap-07.c index 1e3223b2e..b87fb1928 100644 --- a/apps/er-coap-07/er-coap-07.c +++ b/apps/er-coap-07/er-coap-07.c @@ -209,6 +209,7 @@ coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option, size_t opt /* Merge multiple options. */ if (*dst_len > 0) { + /* dst already contains an option: concatenate */ (*dst)[*dst_len] = separator; *dst_len += 1; @@ -219,7 +220,8 @@ coap_merge_multi_option(char **dst, size_t *dst_len, uint8_t *option, size_t opt } else { - *dst = (char *) option; /* thus pointer pointer */ + /* dst is empty: set to option */ + *dst = (char *) option; *dst_len = option_len; } } @@ -613,7 +615,8 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_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, '/'); + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option( (char **) &(((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: @@ -621,11 +624,13 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_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, '&'); + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option( (char **) &(((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, '/'); + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option( (char **) &(((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: @@ -673,7 +678,8 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) 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, '&'); + /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ + coap_merge_multi_option( (char **) &(((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: @@ -752,7 +758,7 @@ coap_set_header_content_type(void *packet, unsigned int content_type) } /*-----------------------------------------------------------------------------------*/ int -coap_get_header_accept(void *packet, uint16_t **accept) +coap_get_header_accept(void *packet, const uint16_t **accept) { if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_ACCEPT)) return 0; @@ -802,7 +808,7 @@ coap_get_header_etag(void *packet, const uint8_t **etag) } 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); memcpy(((coap_packet_t *)packet)->etag, etag, ((coap_packet_t *)packet)->etag_len); @@ -822,7 +828,7 @@ 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) +coap_set_header_if_match(void *packet, const uint8_t *etag, size_t etag_len) { ((coap_packet_t *)packet)->if_match_len = MIN(COAP_ETAG_LEN, etag_len); memcpy(((coap_packet_t *)packet)->if_match, etag, ((coap_packet_t *)packet)->if_match_len); @@ -854,7 +860,7 @@ coap_get_header_token(void *packet, const uint8_t **token) } 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); memcpy(((coap_packet_t *)packet)->token, token, ((coap_packet_t *)packet)->token_len); @@ -873,7 +879,7 @@ coap_get_header_proxy_uri(void *packet, const char **uri) } int -coap_set_header_proxy_uri(void *packet, char *uri) +coap_set_header_proxy_uri(void *packet, const char *uri) { ((coap_packet_t *)packet)->proxy_uri = uri; ((coap_packet_t *)packet)->proxy_uri_len = strlen(uri); @@ -892,7 +898,7 @@ coap_get_header_uri_host(void *packet, const char **host) } 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 = host; ((coap_packet_t *)packet)->uri_host_len = strlen(host); @@ -911,7 +917,7 @@ coap_get_header_uri_path(void *packet, const char **path) } int -coap_set_header_uri_path(void *packet, char *path) +coap_set_header_uri_path(void *packet, const char *path) { while (path[0]=='/') ++path; @@ -932,7 +938,7 @@ coap_get_header_uri_query(void *packet, const char **query) } int -coap_set_header_uri_query(void *packet, char *query) +coap_set_header_uri_query(void *packet, const char *query) { while (query[0]=='?') ++query; @@ -953,7 +959,7 @@ coap_get_header_location_path(void *packet, const char **path) } int -coap_set_header_location_path(void *packet, char *path) +coap_set_header_location_path(void *packet, const char *path) { char *query; @@ -985,7 +991,7 @@ coap_get_header_location_query(void *packet, const char **query) } int -coap_set_header_location_query(void *packet, char *query) +coap_set_header_location_query(void *packet, const char *query) { while (query[0]=='?') ++query; diff --git a/apps/er-coap-07/er-coap-07.h b/apps/er-coap-07/er-coap-07.h index 13c83b1e0..f7f622404 100644 --- a/apps/er-coap-07/er-coap-07.h +++ b/apps/er-coap-07/er-coap-07.h @@ -213,18 +213,18 @@ typedef struct { 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; + const char *proxy_uri; uint8_t etag_len; uint8_t etag[COAP_ETAG_LEN]; size_t uri_host_len; - char *uri_host; + const char *uri_host; size_t location_path_len; - char *location_path; + const char *location_path; uint16_t uri_port; size_t location_query_len; - char *location_query; + const char *location_query; size_t uri_path_len; - char *uri_path; + const char *uri_path; uint16_t observe; uint8_t token_len; uint8_t token[COAP_TOKEN_LEN]; @@ -241,7 +241,7 @@ typedef struct { uint16_t block1_size; uint32_t block1_offset; size_t uri_query_len; - char *uri_query; + const char *uri_query; uint8_t if_none_match; uint16_t payload_len; @@ -268,41 +268,41 @@ 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_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_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_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_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_set_header_if_none_match(void *packet); 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_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_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_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_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_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_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_set_header_observe(void *packet, uint32_t observe); diff --git a/apps/erbium/erbium.c b/apps/erbium/erbium.c index 007b1ee2f..53d129d8f 100644 --- a/apps/erbium/erbium.c +++ b/apps/erbium/erbium.c @@ -59,33 +59,6 @@ LIST(restful_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= 5 +#else 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); @@ -240,15 +238,15 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre { strpos += snprintf((char *)buffer+strpos, REST_MAX_CHUNK_SIZE-strpos+1, "B2 %lu%s (%u)\n", block_num, block_more ? "+" : "", block_size); } - if (strpos<=REST_MAX_CHUNK_SIZE && coap_get_header_block1(request, &block_num, &block_more, &block_size, NULL)) /* 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); } -#if WITH_COAP >= 7 - -#endif - -#endif + */ +#endif /* CoAP > 03 */ #endif /* CoAP-specific example */ if (strpos<=REST_MAX_CHUNK_SIZE && (len = REST.get_query(request, &query))) @@ -281,16 +279,13 @@ mirror_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre coap_set_header_observe(response, 10); #if WITH_COAP == 3 coap_set_header_block(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ -#elif WITH_COAP >= 5 +#else coap_set_header_proxy_uri(response, "ftp://x"); coap_set_header_block2(response, 42, 0, 64); /* The block option might be overwritten by the framework when blockwise transfer is requested. */ coap_set_header_block1(response, 23, 0, 16); -#if WITH_COAP >= 7 coap_set_header_accept(response, TEXT_PLAIN); coap_set_header_if_none_match(response); -#endif - -#endif +#endif /* CoAP > 03 */ #endif /* CoAP-specific example */ } #endif /* REST_RES_MIRROR */ @@ -497,7 +492,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_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); if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) @@ -537,7 +532,7 @@ battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr { int battery = battery_sensor.value(0); - uint16_t *accept = NULL; + const uint16_t *accept = NULL; int num = REST.get_header_accept(request, &accept); if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) From 2240289d1f70a5b28a7f8bd32b68ca220ab12c34 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Sat, 28 Jan 2012 18:52:14 +0100 Subject: [PATCH 04/37] Erbium code cleanup. --- apps/er-coap-07/er-coap-07-engine.c | 6 +- apps/er-coap-07/er-coap-07-observing.c | 22 +- apps/er-coap-07/er-coap-07-separate.c | 9 +- apps/er-coap-07/er-coap-07.c | 687 ++++++++++-------- apps/er-coap-07/er-coap-07.h | 4 +- apps/erbium/erbium.h | 4 +- examples/er-rest-example/README | 3 +- .../er-rest-example/coap-client-example.c | 13 +- .../er-rest-example/rest-server-example.c | 22 +- 9 files changed, 430 insertions(+), 340 deletions(-) diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index d2e4f9b63..875db015e 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -167,7 +167,7 @@ handle_incoming_data(void) PRINTF("handle_incoming_data(): block_offset >= response->payload_len\n"); 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 { @@ -259,7 +259,7 @@ handle_incoming_data(void) } /* 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_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)); } } /* if (new data) */ @@ -396,7 +396,7 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t PRINTF("well_known_core_handler(): bufpos<=0\n"); coap_set_rest_status(response, BAD_OPTION_4_02); - coap_set_payload(response, (uint8_t*)"BlockOutOfScope", 15); + coap_set_payload(response, "BlockOutOfScope", 15); } if (resource==NULL) { diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index 6c6ed7f1c..5ef27f024 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -186,27 +186,25 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl void 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_res = (coap_packet_t *) response; + static char content[26]; - if (response && ((coap_packet_t *)response)->code<128) /* response without error code */ + if (coap_res && coap_res->code<128) /* response without error code */ { - if (IS_OPTION((coap_packet_t *)request, COAP_OPTION_OBSERVE)) + if (IS_OPTION(coap_req, 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_add_observer(resource->url, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, coap_req->token, coap_req->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)); + 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)); } else { - ((coap_packet_t *)response)->code = SERVICE_UNAVAILABLE_5_03; - coap_set_payload(response, (uint8_t *)"Too many observers", 18); + coap_res->code = SERVICE_UNAVAILABLE_5_03; + coap_set_payload(coap_res, "TooManyObservers", 16); } /* if (added observer) */ } else /* if (observe) */ diff --git a/apps/er-coap-07/er-coap-07-separate.c b/apps/er-coap-07/er-coap-07-separate.c index f27aed4a7..ef6266dbf 100644 --- a/apps/er-coap-07/er-coap-07-separate.c +++ b/apps/er-coap-07/er-coap-07-separate.c @@ -55,15 +55,18 @@ /*-----------------------------------------------------------------------------------*/ void 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_res = (coap_packet_t *) response; + 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); + coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->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(); + coap_res->type = COAP_TYPE_CON; + coap_res->tid = coap_get_tid(); } diff --git a/apps/er-coap-07/er-coap-07.c b/apps/er-coap-07/er-coap-07.c index b87fb1928..895a6e587 100644 --- a/apps/er-coap-07/er-coap-07.c +++ b/apps/er-coap-07/er-coap-07.c @@ -288,234 +288,238 @@ coap_get_tid() 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 *const coap_pkt = (coap_packet_t *) packet; - ((coap_packet_t *)packet)->type = type; - ((coap_packet_t *)packet)->code = code; - ((coap_packet_t *)packet)->tid = tid; + /* Important thing */ + memset(coap_pkt, 0, sizeof(coap_packet_t)); + + coap_pkt->type = type; + coap_pkt->code = code; + coap_pkt->tid = tid; } /*-----------------------------------------------------------------------------------*/ size_t coap_serialize_message(void *packet, uint8_t *buffer) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + /* Initialize */ - ((coap_packet_t *)packet)->buffer = buffer; - ((coap_packet_t *)packet)->version = 1; - ((coap_packet_t *)packet)->option_count = 0; + coap_pkt->buffer = buffer; + coap_pkt->version = 1; + coap_pkt->option_count = 0; /* serialize options */ - uint8_t *option = ((coap_packet_t *)packet)->buffer + COAP_HEADER_LEN; + uint8_t *option = coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_CONTENT_TYPE)) { + PRINTF("Content-Type [%u]\n", coap_pkt->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; + option += serialize_int_option(COAP_OPTION_CONTENT_TYPE, current_number, option, coap_pkt->content_type); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_MAX_AGE)) { + PRINTF("Max-Age [%lu]\n", coap_pkt->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; + option += serialize_int_option(COAP_OPTION_MAX_AGE, current_number, option, coap_pkt->max_age); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) { + PRINTF("Proxy-Uri [%.*s]\n", coap_pkt->proxy_uri_len, coap_pkt->proxy_uri); - int length = ((coap_packet_t *)packet)->proxy_uri_len; + int length = coap_pkt->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; + option += serialize_array_option(COAP_OPTION_PROXY_URI, current_number, option, (uint8_t *) coap_pkt->proxy_uri + j*270, MIN(270, length), NULL); + coap_pkt->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] + if (IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) { + PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->etag_len, + coap_pkt->etag[0], + coap_pkt->etag[1], + coap_pkt->etag[2], + coap_pkt->etag[3], + coap_pkt->etag[4], + coap_pkt->etag[5], + coap_pkt->etag[6], + coap_pkt->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; + option += serialize_array_option(COAP_OPTION_ETAG, current_number, option, coap_pkt->etag, coap_pkt->etag_len, NULL); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_URI_HOST)) { + PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->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; + option += serialize_array_option(COAP_OPTION_URI_HOST, current_number, option, (uint8_t *) coap_pkt->uri_host, coap_pkt->uri_host_len, NULL); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH)) { + PRINTF("Location [%.*s]\n", coap_pkt->location_path_len, coap_pkt->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; + option += serialize_array_option(COAP_OPTION_LOCATION_PATH, current_number, option, (uint8_t *) coap_pkt->location_path, coap_pkt->location_path_len, &split_options); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_URI_PORT)) { + PRINTF("Uri-Port [%u]\n", coap_pkt->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; + option += serialize_int_option(COAP_OPTION_URI_PORT, current_number, option, coap_pkt->uri_port); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) { + PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, coap_pkt->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; + option += serialize_array_option(COAP_OPTION_LOCATION_QUERY, current_number, option, (uint8_t *) coap_pkt->location_query, coap_pkt->location_query_len, &split_options); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_URI_PATH)) { + PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->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; + option += serialize_array_option(COAP_OPTION_URI_PATH, current_number, option, (uint8_t *) coap_pkt->uri_path, coap_pkt->uri_path_len, &split_options); + coap_pkt->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); + if (IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) { + PRINTF("Observe [%u]\n", coap_pkt->observe); - option += serialize_int_option(COAP_OPTION_OBSERVE, current_number, option, ((coap_packet_t *)packet)->observe); - ((coap_packet_t *)packet)->option_count += 1; + option += serialize_int_option(COAP_OPTION_OBSERVE, current_number, option, coap_pkt->observe); + coap_pkt->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] + if (IS_OPTION(coap_pkt, COAP_OPTION_TOKEN)) { + PRINTF("Token %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->token_len, + coap_pkt->token[0], + coap_pkt->token[1], + coap_pkt->token[2], + coap_pkt->token[3], + coap_pkt->token[4], + coap_pkt->token[5], + coap_pkt->token[6], + coap_pkt->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; + option += serialize_array_option(COAP_OPTION_TOKEN, current_number, option, coap_pkt->token, coap_pkt->token_len, NULL); + coap_pkt->option_count += 1; current_number = COAP_OPTION_TOKEN; } - if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_ACCEPT)) { + if (IS_OPTION(coap_pkt, COAP_OPTION_ACCEPT)) { int i; - for (i=0; i<((coap_packet_t *)packet)->accept_num; ++i) + for (i=0; iaccept_num; ++i) { - PRINTF("Accept [%u]\n", ((coap_packet_t *)packet)->accept[i]); + PRINTF("Accept [%u]\n", coap_pkt->accept[i]); - option += serialize_int_option(COAP_OPTION_ACCEPT, current_number, option, (uint32_t)((coap_packet_t *)packet)->accept[i]); - ((coap_packet_t *)packet)->option_count += 1; + option += serialize_int_option(COAP_OPTION_ACCEPT, current_number, option, (uint32_t)coap_pkt->accept[i]); + coap_pkt->option_count += 1; current_number = COAP_OPTION_ACCEPT; } } - if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_IF_MATCH)) { + if (IS_OPTION(coap_pkt, COAP_OPTION_IF_MATCH)) { PRINTF("If-Match [FIXME]\n"); - option += serialize_array_option(COAP_OPTION_IF_MATCH, current_number, option, ((coap_packet_t *)packet)->if_match, ((coap_packet_t *)packet)->if_match_len, NULL); - ((coap_packet_t *)packet)->option_count += 1; + option += serialize_array_option(COAP_OPTION_IF_MATCH, current_number, option, coap_pkt->if_match, coap_pkt->if_match_len, NULL); + coap_pkt->option_count += 1; current_number = COAP_OPTION_IF_MATCH; } - 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); + if (IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { + PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, coap_pkt->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; + option += serialize_array_option(COAP_OPTION_URI_QUERY, current_number, option, (uint8_t *) coap_pkt->uri_query, coap_pkt->uri_query_len, &split_options); + coap_pkt->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)) + if (IS_OPTION(coap_pkt, 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); + PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, coap_pkt->block2_more ? "+" : "", coap_pkt->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); + uint32_t block = coap_pkt->block2_num << 4; + if (coap_pkt->block2_more) block |= 0x8; + block |= 0xF & log_2(coap_pkt->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; + coap_pkt->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)) + if (IS_OPTION(coap_pkt, 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); + PRINTF("Block1 [%lu%s (%u B/blk)]\n", coap_pkt->block1_num, coap_pkt->block1_more ? "+" : "", coap_pkt->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); + uint32_t block = coap_pkt->block1_num << 4; + if (coap_pkt->block1_more) block |= 0x8; + block |= 0xF & log_2(coap_pkt->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; + coap_pkt->option_count += 1 + (COAP_OPTION_BLOCK1-current_number)/COAP_OPTION_FENCE_POST; current_number = COAP_OPTION_BLOCK1; } - if (IS_OPTION((coap_packet_t *)packet, COAP_OPTION_IF_NONE_MATCH)) { + if (IS_OPTION(coap_pkt, COAP_OPTION_IF_NONE_MATCH)) { PRINTF("If-None-Match\n"); option += serialize_int_option(COAP_OPTION_IF_NONE_MATCH, current_number, option, 0); - ((coap_packet_t *)packet)->option_count += 1 + (COAP_OPTION_IF_NONE_MATCH-current_number)/COAP_OPTION_FENCE_POST; + coap_pkt->option_count += 1 + (COAP_OPTION_IF_NONE_MATCH-current_number)/COAP_OPTION_FENCE_POST; current_number = COAP_OPTION_IF_NONE_MATCH; } /* pack payload */ - if ((option - ((coap_packet_t *)packet)->buffer)<=COAP_MAX_HEADER_SIZE) + if ((option - coap_pkt->buffer)<=COAP_MAX_HEADER_SIZE) { - memmove(option, ((coap_packet_t *)packet)->payload, ((coap_packet_t *)packet)->payload_len); + memmove(option, coap_pkt->payload, coap_pkt->payload_len); } else { /* An error occured. Caller must check for !=0. */ - ((coap_packet_t *)packet)->buffer = NULL; + coap_pkt->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)<buffer[0] |= COAP_HEADER_TYPE_MASK & (((coap_packet_t *)packet)->type)<buffer[0] |= COAP_HEADER_OPTION_COUNT_MASK & (((coap_packet_t *)packet)->option_count)<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; + coap_pkt->buffer[0] = 0x00; + coap_pkt->buffer[0] |= COAP_HEADER_VERSION_MASK & (coap_pkt->version)<buffer[0] |= COAP_HEADER_TYPE_MASK & (coap_pkt->type)<buffer[0] |= COAP_HEADER_OPTION_COUNT_MASK & (coap_pkt->option_count)<buffer[1] = coap_pkt->code; + coap_pkt->buffer[2] = 0xFF & (coap_pkt->tid)>>8; + coap_pkt->buffer[3] = 0xFF & coap_pkt->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); + PRINTF("-Done %u options, header len %u, payload len %u-\n", coap_pkt->option_count, option - buffer, coap_pkt->payload_len); - return (option - buffer) + ((coap_packet_t *)packet)->payload_len; /* packet length */ + return (option - buffer) + coap_pkt->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*/ + /* Configure connection to reply to client */ uip_ipaddr_copy(&udp_conn->ripaddr, addr); udp_conn->rport = port; @@ -530,38 +534,40 @@ coap_send_message(uip_ipaddr_t *addr, uint16_t port, uint8_t *data, uint16_t len coap_status_t coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + /* Initialize packet */ - memset(packet, 0, sizeof(coap_packet_t)); + memset(coap_pkt, 0, sizeof(coap_packet_t)); /* pointer to packet bytes */ - ((coap_packet_t *)packet)->buffer = data; + coap_pkt->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]; + coap_pkt->version = (COAP_HEADER_VERSION_MASK & coap_pkt->buffer[0])>>COAP_HEADER_VERSION_POSITION; + coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])>>COAP_HEADER_TYPE_POSITION; + coap_pkt->option_count = (COAP_HEADER_OPTION_COUNT_MASK & coap_pkt->buffer[0])>>COAP_HEADER_OPTION_COUNT_POSITION; + coap_pkt->code = coap_pkt->buffer[1]; + coap_pkt->tid = coap_pkt->buffer[2]<<8 | coap_pkt->buffer[3]; - if (((coap_packet_t *)packet)->version != 1) + if (coap_pkt->version != 1) { coap_error_message = "CoAP version must be 1"; return BAD_REQUEST_4_00; } /* parse options */ - ((coap_packet_t *)packet)->options = 0x0000; + coap_pkt->options = 0x0000; uint8_t *current_option = data + COAP_HEADER_LEN; - if (((coap_packet_t *)packet)->option_count) + if (coap_pkt->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) { + PRINTF("-Parsing %u options-\n", coap_pkt->option_count); + for (option_index=0; option_index < coap_pkt->option_count; ++option_index) { current_number += current_option[0]>>4; @@ -575,103 +581,103 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) current_option += 2; } - SET_OPTION((coap_packet_t *)packet, current_number); + SET_OPTION(coap_pkt, 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); + coap_pkt->content_type = parse_int_option(current_option, option_len); + PRINTF("Content-Type [%u]\n", coap_pkt->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); + coap_pkt->max_age = parse_int_option(current_option, option_len); + PRINTF("Max-Age [%lu]\n", coap_pkt->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; + coap_pkt->proxy_uri = (char *) current_option; + coap_pkt->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); + PRINTF("Proxy-Uri NOT IMPLEMENTED [%.*s]\n", coap_pkt->proxy_uri_len, coap_pkt->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] + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, option_len); + memcpy(coap_pkt->etag, current_option, coap_pkt->etag_len); + PRINTF("ETag %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->etag_len, + coap_pkt->etag[0], + coap_pkt->etag[1], + coap_pkt->etag[2], + coap_pkt->etag[3], + coap_pkt->etag[4], + coap_pkt->etag[5], + coap_pkt->etag[6], + coap_pkt->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); + coap_pkt->uri_host = (char *) current_option; + coap_pkt->uri_host_len = option_len; + PRINTF("Uri-Host [%.*s]\n", coap_pkt->uri_host_len, coap_pkt->uri_host); break; case COAP_OPTION_LOCATION_PATH: /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ - coap_merge_multi_option( (char **) &(((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); + coap_merge_multi_option( (char **) &(coap_pkt->location_path), &(coap_pkt->location_path_len), current_option, option_len, '/'); + PRINTF("Location-Path [%.*s]\n", coap_pkt->location_path_len, coap_pkt->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); + coap_pkt->uri_port = parse_int_option(current_option, option_len); + PRINTF("Uri-Port [%u]\n", coap_pkt->uri_port); break; case COAP_OPTION_LOCATION_QUERY: /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ - coap_merge_multi_option( (char **) &(((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); + coap_merge_multi_option( (char **) &(coap_pkt->location_query), &(coap_pkt->location_query_len), current_option, option_len, '&'); + PRINTF("Location-Query [%.*s]\n", coap_pkt->location_query_len, coap_pkt->location_query); break; case COAP_OPTION_URI_PATH: /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ - coap_merge_multi_option( (char **) &(((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); + coap_merge_multi_option( (char **) &(coap_pkt->uri_path), &(coap_pkt->uri_path_len), current_option, option_len, '/'); + PRINTF("Uri-Path [%.*s]\n", coap_pkt->uri_path_len, coap_pkt->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); + coap_pkt->observe = parse_int_option(current_option, option_len); + PRINTF("Observe [%u]\n", coap_pkt->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] + coap_pkt->token_len = MIN(COAP_TOKEN_LEN, option_len); + memcpy(coap_pkt->token, current_option, coap_pkt->token_len); + PRINTF("Token %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->token_len, + coap_pkt->token[0], + coap_pkt->token[1], + coap_pkt->token[2], + coap_pkt->token[3], + coap_pkt->token[4], + coap_pkt->token[5], + coap_pkt->token[6], + coap_pkt->token[7] ); /*FIXME always prints 8 bytes */ break; case COAP_OPTION_ACCEPT: - if (((coap_packet_t *)packet)->accept_num < COAP_MAX_ACCEPT_NUM) + if (coap_pkt->accept_num < COAP_MAX_ACCEPT_NUM) { - ((coap_packet_t *)packet)->accept[((coap_packet_t *)packet)->accept_num] = parse_int_option(current_option, option_len); - ((coap_packet_t *)packet)->accept_num += 1; - PRINTF("Accept [%u]\n", ((coap_packet_t *)packet)->content_type); + coap_pkt->accept[coap_pkt->accept_num] = parse_int_option(current_option, option_len); + coap_pkt->accept_num += 1; + PRINTF("Accept [%u]\n", coap_pkt->content_type); } break; case COAP_OPTION_IF_MATCH: /*FIXME support multiple ETags */ - ((coap_packet_t *)packet)->if_match_len = MIN(COAP_ETAG_LEN, option_len); - memcpy(((coap_packet_t *)packet)->if_match, current_option, ((coap_packet_t *)packet)->if_match_len); - PRINTF("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", ((coap_packet_t *)packet)->if_match_len, - ((coap_packet_t *)packet)->if_match[0], - ((coap_packet_t *)packet)->if_match[1], - ((coap_packet_t *)packet)->if_match[2], - ((coap_packet_t *)packet)->if_match[3], - ((coap_packet_t *)packet)->if_match[4], - ((coap_packet_t *)packet)->if_match[5], - ((coap_packet_t *)packet)->if_match[6], - ((coap_packet_t *)packet)->if_match[7] + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, option_len); + memcpy(coap_pkt->if_match, current_option, coap_pkt->if_match_len); + PRINTF("If-Match %u [0x%02X%02X%02X%02X%02X%02X%02X%02X]\n", coap_pkt->if_match_len, + coap_pkt->if_match[0], + coap_pkt->if_match[1], + coap_pkt->if_match[2], + coap_pkt->if_match[3], + coap_pkt->if_match[4], + coap_pkt->if_match[5], + coap_pkt->if_match[6], + coap_pkt->if_match[7] ); /*FIXME always prints 8 bytes */ break; case COAP_OPTION_FENCE_POST: @@ -679,16 +685,16 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) break; case COAP_OPTION_URI_QUERY: /* coap_merge_multi_option() operates in-place on the IPBUF, but final packet field should be const string -> cast to string */ - coap_merge_multi_option( (char **) &(((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); + coap_merge_multi_option( (char **) &(coap_pkt->uri_query), &(coap_pkt->uri_query_len), current_option, option_len, '&'); + PRINTF("Uri-Query [%.*s]\n", coap_pkt->uri_query_len, coap_pkt->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 & ~0x0000000F)<<(((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); + coap_pkt->block2_num = parse_int_option(current_option, option_len); + coap_pkt->block2_more = (coap_pkt->block2_num & 0x08)>>3; + coap_pkt->block2_size = 16 << (coap_pkt->block2_num & 0x07); + coap_pkt->block2_offset = (coap_pkt->block2_num & ~0x0000000F)<<(coap_pkt->block2_num & 0x07); + coap_pkt->block2_num >>= 4; + PRINTF("Block2 [%lu%s (%u B/blk)]\n", coap_pkt->block2_num, coap_pkt->block2_more ? "+" : "", coap_pkt->block2_size); break; case COAP_OPTION_BLOCK1: PRINTF("Block1 NOT IMPLEMENTED\n"); @@ -697,7 +703,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) return NOT_IMPLEMENTED_5_01; break; case COAP_OPTION_IF_NONE_MATCH: - ((coap_packet_t *)packet)->if_none_match = 1; + coap_pkt->if_none_match = 1; PRINTF("If-None-Match\n"); break; default: @@ -715,8 +721,17 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) 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); + coap_pkt->payload = current_option; + coap_pkt->payload_len = data_len - (coap_pkt->payload - data); + + /* also for receiving, the Erbium upper bound is REST_MAX_CHUNK_SIZE */ + if (coap_pkt->payload_len > REST_MAX_CHUNK_SIZE) + { + coap_pkt->payload_len = REST_MAX_CHUNK_SIZE; + } + + /* Null-terminate payload */ + coap_pkt->payload[coap_pkt->payload_len] = '\0'; return NO_ERROR; } @@ -726,8 +741,10 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) 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); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + if (IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) { + return coap_get_variable(coap_pkt->uri_query, coap_pkt->uri_query_len, name, output); } return 0; } @@ -735,8 +752,10 @@ 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) { - 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); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + if (coap_pkt->payload_len) { + return coap_get_variable((const char *)coap_pkt->payload, coap_pkt->payload_len, name, output); } return 0; } @@ -752,40 +771,48 @@ coap_get_header_content_type(void *packet) 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); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->content_type = (coap_content_type_t) content_type; + SET_OPTION(coap_pkt, COAP_OPTION_CONTENT_TYPE); return 1; } /*-----------------------------------------------------------------------------------*/ int coap_get_header_accept(void *packet, const uint16_t **accept) { - if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_ACCEPT)) return 0; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *accept = ((coap_packet_t *)packet)->accept; - return ((coap_packet_t *)packet)->accept_num; + if (!IS_OPTION(coap_pkt, COAP_OPTION_ACCEPT)) return 0; + + *accept = coap_pkt->accept; + return coap_pkt->accept_num; } int coap_set_header_accept(void *packet, uint16_t accept) { - if (((coap_packet_t *)packet)->accept_num < COAP_MAX_ACCEPT_NUM) - { - ((coap_packet_t *)packet)->accept[((coap_packet_t *)packet)->accept_num] = accept; - ((coap_packet_t *)packet)->accept_num += 1; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_ACCEPT); + if (coap_pkt->accept_num < COAP_MAX_ACCEPT_NUM) + { + coap_pkt->accept[coap_pkt->accept_num] = accept; + coap_pkt->accept_num += 1; + + SET_OPTION(coap_pkt, COAP_OPTION_ACCEPT); } - return ((coap_packet_t *)packet)->accept_num; + return coap_pkt->accept_num; } /*-----------------------------------------------------------------------------------*/ int coap_get_header_max_age(void *packet, uint32_t *age) { - if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_MAX_AGE)) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, COAP_OPTION_MAX_AGE)) { *age = COAP_DEFAULT_MAX_AGE; } else { - *age = ((coap_packet_t *)packet)->max_age; + *age = coap_pkt->max_age; } return 1; } @@ -793,48 +820,58 @@ coap_get_header_max_age(void *packet, uint32_t *age) 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); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->max_age = age; + SET_OPTION(coap_pkt, 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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *etag = ((coap_packet_t *)packet)->etag; - return ((coap_packet_t *)packet)->etag_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_ETAG)) return 0; + + *etag = coap_pkt->etag; + return coap_pkt->etag_len; } int 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); - memcpy(((coap_packet_t *)packet)->etag, etag, ((coap_packet_t *)packet)->etag_len); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_ETAG); - return ((coap_packet_t *)packet)->etag_len; + coap_pkt->etag_len = MIN(COAP_ETAG_LEN, etag_len); + memcpy(coap_pkt->etag, etag, coap_pkt->etag_len); + + SET_OPTION(coap_pkt, COAP_OPTION_ETAG); + return coap_pkt->etag_len; } /*-----------------------------------------------------------------------------------*/ /*FIXME support multiple ETags */ int coap_get_header_if_match(void *packet, const uint8_t **etag) { - if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_IF_MATCH)) return 0; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *etag = ((coap_packet_t *)packet)->if_match; - return ((coap_packet_t *)packet)->if_match_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_IF_MATCH)) return 0; + + *etag = coap_pkt->if_match; + return coap_pkt->if_match_len; } int coap_set_header_if_match(void *packet, const uint8_t *etag, size_t etag_len) { - ((coap_packet_t *)packet)->if_match_len = MIN(COAP_ETAG_LEN, etag_len); - memcpy(((coap_packet_t *)packet)->if_match, etag, ((coap_packet_t *)packet)->if_match_len); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_IF_MATCH); - return ((coap_packet_t *)packet)->if_match_len; + coap_pkt->if_match_len = MIN(COAP_ETAG_LEN, etag_len); + memcpy(coap_pkt->if_match, etag, coap_pkt->if_match_len); + + SET_OPTION(coap_pkt, COAP_OPTION_IF_MATCH); + return coap_pkt->if_match_len; } /*-----------------------------------------------------------------------------------*/ int @@ -853,114 +890,138 @@ coap_set_header_if_none_match(void *packet) int coap_get_header_token(void *packet, const uint8_t **token) { - if (!IS_OPTION((coap_packet_t *)packet, COAP_OPTION_TOKEN)) return 0; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *token = ((coap_packet_t *)packet)->token; - return ((coap_packet_t *)packet)->token_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_TOKEN)) return 0; + + *token = coap_pkt->token; + return coap_pkt->token_len; } int 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); - memcpy(((coap_packet_t *)packet)->token, token, ((coap_packet_t *)packet)->token_len); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_TOKEN); - return ((coap_packet_t *)packet)->token_len; + coap_pkt->token_len = MIN(COAP_TOKEN_LEN, token_len); + memcpy(coap_pkt->token, token, coap_pkt->token_len); + + SET_OPTION(coap_pkt, COAP_OPTION_TOKEN); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *uri = ((coap_packet_t *)packet)->proxy_uri; - return ((coap_packet_t *)packet)->proxy_uri_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_PROXY_URI)) return 0; + + *uri = coap_pkt->proxy_uri; + return coap_pkt->proxy_uri_len; } int coap_set_header_proxy_uri(void *packet, const char *uri) { - ((coap_packet_t *)packet)->proxy_uri = uri; - ((coap_packet_t *)packet)->proxy_uri_len = strlen(uri); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_PROXY_URI); - return ((coap_packet_t *)packet)->proxy_uri_len; + coap_pkt->proxy_uri = uri; + coap_pkt->proxy_uri_len = strlen(uri); + + SET_OPTION(coap_pkt, COAP_OPTION_PROXY_URI); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *host = ((coap_packet_t *)packet)->uri_host; - return ((coap_packet_t *)packet)->uri_host_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_URI_HOST)) return 0; + + *host = coap_pkt->uri_host; + return coap_pkt->uri_host_len; } int coap_set_header_uri_host(void *packet, const char *host) { - ((coap_packet_t *)packet)->uri_host = host; - ((coap_packet_t *)packet)->uri_host_len = strlen(host); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_HOST); - return ((coap_packet_t *)packet)->uri_host_len; + coap_pkt->uri_host = host; + coap_pkt->uri_host_len = strlen(host); + + SET_OPTION(coap_pkt, COAP_OPTION_URI_HOST); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *path = ((coap_packet_t *)packet)->uri_path; - return ((coap_packet_t *)packet)->uri_path_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_URI_PATH)) return 0; + + *path = coap_pkt->uri_path; + return coap_pkt->uri_path_len; } int coap_set_header_uri_path(void *packet, const char *path) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + while (path[0]=='/') ++path; - ((coap_packet_t *)packet)->uri_path = path; - ((coap_packet_t *)packet)->uri_path_len = strlen(path); + coap_pkt->uri_path = path; + coap_pkt->uri_path_len = strlen(path); - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_PATH); - return ((coap_packet_t *)packet)->uri_path_len; + SET_OPTION(coap_pkt, COAP_OPTION_URI_PATH); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *query = ((coap_packet_t *)packet)->uri_query; - return ((coap_packet_t *)packet)->uri_query_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_URI_QUERY)) return 0; + + *query = coap_pkt->uri_query; + return coap_pkt->uri_query_len; } int coap_set_header_uri_query(void *packet, const char *query) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + while (query[0]=='?') ++query; - ((coap_packet_t *)packet)->uri_query = query; - ((coap_packet_t *)packet)->uri_query_len = strlen(query); + coap_pkt->uri_query = query; + coap_pkt->uri_query_len = strlen(query); - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_URI_QUERY); - return ((coap_packet_t *)packet)->uri_query_len; + SET_OPTION(coap_pkt, COAP_OPTION_URI_QUERY); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *path = ((coap_packet_t *)packet)->location_path; - return ((coap_packet_t *)packet)->location_path_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH)) return 0; + + *path = coap_pkt->location_path; + return coap_pkt->location_path_len; } int coap_set_header_location_path(void *packet, const char *path) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + char *query; while (path[0]=='/') ++path; @@ -968,67 +1029,77 @@ coap_set_header_location_path(void *packet, const char *path) if ((query = strchr(path, '?'))) { coap_set_header_location_query(packet, query+1); - ((coap_packet_t *)packet)->location_path_len = query - path; + coap_pkt->location_path_len = query - path; } else { - ((coap_packet_t *)packet)->location_path_len = strlen(path); + coap_pkt->location_path_len = strlen(path); } - ((coap_packet_t *)packet)->location_path = path; + coap_pkt->location_path = path; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_PATH); - return ((coap_packet_t *)packet)->location_path_len; + SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_PATH); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *query = ((coap_packet_t *)packet)->location_query; - return ((coap_packet_t *)packet)->location_query_len; + if (!IS_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY)) return 0; + + *query = coap_pkt->location_query; + return coap_pkt->location_query_len; } int coap_set_header_location_query(void *packet, const char *query) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + while (query[0]=='?') ++query; - ((coap_packet_t *)packet)->location_query = query; - ((coap_packet_t *)packet)->location_query_len = strlen(query); + coap_pkt->location_query = query; + coap_pkt->location_query_len = strlen(query); - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_LOCATION_QUERY); - return ((coap_packet_t *)packet)->location_query_len; + SET_OPTION(coap_pkt, COAP_OPTION_LOCATION_QUERY); + return coap_pkt->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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; - *observe = ((coap_packet_t *)packet)->observe; + if (!IS_OPTION(coap_pkt, COAP_OPTION_OBSERVE)) return 0; + + *observe = coap_pkt->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); + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + coap_pkt->observe = observe; + SET_OPTION(coap_pkt, 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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, 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; + if (num!=NULL) *num = coap_pkt->block2_num; + if (more!=NULL) *more = coap_pkt->block2_more; + if (size!=NULL) *size = coap_pkt->block2_size; + if (offset!=NULL) *offset = coap_pkt->block2_offset; return 1; } @@ -1036,28 +1107,32 @@ coap_get_header_block2(void *packet, uint32_t *num, uint8_t *more, uint16_t *siz int coap_set_header_block2(void *packet, uint32_t num, uint8_t more, uint16_t size) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + 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 ? 1 : 0; - ((coap_packet_t *)packet)->block2_size = size; + coap_pkt->block2_num = num; + coap_pkt->block2_more = more ? 1 : 0; + coap_pkt->block2_size = size; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK2); + SET_OPTION(coap_pkt, 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; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + if (!IS_OPTION(coap_pkt, 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; + if (num!=NULL) *num = coap_pkt->block1_num; + if (more!=NULL) *more = coap_pkt->block1_more; + if (size!=NULL) *size = coap_pkt->block1_size; + if (offset!=NULL) *offset = coap_pkt->block1_offset; return 1; } @@ -1065,26 +1140,30 @@ coap_get_header_block1(void *packet, uint32_t *num, uint8_t *more, uint16_t *siz int coap_set_header_block1(void *packet, uint32_t num, uint8_t more, uint16_t size) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + 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; + coap_pkt->block1_num = num; + coap_pkt->block1_more = more; + coap_pkt->block1_size = size; - SET_OPTION((coap_packet_t *)packet, COAP_OPTION_BLOCK1); + SET_OPTION(coap_pkt, COAP_OPTION_BLOCK1); return 1; } /*-----------------------------------------------------------------------------------*/ /*- PAYLOAD -------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ int -coap_get_payload(void *packet, const uint8_t **payload) +coap_get_payload(void *packet, uint8_t **payload) { - if (((coap_packet_t *)packet)->payload) { - *payload = ((coap_packet_t *)packet)->payload; - return ((coap_packet_t *)packet)->payload_len; + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + + if (coap_pkt->payload) { + *payload = coap_pkt->payload; + return coap_pkt->payload_len; } else { *payload = NULL; return 0; @@ -1092,13 +1171,15 @@ coap_get_payload(void *packet, const uint8_t **payload) } int -coap_set_payload(void *packet, uint8_t *payload, size_t length) +coap_set_payload(void *packet, const void *payload, size_t length) { + coap_packet_t *const coap_pkt = (coap_packet_t *) packet; + 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); + coap_pkt->payload = (uint8_t *) payload; + coap_pkt->payload_len = MIN(REST_MAX_CHUNK_SIZE, length); - return ((coap_packet_t *)packet)->payload_len; + return coap_pkt->payload_len; } /*-----------------------------------------------------------------------------------*/ diff --git a/apps/er-coap-07/er-coap-07.h b/apps/er-coap-07/er-coap-07.h index f7f622404..d7aead6d5 100644 --- a/apps/er-coap-07/er-coap-07.h +++ b/apps/er-coap-07/er-coap-07.h @@ -313,7 +313,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_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); +int coap_get_payload(void *packet, uint8_t **payload); +int coap_set_payload(void *packet, const void *payload, size_t length); #endif /* COAP_07_H_ */ diff --git a/apps/erbium/erbium.h b/apps/erbium/erbium.h index 2ab637e3e..f550deeed 100644 --- a/apps/erbium/erbium.h +++ b/apps/erbium/erbium.h @@ -184,10 +184,10 @@ struct rest_implementation { int (* set_header_location)(void *response, const char *location); /** 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. */ - 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. */ int (* get_query)(void *request, const char **value); diff --git a/examples/er-rest-example/README b/examples/er-rest-example/README index 3642a1b05..df390ce83 100644 --- a/examples/er-rest-example/README +++ b/examples/er-rest-example/README @@ -59,7 +59,7 @@ DETAILS The Erbium CoAP currently implements draft 08. Central features are commented in rest-server-example.c. In general, apps/er-coap-07 supports: -* All CoAP-07 header options +* All draft 08 header options * CON Retransmissions (note COAP_MAX_OPEN_TRANSACTIONS) * Blockwise Transfers (note REST_MAX_CHUNK_SIZE) * Separate Responses (see rest_set_pre_handler() and coap_separate_handler()) @@ -73,6 +73,7 @@ The Makefile uses WITH_COAP to configure different implementations for the Erbiu 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 diff --git a/examples/er-rest-example/coap-client-example.c b/examples/er-rest-example/coap-client-example.c index 1bd5f1fac..c67840306 100644 --- a/examples/er-rest-example/coap-client-example.c +++ b/examples/er-rest-example/coap-client-example.c @@ -99,7 +99,7 @@ static int uri_switch = 0; void client_chunk_handler(void *response) { - const uint8_t *chunk; + uint8_t *chunk; int len = coap_get_payload(response, &chunk); printf("|%.*s", len, (char *)chunk); } @@ -128,16 +128,13 @@ PROCESS_THREAD(coap_client_example, ev, data) if (etimer_expired(&et)) { printf("--Toggle timer--\n"); -#if PLATFORM_HAS_LEDS /* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ coap_init_message(request, COAP_TYPE_CON, COAP_POST, 0 ); coap_set_header_uri_path(request, service_urls[1]); - coap_set_payload(request, (uint8_t *)"Toggle!", 8); -#else - /* prepare request, TID is set by COAP_BLOCKING_REQUEST() */ - coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0 ); - coap_set_header_uri_path(request, "hello"); -#endif + + const char msg[] = "Toggle!"; + coap_set_payload(request, (uint8_t *)msg, sizeof(msg)-1); + PRINT6ADDR(&server_ipaddr); PRINTF(" : %u\n", UIP_HTONS(REMOTE_PORT)); diff --git a/examples/er-rest-example/rest-server-example.c b/examples/er-rest-example/rest-server-example.c index a1b334a5c..f36209ba2 100644 --- a/examples/er-rest-example/rest-server-example.c +++ b/examples/er-rest-example/rest-server-example.c @@ -158,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. */ uint32_t max_age = 0; - const char *str = ""; + const char *str = NULL; uint32_t observe = 0; const uint8_t *bytes = NULL; uint32_t block_num = 0; @@ -312,7 +312,9 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre { REST.set_response_status(response, REST.status.BAD_OPTION); /* 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, (uint8_t *)error_msg, sizeof(error_msg)-1); return; } @@ -359,7 +361,10 @@ void polling_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - REST.set_response_payload(response, (uint8_t *)"It's periodic!", 14); + + /* Usually, a CoAP server would response with the current resource representation. */ + const char msg[] = "It's periodic!"; + REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ } @@ -397,7 +402,10 @@ void event_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - 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, sizeof(msg)-1); /* A post_handler that handles subscriptions/observing will be called for periodic resources by the framework. */ } @@ -519,7 +527,8 @@ light_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred else { REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE); - REST.set_response_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, (uint8_t *)msg, sizeof(msg)-1); } } #endif /* PLATFORM_HAS_LIGHT */ @@ -552,7 +561,8 @@ battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr else { REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE); - REST.set_response_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, (uint8_t *)msg, sizeof(msg)-1); } } #endif /* PLATFORM_HAS_BATTERY */ From a4589ee9dad34af5c5ee039a5a2797cbf98a64b8 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Sat, 28 Jan 2012 19:21:13 +0100 Subject: [PATCH 05/37] Renamed CoAP transaction ID (tid) to message ID (mid). --- apps/er-coap-07/er-coap-07-engine.c | 18 +++++++++--------- apps/er-coap-07/er-coap-07-observing.c | 4 ++-- apps/er-coap-07/er-coap-07-separate.c | 4 ++-- apps/er-coap-07/er-coap-07-transactions.c | 18 +++++++++--------- apps/er-coap-07/er-coap-07-transactions.h | 6 +++--- apps/er-coap-07/er-coap-07.c | 18 +++++++++--------- apps/er-coap-07/er-coap-07.h | 8 ++++---- 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index 875db015e..a65262172 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -102,7 +102,7 @@ handle_incoming_data(void) /*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(" 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(" Payload: %.*s\n", message->payload_len, message->payload); @@ -110,7 +110,7 @@ handle_incoming_data(void) 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)) ) + if ( (transaction = coap_new_transaction(message->mid, &UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport)) ) { static uint32_t block_num = 0; static uint16_t block_size = REST_MAX_CHUNK_SIZE; @@ -121,12 +121,12 @@ handle_incoming_data(void) 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); + coap_init_message(response, COAP_TYPE_ACK, CONTENT_2_05, message->mid); } else { /* 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) */ @@ -228,7 +228,7 @@ handle_incoming_data(void) } } - 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. */ restful_response_handler callback = transaction->callback; @@ -258,7 +258,7 @@ handle_incoming_data(void) 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_init_message(message, COAP_TYPE_ACK, coap_error_code, message->mid); 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)); } @@ -462,8 +462,8 @@ PT_THREAD(coap_blocking_request(struct request_state_t *state, process_event_t e block_error = 0; do { - request->tid = coap_get_tid(); - if ((state->transaction = coap_new_transaction(request->tid, remote_ipaddr, remote_port))) + request->mid = coap_get_mid(); + if ((state->transaction = coap_new_transaction(request->mid, remote_ipaddr, remote_port))) { state->transaction->callback = blocking_request_callback; state->transaction->callback_data = state; @@ -476,7 +476,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); 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); diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index 5ef27f024..042358ded 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -154,7 +154,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 */ - 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. */ if (stimer_expired(&obs->refresh_timer)) @@ -166,7 +166,7 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl /* 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_init_message(push, (coap_message_type_t)type, CONTENT_2_05, transaction->mid ); coap_set_header_observe(push, observe); coap_set_header_token(push, obs->token, obs->token_len); coap_set_payload(push, payload, payload_len); diff --git a/apps/er-coap-07/er-coap-07-separate.c b/apps/er-coap-07/er-coap-07-separate.c index ef6266dbf..4377de7a2 100644 --- a/apps/er-coap-07/er-coap-07-separate.c +++ b/apps/er-coap-07/er-coap-07-separate.c @@ -62,11 +62,11 @@ void coap_separate_handler(resource_t *resource, void *request, void *response) /* send separate ACK. */ coap_packet_t ack[1]; /* ACK with empty code (0) */ - coap_init_message(ack, COAP_TYPE_ACK, 0, coap_req->tid); + 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. */ coap_res->type = COAP_TYPE_CON; - coap_res->tid = coap_get_tid(); + coap_res->mid = coap_get_mid(); } diff --git a/apps/er-coap-07/er-coap-07-transactions.c b/apps/er-coap-07/er-coap-07-transactions.c index 739fd746a..5b56cd477 100644 --- a/apps/er-coap-07/er-coap-07-transactions.c +++ b/apps/er-coap-07/er-coap-07-transactions.c @@ -75,13 +75,13 @@ coap_register_as_transaction_handler() } 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); if (t) { - t->tid = tid; + t->mid = mid; t->retrans_counter = 0; /* save client address */ @@ -95,7 +95,7 @@ coap_new_transaction(uint16_t tid, uip_ipaddr_t *addr, uint16_t port) void 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); @@ -103,7 +103,7 @@ coap_send_transaction(coap_transaction_t *t) { if (t->retrans_countertid); + PRINTF("Keeping transaction %u\n", t->mid); if (t->retrans_counter==0) { @@ -154,7 +154,7 @@ coap_clear_transaction(coap_transaction_t *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); list_remove(transactions_list, t); @@ -163,15 +163,15 @@ coap_clear_transaction(coap_transaction_t *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; 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; } } @@ -188,7 +188,7 @@ coap_check_transactions() if (etimer_expired(&t->retrans_timer)) { ++(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); } } diff --git a/apps/er-coap-07/er-coap-07-transactions.h b/apps/er-coap-07/er-coap-07-transactions.h index e78a2ef55..0301ec13d 100644 --- a/apps/er-coap-07/er-coap-07-transactions.h +++ b/apps/er-coap-07/er-coap-07-transactions.h @@ -52,7 +52,7 @@ typedef struct coap_transaction { struct coap_transaction *next; /* for LIST */ - uint16_t tid; + uint16_t mid; struct etimer retrans_timer; uint8_t retrans_counter; @@ -68,10 +68,10 @@ typedef struct coap_transaction { 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_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(); diff --git a/apps/er-coap-07/er-coap-07.c b/apps/er-coap-07/er-coap-07.c index 895a6e587..3745f722f 100644 --- a/apps/er-coap-07/er-coap-07.c +++ b/apps/er-coap-07/er-coap-07.c @@ -61,7 +61,7 @@ /*- Variables -----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ static struct uip_udp_conn *udp_conn = NULL; -static uint16_t current_tid = 0; +static uint16_t current_mid = 0; coap_status_t coap_error_code = NO_ERROR; char *coap_error_message = ""; @@ -274,19 +274,19 @@ coap_init_connection(uint16_t port) PRINTF("Listening on port %u\n", uip_ntohs(udp_conn->lport)); /* Initialize transaction ID. */ - current_tid = random_rand(); + current_mid = random_rand(); } /*-----------------------------------------------------------------------------------*/ uint16_t -coap_get_tid() +coap_get_mid() { - return ++current_tid; + return ++current_mid; } /*-----------------------------------------------------------------------------------*/ /*- MEASSAGE PROCESSING -------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ void -coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t tid) +coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t mid) { coap_packet_t *const coap_pkt = (coap_packet_t *) packet; @@ -295,7 +295,7 @@ coap_init_message(void *packet, coap_message_type_t type, uint8_t code, uint16_t coap_pkt->type = type; coap_pkt->code = code; - coap_pkt->tid = tid; + coap_pkt->mid = mid; } /*-----------------------------------------------------------------------------------*/ size_t @@ -508,8 +508,8 @@ coap_serialize_message(void *packet, uint8_t *buffer) coap_pkt->buffer[0] |= COAP_HEADER_TYPE_MASK & (coap_pkt->type)<buffer[0] |= COAP_HEADER_OPTION_COUNT_MASK & (coap_pkt->option_count)<buffer[1] = coap_pkt->code; - coap_pkt->buffer[2] = 0xFF & (coap_pkt->tid)>>8; - coap_pkt->buffer[3] = 0xFF & coap_pkt->tid; + coap_pkt->buffer[2] = 0xFF & (coap_pkt->mid)>>8; + coap_pkt->buffer[3] = 0xFF & coap_pkt->mid; PRINTF("-Done %u options, header len %u, payload len %u-\n", coap_pkt->option_count, option - buffer, coap_pkt->payload_len); @@ -547,7 +547,7 @@ coap_parse_message(void *packet, uint8_t *data, uint16_t data_len) coap_pkt->type = (COAP_HEADER_TYPE_MASK & coap_pkt->buffer[0])>>COAP_HEADER_TYPE_POSITION; coap_pkt->option_count = (COAP_HEADER_OPTION_COUNT_MASK & coap_pkt->buffer[0])>>COAP_HEADER_OPTION_COUNT_POSITION; coap_pkt->code = coap_pkt->buffer[1]; - coap_pkt->tid = coap_pkt->buffer[2]<<8 | coap_pkt->buffer[3]; + coap_pkt->mid = coap_pkt->buffer[2]<<8 | coap_pkt->buffer[3]; if (coap_pkt->version != 1) { diff --git a/apps/er-coap-07/er-coap-07.h b/apps/er-coap-07/er-coap-07.h index d7aead6d5..2346765da 100644 --- a/apps/er-coap-07/er-coap-07.h +++ b/apps/er-coap-07/er-coap-07.h @@ -54,7 +54,7 @@ #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_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_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 */ @@ -206,7 +206,7 @@ typedef struct { coap_message_type_t type; uint8_t option_count; uint8_t code; - uint16_t tid; + uint16_t mid; uint32_t options; /* Bitmap to check if option is set */ @@ -255,9 +255,9 @@ 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); +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); 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); From f23e86f5890ad8af2d57765746deb449fd1f7ea1 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Mon, 30 Jan 2012 01:28:43 +0100 Subject: [PATCH 06/37] Moved status code API from REST engine to main coap implementation. --- apps/er-coap-07/er-coap-07-engine.c | 18 ++---------------- apps/er-coap-07/er-coap-07.c | 14 ++++++++++++++ apps/er-coap-07/er-coap-07.h | 4 ++++ examples/er-rest-example/Makefile | 14 ++++++++++++++ examples/er-rest-example/coap-client-example.c | 1 + 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index a65262172..f058d499b 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -285,20 +285,6 @@ 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 ---------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ @@ -395,7 +381,7 @@ well_known_core_handler(void* request, void* response, uint8_t *buffer, uint16_t { 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, "BlockOutOfScope", 15); } @@ -522,7 +508,7 @@ const struct rest_implementation coap_rest_implementation = { coap_get_header_uri_path, coap_set_header_uri_path, coap_get_rest_method, - coap_set_rest_status, + coap_set_status_code, coap_get_header_content_type, coap_set_header_content_type, diff --git a/apps/er-coap-07/er-coap-07.c b/apps/er-coap-07/er-coap-07.c index 3745f722f..c5c72abaa 100644 --- a/apps/er-coap-07/er-coap-07.c +++ b/apps/er-coap-07/er-coap-07.c @@ -760,6 +760,20 @@ coap_get_post_variable(void *packet, const char *name, const char **output) return 0; } /*-----------------------------------------------------------------------------------*/ +int +coap_set_status_code(void *packet, unsigned int code) +{ + if (code <= 0xFF) + { + ((coap_packet_t *)packet)->code = (uint8_t) code; + return 1; + } + else + { + return 0; + } +} +/*-----------------------------------------------------------------------------------*/ /*- HEADER OPTION GETTERS AND SETTERS -----------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ unsigned int diff --git a/apps/er-coap-07/er-coap-07.h b/apps/er-coap-07/er-coap-07.h index 2346765da..62f943898 100644 --- a/apps/er-coap-07/er-coap-07.h +++ b/apps/er-coap-07/er-coap-07.h @@ -265,6 +265,10 @@ 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); +/*-----------------------------------------------------------------------------------*/ + +int coap_set_status_code(void *packet, unsigned int code); + unsigned int coap_get_header_content_type(void *packet); int coap_set_header_content_type(void *packet, unsigned int content_type); diff --git a/examples/er-rest-example/Makefile b/examples/er-rest-example/Makefile index 50678a2db..3a9c02c58 100644 --- a/examples/er-rest-example/Makefile +++ b/examples/er-rest-example/Makefile @@ -50,8 +50,22 @@ endif APPS += erbium +#CUSTOM_RULE_C_TO_OBJECTDIR_O = 1 +#CUSTOM_RULE_S_TO_OBJECTDIR_O = 1 + 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 (cd $(CONTIKI)/tools && $(MAKE) tunslip6) diff --git a/examples/er-rest-example/coap-client-example.c b/examples/er-rest-example/coap-client-example.c index c67840306..4c6af9298 100644 --- a/examples/er-rest-example/coap-client-example.c +++ b/examples/er-rest-example/coap-client-example.c @@ -100,6 +100,7 @@ void client_chunk_handler(void *response) { uint8_t *chunk; + int len = coap_get_payload(response, &chunk); printf("|%.*s", len, (char *)chunk); } From 417a2b691f398f96eeac5d8c3025ad23b2fadf7f Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Thu, 23 Feb 2012 13:59:39 -0800 Subject: [PATCH 07/37] increase uip buffer size for native border router --- examples/ipv6/native-border-router/project-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ipv6/native-border-router/project-conf.h b/examples/ipv6/native-border-router/project-conf.h index 6258b4eca..90576783a 100644 --- a/examples/ipv6/native-border-router/project-conf.h +++ b/examples/ipv6/native-border-router/project-conf.h @@ -37,7 +37,7 @@ #define QUEUEBUF_CONF_NUM 4 #undef UIP_CONF_BUFFER_SIZE -#define UIP_CONF_BUFFER_SIZE 140 +#define UIP_CONF_BUFFER_SIZE 1280 #undef UIP_CONF_RECEIVE_WINDOW #define UIP_CONF_RECEIVE_WINDOW 60 From 008250afc64e6fa4692b95638f2c8edd29878aa1 Mon Sep 17 00:00:00 2001 From: Mariano Alvira Date: Fri, 24 Feb 2012 12:19:05 -0500 Subject: [PATCH 08/37] econotag: increase UIP_CONF_RECEIVE_WINDOW to 300 for webserver nano --- platform/redbee-econotag/contiki-conf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/redbee-econotag/contiki-conf.h b/platform/redbee-econotag/contiki-conf.h index 1e87ea5e9..1aee86f44 100644 --- a/platform/redbee-econotag/contiki-conf.h +++ b/platform/redbee-econotag/contiki-conf.h @@ -227,7 +227,7 @@ typedef unsigned long rtimer_clock_t; #define UIP_CONF_DHCP_LIGHT #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_MAX_CONNECTIONS 4 #define UIP_CONF_MAX_LISTENPORTS 8 From 9c99d46e24ac79e96b62eddbd9877be2a5273aa6 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Tue, 21 Feb 2012 23:57:22 +0000 Subject: [PATCH 09/37] Simplified host OS platform detection in Makefiles --- Makefile.include | 9 +++++ cpu/avr/Makefile.avr | 10 ----- cpu/mc1322x/Makefile.mc1322x | 3 +- cpu/stm32w108/Makefile.stm32w108 | 6 +-- doc/Makefile | 12 +++--- platform/cooja/Makefile.cooja | 8 ---- platform/esb/Makefile.esb | 24 ++++------- platform/iris/Makefile.iris | 14 ++----- platform/mb851/Makefile.mb851 | 6 +-- platform/mbxxx/Makefile.mbxxx | 6 +-- platform/micaz/Makefile.micaz | 14 ++----- platform/minimal-net/Makefile.minimal-net | 4 +- platform/msb430/Makefile.msb430 | 24 ++++------- platform/native/Makefile.native | 2 +- platform/sky/Makefile.common | 40 +++++++++---------- platform/stepper-robot/Makefile.stepper-robot | 9 ----- platform/stm32test/Makefile.stm32test | 9 ----- 17 files changed, 66 insertions(+), 134 deletions(-) diff --git a/Makefile.include b/Makefile.include index 0c2988548..e00c804d2 100644 --- a/Makefile.include +++ b/Makefile.include @@ -21,6 +21,15 @@ ifeq ($(DEFINES),) endif endif +ifndef HOST_OS + ifeq ($(OS),Windows_NT) + $(warning Windows (NT) deteced.) + HOST_OS := Windows + else + HOST_OS := $(shell uname) + endif +endif + usage: @echo "make MAKETARGETS... [TARGET=(TARGET)] [savetarget] [targets]" diff --git a/cpu/avr/Makefile.avr b/cpu/avr/Makefile.avr index 8a94b9eb0..611c8d1a1 100644 --- a/cpu/avr/Makefile.avr +++ b/cpu/avr/Makefile.avr @@ -1,15 +1,5 @@ # $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: ### Optimization setting. $make OPTI=0 for easier debugging of changed source file(s) diff --git a/cpu/mc1322x/Makefile.mc1322x b/cpu/mc1322x/Makefile.mc1322x index 389185b05..c0a95b009 100644 --- a/cpu/mc1322x/Makefile.mc1322x +++ b/cpu/mc1322x/Makefile.mc1322x @@ -72,8 +72,7 @@ CUSTOM_RULE_C_TO_O=yes CFLAGS += -I$(OBJECTDIR) -I$(CONTIKI_CPU)/board -DBOARD=$(TARGET) $(OBJECTDIR)/board.h: $(OBJECTDIR) -ifneq (,$(findstring Windows,$(OS))) - ${info Cygwin detected.} +ifeq ($(HOST_OS),Windows) ln -f $(CONTIKI_CPU)/board/board.h $(OBJECTDIR)/board.h else ln -sf ../$(CONTIKI_CPU)/board/board.h $(OBJECTDIR)/board.h diff --git a/cpu/stm32w108/Makefile.stm32w108 b/cpu/stm32w108/Makefile.stm32w108 index 494de3a31..7eae06d4c 100644 --- a/cpu/stm32w108/Makefile.stm32w108 +++ b/cpu/stm32w108/Makefile.stm32w108 @@ -166,10 +166,8 @@ endif FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher # Check if we are running under Windows -ifdef OS - ifneq (,$(findstring Windows,$(OS))) - FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher.exe - endif +ifeq ($(HOST_OS),Windows) + FLASHER = $(CONTIKI)/tools/stm32w/stm32w_flasher/stm32w_flasher.exe endif diff --git a/doc/Makefile b/doc/Makefile index 36f37491e..5e1591985 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -13,12 +13,12 @@ export doclatex := NO export docroot := ../ # Get appropriate root for doxygen path cutoff -ifneq (,$(findstring Windows,$(OS))) -# on windows need to convert cygwin path to windows path for doxygen -ifneq (,$(findstring cygdrive,$(pwd))) - cygroot = $(subst /,$(space),$(patsubst /cygdrive/%,%,$(pwd))) - export docroot = $(firstword $(cygroot)):/$(subst $(space),/,$(wordlist 2,$(words $(cygroot)),$(cygroot))) -endif +ifeq ($(HOST_OS),Windows) + # on windows need to convert cygwin path to windows path for doxygen + ifneq (,$(findstring cygdrive,$(pwd))) + cygroot = $(subst /,$(space),$(patsubst /cygdrive/%,%,$(pwd))) + export docroot = $(firstword $(cygroot)):/$(subst $(space),/,$(wordlist 2,$(words $(cygroot)),$(cygroot))) + endif endif .PHONY: clean html pdf upload diff --git a/platform/cooja/Makefile.cooja b/platform/cooja/Makefile.cooja index 61c958735..e79fdbf1b 100644 --- a/platform/cooja/Makefile.cooja +++ b/platform/cooja/Makefile.cooja @@ -11,14 +11,6 @@ ifndef CONTIKI $(error CONTIKI not defined!) 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 ifndef LIBNAME QUICKSTART=1 diff --git a/platform/esb/Makefile.esb b/platform/esb/Makefile.esb index 91759f980..8aaf31edd 100644 --- a/platform/esb/Makefile.esb +++ b/platform/esb/Makefile.esb @@ -68,23 +68,15 @@ send: $(CONTIKI)/tools/codeprop.c ### System dependent Makefile -ifndef WINDIR - ifdef OS - ifneq (,$(findstring Windows,$(OS))) - WINDIR := Windows - endif - endif -endif - -ifeq (${HOSTTYPE},FreeBSD) +ifeq ($(HOST_OS),FreeBSD) # settings for FreeBSD -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.freebsd else -ifndef WINDIR - # settings for unix - -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix -else - # settings for windows - -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win -endif + ifeq ($(HOST_OS),Windows) + # settings for Windows + -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win + else + # settings for an arbitary unix-like platform + -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix + endif endif diff --git a/platform/iris/Makefile.iris b/platform/iris/Makefile.iris index 8d58e24d5..d7ce508bb 100644 --- a/platform/iris/Makefile.iris +++ b/platform/iris/Makefile.iris @@ -31,23 +31,15 @@ include $(CONTIKIAVR)/Makefile.avr avr-objdump -zhD $< > $@ -ifndef WINDIR - ifdef OS - ifneq (,$(findstring Windows,$(OS))) - WINDIR := Windows - endif - endif -endif - ifeq ($(PRGBOARD), ) PRGBOARD = mib510 endif ifeq ($(PORT), ) - ifndef WINDIR - PORT = /dev/ttyUSB0 - else + ifeq ($(HOST_OS), Windows) PORT = COM1 + else + PORT = /dev/ttyUSB0 endif endif diff --git a/platform/mb851/Makefile.mb851 b/platform/mb851/Makefile.mb851 index f1b127fde..ba3ac91a2 100644 --- a/platform/mb851/Makefile.mb851 +++ b/platform/mb851/Makefile.mb851 @@ -19,10 +19,8 @@ include $(CONTIKI)/cpu/stm32w108/Makefile.stm32w108 SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux -ifdef OS - ifneq (,$(findstring Windows,$(OS))) - SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows - endif +ifeq ($(HOST_OS),Windows) + SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows endif diff --git a/platform/mbxxx/Makefile.mbxxx b/platform/mbxxx/Makefile.mbxxx index e100e2991..6925a231f 100644 --- a/platform/mbxxx/Makefile.mbxxx +++ b/platform/mbxxx/Makefile.mbxxx @@ -18,10 +18,8 @@ include $(CONTIKI)/cpu/stm32w108/Makefile.stm32w108 SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-linux -ifdef OS - ifneq (,$(findstring Windows,$(OS))) - SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows - endif +ifeq ($(HOST_OS),Windows) + SERIALDUMP = $(CONTIKI)/tools/stm32w/serialdump-windows endif diff --git a/platform/micaz/Makefile.micaz b/platform/micaz/Makefile.micaz index 021444e14..49499cf1a 100644 --- a/platform/micaz/Makefile.micaz +++ b/platform/micaz/Makefile.micaz @@ -26,23 +26,15 @@ include $(CONTIKIAVR)/Makefile.avr avr-objdump -zhD $< > $@ -ifndef WINDIR - ifdef OS - ifneq (,$(findstring Windows,$(OS))) - WINDIR := Windows - endif - endif -endif - ifeq ($(PRGBOARD), ) PRGBOARD = mib510 endif ifeq ($(PORT), ) - ifndef WINDIR - PORT = /dev/ttyS0 - else + ifeq ($(HOST_OS),Windows) PORT = COM1 + else + PORT = /dev/ttyS0 endif endif diff --git a/platform/minimal-net/Makefile.minimal-net b/platform/minimal-net/Makefile.minimal-net index 37e487cbc..dd35c8880 100644 --- a/platform/minimal-net/Makefile.minimal-net +++ b/platform/minimal-net/Makefile.minimal-net @@ -7,7 +7,7 @@ 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 -ifeq ($(OS),Windows_NT) +ifeq ($(HOST_OS),Windows) CONTIKI_TARGET_SOURCEFILES += wpcap-drv.c wpcap.c else CONTIKI_TARGET_SOURCEFILES += tapdev-drv.c @@ -21,7 +21,7 @@ endif CONTIKI_SOURCEFILES += $(CONTIKI_TARGET_SOURCEFILES) -ifeq ($(OS),Windows_NT) +ifeq ($(HOST_OS),Windows) TARGET_LIBFILES = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a endif diff --git a/platform/msb430/Makefile.msb430 b/platform/msb430/Makefile.msb430 index f74ce49bf..af5c95caa 100644 --- a/platform/msb430/Makefile.msb430 +++ b/platform/msb430/Makefile.msb430 @@ -24,25 +24,17 @@ endif ### System dependent Makefile -ifndef WINDIR - ifdef OS - ifneq (,$(findstring Windows,$(OS))) - WINDIR := Windows - endif - endif -endif - -ifeq (${HOSTTYPE},FreeBSD) +ifeq ($(HOST_OS),FreeBSD) # settings for FreeBSD -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.freebsd else -ifndef WINDIR - # settings for unix - -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix -else - # settings for windows - -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win -endif + ifeq ($(HOST_OS),Windows) + # settings for Windows + -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.win + else + # settings for an arbitary unix-like platform + -include $(CONTIKI)/platform/$(TARGET)/buildscripts/Makefile.unix + endif endif # If we are not running under Windows, we assume Linux diff --git a/platform/native/Makefile.native b/platform/native/Makefile.native index eade2e7a4..63ba12e9d 100644 --- a/platform/native/Makefile.native +++ b/platform/native/Makefile.native @@ -13,7 +13,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 \ 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 TARGET_LIBFILES = /lib/w32api/libws2_32.a /lib/w32api/libiphlpapi.a else diff --git a/platform/sky/Makefile.common b/platform/sky/Makefile.common index 066cad86b..e922d61c7 100644 --- a/platform/sky/Makefile.common +++ b/platform/sky/Makefile.common @@ -43,29 +43,27 @@ NUMPAR=20 IHEXFILE=tmpimage.ihex # Check if we are running under Windows -ifdef OS - ifneq (,$(findstring Windows,$(OS))) - USBDEVPREFIX=/dev/com - SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-windows - MOTELIST = $(CONTIKI)/tools/sky/motelist-windows - TMOTE_BSL_FILE = tmote-bsl - TMOTE_BSL=$(if $(wildcard $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE).exe),1,0) - ifeq ($(TMOTE_BSL), 1) - NUMPAR = 1 - BSL = $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE) - MOTES = $(shell $(MOTELIST) | grep COM | \ - cut -f 4 -d \ ) - else - BSL = $(CONTIKI)/tools/sky/msp430-bsl-windows --telosb - BSL_FILETYPE = -I - MOTES = $(shell $(MOTELIST) | grep COM | \ - cut -f 4 -d \ | \ - perl -ne 'print $$1 - 1 . " " if(/COM(\d+)/);') - endif - CMOTES = $(shell $(MOTELIST) | grep COM | \ + + USBDEVPREFIX=/dev/com + SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-windows + MOTELIST = $(CONTIKI)/tools/sky/motelist-windows + TMOTE_BSL_FILE = tmote-bsl + TMOTE_BSL=$(if $(wildcard $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE).exe),1,0) + ifeq ($(TMOTE_BSL), 1) + NUMPAR = 1 + BSL = $(CONTIKI)/tools/sky/$(TMOTE_BSL_FILE) + MOTES = $(shell $(MOTELIST) | grep COM | \ + cut -f 4 -d \ ) + else + BSL = $(CONTIKI)/tools/sky/msp430-bsl-windows --telosb + BSL_FILETYPE = -I + MOTES = $(shell $(MOTELIST) | grep COM | \ cut -f 4 -d \ | \ - perl -ne 'print $$1 . " " if(/COM(\d+)/);') + perl -ne 'print $$1 - 1 . " " if(/COM(\d+)/);') endif + CMOTES = $(shell $(MOTELIST) | grep COM | \ + cut -f 4 -d \ | \ + perl -ne 'print $$1 . " " if(/COM(\d+)/);') endif # If we are not running under Windows, we assume Linux diff --git a/platform/stepper-robot/Makefile.stepper-robot b/platform/stepper-robot/Makefile.stepper-robot index 6ad4065c8..b74e6180d 100644 --- a/platform/stepper-robot/Makefile.stepper-robot +++ b/platform/stepper-robot/Makefile.stepper-robot @@ -27,12 +27,3 @@ ifndef BASE_IP BASE_IP := 172.16.1.1 endif -### System dependent Makefile - -ifndef WINDIR - ifdef OS - ifneq (,$(findstring Windows,$(OS))) - WINDIR := Windows - endif - endif -endif diff --git a/platform/stm32test/Makefile.stm32test b/platform/stm32test/Makefile.stm32test index 8f003a200..4c7cf90c9 100644 --- a/platform/stm32test/Makefile.stm32test +++ b/platform/stm32test/Makefile.stm32test @@ -24,12 +24,3 @@ ifndef BASE_IP BASE_IP := 172.16.1.1 endif -### System dependent Makefile - -ifndef WINDIR - ifdef OS - ifneq (,$(findstring Windows,$(OS))) - WINDIR := Windows - endif - endif -endif From 4b608515278fd1adc9b8b4d12ecb2a016f23c872 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Fri, 24 Feb 2012 10:19:50 +0000 Subject: [PATCH 10/37] Missed `ifeq ...` --- platform/sky/Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/sky/Makefile.common b/platform/sky/Makefile.common index e922d61c7..d5f0c82d1 100644 --- a/platform/sky/Makefile.common +++ b/platform/sky/Makefile.common @@ -43,7 +43,7 @@ NUMPAR=20 IHEXFILE=tmpimage.ihex # Check if we are running under Windows - +ifeq ($(HOST_OS),Windows) USBDEVPREFIX=/dev/com SERIALDUMP = $(CONTIKI)/tools/sky/serialdump-windows MOTELIST = $(CONTIKI)/tools/sky/motelist-windows From ab9ddc62eab0221cd3d94405155ab8a96b85b9f4 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Fri, 24 Feb 2012 10:21:48 +0000 Subject: [PATCH 11/37] Added TODO note regarding flavours of Windows. --- Makefile.include | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.include b/Makefile.include index e00c804d2..d427d8c6b 100644 --- a/Makefile.include +++ b/Makefile.include @@ -23,7 +23,9 @@ endif ifndef HOST_OS ifeq ($(OS),Windows_NT) - $(warning Windows (NT) deteced.) + ## 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) From 16c437da7e6084f3063ffd7a297f007e7de7603d Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Mon, 27 Feb 2012 23:03:52 +0100 Subject: [PATCH 12/37] Adjust for the multi-instance structures. --- core/net/rpl/rpl-of0.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index 19ea4277c..ca239eb20 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -50,7 +50,7 @@ static void reset(rpl_dag_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_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 = { reset, @@ -83,7 +83,9 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_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) { PRINTF("RPL: OF0 rank %d incremented to infinite rank due to wrapping\n", @@ -135,10 +137,10 @@ best_parent(rpl_parent_t *p1, rpl_parent_t *p2) p2->link_metric, p2->rank); - r1 = DAG_RANK(p1->rank, (rpl_dag_t *)p1->dag) * NEIGHBOR_INFO_ETX_DIVISOR + - p1->link_metric; - r2 = DAG_RANK(p2->rank, (rpl_dag_t *)p1->dag) * NEIGHBOR_INFO_ETX_DIVISOR + - p2->link_metric; + r1 = DAG_RANK(p1->rank, p1->dag->instance) * NEIGHBOR_INFO_ETX_DIVISOR + + p1->link_metric; + r2 = DAG_RANK(p2->rank, p1->dag->instance) * NEIGHBOR_INFO_ETX_DIVISOR + + p2->link_metric; /* Compare two parents by looking both and their rank and at the ETX for that parent. We choose the parent that has the most favourable combination. */ From 2b7ecefce7790fa4d69473ed613705f2194a7832 Mon Sep 17 00:00:00 2001 From: David Kopf Date: Mon, 27 Feb 2012 17:05:22 -0500 Subject: [PATCH 13/37] Remove unused SPI initializer flag from AVR. Comment out in the msp-430 template. --- cpu/avr/spi.c | 6 ------ cpu/msp430/f1xxx/spi.c | 4 ++-- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/cpu/avr/spi.c b/cpu/avr/spi.c index 45fa011fa..c96f24032 100644 --- a/cpu/avr/spi.c +++ b/cpu/avr/spi.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)$Id: spi.c,v 1.1 2007/01/25 18:22:55 bg- Exp $ */ #include @@ -48,11 +47,6 @@ unsigned char spi_busy = 0; void spi_init(void) { - static unsigned char spi_inited = 0; - - if (spi_inited) - return; - /* Initalize ports for communication with SPI units. */ /* CSN=SS and must be output when master! */ DDRB |= BV(MOSI) | BV(SCK) | BV(CSN); diff --git a/cpu/msp430/f1xxx/spi.c b/cpu/msp430/f1xxx/spi.c index a88f69a57..0cf7c7715 100644 --- a/cpu/msp430/f1xxx/spi.c +++ b/cpu/msp430/f1xxx/spi.c @@ -26,7 +26,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * @(#)$Id: spi.c,v 1.1 2006/06/17 22:41:21 adamdunkels Exp $ */ #include "contiki-conf.h" @@ -46,11 +45,12 @@ unsigned char spi_busy = 0; void spi_init(void) { +/* static unsigned char spi_inited = 0; if (spi_inited) return; - +*/ /* Initalize ports for communication with SPI units. */ U0CTL = CHAR + SYNC + MM + SWRST; /* SW reset,8-bit transfer, SPI master */ From 6e41f6fbe9a23b15be2126f9c8747cd86e593363 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Mon, 30 Jan 2012 01:41:53 +0100 Subject: [PATCH 14/37] Erbium README update. --- examples/er-rest-example/README | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/er-rest-example/README b/examples/er-rest-example/README index df390ce83..39b364d6d 100644 --- a/examples/er-rest-example/README +++ b/examples/er-rest-example/README @@ -8,7 +8,7 @@ coap-client-example.c: A CoAP client that polls the /toggle resource every 10 se PRELIMINARIES ------------- -a) Make sure rpl-border-router has the same stack and fits into mote memory, e.g.: +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 @@ -17,7 +17,7 @@ b) For convenience, define the Cooja addresses in /etc/hosts aaaa::0212:7402:0002:0202 cooja2 ... c) Get the Copper CoAP browser from https://addons.mozilla.org/en-US/firefox/addon/copper-270430/ -d) Optional: Save Tmotes as default target +d) Optional: Save your target as default target $ make TARGET=sky savetarget COOJA HOWTO @@ -56,7 +56,7 @@ Add a client: DETAILS ------- -The Erbium CoAP currently implements draft 08. +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. In general, apps/er-coap-07 supports: * All draft 08 header options From b44d125d80f3ae09da939e96e4f36e320ff28a03 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Mon, 30 Jan 2012 22:01:31 +0100 Subject: [PATCH 15/37] Observe handler now checks if GET request. --- apps/er-coap-07/er-coap-07-observing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index f3dc7425d..4da0f5f67 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -191,7 +191,7 @@ coap_observe_handler(resource_t *resource, void *request, void *response) static char content[26]; - if (coap_res && coap_res->code<128) /* response without error code */ + if (coap_req->code==COAP_GET && coap_res && coap_res->code<128) /* GET request and response without error code */ { if (IS_OPTION(coap_req, COAP_OPTION_OBSERVE)) { From 4a02790c7681250e91441b3a1c50ae59010ddf23 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Tue, 31 Jan 2012 04:38:07 +0100 Subject: [PATCH 16/37] Simplified Erbium support for separate responses. --- apps/er-coap-03/er-coap-03-engine.c | 2 +- apps/er-coap-03/er-coap-03.h | 2 +- apps/er-coap-07/er-coap-07-engine.c | 98 ++++++++++--------- apps/er-coap-07/er-coap-07-separate.c | 69 ++++++++++--- apps/er-coap-07/er-coap-07-separate.h | 24 ++++- apps/er-coap-07/er-coap-07-transactions.c | 4 +- apps/er-coap-07/er-coap-07.h | 14 ++- apps/erbium/erbium.c | 2 +- apps/erbium/erbium.h | 2 +- .../er-rest-example/rest-server-example.c | 98 +++++++++++++++++-- 10 files changed, 238 insertions(+), 77 deletions(-) diff --git a/apps/er-coap-03/er-coap-03-engine.c b/apps/er-coap-03/er-coap-03-engine.c index 610209f13..048261349 100644 --- a/apps/er-coap-03/er-coap-03-engine.c +++ b/apps/er-coap-03/er-coap-03-engine.c @@ -206,7 +206,7 @@ handle_incoming_data(void) } } else { - error = MEMORY_ALLOC_ERR; + error = MEMORY_ALLOCATION_ERROR; } } else diff --git a/apps/er-coap-03/er-coap-03.h b/apps/er-coap-03/er-coap-03.h index 9b5f3a887..f6a2639ba 100644 --- a/apps/er-coap-03/er-coap-03.h +++ b/apps/er-coap-03/er-coap-03.h @@ -226,7 +226,7 @@ typedef enum NO_ERROR, /* Memory errors */ - MEMORY_ALLOC_ERR, + MEMORY_ALLOCATION_ERROR, MEMORY_BOUNDARY_EXCEEDED, /* CoAP errors */ diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index 1d27b6760..df86d5719 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -100,7 +100,7 @@ handle_incoming_data(void) 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(" 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. */ if ( (transaction = coap_new_transaction(message->mid, &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; + uint32_t block_num = 0; + uint16_t block_size = REST_MAX_CHUNK_SIZE; + uint32_t block_offset = 0; + int32_t new_offset = 0; /* prepare response */ if (message->type==COAP_TYPE_CON) @@ -143,11 +143,6 @@ handle_incoming_data(void) block_size = MIN(block_size, REST_MAX_CHUNK_SIZE); new_offset = block_offset; } - else - { - block_size = REST_MAX_CHUNK_SIZE; - new_offset = 0; - } /* Invoke resource handler. */ if (service_cbk) @@ -155,42 +150,55 @@ handle_incoming_data(void) /* 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) ) + if (coap_error_code==NO_ERROR) { - /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ - if (new_offset==block_offset) + /* Apply blockwise transfers. */ + if ( IS_OPTION(message, COAP_OPTION_BLOCK2) ) { - PRINTF("Blockwise: unaware resource with payload length %u/%u\n", response->payload_len, block_size); - if (block_offset >= response->payload_len) + /* unchanged new_offset indicates that resource is unaware of blockwise transfer */ + 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; - coap_set_payload(response, "BlockOutOfScope", 15); /* a const char str[] and sizeof(str) produces larger code size */ + response->code = BAD_OPTION_4_02; + 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 { - 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) */ + /* 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 + else if (new_offset!=0) { - /* 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); + 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) */ + 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) */ + } /* 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 { @@ -198,14 +206,8 @@ handle_incoming_data(void) 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_code = MEMORY_ALLOCATION_ERROR; coap_error_message = "Transaction buffer allocation failed"; } /* if (transaction buffer) */ } @@ -241,12 +243,20 @@ handle_incoming_data(void) } } /* if (ACKed transaction) */ transaction = NULL; - } + + } /* Request or Response */ + } /* if (parsed correctly) */ - if (coap_error_code==NO_ERROR) { + if (coap_error_code==NO_ERROR) + { if (transaction) coap_send_transaction(transaction); } + else if (coap_error_code==MANUAL_RESPONSE) + { + PRINTF("Clearing transaction for manual response"); + coap_clear_transaction(transaction); + } else { PRINTF("ERROR %u: %s\n", coap_error_code, coap_error_message); diff --git a/apps/er-coap-07/er-coap-07-separate.c b/apps/er-coap-07/er-coap-07-separate.c index 259398f26..b5f9c5c3a 100644 --- a/apps/er-coap-07/er-coap-07-separate.c +++ b/apps/er-coap-07/er-coap-07-separate.c @@ -40,6 +40,7 @@ #include #include "er-coap-07-separate.h" +#include "er-coap-07-transactions.h" #define DEBUG 0 #if DEBUG @@ -53,20 +54,66 @@ #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_res = (coap_packet_t *) response; - 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_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))); + PRINTF("Separate response for /%s MID %u\n", resource->url, coap_res->mid); - /* Change response to separate response. */ - coap_res->type = COAP_TYPE_CON; - coap_res->mid = coap_get_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. */ + 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; + } } diff --git a/apps/er-coap-07/er-coap-07-separate.h b/apps/er-coap-07/er-coap-07-separate.h index ace2388f5..8d677ea0d 100644 --- a/apps/er-coap-07/er-coap-07-separate.h +++ b/apps/er-coap-07/er-coap-07-separate.h @@ -41,6 +41,28 @@ #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_ */ diff --git a/apps/er-coap-07/er-coap-07-transactions.c b/apps/er-coap-07/er-coap-07-transactions.c index 4dfff6553..10070a29e 100644 --- a/apps/er-coap-07/er-coap-07-transactions.c +++ b/apps/er-coap-07/er-coap-07-transactions.c @@ -87,6 +87,8 @@ coap_new_transaction(uint16_t mid, uip_ipaddr_t *addr, uint16_t port) /* save client address */ uip_ipaddr_copy(&t->addr, addr); t->port = port; + + list_add(transactions_list, t); /* List itself makes sure same element is not added twice. */ } return t; @@ -122,8 +124,6 @@ coap_send_transaction(coap_transaction_t *t) 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 diff --git a/apps/er-coap-07/er-coap-07.h b/apps/er-coap-07/er-coap-07.h index 62f943898..2284f0a00 100644 --- a/apps/er-coap-07/er-coap-07.h +++ b/apps/er-coap-07/er-coap-07.h @@ -140,15 +140,13 @@ typedef enum { 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, + /* Erbium errors */ + MEMORY_ALLOCATION_ERROR = 192, + PACKET_SERIALIZATION_ERROR, + + /* Erbium hooks */ + MANUAL_RESPONSE - /* CoAP errors */ - UNIMPLEMENTED_CRITICAL_OPTION, - UNKNOWN_CRITICAL_OPTION, - PACKET_SERIALIZATION_ERROR } coap_status_t; /* CoAP header options */ diff --git a/apps/erbium/erbium.c b/apps/erbium/erbium.c index d2708616c..f624dd594 100644 --- a/apps/erbium/erbium.c +++ b/apps/erbium/erbium.c @@ -60,7 +60,7 @@ LIST(restful_periodic_services); void -rest_init_framework(void) +rest_init_engine(void) { list_init(restful_services); diff --git a/apps/erbium/erbium.h b/apps/erbium/erbium.h index f550deeed..1c29ab125 100644 --- a/apps/erbium/erbium.h +++ b/apps/erbium/erbium.h @@ -282,7 +282,7 @@ periodic_resource_t periodic_resource_##name = {NULL, &resource_##name, period, /* * 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. diff --git a/examples/er-rest-example/rest-server-example.c b/examples/er-rest-example/rest-server-example.c index 0195295b3..88dab13a0 100644 --- a/examples/er-rest-example/rest-server-example.c +++ b/examples/er-rest-example/rest-server-example.c @@ -47,11 +47,12 @@ #define REST_RES_HELLO 1 #define REST_RES_MIRROR 0 /* causes largest code size */ #define REST_RES_CHUNKS 1 -#define REST_RES_POLLING 1 +#define REST_RES_POLLING 0 +#define REST_RES_SEPARATE 1 #define REST_RES_EVENT 1 #define REST_RES_LEDS 1 #define REST_RES_TOGGLE 1 -#define REST_RES_LIGHT 1 +#define REST_RES_LIGHT 0 #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. */ uint8_t opaque[] = {0x0A, 0xBC, 0xDE}; - /* Strings are not copied and should be static or in program memory (char *str = "string in .text";). - * They must be '\0'-terminated as the setters use strlen(). */ + /* Strings are not copied, so use static string buffers or strings in .text memory (char *str = "string in .text";). */ static char location[] = {'/','f','/','a','?','k','&','e', 0}; /* Getter for the header option Content-Type. If the option is not set, text/plain is returned by default. */ @@ -390,6 +390,79 @@ polling_periodic_handler(resource_t *r) } #endif +#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, (uint8_t *)msg, sizeof(msg)-1); + } + 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 defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT /* * Example for an event resource. @@ -594,8 +667,8 @@ PROCESS_THREAD(rest_server_example, ev, data) configure_routing(); #endif - /* Initialize the REST framework. */ - rest_init_framework(); + /* Initialize the REST engine. */ + rest_init_engine(); /* Activate the application-specific resources. */ #if REST_RES_HELLO @@ -610,6 +683,11 @@ PROCESS_THREAD(rest_server_example, ev, data) #if REST_RES_POLLING rest_activate_periodic_resource(&periodic_resource_polling); #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 SENSORS_ACTIVATE(button_sensor); rest_activate_event_resource(&resource_event); @@ -634,11 +712,17 @@ PROCESS_THREAD(rest_server_example, ev, data) /* Define application-specific events here. */ while(1) { PROCESS_WAIT_EVENT(); -#if defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT +#if defined (PLATFORM_HAS_BUTTON) if (ev == sensors_event && data == &button_sensor) { PRINTF("BUTTON\n"); +#if REST_RES_EVENT /* Call the event_handler for this application-specific 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 */ } /* while (1) */ From dc6142fa0b6d5f00c9f2e2b3163d3f33ab88fde6 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Wed, 1 Feb 2012 03:24:49 +0100 Subject: [PATCH 17/37] Revised Erbium observing. --- apps/er-coap-03/er-coap-03-observing.c | 4 +- apps/er-coap-03/er-coap-03-observing.h | 2 +- apps/er-coap-03/er-coap-03.c | 6 +- apps/er-coap-03/er-coap-03.h | 4 +- apps/er-coap-07/er-coap-07-engine.c | 4 +- apps/er-coap-07/er-coap-07-observing.c | 20 ++-- apps/er-coap-07/er-coap-07-observing.h | 6 +- .../er-rest-example/rest-server-example.c | 109 +++++++++--------- 8 files changed, 79 insertions(+), 76 deletions(-) diff --git a/apps/er-coap-03/er-coap-03-observing.c b/apps/er-coap-03/er-coap-03-observing.c index 2da95248c..dc8fbc048 100644 --- a/apps/er-coap-03/er-coap-03-observing.c +++ b/apps/er-coap-03/er-coap-03-observing.c @@ -58,7 +58,7 @@ 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_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); @@ -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 (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_payload(response, (uint8_t *)content, snprintf(content, sizeof(content), "Added as observer %u/%u", list_length(observers_list), COAP_MAX_OBSERVERS)); diff --git a/apps/er-coap-03/er-coap-03-observing.h b/apps/er-coap-03/er-coap-03-observing.h index 90cbdf0b0..287c11e9f 100644 --- a/apps/er-coap-03/er-coap-03-observing.h +++ b/apps/er-coap-03/er-coap-03-observing.h @@ -65,7 +65,7 @@ typedef struct coap_observer { } 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); +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); 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); diff --git a/apps/er-coap-03/er-coap-03.c b/apps/er-coap-03/er-coap-03.c index 9a9189261..4f7a5b81c 100644 --- a/apps/er-coap-03/er-coap-03.c +++ b/apps/er-coap-03/er-coap-03.c @@ -745,7 +745,7 @@ coap_set_header_uri_query(void *packet, const char *query) /*- PAYLOAD -------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/ int -coap_get_payload(void *packet, const uint8_t **payload) +coap_get_payload(void *packet, uint8_t **payload) { if (((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 -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); - ((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); return ((coap_packet_t *)packet)->payload_len; diff --git a/apps/er-coap-03/er-coap-03.h b/apps/er-coap-03/er-coap-03.h index f6a2639ba..ebd2f164f 100644 --- a/apps/er-coap-03/er-coap-03.h +++ b/apps/er-coap-03/er-coap-03.h @@ -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_set_header_uri_query(void *packet, const char *query); -int coap_get_payload(void *packet, const uint8_t **payload); -int coap_set_payload(void *packet, uint8_t *payload, size_t length); +int coap_get_payload(void *packet, uint8_t **payload); +int coap_set_payload(void *packet, const void *payload, size_t length); #endif /* COAP_03_H_ */ diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index df86d5719..f0545d61e 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -225,8 +225,8 @@ handle_incoming_data(void) /* 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); + /* RST must be empty, so it is a full client reset. */ + coap_remove_observer_by_client(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport); } } diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index 4da0f5f67..5324a3a00 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -58,7 +58,7 @@ 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_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); @@ -125,7 +125,7 @@ coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, return removed; } 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; coap_observer_t* obs = NULL; @@ -133,7 +133,7 @@ coap_remove_observer_by_url(const char *url) for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) { 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++; @@ -189,17 +189,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_res = (coap_packet_t *) response; - static char content[26]; + static char content[16]; - if (coap_req->code==COAP_GET && coap_res && coap_res->code<128) /* GET request and 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 (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_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 { @@ -210,7 +214,7 @@ coap_observe_handler(resource_t *resource, void *request, void *response) else /* if (observe) */ { /* 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) */ } } diff --git a/apps/er-coap-07/er-coap-07-observing.h b/apps/er-coap-07/er-coap-07-observing.h index 078e9b430..d30acbebc 100644 --- a/apps/er-coap-07/er-coap-07-observing.h +++ b/apps/er-coap-07/er-coap-07-observing.h @@ -66,12 +66,12 @@ typedef struct coap_observer { 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); +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); 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_url(const char *url); +int coap_remove_observer_by_url(uip_ipaddr_t *addr, uint16_t port, const char *url); void coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len); diff --git a/examples/er-rest-example/rest-server-example.c b/examples/er-rest-example/rest-server-example.c index 88dab13a0..65ccdc48e 100644 --- a/examples/er-rest-example/rest-server-example.c +++ b/examples/er-rest-example/rest-server-example.c @@ -47,8 +47,8 @@ #define REST_RES_HELLO 1 #define REST_RES_MIRROR 0 /* causes largest code size */ #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_LEDS 1 #define REST_RES_TOGGLE 1 @@ -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); /* A block error message should not exceed the minimum block size (16). */ - const char error_msg[] = "BlockOutOfScope"; - REST.set_response_payload(response, (uint8_t *)error_msg, sizeof(error_msg)-1); + const char *error_msg = "BlockOutOfScope"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); return; } @@ -349,47 +349,6 @@ chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferre } #endif -#if REST_RES_POLLING -/* - * Example for a periodic resource. - * It takes an additional period parameter, which defines the interval to call [name]_periodic_handler(). - * A default post_handler takes care of subscriptions by managing a list of subscribers to notify. - */ -PERIODIC_RESOURCE(polling, METHOD_GET, "debug/poll", "title=\"Periodic demo\";rt=\"Observable\"", 5*CLOCK_SECOND); - -void -polling_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) -{ - REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - - /* Usually, a CoAP server would response with the current resource representation. */ - const char msg[] = "It's periodic!"; - REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); - - /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ -} - -/* - * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. - * It will be called by the REST manager process with the defined period. - */ -int -polling_periodic_handler(resource_t *r) -{ - static uint32_t periodic_i = 0; - static char content[16]; - - PRINTF("TICK /%s\n", r->url); - periodic_i = periodic_i + 1; - - /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(r->url, 1, periodic_i, (uint8_t *)content, snprintf(content, sizeof(content), "TICK %lu", periodic_i)); - /* |-> implementation-specific, e.g. CoAP: 1=CON and 0=NON notification */ - - return 1; -} -#endif - #if REST_RES_SEPARATE && WITH_COAP > 3 /* Required to manually (=not by the engine) handle the response transaction. */ #include "er-coap-07-separate.h" @@ -413,8 +372,8 @@ separate_handler(void* request, void* response, uint8_t *buffer, uint16_t prefer if (separate_active) { REST.set_response_status(response, REST.status.SERVICE_UNAVAILABLE); - const char msg[] = "AlreadyInUse"; - REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); + const char *msg = "AlreadyInUse"; + REST.set_response_payload(response, msg, strlen(msg)); } else { @@ -463,6 +422,47 @@ separate_finalize_handler() } #endif +#if REST_RES_PUSHING +/* + * Example for a periodic resource. + * It takes an additional period parameter, which defines the interval to call [name]_periodic_handler(). + * A default post_handler takes care of subscriptions by managing a list of subscribers to notify. + */ +PERIODIC_RESOURCE(pushing, METHOD_GET, "debug/push", "title=\"Periodic demo\";rt=\"Observable\"", 5*CLOCK_SECOND); + +void +pushing_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + + /* Usually, a CoAP server would response with the resource representation matching the periodic_handler. */ + const char *msg = "It's periodic!"; + REST.set_response_payload(response, msg, strlen(msg)); + + /* A post_handler that handles subscriptions will be called for periodic resources by the REST framework. */ +} + +/* + * Additionally, a handler function named [resource name]_handler must be implemented for each PERIODIC_RESOURCE. + * It will be called by the REST manager process with the defined period. + */ +int +pushing_periodic_handler(resource_t *r) +{ + static uint32_t periodic_i = 0; + static char content[16]; + + PRINTF("TICK /%s\n", r->url); + periodic_i = periodic_i + 1; + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(r->url, 1, periodic_i, (uint8_t *)content, snprintf(content, sizeof(content), "TICK %lu", periodic_i)); + /* |-> implementation-specific, e.g. CoAP: 1=CON and 0=NON notification */ + + return 1; +} +#endif + #if defined (PLATFORM_HAS_BUTTON) && REST_RES_EVENT /* * Example for an event resource. @@ -475,10 +475,9 @@ void event_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { REST.set_header_content_type(response, REST.type.TEXT_PLAIN); - /* Usually, a CoAP server would response with the current resource representation. */ - const char msg[] = "It's eventful!"; - REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); + 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. */ } @@ -600,8 +599,8 @@ light_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred else { REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE); - const char msg[] = "Supporting content-types text/plain, application/xml, and application/json"; - REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); + 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 */ @@ -634,8 +633,8 @@ battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr else { REST.set_response_status(response, REST.status.UNSUPPORTED_MADIA_TYPE); - const char msg[] = "Supporting content-types text/plain and application/json"; - REST.set_response_payload(response, (uint8_t *)msg, sizeof(msg)-1); + const char *msg = "Supporting content-types text/plain and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); } } #endif /* PLATFORM_HAS_BATTERY */ @@ -680,8 +679,8 @@ PROCESS_THREAD(rest_server_example, ev, data) #if REST_RES_CHUNKS rest_activate_resource(&resource_chunks); #endif -#if REST_RES_POLLING - rest_activate_periodic_resource(&periodic_resource_polling); +#if REST_RES_PUSHING + rest_activate_periodic_resource(&periodic_resource_pushing); #endif #if REST_RES_SEPARATE && WITH_COAP > 3 rest_set_pre_handler(&resource_separate, coap_separate_handler); From d0e2d9b47e7e3370a6a9d8338052041af2b7390f Mon Sep 17 00:00:00 2001 From: Nicolas Tsiftes Date: Wed, 29 Feb 2012 21:59:50 +0100 Subject: [PATCH 18/37] Cleaned up code style, comments, and print outs. Set default DAG parameters when the DIO configuration option is missing. --- core/net/rpl/rpl-dag.c | 71 +++++++++++++++----------------------- core/net/rpl/rpl-icmp6.c | 47 +++++++++++++++---------- core/net/rpl/rpl-of-etx.c | 2 +- core/net/rpl/rpl-of0.c | 2 +- core/net/rpl/rpl-private.h | 39 ++++++++++++++------- core/net/rpl/rpl-timers.c | 4 +-- core/net/rpl/rpl.h | 44 ++++++++--------------- 7 files changed, 102 insertions(+), 107 deletions(-) diff --git a/core/net/rpl/rpl-dag.c b/core/net/rpl/rpl-dag.c index f8587dbf8..7240ae7cb 100644 --- a/core/net/rpl/rpl-dag.c +++ b/core/net/rpl/rpl-dag.c @@ -62,11 +62,11 @@ extern rpl_of_t RPL_OF; static rpl_of_t * const objective_functions[] = {&RPL_OF}; /************************************************************************/ -#ifndef RPL_CONF_MAX_PARENTS_PER_DODAG -#define RPL_MAX_PARENTS_PER_DODAG 8 +#ifndef RPL_CONF_MAX_PARENTS_PER_DAG +#define RPL_MAX_PARENTS_PER_DAG 8 #else -#define RPL_MAX_PARENTS_PER_DODAG RPL_CONF_MAX_PARENTS_PER_DODAG -#endif /* !RPL_CONF_MAX_PARENTS */ +#define RPL_MAX_PARENTS_PER_DAG RPL_CONF_MAX_PARENTS_PER_DAG +#endif /* !RPL_CONF_MAX_PARENTS_PER_DAG */ /************************************************************************/ /* RPL definitions. */ @@ -77,30 +77,16 @@ static rpl_of_t * const objective_functions[] = {&RPL_OF}; #define RPL_GROUNDED 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. */ 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. */ rpl_instance_t instance_table[RPL_MAX_INSTANCES]; 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) { /* 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- RPL_LOLLIPOP_SEQUENCE_WINDOWS)); } - /************************************************************************/ /* Remove DAG parents with a rank that is at least the same as minimum_rank. */ 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)); - instance->dio_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS; - instance->dio_intmin = DEFAULT_DIO_INTERVAL_MIN; + instance->dio_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS; + instance->dio_intmin = RPL_DIO_INTERVAL_MIN; /* The current interval must differ from the minimum interval in order to trigger a DIO timer reset. */ - instance->dio_intcurrent = DEFAULT_DIO_INTERVAL_MIN + - DEFAULT_DIO_INTERVAL_DOUBLINGS; - instance->dio_redundancy = DEFAULT_DIO_REDUNDANCY; - instance->max_rankinc = DEFAULT_MAX_RANKINC; - instance->min_hoprankinc = DEFAULT_MIN_HOPRANKINC; + instance->dio_intcurrent = RPL_DIO_INTERVAL_MIN + + RPL_DIO_INTERVAL_DOUBLINGS; + instance->dio_redundancy = RPL_DIO_REDUNDANCY; + instance->max_rankinc = RPL_MAX_RANKINC; + instance->min_hoprankinc = RPL_MIN_HOPRANKINC; instance->default_lifetime = RPL_DEFAULT_LIFETIME; 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; } - 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) { memset(dag, 0, sizeof(*dag)); 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); - /* Remove any DODAG inside this instance */ - for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DODAG_PER_INSTANCE; dag < end; ++dag) { + /* Remove any DAG inside this instance */ + for(dag = &instance->dag_table[0], end = dag + RPL_MAX_DAG_PER_INSTANCE; dag < end; ++dag) { if(dag->used) { rpl_free_dodag(dag); } @@ -519,7 +504,7 @@ find_parent_dag(rpl_instance_t *instance, uip_ipaddr_t *addr) rpl_parent_t *p; 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) { for(p = list_head(dag->parents); p != NULL; p = p->next) { 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_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) { for(p = list_head(dag->parents); p != NULL; p = p->next) { 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) { 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(best_dag == NULL) { best_dag = dag; @@ -588,7 +573,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p) /* Remove routes installed by DAOs. */ rpl_remove_routes(instance->current_dag); - PRINTF("RPL: New preferred DODAG: "); + PRINTF("RPL: New preferred DAG: "); PRINT6ADDR(&best_dag->dag_id); PRINTF("\n"); @@ -613,7 +598,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p) instance->current_dag->preferred_parent = NULL; if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES && last_parent != NULL) { /* 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; } @@ -626,7 +611,7 @@ rpl_select_dodag(rpl_instance_t *instance, rpl_parent_t *p) if(instance->mop != RPL_MOP_NO_DOWNWARD_ROUTES) { if(last_parent != NULL) { /* 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. */ 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; } - 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; } - 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]; if(dag->used && uip_ipaddr_cmp(&dag->dag_id, dag_id)) { return dag; @@ -1003,7 +988,7 @@ rpl_local_repair(rpl_instance_t *instance) int i; 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) { instance->dag_table[i].rank = INFINITE_RANK; 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) { 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) { for(p = list_head(instance->dag_table[i].parents); p != NULL; p = p->next) { if(p->updated) { @@ -1190,7 +1175,7 @@ rpl_process_dio(uip_ipaddr_t *from, rpl_dio_t *dio) if(p == NULL) { previous_dag = find_parent_dag(instance, from); 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. */ remove_worst_parent(dag, dio->rank); } @@ -1220,7 +1205,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); PRINTF(", rank %u, min_rank %u, ", instance->current_dag->rank, instance->current_dag->min_rank); diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index efc9ee7fa..424e7ed19 100755 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -92,6 +92,8 @@ void RPL_DEBUG_DIO_INPUT(uip_ipaddr_t *, rpl_dio_t *); void RPL_DEBUG_DAO_OUTPUT(rpl_parent_t *); #endif +extern rpl_of_t RPL_OF; + /*---------------------------------------------------------------------------*/ static int get_global_addr(uip_ipaddr_t *addr) @@ -209,9 +211,15 @@ dio_input(void) memset(&dio, 0, sizeof(dio)); - dio.dag_intdoubl = DEFAULT_DIO_INTERVAL_DOUBLINGS; - dio.dag_intmin = DEFAULT_DIO_INTERVAL_MIN; - dio.dag_redund = DEFAULT_DIO_REDUNDANCY; + /* Set default values in case the DIO configuration option is missing. */ + dio.dag_intdoubl = RPL_DIO_INTERVAL_DOUBLINGS; + 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); @@ -251,8 +259,10 @@ dio_input(void) dio.rank = get16(buffer, i); i += 2; - PRINTF("RPL: Incoming DIO InstanceID-Version %u-%u\n", (unsigned)dio.instance_id,(unsigned)dio.version); - PRINTF("RPL: Incoming DIO rank %u\n", (unsigned)dio.rank); + PRINTF("RPL: Incoming DIO (id, ver, rank) = (%u,%u,%u)\n", + (unsigned)dio.instance_id, + (unsigned)dio.version, + (unsigned)dio.rank); dio.grounded = buffer[i] & RPL_DIO_GROUNDED; 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)); i += sizeof(dio.dag_id); - PRINTF("RPL: Incoming DIO DODAG "); + PRINTF("RPL: Incoming DIO (dag_id, pref) = ("); PRINT6ADDR(&dio.dag_id); - PRINTF(", preference: %u\n", dio.preference); + PRINTF(", %u)\n", dio.preference); /* Check if there are any DIO suboptions. */ for(; i < buffer_length; i += len) { @@ -326,7 +336,7 @@ dio_input(void) 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.flags = buffer[i + 3]; dio.destination_prefix.lifetime = get32(buffer, i + 4); @@ -337,7 +347,7 @@ dio_input(void) memcpy(&dio.destination_prefix.prefix, &buffer[i + 8], (dio.destination_prefix.length + 7) / 8); } 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++); return; } @@ -360,14 +370,14 @@ dio_input(void) /* buffer + 12 is reserved */ dio.default_lifetime = buffer[i + 13]; 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_max_rankinc, dio.dag_min_hoprankinc, dio.ocp, dio.default_lifetime, dio.lifetime_unit); break; case RPL_OPTION_PREFIX_INFO: 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++); return; } @@ -398,6 +408,7 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) { unsigned char *buffer; int pos; + rpl_dag_t *dag = instance->current_dag; #if !RPL_LEAF_ONLY uip_ipaddr_t addr; #endif /* !RPL_LEAF_ONLY */ @@ -409,8 +420,6 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) } #endif /* RPL_LEAF_ONLY */ - rpl_dag_t *dag = instance->current_dag; - /* DAG Information Object */ pos = 0; @@ -597,7 +606,7 @@ dao_input(void) /* Is the DAGID present? */ if(flags & RPL_DAO_D_FLAG) { 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; } pos += 16; @@ -640,7 +649,7 @@ dao_input(void) rep = uip_ds6_route_lookup(&prefix); - if(lifetime == ZERO_LIFETIME) { + if(lifetime == RPL_ZERO_LIFETIME) { /* No-Path DAO received; invoke the route purging routine. */ if(rep != NULL && rep->state.saved_lifetime == 0 && rep->length == prefixlen) { PRINTF("RPL: Setting expiration timer for prefix "); @@ -733,19 +742,19 @@ dao_output(rpl_parent_t *n, uint8_t lifetime) buffer[pos++] = instance->instance_id; buffer[pos] = 0; -#if RPL_DAO_SPECIFY_DODAG +#if RPL_DAO_SPECIFY_DAG buffer[pos] |= RPL_DAO_D_FLAG; -#endif /* RPL_DAO_SPECIFY_DODAG */ +#endif /* RPL_DAO_SPECIFY_DAG */ #if RPL_CONF_DAO_ACK buffer[pos] |= RPL_DAO_K_FLAG; #endif /* RPL_CONF_DAO_ACK */ ++pos; buffer[pos++] = 0; /* reserved */ buffer[pos++] = dao_sequence; -#if RPL_DAO_SPECIFY_DODAG +#if RPL_DAO_SPECIFY_DAG memcpy(buffer + pos, &dag->dag_id, sizeof(dag->dag_id)); pos+=sizeof(dag->dag_id); -#endif /* RPL_DAO_SPECIFY_DODAG */ +#endif /* RPL_DAO_SPECIFY_DAG */ /* create target subopt */ prefixlen = sizeof(prefix) * CHAR_BIT; diff --git a/core/net/rpl/rpl-of-etx.c b/core/net/rpl/rpl-of-etx.c index 05a521c83..a7c0e4429 100644 --- a/core/net/rpl/rpl-of-etx.c +++ b/core/net/rpl/rpl-of-etx.c @@ -112,7 +112,7 @@ calculate_rank(rpl_parent_t *p, rpl_rank_t base_rank) if(base_rank == 0) { 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 { /* multiply first, then scale down to avoid truncation effects */ rank_increase = NEIGHBOR_INFO_FIX2ETX(p->link_metric * p->dag->instance->min_hoprankinc); diff --git a/core/net/rpl/rpl-of0.c b/core/net/rpl/rpl-of0.c index ca239eb20..49f3c99d0 100644 --- a/core/net/rpl/rpl-of0.c +++ b/core/net/rpl/rpl-of0.c @@ -62,7 +62,7 @@ rpl_of_t rpl_of0 = { 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) diff --git a/core/net/rpl/rpl-private.h b/core/net/rpl/rpl-private.h index 94eaec0d8..f48d31afd 100644 --- a/core/net/rpl/rpl-private.h +++ b/core/net/rpl/rpl-private.h @@ -110,10 +110,10 @@ /* Default values for RPL constants and variables. */ /* 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. */ -#define ZERO_LIFETIME 0 +#define RPL_ZERO_LIFETIME 0 /* Default route lifetime unit. */ #define RPL_DEFAULT_LIFETIME_UNIT 0xffff @@ -125,13 +125,14 @@ ((unsigned long)(instance)->lifetime_unit * (lifetime)) #ifndef RPL_CONF_MIN_HOPRANKINC -#define DEFAULT_MIN_HOPRANKINC 256 +#define RPL_MIN_HOPRANKINC 256 #else -#define DEFAULT_MIN_HOPRANKINC RPL_CONF_MIN_HOPRANKINC +#define RPL_MIN_HOPRANKINC RPL_CONF_MIN_HOPRANKINC #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. */ #define BASE_RANK 0 @@ -148,23 +149,23 @@ means 8 milliseconds, but that is an unreasonable value if using power-saving / duty-cycling */ #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 -#define DEFAULT_DIO_INTERVAL_MIN 12 +#define RPL_DIO_INTERVAL_MIN 12 #endif /* Maximum amount of timer 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 -#define DEFAULT_DIO_INTERVAL_DOUBLINGS 8 +#define RPL_DIO_INTERVAL_DOUBLINGS 8 #endif /* Default DIO redundancy. */ #ifdef RPL_CONF_DIO_REDUNDANCY -#define DEFAULT_DIO_REDUNDANCY RPL_CONF_DIO_REDUNDANCY +#define RPL_DIO_REDUNDANCY RPL_CONF_DIO_REDUNDANCY #else -#define DEFAULT_DIO_REDUNDANCY 10 +#define RPL_DIO_REDUNDANCY 10 #endif /* Expire DAOs from neighbors that do not respond in this time. (seconds) */ @@ -207,6 +208,20 @@ #endif #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.) */ struct rpl_dio { uip_ipaddr_t dag_id; diff --git a/core/net/rpl/rpl-timers.c b/core/net/rpl/rpl-timers.c index 01cbe9138..0527d5363 100644 --- a/core/net/rpl/rpl-timers.c +++ b/core/net/rpl/rpl-timers.c @@ -225,8 +225,8 @@ rpl_schedule_dao(rpl_instance_t *instance) if(!etimer_expired(&instance->dao_timer.etimer)) { PRINTF("RPL: DAO timer already scheduled\n"); } else { - expiration_time = DEFAULT_DAO_LATENCY / 2 + - (random_rand() % (DEFAULT_DAO_LATENCY)); + expiration_time = RPL_DAO_LATENCY / 2 + + (random_rand() % (RPL_DAO_LATENCY)); PRINTF("RPL: Scheduling DAO timer %u ticks in the future\n", (unsigned)expiration_time); ctimer_set(&instance->dao_timer, expiration_time, diff --git a/core/net/rpl/rpl.h b/core/net/rpl/rpl.h index e039cf98d..90bf43626 100644 --- a/core/net/rpl/rpl.h +++ b/core/net/rpl/rpl.h @@ -97,24 +97,24 @@ /* * Maximum of concurent dodag inside an instance */ -#ifndef RPL_CONF_MAX_DODAG_PER_INSTANCE -#define RPL_MAX_DODAG_PER_INSTANCE 2 +#ifndef RPL_CONF_MAX_DAG_PER_INSTANCE +#define RPL_MAX_DAG_PER_INSTANCE 2 #else -#define RPL_MAX_DODAG_PER_INSTANCE RPL_CONF_MAX_DODAG_PER_INSTANCE -#endif /* !RPL_CONF_MAX_DODAG_PER_INSTANCE */ +#define RPL_MAX_DAG_PER_INSTANCE RPL_CONF_MAX_DAG_PER_INSTANCE +#endif /* !RPL_CONF_MAX_DAG_PER_INSTANCE */ /* * */ -#ifndef RPL_CONF_DAO_SPECIFY_DODAG -#if RPL_MAX_DODAG_PER_INSTANCE > 1 -#define RPL_DAO_SPECIFY_DODAG 1 -#else /* RPL_MAX_DODAG_PER_INSTANCE > 1*/ -#define RPL_DAO_SPECIFY_DODAG 0 -#endif /* RPL_MAX_DODAG_PER_INSTANCE > 1 */ -#else /* RPL_CONF_DAO_SPECIFY_DODAG */ -#define RPL_DAO_SPECIFY_DODAG RPL_CONF_DAO_SPECIFY_DODAG -#endif /* RPL_CONF_DAO_SPECIFY_DODAG */ +#ifndef RPL_CONF_DAO_SPECIFY_DAG +#if RPL_MAX_DAG_PER_INSTANCE > 1 +#define RPL_DAO_SPECIFY_DAG 1 +#else /* RPL_MAX_DAG_PER_INSTANCE > 1*/ +#define RPL_DAO_SPECIFY_DAG 0 +#endif /* RPL_MAX_DAG_PER_INSTANCE > 1 */ +#else /* RPL_CONF_DAO_SPECIFY_DAG */ +#define RPL_DAO_SPECIFY_DAG RPL_CONF_DAO_SPECIFY_DAG +#endif /* RPL_CONF_DAO_SPECIFY_DAG */ /*---------------------------------------------------------------------------*/ @@ -123,20 +123,6 @@ /*---------------------------------------------------------------------------*/ typedef uint16_t rpl_rank_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. */ #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 */ struct rpl_dag { 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 grounded; uint8_t preference; @@ -286,7 +272,7 @@ struct rpl_instance { rpl_metric_container_t mc; rpl_of_t *of; 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" */ uip_ds6_defrt_t *def_route; uint8_t instance_id; From 729a434d0f2889486765ff4b14c44189bff1a224 Mon Sep 17 00:00:00 2001 From: Joakim Eriksson Date: Wed, 29 Feb 2012 15:01:59 -0800 Subject: [PATCH 19/37] always send DAO to refresh routes --- core/net/rpl/rpl-icmp6.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/net/rpl/rpl-icmp6.c b/core/net/rpl/rpl-icmp6.c index 424e7ed19..114b673e4 100755 --- a/core/net/rpl/rpl-icmp6.c +++ b/core/net/rpl/rpl-icmp6.c @@ -445,9 +445,8 @@ dio_output(rpl_instance_t *instance, uip_ipaddr_t *uc_addr) buffer[pos++] = instance->dtsn_out; - if(RPL_LOLLIPOP_IS_INIT(instance->dtsn_out)) { - RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); - } + /* always request new DAO to refresh route */ + RPL_LOLLIPOP_INCREMENT(instance->dtsn_out); /* reserved 2 bytes */ buffer[pos++] = 0; /* flags */ From 383d277277d935039974d48bf540d8faafed0b9d Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 1 Mar 2012 15:21:06 +0100 Subject: [PATCH 20/37] improved source info, added optional stack trace tooltip --- .../se/sics/cooja/plugins/BufferListener.java | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java b/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java index f7751aa22..58fd675bf 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java +++ b/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java @@ -198,6 +198,9 @@ public class BufferListener extends VisPlugin { private boolean hideReads = true; private JCheckBoxMenuItem hideReadsCheckbox; + private boolean withStackTrace = false; + private JCheckBoxMenuItem withStackTraceCheckbox; + private JMenu parserMenu = new JMenu("Parser"); private JMenu bufferMenu = new JMenu("Buffer"); @@ -336,7 +339,18 @@ public class BufferListener extends VisPlugin { if (rowIndex < 0 || columnIndex < 0) { return super.getToolTipText(e); } + Object v = getValueAt(rowIndex, columnIndex); + if (columnIndex == COLUMN_SOURCE) { + BufferAccess ba = logs.get(rowIndex); + if (ba.stackTrace != null) { + return + "
" +
+            ba.stackTrace +
+            "
"; + } + return "No stack trace (enable in popup menu)"; + } if (v instanceof BufferAccess && parser instanceof GraphicalParser) { return "" + @@ -493,6 +507,7 @@ public class BufferListener extends VisPlugin { /* Automatically update column widths */ final TableColumnAdjuster adjuster = new TableColumnAdjuster(logTable, 0); adjuster.packColumns(); + logTable.getColumnModel().getColumn(COLUMN_DATA).setWidth(400); /* Popup menu */ JPopupMenu popupMenu = new JPopupMenu(); @@ -555,7 +570,7 @@ public class BufferListener extends VisPlugin { repaint(); } }); - hideReadsCheckbox = new JCheckBoxMenuItem("Hide READs", true); + hideReadsCheckbox = new JCheckBoxMenuItem("Hide READs", hideReads); popupMenu.add(hideReadsCheckbox); hideReadsCheckbox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -565,7 +580,16 @@ 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); /* Column width adjustment */ @@ -573,6 +597,7 @@ public class BufferListener extends VisPlugin { public void run() { /* Make sure this happens *after* adding history */ adjuster.setDynamicAdjustment(true); + adjuster.setAdjustColumn(COLUMN_DATA, false); } }); @@ -775,6 +800,10 @@ public class BufferListener extends VisPlugin { element = new Element("showreads"); config.add(element); } + if (withStackTrace) { + element = new Element("stacktrace"); + config.add(element); + } element = new Element("parser"); element.setText(parser.getClass().getName()); config.add(element); @@ -815,6 +844,9 @@ public class BufferListener extends VisPlugin { } else if ("showreads".equals(name)) { hideReads = false; hideReadsCheckbox.setSelected(false); + } else if ("stacktrace".equals(name)) { + withStackTrace = true; + withStackTraceCheckbox.setSelected(true); } else if ("formatted_time".equals(name)) { formatTimeString = true; repaintTimeColumn(); @@ -928,6 +960,7 @@ public class BufferListener extends VisPlugin { public final String typeStr; public final String sourceStr; + public final String stackTrace; public final byte[] mem; private boolean[] accessedBitpattern = null; @@ -970,6 +1003,11 @@ public class BufferListener extends VisPlugin { typeStr = type.toString(); String s = mote.getPCString(); sourceStr = s==null?"[unknown]":s; + if (withStackTrace) { + this.stackTrace = mote.getStackTrace(); + } else { + this.stackTrace = null; + } } public Object getParsedData() { @@ -1285,8 +1323,7 @@ public class BufferListener extends VisPlugin { } parser = bp; - logTable.getColumnModel().getColumn(COLUMN_DATA).setHeaderValue( - GUI.getDescriptionOf(bp)); + logTable.getColumnModel().getColumn(COLUMN_DATA).setHeaderValue(GUI.getDescriptionOf(bp)); repaint(); } From fbb1a56c95237badc2ce7ad541cf8d0dfcb80789 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 1 Mar 2012 15:22:32 +0100 Subject: [PATCH 21/37] possibility to disable individual columns from auto-resize --- .../cooja/dialogs/TableColumnAdjuster.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/cooja/java/se/sics/cooja/dialogs/TableColumnAdjuster.java b/tools/cooja/java/se/sics/cooja/dialogs/TableColumnAdjuster.java index adf7c4825..af88396a2 100644 --- a/tools/cooja/java/se/sics/cooja/dialogs/TableColumnAdjuster.java +++ b/tools/cooja/java/se/sics/cooja/dialogs/TableColumnAdjuster.java @@ -40,6 +40,8 @@ package se.sics.cooja.dialogs; import java.awt.Component; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.util.Arrays; + import javax.swing.JTable; import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelListener; @@ -68,16 +70,23 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi this(table, 6); } + private boolean[] adjustColumns; + /* * Specify the table and spacing */ public TableColumnAdjuster(JTable table, int spacing) { this.table = table; this.spacing = spacing; + TableColumnModel tcm = table.getColumnModel(); + adjustColumns = new boolean[tcm.getColumnCount()]; + Arrays.fill(adjustColumns, true); + setColumnHeaderIncluded(true); setColumnDataIncluded(true); setOnlyAdjustLarger(true); setDynamicAdjustment(false); + } public void packColumns() { @@ -97,10 +106,16 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi public void adjustColumns() { TableColumnModel tcm = table.getColumnModel(); for (int i = 0, n = tcm.getColumnCount(); i < n; i++) { - adjustColumn(i, isOnlyAdjustLarger); + if (adjustColumns[i]) { + adjustColumn(i, isOnlyAdjustLarger); + } } } + public void setAdjustColumn(int i, boolean adjust) { + adjustColumns[i] = adjust; + } + /* * 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) { + if (!adjustColumns[column]) { + return; + } int viewColumn = table.convertColumnIndexToView(column); if (viewColumn < 0) { return; @@ -194,6 +212,9 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi private void adjustColumnsForNewRows(int firstRow, int lastRow) { TableColumnModel tcm = table.getColumnModel(); for (int column = 0, n = tcm.getColumnCount(); column < n; column++) { + if (!adjustColumns[column]) { + continue; + } int viewColumn = table.convertColumnIndexToView(column); if (viewColumn < 0) { continue; @@ -302,6 +323,9 @@ public class TableColumnAdjuster implements PropertyChangeListener, TableModelLi } else if (isOnlyAdjustLarger) { // Only need to worry about an increase in width for these cells + if (!adjustColumns[column]) { + return; + } int viewColumn = table.convertColumnIndexToView(column); if (viewColumn < 0) { // Column is not visible From 681fe65c04b7c7f3fc274f9413b01c0d16c53685 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 1 Mar 2012 15:23:25 +0100 Subject: [PATCH 22/37] added stack trace method stub --- .../java/se/sics/cooja/motes/AbstractEmulatedMote.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/cooja/java/se/sics/cooja/motes/AbstractEmulatedMote.java b/tools/cooja/java/se/sics/cooja/motes/AbstractEmulatedMote.java index fae2c4e50..1d9dae44e 100644 --- a/tools/cooja/java/se/sics/cooja/motes/AbstractEmulatedMote.java +++ b/tools/cooja/java/se/sics/cooja/motes/AbstractEmulatedMote.java @@ -60,7 +60,11 @@ public abstract class AbstractEmulatedMote extends AbstractWakeupMote implements public String getPCString() { return null; } - + + public String getStackTrace() { + return null; + } + public interface MemoryMonitor { public boolean start(int address, int size); public void stop(); From 268608f7e3fd8993ffdf69078d1ba16e09bcf7f6 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 1 Mar 2012 15:24:32 +0100 Subject: [PATCH 23/37] improved mspsim-connected regarding command handlers and context, implemented stack track method --- .../src/se/sics/cooja/mspmote/MspMote.java | 93 +++++++++---------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java index f71d29fe2..217836800 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/MspMote.java @@ -59,6 +59,7 @@ import se.sics.cooja.mspmote.plugins.CodeVisualizerSkin; import se.sics.cooja.mspmote.plugins.MspBreakpointContainer; import se.sics.cooja.plugins.BufferListener.BufferAccess; import se.sics.cooja.plugins.Visualizer; +import se.sics.mspsim.cli.CommandContext; import se.sics.mspsim.cli.CommandHandler; import se.sics.mspsim.cli.LineListener; 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.MapEntry; import se.sics.mspsim.util.MapTable; +import se.sics.mspsim.util.SimpleProfiler; /** * @author Fredrik Osterlind @@ -88,7 +90,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc } private CommandHandler commandHandler; - private ArrayList commandListeners = new ArrayList(); private MSP430 myCpu = null; private MspMoteType myMoteType = null; private MspMoteMemory myMemory = null; @@ -150,24 +151,6 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc 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 */ @@ -234,17 +217,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc * @throws IOException Preparing mote failed */ protected void prepareMote(File fileELF, GenericNode node) throws IOException { - LineOutputStream lout = new LineOutputStream(new LineListener() { - 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); + this.commandHandler = new CommandHandler(System.out, System.err); node.setCommandHandler(commandHandler); ConfigManager config = new ConfigManager(); @@ -271,6 +244,10 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc myCpu.reset(); } + public CommandHandler getCLICommandHandler() { + return commandHandler; + } + /* called when moteID is updated */ public void idUpdated(int newID) { } @@ -344,13 +321,9 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc myCpu.stepMicros(t - lastExecute, duration); lastExecute = t; } catch (EmulationException e) { - String stackTraceOutput = sendCLICommandAndPrint("stacktrace"); - if (stackTraceOutput == null) { - stackTraceOutput = ""; - } - stackTraceOutput = e.getMessage() + "\n\n" + stackTraceOutput; + String trace = e.getMessage() + "\n\n" + getStackTrace(); throw (ContikiError) - new ContikiError(stackTraceOutput).initCause(e); + new ContikiError(trace).initCause(e); } /* Schedule wakeup */ @@ -377,22 +350,29 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc }*/ } - public String sendCLICommandAndPrint(String cmd) { - String response = executeCLICommand(cmd); - logger.fatal(response); - return response; + public String getStackTrace() { + return executeCLICommand("stacktrace"); + } + + public int executeCLICommand(String cmd, CommandContext context) { + return commandHandler.executeCommand(cmd, context); } public String executeCLICommand(String cmd) { final StringBuilder sb = new StringBuilder(); - LineListener tmp = new LineListener() { + LineListener ll = new LineListener() { public void lineRead(String line) { - sb.append(line + "\n"); + sb.append(line).append("\n"); } }; - commandListeners.add(tmp); - sendCLICommand(cmd); - commandListeners.remove(tmp); + PrintStream po = new PrintStream(new LineOutputStream(ll)); + CommandContext c = new CommandContext(commandHandler, null, "", new String[0], 1, null); + c.out = po; + c.err = po; + + if (0 != executeCLICommand(cmd, c)) { + sb.append("\nWarning: command failed"); + } return sb.toString(); } @@ -507,7 +487,7 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc } public String getPCString() { - int pc = myCpu.reg[MSP430Constants.PC]; + int pc = myCpu.getPC(); ELF elf = (ELF)myCpu.getRegistry().getComponent(ELF.class); DebugInfo di = elf.getDebugInfo(pc); @@ -517,6 +497,17 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc } if (di == null) { /* 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]); } @@ -527,15 +518,19 @@ public abstract class MspMote extends AbstractEmulatedMote implements Mote, Watc /* strip path */ file = file.substring(file.lastIndexOf('/')+1, file.length()); } + String function = di.getFunction(); - function = function==null?"?":function; + function = function==null?"":function; if (function.contains(":")) { /* strip arguments */ 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) { From 8229cb8982172d1a2bf953b6977e4b343f5092aa Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 1 Mar 2012 15:25:17 +0100 Subject: [PATCH 24/37] using new mspsim cli api --- .../se/sics/cooja/mspmote/plugins/MspCLI.java | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCLI.java b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCLI.java index 5836b07be..6b375e0fa 100644 --- a/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCLI.java +++ b/tools/cooja/apps/mspsim/src/se/sics/cooja/mspmote/plugins/MspCLI.java @@ -36,6 +36,8 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; +import java.io.PrintStream; + import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPopupMenu; @@ -43,6 +45,7 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingUtilities; + import se.sics.cooja.ClassDescription; import se.sics.cooja.GUI; import se.sics.cooja.Mote; @@ -51,7 +54,9 @@ import se.sics.cooja.PluginType; import se.sics.cooja.Simulation; import se.sics.cooja.VisPlugin; import se.sics.cooja.mspmote.MspMote; +import se.sics.mspsim.cli.CommandContext; import se.sics.mspsim.cli.LineListener; +import se.sics.mspsim.cli.LineOutputStream; @ClassDescription("Msp CLI") @PluginType(PluginType.MOTE_PLUGIN) @@ -66,8 +71,6 @@ public class MspCLI extends VisPlugin implements MotePlugin { private int historyPos = 0; private int historyCount = 0; - private LineListener myListener; - public MspCLI(Mote mote, Simulation simulationToVisualize, GUI gui) { super("Msp CLI (" + mote.getID() + ')', gui); this.mspMote = (MspMote) mote; @@ -79,20 +82,27 @@ public class MspCLI extends VisPlugin implements MotePlugin { logArea.setEditable(false); 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(); JMenuItem clearItem = new JMenuItem("Clear"); clearItem.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { logArea.setText(""); } - }); popupMenu.add(clearItem); logArea.setComponentPopupMenu(popupMenu); ActionListener action = new ActionListener() { - public void actionPerformed(ActionEvent e) { String command = trim(commandField.getText()); if (command != null) { @@ -107,15 +117,16 @@ public class MspCLI extends VisPlugin implements MotePlugin { } historyPos = historyCount; addCLIData("> " + command); - mspMote.sendCLICommand(command); + + mspMote.executeCLICommand(command, commandContext); commandField.setText(""); } catch (Exception ex) { System.err.println("could not send '" + command + "':"); ex.printStackTrace(); JOptionPane.showMessageDialog(panel, - "could not send '" + command + "':\n" - + ex, "ERROR", - JOptionPane.ERROR_MESSAGE); + "could not send '" + command + "':\n" + + ex, "ERROR", + JOptionPane.ERROR_MESSAGE); } } else { commandField.getToolkit().beep(); @@ -166,19 +177,9 @@ public class MspCLI extends VisPlugin implements MotePlugin { }); panel.add(commandField, BorderLayout.SOUTH); - - myListener = new LineListener() { - public void lineRead(String line) { - addCLIData(line); - } - }; - mspMote.addCLIListener(myListener); } public void closePlugin() { - if (myListener != null) { - mspMote.addCLIListener(null); - } } public void addCLIData(final String text) { @@ -199,7 +200,7 @@ public class MspCLI extends VisPlugin implements MotePlugin { private String trim(String text) { return (text != null) && ((text = text.trim()).length() > 0) ? text : null; } - + public Mote getMote() { return mspMote; } From 656251a6afef4c1d1d65c3e99f6088dd261647b0 Mon Sep 17 00:00:00 2001 From: Fredrik Osterlind Date: Thu, 1 Mar 2012 15:28:07 +0100 Subject: [PATCH 25/37] new mspsim.jar, supporting the recent changes in bufferlistener --- tools/mspsim/mspsim.jar | Bin 645956 -> 646841 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/tools/mspsim/mspsim.jar b/tools/mspsim/mspsim.jar index 43689baa7e6a8b47cda4d5fc9ce65d9b6555584f..fa3178fce78e5ee4356564ddf2f2d0f88615608d 100644 GIT binary patch delta 68556 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 AQ~&?~ delta 67488 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 t=e0e993BwX Date: Thu, 1 Mar 2012 16:37:26 +0100 Subject: [PATCH 26/37] bugfixed stacktrace tooltip --- .../se/sics/cooja/plugins/BufferListener.java | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java b/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java index 58fd675bf..6e4323650 100644 --- a/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java +++ b/tools/cooja/java/se/sics/cooja/plugins/BufferListener.java @@ -335,14 +335,17 @@ public class BufferListener extends VisPlugin { java.awt.Point p = e.getPoint(); int rowIndex = rowAtPoint(p); int colIndex = columnAtPoint(p); - int columnIndex = convertColumnIndexToModel(colIndex); - if (rowIndex < 0 || columnIndex < 0) { + if (rowIndex < 0 || colIndex < 0) { + return super.getToolTipText(e); + } + int row = convertRowIndexToModel(rowIndex); + int column = convertColumnIndexToModel(colIndex); + if (row < 0 || column < 0) { return super.getToolTipText(e); } - Object v = getValueAt(rowIndex, columnIndex); - if (columnIndex == COLUMN_SOURCE) { - BufferAccess ba = logs.get(rowIndex); + if (column == COLUMN_SOURCE) { + BufferAccess ba = logs.get(row); if (ba.stackTrace != null) { return "
" +
@@ -351,24 +354,25 @@ public class BufferListener extends VisPlugin {
           }
           return "No stack trace (enable in popup menu)";
         }
-        if (v instanceof BufferAccess && parser instanceof GraphicalParser) {
-          return
-          "" + 
-          StringUtils.hexDump(((BufferAccess)v).mem, 4, 4).replaceAll("\n", "
") + - ""; - } - if (v != null) { - String t = v.toString(); - if (t.length() > 60) { - StringBuilder sb = new StringBuilder(); - sb.append(""); - do { - sb.append(t.substring(0, 60)).append("
"); - t = t.substring(60); - } while (t.length() > 60); - return sb.append(t).append("").toString(); + if (column == COLUMN_DATA) { + BufferAccess ba = logs.get(row); + if (parser instanceof GraphicalParser) { + return + "
" +
+            StringUtils.hexDump(ba.mem, 4, 4) +
+            "
"; } + + String baString = ba.getParsedString(); + StringBuilder sb = new StringBuilder(); + sb.append(""); + while (baString.length() > 60) { + sb.append(baString.substring(0, 60)).append("
"); + baString = baString.substring(60); + }; + return sb.append(baString).append("").toString(); } + return super.getToolTipText(e); } }; From c1aa211dc757bc46e07f27e5ff527e037eafc03d Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Wed, 1 Feb 2012 03:58:35 +0100 Subject: [PATCH 27/37] Added RST-MID matching for observing. --- apps/er-coap-07/er-coap-07-engine.c | 4 ++-- apps/er-coap-07/er-coap-07-observing.c | 24 ++++++++++++++++++++++++ apps/er-coap-07/er-coap-07-observing.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index f0545d61e..326d811a9 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -225,8 +225,8 @@ handle_incoming_data(void) /* Cancel possible subscriptions. */ if (IS_OPTION(message, COAP_OPTION_TOKEN)) { - /* RST must be empty, so it is a full client reset. */ - coap_remove_observer_by_client(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport); + /* Erbium stores last MID for each observer. */ + coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); } } diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index 5324a3a00..d9852f4e0 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -69,6 +69,7 @@ coap_add_observer(uip_ipaddr_t *addr, uint16_t port, const uint8_t *token, size_ o->port = port; o->token_len = token_len; memcpy(o->token, token, token_len); + o->last_mid = 0; 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; } + int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, size_t token_len) { @@ -124,6 +126,7 @@ coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *token, } return removed; } + int coap_remove_observer_by_url(uip_ipaddr_t *addr, uint16_t port, const char *url) { @@ -141,6 +144,24 @@ coap_remove_observer_by_url(uip_ipaddr_t *addr, uint16_t port, const char *url) } 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 URL %p\n", url); + if (uip_ipaddr_cmp(&obs->addr, addr) && obs->port==port && obs->last_mid==mid) + { + 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) @@ -177,6 +198,9 @@ coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payl PRINTF(":%u\n", obs->port); PRINTF(" %.*s\n", payload_len, payload); + /* Update last MID for RST matching. */ + obs->last_mid = transaction->mid; + coap_send_transaction(transaction); } } diff --git a/apps/er-coap-07/er-coap-07-observing.h b/apps/er-coap-07/er-coap-07-observing.h index d30acbebc..7b09ba83e 100644 --- a/apps/er-coap-07/er-coap-07-observing.h +++ b/apps/er-coap-07/er-coap-07-observing.h @@ -61,6 +61,7 @@ typedef struct coap_observer { uint16_t port; uint8_t token_len; uint8_t token[COAP_TOKEN_LEN]; + uint16_t last_mid; struct stimer refresh_timer; } coap_observer_t; @@ -72,6 +73,7 @@ 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); 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); From 860de0dd01f17f440d8122de9d88a062c7f959b5 Mon Sep 17 00:00:00 2001 From: Matthias Kovatsch Date: Wed, 1 Feb 2012 05:16:16 +0100 Subject: [PATCH 28/37] Bugfixes for observing. Many thanks to Klaus Hartke. --- apps/er-coap-07/er-coap-07-engine.c | 6 +----- apps/er-coap-07/er-coap-07-observing.c | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/apps/er-coap-07/er-coap-07-engine.c b/apps/er-coap-07/er-coap-07-engine.c index 326d811a9..b9f790e29 100644 --- a/apps/er-coap-07/er-coap-07-engine.c +++ b/apps/er-coap-07/er-coap-07-engine.c @@ -223,11 +223,7 @@ handle_incoming_data(void) { PRINTF("Received RST\n"); /* Cancel possible subscriptions. */ - if (IS_OPTION(message, COAP_OPTION_TOKEN)) - { - /* Erbium stores last MID for each observer. */ - coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); - } + coap_remove_observer_by_mid(&UIP_IP_BUF->srcipaddr, UIP_UDP_BUF->srcport, message->mid); } if ( (transaction = coap_get_transaction_by_mid(message->mid)) ) diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index d9852f4e0..11eef1935 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -118,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) { 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); removed++; @@ -153,7 +153,7 @@ coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid) for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) { - PRINTF("Remove check URL %p\n", url); + 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); From 499d3052ee5ad19b7c951cfa59d343af83765ede Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Wed, 22 Feb 2012 00:46:32 +0000 Subject: [PATCH 29/37] Fixed TARGET=native compilation issues on Darwin. --- cpu/native/Makefile.native | 6 +++++- cpu/x86/Makefile.x86 | 6 +++++- platform/native/Makefile.native | 4 ++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cpu/native/Makefile.native b/cpu/native/Makefile.native index d2a8c1d3c..56fb6688b 100644 --- a/cpu/native/Makefile.native +++ b/cpu/native/Makefile.native @@ -14,7 +14,11 @@ CFLAGSWERROR=-Werror -pedantic -std=c99 -Werror endif CFLAGSNO = -Wall -g -I/usr/local/include $(CFLAGSWERROR) 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 diff --git a/cpu/x86/Makefile.x86 b/cpu/x86/Makefile.x86 index be3f62579..612603f52 100644 --- a/cpu/x86/Makefile.x86 +++ b/cpu/x86/Makefile.x86 @@ -10,7 +10,11 @@ OBJCOPY = objcopy STRIP = strip CFLAGSNO = -Wall -g -I/usr/local/include 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 diff --git a/platform/native/Makefile.native b/platform/native/Makefile.native index 63ba12e9d..36368e266 100644 --- a/platform/native/Makefile.native +++ b/platform/native/Makefile.native @@ -2,6 +2,10 @@ ifndef CONTIKI $(error CONTIKI not defined! You must specify where CONTIKI resides!) endif +ifeq ($(HOST_OS),Darwin) + AROPTS = rc +endif + ifdef UIP_CONF_IPV6 CFLAGS += -DWITH_UIP6=1 endif From 70d3acf9afd78180de27cb6b7aa36b903b735a63 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Wed, 22 Feb 2012 00:47:51 +0000 Subject: [PATCH 30/37] Fixed baudrate issue on Darwin. --- examples/ipv6/native-border-router/slip-config.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/ipv6/native-border-router/slip-config.c b/examples/ipv6/native-border-router/slip-config.c index fb00d18cc..daad4907a 100644 --- a/examples/ipv6/native-border-router/slip-config.c +++ b/examples/ipv6/native-border-router/slip-config.c @@ -127,7 +127,11 @@ slip_config_handle_arguments(int argc, char **argv) fprintf(stderr,"usage: %s [options] ipaddress\n", prog); fprintf(stderr,"example: border-router.native -L -v2 -s ttyUSB1 aaaa::1/64\n"); fprintf(stderr,"Options are:\n"); +#ifdef linux 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," -L Log output format (adds time stamps)\n"); fprintf(stderr," -s siodev Serial device (default /dev/ttyUSB0)\n"); @@ -175,9 +179,11 @@ exit(1); case 115200: slip_config_b_rate = B115200; break; +#ifdef linux case 921600: slip_config_b_rate = B921600; break; +#endif default: err(1, "unknown baudrate %d", baudrate); break; From 7621bdfc777a44b80b83df3caa67c490c60a9ab8 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Wed, 22 Feb 2012 17:28:33 +0000 Subject: [PATCH 31/37] Fixed ifconfig for Darwin --- examples/ipv6/native-border-router/tun-bridge.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/ipv6/native-border-router/tun-bridge.c b/examples/ipv6/native-border-router/tun-bridge.c index db695c289..3eae3795f 100644 --- a/examples/ipv6/native-border-router/tun-bridge.c +++ b/examples/ipv6/native-border-router/tun-bridge.c @@ -125,13 +125,17 @@ void ifconf(const char *tundev, const char *ipaddr) { #ifdef linux - ssystem("ifconfig %s inet `hostname` up", tundev); + ssystem("ifconfig %s inet6 `hostname` up", tundev); ssystem("ifconfig %s add %s", tundev, ipaddr); +#elif defined(__MACH__) + ssystem("ifconfig %s inet6 %s up", tundev, ipaddr); + ssystem("sysctl -w net.inet.ip.forwarding=1"); #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"); #endif /* !linux */ + /* Print the configuration to the console. */ ssystem("ifconfig %s\n", tundev); } /*---------------------------------------------------------------------------*/ From b67e49051cc9b55d52c5e08b1c9b6dc2d4f13d3c Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Tue, 28 Feb 2012 21:28:57 +0000 Subject: [PATCH 32/37] Use `__APPLE__` instead of `__MACH__`. --- examples/ipv6/native-border-router/tun-bridge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ipv6/native-border-router/tun-bridge.c b/examples/ipv6/native-border-router/tun-bridge.c index 3eae3795f..54d16339c 100644 --- a/examples/ipv6/native-border-router/tun-bridge.c +++ b/examples/ipv6/native-border-router/tun-bridge.c @@ -127,7 +127,7 @@ ifconf(const char *tundev, const char *ipaddr) #ifdef linux ssystem("ifconfig %s inet6 `hostname` up", tundev); ssystem("ifconfig %s add %s", tundev, ipaddr); -#elif defined(__MACH__) +#elif defined(__APPLE__) ssystem("ifconfig %s inet6 %s up", tundev, ipaddr); ssystem("sysctl -w net.inet.ip.forwarding=1"); #else From 49cd7878e3ca45ac0a609a1511f9a9bdba4094ef Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Tue, 28 Feb 2012 21:36:05 +0000 Subject: [PATCH 33/37] Avoid deprecated error on Darwin. --- cpu/native/mtarch.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cpu/native/mtarch.c b/cpu/native/mtarch.c index 5bb01a0cc..e9df427d0 100644 --- a/cpu/native/mtarch.c +++ b/cpu/native/mtarch.c @@ -40,7 +40,12 @@ static void *main_fiber; -#elif defined(__linux) +#elif defined(__linux) || defined(__APPLE__) + +#ifdef __APPLE__ +/* Avoid deprecated error on Darwin */ +#define _XOPEN_SOURCE +#endif #include #include From 1214086f97abc74eee07d7d7e08e75b55906a989 Mon Sep 17 00:00:00 2001 From: Ilya Dmitrichenko Date: Fri, 2 Mar 2012 10:04:59 +0000 Subject: [PATCH 34/37] Fixed TARGET=minimal-net compilation issues on Darwin. --- platform/minimal-net/Makefile.minimal-net | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/minimal-net/Makefile.minimal-net b/platform/minimal-net/Makefile.minimal-net index dd35c8880..296d5684e 100644 --- a/platform/minimal-net/Makefile.minimal-net +++ b/platform/minimal-net/Makefile.minimal-net @@ -2,6 +2,10 @@ ifndef CONTIKI $(error CONTIKI not defined! You must specify where CONTIKI resides!) endif +ifeq ($(HOST_OS),Darwin) + AROPTS = rc +endif + CONTIKI_TARGET_DIRS = . CONTIKI_TARGET_MAIN = ${addprefix $(OBJECTDIR)/,contiki-main.o} From 358530e1d3b52c514dd2511e64e0976d5a9d0fb1 Mon Sep 17 00:00:00 2001 From: David Kopf Date: Fri, 2 Mar 2012 15:28:26 -0500 Subject: [PATCH 35/37] Add higher baud rates, option for link-local address assignment --- tools/tunslip6.c | 57 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/tools/tunslip6.c b/tools/tunslip6.c index 4192dae4f..3b6a51601 100644 --- a/tools/tunslip6.c +++ b/tools/tunslip6.c @@ -29,7 +29,6 @@ * * 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); if (timestamp) stamptime(); 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 Date: Fri, 2 Mar 2012 15:51:42 -0500 Subject: [PATCH 36/37] Redo html output, more options, httpd state variables to allow neighbors and routes to span tcp segments. --- apps/webserver-nano/httpd-cgi.c | 273 ++++++++++++++++++++++---------- apps/webserver-nano/httpd.h | 32 +++- 2 files changed, 215 insertions(+), 90 deletions(-) diff --git a/apps/webserver-nano/httpd-cgi.c b/apps/webserver-nano/httpd-cgi.c index 8a78bee0a..ba36461e1 100644 --- a/apps/webserver-nano/httpd-cgi.c +++ b/apps/webserver-nano/httpd-cgi.c @@ -283,7 +283,7 @@ generate_file_stats(void *arg) { struct httpd_state *s = (struct httpd_state *)arg; #if WEBSERVER_CONF_LOADTIME - static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "



This page has been sent %u times (%1u.%u sec)"; + static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "



This page has been sent %u times (%1u.%02u sec)"; #else static const char httpd_cgi_filestat1[] HTTPD_STRING_ATTR = "



This page has been sent %u times"; #endif @@ -301,7 +301,7 @@ generate_file_stats(void *arg) #if WEBSERVER_CONF_LOADTIME s->pagetime = clock_time() - s->pagetime; 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 numprinted=httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_filestat1, httpd_fs_open(s->filename, 0)); #endif @@ -433,10 +433,12 @@ PT_THREAD(processes(struct httpd_state *s, char *ptr)) #endif /* WEBSERVER_CONF_PROCESSES */ #if WEBSERVER_CONF_ADDRESSES || WEBSERVER_CONF_NEIGHBORS || WEBSERVER_CONF_ROUTES -static const char httpd_cgi_addrh[] HTTPD_STRING_ATTR = ""; -static const char httpd_cgi_addrf[] HTTPD_STRING_ATTR = "[Room for %u more]"; -static const char httpd_cgi_addrb[] HTTPD_STRING_ATTR = "
"; -static const char httpd_cgi_addrn[] HTTPD_STRING_ATTR = "(none)
"; +#if WEBSERVER_CONF_SHOW_ROOM +static const char httpd_cgi_addrf[] HTTPD_STRING_ATTR = "[Room for %u more]\n"; +#else +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 #if WEBSERVER_CONF_ADDRESSES @@ -447,16 +449,21 @@ static unsigned short make_addresses(void *p) { uint8_t i,j=0; -uint16_t numprinted; - numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh); +uint16_t numprinted = 0; for (i=0; istarti;j=s->startj; + for (;i (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; } /*---------------------------------------------------------------------------*/ @@ -496,7 +541,13 @@ PT_THREAD(neighbors(struct httpd_state *s, char *ptr)) { 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); } @@ -508,27 +559,57 @@ extern uip_ds6_route_t uip_ds6_routing_table[]; static unsigned short make_routes(void *p) { -static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "(%u (via "; -static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ") %lus
"; -static const char httpd_cgi_rtes3[] HTTPD_STRING_ATTR = ")
"; -uint8_t i,j=0; -uint16_t numprinted; - numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(),httpd_cgi_addrh); - for (i=0; istarti;j=s->startj; + for (;i (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); - 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; } /*---------------------------------------------------------------------------*/ @@ -536,8 +617,14 @@ static PT_THREAD(routes(struct httpd_state *s, char *ptr)) { 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); } @@ -548,18 +635,15 @@ PT_THREAD(routes(struct httpd_state *s, char *ptr)) static unsigned short generate_sensor_readings(void *arg) { - uint16_t numprinted; + uint16_t numprinted=0; uint16_t days,h,m,s; unsigned long seconds=clock_seconds(); - static const char httpd_cgi_sensor0[] HTTPD_STRING_ATTR = "[Updated %d seconds ago]

"; - static const char httpd_cgi_sensor1[] HTTPD_STRING_ATTR = "

Temperature: %s\n";
+  static const char httpd_cgi_sensor0[] HTTPD_STRING_ATTR = "[Updated %d seconds ago]\n";
+  static const char httpd_cgi_sensor1[] HTTPD_STRING_ATTR = "Temperature: %s\n";
   static const char httpd_cgi_sensor2[] HTTPD_STRING_ATTR = "Battery    : %s\n";
-//  static const char httpd_cgi_sensr12[] HTTPD_STRING_ATTR = "Temperature: %s   Battery: %s
"; static const char httpd_cgi_sensor3[] HTTPD_STRING_ATTR = "Uptime : %02d:%02d:%02d\n"; static const char httpd_cgi_sensor3d[] HTTPD_STRING_ATTR = "Uptime : %u days %02u:%02u:%02u\n"; -// static const char httpd_cgi_sensor4[] HTTPD_STRING_ATTR = "Sleeping time : %02d:%02d:%02d (%d%%)
"; - numprinted=0; /* Generate temperature and voltage strings for each platform */ #if CONTIKI_TARGET_AVR_ATMEGA128RFA1 {uint8_t i; @@ -623,29 +707,36 @@ generate_sensor_readings(void *arg) #elif CONTIKI_TARGET_REDBEE_ECONOTAG //#include "adc.h" { +#if 0 +/* Scan ADC channels if not already being done elsewhere */ uint8_t c; - adc_reading[8]=0; - adc_init(); - while (adc_reading[8]==0) adc_service(); - // for (c=0; csout); PSOCK_GENERATOR_SEND(&s->sout, generate_sensor_readings, s); -#if RADIOSTATS - PSOCK_GENERATOR_SEND(&s->sout, generate_radio_stats, s); +#if WEBSERVER_CONF_STATISTICS + PSOCK_GENERATOR_SEND(&s->sout, generate_stats, s); #endif PSOCK_END(&s->sout); @@ -971,15 +1055,40 @@ PT_THREAD(ajax_call(struct httpd_state *s, char *ptr)) SENSORS_DEACTIVATE(acc_sensor); #elif CONTIKI_TARGET_REDBEE_ECONOTAG -{ uint8_t c; - adc_reading[8]=0; - adc_init(); - while (adc_reading[8]==0) adc_service(); - adc_disable(); - 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]); +#if 0 +/* Scan ADC channels if not already done elsewhere */ +{ uint8_t c; + adc_reading[8]=0; + adc_init(); + while (adc_reading[8]==0) adc_service(); + 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 Date: Fri, 2 Mar 2012 16:01:12 -0500 Subject: [PATCH 37/37] Add display options to border router web page, default now uses stack instead of static buffer. Turn radio off until prefix is acquired. --- core/net/mac/contikimac.c | 6 + .../ipv6/rpl-border-router/border-router.c | 139 ++++++++++++++++-- 2 files changed, 130 insertions(+), 15 deletions(-) diff --git a/core/net/mac/contikimac.c b/core/net/mac/contikimac.c index c65a975c9..81640793e 100644 --- a/core/net/mac/contikimac.c +++ b/core/net/mac/contikimac.c @@ -535,6 +535,12 @@ send_packet(mac_callback_t mac_callback, void *mac_callback_ptr, struct rdc_buf_ struct hdr *chdr; #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) { PRINTF("contikimac: send_packet data len 0\n"); return MAC_TX_ERR_FATAL; diff --git a/examples/ipv6/rpl-border-router/border-router.c b/examples/ipv6/rpl-border-router/border-router.c index 418425ff9..33d9f754b 100644 --- a/examples/ipv6/rpl-border-router/border-router.c +++ b/examples/ipv6/rpl-border-router/border-router.c @@ -74,6 +74,13 @@ AUTOSTART_PROCESSES(&border_router_process,&webserver_nogui_process); #else /* Use simple webserver with only one page */ #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_THREAD(webserver_nogui_process, ev, data) { @@ -92,11 +99,19 @@ AUTOSTART_PROCESSES(&border_router_process,&webserver_nogui_process); static const char *TOP = "ContikiRPL\n"; static const char *BOTTOM = "\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; #define ADD(...) do { \ blen += snprintf(&buf[blen], sizeof(buf) - blen, __VA_ARGS__); \ } while(0) +#endif + /*---------------------------------------------------------------------------*/ static void 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) { a = (addr->u8[i] << 8) + addr->u8[i + 1]; if(a == 0 && f >= 0) { - if(f++ == 0 && sizeof(buf) - blen >= 2) { - buf[blen++] = ':'; - buf[blen++] = ':'; - } + if(f++ == 0) ADD("::"); } else { if(f > 0) { f = -1; - } else if(i > 0 && blen < sizeof(buf)) { - buf[blen++] = ':'; + } else if(i > 0) { + ADD(":"); } ADD("%x", a); } @@ -125,46 +137,130 @@ static PT_THREAD(generate_routes(struct httpd_state *s)) { 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); SEND_STRING(&s->sout, TOP); - +#if BUF_USES_STACK + bufptr = buf;bufend=bufptr+sizeof(buf); +#else blen = 0; +#endif ADD("Neighbors
");
   for(i = 0; i < UIP_DS6_NBR_NB; i++) {
     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);
+      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");
+#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) {
         SEND_STRING(&s->sout, buf);
         blen = 0;
       }
+#endif
     }
   }
-
   ADD("
Routes
");
   SEND_STRING(&s->sout, buf);
+#if BUF_USES_STACK
+  bufptr = buf; bufend = bufptr + sizeof(buf);
+#else
   blen = 0;
+#endif
   for(i = 0; i < UIP_DS6_ROUTE_NB; i++) {
     if(uip_ds6_routing_table[i].isused) {
+#if BUF_USES_STACK
+#if WEBSERVER_CONF_ROUTE_LINKS
+      ADD("");
+      ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
+      ADD("");
+#else
+      ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
+#endif
+#else
+#if WEBSERVER_CONF_ROUTE_LINKS
+      ADD("");
+      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("");
+#else
+      ipaddr_add(&uip_ds6_routing_table[i].ipaddr);
+#endif
+#endif
       ADD("/%u (via ", uip_ds6_routing_table[i].length);
       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);
       } else {
         ADD(")\n");
       }
       SEND_STRING(&s->sout, buf);
+#if BUF_USES_STACK
+      bufptr = buf; bufend = bufptr + sizeof(buf);
+#else
       blen = 0;
+#endif
     }
   }
   ADD("
"); -//if(blen > 0) { - SEND_STRING(&s->sout, buf); -// blen = 0; -//} +#if WEBSERVER_CONF_FILESTATS + static uint16_t numtimes; + ADD("
This page sent %u times",++numtimes); +#endif + +#if WEBSERVER_CONF_LOADTIME + numticks = clock_time() - numticks + 1; + ADD(" (%u.%02u sec)",numticks/CLOCK_SECOND,(100*(numticks%CLOCK_SECOND))/CLOCK_SECOND)); +#endif + + SEND_STRING(&s->sout, buf); SEND_STRING(&s->sout, BOTTOM); PSOCK_END(&s->sout); @@ -173,6 +269,7 @@ PT_THREAD(generate_routes(struct httpd_state *s)) httpd_simple_script_t httpd_simple_get_script(const char *name) { + return generate_routes; } @@ -226,19 +323,26 @@ PROCESS_THREAD(border_router_process, ev, data) 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; + NETSTACK_MAC.off(0); PROCESS_PAUSE(); SENSORS_ACTIVATE(button_sensor); PRINTF("RPL-Border router started\n"); - +#if 0 /* The border router runs with a 100% duty cycle in order to ensure high packet reception rates. Note if the MAC RDC is not turned off now, aggressive power management of the cpu will interfere with establishing the SLIP connection */ NETSTACK_MAC.off(1); +#endif /* Request prefix until it has been received */ while(!prefix_set) { @@ -253,6 +357,11 @@ PROCESS_THREAD(border_router_process, ev, data) 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 print_local_addresses(); #endif