blob: a4b7674e2599a90b7fa43749febd3895456d8534 [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;
Cristovao Rufinod8793332017-11-22 14:09:36 -030069static struct nrf24_config config = { .mac = 0, .channel = 76 , .name = NULL};
Tiago Barros41587792017-07-07 11:01:45 -030070static unsigned long clear_time;
71static uint32_t last_timeout;
Rodrigo Alvesf10624f2016-11-09 11:05:16 -030072static int sock = -1;
Rodrigo Alves482954a2016-11-22 08:04:20 -030073static int cli_sock = -1;
Paulo Serra Filhoe105eca2017-01-05 22:22:07 -030074static bool schema_flag = false;
Tiago Barros2ebe55a2017-07-20 17:18:01 -030075static uint8_t enable_run = 0, msg_sensor_id = 0;
Renie Delgadof0206e92016-11-25 09:39:13 -030076
77/*
78 * FIXME: Thing address should be received via NFC
79 * Mac address must be stored in big endian format
80 */
Claudio Takahasic2c1d9d2017-05-15 15:55:39 -030081static void set_nrf24MAC(void)
Renie Delgadof0206e92016-11-25 09:39:13 -030082{
Claudio Takahasi707e2132017-11-21 16:07:15 -030083 hal_getrandom(config.mac.address.b, sizeof(struct nrf24_mac));
84 hal_storage_write_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -030085 sizeof(struct nrf24_mac));
Renie Delgadof0206e92016-11-25 09:39:13 -030086}
Tiago Barros864f1d02017-07-21 10:25:34 -030087static void halt_blinking_led(uint32_t period)
88{
Claudio Takahasi25d2e432017-11-20 14:14:25 -030089 while (1) {
Tiago Barros864f1d02017-07-21 10:25:34 -030090 hal_gpio_digital_write(PIN_LED_STATUS, 0);
91 hal_delay_ms(period);
92 hal_gpio_digital_write(PIN_LED_STATUS, 1);
93 hal_delay_ms(period);
94 }
95}
Erick Simões9d64fc82017-02-13 11:04:53 -030096
Claudio Takahasi25d2e432017-11-20 14:14:25 -030097static int init_connection(void)
Tiago Barroseee47082017-07-20 15:40:35 -030098{
99#if (KNOT_DEBUG_ENABLED == 1)
100 char macString[25] = {0};
Claudio Takahasi707e2132017-11-21 16:07:15 -0300101 nrf24_mac2str(&config.mac, macString);
Tiago Barroseee47082017-07-20 15:40:35 -0300102
103 hal_log_str("MAC");
104 hal_log_str(macString);
105#endif
Claudio Takahasi707e2132017-11-21 16:07:15 -0300106 if (hal_comm_init("NRF0", &config) < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300107 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300108
109 sock = hal_comm_socket(HAL_COMM_PF_NRF24, HAL_COMM_PROTO_RAW);
110 if (sock < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300111 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300112
113 clear_time = 0;
114 enable_run = 1;
115 last_timeout = 0;
116
117 return 0;
118}
119
Tiago Barros6f3ab062017-07-07 10:50:44 -0300120int knot_thing_protocol_init(const char *thing_name)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300121{
Erick Simões385cf152017-01-17 14:47:21 -0300122 hal_gpio_pin_mode(PIN_LED_STATUS, OUTPUT);
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300123 hal_gpio_pin_mode(CLEAR_EEPROM_PIN, INPUT_PULLUP);
124
Vitor Barrosa4c95652017-11-06 10:50:08 -0300125 if (thing_name == NULL)
Tiago Barros864f1d02017-07-21 10:25:34 -0300126 halt_blinking_led(NAME_ERROR);
Tiago Barros562946b2017-07-07 10:53:54 -0300127
Cristovao Rufinod8793332017-11-22 14:09:36 -0300128 config.name = (const char *) thing_name;
Tiago Barros562946b2017-07-07 10:53:54 -0300129
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300130 /* Set mac address if it's invalid on eeprom */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300131 hal_storage_read_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300132 sizeof(struct nrf24_mac));
Claudio Takahasic9c480a2017-11-08 13:07:23 -0300133 /* MAC criteria: less significant 32-bits should not be zero */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300134 if (!(config.mac.address.uint64 & 0x00000000ffffffff)) {
Renie Delgado6ecb9292016-12-21 13:33:00 -0300135 hal_storage_reset_end();
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300136 set_nrf24MAC();
Renie Delgado6ecb9292016-12-21 13:33:00 -0300137 }
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300138
Tiago Barroseee47082017-07-20 15:40:35 -0300139 return init_connection();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300140}
141
142void knot_thing_protocol_exit(void)
143{
Tiago Barroseee47082017-07-20 15:40:35 -0300144 hal_comm_close(cli_sock);
Rodrigo Alvesf4eb68b2016-11-09 11:10:12 -0300145 hal_comm_close(sock);
Tiago Barroseee47082017-07-20 15:40:35 -0300146 hal_comm_deinit();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300147 enable_run = 0;
148}
149
Erick Simões385cf152017-01-17 14:47:21 -0300150/*
Tiago Barros896112d2017-07-21 14:08:03 -0300151 * The function receives the number of times LED shall blink.
152 * For each number n, the status LED should flash 2 * n
Erick Simões385cf152017-01-17 14:47:21 -0300153 * (once to light, another to turn off)
154 */
155static void led_status(uint8_t status)
156{
Tiago Barros41587792017-07-07 11:01:45 -0300157 static uint32_t previous_status_time = 0;
158 static uint16_t status_interval;
159 static uint8_t nblink, led_state, previous_led_state = LOW;
Claudio Takahasi8b9b41b2017-03-16 09:03:00 -0300160 uint32_t current_status_time = hal_time_ms();
Erick Simões385cf152017-01-17 14:47:21 -0300161
162 /*
163 * If the LED has lit and off twice the state,
164 * a set a long interval
165 */
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300166 if (nblink >= (status * 2)) {
Erick Simões385cf152017-01-17 14:47:21 -0300167 nblink = 0;
168 status_interval = LONG_INTERVAL;
Tiago Barros896112d2017-07-21 14:08:03 -0300169 hal_gpio_digital_write(PIN_LED_STATUS, 0);
Erick Simões385cf152017-01-17 14:47:21 -0300170 }
171
172 /*
173 * Ensures that whenever the status changes,
174 * the blink starts by turning on the LED
175 **/
176 if (status != previous_led_state) {
177 previous_led_state = status;
178 led_state = LOW;
179 }
180
181 if ((current_status_time - previous_status_time) >= status_interval) {
182 previous_status_time = current_status_time;
183 led_state = !led_state;
184 hal_gpio_digital_write(PIN_LED_STATUS, led_state);
185
186 nblink++;
187 status_interval = SHORT_INTERVAL;
188 }
Erick Simões385cf152017-01-17 14:47:21 -0300189}
190
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300191static int send_register(void)
192{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300193 uint8_t len;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300194
Cristovao Rufinod8793332017-11-22 14:09:36 -0300195 len = MIN(sizeof(msg.reg.devName), strlen(config.name));
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300196 msg.hdr.type = KNOT_MSG_REGISTER_REQ;
Cristovao Rufinod8793332017-11-22 14:09:36 -0300197 strncpy(msg.reg.devName, config.name, len);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300198 msg.hdr.payload_len = len;
Rodrigo Alvescd2ebec2016-11-29 12:43:59 -0300199
Tiago Barrosd49fd272017-07-07 11:59:25 -0300200 if (hal_comm_write(cli_sock, &(msg.buffer), sizeof(msg.hdr) + len) < 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300201 return -1;
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300202
203 return 0;
204}
205
206static int read_register(void)
207{
208 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300209
Tiago Barrosd49fd272017-07-07 11:59:25 -0300210 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300211 if (nbytes <= 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300212 return nbytes;
213
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300214 if (msg.cred.result != KNOT_SUCCESS)
215 return -1;
216
217 hal_storage_write_end(HAL_STORAGE_ID_UUID, msg.cred.uuid,
218 KNOT_PROTOCOL_UUID_LEN);
219 hal_storage_write_end(HAL_STORAGE_ID_TOKEN, msg.cred.token,
220 KNOT_PROTOCOL_TOKEN_LEN);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300221 return 0;
222}
223
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300224static int read_auth(void)
225{
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300226 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300227
Tiago Barrosd49fd272017-07-07 11:59:25 -0300228 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300229 if (nbytes <= 0)
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300230 return nbytes;
231
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300232 if (msg.action.result != KNOT_SUCCESS)
233 return -1;
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300234 return 0;
235}
236
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300237static int send_schema(void)
238{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300239 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300240
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300241 err = knot_thing_create_schema(msg_sensor_id, &(msg.schema));
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300242
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300243 if (err < 0)
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300244 return err;
245
Vitor Barrosa4c95652017-11-06 10:50:08 -0300246 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300247 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300248 /* TODO create a better error define in the protocol */
249 return KNOT_ERROR_UNKNOWN;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300250
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300251 return KNOT_SUCCESS;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300252}
253
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300254static int msg_set_config(uint8_t sensor_id)
Rodrigo Alves19108182016-11-08 13:49:22 -0300255{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300256 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300257
Vitor Barrosa4c95652017-11-06 10:50:08 -0300258 err = knot_thing_config_data_item(msg.config.sensor_id,
Tiago Barrosd49fd272017-07-07 11:59:25 -0300259 msg.config.values.event_flags,
260 msg.config.values.time_sec,
261 &(msg.config.values.lower_limit),
262 &(msg.config.values.upper_limit));
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300263 if (err)
Paulo Serra Filho2c36dff2017-01-09 10:33:21 -0300264 return KNOT_ERROR_UNKNOWN;
265
Tiago Barrosd49fd272017-07-07 11:59:25 -0300266 msg.item.sensor_id = sensor_id;
267 msg.hdr.type = KNOT_MSG_CONFIG_RESP;
268 msg.hdr.payload_len = sizeof(msg.item.sensor_id);
Rodrigo Alves19108182016-11-08 13:49:22 -0300269
Vitor Barrosa4c95652017-11-06 10:50:08 -0300270 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300271 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves19108182016-11-08 13:49:22 -0300272 return -1;
273
274 return 0;
275}
276
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300277static int msg_set_data(uint8_t sensor_id)
Rodrigo Alves97001062016-11-08 13:51:48 -0300278{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300279 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300280
Tiago Barrosd49fd272017-07-07 11:59:25 -0300281 err = knot_thing_data_item_write(sensor_id, &(msg.data));
Rodrigo Alves97001062016-11-08 13:51:48 -0300282
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300283 /*
284 * GW must be aware if the data was succesfully set, so we resend
285 * the request only changing the header type
286 */
Tiago Barrosd49fd272017-07-07 11:59:25 -0300287 msg.hdr.type = KNOT_MSG_DATA_RESP;
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300288 /* TODO: Improve error handling: Sensor not found, invalid data, etc */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300289 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300290 msg.hdr.type = KNOT_ERROR_UNKNOWN;
Rodrigo Alves97001062016-11-08 13:51:48 -0300291
Vitor Barrosa4c95652017-11-06 10:50:08 -0300292 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300293 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves52955152016-11-10 09:36:22 -0300294 return -1;
295
296 return 0;
297}
298
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300299static int msg_get_data(uint8_t sensor_id)
Renie Delgado63be4f62016-11-18 11:06:20 -0300300{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300301 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300302
Tiago Barrosd49fd272017-07-07 11:59:25 -0300303 err = knot_thing_data_item_read(sensor_id, &(msg.data));
Tiago Barrosdde937f2017-07-21 14:24:58 -0300304 if (err == -2)
305 return err;
Tiago Barrosd49fd272017-07-07 11:59:25 -0300306
307 msg.hdr.type = KNOT_MSG_DATA;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300308 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300309 msg.hdr.type = KNOT_ERROR_UNKNOWN;
310
311 msg.data.sensor_id = sensor_id;
312
Vitor Barrosa4c95652017-11-06 10:50:08 -0300313 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300314 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
315 return -1;
Renie Delgado63be4f62016-11-18 11:06:20 -0300316
317 return 0;
318}
319
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300320static inline int is_uuid(const char *string)
321{
Tiago Barros62ec6622017-07-10 15:51:32 -0300322 return (string != NULL && string[8] == '-' &&
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300323 string[13] == '-' && string[18] == '-' && string[23] == '-');
324}
325
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300326static int clear_data(void)
327{
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300328 if (!hal_gpio_digital_read(CLEAR_EEPROM_PIN)) {
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300329 if (clear_time == 0)
Tiago Barros41587792017-07-07 11:01:45 -0300330 clear_time = hal_time_ms();
Tiago Barros4375b772017-07-20 11:23:35 -0300331 if ((hal_time_ms() - clear_time) >= 5000)
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300332 return 1;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300333
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300334 return 0;
335 }
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300336
Tiago Barros41587792017-07-07 11:01:45 -0300337 clear_time = 0;
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300338
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300339 return 0;
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300340}
341
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300342static int8_t mgmt_read(void)
343{
344 uint8_t buffer[MTU];
345 struct mgmt_nrf24_header *mhdr = (struct mgmt_nrf24_header *) buffer;
Vitor Barros5f00faf2017-11-13 10:48:31 -0300346 ssize_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300347
Vitor Barros5f00faf2017-11-13 10:48:31 -0300348 retval = hal_comm_read(sock, buffer, sizeof(buffer));
349 if (retval < 0)
350 return retval;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300351
352 /* Return/ignore if it is not an event? */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300353 if (!(mhdr->opcode & 0x0200))
Vitor Barros5f00faf2017-11-13 10:48:31 -0300354 return -EPROTO;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300355
356 switch (mhdr->opcode) {
357
358 case MGMT_EVT_NRF24_DISCONNECTED:
Vitor Barros5f00faf2017-11-13 10:48:31 -0300359 return -ENOTCONN;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300360 }
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300361
Vitor Barros5f00faf2017-11-13 10:48:31 -0300362 return 0;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300363}
364
Vitor Barrosa4c95652017-11-06 10:50:08 -0300365static void read_online_messages(void)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300366{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300367 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) <= 0)
368 return;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300369
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300370 /* There is a message to read */
371 switch (msg.hdr.type) {
372 case KNOT_MSG_SET_CONFIG:
373 msg_set_config(msg.config.sensor_id);
374 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300375
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300376 case KNOT_MSG_SET_DATA:
377 msg_set_data(msg.data.sensor_id);
378 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300379
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300380 case KNOT_MSG_GET_DATA:
381 msg_get_data(msg.item.sensor_id);
382 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300383
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300384 case KNOT_MSG_DATA_RESP:
385 hal_log_str("DT RSP");
386 if (msg.action.result != KNOT_SUCCESS) {
387 hal_log_str("DT R ERR");
388 msg_get_data(msg.item.sensor_id);
Paulo Serra Filho58dd0302016-11-22 17:59:24 -0300389 }
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300390 break;
391
392 default:
393 /* Invalid command, ignore */
394 break;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300395 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300396}
397
398int knot_thing_protocol_run(void)
399{
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300400 static uint8_t run_state = STATE_DISCONNECTED;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300401
Claudio Takahasi552d2a02017-06-12 14:22:08 -0300402 struct nrf24_mac peer;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300403 int8_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300404
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300405 /*
406 * Verifies if the button for eeprom clear is pressed for more than 5s
407 */
408 if (clear_data()) {
Tiago Barroseee47082017-07-20 15:40:35 -0300409 /* close connection */
410 knot_thing_protocol_exit();
411
412 /* generate new MAC addr */
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300413 hal_storage_reset_end();
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300414 set_nrf24MAC();
Tiago Barroseee47082017-07-20 15:40:35 -0300415
Vitor Barrosa4c95652017-11-06 10:50:08 -0300416 /* init connection */
Tiago Barros864f1d02017-07-21 10:25:34 -0300417 init_connection();
Tiago Barroseee47082017-07-20 15:40:35 -0300418
419 run_state = STATE_DISCONNECTED;
420 }
421
422 if (enable_run == 0) {
423 return -1;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300424 }
425
Vitor Barros5f00faf2017-11-13 10:48:31 -0300426 if (run_state >= STATE_CONNECTED) {
427 if (mgmt_read() == -ENOTCONN)
428 run_state = STATE_DISCONNECTED;
429 }
430
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300431 /* Network message handling state machine */
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300432 switch (run_state) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300433 case STATE_DISCONNECTED:
434 /* Internally listen starts broadcasting presence*/
Tiago Barros896112d2017-07-21 14:08:03 -0300435 led_status(BLINK_DISCONNECTED);
Tiago Barrosd39fc9c2017-07-18 10:31:23 -0300436 hal_comm_close(cli_sock);
Tiago Barros8c61bd52017-07-18 16:51:28 -0300437 hal_log_str("DISC");
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300438 if (hal_comm_listen(sock) < 0) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300439 break;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300440 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300441
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300442 run_state = STATE_ACCEPTING;
443 hal_log_str("ACCT");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300444 break;
445
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300446 case STATE_ACCEPTING:
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300447 /*
448 * Try to accept GW connection request. EAGAIN means keep
449 * waiting, less then 0 means error and greater then 0 success
450 */
Tiago Barros896112d2017-07-21 14:08:03 -0300451 led_status(BLINK_DISCONNECTED);
Claudio Takahasi8b54e652017-07-03 13:38:00 -0300452 cli_sock = hal_comm_accept(sock, (void *) &peer);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300453 if (cli_sock == -EAGAIN)
454 break;
455 else if (cli_sock < 0) {
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300456 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300457 break;
458 }
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300459 run_state = STATE_CONNECTED;
460 hal_log_str("CONN");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300461 break;
462
463 case STATE_CONNECTED:
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300464 /*
465 * If uuid/token were found, read the addresses and send
466 * the auth request, otherwise register request
467 */
Tiago Barros896112d2017-07-21 14:08:03 -0300468 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300469 hal_storage_read_end(HAL_STORAGE_ID_UUID, &(msg.auth.uuid),
470 KNOT_PROTOCOL_UUID_LEN);
471 hal_storage_read_end(HAL_STORAGE_ID_TOKEN, &(msg.auth.token),
472 KNOT_PROTOCOL_TOKEN_LEN);
473
474 if (is_uuid(msg.auth.uuid)) {
475 run_state = STATE_AUTHENTICATING;
476 hal_log_str("AUTH");
477 msg.hdr.type = KNOT_MSG_AUTH_REQ;
Vitor Barrosa4c95652017-11-06 10:50:08 -0300478 msg.hdr.payload_len = KNOT_PROTOCOL_UUID_LEN +
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300479 KNOT_PROTOCOL_TOKEN_LEN;
480
Vitor Barrosa4c95652017-11-06 10:50:08 -0300481 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300482 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
483 run_state = STATE_ERROR;
484 } else {
485 hal_log_str("REG");
486 run_state = STATE_REGISTERING;
487 if (send_register() < 0)
488 run_state = STATE_ERROR;
489 }
490 last_timeout = hal_time_ms();
491 break;
492
493 /*
494 * Authenticating, Resgistering cases waits (without blocking)
495 * for an response of the respective requests, -EAGAIN means there was
496 * nothing to read so we ignore it, less then 0 an error and 0 success
497 */
498 case STATE_AUTHENTICATING:
Tiago Barros896112d2017-07-21 14:08:03 -0300499 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300500 retval = read_auth();
501 if (retval == KNOT_SUCCESS) {
502 run_state = STATE_ONLINE;
503 hal_log_str("ONLN");
504 /* Checks if all the schemas were sent to the GW and */
505 hal_storage_read_end(HAL_STORAGE_ID_SCHEMA_FLAG,
506 &schema_flag, sizeof(schema_flag));
507 if (!schema_flag)
508 run_state = STATE_SCHEMA;
509 }
510 else if (retval != -EAGAIN)
511 run_state = STATE_ERROR;
512 else if (hal_timeout(hal_time_ms(), last_timeout,
513 RETRANSMISSION_TIMEOUT) > 0)
514 run_state = STATE_CONNECTED;
515 break;
516
517 case STATE_REGISTERING:
Tiago Barros896112d2017-07-21 14:08:03 -0300518 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300519 retval = read_register();
520 if (!retval)
521 run_state = STATE_SCHEMA;
522 else if (retval != -EAGAIN)
523 run_state = STATE_ERROR;
524 else if (hal_timeout(hal_time_ms(), last_timeout,
525 RETRANSMISSION_TIMEOUT) > 0)
526 run_state = STATE_CONNECTED;
527 break;
528
529 /*
530 * STATE_SCHEMA tries to send an schema and go to STATE_SCHEMA_RESP to
531 * wait for the ack of this schema. If there is no schema for that
532 * msg_sensor_id, increments and stays in the STATE_SCHEMA. If an
533 * error occurs, goes to STATE_ERROR.
534 */
535 case STATE_SCHEMA:
Tiago Barros896112d2017-07-21 14:08:03 -0300536 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300537 hal_log_str("SCH");
538 retval = send_schema();
539 switch (retval) {
540 case KNOT_SUCCESS:
541 last_timeout = hal_time_ms();
542 run_state = STATE_SCHEMA_RESP;
543 break;
544 case KNOT_ERROR_UNKNOWN:
545 run_state = STATE_ERROR;
546 break;
547 case KNOT_SCHEMA_EMPTY:
548 case KNOT_INVALID_DEVICE:
549 run_state = STATE_SCHEMA;
550 msg_sensor_id++;
551 break;
552 default:
553 run_state = STATE_ERROR;
554 break;
555 }
556 break;
557
558 /*
559 * Receives the ack from the GW and returns to STATE_SCHEMA to send the
560 * next schema. If it was the ack for the last schema, goes to
561 * STATE_ONLINE. If it is not a KNOT_MSG_SCHEMA_RESP, ignores. If the
562 * result was not KNOT_SUCCESS, goes to STATE_ERROR.
563 */
564 case STATE_SCHEMA_RESP:
Tiago Barros896112d2017-07-21 14:08:03 -0300565 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300566 hal_log_str("SCH_R");
567 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) > 0) {
568 if (msg.hdr.type != KNOT_MSG_SCHEMA_RESP &&
569 msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP)
570 break;
571 if (msg.action.result != KNOT_SUCCESS) {
572 run_state = STATE_SCHEMA;
573 break;
574 }
575 if (msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP) {
576 run_state = STATE_SCHEMA;
577 msg_sensor_id++;
578 break;
579 }
580 /* All the schemas were sent to GW */
581 schema_flag = true;
582 hal_storage_write_end(HAL_STORAGE_ID_SCHEMA_FLAG,
583 &schema_flag, sizeof(schema_flag));
584 run_state = STATE_ONLINE;
585 hal_log_str("ONLN");
586 msg_sensor_id = 0;
587 } else if (hal_timeout(hal_time_ms(), last_timeout,
588 RETRANSMISSION_TIMEOUT) > 0)
589 run_state = STATE_SCHEMA;
590 break;
591
592 case STATE_ONLINE:
Tiago Barros896112d2017-07-21 14:08:03 -0300593 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300594 read_online_messages();
595 msg_sensor_id++;
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300596 msg_get_data(msg_sensor_id);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300597 hal_log_str("DT");
598 if (msg_sensor_id >= KNOT_THING_DATA_MAX) {
599 msg_sensor_id = 0;
600 run_state = STATE_RUNNING;
601 hal_log_str("RUN");
602 }
603 break;
604
605 case STATE_RUNNING:
Tiago Barros896112d2017-07-21 14:08:03 -0300606 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300607 read_online_messages();
608 /* If some event ocurred send msg_data */
609 if (knot_thing_verify_events(&(msg.data)) == 0) {
610 if (hal_comm_write(cli_sock, &(msg.buffer),
611 sizeof(msg.hdr) + msg.hdr.payload_len) < 0) {
612 hal_log_str("DT ERR");
613 hal_comm_write(cli_sock, &(msg.buffer),
614 sizeof(msg.hdr) + msg.hdr.payload_len);
615 } else {
616 hal_log_str("DT");
617 }
618 }
619 break;
620
621 case STATE_ERROR:
Tiago Barros896112d2017-07-21 14:08:03 -0300622 hal_gpio_digital_write(PIN_LED_STATUS, 1);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300623 hal_log_str("ERR");
Vitor Barros5f00faf2017-11-13 10:48:31 -0300624 /* TODO: Review error state handling */
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300625 run_state = STATE_DISCONNECTED;
Tiago Barros896112d2017-07-21 14:08:03 -0300626 hal_delay_ms(1000);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300627 break;
628
629 default:
Tiago Barros8c61bd52017-07-18 16:51:28 -0300630 hal_log_str("INV");
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300631 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300632 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300633 }
634
635 return 0;
Rodrigo Alves19108182016-11-08 13:49:22 -0300636}