diff --git a/examples/osd/embedd-vm-merkurboard/Makefile b/examples/osd/embedd-vm-merkurboard/Makefile new file mode 100644 index 000000000..11973023b --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/Makefile @@ -0,0 +1,98 @@ +all: embedd-vm-server +# 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 + + +# variable for Makefile.include +WITH_UIP6=1 +# 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 += embedvm.c + +# 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 + +# optional rules to get assembly +#CUSTOM_RULE_C_TO_OBJECTDIR_O = 1 +#CUSTOM_RULE_S_TO_OBJECTDIR_O = 1 + +include $(CONTIKI)/Makefile.include + +# optional rules to get assembly +#$(OBJECTDIR)/%.o: asmdir/%.S +# $(CC) $(CFLAGS) -MMD -c $< -o $@ +# @$(FINALIZE_DEPENDENCY) +# +#asmdir/%.S: %.c +# $(CC) $(CFLAGS) -MMD -S $< -o $@ + +# border router rules +$(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/embedd-vm-merkurboard/README b/examples/osd/embedd-vm-merkurboard/README new file mode 100644 index 000000000..59c1a7f57 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/README @@ -0,0 +1,31 @@ +A Quick Introduction to the embedd-vm virtual machine +===================================================== +Compile the Example +------------------- +./run.sh + +OSD-Merkur Board +---------------------- +write the images to the OSD-Merkur Board: + +./flash.sh + +EXAMPLE FILES +------------- + +PRELIMINARIES +------------- + +COOJA HOWTO +----------- +Server only: + +DETAILS +------- + +REST IMPLEMENTATIONS +-------------------- + +TODOs +----- + diff --git a/examples/osd/embedd-vm-merkurboard/embedd-vm-server.c b/examples/osd/embedd-vm-merkurboard/embedd-vm-server.c new file mode 100644 index 000000000..146d75eab --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/embedd-vm-server.c @@ -0,0 +1,529 @@ +/* + * 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) REST Engine example (with CoAP-specific code) + * \author + * Matthias Kovatsch + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" + + +/* Define which resources to include to meet memory constraints. */ +#define REST_RES_INFO 1 +#define REST_RES_EVM 1 +#define REST_RES_CHUNKS 0 +#define REST_RES_BATTERY 1 +#define REST_RES_LEDS 1 +#define REST_RES_TOGGLE 1 + +#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE) +#warning "Compiling with static routing!" +#include "static-routing.h" +#endif + +#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 + +// embedd-vm +#include "embedvm.h" + +/* 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\" : \"V0.1\",\n"); + index += sprintf(message + index," \"name\" : \"embedd-vm demo\"\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 REST_RES_CHUNKS +/* + * For data larger than REST_MAX_CHUNK_SIZE (e.g., stored in flash) resources must be aware of the buffer limitation + * and split their responses by themselves. To transfer the complete resource through a TCP stream or CoAP's blockwise transfer, + * the byte offset where to continue is provided to the handler as int32_t pointer. + * These chunk-wise resources must set the offset value to its new position or -1 of the end is reached. + * (The offset for CoAP's blockwise transfer can go up to 2'147'481'600 = ~2047 M for block size 2048 (reduced to 1024 in observe-03.) + */ +RESOURCE(chunks, METHOD_GET, "test/chunks", "title=\"Blockwise demo\";rt=\"Data\""); + +#define CHUNKS_TOTAL 2050 + +void +chunks_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + + /* Check the offset for boundaries of the resource data. */ + if (*offset>=CHUNKS_TOTAL) + { + 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, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while (strpos preferred_size) + { + strpos = preferred_size; + } + + /* Truncate if above CHUNKS_TOTAL bytes. */ + if (*offset+(int32_t)strpos > CHUNKS_TOTAL) + { + strpos = CHUNKS_TOTAL - *offset; + } + + REST.set_response_payload(response, buffer, strpos); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if (*offset>=CHUNKS_TOTAL) + { + *offset = -1; + } +} +#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\""); +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 */ + +#include "vmcode.hdr" +#define UNUSED __attribute__((unused)) + +uint8_t vm_mem[256] = { EMBEDVM_SECT_SRAM_DATA }; +struct embedvm_s vm = { }; +// Global Variable coap answear + char gmessage[100]; + int gindex = 0; +/******************************************************************************/ +#if defined (PLATFORM_HAS_EVM) +/******************************************************************************/ +#if REST_RES_EVM +/*A simple actuator example, depending on the color query parameter and post variable mode, corresponding led is activated or deactivated*/ +RESOURCE(evm, METHOD_GET | METHOD_POST | METHOD_PUT , "evm", "title=\"Embedd-VM, POST/PUT player=0/9999\";rt=\"Embedd-VM\""); + +void +evm_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + size_t len = 0; + const char *player = NULL; + int success = 1; + //int length = 0; /* |<-------->| */ + int16_t val = 0; + uint16_t old_ip=0; + const uint16_t *accept = NULL; + + switch(REST.get_method_type(request)){ + case METHOD_GET: + gindex=0; + gindex += sprintf(gmessage + gindex,"Number-Quiz!\nI think at a Number between 0 and 9999 :-)\n"); + break; + case METHOD_PUT: + if ((len=REST.get_post_variable(request, "player", &player))) { + PRINTF("player %.*s\n", len, player); + gindex=0; + val = atoi(player); + embedvm_push(&vm, 1); + embedvm_push(&vm, val); + old_ip=vm.ip; + embedvm_interrupt(&vm, EMBEDVM_SYM_play); + while (vm.ip != old_ip) { + // printf("<%X>",vm.ip); + embedvm_exec(&vm); + } + embedvm_pop(&vm); + embedvm_pop(&vm); + + } else { + success = 0; + } + break; + default: + success = 0; + } + int num = REST.get_header_accept(request, &accept); + if ((num==0) || (num && accept[0]==REST.type.TEXT_PLAIN)) + { + if(success){ + //length = strlen(gmessage); + memcpy(buffer, gmessage,gindex ); + buffer[gindex]=0; + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, (uint8_t *)buffer, strlen((char *)buffer)); + } else { + REST.set_response_status(response, REST.status.BAD_REQUEST); + } + } + else + { + REST.set_response_status(response, REST.status.NOT_ACCEPTABLE); + const char *msg = "Supporting content-types text/plain"; + REST.set_response_payload(response, msg, strlen(msg)); + } +} +#endif +#endif + + +int16_t mem_read(uint16_t addr, bool is16bit, void *ctx) +{ + if (addr + (is16bit ? 1 : 0) >= sizeof(vm_mem)) + return 0; + if (is16bit) + return (vm_mem[addr] << 8) | vm_mem[addr+1]; + return vm_mem[addr]; +} + +void mem_write(uint16_t addr, int16_t value, bool is16bit, void *ctx) +{ + if (addr + (is16bit ? 1 : 0) >= sizeof(vm_mem)) + return; + if (is16bit) { + vm_mem[addr] = value >> 8; + vm_mem[addr+1] = value; + } else + vm_mem[addr] = value; +} + +extern uint8_t rng_get_uint8(void); +int16_t call_user(uint8_t funcid, uint8_t argc, int16_t *argv, void *ctx) +{ + if (funcid == 0) + return (random()%99)+1; + + if (funcid == 1 && argc >= 1) { + if (argv[0] > 0){ + gindex += sprintf(gmessage + gindex,"Try larger numbers.\n"); + PRINTF("Try larger numbers.\n"); + }else{ + gindex += sprintf(gmessage + gindex,"Try smaler numbers.\n"); + PRINTF("Try smaller numbers.\n"); + } + return 0; + } + if (funcid == 2) { + gindex += sprintf(gmessage + gindex,"This is correct!\n"); + PRINTF("This is correct!\n"); + return 0; + } + if (funcid == 3) { + gindex += sprintf(gmessage + gindex,"\nYou currently have %d points.\n", mem_read(EMBEDVM_SYM_points, true, ctx)); + PRINTF("\n"); + PRINTF("You currently have %d points.\n", mem_read(EMBEDVM_SYM_points, true, ctx)); + return 0; + } + if (funcid == 4) { + PRINTF("\n"); + PRINTF("D: %d\n", mem_read(EMBEDVM_SYM_dbg, true, ctx)); + return 0; + } + if (funcid == 10) { + PRINTF("D: LED-RED off\n"); + leds_off(LEDS_RED); + return 0; + } + if (funcid == 11) { + PRINTF("D: LED-RED on\n"); + leds_on(LEDS_RED); + return 0; + } + if (funcid == 12) { + PRINTF("D: LED-RED Toggle\n"); + leds_toggle(LEDS_RED); + return 0; + } + return 1; +} + +void vm_setup() +{ + PRINTF("Initializing embedded-vm...\n"); + + vm.ip = EMBEDVM_SYM_main; + vm.sp = vm.sfp = sizeof(vm_mem); + vm.mem_read = &mem_read; + vm.mem_write = &mem_write; + vm.call_user = &call_user; + + embedvm_push(&vm, 0); + while (vm.ip > 0) { + // printf("<%X>",vm.ip); + embedvm_exec(&vm); + } +} + +void +hw_init() +{ +#if defined (PLATFORM_HAS_LEDS) + leds_off(LEDS_RED); +#endif + vm_setup(); +} + +PROCESS(rest_server_example, "Erbium Example Server"); +AUTOSTART_PROCESSES(&rest_server_example); + +PROCESS_THREAD(rest_server_example, ev, data) +{ + PROCESS_BEGIN(); + + PRINTF("Starting Embedd-VM 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 REST_RES_CHUNKS + rest_activate_resource(&resource_chunks); +#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 REST_RES_EVM + rest_activate_resource(&resource_evm); +#endif +#if defined (PLATFORM_HAS_BATTERY) && REST_RES_BATTERY + SENSORS_ACTIVATE(battery_sensor); + rest_activate_resource(&resource_battery); +#endif + + while(1) { + PROCESS_WAIT_EVENT(); + + } /* while (1) */ + PROCESS_END(); +} diff --git a/examples/osd/embedd-vm-merkurboard/embedd-vm-server.osd-merkur b/examples/osd/embedd-vm-merkurboard/embedd-vm-server.osd-merkur new file mode 100755 index 000000000..c4bbbeb36 Binary files /dev/null and b/examples/osd/embedd-vm-merkurboard/embedd-vm-server.osd-merkur differ diff --git a/examples/osd/embedd-vm-merkurboard/embedd-vm-server.osd-merkur.eep b/examples/osd/embedd-vm-merkurboard/embedd-vm-server.osd-merkur.eep new file mode 100644 index 000000000..1996e8fde --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/embedd-vm-server.osd-merkur.eep @@ -0,0 +1 @@ +:00000001FF diff --git a/examples/osd/embedd-vm-merkurboard/embedvm.c b/examples/osd/embedd-vm-merkurboard/embedvm.c new file mode 100644 index 000000000..88ec457e0 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/embedvm.c @@ -0,0 +1,311 @@ +/* + * EmbedVM - Embedded Virtual Machine for uC Applications + * + * Copyright (C) 2011 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "embedvm.h" + +static inline int16_t signext(uint16_t val, uint16_t mask) +{ + val = val & mask; + if ((val & ~(mask >> 1)) != 0) + val |= ~mask; + return val; +} + +extern void embedvm_exec(struct embedvm_s *vm) +{ + uint8_t opcode = vm->mem_read(vm->ip, false, vm->user_ctx); + uint16_t addr = 0; + int16_t a = 0, b = 0; + int8_t sfa = 0; + + switch (opcode) + { + case 0x00 ... 0x3f: + sfa = signext(opcode, 0x3f); + embedvm_push(vm, embedvm_local_read(vm, sfa)); + vm->ip++; + break; + case 0x40 ... 0x7f: + sfa = signext(opcode, 0x3f); + embedvm_local_write(vm, sfa, embedvm_pop(vm)); + vm->ip++; + break; + case 0x80+0 ... 0x80+11: + case 0xa8+0 ... 0xa8+5: + b = embedvm_pop(vm); + case 0x80+12 ... 0x80+14: + a = embedvm_pop(vm); + switch (opcode) + { + case 0x80 + 0: embedvm_push(vm, a + b); break; + case 0x80 + 1: embedvm_push(vm, a - b); break; + case 0x80 + 2: embedvm_push(vm, a * b); break; + case 0x80 + 3: embedvm_push(vm, a / b); break; + case 0x80 + 4: embedvm_push(vm, a % b); break; + case 0x80 + 5: embedvm_push(vm, a << b); break; + case 0x80 + 6: embedvm_push(vm, a >> b); break; + case 0x80 + 7: embedvm_push(vm, a & b); break; + case 0x80 + 8: embedvm_push(vm, a | b); break; + case 0x80 + 9: embedvm_push(vm, a ^ b); break; + case 0x80 + 10: embedvm_push(vm, a && b); break; + case 0x80 + 11: embedvm_push(vm, a || b); break; + case 0x80 + 12: embedvm_push(vm, ~a); break; + case 0x80 + 13: embedvm_push(vm, -a); break; + case 0x80 + 14: embedvm_push(vm, !a); break; + case 0xa8 + 0: embedvm_push(vm, a < b); break; + case 0xa8 + 1: embedvm_push(vm, a <= b); break; + case 0xa8 + 2: embedvm_push(vm, a == b); break; + case 0xa8 + 3: embedvm_push(vm, a != b); break; + case 0xa8 + 4: embedvm_push(vm, a >= b); break; + case 0xa8 + 5: embedvm_push(vm, a > b); break; + + } + vm->ip++; + break; + case 0x90 ... 0x97: + a = signext(opcode, 0x07); + if ((a & 0x04) != 0) + a |= ~0x07; + embedvm_push(vm, a); + vm->ip++; + break; + case 0x98: + a = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff; + embedvm_push(vm, a); + vm->ip += 2; + break; + case 0x99: + a = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff; + embedvm_push(vm, signext(a, 0x00ff)); + vm->ip += 2; + break; + case 0x9a: + a = vm->mem_read(vm->ip+1, true, vm->user_ctx); + embedvm_push(vm, a); + vm->ip += 3; + break; + case 0x9b: + a = embedvm_pop(vm); + if (0) { + case 0x9c: + a = 0; + } + vm->sp = vm->sfp; + vm->ip = embedvm_pop(vm); + vm->sfp = embedvm_pop(vm); + if ((vm->sfp & 1) != 0) + vm->sfp &= ~1; + else + embedvm_push(vm, a); + break; + case 0x9d: + embedvm_pop(vm); + vm->ip++; + break; + case 0x9e: + addr = embedvm_pop(vm); + if (vm->mem_read(vm->ip+1, false, vm->user_ctx) == 0x9d) { + embedvm_push(vm, vm->sfp | 1); + embedvm_push(vm, vm->ip + 2); + } else { + embedvm_push(vm, vm->sfp); + embedvm_push(vm, vm->ip + 1); + } + vm->sfp = vm->sp; + vm->ip = addr; + break; + case 0x9f: + vm->ip = embedvm_pop(vm); + break; + case 0xa0 ... 0xa0+7: + if ((opcode & 1) == 0) { + addr = vm->ip + signext(vm->mem_read(vm->ip+1, false, vm->user_ctx), 0x00ff); + vm->ip += 2; + } else { + addr = vm->ip + vm->mem_read(vm->ip+1, true, vm->user_ctx); + vm->ip += 3; + } + switch (opcode) + { + case 0xa0: + case 0xa1: + vm->ip = addr; + break; + case 0xa2: + case 0xa3: + if (vm->mem_read(vm->ip, false, vm->user_ctx) == 0x9d) { + embedvm_push(vm, vm->sfp | 1); + embedvm_push(vm, vm->ip + 1); + } else { + embedvm_push(vm, vm->sfp); + embedvm_push(vm, vm->ip); + } + vm->sfp = vm->sp; + vm->ip = addr; + break; + case 0xa4: + case 0xa5: + if (embedvm_pop(vm)) + vm->ip = addr; + break; + case 0xa6: + case 0xa7: + if (!embedvm_pop(vm)) + vm->ip = addr; + break; + } + break; + case 0xae: + embedvm_push(vm, vm->sp); + vm->ip++; + break; + case 0xaf: + embedvm_push(vm, vm->sfp); + vm->ip++; + break; + case 0xb0 ... 0xb0+15: + { + uint8_t argc = embedvm_pop(vm); + int16_t argv[argc]; + for (sfa=0; sfacall_user(opcode - 0xb0, argc, argv, vm->user_ctx); + embedvm_push(vm, a); + } + vm->ip++; + break; + case 0xc0 ... 0xef: + if ((opcode & 0x07) == 5) { + /* this is a "bury" instruction */ + uint8_t depth = (opcode >> 3) & 0x07; + int16_t stack[depth+1]; + for (sfa = 0; sfa <= depth; sfa++) + stack[sfa] = embedvm_pop(vm); + embedvm_push(vm, stack[0]); + for (sfa = depth; sfa > 0; sfa--) + embedvm_push(vm, stack[sfa]); + embedvm_push(vm, stack[0]); + vm->ip++; + break; + } + if ((opcode & 0x07) == 6) { + /* this is a "dig" instruction */ + uint8_t depth = (opcode >> 3) & 0x07; + int16_t stack[depth+2]; + for (sfa = 0; sfa < depth+2; sfa++) + stack[sfa] = embedvm_pop(vm); + for (sfa = depth+1; sfa > 0; sfa--) + embedvm_push(vm, stack[sfa-1]); + embedvm_push(vm, stack[depth+1]); + vm->ip++; + break; + } + sfa = ((opcode >> 3) & 0x07) == 4 || ((opcode >> 3) & 0x07) == 5 ? 1 : 0; + switch (opcode & 0x07) + { + case 0: + addr = vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff; + vm->ip += 2; + break; + case 1: + addr = vm->mem_read(vm->ip+1, true, vm->user_ctx); + vm->ip += 3; + break; + case 2: + addr = embedvm_pop(vm); + vm->ip++; + break; + case 3: + addr = (embedvm_pop(vm) << sfa) + (vm->mem_read(vm->ip+1, false, vm->user_ctx) & 0x00ff); + vm->ip += 2; + break; + case 4: + addr = (embedvm_pop(vm) << sfa) + vm->mem_read(vm->ip+1, true, vm->user_ctx); + vm->ip += 3; + break; + } + switch ((opcode >> 3) & 0x07) + { + case 0: + embedvm_push(vm, vm->mem_read(addr, false, vm->user_ctx) & 0x00ff); + break; + case 1: + vm->mem_write(addr, embedvm_pop(vm), false, vm->user_ctx); + break; + case 2: + embedvm_push(vm, signext(vm->mem_read(addr, false, vm->user_ctx), 0x00ff)); + break; + case 3: + vm->mem_write(addr, embedvm_pop(vm), false, vm->user_ctx); + break; + case 4: + embedvm_push(vm, vm->mem_read(addr, true, vm->user_ctx)); + break; + case 5: + vm->mem_write(addr, embedvm_pop(vm), true, vm->user_ctx); + break; + } + break; + case 0xf0 ... 0xf7: + for (sfa = 0; sfa <= (opcode & 0x07); sfa++) + embedvm_push(vm, 0); + vm->ip++; + break; + case 0xf8 ... 0xff: + a = embedvm_pop(vm); + vm->sp += 2 + 2*(opcode & 0x07); + embedvm_push(vm, a); + vm->ip++; + break; + } +} + +void embedvm_interrupt(struct embedvm_s *vm, uint16_t addr) +{ + embedvm_push(vm, vm->sfp | 1); + embedvm_push(vm, vm->ip); + vm->sfp = vm->sp; + vm->ip = addr; +} + +int16_t embedvm_pop(struct embedvm_s *vm) +{ + int16_t value = vm->mem_read(vm->sp, true, vm->user_ctx); + vm->sp += 2; + return value; +} + +void embedvm_push(struct embedvm_s *vm, int16_t value) +{ + vm->sp -= 2; + vm->mem_write(vm->sp, value, true, vm->user_ctx); +} + +int16_t embedvm_local_read(struct embedvm_s *vm, int8_t sfa) +{ + uint16_t addr = vm->sfp - 2*sfa + (sfa < 0 ? +2 : -2); + return vm->mem_read(addr, true, vm->user_ctx); +} + +void embedvm_local_write(struct embedvm_s *vm, int8_t sfa, int16_t value) +{ + uint16_t addr = vm->sfp - 2*sfa + (sfa < 0 ? +2 : -2); + vm->mem_write(addr, value, true, vm->user_ctx); +} + diff --git a/examples/osd/embedd-vm-merkurboard/embedvm.h b/examples/osd/embedd-vm-merkurboard/embedvm.h new file mode 100644 index 000000000..1381b24a8 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/embedvm.h @@ -0,0 +1,53 @@ +/* + * EmbedVM - Embedded Virtual Machine for uC Applications + * + * Copyright (C) 2011 Clifford Wolf + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#ifndef EMBEDVM_H +#define EMBEDVM_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct embedvm_s +{ + uint16_t ip, sp, sfp; + void *user_ctx; + + int16_t (*mem_read)(uint16_t addr, bool is16bit, void *ctx); + void (*mem_write)(uint16_t addr, int16_t value, bool is16bit, void *ctx); + int16_t (*call_user)(uint8_t funcid, uint8_t argc, int16_t *argv, void *ctx); +}; + +extern void embedvm_exec(struct embedvm_s *vm); +extern void embedvm_interrupt(struct embedvm_s *vm, uint16_t addr); + +int16_t embedvm_pop(struct embedvm_s *vm); +void embedvm_push(struct embedvm_s *vm, int16_t value); + +int16_t embedvm_local_read(struct embedvm_s *vm, int8_t sfa); +void embedvm_local_write(struct embedvm_s *vm, int8_t sfa, int16_t value); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/osd/embedd-vm-merkurboard/er-plugtest-server.c b/examples/osd/embedd-vm-merkurboard/er-plugtest-server.c new file mode 100644 index 000000000..051b44be0 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/er-plugtest-server.c @@ -0,0 +1,561 @@ +/* + * 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 + * Server for the ETSI IoT CoAP Plugtests, Paris, France, 24 - 25 March 2012 + * \author + * Matthias Kovatsch + */ + +#include +#include +#include +#include "contiki.h" +#include "contiki-net.h" + +#define MAX_PLUGFEST_PAYLOAD 64+1 /* +1 for the terminating zero, which is not transmitted */ + +/* Define which resources to include to meet memory constraints. */ +#define REST_RES_TEST 1 +#define REST_RES_LONG 1 +#define REST_RES_QUERY 1 +#define REST_RES_SEPARATE 1 +#define REST_RES_LARGE 1 +#define REST_RES_LARGE_UPDATE 1 +#define REST_RES_LARGE_CREATE 1 +#define REST_RES_OBS 1 + + +#if !defined (CONTIKI_TARGET_MINIMAL_NET) +#warning "Should only be compiled for minimal-net!" +#endif + + +#if !UIP_CONF_IPV6_RPL && !defined (CONTIKI_TARGET_MINIMAL_NET) && !defined (CONTIKI_TARGET_NATIVE) +#warning "Compiling with static routing!" +#include "static-routing.h" +#endif + +#include "erbium.h" + +/* For CoAP-specific example: not required for normal RESTful Web service. */ +#if WITH_COAP==7 +#include "er-coap-07.h" +#else +#error "Plugtests server without CoAP" +#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_TEST +/* + * Default test resource + */ +RESOURCE(test, METHOD_GET|METHOD_POST|METHOD_PUT|METHOD_DELETE, "test", "title=\"Default test resource\""); + +void +test_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); + + PRINTF("/test "); + if (method & METHOD_GET) + { + PRINTF("GET "); + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); + } + else if (method & METHOD_POST) + { + PRINTF("POST "); + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/nirvana"); + } + else if (method & METHOD_PUT) + { + PRINTF("PUT "); + REST.set_response_status(response, REST.status.CHANGED); + } + else if (method & METHOD_DELETE) + { + PRINTF("DELETE "); + REST.set_response_status(response, REST.status.DELETED); + } + + PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); +} +#endif + +#if REST_RES_LONG +/* + * Long path resource + */ +RESOURCE(longpath, METHOD_GET, "seg1/seg2/seg3", "title=\"Long path resource\""); + +void +longpath_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); + + PRINTF("/seg1/seg2/seg3 "); + if (method & METHOD_GET) + { + PRINTF("GET "); + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid)); + } + PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); +} +#endif + +#if REST_RES_QUERY +/* + * Resource accepting query parameters + */ +RESOURCE(query, METHOD_GET, "query", "title=\"Resource accepting query parameters\""); + +void +query_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; + int len = 0; + const char *query = NULL; + + PRINTF("/query GET (%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); + + if ((len = REST.get_query(request, &query))) + { + PRINTF("Query: %.*s\n", len, query); + } + + /* Code 2.05 CONTENT is default. */ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u\nQuery: %.*s", coap_req->type, coap_req->code, coap_req->mid, len, query)); +} +#endif + +#if REST_RES_SEPARATE +/* Required to manually (=not by the engine) handle the response transaction. */ +#include "er-coap-07-separate.h" +#include "er-coap-07-transactions.h" +/* + * Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way + */ +PERIODIC_RESOURCE(separate, METHOD_GET, "separate", "title=\"Resource which cannot be served immediately and which cannot be acknowledged in a piggy-backed way\"", 3*CLOCK_SECOND); + +/* A structure to store the required information */ +typedef struct application_separate_store { + /* Provided by Erbium to store generic request information such as remote address and token. */ + coap_separate_t request_metadata; + /* Add fields for addition information to be stored for finalizing, e.g.: */ + char buffer[MAX_PLUGFEST_PAYLOAD]; +} application_separate_store_t; + +static uint8_t separate_active = 0; +static application_separate_store_t separate_store[1]; + +void +separate_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; + + PRINTF("/separate "); + if (separate_active) + { + PRINTF("REJECTED "); + coap_separate_reject(); + } + else + { + PRINTF("STORED "); + separate_active = 1; + + /* Take over and skip response by engine. */ + coap_separate_accept(request, &separate_store->request_metadata); + /* Be aware to respect the Block2 option, which is also stored in the coap_separate_t. */ + + snprintf(separate_store->buffer, MAX_PLUGFEST_PAYLOAD, "Type: %u\nCode: %u\nMID: %u", coap_req->type, coap_req->code, coap_req->mid); + } + + PRINTF("(%s %u)\n", coap_req->type==COAP_TYPE_CON?"CON":"NON", coap_req->mid); +} + +void +separate_periodic_handler(resource_t *resource) +{ + if (separate_active) + { + PRINTF("/separate "); + coap_transaction_t *transaction = NULL; + if ( (transaction = coap_new_transaction(separate_store->request_metadata.mid, &separate_store->request_metadata.addr, separate_store->request_metadata.port)) ) + { + PRINTF("RESPONSE (%s %u)\n", separate_store->request_metadata.type==COAP_TYPE_CON?"CON":"NON", separate_store->request_metadata.mid); + + coap_packet_t response[1]; /* This way the packet can be treated as pointer as usual. */ + + /* Restore the request information for the response. */ + coap_separate_resume(response, &separate_store->request_metadata, CONTENT_2_05); + + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + coap_set_payload(response, separate_store->buffer, strlen(separate_store->buffer)); + + /* + * Be aware to respect the Block2 option, which is also stored in the coap_separate_t. + * As it is a critical option, this example resource pretends to handle it for compliance. + */ + coap_set_header_block2(response, separate_store->request_metadata.block2_num, 0, separate_store->request_metadata.block2_size); + + /* 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 { + PRINTF("ERROR (transaction)\n"); + } + } /* if (separate_active) */ +} +#endif + +#if REST_RES_LARGE +/* + * Large resource + */ +RESOURCE(large, METHOD_GET, "large", "title=\"Large resource\";rt=\"block\""); + +#define CHUNKS_TOTAL 1280 + +void +large_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + int32_t strpos = 0; + + /* Check the offset for boundaries of the resource data. */ + if (*offset>=CHUNKS_TOTAL) + { + 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, error_msg, strlen(error_msg)); + return; + } + + /* Generate data until reaching CHUNKS_TOTAL. */ + while (strpos preferred_size) + { + strpos = preferred_size; + } + + /* Truncate if above CHUNKS_TOTAL bytes. */ + if (*offset+(int32_t)strpos > CHUNKS_TOTAL) + { + strpos = CHUNKS_TOTAL - *offset; + } + + REST.set_response_payload(response, buffer, strpos); + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += strpos; + + /* Signal end of resource representation. */ + if (*offset>=CHUNKS_TOTAL) + { + *offset = -1; + } +} +#endif + +#if REST_RES_LARGE_UPDATE +/* + * Large resource that can be updated using PUT method + */ +RESOURCE(large_update, METHOD_GET|METHOD_PUT, "large-update", "title=\"Large resource that can be updated using PUT method\";rt=\"block\""); + +static int32_t large_update_size = 1280; +static uint8_t large_update_store[2048] = {0}; +static unsigned int large_update_ct = -1; + +void +large_update_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); + + if (method & METHOD_GET) + { + /* Check the offset for boundaries of the resource data. */ + if (*offset>=large_update_size) + { + 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, error_msg, strlen(error_msg)); + return; + } + + REST.set_response_payload(response, large_update_store+*offset, preferred_size); + REST.set_header_content_type(response, large_update_ct); + + /* IMPORTANT for chunk-wise resources: Signal chunk awareness to REST engine. */ + *offset += preferred_size; + + /* Signal end of resource representation. */ + if (*offset>=large_update_size) + { + *offset = -1; + } + } else { + uint8_t *incoming = NULL; + size_t len = 0; + + unsigned int ct = REST.get_header_content_type(request); + if (ct==-1) + { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoContentType"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + if ((len = REST.get_request_payload(request, &incoming))) + { + if (coap_req->block1_num*coap_req->block1_size+len <= sizeof(large_update_store)) + { + memcpy(large_update_store+coap_req->block1_num*coap_req->block1_size, incoming, len); + large_update_size = coap_req->block1_num*coap_req->block1_size+len; + large_update_ct = REST.get_header_content_type(request); + + REST.set_response_status(response, REST.status.CHANGED); + coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); + } + else + { + REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); + REST.set_response_payload(response, buffer, snprintf((char *)buffer, MAX_PLUGFEST_PAYLOAD, "%uB max.", sizeof(large_update_store))); + return; + } + } + else + { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoPayload"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + } +} +#endif + +#if REST_RES_LARGE_CREATE +/* + * Large resource that can be created using POST method + */ +RESOURCE(large_create, METHOD_POST, "large-create", "title=\"Large resource that can be created using POST method\";rt=\"block\""); + +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 *incoming = NULL; + size_t len = 0; + + unsigned int ct = REST.get_header_content_type(request); + if (ct==-1) + { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoContentType"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + + if ((len = REST.get_request_payload(request, &incoming))) + { + if (coap_req->block1_num*coap_req->block1_size+len <= 2048) + { + REST.set_response_status(response, REST.status.CREATED); + REST.set_header_location(response, "/nirvana"); + coap_set_header_block1(response, coap_req->block1_num, 0, coap_req->block1_size); + } + else + { + REST.set_response_status(response, REST.status.REQUEST_ENTITY_TOO_LARGE); + const char *error_msg = "2048B max."; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } + } + else + { + REST.set_response_status(response, REST.status.BAD_REQUEST); + const char *error_msg = "NoPayload"; + REST.set_response_payload(response, error_msg, strlen(error_msg)); + return; + } +} +#endif + +#if REST_RES_OBS +/* + * Observable resource which changes every 5 seconds + */ +PERIODIC_RESOURCE(obs, METHOD_GET, "obs", "title=\"Observable resource which changes every 5 seconds\";obs;rt=\"observe\"", 5*CLOCK_SECOND); + +static uint16_t obs_counter = 0; +static char obs_content[16]; + +void +obs_handler(void* request, void* response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) +{ + REST.set_header_content_type(response, REST.type.TEXT_PLAIN); + REST.set_header_max_age(response, 5); + + REST.set_response_payload(response, obs_content, snprintf(obs_content, MAX_PLUGFEST_PAYLOAD, "TICK %lu", obs_counter)); + + /* 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. + */ +void +obs_periodic_handler(resource_t *r) +{ + ++obs_counter; + + PRINTF("TICK %u for /%s\n", obs_counter, r->url); + + /* Build notification. */ + /*TODO: REST.new_response() */ + 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 ); + + /* Better use a generator function for both handlers that only takes *resonse. */ + obs_handler(NULL, notification, NULL, 0, NULL); + + /* Notify the registered observers with the given message type, observe option, and payload. */ + REST.notify_subscribers(r, obs_counter, notification); +} +#endif + +PROCESS(plugtest_server, "PlugtestServer"); +AUTOSTART_PROCESSES(&plugtest_server); + +PROCESS_THREAD(plugtest_server, ev, data) +{ + PROCESS_BEGIN(); + + PRINTF("ETSI IoT CoAP Plugtests 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) + set_global_address(); + configure_routing(); +#endif + + /* Initialize the REST engine. */ + rest_init_engine(); + + /* Activate the application-specific resources. */ +#if REST_RES_TEST + rest_activate_resource(&resource_test); +#endif +#if REST_RES_LONG + rest_activate_resource(&resource_longpath); +#endif +#if REST_RES_QUERY + rest_activate_resource(&resource_query); +#endif +#if REST_RES_SEPARATE + rest_activate_periodic_resource(&periodic_resource_separate); +#endif +#if REST_RES_LARGE + rest_activate_resource(&resource_large); +#endif +#if REST_RES_LARGE_UPDATE + large_update_ct = REST.type.APPLICATION_OCTET_STREAM; + rest_activate_resource(&resource_large_update); +#endif +#if REST_RES_LARGE_CREATE + rest_activate_resource(&resource_large_create); +#endif +#if REST_RES_OBS + rest_activate_periodic_resource(&periodic_resource_obs); +#endif + + /* Define application-specific events here. */ + while(1) { + PROCESS_WAIT_EVENT(); + + } /* while (1) */ + + PROCESS_END(); +} diff --git a/examples/osd/embedd-vm-merkurboard/flash.sh b/examples/osd/embedd-vm-merkurboard/flash.sh new file mode 100755 index 000000000..fe0d83f0d --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/flash.sh @@ -0,0 +1,2 @@ +#!/bin/bash +sudo avrdude -pm128rfa1 -c arduino -P/dev/ttyUSB0 -b57600 -e -U flash:w:embedd-vm-server.osd-merkur.hex:a -U eeprom:w:embedd-vm-server.osd-merkur.eep:a diff --git a/examples/osd/embedd-vm-merkurboard/project-conf.h b/examples/osd/embedd-vm-merkurboard/project-conf.h new file mode 100644 index 000000000..2b6d52421 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/project-conf.h @@ -0,0 +1,80 @@ +/* + * 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 SICSLOWPAN_CONF_FRAG 1 + +#define PLATFORM_HAS_EVM 1 +#define PLATFORM_HAS_BATTERY 1 +#define PLATFORM_HAS_LEDS 1 + +/* 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 + +/* Debugmode Dont allow MCU sleeping between channel checks */ +#undef RDC_CONF_MCU_SLEEP +#define RDC_CONF_MCU_SLEEP 0 + +/* The IP buffer size must fit all other hops, in particular the border router. */ + +#undef UIP_CONF_BUFFER_SIZE +#define UIP_CONF_BUFFER_SIZE 1280 + +/* Save some memory for the sky platform. */ +#undef UIP_CONF_DS6_NBR_NBU +#define UIP_CONF_DS6_NBR_NBU 10 +#undef UIP_CONF_DS6_ROUTE_NBU +#define UIP_CONF_DS6_ROUTE_NBU 10 + +/* Increase rpl-border-router IP-buffer when using 128. */ +#ifndef REST_MAX_CHUNK_SIZE +#define REST_MAX_CHUNK_SIZE 64 +#endif + +/* Multiplies with chunk size, be aware of memory constraints. */ +#ifndef COAP_MAX_OPEN_TRANSACTIONS +#define COAP_MAX_OPEN_TRANSACTIONS 2 +#endif + +/* Must be <= open transaction number. */ +#ifndef COAP_MAX_OBSERVERS +#define COAP_MAX_OBSERVERS COAP_MAX_OPEN_TRANSACTIONS-1 +#endif + +/* Reduce 802.15.4 frame queue to save RAM. */ +#undef QUEUEBUF_CONF_NUM +#define QUEUEBUF_CONF_NUM 4 + +#endif /* __PROJECT_RPL_WEB_CONF_H__ */ diff --git a/examples/osd/embedd-vm-merkurboard/run.sh b/examples/osd/embedd-vm-merkurboard/run.sh new file mode 100755 index 000000000..c20cc4e5b --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/run.sh @@ -0,0 +1,6 @@ +#!/bin/bash +make clean TARGET=osd-merkur +make TARGET=osd-merkur +avr-size -C --mcu=MCU=atmega128rfa1 embedd-vm-server.osd-merkur +avr-objcopy -j .text -j .data -O ihex embedd-vm-server.osd-merkur embedd-vm-server.osd-merkur.hex +avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" --change-section-lma .eeprom=0 -O ihex embedd-vm-server.osd-merkur embedd-vm-server.osd-merkur.eep diff --git a/examples/osd/embedd-vm-merkurboard/server-only.csc b/examples/osd/embedd-vm-merkurboard/server-only.csc new file mode 100644 index 000000000..d5eee34d6 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/server-only.csc @@ -0,0 +1,189 @@ + + + [CONTIKI_DIR]/tools/cooja/apps/mrm + [CONTIKI_DIR]/tools/cooja/apps/mspsim + [CONTIKI_DIR]/tools/cooja/apps/avrora + [CONTIKI_DIR]/tools/cooja/apps/serial_socket + [CONTIKI_DIR]/tools/cooja/apps/collect-view + + REST with RPL router + -2147483648 + 123456 + 1000000 + + se.sics.cooja.radiomediums.UDGM + 50.0 + 50.0 + 1.0 + 1.0 + + + 40000 + + + se.sics.cooja.mspmote.SkyMoteType + rplroot + Sky RPL Root + [CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.c + make border-router.sky TARGET=sky + [CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + se.sics.cooja.mspmote.SkyMoteType + server + Erbium Server + [CONTIKI_DIR]/examples/er-rest-example/er-example-server.c + make er-example-server.sky TARGET=sky + [CONTIKI_DIR]/examples/er-rest-example/er-example-server.sky + se.sics.cooja.interfaces.Position + se.sics.cooja.interfaces.RimeAddress + se.sics.cooja.interfaces.IPAddress + se.sics.cooja.interfaces.Mote2MoteRelations + se.sics.cooja.interfaces.MoteAttributes + se.sics.cooja.mspmote.interfaces.MspClock + se.sics.cooja.mspmote.interfaces.MspMoteID + se.sics.cooja.mspmote.interfaces.SkyButton + se.sics.cooja.mspmote.interfaces.SkyFlash + se.sics.cooja.mspmote.interfaces.SkyCoffeeFilesystem + se.sics.cooja.mspmote.interfaces.SkyByteRadio + se.sics.cooja.mspmote.interfaces.MspSerial + se.sics.cooja.mspmote.interfaces.SkyLED + se.sics.cooja.mspmote.interfaces.MspDebugOutput + se.sics.cooja.mspmote.interfaces.SkyTemperature + + + + + se.sics.cooja.interfaces.Position + 33.260163187353555 + 30.643217359962595 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 1 + + rplroot + + + + + se.sics.cooja.interfaces.Position + 35.100895239785295 + 39.70574552287428 + 0.0 + + + se.sics.cooja.mspmote.interfaces.MspMoteID + 2 + + server + + + + se.sics.cooja.plugins.SimControl + 259 + 5 + 179 + 0 + 0 + + + se.sics.cooja.plugins.Visualizer + + se.sics.cooja.plugins.skins.IDVisualizerSkin + se.sics.cooja.plugins.skins.UDGMVisualizerSkin + se.sics.cooja.plugins.skins.MoteTypeVisualizerSkin + se.sics.cooja.plugins.skins.AttributeVisualizerSkin + se.sics.cooja.plugins.skins.LEDVisualizerSkin + se.sics.cooja.plugins.skins.AddressVisualizerSkin + 7.9849281638410705 0.0 0.0 7.9849281638410705 -133.27812697619663 -225.04752569190535 + + 300 + 4 + 175 + 263 + 3 + + + se.sics.cooja.plugins.LogListener + + + + + 560 + 1 + 326 + 1 + 293 + + + se.sics.cooja.plugins.RadioLogger + + 150 + + + 451 + -1 + 305 + 73 + 140 + true + + + SerialSocketServer + 0 + 422 + 2 + 74 + 39 + 199 + + + se.sics.cooja.plugins.TimeLine + + 0 + 1 + + + + + 125 + 25.49079397896416 + + 1624 + 3 + 252 + 4 + 622 + + + se.sics.cooja.plugins.MoteInterfaceViewer + 1 + + Serial port + 0,0 + + 702 + 0 + 646 + 564 + 2 + + + diff --git a/examples/osd/embedd-vm-merkurboard/static-routing.c b/examples/osd/embedd-vm-merkurboard/static-routing.c new file mode 100644 index 000000000..628594892 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/static-routing.c @@ -0,0 +1,155 @@ +/* + * static-routing.c + * + * Created on: Oct 12, 2010 + * Author: simonduq + */ + +#include +#include "static-routing.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 ", ((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 + +#include "contiki-net.h" +#include "node-id.h" + +int node_rank; + +struct id_to_addrs { + int id; + uint32_t addr; +}; + +const struct id_to_addrs motes_addrs[] = { +/* + * Static routing requires a map nodeid => address. + * The nodeid can be programmed with the sky-shell. + * The addresses should also be added to /etc/hosts. + * + * aaaa::212:7400:1160:f62d sky1 + * aaaa::212:7400:0da0:d748 sky2 + * aaaa::212:7400:116e:c325 sky3 + * aaaa::212:7400:116e:c444 sky4 + * aaaa::212:7400:115e:b717 sky5 + * + * Add the nodeid and last 4 bytes of the address to the map. + */ + {1, 0x1160f62d}, + {2, 0x0da0d748}, + {3, 0x116ec325}, + {4, 0x116ec444}, + {5, 0x115eb717}, +}; +/* Define the size of the map. */ +#define NODES_IN_MAP 5 + +uint32_t get_mote_suffix(int rank) { + if(--rank >=0 && rank<(sizeof(motes_addrs)/sizeof(struct id_to_addrs))) { + return motes_addrs[rank].addr; + } + return 0; +} + +int get_mote_id(uint32_t suffix) { +#if IN_COOJA + return suffix & 0xff; +#else + int i; + for(i=0; i<(sizeof(motes_addrs)/sizeof(struct id_to_addrs)); i++) { + if(suffix == motes_addrs[i].addr) { + return motes_addrs[i].id; + } + } + return 0; +#endif +} + +void set_global_address(void) { + uip_ipaddr_t ipaddr; + + uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0); + uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr); + uip_ds6_addr_add(&ipaddr, 0, ADDR_AUTOCONF); +} + +static void add_route_ext(int dest, int next) { + PRINTF("add route ext %d %d\n", dest, next); + uip_ipaddr_t ipaddr_dest, ipaddr_next; + uip_ip6addr(&ipaddr_dest, 0xaaaa, 0, 0, 0, 0, 0, 0, dest); +#if IN_COOJA + uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400 | next, next, next<<8 | next); +#else + uint32_t next_suffix = get_mote_suffix(next); + uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400, (next_suffix >> 16) & 0xffff, next_suffix & 0xffff); +#endif + uip_ds6_route_add(&ipaddr_dest, 128, &ipaddr_next, 0); +} + +void add_route(int dest, int next) { + PRINTF("add route %d %d\n", dest, next); + uip_ipaddr_t ipaddr_dest, ipaddr_next; +#if IN_COOJA + uip_ip6addr(&ipaddr_dest, 0xaaaa, 0, 0, 0, 0x0212, 0x7400 | dest, dest, dest<<8 | dest); + uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400 | next, next, next<<8 | next); +#else + uint32_t dest_suffix = get_mote_suffix(dest); + uint32_t next_suffix = get_mote_suffix(next); + uip_ip6addr(&ipaddr_dest, 0xaaaa, 0, 0, 0, 0x0212, 0x7400, (dest_suffix >> 16) & 0xffff, dest_suffix & 0xffff); + uip_ip6addr(&ipaddr_next, 0xfe80, 0, 0, 0, 0x0212, 0x7400, (next_suffix >> 16) & 0xffff, next_suffix & 0xffff); +#endif + uip_ds6_route_add(&ipaddr_dest, 128, &ipaddr_next, 0); +} + +void configure_routing(void) { + int i; +#if IN_COOJA + node_rank = node_id; +#else + node_rank = -1; + for(i=0; i<(sizeof(motes_addrs)/sizeof(struct id_to_addrs)); ++i) { + if(node_id == motes_addrs[i].id) { + node_rank = i+1; + break; + } + } + + if(node_rank == -1) { + printf("unable to configure routing, node_id=%d\n", node_id); + return; + } +#endif + + printf("configure_routing, node_id=%d, node_rank %d\n", node_id, node_rank); + + if (node_rank == 1) { /* border router #1 */ + add_route_ext(2, 2); + for(i=2; i<=NODES_IN_MAP; ++i) { + add_route(i, 2); + } + } else if (node_rank < NODES_IN_MAP) { /* other node */ + add_route_ext(1, node_rank-1); + add_route_ext(2, node_rank+1); + for(i=1; i<=NODES_IN_MAP; ++i) { + if(inode_rank) { + add_route(i, node_rank+1); + } + } + } else if (node_rank == NODES_IN_MAP) { /* 2nd border router */ + add_route_ext(1, NODES_IN_MAP-1); + for(i=1; i<=NODES_IN_MAP-1; ++i) { + add_route(i, NODES_IN_MAP-1); + } + } +} diff --git a/examples/osd/embedd-vm-merkurboard/static-routing.h b/examples/osd/embedd-vm-merkurboard/static-routing.h new file mode 100644 index 000000000..0dff0b7ba --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/static-routing.h @@ -0,0 +1,20 @@ +/* + * static-routing.h + * + * Created on: Oct 12, 2010 + * Author: simonduq + */ + +#ifndef STATICROUTING_H_ +#define STATICROUTING_H_ + +#include "contiki.h" + +extern int node_rank; +extern uint32_t get_mote_suffix(int id); +extern int get_mote_id(uint32_t suffix); +extern void add_route(int dest, int next); +extern void set_global_address(void); +extern void configure_routing(void); + +#endif /* STATICROUTING_H_ */ diff --git a/examples/osd/embedd-vm-merkurboard/vmcode.evm b/examples/osd/embedd-vm-merkurboard/vmcode.evm new file mode 100644 index 000000000..437207516 --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/vmcode.evm @@ -0,0 +1,43 @@ +// $uf10(); // LED OFF +// $uf11(); // LED ON +// $uf12(); // LED Toggle + +global points; +global num; +global dbg; + +function main() +{ + points = 0; + // get next random number + num = $uf0(); +} + +function play(guess) +{ + if (guess != num) { + if (guess < num) { + // hint to user: try larger numbers + $uf1(+1); + points = points - 1; + $uf11(); // LED ON + } + if (guess > num) { + // hint to user: try smaller numbers + $uf1(-1); + points = points - 1; + $uf10(); // LED OFF + } + } else { + // level up! + // LED ON + $uf11(); + points = points + 10; + $uf2(); + num = $uf0(); + $uf10(); // LED OFF + } + // report points + $uf3(); +} + diff --git a/examples/osd/embedd-vm-merkurboard/vmcode.hdr b/examples/osd/embedd-vm-merkurboard/vmcode.hdr new file mode 100644 index 000000000..e145c8f4a --- /dev/null +++ b/examples/osd/embedd-vm-merkurboard/vmcode.hdr @@ -0,0 +1,9 @@ +#define EMBEDVM_SYM__end 0x0054 +#define EMBEDVM_SYM_play 0x000e +#define EMBEDVM_SYM_main 0x0006 +#define EMBEDVM_SYM_dbg 0x0004 +#define EMBEDVM_SYM_num 0x0002 +#define EMBEDVM_SYM_points 0x0000 +#define EMBEDVM_SECT_SRAM_BEGIN 0x0000 +#define EMBEDVM_SECT_SRAM_END 0xffff +#define EMBEDVM_SECT_SRAM_DATA 0,0,0,0,0,0,144,232,0,144,176,232,2,156,63,224,2,171,166,42,63,224,2,168,166,15,145,145,177,157,224,0,145,129,232,0,144,187,157,63,224,2,173,166,15,151,145,177,157,224,0,145,129,232,0,144,186,157,160,22,144,187,157,224,0,152,10,128,232,0,144,178,157,144,176,232,2,144,186,157,144,179,157,156