blob: 918cb8f419206107c4548bfc64dc71a062af944b [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
Tiago Barroseee47082017-07-20 15:40:35 -0300172 return init_connection();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300173}
174
175void knot_thing_protocol_exit(void)
176{
Tiago Barroseee47082017-07-20 15:40:35 -0300177 hal_comm_close(cli_sock);
Rodrigo Alvesf4eb68b2016-11-09 11:10:12 -0300178 hal_comm_close(sock);
Tiago Barroseee47082017-07-20 15:40:35 -0300179 hal_comm_deinit();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300180 enable_run = 0;
181}
182
Erick Simões385cf152017-01-17 14:47:21 -0300183/*
Tiago Barros896112d2017-07-21 14:08:03 -0300184 * The function receives the number of times LED shall blink.
185 * For each number n, the status LED should flash 2 * n
Erick Simões385cf152017-01-17 14:47:21 -0300186 * (once to light, another to turn off)
187 */
188static void led_status(uint8_t status)
189{
Tiago Barros41587792017-07-07 11:01:45 -0300190 static uint32_t previous_status_time = 0;
191 static uint16_t status_interval;
192 static uint8_t nblink, led_state, previous_led_state = LOW;
Claudio Takahasi8b9b41b2017-03-16 09:03:00 -0300193 uint32_t current_status_time = hal_time_ms();
Erick Simões385cf152017-01-17 14:47:21 -0300194
195 /*
196 * If the LED has lit and off twice the state,
197 * a set a long interval
198 */
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300199 if (nblink >= (status * 2)) {
Erick Simões385cf152017-01-17 14:47:21 -0300200 nblink = 0;
201 status_interval = LONG_INTERVAL;
Tiago Barros896112d2017-07-21 14:08:03 -0300202 hal_gpio_digital_write(PIN_LED_STATUS, 0);
Erick Simões385cf152017-01-17 14:47:21 -0300203 }
204
205 /*
206 * Ensures that whenever the status changes,
207 * the blink starts by turning on the LED
208 **/
209 if (status != previous_led_state) {
210 previous_led_state = status;
211 led_state = LOW;
212 }
213
214 if ((current_status_time - previous_status_time) >= status_interval) {
215 previous_status_time = current_status_time;
216 led_state = !led_state;
217 hal_gpio_digital_write(PIN_LED_STATUS, led_state);
218
219 nblink++;
220 status_interval = SHORT_INTERVAL;
221 }
Erick Simões385cf152017-01-17 14:47:21 -0300222}
223
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300224static int send_register(void)
225{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300226 uint8_t len;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300227
Cristovao Rufinod8793332017-11-22 14:09:36 -0300228 len = MIN(sizeof(msg.reg.devName), strlen(config.name));
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300229 msg.hdr.type = KNOT_MSG_REGISTER_REQ;
Claudio Takahasid22b3272017-12-05 16:23:20 -0300230 msg.reg.id = config.mac.address.uint64; /* Maps id to nRF24 MAC */
Cristovao Rufinod8793332017-11-22 14:09:36 -0300231 strncpy(msg.reg.devName, config.name, len);
Claudio Takahasid22b3272017-12-05 16:23:20 -0300232 msg.hdr.payload_len = len + sizeof(msg.reg.id);
Rodrigo Alvescd2ebec2016-11-29 12:43:59 -0300233
Claudio Takahasid22b3272017-12-05 16:23:20 -0300234 if (hal_comm_write(cli_sock, &(msg.buffer),
235 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300236 return -1;
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300237
238 return 0;
239}
240
241static int read_register(void)
242{
243 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300244
Tiago Barrosd49fd272017-07-07 11:59:25 -0300245 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300246 if (nbytes <= 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300247 return nbytes;
248
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300249 if (msg.cred.result != KNOT_SUCCESS)
250 return -1;
251
252 hal_storage_write_end(HAL_STORAGE_ID_UUID, msg.cred.uuid,
253 KNOT_PROTOCOL_UUID_LEN);
254 hal_storage_write_end(HAL_STORAGE_ID_TOKEN, msg.cred.token,
255 KNOT_PROTOCOL_TOKEN_LEN);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300256 return 0;
257}
258
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300259static int read_auth(void)
260{
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300261 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300262
Tiago Barrosd49fd272017-07-07 11:59:25 -0300263 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300264 if (nbytes <= 0)
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300265 return nbytes;
266
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300267 if (msg.action.result != KNOT_SUCCESS)
268 return -1;
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300269 return 0;
270}
271
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300272static int send_schema(void)
273{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300274 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300275
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300276 err = knot_thing_create_schema(msg_sensor_id, &(msg.schema));
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300277
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300278 if (err < 0)
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300279 return err;
280
Vitor Barrosa4c95652017-11-06 10:50:08 -0300281 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300282 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300283 /* TODO create a better error define in the protocol */
284 return KNOT_ERROR_UNKNOWN;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300285
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300286 return KNOT_SUCCESS;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300287}
288
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300289static int msg_set_config(uint8_t sensor_id)
Rodrigo Alves19108182016-11-08 13:49:22 -0300290{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300291 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300292
Vitor Barrosa4c95652017-11-06 10:50:08 -0300293 err = knot_thing_config_data_item(msg.config.sensor_id,
Tiago Barrosd49fd272017-07-07 11:59:25 -0300294 msg.config.values.event_flags,
295 msg.config.values.time_sec,
296 &(msg.config.values.lower_limit),
297 &(msg.config.values.upper_limit));
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300298 if (err)
Paulo Serra Filho2c36dff2017-01-09 10:33:21 -0300299 return KNOT_ERROR_UNKNOWN;
300
Tiago Barrosd49fd272017-07-07 11:59:25 -0300301 msg.item.sensor_id = sensor_id;
302 msg.hdr.type = KNOT_MSG_CONFIG_RESP;
303 msg.hdr.payload_len = sizeof(msg.item.sensor_id);
Rodrigo Alves19108182016-11-08 13:49:22 -0300304
Vitor Barrosa4c95652017-11-06 10:50:08 -0300305 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300306 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves19108182016-11-08 13:49:22 -0300307 return -1;
308
309 return 0;
310}
311
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300312static int msg_set_data(uint8_t sensor_id)
Rodrigo Alves97001062016-11-08 13:51:48 -0300313{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300314 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300315
Tiago Barrosd49fd272017-07-07 11:59:25 -0300316 err = knot_thing_data_item_write(sensor_id, &(msg.data));
Rodrigo Alves97001062016-11-08 13:51:48 -0300317
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300318 /*
319 * GW must be aware if the data was succesfully set, so we resend
320 * the request only changing the header type
321 */
Tiago Barrosd49fd272017-07-07 11:59:25 -0300322 msg.hdr.type = KNOT_MSG_DATA_RESP;
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300323 /* TODO: Improve error handling: Sensor not found, invalid data, etc */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300324 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300325 msg.hdr.type = KNOT_ERROR_UNKNOWN;
Rodrigo Alves97001062016-11-08 13:51:48 -0300326
Vitor Barrosa4c95652017-11-06 10:50:08 -0300327 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300328 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves52955152016-11-10 09:36:22 -0300329 return -1;
330
331 return 0;
332}
333
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300334static int msg_get_data(uint8_t sensor_id)
Renie Delgado63be4f62016-11-18 11:06:20 -0300335{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300336 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300337
Tiago Barrosd49fd272017-07-07 11:59:25 -0300338 err = knot_thing_data_item_read(sensor_id, &(msg.data));
Tiago Barrosdde937f2017-07-21 14:24:58 -0300339 if (err == -2)
340 return err;
Tiago Barrosd49fd272017-07-07 11:59:25 -0300341
342 msg.hdr.type = KNOT_MSG_DATA;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300343 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300344 msg.hdr.type = KNOT_ERROR_UNKNOWN;
345
346 msg.data.sensor_id = sensor_id;
347
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)
350 return -1;
Renie Delgado63be4f62016-11-18 11:06:20 -0300351
352 return 0;
353}
354
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300355static inline int is_uuid(const char *string)
356{
Tiago Barros62ec6622017-07-10 15:51:32 -0300357 return (string != NULL && string[8] == '-' &&
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300358 string[13] == '-' && string[18] == '-' && string[23] == '-');
359}
360
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300361static int8_t mgmt_read(void)
362{
363 uint8_t buffer[MTU];
364 struct mgmt_nrf24_header *mhdr = (struct mgmt_nrf24_header *) buffer;
Vitor Barros5f00faf2017-11-13 10:48:31 -0300365 ssize_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300366
Vitor Barros5f00faf2017-11-13 10:48:31 -0300367 retval = hal_comm_read(sock, buffer, sizeof(buffer));
368 if (retval < 0)
369 return retval;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300370
371 /* Return/ignore if it is not an event? */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300372 if (!(mhdr->opcode & 0x0200))
Vitor Barros5f00faf2017-11-13 10:48:31 -0300373 return -EPROTO;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300374
375 switch (mhdr->opcode) {
376
377 case MGMT_EVT_NRF24_DISCONNECTED:
Vitor Barros5f00faf2017-11-13 10:48:31 -0300378 return -ENOTCONN;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300379 }
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300380
Vitor Barros5f00faf2017-11-13 10:48:31 -0300381 return 0;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300382}
383
Vitor Barrosa4c95652017-11-06 10:50:08 -0300384static void read_online_messages(void)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300385{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300386 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) <= 0)
387 return;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300388
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300389 /* There is a message to read */
390 switch (msg.hdr.type) {
391 case KNOT_MSG_SET_CONFIG:
392 msg_set_config(msg.config.sensor_id);
393 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300394
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300395 case KNOT_MSG_SET_DATA:
396 msg_set_data(msg.data.sensor_id);
397 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300398
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300399 case KNOT_MSG_GET_DATA:
400 msg_get_data(msg.item.sensor_id);
401 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300402
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300403 case KNOT_MSG_DATA_RESP:
404 hal_log_str("DT RSP");
405 if (msg.action.result != KNOT_SUCCESS) {
406 hal_log_str("DT R ERR");
407 msg_get_data(msg.item.sensor_id);
Paulo Serra Filho58dd0302016-11-22 17:59:24 -0300408 }
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300409 break;
410
411 default:
412 /* Invalid command, ignore */
413 break;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300414 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300415}
416
417int knot_thing_protocol_run(void)
418{
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300419 static uint8_t run_state = STATE_DISCONNECTED;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300420
Claudio Takahasi552d2a02017-06-12 14:22:08 -0300421 struct nrf24_mac peer;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300422 int8_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300423
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300424 /*
425 * Verifies if the button for eeprom clear is pressed for more than 5s
426 */
Larissaca16a322017-12-12 13:37:01 -0300427 verify_clear_data();
Tiago Barroseee47082017-07-20 15:40:35 -0300428
429 if (enable_run == 0) {
430 return -1;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300431 }
432
Vitor Barros5f00faf2017-11-13 10:48:31 -0300433 if (run_state >= STATE_CONNECTED) {
434 if (mgmt_read() == -ENOTCONN)
435 run_state = STATE_DISCONNECTED;
436 }
437
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300438 /* Network message handling state machine */
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300439 switch (run_state) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300440 case STATE_DISCONNECTED:
441 /* Internally listen starts broadcasting presence*/
Tiago Barros896112d2017-07-21 14:08:03 -0300442 led_status(BLINK_DISCONNECTED);
Tiago Barrosd39fc9c2017-07-18 10:31:23 -0300443 hal_comm_close(cli_sock);
Tiago Barros8c61bd52017-07-18 16:51:28 -0300444 hal_log_str("DISC");
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300445 if (hal_comm_listen(sock) < 0) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300446 break;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300447 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300448
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300449 run_state = STATE_ACCEPTING;
450 hal_log_str("ACCT");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300451 break;
452
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300453 case STATE_ACCEPTING:
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300454 /*
455 * Try to accept GW connection request. EAGAIN means keep
456 * waiting, less then 0 means error and greater then 0 success
457 */
Tiago Barros896112d2017-07-21 14:08:03 -0300458 led_status(BLINK_DISCONNECTED);
Claudio Takahasi8b54e652017-07-03 13:38:00 -0300459 cli_sock = hal_comm_accept(sock, (void *) &peer);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300460 if (cli_sock == -EAGAIN)
461 break;
462 else if (cli_sock < 0) {
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300463 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300464 break;
465 }
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300466 run_state = STATE_CONNECTED;
467 hal_log_str("CONN");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300468 break;
469
470 case STATE_CONNECTED:
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300471 /*
472 * If uuid/token were found, read the addresses and send
473 * the auth request, otherwise register request
474 */
Tiago Barros896112d2017-07-21 14:08:03 -0300475 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300476 hal_storage_read_end(HAL_STORAGE_ID_UUID, &(msg.auth.uuid),
477 KNOT_PROTOCOL_UUID_LEN);
478 hal_storage_read_end(HAL_STORAGE_ID_TOKEN, &(msg.auth.token),
479 KNOT_PROTOCOL_TOKEN_LEN);
480
481 if (is_uuid(msg.auth.uuid)) {
482 run_state = STATE_AUTHENTICATING;
483 hal_log_str("AUTH");
484 msg.hdr.type = KNOT_MSG_AUTH_REQ;
Vitor Barrosa4c95652017-11-06 10:50:08 -0300485 msg.hdr.payload_len = KNOT_PROTOCOL_UUID_LEN +
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300486 KNOT_PROTOCOL_TOKEN_LEN;
487
Vitor Barrosa4c95652017-11-06 10:50:08 -0300488 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300489 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
490 run_state = STATE_ERROR;
491 } else {
492 hal_log_str("REG");
493 run_state = STATE_REGISTERING;
494 if (send_register() < 0)
495 run_state = STATE_ERROR;
496 }
497 last_timeout = hal_time_ms();
498 break;
499
500 /*
501 * Authenticating, Resgistering cases waits (without blocking)
502 * for an response of the respective requests, -EAGAIN means there was
503 * nothing to read so we ignore it, less then 0 an error and 0 success
504 */
505 case STATE_AUTHENTICATING:
Tiago Barros896112d2017-07-21 14:08:03 -0300506 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300507 retval = read_auth();
508 if (retval == KNOT_SUCCESS) {
509 run_state = STATE_ONLINE;
510 hal_log_str("ONLN");
511 /* Checks if all the schemas were sent to the GW and */
512 hal_storage_read_end(HAL_STORAGE_ID_SCHEMA_FLAG,
513 &schema_flag, sizeof(schema_flag));
514 if (!schema_flag)
515 run_state = STATE_SCHEMA;
516 }
517 else if (retval != -EAGAIN)
Larissaca16a322017-12-12 13:37:01 -0300518 halt_blinking_led(AUTH_ERROR);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300519 else if (hal_timeout(hal_time_ms(), last_timeout,
520 RETRANSMISSION_TIMEOUT) > 0)
521 run_state = STATE_CONNECTED;
522 break;
523
524 case STATE_REGISTERING:
Tiago Barros896112d2017-07-21 14:08:03 -0300525 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300526 retval = read_register();
527 if (!retval)
528 run_state = STATE_SCHEMA;
529 else if (retval != -EAGAIN)
530 run_state = STATE_ERROR;
531 else if (hal_timeout(hal_time_ms(), last_timeout,
532 RETRANSMISSION_TIMEOUT) > 0)
533 run_state = STATE_CONNECTED;
534 break;
535
536 /*
537 * STATE_SCHEMA tries to send an schema and go to STATE_SCHEMA_RESP to
538 * wait for the ack of this schema. If there is no schema for that
539 * msg_sensor_id, increments and stays in the STATE_SCHEMA. If an
540 * error occurs, goes to STATE_ERROR.
541 */
542 case STATE_SCHEMA:
Tiago Barros896112d2017-07-21 14:08:03 -0300543 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300544 hal_log_str("SCH");
545 retval = send_schema();
546 switch (retval) {
547 case KNOT_SUCCESS:
548 last_timeout = hal_time_ms();
549 run_state = STATE_SCHEMA_RESP;
550 break;
551 case KNOT_ERROR_UNKNOWN:
552 run_state = STATE_ERROR;
553 break;
554 case KNOT_SCHEMA_EMPTY:
555 case KNOT_INVALID_DEVICE:
556 run_state = STATE_SCHEMA;
557 msg_sensor_id++;
558 break;
559 default:
560 run_state = STATE_ERROR;
561 break;
562 }
563 break;
564
565 /*
566 * Receives the ack from the GW and returns to STATE_SCHEMA to send the
567 * next schema. If it was the ack for the last schema, goes to
568 * STATE_ONLINE. If it is not a KNOT_MSG_SCHEMA_RESP, ignores. If the
569 * result was not KNOT_SUCCESS, goes to STATE_ERROR.
570 */
571 case STATE_SCHEMA_RESP:
Tiago Barros896112d2017-07-21 14:08:03 -0300572 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300573 hal_log_str("SCH_R");
574 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) > 0) {
575 if (msg.hdr.type != KNOT_MSG_SCHEMA_RESP &&
576 msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP)
577 break;
578 if (msg.action.result != KNOT_SUCCESS) {
579 run_state = STATE_SCHEMA;
580 break;
581 }
582 if (msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP) {
583 run_state = STATE_SCHEMA;
584 msg_sensor_id++;
585 break;
586 }
587 /* All the schemas were sent to GW */
588 schema_flag = true;
589 hal_storage_write_end(HAL_STORAGE_ID_SCHEMA_FLAG,
590 &schema_flag, sizeof(schema_flag));
591 run_state = STATE_ONLINE;
592 hal_log_str("ONLN");
593 msg_sensor_id = 0;
594 } else if (hal_timeout(hal_time_ms(), last_timeout,
595 RETRANSMISSION_TIMEOUT) > 0)
596 run_state = STATE_SCHEMA;
597 break;
598
599 case STATE_ONLINE:
Tiago Barros896112d2017-07-21 14:08:03 -0300600 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300601 read_online_messages();
602 msg_sensor_id++;
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300603 msg_get_data(msg_sensor_id);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300604 hal_log_str("DT");
605 if (msg_sensor_id >= KNOT_THING_DATA_MAX) {
606 msg_sensor_id = 0;
607 run_state = STATE_RUNNING;
608 hal_log_str("RUN");
609 }
610 break;
611
612 case STATE_RUNNING:
Tiago Barros896112d2017-07-21 14:08:03 -0300613 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300614 read_online_messages();
615 /* If some event ocurred send msg_data */
616 if (knot_thing_verify_events(&(msg.data)) == 0) {
617 if (hal_comm_write(cli_sock, &(msg.buffer),
618 sizeof(msg.hdr) + msg.hdr.payload_len) < 0) {
619 hal_log_str("DT ERR");
620 hal_comm_write(cli_sock, &(msg.buffer),
621 sizeof(msg.hdr) + msg.hdr.payload_len);
622 } else {
623 hal_log_str("DT");
624 }
625 }
626 break;
627
628 case STATE_ERROR:
Tiago Barros896112d2017-07-21 14:08:03 -0300629 hal_gpio_digital_write(PIN_LED_STATUS, 1);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300630 hal_log_str("ERR");
Vitor Barros5f00faf2017-11-13 10:48:31 -0300631 /* TODO: Review error state handling */
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300632 run_state = STATE_DISCONNECTED;
Tiago Barros896112d2017-07-21 14:08:03 -0300633 hal_delay_ms(1000);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300634 break;
635
636 default:
Tiago Barros8c61bd52017-07-18 16:51:28 -0300637 hal_log_str("INV");
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300638 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300639 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300640 }
641
642 return 0;
Rodrigo Alves19108182016-11-08 13:49:22 -0300643}