blob: d742f5f87f4fc75eda97e251bba85ea0f556b7d5 [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>
João Netod8e81a32018-07-03 15:20:03 -030027#include <hal/gpio_avr.h>
Claudio Takahasi99c902a2017-05-03 15:51:47 -030028#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;
João Netoa0d51ff2018-06-05 17:01:42 -030076static uint32_t unreg_timeout;
Rodrigo Alvesf10624f2016-11-09 11:05:16 -030077static int sock = -1;
Rodrigo Alves482954a2016-11-22 08:04:20 -030078static int cli_sock = -1;
Paulo Serra Filhoe105eca2017-01-05 22:22:07 -030079static bool schema_flag = false;
Tiago Barros2ebe55a2017-07-20 17:18:01 -030080static uint8_t enable_run = 0, msg_sensor_id = 0;
Renie Delgadof0206e92016-11-25 09:39:13 -030081
82/*
83 * FIXME: Thing address should be received via NFC
84 * Mac address must be stored in big endian format
85 */
Larissaca16a322017-12-12 13:37:01 -030086
87void(* reset_function) (void) = 0; //declare reset function @ address 0
88
Claudio Takahasic2c1d9d2017-05-15 15:55:39 -030089static void set_nrf24MAC(void)
Renie Delgadof0206e92016-11-25 09:39:13 -030090{
Claudio Takahasi707e2132017-11-21 16:07:15 -030091 hal_getrandom(config.mac.address.b, sizeof(struct nrf24_mac));
92 hal_storage_write_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -030093 sizeof(struct nrf24_mac));
Renie Delgadof0206e92016-11-25 09:39:13 -030094}
Larissaca16a322017-12-12 13:37:01 -030095
João Netoa0d51ff2018-06-05 17:01:42 -030096static void thing_disconnect_exit(void)
97{
98 /* reset EEPROM (UUID/Token) and generate new MAC addr */
99 hal_storage_reset_end();
100 set_nrf24MAC();
101
102 /* close connection */
103 knot_thing_protocol_exit();
104
105 /* reset thing */
106 reset_function();
107}
108
Larissaca16a322017-12-12 13:37:01 -0300109static void verify_clear_data(void)
110{
111 if (!hal_gpio_digital_read(CLEAR_EEPROM_PIN)) {
112
113 if (clear_time == 0)
114 clear_time = hal_time_ms();
115
116 if (hal_timeout(hal_time_ms(), clear_time, BUTTON_PRESSED_TIME)) {
João Netoa0d51ff2018-06-05 17:01:42 -0300117 thing_disconnect_exit();
Larissaca16a322017-12-12 13:37:01 -0300118 }
119 } else
120 clear_time = 0;
121
122}
123
Tiago Barros864f1d02017-07-21 10:25:34 -0300124static void halt_blinking_led(uint32_t period)
125{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300126 while (1) {
Tiago Barros864f1d02017-07-21 10:25:34 -0300127 hal_gpio_digital_write(PIN_LED_STATUS, 0);
128 hal_delay_ms(period);
129 hal_gpio_digital_write(PIN_LED_STATUS, 1);
130 hal_delay_ms(period);
Larissaca16a322017-12-12 13:37:01 -0300131 verify_clear_data();
Tiago Barros864f1d02017-07-21 10:25:34 -0300132 }
133}
Erick Simões9d64fc82017-02-13 11:04:53 -0300134
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300135static int init_connection(void)
Tiago Barroseee47082017-07-20 15:40:35 -0300136{
137#if (KNOT_DEBUG_ENABLED == 1)
138 char macString[25] = {0};
Claudio Takahasi707e2132017-11-21 16:07:15 -0300139 nrf24_mac2str(&config.mac, macString);
Tiago Barroseee47082017-07-20 15:40:35 -0300140
141 hal_log_str("MAC");
142 hal_log_str(macString);
143#endif
Claudio Takahasi707e2132017-11-21 16:07:15 -0300144 if (hal_comm_init("NRF0", &config) < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300145 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300146
147 sock = hal_comm_socket(HAL_COMM_PF_NRF24, HAL_COMM_PROTO_RAW);
148 if (sock < 0)
Tiago Barros864f1d02017-07-21 10:25:34 -0300149 halt_blinking_led(COMM_ERROR);
Tiago Barroseee47082017-07-20 15:40:35 -0300150
151 clear_time = 0;
152 enable_run = 1;
153 last_timeout = 0;
154
155 return 0;
156}
157
Tiago Barros6f3ab062017-07-07 10:50:44 -0300158int knot_thing_protocol_init(const char *thing_name)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300159{
Erick Simões385cf152017-01-17 14:47:21 -0300160 hal_gpio_pin_mode(PIN_LED_STATUS, OUTPUT);
Paulo Serra Filhob306c252016-12-07 13:01:44 -0300161 hal_gpio_pin_mode(CLEAR_EEPROM_PIN, INPUT_PULLUP);
162
Vitor Barrosa4c95652017-11-06 10:50:08 -0300163 if (thing_name == NULL)
Tiago Barros864f1d02017-07-21 10:25:34 -0300164 halt_blinking_led(NAME_ERROR);
Tiago Barros562946b2017-07-07 10:53:54 -0300165
Cristovao Rufinod8793332017-11-22 14:09:36 -0300166 config.name = (const char *) thing_name;
Tiago Barros562946b2017-07-07 10:53:54 -0300167
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300168 /* Set mac address if it's invalid on eeprom */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300169 hal_storage_read_end(HAL_STORAGE_ID_MAC, &config.mac,
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300170 sizeof(struct nrf24_mac));
Claudio Takahasic9c480a2017-11-08 13:07:23 -0300171 /* MAC criteria: less significant 32-bits should not be zero */
Claudio Takahasi707e2132017-11-21 16:07:15 -0300172 if (!(config.mac.address.uint64 & 0x00000000ffffffff)) {
Renie Delgado6ecb9292016-12-21 13:33:00 -0300173 hal_storage_reset_end();
Reniê Delgado8a8cea92016-12-21 09:10:07 -0300174 set_nrf24MAC();
Renie Delgado6ecb9292016-12-21 13:33:00 -0300175 }
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300176
Vitor Barrosb6169de2018-02-07 14:04:23 -0300177 config.id = config.mac.address.uint64;
178
Tiago Barroseee47082017-07-20 15:40:35 -0300179 return init_connection();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300180}
181
182void knot_thing_protocol_exit(void)
183{
Tiago Barroseee47082017-07-20 15:40:35 -0300184 hal_comm_close(cli_sock);
Rodrigo Alvesf4eb68b2016-11-09 11:10:12 -0300185 hal_comm_close(sock);
Tiago Barroseee47082017-07-20 15:40:35 -0300186 hal_comm_deinit();
Tiago Barrosc182ada2016-11-03 10:51:28 -0300187 enable_run = 0;
188}
189
Erick Simões385cf152017-01-17 14:47:21 -0300190/*
Tiago Barros896112d2017-07-21 14:08:03 -0300191 * The function receives the number of times LED shall blink.
192 * For each number n, the status LED should flash 2 * n
Erick Simões385cf152017-01-17 14:47:21 -0300193 * (once to light, another to turn off)
194 */
195static void led_status(uint8_t status)
196{
Tiago Barros41587792017-07-07 11:01:45 -0300197 static uint32_t previous_status_time = 0;
198 static uint16_t status_interval;
199 static uint8_t nblink, led_state, previous_led_state = LOW;
Claudio Takahasi8b9b41b2017-03-16 09:03:00 -0300200 uint32_t current_status_time = hal_time_ms();
Erick Simões385cf152017-01-17 14:47:21 -0300201
202 /*
203 * If the LED has lit and off twice the state,
204 * a set a long interval
205 */
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300206 if (nblink >= (status * 2)) {
Erick Simões385cf152017-01-17 14:47:21 -0300207 nblink = 0;
208 status_interval = LONG_INTERVAL;
Tiago Barros896112d2017-07-21 14:08:03 -0300209 hal_gpio_digital_write(PIN_LED_STATUS, 0);
Erick Simões385cf152017-01-17 14:47:21 -0300210 }
211
212 /*
213 * Ensures that whenever the status changes,
214 * the blink starts by turning on the LED
215 **/
216 if (status != previous_led_state) {
217 previous_led_state = status;
218 led_state = LOW;
219 }
220
221 if ((current_status_time - previous_status_time) >= status_interval) {
222 previous_status_time = current_status_time;
223 led_state = !led_state;
224 hal_gpio_digital_write(PIN_LED_STATUS, led_state);
225
226 nblink++;
227 status_interval = SHORT_INTERVAL;
228 }
Erick Simões385cf152017-01-17 14:47:21 -0300229}
230
João Netoa0d51ff2018-06-05 17:01:42 -0300231
232
233static int send_unregister(void)
234{
Tiago Barrosc1e56d52018-03-08 12:02:01 -0300235 /* send KNOT_MSG_UNREGISTER_RESP message */
236 msg.hdr.type = KNOT_MSG_UNREGISTER_RESP;
João Netoa0d51ff2018-06-05 17:01:42 -0300237 msg.hdr.payload_len = 0;
Tiago Barrosc1e56d52018-03-08 12:02:01 -0300238
João Netoa0d51ff2018-06-05 17:01:42 -0300239 if (hal_comm_write(cli_sock, &(msg.buffer),
240 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
241 return -1;
Tiago Barrosc1e56d52018-03-08 12:02:01 -0300242
João Netoa0d51ff2018-06-05 17:01:42 -0300243 unreg_timeout = hal_time_ms();
Tiago Barrosc1e56d52018-03-08 12:02:01 -0300244
João Netoa0d51ff2018-06-05 17:01:42 -0300245 return 0;
Tiago Barrosc1e56d52018-03-08 12:02:01 -0300246}
247
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300248static int send_register(void)
249{
Larissa Lages7a26df12018-01-04 10:43:14 -0300250 /*
251 * KNOT_MSG_REGISTER_REQ PDU should fit in nRF24 MTU in order
252 * to avoid frame segmentation. Re-transmission may happen
253 * frequently at noisy environments or if the remote is not ready.
254 */
255 uint8_t name_len = NRF24_MTU - (sizeof(msg.reg.hdr) +
256 sizeof(msg.reg.id));
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300257
Larissa Lages7a26df12018-01-04 10:43:14 -0300258 name_len = MIN(name_len, strlen(config.name));
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300259 msg.hdr.type = KNOT_MSG_REGISTER_REQ;
Claudio Takahasid22b3272017-12-05 16:23:20 -0300260 msg.reg.id = config.mac.address.uint64; /* Maps id to nRF24 MAC */
Larissa Lages7a26df12018-01-04 10:43:14 -0300261 strncpy(msg.reg.devName, config.name, name_len);
262 msg.hdr.payload_len = name_len + sizeof(msg.reg.id);
Rodrigo Alvescd2ebec2016-11-29 12:43:59 -0300263
Claudio Takahasid22b3272017-12-05 16:23:20 -0300264 if (hal_comm_write(cli_sock, &(msg.buffer),
265 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300266 return -1;
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300267
268 return 0;
269}
270
271static int read_register(void)
272{
273 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300274
Tiago Barrosd49fd272017-07-07 11:59:25 -0300275 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300276 if (nbytes <= 0)
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300277 return nbytes;
278
Tiago Barros830df552018-03-08 14:12:13 -0300279 if (msg.hdr.type == KNOT_MSG_UNREGISTER_REQ) {
João Netoa0d51ff2018-06-05 17:01:42 -0300280 return send_unregister();
Tiago Barros830df552018-03-08 14:12:13 -0300281 }
282
283 if (msg.hdr.type != KNOT_MSG_REGISTER_RESP)
284 return -1;
285
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300286 if (msg.cred.result != KNOT_SUCCESS)
287 return -1;
288
289 hal_storage_write_end(HAL_STORAGE_ID_UUID, msg.cred.uuid,
290 KNOT_PROTOCOL_UUID_LEN);
291 hal_storage_write_end(HAL_STORAGE_ID_TOKEN, msg.cred.token,
292 KNOT_PROTOCOL_TOKEN_LEN);
Rodrigo Alves2d602ae2016-11-04 14:03:13 -0300293 return 0;
294}
295
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300296static int read_auth(void)
297{
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300298 ssize_t nbytes;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300299
Tiago Barrosd49fd272017-07-07 11:59:25 -0300300 nbytes = hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE);
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300301 if (nbytes <= 0)
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300302 return nbytes;
303
Tiago Barros775fd652018-03-08 14:24:31 -0300304 if (msg.hdr.type == KNOT_MSG_UNREGISTER_REQ) {
João Netoa0d51ff2018-06-05 17:01:42 -0300305 return send_unregister();
Tiago Barros775fd652018-03-08 14:24:31 -0300306 }
307
308 if (msg.hdr.type != KNOT_MSG_AUTH_RESP)
309 return -1;
310
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300311 if (msg.action.result != KNOT_SUCCESS)
João Netoec02f772018-06-26 10:56:09 -0300312 return -1;
João Netoa0d51ff2018-06-05 17:01:42 -0300313
Rodrigo Alves8f2ef6a2016-11-04 14:06:24 -0300314 return 0;
315}
316
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300317static int send_schema(void)
318{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300319 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300320
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300321 err = knot_thing_create_schema(msg_sensor_id, &(msg.schema));
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300322
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300323 if (err < 0)
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300324 return err;
325
Vitor Barrosa4c95652017-11-06 10:50:08 -0300326 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300327 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300328 /* TODO create a better error define in the protocol */
329 return KNOT_ERROR_UNKNOWN;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300330
Paulo Serra Filhoc95ab5f2016-11-22 11:50:44 -0300331 return KNOT_SUCCESS;
Rodrigo Alves962fd2a2016-11-08 13:47:21 -0300332}
333
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300334static int msg_set_config(uint8_t sensor_id)
Rodrigo Alves19108182016-11-08 13:49:22 -0300335{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300336 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300337
Vitor Barrosa4c95652017-11-06 10:50:08 -0300338 err = knot_thing_config_data_item(msg.config.sensor_id,
Tiago Barrosd49fd272017-07-07 11:59:25 -0300339 msg.config.values.event_flags,
340 msg.config.values.time_sec,
341 &(msg.config.values.lower_limit),
342 &(msg.config.values.upper_limit));
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300343 if (err)
Paulo Serra Filho2c36dff2017-01-09 10:33:21 -0300344 return KNOT_ERROR_UNKNOWN;
345
Tiago Barrosd49fd272017-07-07 11:59:25 -0300346 msg.item.sensor_id = sensor_id;
347 msg.hdr.type = KNOT_MSG_CONFIG_RESP;
348 msg.hdr.payload_len = sizeof(msg.item.sensor_id);
Rodrigo Alves19108182016-11-08 13:49:22 -0300349
Vitor Barrosa4c95652017-11-06 10:50:08 -0300350 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300351 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves19108182016-11-08 13:49:22 -0300352 return -1;
353
354 return 0;
355}
356
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300357static int msg_set_data(uint8_t sensor_id)
Rodrigo Alves97001062016-11-08 13:51:48 -0300358{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300359 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300360
Tiago Barrosd49fd272017-07-07 11:59:25 -0300361 err = knot_thing_data_item_write(sensor_id, &(msg.data));
Rodrigo Alves97001062016-11-08 13:51:48 -0300362
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300363 /*
364 * GW must be aware if the data was succesfully set, so we resend
365 * the request only changing the header type
366 */
Tiago Barrosd49fd272017-07-07 11:59:25 -0300367 msg.hdr.type = KNOT_MSG_DATA_RESP;
Rodrigo Alves93b2a6a2016-11-21 14:56:13 -0300368 /* TODO: Improve error handling: Sensor not found, invalid data, etc */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300369 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300370 msg.hdr.type = KNOT_ERROR_UNKNOWN;
Rodrigo Alves97001062016-11-08 13:51:48 -0300371
Vitor Barrosa4c95652017-11-06 10:50:08 -0300372 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300373 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
Rodrigo Alves52955152016-11-10 09:36:22 -0300374 return -1;
375
376 return 0;
377}
378
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300379static int msg_get_data(uint8_t sensor_id)
Renie Delgado63be4f62016-11-18 11:06:20 -0300380{
Lucas Cavalcanti2f658c02017-03-07 15:32:27 -0300381 int8_t err;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300382
Tiago Barrosd49fd272017-07-07 11:59:25 -0300383 err = knot_thing_data_item_read(sensor_id, &(msg.data));
Tiago Barrosdde937f2017-07-21 14:24:58 -0300384 if (err == -2)
385 return err;
Tiago Barrosd49fd272017-07-07 11:59:25 -0300386
387 msg.hdr.type = KNOT_MSG_DATA;
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300388 if (err < 0)
Tiago Barrosd49fd272017-07-07 11:59:25 -0300389 msg.hdr.type = KNOT_ERROR_UNKNOWN;
390
391 msg.data.sensor_id = sensor_id;
392
Vitor Barrosa4c95652017-11-06 10:50:08 -0300393 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barrosd49fd272017-07-07 11:59:25 -0300394 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
395 return -1;
Renie Delgado63be4f62016-11-18 11:06:20 -0300396
397 return 0;
398}
399
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300400static inline int is_uuid(const char *string)
401{
Tiago Barros62ec6622017-07-10 15:51:32 -0300402 return (string != NULL && string[8] == '-' &&
Rodrigo Alvesd03f53e2016-12-06 15:00:27 -0300403 string[13] == '-' && string[18] == '-' && string[23] == '-');
404}
405
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300406static int8_t mgmt_read(void)
407{
408 uint8_t buffer[MTU];
409 struct mgmt_nrf24_header *mhdr = (struct mgmt_nrf24_header *) buffer;
Vitor Barros5f00faf2017-11-13 10:48:31 -0300410 ssize_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300411
Vitor Barros5f00faf2017-11-13 10:48:31 -0300412 retval = hal_comm_read(sock, buffer, sizeof(buffer));
413 if (retval < 0)
414 return retval;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300415
416 /* Return/ignore if it is not an event? */
Claudio Takahasiedf29ff2017-03-16 09:26:21 -0300417 if (!(mhdr->opcode & 0x0200))
Vitor Barros5f00faf2017-11-13 10:48:31 -0300418 return -EPROTO;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300419
420 switch (mhdr->opcode) {
421
422 case MGMT_EVT_NRF24_DISCONNECTED:
Vitor Barros5f00faf2017-11-13 10:48:31 -0300423 return -ENOTCONN;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300424 }
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300425
Vitor Barros5f00faf2017-11-13 10:48:31 -0300426 return 0;
Rodrigo Alvesc623c042016-12-14 09:59:27 -0300427}
428
Vitor Barrosa4c95652017-11-06 10:50:08 -0300429static void read_online_messages(void)
Tiago Barrosc182ada2016-11-03 10:51:28 -0300430{
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300431 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) <= 0)
432 return;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300433
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300434 /* There is a message to read */
435 switch (msg.hdr.type) {
436 case KNOT_MSG_SET_CONFIG:
437 msg_set_config(msg.config.sensor_id);
438 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300439
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300440 case KNOT_MSG_SET_DATA:
441 msg_set_data(msg.data.sensor_id);
442 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300443
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300444 case KNOT_MSG_GET_DATA:
445 msg_get_data(msg.item.sensor_id);
446 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300447
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300448 case KNOT_MSG_DATA_RESP:
449 hal_log_str("DT RSP");
450 if (msg.action.result != KNOT_SUCCESS) {
451 hal_log_str("DT R ERR");
452 msg_get_data(msg.item.sensor_id);
Paulo Serra Filho58dd0302016-11-22 17:59:24 -0300453 }
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300454 break;
Tiago Barros1238e1e2018-03-08 14:50:43 -0300455 case KNOT_MSG_UNREGISTER_REQ:
João Netoa0d51ff2018-06-05 17:01:42 -0300456 send_unregister();
Tiago Barros1238e1e2018-03-08 14:50:43 -0300457 break;
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300458 default:
459 /* Invalid command, ignore */
460 break;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300461 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300462}
463
464int knot_thing_protocol_run(void)
465{
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300466 static uint8_t run_state = STATE_DISCONNECTED;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300467
Claudio Takahasi552d2a02017-06-12 14:22:08 -0300468 struct nrf24_mac peer;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300469 int8_t retval;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300470
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300471 /*
472 * Verifies if the button for eeprom clear is pressed for more than 5s
473 */
Larissaca16a322017-12-12 13:37:01 -0300474 verify_clear_data();
Tiago Barroseee47082017-07-20 15:40:35 -0300475
476 if (enable_run == 0) {
477 return -1;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300478 }
479
Vitor Barros5f00faf2017-11-13 10:48:31 -0300480 if (run_state >= STATE_CONNECTED) {
481 if (mgmt_read() == -ENOTCONN)
482 run_state = STATE_DISCONNECTED;
483 }
484
João Netoa0d51ff2018-06-05 17:01:42 -0300485 if (unreg_timeout && hal_timeout(hal_time_ms(), unreg_timeout, 10000) > 0)
486 thing_disconnect_exit();
487
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300488 /* Network message handling state machine */
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300489 switch (run_state) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300490 case STATE_DISCONNECTED:
491 /* Internally listen starts broadcasting presence*/
Tiago Barros896112d2017-07-21 14:08:03 -0300492 led_status(BLINK_DISCONNECTED);
Tiago Barrosd39fc9c2017-07-18 10:31:23 -0300493 hal_comm_close(cli_sock);
Tiago Barros8c61bd52017-07-18 16:51:28 -0300494 hal_log_str("DISC");
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300495 if (hal_comm_listen(sock) < 0) {
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300496 break;
Gabriel Bandeirad6676122017-02-02 21:48:11 -0300497 }
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300498
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300499 run_state = STATE_ACCEPTING;
500 hal_log_str("ACCT");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300501 break;
502
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300503 case STATE_ACCEPTING:
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300504 /*
505 * Try to accept GW connection request. EAGAIN means keep
506 * waiting, less then 0 means error and greater then 0 success
507 */
Tiago Barros896112d2017-07-21 14:08:03 -0300508 led_status(BLINK_DISCONNECTED);
Claudio Takahasi8b54e652017-07-03 13:38:00 -0300509 cli_sock = hal_comm_accept(sock, (void *) &peer);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300510 if (cli_sock == -EAGAIN)
511 break;
512 else if (cli_sock < 0) {
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300513 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300514 break;
515 }
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300516 run_state = STATE_CONNECTED;
517 hal_log_str("CONN");
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300518 break;
519
520 case STATE_CONNECTED:
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300521 /*
522 * If uuid/token were found, read the addresses and send
523 * the auth request, otherwise register request
524 */
Tiago Barros896112d2017-07-21 14:08:03 -0300525 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300526 hal_storage_read_end(HAL_STORAGE_ID_UUID, &(msg.auth.uuid),
527 KNOT_PROTOCOL_UUID_LEN);
528 hal_storage_read_end(HAL_STORAGE_ID_TOKEN, &(msg.auth.token),
529 KNOT_PROTOCOL_TOKEN_LEN);
530
531 if (is_uuid(msg.auth.uuid)) {
532 run_state = STATE_AUTHENTICATING;
533 hal_log_str("AUTH");
534 msg.hdr.type = KNOT_MSG_AUTH_REQ;
Vitor Barrosa4c95652017-11-06 10:50:08 -0300535 msg.hdr.payload_len = KNOT_PROTOCOL_UUID_LEN +
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300536 KNOT_PROTOCOL_TOKEN_LEN;
537
Vitor Barrosa4c95652017-11-06 10:50:08 -0300538 if (hal_comm_write(cli_sock, &(msg.buffer),
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300539 sizeof(msg.hdr) + msg.hdr.payload_len) < 0)
540 run_state = STATE_ERROR;
541 } else {
542 hal_log_str("REG");
543 run_state = STATE_REGISTERING;
544 if (send_register() < 0)
545 run_state = STATE_ERROR;
546 }
547 last_timeout = hal_time_ms();
548 break;
549
550 /*
551 * Authenticating, Resgistering cases waits (without blocking)
552 * for an response of the respective requests, -EAGAIN means there was
553 * nothing to read so we ignore it, less then 0 an error and 0 success
554 */
555 case STATE_AUTHENTICATING:
Tiago Barros896112d2017-07-21 14:08:03 -0300556 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300557 retval = read_auth();
558 if (retval == KNOT_SUCCESS) {
559 run_state = STATE_ONLINE;
560 hal_log_str("ONLN");
561 /* Checks if all the schemas were sent to the GW and */
562 hal_storage_read_end(HAL_STORAGE_ID_SCHEMA_FLAG,
563 &schema_flag, sizeof(schema_flag));
564 if (!schema_flag)
565 run_state = STATE_SCHEMA;
566 }
567 else if (retval != -EAGAIN)
Larissaca16a322017-12-12 13:37:01 -0300568 halt_blinking_led(AUTH_ERROR);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300569 else if (hal_timeout(hal_time_ms(), last_timeout,
570 RETRANSMISSION_TIMEOUT) > 0)
571 run_state = STATE_CONNECTED;
572 break;
573
574 case STATE_REGISTERING:
Tiago Barros896112d2017-07-21 14:08:03 -0300575 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300576 retval = read_register();
577 if (!retval)
578 run_state = STATE_SCHEMA;
579 else if (retval != -EAGAIN)
580 run_state = STATE_ERROR;
581 else if (hal_timeout(hal_time_ms(), last_timeout,
582 RETRANSMISSION_TIMEOUT) > 0)
583 run_state = STATE_CONNECTED;
584 break;
585
586 /*
587 * STATE_SCHEMA tries to send an schema and go to STATE_SCHEMA_RESP to
588 * wait for the ack of this schema. If there is no schema for that
589 * msg_sensor_id, increments and stays in the STATE_SCHEMA. If an
590 * error occurs, goes to STATE_ERROR.
591 */
592 case STATE_SCHEMA:
Tiago Barros896112d2017-07-21 14:08:03 -0300593 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300594 hal_log_str("SCH");
595 retval = send_schema();
596 switch (retval) {
597 case KNOT_SUCCESS:
598 last_timeout = hal_time_ms();
599 run_state = STATE_SCHEMA_RESP;
600 break;
601 case KNOT_ERROR_UNKNOWN:
602 run_state = STATE_ERROR;
603 break;
604 case KNOT_SCHEMA_EMPTY:
605 case KNOT_INVALID_DEVICE:
606 run_state = STATE_SCHEMA;
607 msg_sensor_id++;
608 break;
609 default:
610 run_state = STATE_ERROR;
611 break;
612 }
613 break;
614
615 /*
616 * Receives the ack from the GW and returns to STATE_SCHEMA to send the
617 * next schema. If it was the ack for the last schema, goes to
618 * STATE_ONLINE. If it is not a KNOT_MSG_SCHEMA_RESP, ignores. If the
619 * result was not KNOT_SUCCESS, goes to STATE_ERROR.
620 */
621 case STATE_SCHEMA_RESP:
Tiago Barros896112d2017-07-21 14:08:03 -0300622 led_status(BLINK_STABLISHING);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300623 hal_log_str("SCH_R");
624 if (hal_comm_read(cli_sock, &(msg.buffer), KNOT_MSG_SIZE) > 0) {
Tiago Barrosefb9c6d2018-03-08 14:41:40 -0300625 if (msg.hdr.type == KNOT_MSG_UNREGISTER_REQ) {
João Netoa0d51ff2018-06-05 17:01:42 -0300626 send_unregister();
Tiago Barrosefb9c6d2018-03-08 14:41:40 -0300627 break;
628 }
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300629 if (msg.hdr.type != KNOT_MSG_SCHEMA_RESP &&
630 msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP)
631 break;
632 if (msg.action.result != KNOT_SUCCESS) {
633 run_state = STATE_SCHEMA;
634 break;
635 }
636 if (msg.hdr.type != KNOT_MSG_SCHEMA_END_RESP) {
637 run_state = STATE_SCHEMA;
638 msg_sensor_id++;
639 break;
640 }
641 /* All the schemas were sent to GW */
642 schema_flag = true;
643 hal_storage_write_end(HAL_STORAGE_ID_SCHEMA_FLAG,
644 &schema_flag, sizeof(schema_flag));
645 run_state = STATE_ONLINE;
646 hal_log_str("ONLN");
647 msg_sensor_id = 0;
648 } else if (hal_timeout(hal_time_ms(), last_timeout,
649 RETRANSMISSION_TIMEOUT) > 0)
650 run_state = STATE_SCHEMA;
651 break;
652
653 case STATE_ONLINE:
Tiago Barros896112d2017-07-21 14:08:03 -0300654 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300655 read_online_messages();
656 msg_sensor_id++;
Claudio Takahasi25d2e432017-11-20 14:14:25 -0300657 msg_get_data(msg_sensor_id);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300658 hal_log_str("DT");
659 if (msg_sensor_id >= KNOT_THING_DATA_MAX) {
660 msg_sensor_id = 0;
661 run_state = STATE_RUNNING;
662 hal_log_str("RUN");
663 }
664 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300665 case STATE_RUNNING:
Tiago Barros896112d2017-07-21 14:08:03 -0300666 led_status(BLINK_ONLINE);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300667 read_online_messages();
668 /* If some event ocurred send msg_data */
669 if (knot_thing_verify_events(&(msg.data)) == 0) {
670 if (hal_comm_write(cli_sock, &(msg.buffer),
671 sizeof(msg.hdr) + msg.hdr.payload_len) < 0) {
672 hal_log_str("DT ERR");
673 hal_comm_write(cli_sock, &(msg.buffer),
674 sizeof(msg.hdr) + msg.hdr.payload_len);
675 } else {
676 hal_log_str("DT");
677 }
678 }
679 break;
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300680 case STATE_ERROR:
Tiago Barros896112d2017-07-21 14:08:03 -0300681 hal_gpio_digital_write(PIN_LED_STATUS, 1);
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300682 hal_log_str("ERR");
Vitor Barros5f00faf2017-11-13 10:48:31 -0300683 /* TODO: Review error state handling */
Tiago Barros2ebe55a2017-07-20 17:18:01 -0300684 run_state = STATE_DISCONNECTED;
Tiago Barros896112d2017-07-21 14:08:03 -0300685 hal_delay_ms(1000);
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300686 break;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300687 default:
Tiago Barros8c61bd52017-07-18 16:51:28 -0300688 hal_log_str("INV");
Claudio Takahasi6b4fea82017-06-13 12:30:41 -0300689 run_state = STATE_DISCONNECTED;
Paulo Serra Filhod01b29e2016-12-16 13:58:42 -0300690 break;
Tiago Barrosc182ada2016-11-03 10:51:28 -0300691 }
692
693 return 0;
Rodrigo Alves19108182016-11-08 13:49:22 -0300694}