blob: af532a11f23629393c2726b73fdd7a94779675b8 [file] [log] [blame]
Tiago Barrosc182ada2016-11-03 10:51:28 -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 */
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 */
Tiago Barros896112d2017-07-21 14:08:03 -030046#define LONG_INTERVAL 5000
47#define SHORT_INTERVAL 250
48
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
57
Rodrigo Alvesc623c042016-12-14 09:59:27 -030058/* KNoT MTU */
59#define MTU 256
60
Rodrigo Alves2d602ae2016-11-04 14:03:13 -030061#ifndef MIN
62#define MIN(a,b) (((a) < (b)) ? (a) : (b))
63#endif
64
Erick Simões385cf152017-01-17 14:47:21 -030065/* Retransmission timeout in ms */
Rodrigo Alvesfe97dad2016-12-13 14:03:19 -030066#define RETRANSMISSION_TIMEOUT 20000
67
Tiago Barrosd49fd272017-07-07 11:59:25 -030068static knot_msg msg;
Claudio Takahasi707e2132017-11-21 16:07:15 -030069static struct nrf24_config config = { .mac = 0, .channel = 76 };
Tiago Barros41587792017-07-07 11:01:45 -030070static unsigned long clear_time;
71static uint32_t last_timeout;
Tiago Barrosb74f0992017-07-10 15:49:15 -030072static char *device_name = NULL;
Rodrigo Alvesf10624f2016-11-09 11:05:16 -030073static int sock = -1;
Rodrigo Alves482954a2016-11-22 08:04:20 -030074static int cli_sock = -1;
Paulo Serra Filhoe105eca2017-01-05 22:22:07 -030075static bool schema_flag = false;
Tiago Barros2ebe55a2017-07-20 17:18:01 -030076static uint8_t enable_run = 0, msg_sensor_id = 0;
Renie Delgadof0206e92016-11-25 09:39:13 -030077
78/*
79 * FIXME: Thing address should be received via NFC
80 * Mac address must be stored in big endian format
81 */
Claudio Takahasic2c1d9d2017-05-15 15:55:39 -030082static void set_nrf24MAC(void)
Renie Delgadof0206e92016-11-25 09:39:13 -030083{
Claudio Takahasi707e2132017-11-21 16:07:15 -030084 hal_getrandom(config.mac.address.b, sizeof(struct nrf24_mac));
85 hal_storage_write_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -030086 sizeof(struct nrf24_mac));
Renie Delgadof0206e92016-11-25 09:39:13 -030087}
Tiago Barros864f1d02017-07-21 10:25:34 -030088static void halt_blinking_led(uint32_t period)
89{
Claudio Takahasi25d2e432017-11-20 14:14:25 -030090 while (1) {
Tiago Barros864f1d02017-07-21 10:25:34 -030091 hal_gpio_digital_write(PIN_LED_STATUS, 0);
92 hal_delay_ms(period);
93 hal_gpio_digital_write(PIN_LED_STATUS, 1);
94 hal_delay_ms(period);
95 }
96}
Erick Simões9d64fc82017-02-13 11:04:53 -030097
Claudio Takahasi25d2e432017-11-20 14:14:25 -030098static int init_connection(void)
Tiago Barroseee47082017-07-20 15:40:35 -030099{
100#if (KNOT_DEBUG_ENABLED == 1)
101 char macString[25] = {0};
Claudio Takahasi707e2132017-11-21 16:07:15 -0300102 nrf24_mac2str(&config.mac, macString);
Tiago Barroseee47082017-07-20 15:40:35 -0300103
104 hal_log_str("MAC");
105 hal_log_str(macString);
106#endif
Claudio Takahasi707e2132017-11-21 16:07:15 -0300107 if (hal_comm_init("NRF0", &config) < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300108 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300109
110 sock = hal_comm_socket(HAL_COMM_PF_NRF24, HAL_COMM_PROTO_RAW);
111 if (sock < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300112 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300113
114 clear_time = 0;
115 enable_run = 1;
116 last_timeout = 0;
117
118 return 0;
119}
120
Tiago Barros6f3ab062017-07-07 10:50:44 -0300121int knot_thing_protocol_init(const char *thing_name)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300122{
Erick Simões385cf152017-01-17 14:47:21 -0300123 hal_gpio_pin_mode(PIN_LED_STATUS, OUTPUT);
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300124 hal_gpio_pin_mode(CLEAR_EEPROM_PIN, INPUT_PULLUP);
125
Vitor Barrosa4c95652017-11-06 10:50:08 -0300126 if (thing_name == NULL)
Tiago Barros864f1d02017-07-21 10:25:34 -0300127 halt_blinking_led(NAME_ERROR);
Tiago Barros562946b2017-07-07 10:53:54 -0300128
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300129 device_name = (char *) thing_name;
Tiago Barros562946b2017-07-07 10:53:54 -0300130
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300131 /* Set mac address if it's invalid on eeprom */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300132 hal_storage_read_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300133 sizeof(struct nrf24_mac));
Claudio Takahasic9c480a2017-11-08 13:07:23 -0300134 /* MAC criteria: less significant 32-bits should not be zero */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300135 if (!(config.mac.address.uint64 & 0x00000000ffffffff)) {
Renie Delgado6ecb9292016-12-21 13:33:00 -0300136 hal_storage_reset_end();
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300137 set_nrf24MAC();
Renie Delgado6ecb9292016-12-21 13:33:00 -0300138 }
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300139
Tiago Barroseee47082017-07-20 15:40:35 -0300140 return init_connection();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300141}
142
143void knot_thing_protocol_exit(void)
144{
Tiago Barroseee47082017-07-20 15:40:35 -0300145 hal_comm_close(cli_sock);
Rodrigo Alvesf4eb68b2016-11-09 11:10:12 -0300146 hal_comm_close(sock);
Tiago Barroseee47082017-07-20 15:40:35 -0300147 hal_comm_deinit();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300148 enable_run = 0;
149}
150
Erick Simões385cf152017-01-17 14:47:21 -0300151/*
Tiago Barros896112d2017-07-21 14:08:03 -0300152 * The function receives the number of times LED shall blink.
153 * For each number n, the status LED should flash 2 * n
Erick Simões385cf152017-01-17 14:47:21 -0300154 * (once to light, another to turn off)
155 */
156static void led_status(uint8_t status)
157{
Tiago Barros41587792017-07-07 11:01:45 -0300158 static uint32_t previous_status_time = 0;
159 static uint16_t status_interval;
160 static uint8_t nblink, led_state, previous_led_state = LOW;
Claudio Takahasi8b9b41b2017-03-16 09:03:00 -0300161 uint32_t current_status_time = hal_time_ms();
Erick Simões385cf152017-01-17 14:47:21 -0300162
163 /*
164 * If the LED has lit and off twice the state,
165 * a set a long interval
166 */
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300167 if (nblink >= (status * 2)) {
Erick Simões385cf152017-01-17 14:47:21 -0300168 nblink = 0;
169 status_interval = LONG_INTERVAL;
Tiago Barros896112d2017-07-21 14:08:03 -0300170 hal_gpio_digital_write(PIN_LED_STATUS, 0);
Erick Simões385cf152017-01-17 14:47:21 -0300171 }
172
173 /*
174 * Ensures that whenever the status changes,
175 * the blink starts by turning on the LED
176 **/
177 if (status != previous_led_state) {
178 previous_led_state = status;
179 led_state = LOW;
180 }
181
182 if ((current_status_time - previous_status_time) >= status_interval) {
183 previous_status_time = current_status_time;
184 led_state = !led_state;
185 hal_gpio_digital_write(PIN_LED_STATUS, led_state);
186
187 nblink++;
188 status_interval = SHORT_INTERVAL;
189 }
Erick Simões385cf152017-01-17 14:47:21 -0300190}
191
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300192static int send_register(void)
193{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300194 uint8_t len;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300195
Tiago Barrosd49fd272017-07-07 11:59:25 -0300196 len = MIN(sizeof(msg.reg.devName), strlen(device_name));
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300197 msg.hdr.type = KNOT_MSG_REGISTER_REQ;
Tiago Barrosd49fd272017-07-07 11:59:25 -0300198 strncpy(msg.reg.devName, device_name, len);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300199 msg.hdr.payload_len = len;
Rodrigo Alvescd2ebec2016-11-29 12:43:59 -0300200
Tiago Barrosd49fd272017-07-07 11:59:25 -0300201 if (hal_comm_write(cli_sock, &(msg.buffer), sizeof(msg.hdr) + len) < 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300202 return -1;
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300203
204 return 0;
205}
206
207static int read_register(void)
208{
209 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300210
Tiago Barrosd49fd272017-07-07 11:59:25 -0300211 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300212 if (nbytes <= 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300213 return nbytes;
214
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300215 if (msg.cred.result != KNOT_SUCCESS)
216 return -1;
217
218 hal_storage_write_end(HAL_STORAGE_ID_UUID, msg.cred.uuid,
219 KNOT_PROTOCOL_UUID_LEN);
220 hal_storage_write_end(HAL_STORAGE_ID_TOKEN, msg.cred.token,
221 KNOT_PROTOCOL_TOKEN_LEN);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300222 return 0;
223}
224
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300225static int read_auth(void)
226{
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300227 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300228
Tiago Barrosd49fd272017-07-07 11:59:25 -0300229 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300230 if (nbytes <= 0)
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300231 return nbytes;
232
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300233 if (msg.action.result != KNOT_SUCCESS)
234 return -1;
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300235 return 0;
236}
237
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300238static int send_schema(void)
239{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300240 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300241
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300242 err = knot_thing_create_schema(msg_sensor_id, &(msg.schema));
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300243
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300244 if (err < 0)
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300245 return err;
246
Vitor Barrosa4c95652017-11-06 10:50:08 -0300247 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300248 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300249 /* TODO create a better error define in the protocol */
250 return KNOT_ERROR_UNKNOWN;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300251
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300252 return KNOT_SUCCESS;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300253}
254
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300255static int msg_set_config(uint8_t sensor_id)
Rodrigo Alves19108182016-11-08 13:49:22 -0300256{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300257 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300258
Vitor Barrosa4c95652017-11-06 10:50:08 -0300259 err = knot_thing_config_data_item(msg.config.sensor_id,
Tiago Barrosd49fd272017-07-07 11:59:25 -0300260 msg.config.values.event_flags,
261 msg.config.values.time_sec,
262 &(msg.config.values.lower_limit),
263 &(msg.config.values.upper_limit));
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300264 if (err)
Paulo Serra Filho2c36dff2017-01-09 10:33:21 -0300265 return KNOT_ERROR_UNKNOWN;
266
Tiago Barrosd49fd272017-07-07 11:59:25 -0300267 msg.item.sensor_id = sensor_id;
268 msg.hdr.type = KNOT_MSG_CONFIG_RESP;
269 msg.hdr.payload_len = sizeof(msg.item.sensor_id);
Rodrigo Alves19108182016-11-08 13:49:22 -0300270
Vitor Barrosa4c95652017-11-06 10:50:08 -0300271 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300272 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves19108182016-11-08 13:49:22 -0300273 return -1;
274
275 return 0;
276}
277
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300278static int msg_set_data(uint8_t sensor_id)
Rodrigo Alves97001062016-11-08 13:51:48 -0300279{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300280 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300281
Tiago Barrosd49fd272017-07-07 11:59:25 -0300282 err = knot_thing_data_item_write(sensor_id, &(msg.data));
Rodrigo Alves97001062016-11-08 13:51:48 -0300283
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300284 /*
285 * GW must be aware if the data was succesfully set, so we resend
286 * the request only changing the header type
287 */
Tiago Barrosd49fd272017-07-07 11:59:25 -0300288 msg.hdr.type = KNOT_MSG_DATA_RESP;
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300289 /* TODO: Improve error handling: Sensor not found, invalid data, etc */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300290 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300291 msg.hdr.type = KNOT_ERROR_UNKNOWN;
Rodrigo Alves97001062016-11-08 13:51:48 -0300292
Vitor Barrosa4c95652017-11-06 10:50:08 -0300293 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300294 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves52955152016-11-10 09:36:22 -0300295 return -1;
296
297 return 0;
298}
299
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300300static int msg_get_data(uint8_t sensor_id)
Renie Delgado63be4f62016-11-18 11:06:20 -0300301{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300302 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300303
Tiago Barrosd49fd272017-07-07 11:59:25 -0300304 err = knot_thing_data_item_read(sensor_id, &(msg.data));
Tiago Barrosdde937f2017-07-21 14:24:58 -0300305 if (err == -2)
306 return err;
Tiago Barrosd49fd272017-07-07 11:59:25 -0300307
308 msg.hdr.type = KNOT_MSG_DATA;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300309 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300310 msg.hdr.type = KNOT_ERROR_UNKNOWN;
311
312 msg.data.sensor_id = sensor_id;
313
Vitor Barrosa4c95652017-11-06 10:50:08 -0300314 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300315 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
316 return -1;
Renie Delgado63be4f62016-11-18 11:06:20 -0300317
318 return 0;
319}
320
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300321static inline int is_uuid(const char *string)
322{
Tiago Barros62ec6622017-07-10 15:51:32 -0300323 return (string != NULL && string[8] == '-' &&
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300324 string[13] == '-' && string[18] == '-' && string[23] == '-');
325}
326
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300327static int clear_data(void)
328{
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300329 if (!hal_gpio_digital_read(CLEAR_EEPROM_PIN)) {
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300330 if (clear_time == 0)
Tiago Barros41587792017-07-07 11:01:45 -0300331 clear_time = hal_time_ms();
Tiago Barros4375b772017-07-20 11:23:35 -0300332 if ((hal_time_ms() - clear_time) >= 5000)
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300333 return 1;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300334
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300335 return 0;
336 }
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300337
Tiago Barros41587792017-07-07 11:01:45 -0300338 clear_time = 0;
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300339
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300340 return 0;
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300341}
342
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300343static int8_t mgmt_read(void)
344{
345 uint8_t buffer[MTU];
346 struct mgmt_nrf24_header *mhdr = (struct mgmt_nrf24_header *) buffer;
Vitor Barros5f00faf2017-11-13 10:48:31 -0300347 ssize_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300348
Vitor Barros5f00faf2017-11-13 10:48:31 -0300349 retval = hal_comm_read(sock, buffer, sizeof(buffer));
350 if (retval < 0)
351 return retval;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300352
353 /* Return/ignore if it is not an event? */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300354 if (!(mhdr->opcode & 0x0200))
Vitor Barros5f00faf2017-11-13 10:48:31 -0300355 return -EPROTO;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300356
357 switch (mhdr->opcode) {
358
359 case MGMT_EVT_NRF24_DISCONNECTED:
Vitor Barros5f00faf2017-11-13 10:48:31 -0300360 return -ENOTCONN;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300361 }
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300362
Vitor Barros5f00faf2017-11-13 10:48:31 -0300363 return 0;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300364}
365
Vitor Barrosa4c95652017-11-06 10:50:08 -0300366static void read_online_messages(void)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300367{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300368 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) <= 0)
369 return;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300370
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300371 /* There is a message to read */
372 switch (msg.hdr.type) {
373 case KNOT_MSG_SET_CONFIG:
374 msg_set_config(msg.config.sensor_id);
375 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300376
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300377 case KNOT_MSG_SET_DATA:
378 msg_set_data(msg.data.sensor_id);
379 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300380
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300381 case KNOT_MSG_GET_DATA:
382 msg_get_data(msg.item.sensor_id);
383 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300384
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300385 case KNOT_MSG_DATA_RESP:
386 hal_log_str("DT RSP");
387 if (msg.action.result != KNOT_SUCCESS) {
388 hal_log_str("DT R ERR");
389 msg_get_data(msg.item.sensor_id);
Paulo Serra Filho58dd0302016-11-22 17:59:24 -0300390 }
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300391 break;
392
393 default:
394 /* Invalid command, ignore */
395 break;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300396 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300397}
398
399int knot_thing_protocol_run(void)
400{
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300401 static uint8_t run_state = STATE_DISCONNECTED;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300402
Claudio Takahasi552d2a02017-06-12 14:22:08 -0300403 struct nrf24_mac peer;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300404 int8_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300405
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300406 /*
407 * Verifies if the button for eeprom clear is pressed for more than 5s
408 */
409 if (clear_data()) {
Tiago Barroseee47082017-07-20 15:40:35 -0300410 /* close connection */
411 knot_thing_protocol_exit();
412
413 /* generate new MAC addr */
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300414 hal_storage_reset_end();
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300415 set_nrf24MAC();
Tiago Barroseee47082017-07-20 15:40:35 -0300416
Vitor Barrosa4c95652017-11-06 10:50:08 -0300417 /* init connection */
Tiago Barros864f1d02017-07-21 10:25:34 -0300418 init_connection();
Tiago Barroseee47082017-07-20 15:40:35 -0300419
420 run_state = STATE_DISCONNECTED;
421 }
422
423 if (enable_run == 0) {
424 return -1;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300425 }
426
Vitor Barros5f00faf2017-11-13 10:48:31 -0300427 if (run_state >= STATE_CONNECTED) {
428 if (mgmt_read() == -ENOTCONN)
429 run_state = STATE_DISCONNECTED;
430 }
431
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300432 /* Network message handling state machine */
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300433 switch (run_state) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300434 case STATE_DISCONNECTED:
435 /* Internally listen starts broadcasting presence*/
Tiago Barros896112d2017-07-21 14:08:03 -0300436 led_status(BLINK_DISCONNECTED);
Tiago Barrosd39fc9c2017-07-18 10:31:23 -0300437 hal_comm_close(cli_sock);
Tiago Barros8c61bd52017-07-18 16:51:28 -0300438 hal_log_str("DISC");
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300439 if (hal_comm_listen(sock) < 0) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300440 break;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300441 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300442
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300443 run_state = STATE_ACCEPTING;
444 hal_log_str("ACCT");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300445 break;
446
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300447 case STATE_ACCEPTING:
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300448 /*
449 * Try to accept GW connection request. EAGAIN means keep
450 * waiting, less then 0 means error and greater then 0 success
451 */
Tiago Barros896112d2017-07-21 14:08:03 -0300452 led_status(BLINK_DISCONNECTED);
Claudio Takahasi8b54e652017-07-03 13:38:00 -0300453 cli_sock = hal_comm_accept(sock, (void *) &peer);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300454 if (cli_sock == -EAGAIN)
455 break;
456 else if (cli_sock < 0) {
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300457 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300458 break;
459 }
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300460 run_state = STATE_CONNECTED;
461 hal_log_str("CONN");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300462 break;
463
464 case STATE_CONNECTED:
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300465 /*
466 * If uuid/token were found, read the addresses and send
467 * the auth request, otherwise register request
468 */
Tiago Barros896112d2017-07-21 14:08:03 -0300469 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300470 hal_storage_read_end(HAL_STORAGE_ID_UUID, &(msg.auth.uuid),
471 KNOT_PROTOCOL_UUID_LEN);
472 hal_storage_read_end(HAL_STORAGE_ID_TOKEN, &(msg.auth.token),
473 KNOT_PROTOCOL_TOKEN_LEN);
474
475 if (is_uuid(msg.auth.uuid)) {
476 run_state = STATE_AUTHENTICATING;
477 hal_log_str("AUTH");
478 msg.hdr.type = KNOT_MSG_AUTH_REQ;
Vitor Barrosa4c95652017-11-06 10:50:08 -0300479 msg.hdr.payload_len = KNOT_PROTOCOL_UUID_LEN +
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300480 KNOT_PROTOCOL_TOKEN_LEN;
481
Vitor Barrosa4c95652017-11-06 10:50:08 -0300482 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300483 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
484 run_state = STATE_ERROR;
485 } else {
486 hal_log_str("REG");
487 run_state = STATE_REGISTERING;
488 if (send_register() < 0)
489 run_state = STATE_ERROR;
490 }
491 last_timeout = hal_time_ms();
492 break;
493
494 /*
495 * Authenticating, Resgistering cases waits (without blocking)
496 * for an response of the respective requests, -EAGAIN means there was
497 * nothing to read so we ignore it, less then 0 an error and 0 success
498 */
499 case STATE_AUTHENTICATING:
Tiago Barros896112d2017-07-21 14:08:03 -0300500 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300501 retval = read_auth();
502 if (retval == KNOT_SUCCESS) {
503 run_state = STATE_ONLINE;
504 hal_log_str("ONLN");
505 /* Checks if all the schemas were sent to the GW and */
506 hal_storage_read_end(HAL_STORAGE_ID_SCHEMA_FLAG,
507 &schema_flag, sizeof(schema_flag));
508 if (!schema_flag)
509 run_state = STATE_SCHEMA;
510 }
511 else if (retval != -EAGAIN)
512 run_state = STATE_ERROR;
513 else if (hal_timeout(hal_time_ms(), last_timeout,
514 RETRANSMISSION_TIMEOUT) > 0)
515 run_state = STATE_CONNECTED;
516 break;
517
518 case STATE_REGISTERING:
Tiago Barros896112d2017-07-21 14:08:03 -0300519 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300520 retval = read_register();
521 if (!retval)
522 run_state = STATE_SCHEMA;
523 else if (retval != -EAGAIN)
524 run_state = STATE_ERROR;
525 else if (hal_timeout(hal_time_ms(), last_timeout,
526 RETRANSMISSION_TIMEOUT) > 0)
527 run_state = STATE_CONNECTED;
528 break;
529
530 /*
531 * STATE_SCHEMA tries to send an schema and go to STATE_SCHEMA_RESP to
532 * wait for the ack of this schema. If there is no schema for that
533 * msg_sensor_id, increments and stays in the STATE_SCHEMA. If an
534 * error occurs, goes to STATE_ERROR.
535 */
536 case STATE_SCHEMA:
Tiago Barros896112d2017-07-21 14:08:03 -0300537 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300538 hal_log_str("SCH");
539 retval = send_schema();
540 switch (retval) {
541 case KNOT_SUCCESS:
542 last_timeout = hal_time_ms();
543 run_state = STATE_SCHEMA_RESP;
544 break;
545 case KNOT_ERROR_UNKNOWN:
546 run_state = STATE_ERROR;
547 break;
548 case KNOT_SCHEMA_EMPTY:
549 case KNOT_INVALID_DEVICE:
550 run_state = STATE_SCHEMA;
551 msg_sensor_id++;
552 break;
553 default:
554 run_state = STATE_ERROR;
555 break;
556 }
557 break;
558
559 /*
560 * Receives the ack from the GW and returns to STATE_SCHEMA to send the
561 * next schema. If it was the ack for the last schema, goes to
562 * STATE_ONLINE. If it is not a KNOT_MSG_SCHEMA_RESP, ignores. If the
563 * result was not KNOT_SUCCESS, goes to STATE_ERROR.
564 */
565 case STATE_SCHEMA_RESP:
Tiago Barros896112d2017-07-21 14:08:03 -0300566 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300567 hal_log_str("SCH_R");
568 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) > 0) {
569 if (msg.hdr.type != KNOT_MSG_SCHEMA_RESP &&
570 msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP)
571 break;
572 if (msg.action.result != KNOT_SUCCESS) {
573 run_state = STATE_SCHEMA;
574 break;
575 }
576 if (msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP) {
577 run_state = STATE_SCHEMA;
578 msg_sensor_id++;
579 break;
580 }
581 /* All the schemas were sent to GW */
582 schema_flag = true;
583 hal_storage_write_end(HAL_STORAGE_ID_SCHEMA_FLAG,
584 &schema_flag, sizeof(schema_flag));
585 run_state = STATE_ONLINE;
586 hal_log_str("ONLN");
587 msg_sensor_id = 0;
588 } else if (hal_timeout(hal_time_ms(), last_timeout,
589 RETRANSMISSION_TIMEOUT) > 0)
590 run_state = STATE_SCHEMA;
591 break;
592
593 case STATE_ONLINE:
Tiago Barros896112d2017-07-21 14:08:03 -0300594 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300595 read_online_messages();
596 msg_sensor_id++;
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300597 msg_get_data(msg_sensor_id);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300598 hal_log_str("DT");
599 if (msg_sensor_id >= KNOT_THING_DATA_MAX) {
600 msg_sensor_id = 0;
601 run_state = STATE_RUNNING;
602 hal_log_str("RUN");
603 }
604 break;
605
606 case STATE_RUNNING:
Tiago Barros896112d2017-07-21 14:08:03 -0300607 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300608 read_online_messages();
609 /* If some event ocurred send msg_data */
610 if (knot_thing_verify_events(&(msg.data)) == 0) {
611 if (hal_comm_write(cli_sock, &(msg.buffer),
612 sizeof(msg.hdr) + msg.hdr.payload_len) < 0) {
613 hal_log_str("DT ERR");
614 hal_comm_write(cli_sock, &(msg.buffer),
615 sizeof(msg.hdr) + msg.hdr.payload_len);
616 } else {
617 hal_log_str("DT");
618 }
619 }
620 break;
621
622 case STATE_ERROR:
Tiago Barros896112d2017-07-21 14:08:03 -0300623 hal_gpio_digital_write(PIN_LED_STATUS, 1);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300624 hal_log_str("ERR");
Vitor Barros5f00faf2017-11-13 10:48:31 -0300625 /* TODO: Review error state handling */
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300626 run_state = STATE_DISCONNECTED;
Tiago Barros896112d2017-07-21 14:08:03 -0300627 hal_delay_ms(1000);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300628 break;
629
630 default:
Tiago Barros8c61bd52017-07-18 16:51:28 -0300631 hal_log_str("INV");
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300632 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300633 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300634 }
635
636 return 0;
Rodrigo Alves19108182016-11-08 13:49:22 -0300637}