blob: b1911f0ef25142931d19c45891e2c9a5552560c4 [file] [log] [blame]
Claudio Takahasi05c71902016-08-10 09:41:51 -03001/*
2 * Copyright (c) 2016, CESAR.
3 * All rights reserved.
4 *
5 * This software may be modified and distributed under the terms
6 * of the BSD license. See the LICENSE file for details.
7 *
8 */
9
Claudio Takahasia927d892016-08-10 10:27:13 -030010#include <stdint.h>
Claudio Takahasi2b569982016-08-12 22:30:48 -030011#include <stdio.h>
Claudio Takahasia927d892016-08-10 10:27:13 -030012#include <errno.h>
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030013#include <string.h>
Claudio Takahasia927d892016-08-10 10:27:13 -030014
Claudio Takahasi99c902a2017-05-03 15:51:47 -030015#include <hal/time.h>
Tiago Barrosc6efab02016-09-01 11:17:15 -030016#include "knot_thing_config.h"
17#include "knot_types.h"
18#include "knot_thing_main.h"
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -030019#include <avr/pgmspace.h>
Claudio Takahasi05c71902016-08-10 09:41:51 -030020
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030021// TODO: normalize all returning error codes
Claudio Takahasia927d892016-08-10 10:27:13 -030022
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -030023
24const char KNOT_THING_EMPTY_ITEM[] PROGMEM = { "EMPTY ITEM" };
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030025static uint8_t pos_count, last_item;
Claudio Takahasi2b569982016-08-12 22:30:48 -030026
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030027static struct _data_items {
28 uint8_t id; // KNOT_ID
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030029 // schema values
30 uint8_t value_type; // KNOT_VALUE_TYPE_* (int, float, bool, raw)
31 uint8_t unit; // KNOT_UNIT_*
32 uint16_t type_id; // KNOT_TYPE_ID_*
33 const char *name; // App defined data item name
Claudio Takahasif0dede22017-03-16 14:41:48 -030034
35 /* Control the upper lower message flow */
36 uint8_t lower_flag;
37 uint8_t upper_flag;
38
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030039 // data values
Claudio Takahasia04a2d42018-07-24 14:24:28 -030040 knot_value_type last_data;
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030041 uint8_t *last_value_raw;
Claudio Takahasid4df10f2018-07-26 13:58:56 -030042 uint8_t raw_length;
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030043 // config values
Rodrigo Alves925ba532016-11-03 10:54:05 -030044 knot_config config; // Flags indicating when data will be sent
Erick Simõese6add262016-11-24 11:32:12 -030045 // time values
46 uint32_t last_timeout; // Stores the last time the data was sent
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030047 // Data read/write functions
48 knot_data_functions functions;
49} data_items[KNOT_THING_DATA_MAX];
Claudio Takahasi2b569982016-08-12 22:30:48 -030050
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030051static struct _data_items *find_item(uint8_t id)
52{
53 uint8_t index;
54 /* Sensor ID value 0 can't be used */
55 if (id == 0)
56 return NULL;
57
58 for (index = 0; index < KNOT_THING_DATA_MAX; index++) {
59 if (data_items[index].id == id)
60 return &data_items[index];
61 }
62
63 return NULL;
64}
65
Tiago Barros9ca6b3d2016-09-05 14:27:05 -030066static void reset_data_items(void)
Claudio Takahasi2b569982016-08-12 22:30:48 -030067{
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030068 struct _data_items *item = data_items;
Rodrigo Alves3291c252016-11-23 10:51:48 -030069 int8_t count;
Claudio Takahasi76c51b92017-02-15 13:45:10 -030070
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030071 pos_count = 0;
72 last_item = 0;
Claudio Takahasi2b569982016-08-12 22:30:48 -030073
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030074 for (count = 0; count < KNOT_THING_DATA_MAX; ++count, ++item) {
75 item->id = 0;
76 item->name = (const char *)pgm_read_word(KNOT_THING_EMPTY_ITEM);
77 item->type_id = KNOT_TYPE_ID_INVALID;
78 item->unit = KNOT_UNIT_NOT_APPLICABLE;
79 item->value_type = KNOT_VALUE_TYPE_INVALID;
80 item->config.event_flags = KNOT_EVT_FLAG_UNREGISTERED;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -030081 /* As "last_data" is a union, we need just to set the "biggest" member*/
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030082 item->last_data.val_f.multiplier = 1;
83 item->last_data.val_f.value_int = 0;
84 item->last_data.val_f.value_dec = 0;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -030085 /* As "lower_limit" is a union, we need just to set the "biggest" member */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030086 item->config.lower_limit.val_f.multiplier = 1;
87 item->config.lower_limit.val_f.value_int = 0;
88 item->config.lower_limit.val_f.value_dec = 0;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -030089 /* As "upper_limit" is a union, we need just to set the "biggest" member */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030090 item->config.upper_limit.val_f.multiplier = 1;
91 item->config.upper_limit.val_f.value_int = 0;
92 item->config.upper_limit.val_f.value_dec = 0;
93 item->last_value_raw = NULL;
Claudio Takahasid4df10f2018-07-26 13:58:56 -030094 item->raw_length = 0;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -030095 /* As "functions" is a union, we need just to set only one of its members */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030096 item->functions.int_f.read = NULL;
97 item->functions.int_f.write = NULL;
Lucas Cavalcanti32e7df22017-01-06 17:34:36 -030098
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -030099 item->lower_flag = 0;
100 item->upper_flag = 0;
Paulo Serra Filhoaec8ea12017-04-21 12:02:05 -0300101 /* Last timeout reset */
102 item->last_timeout = 0;
103 /* TODO:last_value_raw needs to be cleared/reset? */
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300104 }
Claudio Takahasi2b569982016-08-12 22:30:48 -0300105}
106
Claudio Takahasi729eb042017-02-15 13:34:04 -0300107static int data_function_is_valid(knot_data_functions *func)
Claudio Takahasi201ebe22016-08-10 10:06:42 -0300108{
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300109 if (func == NULL)
110 return -1;
Rodrigo Alves925ba532016-11-03 10:54:05 -0300111
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300112 if (func->int_f.read == NULL && func->int_f.write == NULL)
113 return -1;
Claudio Takahasia927d892016-08-10 10:27:13 -0300114
Claudio Takahasi201ebe22016-08-10 10:06:42 -0300115 return 0;
116}
117
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300118void knot_thing_exit(void)
Claudio Takahasi201ebe22016-08-10 10:06:42 -0300119{
Tiago Barros8f02e1b2017-07-07 10:52:24 -0300120 knot_thing_protocol_exit();
Claudio Takahasi201ebe22016-08-10 10:06:42 -0300121}
122
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300123int8_t knot_thing_register_raw_data_item(uint8_t id, const char *name,
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300124 uint8_t *raw_buffer, uint8_t raw_buffer_len, uint16_t type_id,
125 uint8_t value_type, uint8_t unit, knot_data_functions *func)
Claudio Takahasifa33d712016-08-10 10:09:39 -0300126{
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300127 if (raw_buffer == NULL)
128 return -1;
Claudio Takahasi2b569982016-08-12 22:30:48 -0300129
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300130 if (raw_buffer_len > KNOT_DATA_RAW_SIZE)
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300131 return -1;
132
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300133 if (knot_thing_register_data_item(id, name, type_id, value_type,
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300134 unit, func) != 0)
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300135 return -1;
136
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300137 /* TODO: Find an alternative way to assign raw buffer */
138 data_items[last_item].last_value_raw = raw_buffer;
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300139 data_items[last_item].raw_length = raw_buffer_len;
Rodrigo Alvesa4035202016-11-08 12:54:22 -0300140
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300141 return 0;
142}
143
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300144/*
145 * TODO: investigate if index/id or a pointer to the registered item
146 * can be returned in order to access/manage the entry easier.
147 */
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300148int8_t knot_thing_register_data_item(uint8_t id, const char *name,
149 uint16_t type_id, uint8_t value_type,
150 uint8_t unit, knot_data_functions *func)
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300151{
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300152 struct _data_items *item;
153 uint8_t index;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300154
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300155 for (index = 0, item = NULL; index < KNOT_THING_DATA_MAX; index++) {
156 if (data_items[index].id == 0) {
157 item = &data_items[index];
158 last_item = index;
159 break;
160 }
161 }
162
163 if ((!item) || (knot_schema_is_valid(type_id, value_type, unit) != 0) ||
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300164 name == NULL || (data_function_is_valid(func) != 0))
165 return -1;
166
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300167 item->id = id;
168 item->name = name;
169 item->type_id = type_id;
170 item->unit = unit;
171 item->value_type = value_type;
Larissa Lages7b7892e2017-07-18 13:50:50 -0300172
173 /* Set default config */
174 item->config.event_flags = KNOT_EVT_FLAG_TIME;
175 item->config.time_sec = 30;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -0300176 /* As "last_data" is a union, we need just to set the "biggest" member */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300177 item->last_data.val_f.multiplier = 1;
178 item->last_data.val_f.value_int = 0;
179 item->last_data.val_f.value_dec = 0;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -0300180 /* As "lower_limit" is a union, we need just to set the "biggest" member */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300181 item->config.lower_limit.val_f.multiplier = 1;
182 item->config.lower_limit.val_f.value_int = 0;
183 item->config.lower_limit.val_f.value_dec = 0;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -0300184 /* As "upper_limit" is a union, we need just to set the "biggest" member */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300185 item->config.upper_limit.val_f.multiplier = 1;
186 item->config.upper_limit.val_f.value_int = 0;
187 item->config.upper_limit.val_f.value_dec = 0;
188 item->last_value_raw = NULL;
Rodrigo Alvesba17e9b2016-11-18 11:01:33 -0300189 /* As "functions" is a union, we need just to set only one of its members */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300190 item->functions.int_f.read = func->int_f.read;
191 item->functions.int_f.write = func->int_f.write;
Paulo Serra Filhoaec8ea12017-04-21 12:02:05 -0300192 /* Starting last_timeout with the current time */
193 item->last_timeout = hal_time_ms();
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300194 return 0;
195}
196
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300197int knot_thing_config_data_item(uint8_t id, uint8_t evflags, uint16_t time_sec,
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300198 knot_value_type *lower,
199 knot_value_type *upper)
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300200{
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300201 struct _data_items *item = find_item(id);
202
Larissa Lages98cede62017-07-19 15:23:12 -0300203 /*Check if config is valid*/
204 if (knot_config_is_valid(evflags, time_sec, lower, upper)
205 != KNOT_SUCCESS)
206 return -1;
Larissa Lages56f067b2017-07-19 15:08:06 -0300207
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300208 if (!item)
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300209 return -1;
210
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300211 item->config.event_flags = evflags;
212 item->config.time_sec = time_sec;
Rodrigo Alves32fbd632016-12-07 12:53:02 -0300213
Claudio Takahasi1e8d2c82017-02-15 16:07:25 -0300214 /*
215 * "lower/upper limit" is a union, we need
216 * just to set the "biggest" member.
217 */
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300218
Claudio Takahasi1e8d2c82017-02-15 16:07:25 -0300219 if (lower)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300220 memcpy(&(item->config.lower_limit), lower, sizeof(*lower));
Claudio Takahasi1e8d2c82017-02-15 16:07:25 -0300221
222 if (upper)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300223 memcpy(&(item->config.upper_limit), upper, sizeof(*upper));
Claudio Takahasi1e8d2c82017-02-15 16:07:25 -0300224
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300225 return 0;
226}
227
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300228int knot_thing_create_schema(uint8_t id, knot_msg_schema *msg)
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300229{
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300230 struct _data_items *item;
231
232 item = find_item(id);
233 if (item == NULL)
234 return KNOT_INVALID_DEVICE;
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300235
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300236 msg->hdr.type = KNOT_MSG_SCHEMA;
237
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300238 if (!item)
Lucas Cavalcantic53c9782017-02-20 12:53:15 -0300239 return KNOT_INVALID_DEVICE;
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300240
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300241 msg->sensor_id = id;
Tiago Barros29a71772017-07-20 10:40:51 -0300242 msg->values.value_type = item->value_type;
243 msg->values.unit = item->unit;
244 msg->values.type_id = item->type_id;
245 strncpy(msg->values.name, item->name, sizeof(msg->values.name));
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300246
Tiago Barros29a71772017-07-20 10:40:51 -0300247 msg->hdr.payload_len = sizeof(msg->values) + sizeof(msg->sensor_id);
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300248
249 /* Send 'end' for the last item (sensor or actuator). */
250 if (data_items[last_item].id == id)
Rodrigo Alvesa9294202016-12-06 14:39:16 -0300251 msg->hdr.type = KNOT_MSG_SCHEMA_END;
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300252
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300253 return KNOT_SUCCESS;
Rodrigo Alvesf34885e2016-11-08 13:59:12 -0300254}
255
Tiago Barrosc468b9e2017-07-07 10:29:02 -0300256int knot_thing_data_item_read(uint8_t id, knot_msg_data *data)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300257{
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300258 struct _data_items *item;
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300259 int len;
Rodrigo Alves2a542862016-11-08 16:10:44 -0300260
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300261 item = find_item(id);
262 if (!item)
Tiago Barrosdde937f2017-07-21 14:24:58 -0300263 return -2;
Rodrigo Alves2a542862016-11-08 16:10:44 -0300264
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300265 data->hdr.payload_len = sizeof(data->sensor_id);
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300266 switch (item->value_type) {
Rodrigo Alves2a542862016-11-08 16:10:44 -0300267 case KNOT_VALUE_TYPE_RAW:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300268 if (item->functions.raw_f.read == NULL)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300269 return -1;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300270
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300271 len = item->functions.raw_f.read(data->payload.raw,
272 sizeof(data->payload.raw));
273 if (len < 0)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300274 return -1;
275
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300276 if (len > item->raw_length)
277 return -1;
278
279 data->hdr.payload_len += len;
Rodrigo Alves2a542862016-11-08 16:10:44 -0300280 break;
281 case KNOT_VALUE_TYPE_BOOL:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300282 if (item->functions.bool_f.read == NULL)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300283 return -1;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300284
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300285 if (item->functions.bool_f.read(&(data->payload.val_b)) < 0)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300286 return -1;
287
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300288 data->hdr.payload_len += sizeof(knot_value_type_bool);
Rodrigo Alves2a542862016-11-08 16:10:44 -0300289 break;
290 case KNOT_VALUE_TYPE_INT:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300291 if (item->functions.int_f.read == NULL)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300292 return -1;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300293
Tiago Barrosad236bd2017-07-13 09:51:45 -0300294 if (item->functions.int_f.read(
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300295 &(data->payload.val_i.value),
296 &(data->payload.val_i.multiplier)) < 0)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300297 return -1;
298
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300299 data->hdr.payload_len += sizeof(knot_value_type_int);
Rodrigo Alves2a542862016-11-08 16:10:44 -0300300 break;
301 case KNOT_VALUE_TYPE_FLOAT:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300302 if (item->functions.float_f.read == NULL)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300303 return -1;
304
Tiago Barrosad236bd2017-07-13 09:51:45 -0300305 if (item->functions.float_f.read(
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300306 &(data->payload.val_f.value_int),
307 &(data->payload.val_f.value_dec),
308 &(data->payload.val_f.multiplier)) < 0)
Rodrigo Alves2a542862016-11-08 16:10:44 -0300309 return -1;
310
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300311 data->hdr.payload_len += sizeof(knot_value_type_float);
Rodrigo Alves2a542862016-11-08 16:10:44 -0300312 break;
313 default:
314 return -1;
Rodrigo Alves2a542862016-11-08 16:10:44 -0300315 }
316
317 return 0;
318}
319
Tiago Barrosc468b9e2017-07-07 10:29:02 -0300320int knot_thing_data_item_write(uint8_t id, knot_msg_data *data)
Rodrigo Alves121eb402016-11-08 16:19:52 -0300321{
Claudio Takahasi001f22b2017-07-03 13:44:21 -0300322 int8_t ret_val = -1;
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300323 int8_t ilen;
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300324 struct _data_items *item;
Rodrigo Alves121eb402016-11-08 16:19:52 -0300325
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300326 item = find_item(id);
327 if (!item)
Rodrigo Alves121eb402016-11-08 16:19:52 -0300328 return -1;
329
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300330 /* Received data length */
331 ilen = data->hdr.payload_len - sizeof(data->sensor_id);
332 /* Setting length to send */
333 data->hdr.payload_len = sizeof(data->sensor_id);
334
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300335 switch (item->value_type) {
Rodrigo Alves121eb402016-11-08 16:19:52 -0300336 case KNOT_VALUE_TYPE_RAW:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300337 if (item->functions.raw_f.write == NULL)
Claudio Takahasi834cd642017-02-16 10:01:13 -0300338 goto done;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300339
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300340 ret_val = item->functions.raw_f.write(data->payload.raw, ilen);
341 if (ret_val < 0 || ret_val > KNOT_DATA_RAW_SIZE)
342 return -1;
343
344 data->hdr.payload_len += ret_val;
Rodrigo Alves121eb402016-11-08 16:19:52 -0300345 break;
346 case KNOT_VALUE_TYPE_BOOL:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300347 if (item->functions.bool_f.write == NULL)
Claudio Takahasi834cd642017-02-16 10:01:13 -0300348 goto done;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300349
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300350 ret_val = item->functions.bool_f.write(
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300351 &data->payload.val_b);
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300352 if (ret_val < 0)
353 break;
354
355 data->hdr.payload_len += sizeof(data->payload.val_b);
Rodrigo Alves121eb402016-11-08 16:19:52 -0300356 break;
357 case KNOT_VALUE_TYPE_INT:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300358 if (item->functions.int_f.write == NULL)
Claudio Takahasi834cd642017-02-16 10:01:13 -0300359 goto done;
Claudio Takahasi76c51b92017-02-15 13:45:10 -0300360
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300361 ret_val = item->functions.int_f.write(
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300362 &data->payload.val_i.value,
363 &data->payload.val_i.multiplier);
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300364 if (ret_val < 0)
365 break;
366
367 data->hdr.payload_len += sizeof(data->payload.val_i);
Rodrigo Alves121eb402016-11-08 16:19:52 -0300368 break;
369 case KNOT_VALUE_TYPE_FLOAT:
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300370 if (item->functions.float_f.write == NULL)
Claudio Takahasi834cd642017-02-16 10:01:13 -0300371 goto done;
Rodrigo Alves121eb402016-11-08 16:19:52 -0300372
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300373 ret_val = item->functions.float_f.write(
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300374 &data->payload.val_f.value_int,
375 &data->payload.val_f.value_dec,
376 &data->payload.val_f.multiplier);
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300377 if (ret_val < 0)
378 break;
379
380 data->hdr.payload_len += sizeof(data->payload.val_f);
Rodrigo Alves121eb402016-11-08 16:19:52 -0300381 break;
382 default:
Claudio Takahasi3f80f502017-02-16 09:52:50 -0300383 break;
Rodrigo Alves121eb402016-11-08 16:19:52 -0300384 }
385
Claudio Takahasi834cd642017-02-16 10:01:13 -0300386done:
Claudio Takahasi3f80f502017-02-16 09:52:50 -0300387 return ret_val;
Rodrigo Alves121eb402016-11-08 16:19:52 -0300388}
389
Tiago Barros9ca6b3d2016-09-05 14:27:05 -0300390int8_t knot_thing_run(void)
391{
Rodrigo Alves84496882016-11-18 17:57:35 -0300392 return knot_thing_protocol_run();
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300393}
394
Tiago Barrosc468b9e2017-07-07 10:29:02 -0300395int knot_thing_verify_events(knot_msg_data *data)
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300396{
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300397 struct _data_items *item;
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300398 knot_value_type *last;
Erick Simõesf619d392016-12-21 11:28:16 -0300399 uint8_t comparison = 0;
Paulo Serra Filho38558e12016-12-15 12:55:20 -0300400 /* Current time in miliseconds to verify sensor timeout */
Claudio Takahasi59a29362017-02-16 09:39:27 -0300401 uint32_t current_time;
Erick Simõese6add262016-11-24 11:32:12 -0300402
Claudio Takahasi2b569982016-08-12 22:30:48 -0300403 /*
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300404 * To avoid an extensive loop we keep an variable to iterate over all
405 * sensors/actuators once at each loop. When the last sensor was verified
406 * we reinitialize the counter, otherwise we just increment it.
Claudio Takahasi2b569982016-08-12 22:30:48 -0300407 */
408
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300409 item = &data_items[pos_count];
410 if (item->id == 0)
411 goto none;
Lucas Cavalcanti5e575662017-01-05 11:24:00 -0300412
Tiago Barrosad236bd2017-07-13 09:51:45 -0300413 data->hdr.type = KNOT_MSG_DATA;
414 data->sensor_id = item->id;
415
Tiago Barrosc468b9e2017-07-07 10:29:02 -0300416 if (knot_thing_data_item_read(item->id, data) < 0)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300417 goto none;
Lucas Cavalcanti5e575662017-01-05 11:24:00 -0300418
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300419 last = &(item->last_data);
Claudio Takahasif0dede22017-03-16 14:41:48 -0300420
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300421 /* Value did not change or error: return -1, 0 means send data */
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300422 switch (item->value_type) {
Claudio Takahasiaf3a5ce2017-02-16 09:34:47 -0300423 case KNOT_VALUE_TYPE_RAW:
Tiago Barros3003fb12016-09-06 09:12:31 -0300424
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300425 if (item->last_value_raw == NULL)
426 goto none;
Tiago Barros3003fb12016-09-06 09:12:31 -0300427
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300428 if (memcmp(item->last_value_raw, data->payload.raw,
429 item->raw_length) == 0)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300430 goto none;
Tiago Barros3003fb12016-09-06 09:12:31 -0300431
Claudio Takahasid4df10f2018-07-26 13:58:56 -0300432 memcpy(item->last_value_raw, data->payload.raw,
433 item->raw_length);
Rodrigo Alvesa3890db2016-11-18 11:35:48 -0300434 comparison = 1;
Claudio Takahasiaf3a5ce2017-02-16 09:34:47 -0300435 break;
436 case KNOT_VALUE_TYPE_BOOL:
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300437 if (data->payload.val_b != last->val_b) {
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300438 comparison |= (KNOT_EVT_FLAG_CHANGE & item->config.event_flags);
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300439 last->val_b = data->payload.val_b;
Tiago Barros3003fb12016-09-06 09:12:31 -0300440 }
Claudio Takahasiaf3a5ce2017-02-16 09:34:47 -0300441 break;
442 case KNOT_VALUE_TYPE_INT:
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300443 // TODO: add multiplier to comparison
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300444 if (data->payload.val_i.value < item->config.lower_limit.val_i.value &&
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300445 item->lower_flag == 0) {
446 comparison |= (KNOT_EVT_FLAG_LOWER_THRESHOLD & item->config.event_flags);
447 item->upper_flag = 0;
448 item->lower_flag = 1;
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300449 } else if (data->payload.val_i.value > item->config.upper_limit.val_i.value &&
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300450 item->upper_flag == 0) {
451 comparison |= (KNOT_EVT_FLAG_UPPER_THRESHOLD & item->config.event_flags);
452 item->upper_flag = 1;
453 item->lower_flag = 0;
Lucas Cavalcanti32e7df22017-01-06 17:34:36 -0300454 } else {
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300455 if (data->payload.val_i.value < item->config.upper_limit.val_i.value)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300456 item->upper_flag = 0;
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300457 if (data->payload.val_i.value > item->config.lower_limit.val_i.value)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300458 item->lower_flag = 0;
Lucas Cavalcanti32e7df22017-01-06 17:34:36 -0300459 }
460
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300461 if (data->payload.val_i.value != last->val_i.value)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300462 comparison |= (KNOT_EVT_FLAG_CHANGE & item->config.event_flags);
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300463
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300464 last->val_i.value = data->payload.val_i.value;
465 last->val_i.multiplier = data->payload.val_i.multiplier;
Claudio Takahasiaf3a5ce2017-02-16 09:34:47 -0300466 break;
467 case KNOT_VALUE_TYPE_FLOAT:
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300468 // TODO: add multiplier and decimal part to comparison
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300469 if (data->payload.val_f.value_int < item->config.lower_limit.val_f.value_int &&
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300470 item->lower_flag == 0) {
471 comparison |= (KNOT_EVT_FLAG_LOWER_THRESHOLD & item->config.event_flags);
472 item->upper_flag = 0;
473 item->lower_flag = 1;
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300474 } else if (data->payload.val_f.value_int > item->config.upper_limit.val_f.value_int &&
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300475 item->upper_flag == 0) {
476 comparison |= (KNOT_EVT_FLAG_UPPER_THRESHOLD & item->config.event_flags);
477 item->upper_flag = 1;
478 item->lower_flag = 0;
Lucas Cavalcanti32e7df22017-01-06 17:34:36 -0300479 } else {
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300480 if (data->payload.val_i.value < item->config.upper_limit.val_i.value)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300481 item->upper_flag = 0;
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300482 if (data->payload.val_i.value > item->config.lower_limit.val_i.value)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300483 item->lower_flag = 0;
Lucas Cavalcanti32e7df22017-01-06 17:34:36 -0300484 }
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300485 if (data->payload.val_f.value_int != last->val_f.value_int)
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300486 comparison |= (KNOT_EVT_FLAG_CHANGE & item->config.event_flags);
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300487
Claudio Takahasia04a2d42018-07-24 14:24:28 -0300488 last->val_f.value_int = data->payload.val_f.value_int;
489 last->val_f.value_dec = data->payload.val_f.value_dec;
490 last->val_f.multiplier = data->payload.val_f.multiplier;
Claudio Takahasiaf3a5ce2017-02-16 09:34:47 -0300491 break;
492 default:
Rodrigo Alves22ae35a2016-12-12 12:55:25 -0300493 // This data item is not registered with a valid value type
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300494 goto none;
Tiago Barros3003fb12016-09-06 09:12:31 -0300495 }
Claudio Takahasibd80a662016-08-10 12:59:25 -0300496
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300497 /*
Erick Simõese6add262016-11-24 11:32:12 -0300498 * It is checked if the data is in time to be updated (time overflow).
499 * If yes, the last timeout value and the comparison variable are updated with the time flag.
500 */
Claudio Takahasi59a29362017-02-16 09:39:27 -0300501 current_time = hal_time_ms();
Tiago Barros579b9b72017-07-20 10:59:20 -0300502 if (hal_timeout(current_time, item->last_timeout,
503 (item->config.time_sec * 1000)) > 0) {
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300504 item->last_timeout = current_time;
505 comparison |= (KNOT_EVT_FLAG_TIME & item->config.event_flags);
Erick Simõese6add262016-11-24 11:32:12 -0300506 }
507
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300508none:
509 /* Wrap or increment to the next item */
Paulo Serra Filho974507e2017-04-21 12:02:45 -0300510 pos_count = (pos_count + 1) > last_item ? 0 : pos_count + 1;
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300511
Douglas Vasconcelos7f19f452017-03-14 23:33:52 -0300512 /* Nothing changed */
Rodrigo Alves96ba1172016-11-17 13:46:51 -0300513 if (comparison == 0)
514 return -1;
515
Claudio Takahasibd80a662016-08-10 12:59:25 -0300516 return 0;
Rodrigo Alvesc5ed82b2016-11-18 17:59:36 -0300517}
518
519int8_t knot_thing_init(const char *thing_name)
520{
521 reset_data_items();
522
Tiago Barros6f3ab062017-07-07 10:50:44 -0300523 return knot_thing_protocol_init(thing_name);
Rodrigo Alvesc5ed82b2016-11-18 17:59:36 -0300524}