Contiki-NG
ipso-sensor-template.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, SICS Swedish ICT AB
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28  * OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 /**
32  * \addtogroup ipso-objects
33  * @{
34  *
35  */
36 
37 /**
38  * \file
39  * Implementation of OMA LWM2M / IPSO sensor template.
40  * \author
41  * Joakim Eriksson <joakime@sics.se>
42  * Niclas Finne <nfi@sics.se>
43  */
44 #include "ipso-sensor-template.h"
45 #include "lwm2m-engine.h"
46 #include <string.h>
47 #include <stdio.h>
48 
49 #define IPSO_SENSOR_VALUE 5700
50 #define IPSO_SENSOR_UNIT 5701
51 #define IPSO_SENSOR_MIN_VALUE 5601
52 #define IPSO_SENSOR_MAX_VALUE 5602
53 #define IPSO_SENSOR_MIN_RANGE 5603
54 #define IPSO_SENSOR_MAX_RANGE 5604
55 
56 #define IPSO_SENSOR_RESET_MINMAX 5605
57 
58 static const lwm2m_resource_id_t resources[] =
59  {
60  RO(IPSO_SENSOR_VALUE), RO(IPSO_SENSOR_UNIT),
61  RO(IPSO_SENSOR_MIN_VALUE), RO(IPSO_SENSOR_MAX_VALUE),
62  RO(IPSO_SENSOR_MIN_RANGE), RO(IPSO_SENSOR_MAX_RANGE),
63  EX(IPSO_SENSOR_RESET_MINMAX)
64  };
65 
66 /*---------------------------------------------------------------------------*/
67 static void update_last_value(ipso_sensor_value_t *sval, int32_t value,
68  uint8_t notify);
69 /*---------------------------------------------------------------------------*/
70 static int init = 0;
71 static coap_timer_t nt;
72 
73 /* Currently support max 4 periodic sensors */
74 #define MAX_PERIODIC 4
75 struct periodic_sensor {
76  ipso_sensor_value_t *value;
77  uint16_t ticks_left;
78 } periodics[MAX_PERIODIC];
79 
80 static void
81 timer_callback(coap_timer_t *timer)
82 {
83  int i;
84  coap_timer_reset(timer, 1000);
85 
86  for(i = 0; i < MAX_PERIODIC; i++) {
87  if(periodics[i].value != NULL) {
88  if(periodics[i].ticks_left > 0) {
89  periodics[i].ticks_left--;
90  } else {
91  int32_t value;
92  periodics[i].ticks_left = periodics[i].value->sensor->update_interval;
93  if(periodics[i].value->sensor->get_value_in_millis(periodics[i].value->sensor, &value) == LWM2M_STATUS_OK) {
94  update_last_value(periodics[i].value, value, 1);
95  }
96  }
97  }
98  }
99 }
100 
101 static void
102 add_periodic(const ipso_sensor_t *sensor)
103 {
104  int i;
105  for(i = 0; i < MAX_PERIODIC; i++) {
106  if(periodics[i].value == NULL) {
107  periodics[i].value = sensor->sensor_value;
108  periodics[i].ticks_left = sensor->update_interval;
109  return;
110  }
111  }
112 }
113 /*---------------------------------------------------------------------------*/
114 static void
115 update_last_value(ipso_sensor_value_t *sval, int32_t value, uint8_t notify)
116 {
117  /* No notification if this a regular read that cause the update */
118  if(sval->last_value != value && notify) {
119  lwm2m_notify_object_observers(&sval->reg_object, IPSO_SENSOR_VALUE);
120  }
121  sval->last_value = value;
122  if(sval->min_value > value) {
123  sval->min_value = value;
124  lwm2m_notify_object_observers(&sval->reg_object, IPSO_SENSOR_MIN_VALUE);
125  }
126  if(sval->max_value < value) {
127  sval->max_value = value;
128  lwm2m_notify_object_observers(&sval->reg_object, IPSO_SENSOR_MAX_VALUE);
129  }
130 }
131 /*---------------------------------------------------------------------------*/
132 static inline size_t
133 write_float32fix(lwm2m_context_t *ctx, int32_t value)
134 {
135  int64_t tmp = value;
136  tmp = (tmp * 1024) / 1000;
137  return lwm2m_object_write_float32fix(ctx, (int32_t)tmp, 10);
138 }
139 /*---------------------------------------------------------------------------*/
140 static lwm2m_status_t
141 lwm2m_callback(lwm2m_object_instance_t *object,
142  lwm2m_context_t *ctx)
143 {
144  /* Here we cast to our sensor-template struct */
145  const ipso_sensor_t *sensor;
146  ipso_sensor_value_t *value;
147  value = (ipso_sensor_value_t *) object;
148  sensor = value->sensor;
149 
150  /* Do the stuff */
151  if(ctx->level == 1) {
152  /* Should not happen 3303 */
153  return LWM2M_STATUS_ERROR;
154  }
155  if(ctx->level == 2) {
156  /* This is a get whole object - or write whole object 3303/0 */
157  return LWM2M_STATUS_ERROR;
158  }
159  if(ctx->level == 3) {
160  /* This is a get request on 3303/0/3700 */
161  /* NOW we assume a get.... which might be wrong... */
162  if(ctx->operation == LWM2M_OP_READ) {
163  switch(ctx->resource_id) {
164  case IPSO_SENSOR_UNIT:
165  if(sensor->unit != NULL) {
166  lwm2m_object_write_string(ctx, sensor->unit, strlen(sensor->unit));
167  }
168  break;
169  case IPSO_SENSOR_MAX_RANGE:
170  write_float32fix(ctx, sensor->max_range);
171  break;
172  case IPSO_SENSOR_MIN_RANGE:
173  write_float32fix(ctx, sensor->min_range);
174  break;
175  case IPSO_SENSOR_MAX_VALUE:
176  write_float32fix(ctx, value->max_value);
177  break;
178  case IPSO_SENSOR_MIN_VALUE:
179  write_float32fix(ctx, value->min_value);
180  break;
181  case IPSO_SENSOR_VALUE:
182  if(sensor->get_value_in_millis != NULL) {
183  int32_t v;
184  if(sensor->get_value_in_millis(sensor, &v) == LWM2M_STATUS_OK) {
185  update_last_value(value, v, 0);
186  write_float32fix(ctx, value->last_value);
187  }
188  }
189  break;
190  default:
191  return LWM2M_STATUS_ERROR;
192  }
193  } else if(ctx->operation == LWM2M_OP_EXECUTE) {
194  if(ctx->resource_id == IPSO_SENSOR_RESET_MINMAX) {
195  value->min_value = value->last_value;
196  value->max_value = value->last_value;
197  }
198  }
199  }
200  return LWM2M_STATUS_OK;
201 }
202 /*---------------------------------------------------------------------------*/
203 int
204 ipso_sensor_add(const ipso_sensor_t *sensor)
205 {
206  if(sensor->update_interval > 0) {
207  if(init == 0) {
208  coap_timer_set_callback(&nt, timer_callback);
209  coap_timer_set(&nt, 1000);
210  init = 1;
211  }
212  add_periodic(sensor);
213  }
214 
215  if(sensor->sensor_value == NULL) {
216  return 0;
217  }
218  sensor->sensor_value->reg_object.object_id = sensor->object_id;
219  sensor->sensor_value->sensor = sensor;
220  if(sensor->instance_id == 0) {
221  sensor->sensor_value->reg_object.instance_id = LWM2M_OBJECT_INSTANCE_NONE;
222  } else {
223  sensor->sensor_value->reg_object.instance_id = sensor->instance_id;
224  }
225  sensor->sensor_value->reg_object.callback = lwm2m_callback;
226  sensor->sensor_value->reg_object.resource_ids = resources;
227  sensor->sensor_value->reg_object.resource_count =
228  sizeof(resources) / sizeof(lwm2m_resource_id_t);
229  return lwm2m_engine_add_object(&sensor->sensor_value->reg_object);
230 }
231 /*---------------------------------------------------------------------------*/
232 int
233 ipso_sensor_remove(const ipso_sensor_t *sensor)
234 {
235  lwm2m_engine_remove_object(&sensor->sensor_value->reg_object);
236  return 1;
237 }
238 /*---------------------------------------------------------------------------*/
239 /** @} */
Implementation of OMA LWM2M / IPSO sensor template.
A timer.
Definition: timer.h:82
static void coap_timer_set_callback(coap_timer_t *timer, void(*callback)(coap_timer_t *))
Set a callback function to be called when a CoAP timer expires.
Definition: coap-timer.h:105
void coap_timer_reset(coap_timer_t *timer, uint64_t time)
Reset a CoAP timer to expire a specified time after the last expiration time.
Definition: coap-timer.c:110
Header file for the Contiki OMA LWM2M engine
void coap_timer_set(coap_timer_t *timer, uint64_t time)
Set a CoAP timer to expire after the specified time.
Definition: coap-timer.c:103