Merge pull request #1409 from nfi/oma-lwm2m-ipso

Implementation of OMA LWM2M Engine / IPSO Objects
This commit is contained in:
Simon Duquennoy 2016-01-17 10:20:33 +01:00
commit c792f5cf4b
36 changed files with 5400 additions and 0 deletions

View file

@ -0,0 +1,3 @@
ipso-objects_src = ipso-temperature.c ipso-button.c ipso-leds-control.c \
ipso-light-control.c ipso-objects.c
CFLAGS += -DWITH_IPSO=1

View file

@ -0,0 +1,163 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup ipso-objects
* @{
*/
/**
* \file
* Implementation of OMA LWM2M / IPSO button as a digital input
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "contiki.h"
#include "lwm2m-object.h"
#include "lwm2m-engine.h"
#include "er-coap-engine.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#if PLATFORM_HAS_BUTTON
#include "dev/button-sensor.h"
PROCESS(ipso_button_process, "ipso-button");
#endif /* PLATFORM_HAS_BUTTON */
static int input_state = 0;
static int polarity = 0;
static int32_t counter = 0;
static int32_t edge_selection = 3;
static int32_t debounce_time = 10;
/*---------------------------------------------------------------------------*/
static int
read_state(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
int value;
if(polarity == 0) {
value = input_state ? 1 : 0;
} else {
value = input_state ? 0 : 1;
}
PRINTF("Read button state (polarity=%d, state=%d): %d\n",
polarity, input_state, value);
return ctx->writer->write_boolean(ctx, outbuf, outsize, value);
}
/*---------------------------------------------------------------------------*/
static int
reset_counter(lwm2m_context_t *ctx, const uint8_t *arg, size_t len,
uint8_t *outbuf, size_t outlen)
{
counter = 0;
return 0;
}
/*---------------------------------------------------------------------------*/
LWM2M_RESOURCES(button_resources,
LWM2M_RESOURCE_CALLBACK(5500, { read_state, NULL, NULL }),
LWM2M_RESOURCE_INTEGER_VAR(5501, &counter),
LWM2M_RESOURCE_BOOLEAN_VAR(5502, &polarity),
LWM2M_RESOURCE_INTEGER_VAR(5503, &debounce_time),
LWM2M_RESOURCE_INTEGER_VAR(5504, &edge_selection),
LWM2M_RESOURCE_CALLBACK(5505, { NULL, NULL, reset_counter }),
LWM2M_RESOURCE_STRING(5751, "Button")
);
LWM2M_INSTANCES(button_instances,
LWM2M_INSTANCE(0, button_resources));
LWM2M_OBJECT(button, 3200, button_instances);
/*---------------------------------------------------------------------------*/
void
ipso_button_init(void)
{
/* register this device and its handlers - the handlers automatically
sends in the object to handle */
lwm2m_engine_register_object(&button);
#if PLATFORM_HAS_BUTTON
process_start(&ipso_button_process, NULL);
#endif /* PLATFORM_HAS_BUTTON */
}
/*---------------------------------------------------------------------------*/
#if PLATFORM_HAS_BUTTON
PROCESS_THREAD(ipso_button_process, ev, data)
{
static struct etimer timer;
int32_t time;
PROCESS_BEGIN();
SENSORS_ACTIVATE(button_sensor);
while(1) {
PROCESS_WAIT_EVENT();
if(ev == sensors_event && data == &button_sensor) {
if(!input_state) {
input_state = 1;
counter++;
if((edge_selection & 2) != 0) {
lwm2m_object_notify_observers(&button, "/0/5500");
}
lwm2m_object_notify_observers(&button, "/0/5501");
time = (debounce_time * CLOCK_SECOND / 1000);
if(time < 1) {
time = 1;
}
etimer_set(&timer, (clock_time_t)time);
}
} else if(ev == PROCESS_EVENT_TIMER && data == &timer) {
if(!input_state) {
/* Button is not in pressed state */
} else if(button_sensor.value(0) != 0) {
/* Button is still pressed */
etimer_reset(&timer);
} else {
input_state = 0;
if((edge_selection & 1) != 0) {
lwm2m_object_notify_observers(&button, "/0/5500");
}
}
}
}
PROCESS_END();
}
#endif /* PLATFORM_HAS_BUTTON */
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,236 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup ipso-objects
* @{
*
*/
/**
* \file
* Implementation of OMA LWM2M / IPSO Light Control for LEDs
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "lwm2m-object.h"
#include "lwm2m-engine.h"
#include "er-coap-engine.h"
#include "dev/leds.h"
#include <stdint.h>
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#if LEDS_ALL & LEDS_BLUE || LEDS_ALL & LEDS_RED || LEDS_ALL & LEDS_BLUE
#define LEDS_CONTROL_NUMBER (((LEDS_ALL & LEDS_BLUE) ? 1 : 0) + ((LEDS_ALL & LEDS_RED) ? 1 : 0) + ((LEDS_ALL & LEDS_GREEN) ? 1 : 0))
#else
#define LEDS_CONTROL_NUMBER 1
#endif
struct led_state {
unsigned long last_on_time;
uint32_t total_on_time;
uint8_t is_on;
uint8_t led_value;
};
static struct led_state states[LEDS_CONTROL_NUMBER];
static lwm2m_instance_t leds_control_instances[LEDS_CONTROL_NUMBER];
/*---------------------------------------------------------------------------*/
static int
read_state(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
uint8_t idx = ctx->object_instance_index;
if(idx >= LEDS_CONTROL_NUMBER) {
return 0;
}
return ctx->writer->write_boolean(ctx, outbuf, outsize,
states[idx].is_on ? 1 : 0);
}
/*---------------------------------------------------------------------------*/
static int
write_state(lwm2m_context_t *ctx, const uint8_t *inbuf, size_t insize,
uint8_t *outbuf, size_t outsize)
{
int value;
size_t len;
uint8_t idx = ctx->object_instance_index;
if(idx >= LEDS_CONTROL_NUMBER) {
return 0;
}
len = ctx->reader->read_boolean(ctx, inbuf, insize, &value);
if(len > 0) {
if(value) {
if(!states[idx].is_on) {
states[idx].is_on = 1;
states[idx].last_on_time = clock_seconds();
#if PLATFORM_HAS_LEDS
leds_on(states[idx].led_value);
#endif /* PLATFORM_HAS_LEDS */
}
} else if(states[idx].is_on) {
states[idx].total_on_time += clock_seconds() - states[idx].last_on_time;
states[idx].is_on = 0;
#if PLATFORM_HAS_LEDS
leds_off(states[idx].led_value);
#endif /* PLATFORM_HAS_LEDS */
}
} else {
PRINTF("IPSO leds control - ignored illegal write to on/off\n");
}
return len;
}
/*---------------------------------------------------------------------------*/
static char *
get_color(int value) {
switch(value) {
case LEDS_GREEN:
return "Green";
case LEDS_RED:
return "Red";
case LEDS_BLUE:
return "Blue";
}
return "None";
}
static int
read_color(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
char *value;
uint8_t idx = ctx->object_instance_index;
if(idx >= LEDS_CONTROL_NUMBER) {
return 0;
}
value = get_color(states[idx].led_value);
return ctx->writer->write_string(ctx, outbuf, outsize,
value, strlen(value));
}
/*---------------------------------------------------------------------------*/
static int
read_on_time(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
unsigned long now;
uint8_t idx = ctx->object_instance_index;
if(idx >= LEDS_CONTROL_NUMBER) {
return 0;
}
if(states[idx].is_on) {
/* Update the on time */
now = clock_seconds();
states[idx].total_on_time += now - states[idx].last_on_time;
states[idx].last_on_time = now;
}
return ctx->writer->write_int(ctx, outbuf, outsize,
(int32_t)states[idx].total_on_time);
}
/*---------------------------------------------------------------------------*/
static int
write_on_time(lwm2m_context_t *ctx,
const uint8_t *inbuf, size_t insize,
uint8_t *outbuf, size_t outsize)
{
int32_t value;
size_t len;
uint8_t idx = ctx->object_instance_index;
if(idx >= LEDS_CONTROL_NUMBER) {
return 0;
}
len = ctx->reader->read_int(ctx, inbuf, insize, &value);
if(len > 0 && value == 0) {
PRINTF("IPSO leds control - reset On Time\n");
states[idx].total_on_time = 0;
if(states[idx].is_on) {
states[idx].last_on_time = clock_seconds();
}
} else {
PRINTF("IPSO leds control - ignored illegal write to On Time\n");
}
return len;
}
/*---------------------------------------------------------------------------*/
LWM2M_RESOURCES(leds_control_resources,
LWM2M_RESOURCE_CALLBACK(5850, { read_state, write_state, NULL }),
LWM2M_RESOURCE_CALLBACK(5706, { read_color, NULL, NULL }),
LWM2M_RESOURCE_CALLBACK(5852, { read_on_time, write_on_time, NULL })
);
LWM2M_OBJECT(leds_control, 3311, leds_control_instances);
/*---------------------------------------------------------------------------*/
static int
bit_no(int bit)
{
int i;
for(i = 0; i < 8; i++) {
if(LEDS_ALL & (1 << i)) {
if(bit == 0) {
/* matching bit */
return 1 << i;
} else {
/* matching but used */
bit--;
}
}
}
return 0;
}
void
ipso_leds_control_init(void)
{
lwm2m_instance_t template = LWM2M_INSTANCE(0, leds_control_resources);
int i;
/* Initialize the instances */
for(i = 0; i < LEDS_CONTROL_NUMBER; i++) {
leds_control_instances[i] = template;
leds_control_instances[i].id = i;
states[i].led_value = bit_no(i);
}
/* register this device and its handlers - the handlers automatically
sends in the object to handle */
lwm2m_engine_register_object(&leds_control);
PRINTF("IPSO leds control initialized with %u instances\n",
LEDS_CONTROL_NUMBER);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,202 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup ipso-objects
* @{
*
*/
/**
* \file
* Implementation of OMA LWM2M / IPSO Light Control
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "ipso-objects.h"
#include "lwm2m-object.h"
#include "lwm2m-engine.h"
#ifdef IPSO_LIGHT_CONTROL
extern const struct ipso_objects_actuator IPSO_LIGHT_CONTROL;
#endif /* IPSO_LIGHT_CONTROL */
/*---------------------------------------------------------------------------*/
static unsigned long last_on_time;
static uint32_t total_on_time;
static int dim_level = 0;
static uint8_t is_on = 0;
/*---------------------------------------------------------------------------*/
static int
read_state(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
return ctx->writer->write_boolean(ctx, outbuf, outsize, is_on ? 1 : 0);
}
/*---------------------------------------------------------------------------*/
static int
write_state(lwm2m_context_t *ctx, const uint8_t *inbuf, size_t insize,
uint8_t *outbuf, size_t outsize)
{
int value;
size_t len;
len = ctx->reader->read_boolean(ctx, inbuf, insize, &value);
if(len > 0) {
if(value) {
if(!is_on) {
is_on = 1;
last_on_time = clock_seconds();
}
} else {
if(is_on) {
total_on_time += clock_seconds() - last_on_time;
is_on = 0;
}
}
#ifdef IPSO_LIGHT_CONTROL
if(IPSO_LIGHT_CONTROL.set_on) {
IPSO_LIGHT_CONTROL.set_on(value);
} else if(IPSO_LIGHT_CONTROL.set_dim_level) {
dim_level = value ? 100 : 0;
IPSO_LIGHT_CONTROL.set_dim_level(dim_level);
}
#endif /* IPSO_LIGHT_CONTROL */
}
return len;
}
/*---------------------------------------------------------------------------*/
static int
read_dim(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
return ctx->writer->write_int(ctx, outbuf, outsize, dim_level);
}
/*---------------------------------------------------------------------------*/
static int
write_dim(lwm2m_context_t *ctx, const uint8_t *inbuf, size_t insize,
uint8_t *outbuf, size_t outsize)
{
int32_t value;
size_t len;
len = ctx->reader->read_int(ctx, inbuf, insize, &value);
if(len > 0) {
if(value < 0) {
value = 0;
} else if(value > 100) {
value = 100;
}
dim_level = value;
if(value > 0) {
if(!is_on) {
is_on = 1;
last_on_time = clock_seconds();
}
} else {
if(is_on) {
total_on_time += clock_seconds() - last_on_time;
is_on = 0;
}
}
#ifdef IPSO_LIGHT_CONTROL
if(IPSO_LIGHT_CONTROL.set_dim_level) {
IPSO_LIGHT_CONTROL.set_dim_level(dim_level);
} else if(IPSO_LIGHT_CONTROL.set_on) {
IPSO_LIGHT_CONTROL.set_on(is_on);
}
#endif /* IPSO_LIGHT_CONTROL */
}
return len;
}
/*---------------------------------------------------------------------------*/
static int
read_on_time(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
unsigned long now;
if(is_on) {
/* Update the on time */
now = clock_seconds();
total_on_time += now - last_on_time;
last_on_time = now;
}
return ctx->writer->write_int(ctx, outbuf, outsize, (int32_t)total_on_time);
}
/*---------------------------------------------------------------------------*/
static int
write_on_time(lwm2m_context_t *ctx,
const uint8_t *inbuf, size_t insize,
uint8_t *outbuf, size_t outsize)
{
int32_t value;
size_t len;
len = ctx->reader->read_int(ctx, inbuf, insize, &value);
if(len > 0 && value == 0) {
total_on_time = 0;
if(is_on) {
last_on_time = clock_seconds();
}
}
return len;
}
/*---------------------------------------------------------------------------*/
LWM2M_RESOURCES(light_control_resources,
LWM2M_RESOURCE_CALLBACK(5850, { read_state, write_state, NULL }),
LWM2M_RESOURCE_CALLBACK(5851, { read_dim, write_dim, NULL }),
LWM2M_RESOURCE_CALLBACK(5852, { read_on_time, write_on_time, NULL }),
);
LWM2M_INSTANCES(light_control_instances,
LWM2M_INSTANCE(0, light_control_resources));
LWM2M_OBJECT(light_control, 3311, light_control_instances);
/*---------------------------------------------------------------------------*/
void
ipso_light_control_init(void)
{
#ifdef IPSO_LIGHT_CONTROL
if(IPSO_LIGHT_CONTROL.init) {
IPSO_LIGHT_CONTROL.init();
}
if(IPSO_LIGHT_CONTROL.is_on) {
is_on = IPSO_LIGHT_CONTROL.is_on();
}
if(IPSO_LIGHT_CONTROL.get_dim_level) {
dim_level = IPSO_LIGHT_CONTROL.get_dim_level();
if(dim_level > 0 && IPSO_LIGHT_CONTROL.is_on == NULL) {
is_on = 1;
}
}
#endif /* IPSO_LIGHT_CONTROL */
last_on_time = clock_seconds();
lwm2m_engine_register_object(&light_control);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,66 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*/
/**
* \file
* Implementation of the IPSO Objects
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "contiki.h"
#include "ipso-objects.h"
/*---------------------------------------------------------------------------*/
void
ipso_objects_init(void)
{
/* initialize any relevant object for the IPSO Objects */
#ifdef IPSO_TEMPERATURE
ipso_temperature_init();
#endif
#if PLATFORM_HAS_BUTTON
ipso_button_init();
#endif
#ifdef IPSO_LIGHT_CONTROL
ipso_light_control_init();
#elif PLATFORM_HAS_LEDS
ipso_leds_control_init();
#endif
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,122 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup apps
* @{
*/
/**
* \defgroup ipso-objects An implementation of IPSO Objects
* @{
*
* This application is an implementation of IPSO Objects for
* OMA Lightweight M2M.
*/
/**
* \file
* Header file for the Contiki IPSO Objects for OMA LWM2M
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef IPSO_OBJECTS_H_
#define IPSO_OBJECTS_H_
#include "contiki-conf.h"
void ipso_temperature_init(void);
void ipso_button_init(void);
void ipso_light_control_init(void);
void ipso_leds_control_init(void);
/* the init function to register the IPSO objects */
void ipso_objects_init(void);
struct ipso_objects_actuator {
/**
* \brief Initialize the driver.
*/
void (* init)(void);
/**
* \brief Check if the actuator is on or off.
*
* \return Zero if the actuator is off and non-zero otherwise.
*/
int (* is_on)(void);
/**
* \brief Set the actuator to on or off.
*
* \param onoroff Zero to set the actuator to off and non-zero otherwise.
* \return Zero if ok and a non-zero error code otherwise.
*/
int (* set_on)(int onoroff);
/**
* \brief Set the actuator to on or off.
*
* \param onoroff Zero to set the actuator to off and non-zero otherwise.
* \return Zero if ok and a non-zero error code otherwise.
*/
int (* get_dim_level)(void);
/**
* \brief Set the dim level of the actuator.
*
* \param level The dim level between 0% and 100%.
* \return Zero if ok and a non-zero error code otherwise.
*/
int (* set_dim_level)(int level);
};
struct ipso_objects_sensor {
/**
* \brief Initialize the driver.
*/
void (* init)(void);
/**
* \brief Read the sensor value in 1/1000 units.
*
* \param value A pointer to the variable to hold the sensor value.
* \return Zero if ok and a non-zero error code otherwise.
*/
int (* read_value)(int32_t *value);
};
#endif /* IPSO_OBJECTS_H_ */
/**
* @}
* @}
*/

View file

@ -0,0 +1,159 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup ipso-objects
* @{
*/
/**
* \file
* Implementation of OMA LWM2M / IPSO Temperature
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include <stdint.h>
#include "ipso-objects.h"
#include "lwm2m-object.h"
#include "lwm2m-engine.h"
#include "er-coap-engine.h"
#ifdef IPSO_TEMPERATURE
extern const struct ipso_objects_sensor IPSO_TEMPERATURE;
#endif /* IPSO_TEMPERATURE */
#ifndef IPSO_TEMPERATURE_MIN
#define IPSO_TEMPERATURE_MIN (-50 * LWM2M_FLOAT32_FRAC)
#endif
#ifndef IPSO_TEMPERATURE_MAX
#define IPSO_TEMPERATURE_MAX (80 * LWM2M_FLOAT32_FRAC)
#endif
static struct ctimer periodic_timer;
static int32_t min_temp;
static int32_t max_temp;
static int read_temp(int32_t *value);
/*---------------------------------------------------------------------------*/
static int
temp(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
int32_t value;
if(read_temp(&value)) {
return ctx->writer->write_float32fix(ctx, outbuf, outsize,
value, LWM2M_FLOAT32_BITS);
}
return 0;
}
/*---------------------------------------------------------------------------*/
LWM2M_RESOURCES(temperature_resources,
/* Temperature (Current) */
LWM2M_RESOURCE_CALLBACK(5700, { temp, NULL, NULL }),
/* Units */
LWM2M_RESOURCE_STRING(5701, "Celcius"),
/* Min Range Value */
LWM2M_RESOURCE_FLOATFIX(5603, IPSO_TEMPERATURE_MIN),
/* Max Range Value */
LWM2M_RESOURCE_FLOATFIX(5604, IPSO_TEMPERATURE_MAX),
/* Min Measured Value */
LWM2M_RESOURCE_FLOATFIX_VAR(5601, &min_temp),
/* Max Measured Value */
LWM2M_RESOURCE_FLOATFIX_VAR(5602, &max_temp),
);
LWM2M_INSTANCES(temperature_instances,
LWM2M_INSTANCE(0, temperature_resources));
LWM2M_OBJECT(temperature, 3303, temperature_instances);
/*---------------------------------------------------------------------------*/
static int
read_temp(int32_t *value)
{
#ifdef IPSO_TEMPERATURE
int32_t temp;
if(IPSO_TEMPERATURE.read_value == NULL ||
IPSO_TEMPERATURE.read_value(&temp) != 0) {
return 0;
}
/* Convert milliCelsius to fix float */
*value = (temp * LWM2M_FLOAT32_FRAC) / 1000;
if(*value < min_temp) {
min_temp = *value;
lwm2m_object_notify_observers(&temperature, "/0/5601");
}
if(*value > max_temp) {
max_temp = *value;
lwm2m_object_notify_observers(&temperature, "/0/5602");
}
return 1;
#else /* IPSO_TEMPERATURE */
return 0;
#endif /* IPSO_TEMPERATURE */
}
/*---------------------------------------------------------------------------*/
static void
handle_periodic_timer(void *ptr)
{
static int32_t last_value = IPSO_TEMPERATURE_MIN;
int32_t v;
/* Only notify when the value has changed since last */
if(read_temp(&v) && v != last_value) {
last_value = v;
lwm2m_object_notify_observers(&temperature, "/0/5700");
}
ctimer_reset(&periodic_timer);
}
/*---------------------------------------------------------------------------*/
void
ipso_temperature_init(void)
{
int32_t v;
min_temp = IPSO_TEMPERATURE_MAX;
max_temp = IPSO_TEMPERATURE_MIN;
#ifdef IPSO_TEMPERATURE
if(IPSO_TEMPERATURE.init) {
IPSO_TEMPERATURE.init();
}
#endif /* IPSO_TEMPERATURE */
/* register this device and its handlers - the handlers automatically
sends in the object to handle */
lwm2m_engine_register_object(&temperature);
/* update temp and min/max + notify any listeners */
read_temp(&v);
ctimer_set(&periodic_timer, CLOCK_SECOND * 10, handle_periodic_timer, NULL);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,5 @@
oma-lwm2m_src = lwm2m-object.c lwm2m-engine.c \
lwm2m-device.c lwm2m-server.c lwm2m-security.c \
oma-tlv.c oma-tlv-reader.c oma-tlv-writer.c \
lwm2m-plain-text.c
CFLAGS += -DHAVE_OMA_LWM2M=1

View file

@ -0,0 +1,152 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M device
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "lwm2m-object.h"
#include "lwm2m-device.h"
#include "lwm2m-engine.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
static int32_t time_offset = 0;
/*---------------------------------------------------------------------------*/
static int
read_lwtime(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outsize)
{
return ctx->writer->write_int(ctx, outbuf, outsize,
time_offset + clock_seconds());
}
/*---------------------------------------------------------------------------*/
static int
set_lwtime(lwm2m_context_t *ctx, const uint8_t *inbuf, size_t insize,
uint8_t *outbuf, size_t outsize)
{
/* assume that this only read one TLV value */
int32_t lw_time;
size_t len = ctx->reader->read_int(ctx, inbuf, insize, &lw_time);
if(len == 0) {
PRINTF("FAIL: could not read time '%*.s'\n", (int)insize, inbuf);
} else {
PRINTF("Got: time: %*.s => %" PRId32 "\n", (int)insize, inbuf, lw_time);
time_offset = lw_time - clock_seconds();
PRINTF("Write time...%" PRId32 " => offset = %" PRId32 "\n",
lw_time, time_offset);
}
/* return the number of bytes read */
return len;
}
/*---------------------------------------------------------------------------*/
#ifdef PLATFORM_REBOOT
static struct ctimer reboot_timer;
static void
do_the_reboot(void *ptr)
{
PLATFORM_REBOOT();
}
static int
reboot(lwm2m_context_t *ctx, const uint8_t *arg, size_t argsize,
uint8_t *outbuf, size_t outsize)
{
PRINTF("Device will reboot!\n");
ctimer_set(&reboot_timer, CLOCK_SECOND / 2, do_the_reboot, NULL);
return 0;
}
#endif /* PLATFORM_REBOOT */
/*---------------------------------------------------------------------------*/
#ifdef PLATFORM_FACTORY_DEFAULT
static int
factory_reset(lwm2m_context_t *ctx, const uint8_t *arg, size_t arg_size,
uint8_t *outbuf, size_t outsize)
{
PRINTF("Device will do factory default!\n");
PLATFORM_FACTORY_DEFAULT();
return 0;
}
#endif /* PLATFORM_FACTORY_DEFAULT */
/*---------------------------------------------------------------------------*/
LWM2M_RESOURCES(device_resources,
#ifdef LWM2M_DEVICE_MANUFACTURER
LWM2M_RESOURCE_STRING(0, LWM2M_DEVICE_MANUFACTURER),
#endif /* LWM2M_DEVICE_MANUFACTURER */
#ifdef LWM2M_DEVICE_TYPE
LWM2M_RESOURCE_STRING(17, LWM2M_DEVICE_TYPE),
#endif /* LWM2M_DEVICE_TYPE */
#ifdef LWM2M_DEVICE_MODEL_NUMBER
LWM2M_RESOURCE_STRING(1, LWM2M_DEVICE_MODEL_NUMBER),
#endif /* LWM2M_DEVICE_MODEL_NUMBER */
#ifdef LWM2M_DEVICE_SERIAL_NO
LWM2M_RESOURCE_STRING(2, LWM2M_DEVICE_SERIAL_NO),
#endif /* LWM2M_DEVICE_SERIAL_NO */
#ifdef LWM2M_DEVICE_FIRMWARE_VERSION
LWM2M_RESOURCE_STRING(3, LWM2M_DEVICE_FIRMWARE_VERSION),
#endif /* LWM2M_DEVICE_FIRMWARE_VERSION */
#ifdef PLATFORM_REBOOT
LWM2M_RESOURCE_CALLBACK(4, { NULL, NULL, reboot }),
#endif /* PLATFORM_REBOOT */
#ifdef PLATFORM_FACTORY_DEFAULT
LWM2M_RESOURCE_CALLBACK(5, { NULL, NULL, factory_reset }),
#endif /* PLATFORM_FACTORY_DEFAULT */
/* Current Time */
LWM2M_RESOURCE_CALLBACK(13, { read_lwtime, set_lwtime, NULL }),
);
LWM2M_INSTANCES(device_instances, LWM2M_INSTANCE(0, device_resources));
LWM2M_OBJECT(device, 3, device_instances);
/*---------------------------------------------------------------------------*/
void
lwm2m_device_init(void)
{
/**
* Register this device and its handlers - the handlers
* automatically sends in the object to handle.
*/
PRINTF("*** Init lwm2m-device\n");
lwm2m_engine_register_object(&device);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*/
/**
* \file
* Header file for the Contiki OMA LWM2M device
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef LWM2M_DEVICE_H_
#define LWM2M_DEVICE_H_
#include "contiki-conf.h"
#ifndef LWM2M_DEVICE_MODEL_NUMBER
#ifdef BOARD_STRING
#define LWM2M_DEVICE_MODEL_NUMBER BOARD_STRING
#endif /* BOARD_STRING */
#endif /* LWM2M_DEVICE_MODEL_NUMBER */
#ifndef LWM2M_DEVICE_FIRMWARE_VERSION
#define LWM2M_DEVICE_FIRMWARE_VERSION CONTIKI_VERSION_STRING
#endif /* LWM2M_DEVICE_FIRMWARE_VERSION */
void lwm2m_device_init(void);
#endif /* LWM2M_DEVICE_H_ */
/** @} */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*/
/**
* \file
* Header file for the Contiki OMA LWM2M engine
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef LWM2M_ENGINE_H
#define LWM2M_ENGINE_H
#include "lwm2m-object.h"
#define LWM2M_FLOAT32_BITS 10
#define LWM2M_FLOAT32_FRAC (1L << LWM2M_FLOAT32_BITS)
/* LWM2M / CoAP Content-Formats */
typedef enum {
LWM2M_TEXT_PLAIN = 1541,
LWM2M_TLV = 1542,
LWM2M_JSON = 1543,
LWM2M_OPAQUE = 1544
} lwm2m_content_format_t;
void lwm2m_engine_init(void);
void lwm2m_engine_register_default_objects(void);
void lwm2m_engine_use_bootstrap_server(int use);
void lwm2m_engine_use_registration_server(int use);
void lwm2m_engine_register_with_server(const uip_ipaddr_t *server, uint16_t port);
void lwm2m_engine_register_with_bootstrap_server(const uip_ipaddr_t *server, uint16_t port);
const lwm2m_object_t *lwm2m_engine_get_object(uint16_t id);
int lwm2m_engine_register_object(const lwm2m_object_t *object);
void lwm2m_engine_handler(const lwm2m_object_t *object,
void *request, void *response,
uint8_t *buffer, uint16_t preferred_size,
int32_t *offset);
void lwm2m_engine_delete_handler(const lwm2m_object_t *object,
void *request, void *response,
uint8_t *buffer, uint16_t preferred_size,
int32_t *offset);
#endif /* LWM2M_ENGINE_H */
/** @} */

View file

@ -0,0 +1,336 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M object API
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "lwm2m-object.h"
#include <string.h>
/*---------------------------------------------------------------------------*/
int
lwm2m_object_is_resource_string(const lwm2m_resource_t *resource)
{
if(resource == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VALUE ||
resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE ||
resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE_ARRAY) {
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
const uint8_t *
lwm2m_object_get_resource_string(const lwm2m_resource_t *resource,
const lwm2m_context_t *context)
{
if(resource == NULL || context == NULL) {
return NULL;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VALUE) {
return resource->value.string.value;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE) {
return *(resource->value.stringvar.var);
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.stringvararr.count) {
return resource->value.stringvararr.var +
resource->value.stringvararr.size * context->object_instance_index;
}
return NULL;
}
/* Not a string */
return NULL;
}
/*---------------------------------------------------------------------------*/
uint16_t
lwm2m_object_get_resource_strlen(const lwm2m_resource_t *resource,
const lwm2m_context_t *context)
{
if(resource == NULL || context == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VALUE) {
return resource->value.string.len;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE) {
return *(resource->value.stringvar.len);
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.stringvararr.count) {
return resource->value.stringvararr.len[context->object_instance_index];
}
return 0;
}
/* Not a string */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_set_resource_string(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
uint16_t len, const uint8_t *string)
{
if(resource == NULL || context == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE) {
if(len > resource->value.stringvar.size) {
/* Too large */
return 0;
}
memcpy(resource->value.stringvar.var, string, len);
*(resource->value.stringvar.len) = len;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_STR_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.stringvararr.count &&
len <= resource->value.stringvararr.size) {
memcpy(resource->value.stringvararr.var +
resource->value.stringvararr.size * context->object_instance_index,
string, len);
resource->value.stringvararr.len[context->object_instance_index] = len;
return 1;
}
return 0;
}
/* Not a string variable */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_is_resource_int(const lwm2m_resource_t *resource)
{
if(resource == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_INT_VALUE ||
resource->type == LWM2M_RESOURCE_TYPE_INT_VARIABLE ||
resource->type == LWM2M_RESOURCE_TYPE_INT_VARIABLE_ARRAY) {
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_get_resource_int(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t *value)
{
if(resource == NULL || context == NULL || value == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_INT_VALUE) {
*value = resource->value.integer.value;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_INT_VARIABLE) {
*value = *(resource->value.integervar.var);
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_INT_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.integervararr.count) {
*value = resource->value.integervararr.var[context->object_instance_index];
return 1;
}
return 0;
}
/* Not an integer */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_set_resource_int(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t value)
{
if(resource == NULL || context == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_INT_VARIABLE) {
*(resource->value.integervar.var) = value;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_INT_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.integervararr.count) {
resource->value.integervararr.var[context->object_instance_index] =
value;
return 1;
}
return 0;
}
/* Not an integer variable */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_is_resource_floatfix(const lwm2m_resource_t *resource)
{
if(resource == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VALUE ||
resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE ||
resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE_ARRAY) {
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_get_resource_floatfix(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t *value)
{
if(resource == NULL || context == NULL || value == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VALUE) {
*value = resource->value.floatfix.value;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE) {
*value = *(resource->value.floatfixvar.var);
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.floatfixvararr.count) {
*value = resource->value.floatfixvararr.var[context->object_instance_index];
return 1;
}
return 0;
}
/* Not an float */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_set_resource_floatfix(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t value)
{
if(resource == NULL || context == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE) {
*(resource->value.floatfixvar.var) = value;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.floatfixvararr.count) {
resource->value.floatfixvararr.var[context->object_instance_index] =
value;
return 1;
}
return 0;
}
/* Not an float variable */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_is_resource_boolean(const lwm2m_resource_t *resource)
{
if(resource == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VALUE ||
resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE ||
resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE_ARRAY) {
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_get_resource_boolean(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int *value)
{
if(resource == NULL || context == NULL || value == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VALUE) {
*value = resource->value.boolean.value;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE) {
*value = *(resource->value.booleanvar.var);
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.booleanvararr.count) {
*value = resource->value.booleanvararr.var[context->object_instance_index];
return 1;
}
return 0;
}
/* Not a boolean */
return 0;
}
/*---------------------------------------------------------------------------*/
int
lwm2m_object_set_resource_boolean(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int value)
{
if(resource == NULL || context == NULL) {
return 0;
}
if(resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE) {
*(resource->value.booleanvar.var) = value;
return 1;
}
if(resource->type == LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE_ARRAY) {
if(context->object_instance_index < resource->value.booleanvararr.count) {
resource->value.booleanvararr.var[context->object_instance_index] =
value;
return 1;
}
return 0;
}
/* Not a boolean variable */
return 0;
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,359 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup apps
* @{
*/
/**
* \defgroup oma-lwm2m An implementation of OMA LWM2M
* @{
*
* This application is an implementation of OMA Lightweight M2M.
*/
/**
* \file
* Header file for the Contiki OMA LWM2M object API
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef LWM2M_OBJECT_H_
#define LWM2M_OBJECT_H_
#include "rest-engine.h"
#include "er-coap-observe.h"
#define LWM2M_OBJECT_SECURITY_ID 0
#define LWM2M_OBJECT_SERVER_ID 1
#define LWM2M_OBJECT_ACCESS_CONTROL_ID 2
#define LWM2M_OBJECT_DEVICE_ID 3
#define LWM2M_OBJECT_CONNECTIVITY_MONITORING_ID 4
#define LWM2M_OBJECT_FIRMWARE_ID 5
#define LWM2M_OBJECT_LOCATION_ID 6
#define LWM2M_OBJECT_CONNECTIVITY_STATISTICS_ID 7
#define LWM2M_SECURITY_SERVER_URI 0
#define LWM2M_SECURITY_BOOTSTRAP_SERVER 1
#define LWM2M_SECURITY_MODE 2
#define LWM2M_SECURITY_CLIENT_PKI 3
#define LWM2M_SECURITY_SERVER_PKI 4
#define LWM2M_SECURITY_KEY 5
#define LWM2M_SECURITY_SHORT_SERVER_ID 10
/* Pre-shared key mode */
#define LWM2M_SECURITY_MODE_PSK 0
/* Raw Public Key mode */
#define LWM2M_SECURITY_MODE_RPK 1
/* Certificate mode */
#define LWM2M_SECURITY_MODE_CERTIFICATE 2
/* NoSec mode */
#define LWM2M_SECURITY_MODE_NOSEC 3
#define LWM2M_OBJECT_STR_HELPER(x) (uint8_t *) #x
#define LWM2M_OBJECT_STR(x) LWM2M_OBJECT_STR_HELPER(x)
#define LWM2M_OBJECT_PATH_STR_HELPER(x) #x
#define LWM2M_OBJECT_PATH_STR(x) LWM2M_OBJECT_PATH_STR_HELPER(x)
struct lwm2m_reader;
struct lwm2m_writer;
/* Data model for OMA LWM2M objects */
typedef struct lwm2m_context {
uint16_t object_id;
uint16_t object_instance_id;
uint16_t resource_id;
uint8_t object_instance_index;
uint8_t resource_index;
/* TODO - add uint16_t resource_instance_id */
const struct lwm2m_reader *reader;
const struct lwm2m_writer *writer;
} lwm2m_context_t;
/* LWM2M format writer for the various formats supported */
typedef struct lwm2m_writer {
size_t (* write_int)(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen, int32_t value);
size_t (* write_string)(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen, const char *value, size_t strlen);
size_t (* write_float32fix)(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen, int32_t value, int bits);
size_t (* write_boolean)(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen, int value);
} lwm2m_writer_t;
typedef struct lwm2m_reader {
size_t (* read_int)(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len, int32_t *value);
size_t (* read_string)(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len, uint8_t *value, size_t strlen);
size_t (* read_float32fix)(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len, int32_t *value, int bits);
size_t (* read_boolean)(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len, int *value);
} lwm2m_reader_t;
typedef struct lwm2m_value_callback {
int (* read)(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen);
int (* write)(lwm2m_context_t *ctx,
const uint8_t *buffer, size_t len,
uint8_t *outbuf, size_t outlen);
int (* exec)(lwm2m_context_t *ctx, const uint8_t *arg, size_t len,
uint8_t *outbuf, size_t outlen);
} lwm2m_value_callback_t;
#define LWM2M_RESOURCE_TYPE_STR_VALUE 1
#define LWM2M_RESOURCE_TYPE_STR_VARIABLE 2
#define LWM2M_RESOURCE_TYPE_STR_VARIABLE_ARRAY 3
#define LWM2M_RESOURCE_TYPE_INT_VALUE 4
#define LWM2M_RESOURCE_TYPE_INT_VARIABLE 5
#define LWM2M_RESOURCE_TYPE_INT_VARIABLE_ARRAY 6
#define LWM2M_RESOURCE_TYPE_FLOATFIX_VALUE 7
#define LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE 8
#define LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE_ARRAY 9
#define LWM2M_RESOURCE_TYPE_BOOLEAN_VALUE 10
#define LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE 11
#define LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE_ARRAY 12
#define LWM2M_RESOURCE_TYPE_CALLBACK 16
#define LWM2M_RESOURCE_TYPE_INSTANCES 17
typedef struct lwm2m_resource {
uint16_t id;
uint8_t type; /* indicate value type and multi-instance resource */
union {
struct {
uint16_t len;
const uint8_t *value;
} string;
struct {
uint16_t size;
uint16_t *len;
uint8_t **var;
} stringvar;
struct {
uint16_t count;
uint16_t size;
/* string var array with counting entries */
uint16_t *len;
uint8_t *var;
} stringvararr;
struct {
int32_t value;
} integer;
struct {
int32_t *var;
} integervar;
struct {
/* used for multiple instances (dynamic) NOTE: this is an index into
the instance so having two instances means that there is need for
allocation of two ints here */
uint16_t count;
int32_t *var; /* used as an array? */
} integervararr;
struct {
int32_t value;
} floatfix;
struct {
int32_t *var;
} floatfixvar;
struct {
uint16_t count;
int32_t *var;
} floatfixvararr;
struct {
int value;
} boolean;
struct {
int *var;
} booleanvar;
struct {
uint16_t count;
int *var;
} booleanvararr;
lwm2m_value_callback_t callback;
/* lwm2m_resource *resources[]; TO BE ADDED LATER*/
} value;
} lwm2m_resource_t;
#define LWM2M_INSTANCE_FLAG_USED 1
typedef struct lwm2m_instance {
uint16_t id;
uint16_t count;
uint16_t flag;
const lwm2m_resource_t *resources;
} lwm2m_instance_t;
typedef struct lwm2m_object {
uint16_t id;
uint16_t count;
const char *path;
resource_t *coap_resource;
lwm2m_instance_t *instances;
} lwm2m_object_t;
#define LWM2M_RESOURCES(name, ...) \
static const lwm2m_resource_t name[] = { __VA_ARGS__ }
#define LWM2M_RESOURCE_STRING(id, s) \
{ id, LWM2M_RESOURCE_TYPE_STR_VALUE, .value.string.len = sizeof(s) - 1, .value.string.value = (uint8_t *) s }
#define LWM2M_RESOURCE_STRING_VAR(id, s, l, v) \
{ id, LWM2M_RESOURCE_TYPE_STR_VARIABLE, .value.stringvar.size = (s), .value.stringvar.len = (l), .value.stringvar.var = (v) }
#define LWM2M_RESOURCE_STRING_VAR_ARR(id, c, s, l, v) \
{ id, LWM2M_RESOURCE_TYPE_STR_VARIABLE_ARRAY, .value.stringvararr.count = c, .value.stringvararr.size = s, .value.stringvararr.len = l, .value.stringvararr.var = (uint8_t *) v }
#define LWM2M_RESOURCE_INTEGER(id, v) \
{ id, LWM2M_RESOURCE_TYPE_INT_VALUE, .value.integer.value = (v) }
#define LWM2M_RESOURCE_INTEGER_VAR(id, v) \
{ id, LWM2M_RESOURCE_TYPE_INT_VARIABLE, .value.integervar.var = (v) }
#define LWM2M_RESOURCE_INTEGER_VAR_ARR(id, c, v) \
{ id, LWM2M_RESOURCE_TYPE_INT_VARIABLE_ARRAY, .value.integervararr.count = (c), .value.integervararr.var = (v) }
#define LWM2M_RESOURCE_FLOATFIX(id, v) \
{ id, LWM2M_RESOURCE_TYPE_FLOATFIX_VALUE, .value.floatfix.value = (v) }
#define LWM2M_RESOURCE_FLOATFIX_VAR(id, v) \
{ id, LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE, .value.floatfixvar.var = (v) }
#define LWM2M_RESOURCE_FLOATFIX_VAR_ARR(id, c, v) \
{ id, LWM2M_RESOURCE_TYPE_FLOATFIX_VARIABLE_ARRAY, .value.floatfixvararr.count = (c), .value.floatfixvararr.var = (v) }
#define LWM2M_RESOURCE_BOOLEAN(id, v) \
{ id, LWM2M_RESOURCE_TYPE_BOOLEAN_VALUE, .value.boolean.value = (v) }
#define LWM2M_RESOURCE_BOOLEAN_VAR(id, v) \
{ id, LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE, .value.booleanvar.var = (v) }
#define LWM2M_RESOURCE_BOOLEAN_VAR_ARR(id, c, v) \
{ id, LWM2M_RESOURCE_TYPE_BOOLEAN_VARIABLE_ARRAY, .value.booleanvararr.count = (c), .value.booleanvararr.var = (v) }
#define LWM2M_RESOURCE_CALLBACK(id, ...) \
{ id, LWM2M_RESOURCE_TYPE_CALLBACK, .value.callback = __VA_ARGS__ }
#define LWM2M_INSTANCE(id, resources) \
{ id, sizeof(resources)/sizeof(lwm2m_resource_t), LWM2M_INSTANCE_FLAG_USED, resources }
#define LWM2M_INSTANCE_UNUSED(id, resources) \
{ id, sizeof(resources)/sizeof(lwm2m_resource_t), 0, resources }
#define LWM2M_INSTANCES(name, ...) \
static lwm2m_instance_t name[] = { __VA_ARGS__ }
#define LWM2M_OBJECT(name, id, instances) \
static void lwm2m_get_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); \
static void lwm2m_put_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); \
static void lwm2m_post_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); \
static void lwm2m_delete_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset); \
static resource_t rest_rsc_##name = { NULL, NULL, HAS_SUB_RESOURCES | IS_OBSERVABLE, NULL, lwm2m_get_h_##name, lwm2m_post_h_##name, lwm2m_put_h_##name, lwm2m_delete_h_##name, { NULL } }; \
static const lwm2m_object_t name = { id, sizeof(instances)/sizeof(lwm2m_instance_t), LWM2M_OBJECT_PATH_STR(id), &rest_rsc_##name, instances}; \
static void lwm2m_get_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { \
lwm2m_engine_handler(&name, request, response, buffer, preferred_size, offset); } \
static void lwm2m_put_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { \
lwm2m_engine_handler(&name, request, response, buffer, preferred_size, offset); } \
static void lwm2m_post_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { \
lwm2m_engine_handler(&name, request, response, buffer, preferred_size, offset); } \
static void lwm2m_delete_h_##name(void *request, void *response, uint8_t *buffer, uint16_t preferred_size, int32_t *offset) { \
lwm2m_engine_delete_handler(&name, request, response, buffer, preferred_size, offset); }
/* how do we register attributes in the above resource here ??? */
int lwm2m_object_is_resource_string(const lwm2m_resource_t *resource);
int lwm2m_object_is_resource_int(const lwm2m_resource_t *resource);
int lwm2m_object_is_resource_floatfix(const lwm2m_resource_t *resource);
int lwm2m_object_is_resource_boolean(const lwm2m_resource_t *resource);
static inline int
lwm2m_object_is_resource_callback(const lwm2m_resource_t *resource)
{
return resource != NULL && resource->type == LWM2M_RESOURCE_TYPE_CALLBACK;
}
const uint8_t *
lwm2m_object_get_resource_string(const lwm2m_resource_t *resource,
const lwm2m_context_t *context);
uint16_t
lwm2m_object_get_resource_strlen(const lwm2m_resource_t *resource,
const lwm2m_context_t *context);
int
lwm2m_object_set_resource_string(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
uint16_t len, const uint8_t *string);
int
lwm2m_object_get_resource_int(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t *value);
int
lwm2m_object_set_resource_int(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t value);
int
lwm2m_object_get_resource_floatfix(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t *value);
int
lwm2m_object_set_resource_floatfix(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int32_t value);
int
lwm2m_object_get_resource_boolean(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int *value);
int
lwm2m_object_set_resource_boolean(const lwm2m_resource_t *resource,
const lwm2m_context_t *context,
int value);
static inline resource_t *
lwm2m_object_get_coap_resource(const lwm2m_object_t *object)
{
return (resource_t *)object->coap_resource;
}
static inline void
lwm2m_object_notify_observers(const lwm2m_object_t *object, char *path)
{
coap_notify_observers_sub(lwm2m_object_get_coap_resource(object), path);
}
#include "lwm2m-engine.h"
#endif /* LWM2M_OBJECT_H_ */
/**
* @}
* @}
*/

View file

@ -0,0 +1,248 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M plain text reader / writer
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "lwm2m-object.h"
#include "lwm2m-plain-text.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG 0
#if DEBUG
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
size_t
lwm2m_plain_text_read_int(const uint8_t *inbuf, size_t len, int32_t *value)
{
int i, neg = 0;
*value = 0;
for(i = 0; i < len; i++) {
if(inbuf[i] >= '0' && inbuf[i] <= '9') {
*value = *value * 10 + (inbuf[i] - '0');
} else if(inbuf[i] == '-' && i == 0) {
neg = 1;
} else {
break;
}
}
if(neg) {
*value = -*value;
}
return i;
}
/*---------------------------------------------------------------------------*/
size_t
lwm2m_plain_text_read_float32fix(const uint8_t *inbuf, size_t len,
int32_t *value, int bits)
{
int i, dot = 0, neg = 0;
int32_t counter, integerpart, frac;
integerpart = 0;
counter = 0;
frac = 0;
for(i = 0; i < len; i++) {
if(inbuf[i] >= '0' && inbuf[i] <= '9') {
counter = counter * 10 + (inbuf[i] - '0');
frac = frac * 10;
} else if(inbuf[i] == '.' && dot == 0) {
integerpart = counter;
counter = 0;
frac = 1;
dot = 1;
} else if(inbuf[i] == '-' && i == 0) {
neg = 1;
} else {
break;
}
}
*value = integerpart << bits;
if(frac > 1) {
*value += ((counter << bits) / frac);
}
PRINTF("READ FLOATFIX: \"%.*s\" => int(%ld) frac(%ld) f=%ld Value=%ld\n",
(int)len, (char *)inbuf,
(long)integerpart,
(long)counter,
(long)frac,
(long)*value);
if(neg) {
*value = -*value;
}
return i;
}
/*---------------------------------------------------------------------------*/
size_t
lwm2m_plain_text_write_float32fix(uint8_t *outbuf, size_t outlen,
int32_t value, int bits)
{
int64_t v;
unsigned long integer_part;
unsigned long frac_part;
int n, o = 0;
if(outlen == 0) {
return 0;
}
if(value < 0) {
*outbuf++ = '-';
outlen--;
o = 1;
value = -value;
}
integer_part = (unsigned long)(value >> bits);
v = value - (integer_part << bits);
v = (v * 100) >> bits;
frac_part = (unsigned long)v;
n = snprintf((char *)outbuf, outlen, "%lu.%02lu", integer_part, frac_part);
if(n < 0 || n >= outlen) {
return 0;
}
return n + o;
}
/*---------------------------------------------------------------------------*/
static size_t
write_boolean(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int value)
{
if(outlen > 0) {
if(value) {
*outbuf = '1';
} else {
*outbuf = '0';
}
return 1;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static size_t
write_int(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int32_t value)
{
int n = snprintf((char *)outbuf, outlen, "%ld", (long)value);
if(n < 0 || n >= outlen) {
return 0;
}
return n;
}
/*---------------------------------------------------------------------------*/
static size_t
write_float32fix(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int32_t value, int bits)
{
return lwm2m_plain_text_write_float32fix(outbuf, outlen, value, bits);
}
/*---------------------------------------------------------------------------*/
static size_t
write_string(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
const char *value, size_t stringlen)
{
int n = snprintf((char *)outbuf, outlen, "%.*s", (int) stringlen, value);
if(n < 0 || n >= outlen) {
return 0;
}
return n;
}
/*---------------------------------------------------------------------------*/
const lwm2m_writer_t lwm2m_plain_text_writer = {
write_int,
write_string,
write_float32fix,
write_boolean
};
/*---------------------------------------------------------------------------*/
static size_t
read_int(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
int32_t *value)
{
return lwm2m_plain_text_read_int(inbuf, len, value);
}
/*---------------------------------------------------------------------------*/
static size_t
read_string(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
uint8_t *value, size_t stringlen)
{
if(stringlen <= len) {
/* The outbuffer can not contain the full string including ending zero */
return 0;
}
memcpy(value, inbuf, len);
value[len] = '\0';
return len;
}
/*---------------------------------------------------------------------------*/
static size_t
read_float32fix(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
int32_t *value, int bits)
{
return lwm2m_plain_text_read_float32fix(inbuf, len, value, bits);
}
/*---------------------------------------------------------------------------*/
static size_t
read_boolean(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
int *value)
{
if(len > 0) {
if(*inbuf == '1' || *inbuf == '0') {
*value = *inbuf == '1' ? 1 : 0;
return 1;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
const lwm2m_reader_t lwm2m_plain_text_reader = {
read_int,
read_string,
read_float32fix,
read_boolean
};
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,62 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*/
/**
* \file
* Header file for the Contiki OMA LWM2M plain text reader / writer
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef LWM2M_PLAIN_TEXT_H_
#define LWM2M_PLAIN_TEXT_H_
#include "lwm2m-object.h"
extern const lwm2m_reader_t lwm2m_plain_text_reader;
extern const lwm2m_writer_t lwm2m_plain_text_writer;
size_t lwm2m_plain_text_read_int(const uint8_t *inbuf, size_t len,
int32_t *value);
size_t lwm2m_plain_text_read_float32fix(const uint8_t *inbuf, size_t len,
int32_t *value, int bits);
size_t lwm2m_plain_text_write_float32fix(uint8_t *outbuf, size_t outlen,
int32_t value, int bits);
#endif /* LWM2M_PLAIN_TEXT_H_ */
/** @} */

View file

@ -0,0 +1,112 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M security
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include <stdint.h>
#include "lwm2m-object.h"
#include "lwm2m-engine.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#ifdef LWM2M_CONF_SERVER_MAX_COUNT
#define MAX_COUNT LWM2M_CONF_SERVER_MAX_COUNT
#else
#define MAX_COUNT 2
#endif
/* hoping that we do not get more than 64 bytes... */
#define MAX_SIZE 64
static int32_t bs_arr[MAX_COUNT];
static int32_t secmode_arr[MAX_COUNT];
static int32_t sid_arr[MAX_COUNT];
static char server_uri[MAX_COUNT][MAX_SIZE];
static uint16_t su_len[MAX_COUNT];
static char client_id[MAX_COUNT][MAX_SIZE];
static uint16_t client_id_len[MAX_COUNT];
static char server_id[MAX_COUNT][MAX_SIZE];
static uint16_t server_id_len[MAX_COUNT];
static char psk_key[MAX_COUNT][MAX_SIZE];
static uint16_t psk_key_len[MAX_COUNT];
static lwm2m_instance_t security_instances[MAX_COUNT];
LWM2M_RESOURCES(security_resources,
LWM2M_RESOURCE_STRING_VAR_ARR(0, MAX_COUNT, MAX_SIZE, su_len, server_uri),
LWM2M_RESOURCE_INTEGER_VAR_ARR(1, MAX_COUNT, bs_arr),
LWM2M_RESOURCE_INTEGER_VAR_ARR(2, MAX_COUNT, secmode_arr),
LWM2M_RESOURCE_STRING_VAR_ARR(3, MAX_COUNT, MAX_SIZE, client_id_len, client_id),
LWM2M_RESOURCE_STRING_VAR_ARR(4, MAX_COUNT, MAX_SIZE, server_id_len, server_id),
/* TODO This should not be readable! */
LWM2M_RESOURCE_STRING_VAR_ARR(5, MAX_COUNT, MAX_SIZE, psk_key_len, psk_key),
LWM2M_RESOURCE_INTEGER_VAR_ARR(10, MAX_COUNT, sid_arr)
);
LWM2M_OBJECT(security, 0, security_instances);
/*---------------------------------------------------------------------------*/
void
lwm2m_security_init(void)
{
lwm2m_instance_t template = LWM2M_INSTANCE_UNUSED(0, security_resources);
int i;
/* Initialize the instances */
for(i = 0; i < MAX_COUNT; i++) {
security_instances[i] = template;
security_instances[i].id = i;
}
/**
* Register this device and its handlers - the handlers
* automatically sends in the object to handle.
*/
PRINTF("*** Init lwm2m-security\n");
lwm2m_engine_register_object(&security);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,93 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M server
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include <stdint.h>
#include "lwm2m-object.h"
#include "lwm2m-engine.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
#ifdef LWM2M_CONF_SERVER_MAX_COUNT
#define MAX_COUNT LWM2M_CONF_SERVER_MAX_COUNT
#else
#define MAX_COUNT 2
#endif
static int32_t sid_arr[MAX_COUNT];
static int32_t lifetime_arr[MAX_COUNT];
static lwm2m_instance_t server_instances[MAX_COUNT];
LWM2M_RESOURCES(server_resources,
LWM2M_RESOURCE_INTEGER_VAR_ARR(0, MAX_COUNT, sid_arr),
LWM2M_RESOURCE_INTEGER_VAR_ARR(1, MAX_COUNT, lifetime_arr),
);
LWM2M_OBJECT(server, 1, server_instances);
/*---------------------------------------------------------------------------*/
void
lwm2m_server_init(void)
{
lwm2m_instance_t template = LWM2M_INSTANCE_UNUSED(0, server_resources);
int i;
/* Initialize the instances */
for(i = 0; i < MAX_COUNT; i++) {
server_instances[i] = template;
server_instances[i].id = i;
}
/**
* Register this device and its handlers - the handlers
* automatically sends in the object to handle
*/
PRINTF("*** Init lwm2m-server\n");
lwm2m_engine_register_object(&server);
}
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,114 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M TLV reader
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "lwm2m-object.h"
#include "oma-tlv-reader.h"
#include "oma-tlv.h"
/*---------------------------------------------------------------------------*/
static size_t
read_int(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
int32_t *value)
{
oma_tlv_t tlv;
size_t size;
size = oma_tlv_read(&tlv, inbuf, len);
if(size > 0) {
*value = oma_tlv_get_int32(&tlv);
}
return size;
}
/*---------------------------------------------------------------------------*/
static size_t
read_string(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
uint8_t *value, size_t stringlen)
{
oma_tlv_t tlv;
size_t size;
size = oma_tlv_read(&tlv, inbuf, len);
if(size > 0) {
if(stringlen <= tlv.length) {
/* The outbuffer can not contain the full string including ending zero */
return 0;
}
memcpy(value, tlv.value, tlv.length);
value[tlv.length] = '\0';
}
return size;
}
/*---------------------------------------------------------------------------*/
static size_t
read_float32fix(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
int32_t *value, int bits)
{
oma_tlv_t tlv;
size_t size;
size = oma_tlv_read(&tlv, inbuf, len);
if(size > 0) {
oma_tlv_float32_to_fix(&tlv, value, bits);
}
return size;
}
/*---------------------------------------------------------------------------*/
static size_t
read_boolean(const lwm2m_context_t *ctx, const uint8_t *inbuf, size_t len,
int *value)
{
oma_tlv_t tlv;
size_t size;
size = oma_tlv_read(&tlv, inbuf, len);
if(size > 0) {
*value = oma_tlv_get_int32(&tlv) != 0;
}
return size;
}
/*---------------------------------------------------------------------------*/
const lwm2m_reader_t oma_tlv_reader = {
read_int,
read_string,
read_float32fix,
read_boolean
};
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/** \addtogroup oma-lwm2m
* @{ */
/**
* \file
* Header file for the Contiki OMA LWM2M TLV reader
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef OMA_TLV_READER_H_
#define OMA_TLV_READER_H_
#include "lwm2m-object.h"
extern const lwm2m_reader_t oma_tlv_reader;
#endif /* OMA_TLV_READER_H_ */
/** @} */

View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M TLV writer
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "lwm2m-object.h"
#include "oma-tlv.h"
/*---------------------------------------------------------------------------*/
static size_t
write_boolean_tlv(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int value)
{
return oma_tlv_write_int32(ctx->resource_id, value != 0 ? 1 : 0,
outbuf, outlen);
}
/*---------------------------------------------------------------------------*/
static size_t
write_int_tlv(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
int32_t value)
{
return oma_tlv_write_int32(ctx->resource_id, value, outbuf, outlen);
}
/*---------------------------------------------------------------------------*/
static size_t
write_float32fix_tlv(const lwm2m_context_t *ctx, uint8_t *outbuf,
size_t outlen, int32_t value, int bits)
{
return oma_tlv_write_float32(ctx->resource_id, value, bits, outbuf, outlen);
}
/*---------------------------------------------------------------------------*/
static size_t
write_string_tlv(const lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
const char *value, size_t stringlen)
{
oma_tlv_t tlv;
tlv.type = OMA_TLV_TYPE_RESOURCE;
tlv.value = (uint8_t *) value;
tlv.length = (uint32_t) stringlen;
tlv.id = ctx->resource_id;
return oma_tlv_write(&tlv, outbuf, outlen);
}
/*---------------------------------------------------------------------------*/
const lwm2m_writer_t oma_tlv_writer = {
write_int_tlv,
write_string_tlv,
write_float32fix_tlv,
write_boolean_tlv
};
/*---------------------------------------------------------------------------*/
/** @} */

View file

@ -0,0 +1,50 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/** \addtogroup oma-lwm2m
* @{ */
/**
* \file
* Header file for the Contiki OMA LWM2M TLV writer
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef OMA_TLV_WRITER_H_
#define OMA_TLV_WRITER_H_
#include "lwm2m-object.h"
extern const lwm2m_writer_t oma_tlv_writer;
#endif /* OMA_TLV_WRITER_H_ */
/** @} */

296
apps/oma-lwm2m/oma-tlv.c Normal file
View file

@ -0,0 +1,296 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \addtogroup oma-lwm2m
* @{
*
*/
/**
* \file
* Implementation of the Contiki OMA LWM2M TLV
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include <string.h>
#include <stdint.h>
#include "oma-tlv.h"
#define DEBUG 0
#if DEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
#else
#define PRINTF(...)
#endif
/*---------------------------------------------------------------------------*/
static inline uint8_t
get_len_type(const oma_tlv_t *tlv)
{
if(tlv->length < 8) {
return 0;
} else if(tlv->length < 256) {
return 1;
} else if(tlv->length < 0x10000) {
return 2;
} else {
return 3;
}
}
/*---------------------------------------------------------------------------*/
size_t
oma_tlv_read(oma_tlv_t *tlv, const uint8_t *buffer, size_t len)
{
uint8_t len_type;
uint8_t len_pos = 1;
size_t tlv_len;
tlv->type = (buffer[0] >> 6) & 3;
len_type = (buffer[0] >> 3) & 3;
len_pos = 1 + (((buffer[0] & (1 << 5)) != 0) ? 2 : 1);
tlv->id = buffer[1];
/* if len_pos is larger than two it means that there is more ID to read */
if(len_pos > 2) {
tlv->id = (tlv->id << 8) + buffer[2];
}
if(len_type == 0) {
tlv_len = buffer[0] & 7;
} else {
/* read the length */
tlv_len = 0;
while(len_type > 0) {
tlv_len = tlv_len << 8 | buffer[len_pos++];
len_type--;
}
}
/* and read out the data??? */
tlv->length = tlv_len;
tlv->value = &buffer[len_pos];
return len_pos + tlv_len;
}
/*---------------------------------------------------------------------------*/
size_t
oma_tlv_get_size(const oma_tlv_t *tlv)
{
size_t size;
/* first hdr + len size */
size = 1 + get_len_type(tlv);
/* id size */
size += (tlv->id > 255) ? 2 : 1;
/* and the length */
size += tlv->length;
return size;
}
/*---------------------------------------------------------------------------*/
size_t
oma_tlv_write(const oma_tlv_t *tlv, uint8_t *buffer, size_t len)
{
int pos;
uint8_t len_type;
/* len type is the same as number of bytes required for length */
len_type = get_len_type(tlv);
pos = 1 + len_type;
/* ensure that we do not write too much */
if(len < tlv->length + pos) {
PRINTF("OMA-TLV: Could not write the TLV - buffer overflow.\n");
return 0;
}
/* first type byte in TLV header */
buffer[0] = (tlv->type << 6) |
(tlv->id > 255 ? (1 << 5) : 0) |
(len_type << 3) |
(len_type == 0 ? tlv->length : 0);
pos = 1;
/* The ID */
if(tlv->id > 255) {
buffer[pos++] = (tlv->id >> 8) & 0xff;
}
buffer[pos++] = tlv->id & 0xff;
/* Add length if needed - unrolled loop ? */
if(len_type > 2) {
buffer[pos++] = (tlv->length >> 16) & 0xff;
}
if(len_type > 1) {
buffer[pos++] = (tlv->length >> 8) & 0xff;
}
if(len_type > 0) {
buffer[pos++] = tlv->length & 0xff;
}
/* finally add the value */
memcpy(&buffer[pos], tlv->value, tlv->length);
if(DEBUG) {
int i;
PRINTF("TLV:");
for(i = 0; i < pos + tlv->length; i++) {
PRINTF("%02x", buffer[i]);
}
PRINTF("\n");
}
return pos + tlv->length;
}
/*---------------------------------------------------------------------------*/
int32_t
oma_tlv_get_int32(const oma_tlv_t *tlv)
{
int i;
int32_t value = 0;
/* will probably need to handle MSB as a sign bit? */
for(i = 0; i < tlv->length; i++) {
value = (value << 8) | tlv->value[i];
}
return value;
}
/*---------------------------------------------------------------------------*/
size_t
oma_tlv_write_int32(int16_t id, int32_t value, uint8_t *buffer, size_t len)
{
oma_tlv_t tlv;
size_t tlvlen = 0;
uint8_t buf[4];
int i;
PRINTF("Exporting int32 %d %ld ", id, (long)value);
buf[3] = value & 0xff;
value = value >> 8;
for(i = 1; value > 0 && i < 4; i++) {
buf[3 - i] = value & 0xff;
value = value >> 8;
}
tlvlen = i;
/* export INT as TLV */
PRINTF("len: %zu\n", tlvlen);
tlv.type = OMA_TLV_TYPE_RESOURCE;
tlv.length = tlvlen;
tlv.value = &buf[3 - (tlvlen - 1)];
tlv.id = id;
return oma_tlv_write(&tlv, buffer, len);
}
/*---------------------------------------------------------------------------*/
/* convert fixpoint 32-bit to a IEEE Float in the byte array*/
size_t
oma_tlv_write_float32(int16_t id, int32_t value, int bits,
uint8_t *buffer, size_t len)
{
int i;
int e = 0;
int32_t val = 0;
int32_t v;
uint8_t b[4];
oma_tlv_t tlv;
v = value;
if(v < 0) {
v = -v;
}
while(v > 1) {
val = (val >> 1);
if (v & 1) {
val = val | (1L << 22);
}
v = (v >> 1);
e++;
}
PRINTF("Sign: %d, Fraction: %06lx 0b", value < 0, (long)val);
for(i = 0; i < 23; i++) {
PRINTF("%d", (int)((val >> (22 - i)) & 1));
}
PRINTF("\nExp:%d\n", e);
/* convert to the thing we should have */
e = e - bits + 127;
/* is this the right byte order? */
b[0] = (value < 0 ? 0x80 : 0) | (e >> 1);
b[1] = ((e & 1) << 7) | ((val >> 16) & 0x7f);
b[2] = (val >> 8) & 0xff;
b[3] = val & 0xff;
/* construct the TLV */
tlv.type = OMA_TLV_TYPE_RESOURCE;
tlv.length = 4;
tlv.value = b;
tlv.id = id;
return oma_tlv_write(&tlv, buffer, len);
}
/*---------------------------------------------------------------------------*/
/* convert float to fixpoint */
size_t
oma_tlv_float32_to_fix(const oma_tlv_t *tlv, int32_t *value, int bits)
{
/* TLV needs to be 4 bytes */
int e, i;
int32_t val;
int sign = (tlv->value[0] & 0x80) != 0;
e = ((tlv->value[0] << 1) & 0xff) | (tlv->value[1] >> 7);
val = (((long)tlv->value[1] & 0x7f) << 16) | (tlv->value[2] << 8) | tlv->value[3];
PRINTF("Sign: %d, Fraction: %06lx 0b", val < 0, (long)val);
for(i = 0; i < 23; i++) {
PRINTF("%d", (int)((val >> (22 - i)) & 1));
}
PRINTF("\nExp:%d => %d\n", e, e - 127);
e = e - 127 + bits;
/* e corresponds to the number of times we need to roll the number */
PRINTF("Actual e=%d\n", e);
e = e - 23;
PRINTF("E after sub %d\n", e);
val = val | 1L << 23;
if(e > 0) {
val = val << e;
} else {
val = val >> -e;
}
*value = sign ? -val : val;
return 4;
}
/*---------------------------------------------------------------------------*/
/** @} */

89
apps/oma-lwm2m/oma-tlv.h Normal file
View file

@ -0,0 +1,89 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/** \addtogroup oma-lwm2m
* @{ */
/**
* \file
* Header file for the Contiki OMA LWM2M TLV
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef OAM_TLV_H_
#define OAM_TLV_H_
#include "contiki.h"
enum {
OMA_TLV_TYPE_OBJECT_INSTANCE = 0,
OMA_TLV_TYPE_RESOURCE_INSTANCE = 1,
OMA_TLV_TYPE_MULTI_RESOURCE = 2,
OMA_TLV_TYPE_RESOURCE = 3
};
typedef uint8_t oma_tlv_type_t;
typedef enum {
OMA_TLV_LEN_TYPE_NO_LEN = 0,
OMA_TLV_LEN_TYPE_8BIT_LEN = 1,
OMA_TLV_LEN_TYPE_16BIT_LEN = 2,
OMA_TLV_LEN_TYPE_24BIT_LEN = 3
} oma_tlv_len_type_t;
typedef struct {
oma_tlv_type_t type;
uint16_t id; /* can be 8-bit or 16-bit when serialized */
uint32_t length;
const uint8_t *value;
} oma_tlv_t;
size_t oma_tlv_get_size(const oma_tlv_t *tlv);
/* read a TLV from the buffer */
size_t oma_tlv_read(oma_tlv_t *tlv, const uint8_t *buffer, size_t len);
/* write a TLV to the buffer */
size_t oma_tlv_write(const oma_tlv_t *tlv, uint8_t *buffer, size_t len);
int32_t oma_tlv_get_int32(const oma_tlv_t *tlv);
/* write a int as a TLV to the buffer */
size_t oma_tlv_write_int32(int16_t id, int32_t value, uint8_t *buffer, size_t len);
/* write a float converted from fixpoint as a TLV to the buffer */
size_t oma_tlv_write_float32(int16_t id, int32_t value, int bits, uint8_t *buffer, size_t len);
/* convert TLV with float32 to fixpoint */
size_t oma_tlv_float32_to_fix(const oma_tlv_t *tlv, int32_t *value, int bits);
#endif /* OAM_TLV_H_ */
/** @} */

View file

@ -0,0 +1,29 @@
CONTIKI_PROJECT = example-ipso-objects
CONTIKI_SOURCEFILES += serial-protocol.c example-ipso-temperature.c
all: $(CONTIKI_PROJECT)
CFLAGS += -DPROJECT_CONF_H=\"project-conf.h\"
APPS += rest-engine
APPS += er-coap
APPS += oma-lwm2m
APPS += ipso-objects
CONTIKI=../..
CONTIKI_WITH_IPV6 = 1
include $(CONTIKI)/Makefile.include
# 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 -p 60001 aaaa::1/64
connect-router-native: $(CONTIKI)/examples/ipv6/native-border-router/border-router.native
sudo $(CONTIKI)/exmples/ipv6/native-border-router/border-router.native -a 127.0.0.1 -p 60001 aaaa::1/64

View file

@ -0,0 +1,48 @@
IPSO Objects Example
============================================
This is an example of how to make use of the IPSO Object and LWM2M
implementation in Contiki.
The LWM2M implementation is based on the Erbium CoAP implementation
and consists of two apps: lwm2m-engine and ipso-objects. The
lwm2m-engine handle the specifics of LWM2M including bootstrapping and
how read/writes of objects and resources are handled. The ipso-objects
contains implementations of some of the IPSO Smart Objects.
The implementation was used during the IPSO Interop in May 2015,
Kista, Sweden, and was successfully tested with other
implementations.
The examples use some of the basic IPSO object for controlling LEDs on
Contiki devices and for reading out temperature.
##Testing IPSO-objects with Leshan
First program a device with the examples/ipso-objects/example-ipso-objects.c
```bash
>make example-ipso-objects.upload TARGET=zoul
>...
```
After that start up a native-border router or other border router on aaaa::1/64
or another prefix - NOTE: if you use another prefix you will need to change LWM2M_SERVER_ADDRESS for which the device will register - in project-conf.h:
```
#define LWM2M_SERVER_ADDRESS "aaaa::1"
```
Then when everything is setup you can download a Leshan and use that to
test controlling LEDs of the device.
###Starting Leshan
```bash
wget https://hudson.eclipse.org/leshan/job/leshan/lastSuccessfulBuild/artifact/leshan-standalone.jar
java -jar ./leshan-standalone.jar
```
Browse to leshans device page with http://127.0.0.1:8080 .
When you have started the border-router and also Leshan you should now
start (or reboot) your IPSO Object enabled device. Within 30 seconds
you should be able to see it on the Leshan device page.

View file

@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>LWM2M &amp; IPSO Objects Example</title>
<speedlimit>1.0</speedlimit>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>50.0</transmitting_range>
<interference_range>100.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.mspmote.WismoteMoteType
<identifier>wismote1</identifier>
<description>Wismote Border Router #border-router</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.c</source>
<commands EXPORT="discard">make border-router.wismote TARGET=wismote DEFINES=NETSTACK_RDC=nullrdc_driver,NETSTACK_MAC=nullmac_driver</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipv6/rpl-border-router/border-router.wismote</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
</motetype>
<motetype>
org.contikios.cooja.mspmote.WismoteMoteType
<identifier>wismote2</identifier>
<description>Wismote IPSO Objects #ipso-example</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipso-objects/example-ipso-objects.c</source>
<commands EXPORT="discard">make example-ipso-objects.wismote TARGET=wismote</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipso-objects/example-ipso-objects.wismote</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>56.362361976162035</x>
<y>11.826023799100883</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<motetype_identifier>wismote1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>60.1539674439426</x>
<y>11.827942168467365</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>wismote2</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>280</width>
<z>2</z>
<height>160</height>
<location_x>400</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Visualizer
<plugin_config>
<moterelations>true</moterelations>
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.LEDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.MoteTypeVisualizerSkin</skin>
<viewport>53.336918739504526 0.0 0.0 53.336918739504526 -2924.9161170527295 -473.3614543395965</viewport>
</plugin_config>
<width>400</width>
<z>4</z>
<height>400</height>
<location_x>1</location_x>
<location_y>1</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter>ID:2</filter>
<formatted_time />
<coloring />
</plugin_config>
<width>1286</width>
<z>1</z>
<height>240</height>
<location_x>400</location_x>
<location_y>160</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Notes
<plugin_config>
<notes>OMA LWM2M &amp; IPSO Object example
1. Start a LWM2M server, for example Leshan
2. Run the example and bridge Cooja using tunslip with the prefix aaaa::1/64:
(cd contiki/examples/ipso-objects &amp;&amp; make connect-router-cooja)
After a short time, the example node should register with the LWM2M server at [aaaa::1]:5683.</notes>
<decorations>true</decorations>
</plugin_config>
<width>1006</width>
<z>0</z>
<height>160</height>
<location_x>680</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.serialsocket.SerialSocketServer
<mote_arg>0</mote_arg>
<plugin_config>
<port>60001</port>
<bound>true</bound>
</plugin_config>
<width>362</width>
<z>3</z>
<height>116</height>
<location_x>1</location_x>
<location_y>399</location_y>
</plugin>
</simconf>

View file

@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8"?>
<simconf>
<project EXPORT="discard">[APPS_DIR]/mrm</project>
<project EXPORT="discard">[APPS_DIR]/mspsim</project>
<project EXPORT="discard">[APPS_DIR]/avrora</project>
<project EXPORT="discard">[APPS_DIR]/serial_socket</project>
<project EXPORT="discard">[APPS_DIR]/collect-view</project>
<project EXPORT="discard">[APPS_DIR]/powertracker</project>
<simulation>
<title>OMA LWM2M and IPSO Object example</title>
<speedlimit>2.0</speedlimit>
<randomseed>123456</randomseed>
<motedelay_us>1000000</motedelay_us>
<radiomedium>
org.contikios.cooja.radiomediums.UDGM
<transmitting_range>500.0</transmitting_range>
<interference_range>500.0</interference_range>
<success_ratio_tx>1.0</success_ratio_tx>
<success_ratio_rx>1.0</success_ratio_rx>
</radiomedium>
<events>
<logoutput>40000</logoutput>
</events>
<motetype>
org.contikios.cooja.mspmote.WismoteMoteType
<identifier>wismote1</identifier>
<description>Wismote Router #wismote1</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipso-objects/example-server.c</source>
<commands EXPORT="discard">make example-server.wismote TARGET=wismote</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipso-objects/example-server.wismote</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
</motetype>
<motetype>
org.contikios.cooja.mspmote.WismoteMoteType
<identifier>wismote2</identifier>
<description>Wismote Mote Type #wismote2</description>
<source EXPORT="discard">[CONTIKI_DIR]/examples/ipso-objects/example-ipso-objects.c</source>
<commands EXPORT="discard">make example-ipso-objects.wismote TARGET=wismote</commands>
<firmware EXPORT="copy">[CONTIKI_DIR]/examples/ipso-objects/example-ipso-objects.wismote</firmware>
<moteinterface>org.contikios.cooja.interfaces.Position</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.RimeAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.IPAddress</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.Mote2MoteRelations</moteinterface>
<moteinterface>org.contikios.cooja.interfaces.MoteAttributes</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspClock</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspMoteID</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspButton</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.Msp802154Radio</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDefaultSerial</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspLED</moteinterface>
<moteinterface>org.contikios.cooja.mspmote.interfaces.MspDebugOutput</moteinterface>
</motetype>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>30.243188653185154</x>
<y>29.963547412144486</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>1</id>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspDefaultSerial
<history>s aaaa::200:0:0:3 /3311/0/5850 0~;s aaaa::200:0:0:3 /3311/0/5850 1~;g aaaa::200:0:0:3 /3311/1/5850~;g aaaa::200:0:0:3 /3311/0/5850~;g aaaa::200:0:0:3 /3311/1/5850~;g aaaa::200:0:0:3 /3311/0/5850~;s aaaa::200:0:0:3 /3311/0/5850 1~;s aaaa::200:0:0:2 /3311/0/5850 1~;h~;s aaaa::200:0:0:2 /3311/0/5850 1~;s aaaa::200:0:0:2 /3311/0/5850 0~;g aaaa::200:0:0:2 /3311/0/5850~;g aaaa::200:0:0:2 /3311/1/5850~;g aaaa::200:0:0:2 /3311/2/5850~;l~;</history>
</interface_config>
<motetype_identifier>wismote1</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>59.75123136831088</x>
<y>29.84506209179908</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>2</id>
</interface_config>
<motetype_identifier>wismote2</motetype_identifier>
</mote>
<mote>
<breakpoints />
<interface_config>
org.contikios.cooja.interfaces.Position
<x>60.30742753391745</x>
<y>59.35092511889063</y>
<z>0.0</z>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspClock
<deviation>1.0</deviation>
</interface_config>
<interface_config>
org.contikios.cooja.mspmote.interfaces.MspMoteID
<id>3</id>
</interface_config>
<motetype_identifier>wismote2</motetype_identifier>
</mote>
</simulation>
<plugin>
org.contikios.cooja.plugins.SimControl
<width>280</width>
<z>0</z>
<height>160</height>
<location_x>400</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Visualizer
<plugin_config>
<moterelations>true</moterelations>
<skin>org.contikios.cooja.plugins.skins.IDVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.GridVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.TrafficVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.UDGMVisualizerSkin</skin>
<skin>org.contikios.cooja.plugins.skins.LEDVisualizerSkin</skin>
<viewport>4.593848158957425 0.0 0.0 4.593848158957425 13.734375417550426 -121.37641081710846</viewport>
</plugin_config>
<width>400</width>
<z>3</z>
<height>400</height>
<location_x>1</location_x>
<location_y>1</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.LogListener
<plugin_config>
<filter />
<formatted_time />
<coloring />
</plugin_config>
<width>959</width>
<z>2</z>
<height>447</height>
<location_x>400</location_x>
<location_y>160</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.Notes
<plugin_config>
<notes>Enter notes here</notes>
<decorations>true</decorations>
</plugin_config>
<width>679</width>
<z>1</z>
<height>160</height>
<location_x>680</location_x>
<location_y>0</location_y>
</plugin>
<plugin>
org.contikios.cooja.plugins.MoteInterfaceViewer
<mote_arg>0</mote_arg>
<plugin_config>
<interface>Serial port</interface>
<scrollpos>0,0</scrollpos>
</plugin_config>
<width>579</width>
<z>4</z>
<height>300</height>
<location_x>49</location_x>
<location_y>414</location_y>
</plugin>
</simconf>

View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*
*/
/**
* \file
* OMA LWM2M and IPSO Objects example.
* \author
* Joakim Eriksson, joakime@sics.se
* Niclas Finne, nfi@sics.se
*/
#include "contiki.h"
#include "lwm2m-engine.h"
#include "ipso-objects.h"
#define DEBUG DEBUG_NONE
#include "net/ip/uip-debug.h"
#ifndef REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER
#define REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER 0
#endif
#ifndef REGISTER_WITH_LWM2M_SERVER
#define REGISTER_WITH_LWM2M_SERVER 1
#endif
#ifndef LWM2M_SERVER_ADDRESS
#define LWM2M_SERVER_ADDRESS "aaaa::1"
#endif
PROCESS(example_ipso_objects, "IPSO object example");
AUTOSTART_PROCESSES(&example_ipso_objects);
/*---------------------------------------------------------------------------*/
static void
setup_lwm2m_servers(void)
{
#ifdef LWM2M_SERVER_ADDRESS
uip_ipaddr_t addr;
if(uiplib_ipaddrconv(LWM2M_SERVER_ADDRESS, &addr)) {
lwm2m_engine_register_with_bootstrap_server(&addr, 0);
lwm2m_engine_register_with_server(&addr, 0);
}
#endif /* LWM2M_SERVER_ADDRESS */
lwm2m_engine_use_bootstrap_server(REGISTER_WITH_LWM2M_BOOTSTRAP_SERVER);
lwm2m_engine_use_registration_server(REGISTER_WITH_LWM2M_SERVER);
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(example_ipso_objects, ev, data)
{
PROCESS_BEGIN();
PROCESS_PAUSE();
PRINTF("Starting IPSO objects example\n");
/* Initialize the OMA LWM2M engine */
lwm2m_engine_init();
/* Register default LWM2M objects */
lwm2m_engine_register_default_objects();
/* Register default IPSO objects */
ipso_objects_init();
setup_lwm2m_servers();
while(1) {
PROCESS_WAIT_EVENT();
}
PROCESS_END();
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \file
* An dummy temperature driver as example
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "ipso-objects.h"
#include "lib/random.h"
static int32_t last_value = 27000;
/*---------------------------------------------------------------------------*/
static int
read_value(int32_t *value)
{
last_value = last_value + (random_rand() % 1000) - 500;
if(last_value < 18000) {
last_value = 18000;
} else if(last_value > 35000) {
last_value = 35000;
}
*value = last_value;
return 0;
}
/*---------------------------------------------------------------------------*/
const struct ipso_objects_sensor example_ipso_temperature = {
.read_value = read_value
};
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,392 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*
*/
/**
* \file
* IPSO Objects and OMA LWM2M example.
* \author
* Joakim Eriksson, joakime@sics.se
* Niclas Finne, nfi@sics.se
*/
#include "contiki.h"
#include "net/ip/uip.h"
#include "net/rpl/rpl.h"
#include "net/netstack.h"
#include "er-coap-constants.h"
#include "er-coap-engine.h"
#include "lwm2m-engine.h"
#include "oma-tlv.h"
#include "dev/serial-line.h"
#include "serial-protocol.h"
#if CONTIKI_TARGET_WISMOTE
#include "dev/uart1.h"
#endif
#define DEBUG DEBUG_PRINT
#include "net/ip/uip-debug.h"
#define REMOTE_PORT UIP_HTONS(COAP_DEFAULT_PORT)
#define URL_WELL_KNOWN ".well-known/core"
#define URL_DEVICE_MODEL "/3/0/1"
#define URL_DEVICE_FIRMWARE_VERSION "/3/0/3"
#define URL_LIGHT_CONTROL "/3311/0/5850"
#define URL_POWER_CONTROL "/3312/0/5850"
#define MAX_NODES 10
#define NODE_HAS_TYPE (1 << 0)
struct node {
uip_ipaddr_t ipaddr;
char type[32];
uint8_t flags;
uint8_t retries;
};
static struct node nodes[MAX_NODES];
static uint8_t node_count;
static struct node *current_target;
static char current_uri[32] = URL_LIGHT_CONTROL;
static char current_value[32] = "1";
static int current_request = COAP_PUT;
static uint8_t fetching_type = 0;
PROCESS(router_process, "router process");
AUTOSTART_PROCESSES(&router_process);
/*---------------------------------------------------------------------------*/
static struct node *
add_node(const uip_ipaddr_t *addr)
{
int i;
for(i = 0; i < node_count; i++) {
if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) {
/* Node already added */
return &nodes[i];
}
}
if(node_count < MAX_NODES) {
uip_ipaddr_copy(&nodes[node_count].ipaddr, addr);
return &nodes[node_count++];
}
return NULL;
}
/*---------------------------------------------------------------------------*/
void
set_value(const uip_ipaddr_t *addr, char *uri, char *value)
{
int i;
printf("#set value ");
uip_debug_ipaddr_print(addr);
printf(" URI: %s Value: %s\n", uri, value);
for(i = 0; i < node_count; i++) {
if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) {
/* setup command */
current_target = &nodes[i];
current_request = COAP_PUT;
strncpy(current_uri, uri, sizeof(current_uri) - 1);
strncpy(current_value, value, sizeof(current_value) - 1);
process_poll(&router_process);
break;
}
}
}
/*---------------------------------------------------------------------------*/
void
get_value(const uip_ipaddr_t *addr, char *uri)
{
int i;
printf("#get value ");
uip_debug_ipaddr_print(addr);
printf(" URI: %s\n", uri);
for(i = 0; i < node_count; i++) {
if(uip_ipaddr_cmp(&nodes[i].ipaddr, addr)) {
/* setup command */
current_target = &nodes[i];
current_request = COAP_GET;
strncpy(current_uri, uri, sizeof(current_uri) - 1);
current_value[0] = 0;
process_poll(&router_process);
break;
}
}
}
/*---------------------------------------------------------------------------*/
void
print_node_list(void)
{
int i;
int out = 0;
for(i = 0; i < node_count; i++) {
if(nodes[i].flags & NODE_HAS_TYPE) {
if(out++) {
printf(";");
}
printf("%s,", nodes[i].type);
uip_debug_ipaddr_print(&nodes[i].ipaddr);
}
}
printf("\n");
}
/*---------------------------------------------------------------------------*/
/**
* This function is will be passed to COAP_BLOCKING_REQUEST() to
* handle responses.
*/
static void
client_chunk_handler(void *response)
{
const uint8_t *chunk;
unsigned int format;
int len = coap_get_payload(response, &chunk);
coap_get_header_content_format(response, &format);
/* if(len > 0) { */
/* printf("|%.*s (%d,%d)", len, (char *)chunk, len, format); */
/* } */
if(current_target != NULL && fetching_type) {
if(len > sizeof(current_target->type) - 1) {
len = sizeof(current_target->type) - 1;
}
memcpy(current_target->type, chunk, len);
current_target->type[len] = 0;
current_target->flags |= NODE_HAS_TYPE;
PRINTF("\nNODE ");
PRINT6ADDR(&current_target->ipaddr);
PRINTF(" HAS TYPE %s\n", current_target->type);
} else {
/* otherwise update the current value */
if(format == LWM2M_TLV) {
oma_tlv_t tlv;
/* we can only read int32 for now ? */
if(oma_tlv_read(&tlv, chunk, len) > 0) {
/* printf("TLV.type=%d len=%d id=%d value[0]=%d\n", */
/* tlv.type, tlv.length, tlv.id, tlv.value[0]); */
int value = oma_tlv_get_int32(&tlv);
snprintf(current_value, sizeof(current_value), "%d", value);
}
} else {
if(len > sizeof(current_value) - 1) {
len = sizeof(current_value) - 1;
}
memcpy(current_value, chunk, len);
current_value[len] = 0;
}
}
}
/*---------------------------------------------------------------------------*/
static void
setup_network(void)
{
uip_ipaddr_t ipaddr;
struct uip_ds6_addr *root_if;
rpl_dag_t *dag;
int i;
uint8_t state;
#if CONTIKI_TARGET_WISMOTE
uart1_set_input(serial_line_input_byte);
serial_line_init();
#endif
#if UIP_CONF_ROUTER
/**
* The choice of server address determines its 6LoWPAN header compression.
* Obviously the choice made here must also be selected in udp-client.c.
*
* For correct Wireshark decoding using a sniffer, add the /64 prefix to the 6LowPAN protocol preferences,
* e.g. set Context 0 to aaaa::. At present Wireshark copies Context/128 and then overwrites it.
* (Setting Context 0 to aaaa::1111:2222:3333:4444 will report a 16 bit compressed address of aaaa::1111:22ff:fe33:xxxx)
* Note Wireshark's IPCMV6 checksum verification depends on the correct uncompressed addresses.
*/
#if 0
/* Mode 1 - 64 bits inline */
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 1);
#elif 1
/* Mode 2 - 16 bits inline */
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0x00ff, 0xfe00, 1);
#else
/* Mode 3 - derived from link local (MAC) address */
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
uip_ds6_set_addr_iid(&ipaddr, &uip_lladdr);
#endif
uip_ds6_addr_add(&ipaddr, 0, ADDR_MANUAL);
root_if = uip_ds6_addr_lookup(&ipaddr);
if(root_if != NULL) {
dag = rpl_set_root(RPL_DEFAULT_INSTANCE, &ipaddr);
uip_ip6addr(&ipaddr, 0xaaaa, 0, 0, 0, 0, 0, 0, 0);
rpl_set_prefix(dag, &ipaddr, 64);
PRINTF("created a new RPL dag\n");
} else {
PRINTF("failed to create a new RPL DAG\n");
}
#endif /* UIP_CONF_ROUTER */
PRINTF("IPv6 addresses: ");
for(i = 0; i < UIP_DS6_ADDR_NB; i++) {
state = uip_ds6_if.addr_list[i].state;
if(state == ADDR_TENTATIVE || state == ADDR_PREFERRED) {
PRINT6ADDR(&uip_ds6_if.addr_list[i].ipaddr);
PRINTF("\n");
/* hack to make address "final" */
if (state == ADDR_TENTATIVE) {
uip_ds6_if.addr_list[i].state = ADDR_PREFERRED;
}
}
}
}
/*---------------------------------------------------------------------------*/
PROCESS_THREAD(router_process, ev, data)
{
/* This way the packet can be treated as pointer as usual. */
static coap_packet_t request[1];
static struct etimer timer;
uip_ds6_route_t *r;
uip_ipaddr_t *nexthop;
int n;
PROCESS_BEGIN();
PROCESS_PAUSE();
/* receives all CoAP messages */
coap_init_engine();
setup_network();
/* The data sink runs with a 100% duty cycle in order to ensure high
packet reception rates. */
NETSTACK_MAC.off(1);
while(1) {
etimer_set(&timer, CLOCK_SECOND * 5);
PROCESS_YIELD();
/* Handle serial line input */
if(ev == serial_line_event_message) {
serial_protocol_input((char *) data);
}
if(etimer_expired(&timer)) {
current_target = NULL;
n = 0;
for(r = uip_ds6_route_head(); r != NULL; r = uip_ds6_route_next(r)) {
current_target = add_node(&r->ipaddr);
if(current_target == NULL ||
(current_target->flags & NODE_HAS_TYPE) != 0 ||
current_target->retries > 5) {
continue;
}
PRINTF(" ");
PRINT6ADDR(&r->ipaddr);
PRINTF(" -> ");
nexthop = uip_ds6_route_nexthop(r);
if(nexthop != NULL) {
PRINT6ADDR(nexthop);
PRINTF("\n");
} else {
PRINTF("-");
}
PRINTF("\n");
n++;
break;
}
}
/* This is a node type discovery */
if(current_target != NULL &&
(current_target->flags & NODE_HAS_TYPE) == 0 &&
current_target->retries < 6) {
/* prepare request, TID is set by COAP_BLOCKING_REQUEST() */
coap_init_message(request, COAP_TYPE_CON, COAP_GET, 0);
coap_set_header_uri_path(request, URL_DEVICE_MODEL);
current_target->retries++;
PRINTF("CoAP request to [");
PRINT6ADDR(&current_target->ipaddr);
PRINTF("]:%u (%u tx)\n", UIP_HTONS(REMOTE_PORT),
current_target->retries);
fetching_type = 1;
COAP_BLOCKING_REQUEST(&current_target->ipaddr, REMOTE_PORT, request,
client_chunk_handler);
fetching_type = 0;
strncpy(current_uri, URL_LIGHT_CONTROL, sizeof(current_uri));
printf("\n--Done--\n");
}
/* If having a type this is another type of request */
if(current_target != NULL &&
(current_target->flags & NODE_HAS_TYPE) && strlen(current_uri) > 0) {
/* prepare request, TID is set by COAP_BLOCKING_REQUEST() */
coap_init_message(request, COAP_TYPE_CON, current_request, 0);
coap_set_header_uri_path(request, current_uri);
if(strlen(current_value) > 0) {
coap_set_payload(request, (uint8_t *)current_value,
strlen(current_value));
}
PRINTF("CoAP request to [");
PRINT6ADDR(&current_target->ipaddr);
PRINTF("]:%u %s\n", UIP_HTONS(REMOTE_PORT), current_uri);
COAP_BLOCKING_REQUEST(&current_target->ipaddr, REMOTE_PORT, request,
client_chunk_handler);
/* print out result of command */
if(current_request == COAP_PUT) {
printf("s ");
} else {
printf("g ");
}
uip_debug_ipaddr_print(&current_target->ipaddr);
printf(" %s %s\n", current_uri, current_value);
current_target = NULL;
current_uri[0] = 0;
current_value[0] = 0;
}
}
PROCESS_END();
}
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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_CONF_H_
#define PROJECT_CONF_H_
#ifdef BOARD_STRING
#define LWM2M_DEVICE_MODEL_NUMBER BOARD_STRING
#elif defined(CONTIKI_TARGET_WISMOTE)
#include "dev/watchdog.h"
#define LWM2M_DEVICE_MODEL_NUMBER "wismote"
#define LWM2M_DEVICE_MANUFACTURER "Arago Systems"
#define LWM2M_DEVICE_SERIAL_NO "001"
#define PLATFORM_REBOOT watchdog_reboot
#endif
#define IPSO_TEMPERATURE example_ipso_temperature
/**
* Disabling RDC and CSMA to save memory on constrained devices.
*/
#undef NETSTACK_CONF_RDC
#define NETSTACK_CONF_RDC nullrdc_driver
#undef NETSTACK_CONF_MAC
#define NETSTACK_CONF_MAC nullmac_driver
/* Disabling TCP on CoAP nodes. */
#undef UIP_CONF_TCP
#define UIP_CONF_TCP 0
/* Increase rpl-border-router IP-buffer when using more than 64. */
#undef REST_MAX_CHUNK_SIZE
#define REST_MAX_CHUNK_SIZE 64
/* Multiplies with chunk size, be aware of memory constraints. */
#undef COAP_MAX_OPEN_TRANSACTIONS
#define COAP_MAX_OPEN_TRANSACTIONS 4
/* Filtering .well-known/core per query can be disabled to save space. */
#undef COAP_LINK_FORMAT_FILTERING
#define COAP_LINK_FORMAT_FILTERING 0
#undef COAP_PROXY_OPTION_PROCESSING
#define COAP_PROXY_OPTION_PROCESSING 0
/* Enable client-side support for COAP observe */
#define COAP_OBSERVE_CLIENT 1
#endif /* PROJECT_CONF_H_ */

View file

@ -0,0 +1,126 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \file
* Simple serial protocol to list and interact with devices
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#include "contiki.h"
#include "net/ip/uip.h"
#include "net/ip/uiplib.h"
#include <stdio.h>
void print_node_list(void);
void set_value(const uip_ipaddr_t *addr, char *uri, char *value);
void get_value(const uip_ipaddr_t *addr, char *uri);
/*---------------------------------------------------------------------------*/
int
find_next_sep(const char *str, char sep, int pos)
{
char c;
while((c = str[pos]) != 0) {
if(c == sep) {
return pos + 1;
}
pos++;
}
return -1;
}
/*---------------------------------------------------------------------------*/
/*
* l - list all discovered devices
* s - set <IP> <URI> <value>
* d - get <IP> <URI>
*/
void
serial_protocol_input(char *data)
{
/* We assume that we have a string here */
char cmd = data[0];
int pos = 0;
switch(cmd) {
case 'l':
/* list devices */
print_node_list();
break;
case 's': {
uip_ip6addr_t ipaddr;
char *uri;
char *value;
pos = find_next_sep(data, ' ', pos);
if(pos > 0) {
/* start of IP */
int start = pos;
pos = find_next_sep(data, ' ', pos);
if(pos == -1) {
return;
}
data[pos - 1] = 0;
if(uiplib_ip6addrconv(&data[start], &ipaddr) == 0) {
printf("* Error not valid IP\n");
}
uri = &data[pos];
pos = find_next_sep(data, ' ', pos);
if(pos == -1) return;
data[pos - 1] = 0;
value = &data[pos];
/* set the value at the specified node */
set_value(&ipaddr, uri, value);
}
break;
}
case 'g': {
uip_ip6addr_t ipaddr;
char *uri;
pos = find_next_sep(data, ' ', pos);
if(pos > 0) {
/* start of IP */
int start = pos;
pos = find_next_sep(data, ' ', pos);
if(pos == -1) return;
data[pos - 1] = 0;
if(uiplib_ip6addrconv((const char *) &data[start], &ipaddr) == 0) {
printf("* Error not valid IP\n");
}
uri = &data[pos];
/* get the value at the specified node */
get_value(&ipaddr, uri);
}
break;
}
default:
printf("Unknown command\n");
}
}
/*---------------------------------------------------------------------------*/

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2015, Yanzi Networks AB.
* 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 copyright holder 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 COPYRIGHT HOLDER 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
* COPYRIGHT HOLDER 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.
*/
/**
* \file
* Simple serial protocol to list and interact with devices
* \author
* Joakim Eriksson <joakime@sics.se>
* Niclas Finne <nfi@sics.se>
*/
#ifndef SERIAL_PROTOCOL_H_
#define SERIAL_PROTOCOL_H_
void serial_protocol_input(char *data);
#endif /* SERIAL_PROTOCOL_H_ */

View file

@ -14,6 +14,7 @@ hello-world/z1 \
eeprom-test/native \
collect/sky \
er-rest-example/wismote \
ipso-objects/wismote \
example-shell/native \
netperf/sky \
powertrace/sky \

View file

@ -15,6 +15,7 @@ cc26xx/very-sleepy-demo/srf06-cc26xx \
hello-world/cc2538dk \
ipv6/rpl-border-router/cc2538dk \
er-rest-example/cc2538dk \
ipso-objects/cc2538dk \
webserver-ipv6/cc2538dk \
cc2538dk/cc2538dk \
cc2538dk/udp-ipv6-echo-server/cc2538dk \
@ -26,6 +27,7 @@ ipv6/multicast/cc2538dk \
zolertia/zoul/zoul \
zolertia/zoul/cc1200-demo/zoul \
er-rest-example/zoul \
ipso-objects/zoul \
hello-world/zoul \
cc2538dk/mqtt-demo/zoul \
er-rest-example/stm32nucleo-spirit1 \