blob: 859be035e777b330c1209323e48bd1f077cbe166 [file] [log] [blame]
Larissaca16a322017-12-12 13:37:01 -03001 /*
Tiago Barrosc182ada2016-11-03 10:51:28 -03002 * 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 */
Tiago Barros8c61bd52017-07-18 16:51:28 -03009
10/* Flag to enable debug logs via Serial */
11#define KNOT_DEBUG_ENABLED 0
12
Rodrigo Alves2d602ae2016-11-04 14:03:13 -030013#include <stdint.h>
Tiago Barrosc182ada2016-11-03 10:51:28 -030014
Paulo Serra Filhob306c252016-12-07 13:01:44 -030015#ifdef ARDUINO
16#include <Arduino.h>
Tiago Barrosed627402017-07-18 15:14:39 -030017#include <hal/avr_errno.h>
18#include <hal/avr_unistd.h>
19#include <hal/avr_log.h>
Paulo Serra Filhoc6f40b82016-12-20 10:34:49 -030020#define CLEAR_EEPROM_PIN 7
Marcela Oliveira33c21c22017-05-15 15:29:06 -030021#define PIN_LED_STATUS 6 //LED used to show thing status
Paulo Serra Filhob306c252016-12-07 13:01:44 -030022#endif
23
Claudio Takahasi99c902a2017-05-03 15:51:47 -030024#include <hal/storage.h>
25#include <hal/nrf24.h>
26#include <hal/comm.h>
27#include <hal/gpio.h>
28#include <hal/time.h>
Tiago Barros6f3ab062017-07-07 10:50:44 -030029#include "knot_thing_protocol.h"
30#include "knot_thing_main.h"
Tiago Barros2ebe55a2017-07-20 17:18:01 -030031#include "knot_thing_config.h"
Tiago Barrosc182ada2016-11-03 10:51:28 -030032
Tiago Barrosc182ada2016-11-03 10:51:28 -030033/* KNoT protocol client states */
34#define STATE_DISCONNECTED 0
Tiago Barros2ebe55a2017-07-20 17:18:01 -030035#define STATE_ACCEPTING 1
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -030036#define STATE_CONNECTED 2
Tiago Barros2ebe55a2017-07-20 17:18:01 -030037#define STATE_AUTHENTICATING 3
38#define STATE_REGISTERING 4
39#define STATE_SCHEMA 5
40#define STATE_SCHEMA_RESP 6
41#define STATE_ONLINE 7
42#define STATE_RUNNING 8
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -030043#define STATE_ERROR 9
Tiago Barrosc182ada2016-11-03 10:51:28 -030044
Paulo Serra Filhocb7268c2017-04-21 12:02:38 -030045/* Intervals for LED blinking */
Larissaca16a322017-12-12 13:37:01 -030046#define LONG_INTERVAL 10000
47#define SHORT_INTERVAL 1000
Tiago Barros896112d2017-07-21 14:08:03 -030048
49/* Number of times LED is blinking */
50#define BLINK_DISCONNECTED 100
51#define BLINK_STABLISHING 2
52#define BLINK_ONLINE 1
Erick Simões385cf152017-01-17 14:47:21 -030053
Tiago Barros864f1d02017-07-21 10:25:34 -030054/* Periods for LED blinking in HALT conditions */
55#define NAME_ERROR 50
56#define COMM_ERROR 100
Larissaca16a322017-12-12 13:37:01 -030057#define AUTH_ERROR 250
58
59/* Time that the clear eeprom button needs to be pressed */
60#define BUTTON_PRESSED_TIME 5000
Tiago Barros864f1d02017-07-21 10:25:34 -030061
Rodrigo Alvesc623c042016-12-14 09:59:27 -030062/* KNoT MTU */
63#define MTU 256
64
Rodrigo Alves2d602ae2016-11-04 14:03:13 -030065#ifndef MIN
66#define MIN(a,b) (((a) < (b)) ? (a) : (b))
67#endif
68
Erick Simões385cf152017-01-17 14:47:21 -030069/* Retransmission timeout in ms */
Rodrigo Alvesfe97dad2016-12-13 14:03:19 -030070#define RETRANSMISSION_TIMEOUT 20000
71
Tiago Barrosd49fd272017-07-07 11:59:25 -030072static knot_msg msg;
Cristovao Rufinod8793332017-11-22 14:09:36 -030073static struct nrf24_config config = { .mac = 0, .channel = 76 , .name = NULL};
Tiago Barros41587792017-07-07 11:01:45 -030074static unsigned long clear_time;
75static uint32_t last_timeout;
Rodrigo Alvesf10624f2016-11-09 11:05:16 -030076static int sock = -1;
Rodrigo Alves482954a2016-11-22 08:04:20 -030077static int cli_sock = -1;
Paulo Serra Filhoe105eca2017-01-05 22:22:07 -030078static bool schema_flag = false;
Tiago Barros2ebe55a2017-07-20 17:18:01 -030079static uint8_t enable_run = 0, msg_sensor_id = 0;
Renie Delgadof0206e92016-11-25 09:39:13 -030080
81/*
82 * FIXME: Thing address should be received via NFC
83 * Mac address must be stored in big endian format
84 */
Larissaca16a322017-12-12 13:37:01 -030085
86void(* reset_function) (void) = 0; //declare reset function @ address 0
87
Claudio Takahasic2c1d9d2017-05-15 15:55:39 -030088static void set_nrf24MAC(void)
Renie Delgadof0206e92016-11-25 09:39:13 -030089{
Claudio Takahasi707e2132017-11-21 16:07:15 -030090 hal_getrandom(config.mac.address.b, sizeof(struct nrf24_mac));
91 hal_storage_write_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -030092 sizeof(struct nrf24_mac));
Renie Delgadof0206e92016-11-25 09:39:13 -030093}
Larissaca16a322017-12-12 13:37:01 -030094
95static void verify_clear_data(void)
96{
97 if (!hal_gpio_digital_read(CLEAR_EEPROM_PIN)) {
98
99 if (clear_time == 0)
100 clear_time = hal_time_ms();
101
102 if (hal_timeout(hal_time_ms(), clear_time, BUTTON_PRESSED_TIME)) {
103 /* close connection */
104 knot_thing_protocol_exit();
105
106 /* generate new MAC addr */
107 hal_storage_reset_end();
108 set_nrf24MAC();
109
110 /* reset thing */
111 reset_function();
112
113 }
114 } else
115 clear_time = 0;
116
117}
118
Tiago Barros864f1d02017-07-21 10:25:34 -0300119static void halt_blinking_led(uint32_t period)
120{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300121 while (1) {
Tiago Barros864f1d02017-07-21 10:25:34 -0300122 hal_gpio_digital_write(PIN_LED_STATUS, 0);
123 hal_delay_ms(period);
124 hal_gpio_digital_write(PIN_LED_STATUS, 1);
125 hal_delay_ms(period);
Larissaca16a322017-12-12 13:37:01 -0300126 verify_clear_data();
Tiago Barros864f1d02017-07-21 10:25:34 -0300127 }
128}
Erick Simões9d64fc82017-02-13 11:04:53 -0300129
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300130static int init_connection(void)
Tiago Barroseee47082017-07-20 15:40:35 -0300131{
132#if (KNOT_DEBUG_ENABLED == 1)
133 char macString[25] = {0};
Claudio Takahasi707e2132017-11-21 16:07:15 -0300134 nrf24_mac2str(&config.mac, macString);
Tiago Barroseee47082017-07-20 15:40:35 -0300135
136 hal_log_str("MAC");
137 hal_log_str(macString);
138#endif
Claudio Takahasi707e2132017-11-21 16:07:15 -0300139 if (hal_comm_init("NRF0", &config) < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300140 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300141
142 sock = hal_comm_socket(HAL_COMM_PF_NRF24, HAL_COMM_PROTO_RAW);
143 if (sock < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300144 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300145
146 clear_time = 0;
147 enable_run = 1;
148 last_timeout = 0;
149
150 return 0;
151}
152
Tiago Barros6f3ab062017-07-07 10:50:44 -0300153int knot_thing_protocol_init(const char *thing_name)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300154{
Erick Simões385cf152017-01-17 14:47:21 -0300155 hal_gpio_pin_mode(PIN_LED_STATUS, OUTPUT);
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300156 hal_gpio_pin_mode(CLEAR_EEPROM_PIN, INPUT_PULLUP);
157
Vitor Barrosa4c95652017-11-06 10:50:08 -0300158 if (thing_name == NULL)
Tiago Barros864f1d02017-07-21 10:25:34 -0300159 halt_blinking_led(NAME_ERROR);
Tiago Barros562946b2017-07-07 10:53:54 -0300160
Cristovao Rufinod8793332017-11-22 14:09:36 -0300161 config.name = (const char *) thing_name;
Tiago Barros562946b2017-07-07 10:53:54 -0300162
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300163 /* Set mac address if it's invalid on eeprom */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300164 hal_storage_read_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300165 sizeof(struct nrf24_mac));
Claudio Takahasic9c480a2017-11-08 13:07:23 -0300166 /* MAC criteria: less significant 32-bits should not be zero */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300167 if (!(config.mac.address.uint64 & 0x00000000ffffffff)) {
Renie Delgado6ecb9292016-12-21 13:33:00 -0300168 hal_storage_reset_end();
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300169 set_nrf24MAC();
Renie Delgado6ecb9292016-12-21 13:33:00 -0300170 }
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300171
Vitor Barrosb6169de2018-02-07 14:04:23 -0300172 config.id = config.mac.address.uint64;
173
Tiago Barroseee47082017-07-20 15:40:35 -0300174 return init_connection();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300175}
176
177void knot_thing_protocol_exit(void)
178{
Tiago Barroseee47082017-07-20 15:40:35 -0300179 hal_comm_close(cli_sock);
Rodrigo Alvesf4eb68b2016-11-09 11:10:12 -0300180 hal_comm_close(sock);
Tiago Barroseee47082017-07-20 15:40:35 -0300181 hal_comm_deinit();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300182 enable_run = 0;
183}
184
Erick Simões385cf152017-01-17 14:47:21 -0300185/*
Tiago Barros896112d2017-07-21 14:08:03 -0300186 * The function receives the number of times LED shall blink.
187 * For each number n, the status LED should flash 2 * n
Erick Simões385cf152017-01-17 14:47:21 -0300188 * (once to light, another to turn off)
189 */
190static void led_status(uint8_t status)
191{
Tiago Barros41587792017-07-07 11:01:45 -0300192 static uint32_t previous_status_time = 0;
193 static uint16_t status_interval;
194 static uint8_t nblink, led_state, previous_led_state = LOW;
Claudio Takahasi8b9b41b2017-03-16 09:03:00 -0300195 uint32_t current_status_time = hal_time_ms();
Erick Simões385cf152017-01-17 14:47:21 -0300196
197 /*
198 * If the LED has lit and off twice the state,
199 * a set a long interval
200 */
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300201 if (nblink >= (status * 2)) {
Erick Simões385cf152017-01-17 14:47:21 -0300202 nblink = 0;
203 status_interval = LONG_INTERVAL;
Tiago Barros896112d2017-07-21 14:08:03 -0300204 hal_gpio_digital_write(PIN_LED_STATUS, 0);
Erick Simões385cf152017-01-17 14:47:21 -0300205 }
206
207 /*
208 * Ensures that whenever the status changes,
209 * the blink starts by turning on the LED
210 **/
211 if (status != previous_led_state) {
212 previous_led_state = status;
213 led_state = LOW;
214 }
215
216 if ((current_status_time - previous_status_time) >= status_interval) {
217 previous_status_time = current_status_time;
218 led_state = !led_state;
219 hal_gpio_digital_write(PIN_LED_STATUS, led_state);
220
221 nblink++;
222 status_interval = SHORT_INTERVAL;
223 }
Erick Simões385cf152017-01-17 14:47:21 -0300224}
225
Tiago Barrosc1e56d52018-03-08 12:02:01 -0300226static void handle_unregister(void) {
227 /* send KNOT_MSG_UNREGISTER_RESP message */
228 msg.hdr.type = KNOT_MSG_UNREGISTER_RESP;
229 msg.action.result = KNOT_SUCCESS;
230 msg.hdr.payload_len = sizeof(msg.action.result);
231 hal_comm_write(cli_sock, &(msg.buffer),
232 sizeof(msg.hdr) + msg.hdr.payload_len);
233
234 /* reset EEPROM (UUID/Token) and generate new MAC addr */
235 hal_storage_reset_end();
236 set_nrf24MAC();
237
238 /* close connection */
239 knot_thing_protocol_exit();
240
241 /* reset thing */
242 reset_function();
243}
244
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300245static int send_register(void)
246{
Larissa Lages7a26df12018-01-04 10:43:14 -0300247 /*
248 * KNOT_MSG_REGISTER_REQ PDU should fit in nRF24 MTU in order
249 * to avoid frame segmentation. Re-transmission may happen
250 * frequently at noisy environments or if the remote is not ready.
251 */
252 uint8_t name_len = NRF24_MTU - (sizeof(msg.reg.hdr) +
253 sizeof(msg.reg.id));
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300254
Larissa Lages7a26df12018-01-04 10:43:14 -0300255 name_len = MIN(name_len, strlen(config.name));
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300256 msg.hdr.type = KNOT_MSG_REGISTER_REQ;
Claudio Takahasid22b3272017-12-05 16:23:20 -0300257 msg.reg.id = config.mac.address.uint64; /* Maps id to nRF24 MAC */
Larissa Lages7a26df12018-01-04 10:43:14 -0300258 strncpy(msg.reg.devName, config.name, name_len);
259 msg.hdr.payload_len = name_len + sizeof(msg.reg.id);
Rodrigo Alvescd2ebec2016-11-29 12:43:59 -0300260
Claudio Takahasid22b3272017-12-05 16:23:20 -0300261 if (hal_comm_write(cli_sock, &(msg.buffer),
262 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300263 return -1;
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300264
265 return 0;
266}
267
268static int read_register(void)
269{
270 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300271
Tiago Barrosd49fd272017-07-07 11:59:25 -0300272 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300273 if (nbytes <= 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300274 return nbytes;
275
Tiago Barros830df552018-03-08 14:12:13 -0300276 if (msg.hdr.type == KNOT_MSG_UNREGISTER_REQ) {
277 handle_unregister();
278 return -1;
279 }
280
281 if (msg.hdr.type != KNOT_MSG_REGISTER_RESP)
282 return -1;
283
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300284 if (msg.cred.result != KNOT_SUCCESS)
285 return -1;
286
287 hal_storage_write_end(HAL_STORAGE_ID_UUID, msg.cred.uuid,
288 KNOT_PROTOCOL_UUID_LEN);
289 hal_storage_write_end(HAL_STORAGE_ID_TOKEN, msg.cred.token,
290 KNOT_PROTOCOL_TOKEN_LEN);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300291 return 0;
292}
293
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300294static int read_auth(void)
295{
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300296 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300297
Tiago Barrosd49fd272017-07-07 11:59:25 -0300298 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300299 if (nbytes <= 0)
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300300 return nbytes;
301
Tiago Barros775fd652018-03-08 14:24:31 -0300302 if (msg.hdr.type == KNOT_MSG_UNREGISTER_REQ) {
303 handle_unregister();
304 return -1;
305 }
306
307 if (msg.hdr.type != KNOT_MSG_AUTH_RESP)
308 return -1;
309
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300310 if (msg.action.result != KNOT_SUCCESS)
311 return -1;
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300312 return 0;
313}
314
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300315static int send_schema(void)
316{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300317 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300318
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300319 err = knot_thing_create_schema(msg_sensor_id, &(msg.schema));
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300320
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300321 if (err < 0)
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300322 return err;
323
Vitor Barrosa4c95652017-11-06 10:50:08 -0300324 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300325 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300326 /* TODO create a better error define in the protocol */
327 return KNOT_ERROR_UNKNOWN;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300328
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300329 return KNOT_SUCCESS;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300330}
331
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300332static int msg_set_config(uint8_t sensor_id)
Rodrigo Alves19108182016-11-08 13:49:22 -0300333{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300334 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300335
Vitor Barrosa4c95652017-11-06 10:50:08 -0300336 err = knot_thing_config_data_item(msg.config.sensor_id,
Tiago Barrosd49fd272017-07-07 11:59:25 -0300337 msg.config.values.event_flags,
338 msg.config.values.time_sec,
339 &(msg.config.values.lower_limit),
340 &(msg.config.values.upper_limit));
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300341 if (err)
Paulo Serra Filho2c36dff2017-01-09 10:33:21 -0300342 return KNOT_ERROR_UNKNOWN;
343
Tiago Barrosd49fd272017-07-07 11:59:25 -0300344 msg.item.sensor_id = sensor_id;
345 msg.hdr.type = KNOT_MSG_CONFIG_RESP;
346 msg.hdr.payload_len = sizeof(msg.item.sensor_id);
Rodrigo Alves19108182016-11-08 13:49:22 -0300347
Vitor Barrosa4c95652017-11-06 10:50:08 -0300348 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300349 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves19108182016-11-08 13:49:22 -0300350 return -1;
351
352 return 0;
353}
354
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300355static int msg_set_data(uint8_t sensor_id)
Rodrigo Alves97001062016-11-08 13:51:48 -0300356{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300357 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300358
Tiago Barrosd49fd272017-07-07 11:59:25 -0300359 err = knot_thing_data_item_write(sensor_id, &(msg.data));
Rodrigo Alves97001062016-11-08 13:51:48 -0300360
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300361 /*
362 * GW must be aware if the data was succesfully set, so we resend
363 * the request only changing the header type
364 */
Tiago Barrosd49fd272017-07-07 11:59:25 -0300365 msg.hdr.type = KNOT_MSG_DATA_RESP;
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300366 /* TODO: Improve error handling: Sensor not found, invalid data, etc */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300367 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300368 msg.hdr.type = KNOT_ERROR_UNKNOWN;
Rodrigo Alves97001062016-11-08 13:51:48 -0300369
Vitor Barrosa4c95652017-11-06 10:50:08 -0300370 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300371 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves52955152016-11-10 09:36:22 -0300372 return -1;
373
374 return 0;
375}
376
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300377static int msg_get_data(uint8_t sensor_id)
Renie Delgado63be4f62016-11-18 11:06:20 -0300378{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300379 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300380
Tiago Barrosd49fd272017-07-07 11:59:25 -0300381 err = knot_thing_data_item_read(sensor_id, &(msg.data));
Tiago Barrosdde937f2017-07-21 14:24:58 -0300382 if (err == -2)
383 return err;
Tiago Barrosd49fd272017-07-07 11:59:25 -0300384
385 msg.hdr.type = KNOT_MSG_DATA;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300386 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300387 msg.hdr.type = KNOT_ERROR_UNKNOWN;
388
389 msg.data.sensor_id = sensor_id;
390
Vitor Barrosa4c95652017-11-06 10:50:08 -0300391 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300392 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
393 return -1;
Renie Delgado63be4f62016-11-18 11:06:20 -0300394
395 return 0;
396}
397
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300398static inline int is_uuid(const char *string)
399{
Tiago Barros62ec6622017-07-10 15:51:32 -0300400 return (string != NULL && string[8] == '-' &&
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300401 string[13] == '-' && string[18] == '-' && string[23] == '-');
402}
403
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300404static int8_t mgmt_read(void)
405{
406 uint8_t buffer[MTU];
407 struct mgmt_nrf24_header *mhdr = (struct mgmt_nrf24_header *) buffer;
Vitor Barros5f00faf2017-11-13 10:48:31 -0300408 ssize_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300409
Vitor Barros5f00faf2017-11-13 10:48:31 -0300410 retval = hal_comm_read(sock, buffer, sizeof(buffer));
411 if (retval < 0)
412 return retval;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300413
414 /* Return/ignore if it is not an event? */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300415 if (!(mhdr->opcode & 0x0200))
Vitor Barros5f00faf2017-11-13 10:48:31 -0300416 return -EPROTO;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300417
418 switch (mhdr->opcode) {
419
420 case MGMT_EVT_NRF24_DISCONNECTED:
Vitor Barros5f00faf2017-11-13 10:48:31 -0300421 return -ENOTCONN;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300422 }
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300423
Vitor Barros5f00faf2017-11-13 10:48:31 -0300424 return 0;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300425}
426
Vitor Barrosa4c95652017-11-06 10:50:08 -0300427static void read_online_messages(void)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300428{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300429 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) <= 0)
430 return;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300431
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300432 /* There is a message to read */
433 switch (msg.hdr.type) {
434 case KNOT_MSG_SET_CONFIG:
435 msg_set_config(msg.config.sensor_id);
436 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300437
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300438 case KNOT_MSG_SET_DATA:
439 msg_set_data(msg.data.sensor_id);
440 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300441
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300442 case KNOT_MSG_GET_DATA:
443 msg_get_data(msg.item.sensor_id);
444 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300445
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300446 case KNOT_MSG_DATA_RESP:
447 hal_log_str("DT RSP");
448 if (msg.action.result != KNOT_SUCCESS) {
449 hal_log_str("DT R ERR");
450 msg_get_data(msg.item.sensor_id);
Paulo Serra Filho58dd0302016-11-22 17:59:24 -0300451 }
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300452 break;
453
454 default:
455 /* Invalid command, ignore */
456 break;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300457 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300458}
459
460int knot_thing_protocol_run(void)
461{
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300462 static uint8_t run_state = STATE_DISCONNECTED;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300463
Claudio Takahasi552d2a02017-06-12 14:22:08 -0300464 struct nrf24_mac peer;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300465 int8_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300466
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300467 /*
468 * Verifies if the button for eeprom clear is pressed for more than 5s
469 */
Larissaca16a322017-12-12 13:37:01 -0300470 verify_clear_data();
Tiago Barroseee47082017-07-20 15:40:35 -0300471
472 if (enable_run == 0) {
473 return -1;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300474 }
475
Vitor Barros5f00faf2017-11-13 10:48:31 -0300476 if (run_state >= STATE_CONNECTED) {
477 if (mgmt_read() == -ENOTCONN)
478 run_state = STATE_DISCONNECTED;
479 }
480
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300481 /* Network message handling state machine */
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300482 switch (run_state) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300483 case STATE_DISCONNECTED:
484 /* Internally listen starts broadcasting presence*/
Tiago Barros896112d2017-07-21 14:08:03 -0300485 led_status(BLINK_DISCONNECTED);
Tiago Barrosd39fc9c2017-07-18 10:31:23 -0300486 hal_comm_close(cli_sock);
Tiago Barros8c61bd52017-07-18 16:51:28 -0300487 hal_log_str("DISC");
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300488 if (hal_comm_listen(sock) < 0) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300489 break;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300490 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300491
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300492 run_state = STATE_ACCEPTING;
493 hal_log_str("ACCT");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300494 break;
495
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300496 case STATE_ACCEPTING:
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300497 /*
498 * Try to accept GW connection request. EAGAIN means keep
499 * waiting, less then 0 means error and greater then 0 success
500 */
Tiago Barros896112d2017-07-21 14:08:03 -0300501 led_status(BLINK_DISCONNECTED);
Claudio Takahasi8b54e652017-07-03 13:38:00 -0300502 cli_sock = hal_comm_accept(sock, (void *) &peer);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300503 if (cli_sock == -EAGAIN)
504 break;
505 else if (cli_sock < 0) {
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300506 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300507 break;
508 }
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300509 run_state = STATE_CONNECTED;
510 hal_log_str("CONN");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300511 break;
512
513 case STATE_CONNECTED:
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300514 /*
515 * If uuid/token were found, read the addresses and send
516 * the auth request, otherwise register request
517 */
Tiago Barros896112d2017-07-21 14:08:03 -0300518 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300519 hal_storage_read_end(HAL_STORAGE_ID_UUID, &(msg.auth.uuid),
520 KNOT_PROTOCOL_UUID_LEN);
521 hal_storage_read_end(HAL_STORAGE_ID_TOKEN, &(msg.auth.token),
522 KNOT_PROTOCOL_TOKEN_LEN);
523
524 if (is_uuid(msg.auth.uuid)) {
525 run_state = STATE_AUTHENTICATING;
526 hal_log_str("AUTH");
527 msg.hdr.type = KNOT_MSG_AUTH_REQ;
Vitor Barrosa4c95652017-11-06 10:50:08 -0300528 msg.hdr.payload_len = KNOT_PROTOCOL_UUID_LEN +
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300529 KNOT_PROTOCOL_TOKEN_LEN;
530
Vitor Barrosa4c95652017-11-06 10:50:08 -0300531 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300532 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
533 run_state = STATE_ERROR;
534 } else {
535 hal_log_str("REG");
536 run_state = STATE_REGISTERING;
537 if (send_register() < 0)
538 run_state = STATE_ERROR;
539 }
540 last_timeout = hal_time_ms();
541 break;
542
543 /*
544 * Authenticating, Resgistering cases waits (without blocking)
545 * for an response of the respective requests, -EAGAIN means there was
546 * nothing to read so we ignore it, less then 0 an error and 0 success
547 */
548 case STATE_AUTHENTICATING:
Tiago Barros896112d2017-07-21 14:08:03 -0300549 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300550 retval = read_auth();
551 if (retval == KNOT_SUCCESS) {
552 run_state = STATE_ONLINE;
553 hal_log_str("ONLN");
554 /* Checks if all the schemas were sent to the GW and */
555 hal_storage_read_end(HAL_STORAGE_ID_SCHEMA_FLAG,
556 &schema_flag, sizeof(schema_flag));
557 if (!schema_flag)
558 run_state = STATE_SCHEMA;
559 }
560 else if (retval != -EAGAIN)
Larissaca16a322017-12-12 13:37:01 -0300561 halt_blinking_led(AUTH_ERROR);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300562 else if (hal_timeout(hal_time_ms(), last_timeout,
563 RETRANSMISSION_TIMEOUT) > 0)
564 run_state = STATE_CONNECTED;
565 break;
566
567 case STATE_REGISTERING:
Tiago Barros896112d2017-07-21 14:08:03 -0300568 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300569 retval = read_register();
570 if (!retval)
571 run_state = STATE_SCHEMA;
572 else if (retval != -EAGAIN)
573 run_state = STATE_ERROR;
574 else if (hal_timeout(hal_time_ms(), last_timeout,
575 RETRANSMISSION_TIMEOUT) > 0)
576 run_state = STATE_CONNECTED;
577 break;
578
579 /*
580 * STATE_SCHEMA tries to send an schema and go to STATE_SCHEMA_RESP to
581 * wait for the ack of this schema. If there is no schema for that
582 * msg_sensor_id, increments and stays in the STATE_SCHEMA. If an
583 * error occurs, goes to STATE_ERROR.
584 */
585 case STATE_SCHEMA:
Tiago Barros896112d2017-07-21 14:08:03 -0300586 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300587 hal_log_str("SCH");
588 retval = send_schema();
589 switch (retval) {
590 case KNOT_SUCCESS:
591 last_timeout = hal_time_ms();
592 run_state = STATE_SCHEMA_RESP;
593 break;
594 case KNOT_ERROR_UNKNOWN:
595 run_state = STATE_ERROR;
596 break;
597 case KNOT_SCHEMA_EMPTY:
598 case KNOT_INVALID_DEVICE:
599 run_state = STATE_SCHEMA;
600 msg_sensor_id++;
601 break;
602 default:
603 run_state = STATE_ERROR;
604 break;
605 }
606 break;
607
608 /*
609 * Receives the ack from the GW and returns to STATE_SCHEMA to send the
610 * next schema. If it was the ack for the last schema, goes to
611 * STATE_ONLINE. If it is not a KNOT_MSG_SCHEMA_RESP, ignores. If the
612 * result was not KNOT_SUCCESS, goes to STATE_ERROR.
613 */
614 case STATE_SCHEMA_RESP:
Tiago Barros896112d2017-07-21 14:08:03 -0300615 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300616 hal_log_str("SCH_R");
617 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) > 0) {
618 if (msg.hdr.type != KNOT_MSG_SCHEMA_RESP &&
619 msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP)
620 break;
621 if (msg.action.result != KNOT_SUCCESS) {
622 run_state = STATE_SCHEMA;
623 break;
624 }
625 if (msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP) {
626 run_state = STATE_SCHEMA;
627 msg_sensor_id++;
628 break;
629 }
630 /* All the schemas were sent to GW */
631 schema_flag = true;
632 hal_storage_write_end(HAL_STORAGE_ID_SCHEMA_FLAG,
633 &schema_flag, sizeof(schema_flag));
634 run_state = STATE_ONLINE;
635 hal_log_str("ONLN");
636 msg_sensor_id = 0;
637 } else if (hal_timeout(hal_time_ms(), last_timeout,
638 RETRANSMISSION_TIMEOUT) > 0)
639 run_state = STATE_SCHEMA;
640 break;
641
642 case STATE_ONLINE:
Tiago Barros896112d2017-07-21 14:08:03 -0300643 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300644 read_online_messages();
645 msg_sensor_id++;
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300646 msg_get_data(msg_sensor_id);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300647 hal_log_str("DT");
648 if (msg_sensor_id >= KNOT_THING_DATA_MAX) {
649 msg_sensor_id = 0;
650 run_state = STATE_RUNNING;
651 hal_log_str("RUN");
652 }
653 break;
654
655 case STATE_RUNNING:
Tiago Barros896112d2017-07-21 14:08:03 -0300656 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300657 read_online_messages();
658 /* If some event ocurred send msg_data */
659 if (knot_thing_verify_events(&(msg.data)) == 0) {
660 if (hal_comm_write(cli_sock, &(msg.buffer),
661 sizeof(msg.hdr) + msg.hdr.payload_len) < 0) {
662 hal_log_str("DT ERR");
663 hal_comm_write(cli_sock, &(msg.buffer),
664 sizeof(msg.hdr) + msg.hdr.payload_len);
665 } else {
666 hal_log_str("DT");
667 }
668 }
669 break;
670
671 case STATE_ERROR:
Tiago Barros896112d2017-07-21 14:08:03 -0300672 hal_gpio_digital_write(PIN_LED_STATUS, 1);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300673 hal_log_str("ERR");
Vitor Barros5f00faf2017-11-13 10:48:31 -0300674 /* TODO: Review error state handling */
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300675 run_state = STATE_DISCONNECTED;
Tiago Barros896112d2017-07-21 14:08:03 -0300676 hal_delay_ms(1000);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300677 break;
678
679 default:
Tiago Barros8c61bd52017-07-18 16:51:28 -0300680 hal_log_str("INV");
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300681 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300682 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300683 }
684
685 return 0;
Rodrigo Alves19108182016-11-08 13:49:22 -0300686}