diff --git a/apps/er-coap-07/er-coap-07-observing.c b/apps/er-coap-07/er-coap-07-observing.c index 11eef1935..5c8b5e465 100644 --- a/apps/er-coap-07/er-coap-07-observing.c +++ b/apps/er-coap-07/er-coap-07-observing.c @@ -164,43 +164,51 @@ 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) +coap_notify_observers(resource_t *resource, uint16_t obs_counter, void *notification) { + coap_packet_t *const coap_res = (coap_packet_t *) notification; coap_observer_t* obs = NULL; + uint8_t preferred_type = coap_res->type; + + PRINTF("Observing: Notification from %s\n", resource->url); + + /* Iterate over observers. */ for (obs = (coap_observer_t*)list_head(observers_list); obs; obs = obs->next) { - if (obs->url==url) /* using RESOURCE url pointer as handle */ + if (obs->url==resource->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 */ + /*TODO implement special transaction for CON, sharing the same buffer to allow for more observers. */ 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)) - { - 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->mid ); - 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); + PRINTF(" Observer "); PRINT6ADDR(&obs->addr); PRINTF(":%u\n", obs->port); - PRINTF(" %.*s\n", payload_len, payload); /* Update last MID for RST matching. */ obs->last_mid = transaction->mid; + /* Prepare response */ + coap_res->mid = transaction->mid; + coap_set_header_observe(coap_res, obs_counter); + coap_set_header_token(coap_res, obs->token, obs->token_len); + + /* Use CON to check whether client is still there/interested after COAP_OBSERVING_REFRESH_INTERVAL. */ + if (stimer_expired(&obs->refresh_timer)) + { + PRINTF(" Refreshing with CON\n"); + coap_res->type = COAP_TYPE_CON; + stimer_restart(&obs->refresh_timer); + } + else + { + coap_res->type = preferred_type; + } + + transaction->packet_len = coap_serialize_message(coap_res, transaction->packet); + 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 7b09ba83e..a17ad86bd 100644 --- a/apps/er-coap-07/er-coap-07-observing.h +++ b/apps/er-coap-07/er-coap-07-observing.h @@ -75,7 +75,7 @@ int coap_remove_observer_by_token(uip_ipaddr_t *addr, uint16_t port, uint8_t *to int coap_remove_observer_by_url(uip_ipaddr_t *addr, uint16_t port, const char *url); int coap_remove_observer_by_mid(uip_ipaddr_t *addr, uint16_t port, uint16_t mid); -void coap_notify_observers(const char *url, int type, uint32_t observe, uint8_t *payload, size_t payload_len); +void coap_notify_observers(resource_t *resource, uint16_t obs_counter, void *notification); void coap_observe_handler(resource_t *resource, void *request, void *response); diff --git a/apps/er-coap-07/er-coap-07-transactions.c b/apps/er-coap-07/er-coap-07-transactions.c index 10070a29e..2a11002d4 100644 --- a/apps/er-coap-07/er-coap-07-transactions.c +++ b/apps/er-coap-07/er-coap-07-transactions.c @@ -105,6 +105,7 @@ coap_send_transaction(coap_transaction_t *t) { if (t->retrans_countermid); if (t->retrans_counter==0) @@ -118,7 +119,10 @@ coap_send_transaction(coap_transaction_t *t) 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 */ + /*FIXME + * Hack: Setting timer for responsible process. + * 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 */ @@ -128,7 +132,7 @@ coap_send_transaction(coap_transaction_t *t) } else { - /* timeout */ + /* Timed out. */ PRINTF("Timeout\n"); restful_response_handler callback = t->callback; void *callback_data = t->callback_data; diff --git a/apps/erbium/erbium.h b/apps/erbium/erbium.h index 7e491c3f8..72b995db0 100644 --- a/apps/erbium/erbium.h +++ b/apps/erbium/erbium.h @@ -75,7 +75,7 @@ struct periodic_resource_s; typedef void (*restful_handler) (void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); typedef int (*restful_pre_handler) (struct resource_s *resource, void* request, void* response); typedef void (*restful_post_handler) (struct resource_s *resource, void* request, void* response); -typedef int (*restful_periodic_handler) (struct resource_s* resource); +typedef void (*restful_periodic_handler) (struct resource_s* resource); typedef void (*restful_response_handler) (void *data, void* response); /* Signature of the rest-engine service function. */ @@ -134,6 +134,31 @@ struct rest_implementation_type unsigned int APPLICATION_X_OBIX_BINARY; }; +/* + * Data structure representing a resource in REST. + */ +struct resource_s { + struct resource_s *next; /* for LIST, points to next resource defined */ + rest_resource_flags_t flags; /* handled RESTful methods */ + const char* url; /*handled URL*/ + const char* attributes; /* link-format attributes */ + restful_handler handler; /* handler function */ + restful_pre_handler pre_handler; /* to be called before handler, may perform initializations */ + restful_post_handler post_handler; /* to be called after handler, may perform finalizations (cleanup, etc) */ + void* user_data; /* pointer to user specific data */ + unsigned int benchmark; /* to benchmark resource handler, used for separate response */ +}; +typedef struct resource_s resource_t; + +struct periodic_resource_s { + struct periodic_resource_s *next; /* for LIST, points to next resource defined */ + resource_t *resource; + uint32_t period; + struct etimer periodic_timer; + restful_periodic_handler periodic_handler; +}; +typedef struct periodic_resource_s periodic_resource_t; + struct rest_implementation { char *name; @@ -199,7 +224,7 @@ struct rest_implementation { int (* get_post_variable)(void *request, const char *name, const char **value); /** Send the payload to all subscribers of the resource at url. */ - void (* notify_subscribers)(const char *url, int implementation_secific_mode, uint32_t counter, uint8_t *payload, size_t payload_len); + void (* notify_subscribers)(resource_t *resource, uint16_t counter, void *notification); /** The handler for resource subscriptions. */ restful_post_handler subscription_handler; @@ -222,32 +247,6 @@ struct rest_implementation { */ extern const struct rest_implementation REST; -/* - * Data structure representing a resource in REST. - */ -struct resource_s { - struct resource_s *next; /* for LIST, points to next resource defined */ - rest_resource_flags_t flags; /* handled RESTful methods */ - const char* url; /*handled URL*/ - const char* attributes; /* link-format attributes */ - restful_handler handler; /* handler function */ - restful_pre_handler pre_handler; /* to be called before handler, may perform initializations */ - restful_post_handler post_handler; /* to be called after handler, may perform finalizations (cleanup, etc) */ - void* user_data; /* pointer to user specific data */ - unsigned int benchmark; /* to benchmark resource handler, used for separate response */ -}; -typedef struct resource_s resource_t; - -struct periodic_resource_s { - struct periodic_resource_s *next; /* for LIST, points to next resource defined */ - resource_t *resource; - uint32_t period; - struct etimer periodic_timer; - restful_periodic_handler periodic_handler; -}; -typedef struct periodic_resource_s periodic_resource_t; - - /* * Macro to define a Resource * Resources are statically defined for the sake of efficiency and better memory management. @@ -282,7 +281,7 @@ int name##_event_handler(resource_t*) #define PERIODIC_RESOURCE(name, flags, url, attributes, period) \ void name##_handler(void *, void *, uint8_t *, uint16_t, int32_t *); \ resource_t resource_##name = {NULL, flags, url, attributes, name##_handler, NULL, NULL, NULL}; \ -int name##_periodic_handler(resource_t*); \ +void name##_periodic_handler(resource_t*); \ periodic_resource_t periodic_resource_##name = {NULL, &resource_##name, period, {{0}}, name##_periodic_handler} diff --git a/examples/er-rest-example/plugtest-server.c b/examples/er-rest-example/plugtest-server.c index 550d1c0c4..0d4eb5c7b 100644 --- a/examples/er-rest-example/plugtest-server.c +++ b/examples/er-rest-example/plugtest-server.c @@ -225,7 +225,7 @@ separate_handler(void* request, void* response, uint8_t *buffer, uint16_t prefer PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); } -int +void separate_periodic_handler(resource_t *resource) { if (separate_active) @@ -256,14 +256,10 @@ separate_periodic_handler(resource_t *resource) /* The engine will clear the transaction (right after send for NON, after acked for CON). */ separate_active = 0; - - return 1; } else { PRINTF("ERROR (transaction)\n"); } } /* if (separate_active) */ - - return 0; } #endif @@ -364,7 +360,7 @@ large_update_handler(void* request, void* response, uint8_t *buffer, uint16_t pr *offset = -1; } } else { - const uint8_t *incoming = NULL; + uint8_t *incoming = NULL; size_t len = 0; unsigned int ct = REST.get_header_content_type(request); @@ -415,9 +411,8 @@ void large_create_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { coap_packet_t *const coap_req = (coap_packet_t *) request; - uint8_t method = REST.get_method_type(request); - const uint8_t *incoming = NULL; + uint8_t *incoming = NULL; size_t len = 0; unsigned int ct = REST.get_header_content_type(request); @@ -461,7 +456,7 @@ large_create_handler(void* request, void* response, uint8_t *buffer, uint16_t pr */ PERIODIC_RESOURCE(obs, METHOD_GET, "obs", "title=\"Observable resource which changes every 5 seconds\";obs;rt=\"observe\"", 5*CLOCK_SECOND); -static uint32_t obs_counter = 0; +static uint16_t obs_counter = 0; static char obs_content[16]; void @@ -479,18 +474,20 @@ obs_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_s * 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 +void obs_periodic_handler(resource_t *r) { + ++obs_counter; - PRINTF("TICK /%s\n", r->url); - obs_counter = obs_counter + 1; + PRINTF("TICK %u for /%s\n", obs_counter, r->url); + + /* Build notification. */ + coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ + coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0 ); + coap_set_payload(notification, obs_content, snprintf(obs_content, sizeof(obs_content), "TICK %u", obs_counter)); /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(r->url, 1, obs_counter, (uint8_t *)obs_content, snprintf(obs_content, sizeof(obs_content), "TICK %lu", obs_counter)); - /* |-> implementation-specific, e.g. CoAP: 0=CON and 1=NON notification */ - - return 1; + REST.notify_subscribers(r, obs_counter, notification); } #endif diff --git a/examples/er-rest-example/rest-server-example.c b/examples/er-rest-example/rest-server-example.c index f7f2e3b55..a958c1d2a 100644 --- a/examples/er-rest-example/rest-server-example.c +++ b/examples/er-rest-example/rest-server-example.c @@ -465,20 +465,23 @@ pushing_handler(void* request, void* response, uint8_t *buffer, uint16_t preferr * 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 +void pushing_periodic_handler(resource_t *r) { - static uint32_t periodic_i = 0; - static char content[16]; + static uint16_t obs_counter = 0; + static char content[11]; - PRINTF("TICK /%s\n", r->url); - periodic_i = periodic_i + 1; + ++obs_counter; + + PRINTF("TICK %u for /%s\n", periodic_i, r->url); + + /* Build notification. */ + coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ + coap_init_message(notification, COAP_TYPE_NON, CONTENT_2_05, 0 ); + coap_set_payload(notification, content, snprintf(content, sizeof(content), "TICK %u", obs_counter)); /* Notify the registered observers with the given message type, observe option, and payload. */ - REST.notify_subscribers(r->url, 1, periodic_i, (uint8_t *)content, snprintf(content, sizeof(content), "TICK %lu", periodic_i)); - /* |-> implementation-specific, e.g. CoAP: 0=CON and 1=NON notification */ - - return 1; + REST.notify_subscribers(r, obs_counter, notification); } #endif @@ -503,21 +506,23 @@ event_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred /* Additionally, a handler function named [resource name]_event_handler must be implemented for each PERIODIC_RESOURCE defined. * It will be called by the REST manager process with the defined period. */ -int +void event_event_handler(resource_t *r) { - static uint32_t event_i = 0; - static char content[10]; + static uint16_t event_counter = 0; + static char content[12]; - PRINTF("EVENT /%s\n", r->url); - ++event_i; + ++event_counter; - /* Notify registered observers with the given message type, observe option, and payload. - * The token will be set automatically. */ + PRINTF("TICK %u for /%s\n", event_counter, r->url); - // FIXME provide a rest_notify_subscribers call; how to manage specific options such as COAP_TYPE? - REST.notify_subscribers(r->url, 0, event_i, content, snprintf(content, sizeof(content), "EVENT %lu", event_i)); - return 1; + /* Build notification. */ + coap_packet_t notification[1]; /* This way the packet can be treated as pointer as usual. */ + coap_init_message(notification, COAP_TYPE_CON, CONTENT_2_05, 0 ); + coap_set_payload(notification, content, snprintf(content, sizeof(content), "EVENT %u", event_counter)); + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(r, event_counter, notification); } #endif /* PLATFORM_HAS_BUTTON */