From b4fb8c3f527fa1c3863b292dc303002f681ccad4 Mon Sep 17 00:00:00 2001 From: Ralf Schlatterbeck Date: Thu, 29 May 2014 17:06:43 +0200 Subject: [PATCH] Add wallclock time handling New application and new example. We use the built-in timer routines and add an offset to get the wallclock time. The offset can be set by time-changing routines (currently only settimeofday). We also maintain an offset for timezone handling but this isn't currently fully implemented. --- apps/time/Makefile.time | 1 + apps/time/resource_gmtime.c | 126 ++++++++ apps/time/resource_timestamp.c | 158 ++++++++++ apps/time/time.c | 165 ++++++++++ apps/time/time.h | 65 ++++ apps/time/time_resource.h | 27 ++ examples/osd/wallclock-time/Makefile | 99 ++++++ .../osd/wallclock-time/er-example-server.c | 297 ++++++++++++++++++ examples/osd/wallclock-time/flash.sh | 2 + examples/osd/wallclock-time/project-conf.h | 101 ++++++ examples/osd/wallclock-time/run.sh | 5 + 11 files changed, 1046 insertions(+) create mode 100644 apps/time/Makefile.time create mode 100644 apps/time/resource_gmtime.c create mode 100644 apps/time/resource_timestamp.c create mode 100644 apps/time/time.c create mode 100644 apps/time/time.h create mode 100644 apps/time/time_resource.h create mode 100644 examples/osd/wallclock-time/Makefile create mode 100644 examples/osd/wallclock-time/er-example-server.c create mode 100755 examples/osd/wallclock-time/flash.sh create mode 100644 examples/osd/wallclock-time/project-conf.h create mode 100755 examples/osd/wallclock-time/run.sh diff --git a/apps/time/Makefile.time b/apps/time/Makefile.time new file mode 100644 index 000000000..1440c805d --- /dev/null +++ b/apps/time/Makefile.time @@ -0,0 +1 @@ +time_src = time.c resource_gmtime.c resource_timestamp.c diff --git a/apps/time/resource_gmtime.c b/apps/time/resource_gmtime.c new file mode 100644 index 000000000..732abd7ac --- /dev/null +++ b/apps/time/resource_gmtime.c @@ -0,0 +1,126 @@ +/** + * \file + * Resource for gmtime (utc) / localtime handling + * \author + * Ralf Schlatterbeck + * + * \brief get time as a string in utc or localtime + */ + +#include +#include +#include +#include "contiki.h" +#include "time.h" +#include "time_resource.h" +#include "jsonparse.h" +/* Only coap 13 for now */ +#include "er-coap-13.h" + +RESOURCE \ + ( localtime + , METHOD_GET + , "clock/localtime" + , "title=\"Time\";rt=\"localtime\"" + ); + +RESOURCE \ + ( gmtime + , METHOD_GET + , "clock/utc" + , "title=\"Time\";rt=\"utc\"" + ); + +void +time_handler + ( void* request + , void* response + , uint8_t *buffer + , uint16_t preferred_size + , int32_t *offset + , struct tm *(*method)(const time_t *,struct tm *) + ) +{ + int success = 1; + + char temp[100]; + int index = 0; + int length = 0; /* |<-------->| */ + struct timeval tv; + struct tm tm; + int i = 0; + int n_acc = 0; + const uint16_t *accept = NULL; + uint16_t a_ctype = REST.type.APPLICATION_JSON; /* for now json is default */ + + /* Looks like accepted content-type isn't currently supported */ + n_acc = REST.get_header_accept (request, &accept); + for (i=0; i + * + * \brief get/put time in seconds since 1970 (UNIX time) + * Note: the internal format of the time in seconds is a 64bit number + * unfortunately javascript (json) will only support double for which + * the mantissa isn't long enough for representing that number. So we're + * back to 32 bit and have a year 2038 problem. + */ + +#include +#include +#include +#include "contiki.h" +#include "time.h" +#include "time_resource.h" +#include "jsonparse.h" +/* Only coap 13 for now */ +#include "er-coap-13.h" + +/* Error-handling macro */ +# define BYE(_exp, _tag) \ + do { \ + PRINTF("Expect "_exp": %d\n",_tag); \ + success=0; \ + goto bye; \ + } while(0) + +#define DEBUG 1 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +RESOURCE \ + ( timestamp, METHOD_GET | METHOD_PUT + , "clock/timestamp" + , "title=\"Time\";rt=\"timestamp\"" + ); + +void +timestamp_handler + ( void* request + , void* response + , uint8_t *buffer + , uint16_t preferred_size + , int32_t *offset + ) +{ + int success = 1; + + int i; + char temp[100]; + int index = 0; + int length = 0; + int tag = 0; + const uint8_t *bytes = NULL; + size_t len = 0; + struct timeval tv; + int n_acc = 0; + const uint16_t *accept = NULL; + uint16_t a_ctype = REST.type.APPLICATION_JSON; + uint16_t c_ctype = REST.get_header_content_type (request); + + /* Seems like accepted type is currently unsupported? */ + n_acc = REST.get_header_accept (request, &accept); + for (i=0; i +#include "contiki.h" +#include "contiki-lib.h" +#include "time.h" + +/* Used for gmtime and localtime, according to manpage on linux the + * internal value may be overwritten "by subsequent calls to any of the + * date and time functions". + */ +static struct tm tm; + +/* + * Internal variables to manage offset of utc from the contiki clock + * and timezone offset from utc in minutes. + * For now we don't manage the sub-second offset -- time of setting the + * clock and the precisiont of the clock in use don't warrant this + * effort. + * The last_seconds is used to check if we had a seconds overflow, + * although this happens only every 136 years :-) + */ +time_t clock_offset; +uint32_t last_seconds; +int16_t minuteswest; + +# define LEAP_YEAR(_year) \ + ((_year % 4) == 0 && (_year % 100 != 0 || _year % 400 == 0)) +# define YDAYS(_year) (LEAP_YEAR(year) ? 366 : 365) + +struct tm * +gmtime_r (const time_t *timep, struct tm *ptm) +{ + unsigned int year; + int days, month, month_len; + time_t t = *timep; + ptm->tm_sec = t % 60; + t /= 60; + ptm->tm_min = t % 60; + t /= 60; + ptm->tm_hour = t % 24; + t /= 24; + ptm->tm_wday = (t+4) % 7; + year = 70; + days = 0; + while ((days += YDAYS (year)) <= t) + { + year++; + } + ptm->tm_year = year; + days -= YDAYS(year); + t -= days; + ptm->tm_yday = t; + for (month=0; month<12; month++) + { + if (month == 1) + { + month_len = LEAP_YEAR(year) ? 29 : 28; + } + else + { + int m = month; + if (m >= 7) + { + m -= 1; + } + m &= 1; + month_len = m ? 30 : 31; + } + if (t >= month_len) + { + t -= month_len; + } + else + { + break; + } + } + ptm->tm_mon = month; + ptm->tm_mday = t + 1; + ptm->tm_isdst = 0; + return ptm; +} + +struct tm * +gmtime (const time_t *timep) +{ + return gmtime_r (timep, &tm); +} + +struct tm * +localtime_r (const time_t *timep, struct tm *ptm) +{ + time_t t = *timep; + t += minuteswest * 60; + return gmtime_r (&t, ptm); +} + +struct tm * +localtime (const time_t *timep) +{ + return localtime_r (timep, &tm); +} + +/** + * \brief Get time in seconds and microseconds + * gettimeofday will return the clock time as the microseconds part + * while settimeofday will *ignore* the microseconds part (for now). + * Note that the contiki clock interface is broken anyway, we can't read + * seconds and sub-seconds atomically. We try to work around this by + * repeatedly reading seconds, sub-seconds, seconds until first and + * second read of seconds match. + */ +int +gettimeofday (struct timeval *tv, struct timezone *tz) +{ + uint32_t cs; + if (tz) { + tz->tz_minuteswest = minuteswest; + tz->tz_dsttime = 0; + } + if (tv) { + int i; + /* Limit tries to get the same second twice to two */ + for (i=0; i<2; i++) { + cs = clock_seconds (); + if (cs < last_seconds) { + clock_offset += 0xFFFFFFFFL; + clock_offset ++; + } + last_seconds = cs; + tv->tv_sec = cs + clock_offset; + tv->tv_usec = ((time_t)(clock_time () % CLOCK_SECOND)) + * 1000000L / CLOCK_SECOND; + if (cs == clock_seconds ()) { + break; + } + } + } + return 0; +} + +/** + * \brief Set time in seconds, microseconds ignored for now + */ +int +settimeofday (const struct timeval *tv, const struct timezone *tz) +{ + /* Don't allow setting timezone */ + if (tz) { + errno = ERANGE; + return -1; + } + if (tv) { + uint32_t cs; + cs = clock_seconds (); + clock_offset = tv->tv_sec - cs; + } + return 0; +} + +/** @} */ diff --git a/apps/time/time.h b/apps/time/time.h new file mode 100644 index 000000000..2ff4a383c --- /dev/null +++ b/apps/time/time.h @@ -0,0 +1,65 @@ +/** + * \defgroup Time related functions + * + * This rolls the necessary definition for getting/setting time and + * managing local time into one include file, on posix systems this + * lives in at least two include files, time.h and sys/time.h + * + * @{ + */ + +/** + * \file + * Definitions for the time module + * + * \author + * Ralf Schlatterbeck + */ + +#ifndef time_h +#define time_h + + +typedef signed long long time_t; +typedef signed long suseconds_t; + +#ifdef __cplusplus +extern "C" { +#endif + +struct tm { + uint32_t tm_year; /* year */ + uint16_t tm_yday; /* day in the year */ + uint8_t tm_sec; /* seconds */ + uint8_t tm_min; /* minutes */ + uint8_t tm_hour; /* hours */ + uint8_t tm_mday; /* day of the month */ + uint8_t tm_mon; /* month */ + uint8_t tm_wday; /* day of the week */ + uint8_t tm_isdst; /* daylight saving time */ +}; + +struct timeval { + time_t tv_sec; /* seconds */ + suseconds_t tv_usec; /* microseconds */ +}; + +struct timezone { + int16_t tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of DST correction, unused */ +}; + +struct tm *gmtime (const time_t *timep); +struct tm *gmtime_r (const time_t *timep, struct tm *result); +struct tm *localtime (const time_t *timep); +struct tm *localtime_r (const time_t *timep, struct tm *result); + +int gettimeofday (struct timeval *tv, struct timezone *tz); +int settimeofday (const struct timeval *tv, const struct timezone *tz); + +#ifdef __cplusplus +} +#endif + +#endif // time_h +/** @} */ diff --git a/apps/time/time_resource.h b/apps/time/time_resource.h new file mode 100644 index 000000000..1334ce99b --- /dev/null +++ b/apps/time/time_resource.h @@ -0,0 +1,27 @@ +/** + * \addgroup Time related functions + * + * Resource definitions for time module + * + * @{ + */ + +/** + * \file + * Resource definitions for the time module + * + * \author + * Ralf Schlatterbeck + */ + +#ifndef time_resource_h +#define time_resource_h +#include "contiki.h" +#include "erbium.h" + +extern resource_t resource_timestamp; +extern resource_t resource_localtime; +extern resource_t resource_gmtime; + +#endif // time_resource_h +/** @} */ diff --git a/examples/osd/wallclock-time/Makefile b/examples/osd/wallclock-time/Makefile new file mode 100644 index 000000000..b54d8eaa9 --- /dev/null +++ b/examples/osd/wallclock-time/Makefile @@ -0,0 +1,99 @@ +all: er-example-server \ + er-example-server.osd-merkur.hex er-example-server.osd-merkur.eep +# use this target explicitly if requried: er-plugtest-server + +# variable for this Makefile +# configure CoAP implementation (3|7|12|13) (er-coap-07 also supports CoAP draft 08) +WITH_COAP=13 + +# for some platforms +UIP_CONF_IPV6=1 +# IPv6 make config disappeared completely +CFLAGS += -DUIP_CONF_IPV6=1 + +CONTIKI=../../.. +CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\" + +PROJECT_SOURCEFILES += + +# variable for Makefile.include +ifneq ($(TARGET), minimal-net) +CFLAGS += -DUIP_CONF_IPV6_RPL=1 +else +# minimal-net does not support RPL under Linux and is mostly used to test CoAP only +${info INFO: compiling without RPL} +CFLAGS += -DUIP_CONF_IPV6_RPL=0 +CFLAGS += -DHARD_CODED_ADDRESS=\"fdfd::10\" +${info INFO: compiling with large buffers} +CFLAGS += -DUIP_CONF_BUFFER_SIZE=2048 +CFLAGS += -DREST_MAX_CHUNK_SIZE=1024 +CFLAGS += -DCOAP_MAX_HEADER_SIZE=640 +endif + +# linker optimizations +SMALL=1 + +# REST framework, requires WITH_COAP +ifeq ($(WITH_COAP), 13) +${info INFO: compiling with CoAP-13} +CFLAGS += -DWITH_COAP=13 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-13 +else ifeq ($(WITH_COAP), 12) +${info INFO: compiling with CoAP-12} +CFLAGS += -DWITH_COAP=12 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-12 +else ifeq ($(WITH_COAP), 7) +${info INFO: compiling with CoAP-08} +CFLAGS += -DWITH_COAP=7 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-07 +else ifeq ($(WITH_COAP), 3) +${info INFO: compiling with CoAP-03} +CFLAGS += -DWITH_COAP=3 +CFLAGS += -DREST=coap_rest_implementation +CFLAGS += -DUIP_CONF_TCP=0 +APPS += er-coap-03 +else +${info INFO: compiling with HTTP} +CFLAGS += -DWITH_HTTP +CFLAGS += -DREST=http_rest_implementation +CFLAGS += -DUIP_CONF_TCP=1 +APPS += er-http-engine +endif + +APPS += erbium time json + +include $(CONTIKI)/Makefile.include + +er-example-server.osd-merkur.hex: er-example-server.osd-merkur + avr-objcopy -j .text -j .data -O ihex er-example-server.osd-merkur \ + er-example-server.osd-merkur.hex + +er-example-server.osd-merkur.eep: er-example-server.osd-merkur + avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 -O ihex \ + er-example-server.osd-merkur er-example-server.osd-merkur.eep + +flash: er-example-server.osd-merkur.hex er-example-server.osd-merkur.eep + avrdude -pm128rfa1 -c arduino -P/dev/ttyUSB0 -b57600 -e -U \ + flash:w:er-example-server.osd-merkur.hex:a -U \ + eeprom:w:er-example-server.osd-merkur.eep:a + +.PHONY: flash + +$(CONTIKI)/tools/tunslip6: $(CONTIKI)/tools/tunslip6.c + (cd $(CONTIKI)/tools && $(MAKE) tunslip6) + +connect-router: $(CONTIKI)/tools/tunslip6 + sudo $(CONTIKI)/tools/tunslip6 aaaa::1/64 + +connect-router-cooja: $(CONTIKI)/tools/tunslip6 + sudo $(CONTIKI)/tools/tunslip6 -a 127.0.0.1 aaaa::1/64 + +connect-minimal: + sudo ip address add fdfd::1/64 dev tap0 diff --git a/examples/osd/wallclock-time/er-example-server.c b/examples/osd/wallclock-time/er-example-server.c new file mode 100644 index 000000000..875483e59 --- /dev/null +++ b/examples/osd/wallclock-time/er-example-server.c @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2011, Matthias Kovatsch and other contributors. + * 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 + * Erbium (Er) Wallclock REST Engine example (with CoAP-specific code) + * \author + * Matthias Kovatsch + * Ralf Schlatterbeck + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" +#include "time.h" +#include "time_resource.h" +#include "jsonparse.h" + +/* Define which resources to include to meet memory constraints. */ +#define REST_RES_INFO 1 +#define REST_RES_LEDS 1 +#define REST_RES_TOGGLE 0 +#define REST_RES_BATTERY 1 + +#include "erbium.h" + +#if defined (PLATFORM_HAS_BUTTON) +#include "dev/button-sensor.h" +#endif +#if defined (PLATFORM_HAS_LEDS) +#include "dev/leds.h" +#endif +#if defined (PLATFORM_HAS_BATTERY) +#include "dev/battery-sensor.h" +#endif + + +/* For CoAP-specific example: not required for normal RESTful Web service. */ +#if WITH_COAP == 3 +#include "er-coap-03.h" +#elif WITH_COAP == 7 +#include "er-coap-07.h" +#elif WITH_COAP == 12 +#include "er-coap-12.h" +#elif WITH_COAP == 13 +#include "er-coap-13.h" +#else +#warning "Erbium example without CoAP-specifc functionality" +#endif /* CoAP-specific example */ + +#define DEBUG 1 +#if DEBUG +#define PRINTF(...) printf(__VA_ARGS__) +#define PRINT6ADDR(addr) PRINTF("[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]", ((uint8_t *)addr)[0], ((uint8_t *)addr)[1], ((uint8_t *)addr)[2], ((uint8_t *)addr)[3], ((uint8_t *)addr)[4], ((uint8_t *)addr)[5], ((uint8_t *)addr)[6], ((uint8_t *)addr)[7], ((uint8_t *)addr)[8], ((uint8_t *)addr)[9], ((uint8_t *)addr)[10], ((uint8_t *)addr)[11], ((uint8_t *)addr)[12], ((uint8_t *)addr)[13], ((uint8_t *)addr)[14], ((uint8_t *)addr)[15]) +#define PRINTLLADDR(lladdr) PRINTF("[%02x:%02x:%02x:%02x:%02x:%02x]",(lladdr)->addr[0], (lladdr)->addr[1], (lladdr)->addr[2], (lladdr)->addr[3],(lladdr)->addr[4], (lladdr)->addr[5]) +#else +#define PRINTF(...) +#define PRINT6ADDR(addr) +#define PRINTLLADDR(addr) +#endif + +/******************************************************************************/ + +#if REST_RES_INFO +/* + * Resources are defined by the RESOURCE macro. + * Signature: resource name, the RESTful methods it handles, and its URI path (omitting the leading slash). + */ +RESOURCE(info, METHOD_GET, "info", "title=\"Info\";rt=\"text\""); + +/* + * A handler function named [resource name]_handler must be implemented for each RESOURCE. + * A buffer for the response payload is provided through the buffer pointer. Simple resources can ignore + * preferred_size and offset, but must respect the REST_MAX_CHUNK_SIZE limit for the buffer. + * If a smaller block size is requested for CoAP, the REST framework automatically splits the data. + */ +void +info_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + char message[100]; + int index = 0; + int length = 0; /* |<-------->| */ + + /* Some data that has the length up to REST_MAX_CHUNK_SIZE. For more, see the chunk resource. */ + // jSON Format + index += sprintf(message + index,"{\n \"Version\" : \"V1.0pre1\",\n"); + index += sprintf(message + index," \"name\" : \"Wallclock-time\"\n"); + index += sprintf(message + index,"}\n"); + + length = strlen(message); + memcpy(buffer, message,length ); + + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + REST.set_response_payload(response, buffer, length); +} +#endif + +/******************************************************************************/ +#if defined (PLATFORM_HAS_LEDS) +/******************************************************************************/ +#if REST_RES_LEDS +/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ +RESOURCE(leds, METHOD_POST | METHOD_PUT , "actuators/leds", "title=\"LEDs: ?color=r|g|b, POST/PUT mode=on|off\";rt=\"Control\""); + +void +leds_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *color = NULL; + const char *mode = NULL; + uint8_t led = 0; + int success = 1; + + if ((len=REST.get_query_variable(request, "color", &color))) { + PRINTF("color %.*s\n", len, color); + + if (strncmp(color, "r", len)==0) { + led = LEDS_RED; + } else if(strncmp(color,"g", len)==0) { + led = LEDS_GREEN; + } else if (strncmp(color,"b", len)==0) { + led = LEDS_BLUE; + } else { + success = 0; + } + } else { + success = 0; + } + + if (success && (len=REST.get_post_variable(request, "mode", &mode))) { + PRINTF("mode %s\n", mode); + + if (strncmp(mode, "on", len)==0) { + leds_on(led); + } else if (strncmp(mode, "off", len)==0) { + leds_off(led); + } else { + success = 0; + } + } else { + success = 0; + } + + if (!success) { + REST.set_response_status(response, REST.status.BAD_REQUEST); + } +} +#endif + +/******************************************************************************/ +#if REST_RES_TOGGLE +/* A simple actuator example. Toggles the red led */ +RESOURCE(toggle, METHOD_GET | METHOD_PUT | METHOD_POST, "actuators/toggle", "title=\"Red LED\";rt=\"Control\""); +void +toggle_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + leds_toggle(LEDS_RED); +} +#endif +#endif /* PLATFORM_HAS_LEDS */ + +/******************************************************************************/ + +/******************************************************************************/ +/******************************************************************************/ +#if REST_RES_BATTERY && defined (PLATFORM_HAS_BATTERY) +/* A simple getter example. Returns the reading from light sensor with a simple etag */ +RESOURCE(battery, METHOD_GET, "sensors/battery", "title=\"Battery status\";rt=\"battery-mV\""); +void +battery_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int battery = battery_sensor.value(0); + + const uint16_t *accept = NULL; + int num = REST.get_header_accept(request, &accept); + + if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) + { + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "%d", battery); + + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } + else if (num && (accept[0]==REST.type.APPLICATION_JSON)) + { + REST.set_header_content_type(response, REST.type.APPLICATION_JSON); + snprintf((char *)buffer, REST_MAX_CHUNK_SIZE, "{'battery':%d}", battery); + + REST.set_response_payload(response, buffer, strlen((char *)buffer)); + } + else + { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain and application/json"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif /* PLATFORM_HAS_BATTERY */ +/******************************************************************************/ + +void +hw_init() +{ +#if defined (PLATFORM_HAS_LEDS) + leds_off(LEDS_RED); +#endif +} + +PROCESS(rest_server_example, "Erbium Example Server"); + +AUTOSTART_PROCESSES(&rest_server_example, &sensors_process); + +PROCESS_THREAD(rest_server_example, ev, data) +{ + PROCESS_BEGIN(); + PRINTF("Starting Erbium Example Server\n"); + +#ifdef RF_CHANNEL + PRINTF("RF channel: %u\n", RF_CHANNEL); +#endif +#ifdef IEEE802154_PANID + PRINTF("PAN ID: 0x%04X\n", IEEE802154_PANID); +#endif + + PRINTF("uIP buffer: %u\n", UIP_BUFSIZE); + PRINTF("LL header: %u\n", UIP_LLH_LEN); + PRINTF("IP+UDP header: %u\n", UIP_IPUDPH_LEN); + PRINTF("REST max chunk: %u\n", REST_MAX_CHUNK_SIZE); + +/* if static routes are used rather than RPL */ +#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE) + set_global_address(); + configure_routing(); +#endif + + /* Initialize the OSD Hardware. */ + hw_init(); + /* Initialize the REST engine. */ + rest_init_engine(); + + /* Activate the application-specific resources. */ +#if REST_RES_INFO + rest_activate_resource(&resource_info); +#endif +#if defined (PLATFORM_HAS_LEDS) +#if REST_RES_LEDS + rest_activate_resource(&resource_leds); +#endif +#if REST_RES_TOGGLE + rest_activate_resource(&resource_toggle); +#endif +#endif /* PLATFORM_HAS_LEDS */ +#if defined (PLATFORM_HAS_BATTERY) && REST_RES_BATTERY + SENSORS_ACTIVATE(battery_sensor); + rest_activate_resource(&resource_battery); +#endif + rest_activate_resource(&resource_timestamp); + rest_activate_resource(&resource_localtime); + rest_activate_resource(&resource_gmtime); + + /* Define application-specific events here. */ + while(1) { + PROCESS_WAIT_EVENT(); + } /* while (1) */ + + PROCESS_END(); +} diff --git a/examples/osd/wallclock-time/flash.sh b/examples/osd/wallclock-time/flash.sh new file mode 100755 index 000000000..e9cb40bfc --- /dev/null +++ b/examples/osd/wallclock-time/flash.sh @@ -0,0 +1,2 @@ +#!/bin/bash +make TARGET=osd-merkur flash diff --git a/examples/osd/wallclock-time/project-conf.h b/examples/osd/wallclock-time/project-conf.h new file mode 100644 index 000000000..574e15250 --- /dev/null +++ b/examples/osd/wallclock-time/project-conf.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2010, Swedish Institute of Computer Science. + * 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. + * + * + */ + +#ifndef PROJECT_RPL_WEB_CONF_H_ +#define PROJECT_RPL_WEB_CONF_H_ + +#define PLATFORM_HAS_LEDS 1 +//#define PLATFORM_HAS_BUTTON 1 +#define PLATFORM_HAS_BATTERY 1 + +#define SICSLOWPAN_CONF_FRAG 1 + +/* For Debug: Dont allow MCU sleeping between channel checks */ +#undef RDC_CONF_MCU_SLEEP +#define RDC_CONF_MCU_SLEEP 0 + +/* Disabling RDC for demo purposes. Core updates often require more memory. */ +/* For projects, optimize memory and enable RDC again. */ +// #undef NETSTACK_CONF_RDC +//#define NETSTACK_CONF_RDC nullrdc_driver + +/* Increase rpl-border-router IP-buffer when using more than 64. */ +#undef REST_MAX_CHUNK_SIZE +#define REST_MAX_CHUNK_SIZE 64 + +/* Estimate your header size, especially when using Proxy-Uri. */ +/* +#undef COAP_MAX_HEADER_SIZE +#define COAP_MAX_HEADER_SIZE 70 +*/ + +/* The IP buffer size must fit all other hops, in particular the border router. */ + +#undef UIP_CONF_BUFFER_SIZE +#define UIP_CONF_BUFFER_SIZE 256 + + +/* Multiplies with chunk size, be aware of memory constraints. */ +#undef COAP_MAX_OPEN_TRANSACTIONS +#define COAP_MAX_OPEN_TRANSACTIONS 4 + +/* Must be <= open transaction number, default is COAP_MAX_OPEN_TRANSACTIONS-1. */ +/* +#undef COAP_MAX_OBSERVERS +#define COAP_MAX_OBSERVERS 2 +*/ + +/* Filtering .well-known/core per query can be disabled to save space. */ +/* +#undef COAP_LINK_FORMAT_FILTERING +#define COAP_LINK_FORMAT_FILTERING 0 +*/ + +/* Save some memory for the sky platform. */ +/* +#undef NBR_TABLE_CONF_MAX_NEIGHBORS +#define NBR_TABLE_CONF_MAX_NEIGHBORS 10 +#undef UIP_CONF_MAX_ROUTES +#define UIP_CONF_MAX_ROUTES 10 +*/ + +/* Reduce 802.15.4 frame queue to save RAM. */ +/* +#undef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 4 +*/ + +/* +#undef SICSLOWPAN_CONF_FRAG +#define SICSLOWPAN_CONF_FRAG 1 +*/ + +#endif /* PROJECT_RPL_WEB_CONF_H_ */ diff --git a/examples/osd/wallclock-time/run.sh b/examples/osd/wallclock-time/run.sh new file mode 100755 index 000000000..295a9ab1d --- /dev/null +++ b/examples/osd/wallclock-time/run.sh @@ -0,0 +1,5 @@ +#!/bin/bash +# For the new bootloader (using a jump-table) you want to use +# BOOTLOADER_GET_MAC=0x0001ff80 (which is the current default) +make clean TARGET=osd-merkur +make TARGET=osd-merkur BOOTLOADER_GET_MAC=0x0001f3a0