Firmware SDK
twr_radio.c
1 #include <twr_radio.h>
2 #include <twr_queue.h>
3 #include <twr_atsha204.h>
4 #include <twr_scheduler.h>
5 #include <twr_eeprom.h>
6 #include <twr_i2c.h>
7 #include <twr_radio_pub.h>
8 #include <twr_radio_node.h>
9 #include <math.h>
10 
11 #define _TWR_RADIO_SCAN_CACHE_LENGTH 4
12 #define _TWR_RADIO_ACK_TIMEOUT 100
13 #define _TWR_RADIO_SLEEP_RX_TIMEOUT 100
14 #define _TWR_RADIO_TX_MAX_COUNT 6
15 #define _TWR_RADIO_ACK_SUB_REQUEST 0x11
16 
17 typedef enum
18 {
19  TWR_RADIO_STATE_SLEEP = 0,
20  TWR_RADIO_STATE_TX = 1,
21  TWR_RADIO_STATE_RX = 2,
22  TWR_RADIO_STATE_TX_WAIT_ACK = 3,
23  TWR_RADIO_STATE_RX_SEND_ACK = 4,
24  TWR_RADIO_STATE_TX_SEND_ACK = 5,
25 
26 } twr_radio_state_t;
27 
28 static struct
29 {
30  twr_radio_mode_t mode;
31  twr_atsha204_t atsha204;
32  twr_radio_state_t state;
33  uint64_t my_id;
34  uint16_t message_id;
35  int transmit_count;
36  void (*event_handler)(twr_radio_event_t, void *);
37  void *event_param;
39  bool pairing_request_to_gateway;
40  const char *firmware;
41  const char *firmware_version;
42  bool pairing_mode;
43 
44  twr_queue_t pub_queue;
45  twr_queue_t rx_queue;
46  uint8_t pub_queue_buffer[TWR_RADIO_PUB_QUEUE_BUFFER_SIZE];
47  uint8_t rx_queue_buffer[TWR_RADIO_RX_QUEUE_BUFFER_SIZE];
48 
49  uint8_t ack_tx_cache_buffer[15];
50  size_t ack_tx_cache_length;
51  int ack_transmit_count;
52  twr_tick_t rx_timeout;
53  bool ack;
54 
55  twr_radio_peer_t peer_devices[TWR_RADIO_MAX_DEVICES];
56  int peer_devices_length;
57 
58  uint64_t peer_id;
59 
60  twr_tick_t sleeping_mode_rx_timeout;
61  twr_tick_t rx_timeout_sleeping;
62 
63  bool scan;
64  uint64_t scan_cache[_TWR_RADIO_SCAN_CACHE_LENGTH];
65  uint8_t scan_length;
66  uint8_t scan_head;
67 
68  bool automatic_pairing;
69  bool save_peer_devices;
70 
71  twr_radio_sub_t *subs;
72  int subs_length;
73  int sent_subs;
74 
75 } _twr_radio;
76 
77 static void _twr_radio_task(void *param);
78 static void _twr_radio_go_to_state_rx_or_sleep(void);
79 static void _twr_radio_spirit1_event_handler(twr_spirit1_event_t event, void *event_param);
80 static void _twr_radio_load_peer_devices(void);
81 static void _twr_radio_save_peer_devices(void);
82 static void _twr_radio_atsha204_event_handler(twr_atsha204_t *self, twr_atsha204_event_t event, void *event_param);
83 static bool _twr_radio_peer_device_add(uint64_t id);
84 static bool _twr_radio_peer_device_remove(uint64_t id);
85 
86 __attribute__((weak)) void twr_radio_on_info(uint64_t *id, char *firmware, char *version, twr_radio_mode_t mode) { (void) id; (void) firmware; (void) version; (void) mode;}
87 __attribute__((weak)) void twr_radio_on_sub(uint64_t *id, uint8_t *order, twr_radio_sub_pt_t *pt, char *topic) { (void) id; (void) order; (void) pt; (void) topic; }
88 
90 {
91  memset(&_twr_radio, 0, sizeof(_twr_radio));
92 
93  _twr_radio.mode = mode;
94 
95  twr_atsha204_init(&_twr_radio.atsha204, TWR_I2C_I2C0, 0x64);
96  twr_atsha204_set_event_handler(&_twr_radio.atsha204, _twr_radio_atsha204_event_handler, NULL);
97  twr_atsha204_read_serial_number(&_twr_radio.atsha204);
98 
99  twr_queue_init(&_twr_radio.pub_queue, _twr_radio.pub_queue_buffer, sizeof(_twr_radio.pub_queue_buffer));
100  twr_queue_init(&_twr_radio.rx_queue, _twr_radio.rx_queue_buffer, sizeof(_twr_radio.rx_queue_buffer));
101 
103  twr_spirit1_set_event_handler(_twr_radio_spirit1_event_handler, NULL);
104 
105  _twr_radio_load_peer_devices();
106 
107  _twr_radio.task_id = twr_scheduler_register(_twr_radio_task, NULL, TWR_TICK_INFINITY);
108 
109  _twr_radio_go_to_state_rx_or_sleep();
110 }
111 
112 void twr_radio_set_event_handler(void (*event_handler)(twr_radio_event_t, void *), void *event_param)
113 {
114  _twr_radio.event_handler = event_handler;
115  _twr_radio.event_param = event_param;
116 }
117 
118 void twr_radio_listen(twr_tick_t timeout)
119 {
120  _twr_radio.rx_timeout_sleeping = twr_tick_get() + timeout;
121 
122  twr_scheduler_plan_now(_twr_radio.task_id);
123 }
124 
125 void twr_radio_pairing_request(const char *firmware, const char *version)
126 {
127  _twr_radio.firmware = firmware == NULL ? "" : firmware;
128 
129  _twr_radio.firmware_version = version == NULL ? "" : version;
130 
131  _twr_radio.pairing_request_to_gateway = true;
132 
133  twr_scheduler_plan_now(_twr_radio.task_id);
134 }
135 
136 void twr_radio_pairing_mode_start(void)
137 {
138  _twr_radio.pairing_mode = true;
139 }
140 
141 void twr_radio_pairing_mode_stop(void)
142 {
143  _twr_radio.pairing_mode = false;
144 }
145 
146 bool twr_radio_peer_device_add(uint64_t id)
147 {
148 
149  if (!_twr_radio_peer_device_add(id))
150  {
151  return false;
152  }
153 
154  uint8_t buffer[1 + TWR_RADIO_ID_SIZE];
155 
156  buffer[0] = TWR_RADIO_HEADER_NODE_ATTACH;
157 
158  twr_radio_id_to_buffer(&id, buffer + 1);
159 
160  twr_queue_put(&_twr_radio.pub_queue, buffer, sizeof(buffer));
161 
162  twr_scheduler_plan_now(_twr_radio.task_id);
163 
164  return true;
165 }
166 
167 bool twr_radio_peer_device_remove(uint64_t id)
168 {
169  if (!_twr_radio_peer_device_remove(id))
170  {
171  return false;
172  }
173 
174  uint8_t buffer[1 + TWR_RADIO_ID_SIZE];
175 
176  buffer[0] = TWR_RADIO_HEADER_NODE_DETACH;
177 
178  twr_radio_id_to_buffer(&id, buffer + 1);
179 
180  twr_queue_put(&_twr_radio.pub_queue, buffer, sizeof(buffer));
181 
182  twr_scheduler_plan_now(_twr_radio.task_id);
183 
184  return true;
185 }
186 
187 bool twr_radio_peer_device_purge_all(void)
188 {
189  for (int i = _twr_radio.peer_devices_length -1; i > -1 ; i--)
190  {
191  if (_twr_radio.peer_devices[i].id != 0)
192  {
193  if (!twr_radio_peer_device_remove(_twr_radio.peer_devices[i].id))
194  {
195  return false;
196  }
197  }
198  }
199  return true;
200 }
201 
202 void twr_radio_get_peer_id(uint64_t *id, int length)
203 {
204  int i;
205  for (i = 0; (i < _twr_radio.peer_devices_length) && (i < length); i++)
206  {
207  id[i] = _twr_radio.peer_devices[i].id;
208  }
209  for (;i < length; i++)
210  {
211  id[i] = 0;
212  }
213 }
214 
215 void twr_radio_scan_start(void)
216 {
217  memset(_twr_radio.scan_cache, 0x00, sizeof(_twr_radio.scan_cache));
218  _twr_radio.scan_length = 0;
219  _twr_radio.scan_head = 0;
220  _twr_radio.scan = true;
221 }
222 
223 void twr_radio_scan_stop(void)
224 {
225  _twr_radio.scan = false;
226 }
227 
228 void twr_radio_automatic_pairing_start(void)
229 {
230  _twr_radio.automatic_pairing = true;
231 }
232 
233 void twr_radio_automatic_pairing_stop(void)
234 {
235  _twr_radio.automatic_pairing = false;
236 }
237 
238 uint64_t twr_radio_get_my_id(void)
239 {
240  return _twr_radio.my_id;
241 }
242 
243 uint64_t twr_radio_get_event_id(void)
244 {
245  return _twr_radio.peer_id;
246 }
247 
248 bool twr_radio_is_peer_device(uint64_t id)
249 {
250  for (int i = 0; i < _twr_radio.peer_devices_length; i++)
251  {
252  if (id == _twr_radio.peer_devices[i].id)
253  {
254  return true;
255  }
256  }
257  return false;
258 }
259 
260 bool twr_radio_pub_queue_put(const void *buffer, size_t length)
261 {
262  if (!twr_queue_put(&_twr_radio.pub_queue, buffer, length))
263  {
264  return false;
265  }
266 
267  twr_scheduler_plan_now(_twr_radio.task_id);
268 
269  return true;
270 }
271 
273 {
274  twr_queue_clear(&_twr_radio.pub_queue);
275 }
276 
277 void twr_radio_set_subs(twr_radio_sub_t *subs, int length)
278 {
279  _twr_radio.subs = subs;
280 
281  _twr_radio.subs_length = length;
282 
283  _twr_radio.sent_subs = 0;
284 }
285 
286 bool twr_radio_send_sub_data(uint64_t *id, uint8_t order, void *payload, size_t size)
287 {
288  uint8_t qbuffer[1 + TWR_RADIO_ID_SIZE + TWR_RADIO_NODE_MAX_BUFFER_SIZE];
289 
290  if (size > TWR_RADIO_NODE_MAX_BUFFER_SIZE - 1)
291  {
292  return false;
293  }
294 
295  qbuffer[0] = TWR_RADIO_HEADER_SUB_DATA;
296 
297  uint8_t *pqbuffer = twr_radio_id_to_buffer(id, qbuffer + 1);
298 
299  *pqbuffer++ = order;
300 
301  if (payload == NULL)
302  {
303  size = 0;
304  }
305 
306  if (size > 0)
307  {
308  memcpy(pqbuffer, payload, size);
309  }
310 
311  return twr_radio_pub_queue_put(qbuffer, 1 + TWR_RADIO_ID_SIZE + 1 + size);
312 }
313 
314 void twr_radio_set_rx_timeout_for_sleeping_node(twr_tick_t timeout)
315 {
316  _twr_radio.sleeping_mode_rx_timeout = timeout;
317 }
318 
319 static void _twr_radio_task(void *param)
320 {
321  (void) param;
322 
323  if (_twr_radio.my_id == 0)
324  {
325  twr_atsha204_read_serial_number(&_twr_radio.atsha204);
326 
328 
329  return;
330  }
331 
332  if ((_twr_radio.state != TWR_RADIO_STATE_RX) && (_twr_radio.state != TWR_RADIO_STATE_SLEEP))
333  {
335 
336  return;
337  }
338 
339  if (_twr_radio.save_peer_devices)
340  {
341  _twr_radio_save_peer_devices();
342  }
343 
344  if (_twr_radio.pairing_request_to_gateway)
345  {
346  _twr_radio.pairing_request_to_gateway = false;
347 
348  size_t len_firmware = strlen(_twr_radio.firmware);
349 
350  size_t len = len_firmware + strlen(_twr_radio.firmware_version);
351 
352  if (len > TWR_RADIO_MAX_BUFFER_SIZE - 5)
353  {
354  return;
355  }
356 
357  uint8_t *buffer = twr_spirit1_get_tx_buffer();
358 
359  twr_radio_id_to_buffer(&_twr_radio.my_id, buffer);
360 
361  _twr_radio.message_id++;
362 
363  buffer[6] = _twr_radio.message_id;
364  buffer[7] = _twr_radio.message_id >> 8;
365 
366  buffer[8] = TWR_RADIO_HEADER_PAIRING;
367  buffer[9] = len_firmware;
368 
369  strncpy((char *)buffer + 10, _twr_radio.firmware, TWR_RADIO_MAX_BUFFER_SIZE - 2);
370  strncpy((char *)buffer + 10 + len_firmware + 1, _twr_radio.firmware_version, TWR_RADIO_MAX_BUFFER_SIZE - 2 - len_firmware - 1);
371 
372  buffer[10 + len + 1] = _twr_radio.mode;
373 
374  twr_spirit1_set_tx_length(10 + len + 2);
375 
376  twr_spirit1_tx();
377 
378  _twr_radio.transmit_count = _TWR_RADIO_TX_MAX_COUNT;
379 
380  _twr_radio.state = TWR_RADIO_STATE_TX;
381 
382  return;
383  }
384 
385  if (_twr_radio.ack && (_twr_radio.sent_subs != _twr_radio.subs_length))
386  {
387  uint8_t *buffer = twr_spirit1_get_tx_buffer();
388 
389  twr_radio_sub_t *sub = &_twr_radio.subs[_twr_radio.sent_subs];
390 
391  twr_radio_id_to_buffer(&_twr_radio.my_id, buffer);
392 
393  _twr_radio.message_id++;
394 
395  buffer[6] = _twr_radio.message_id;
396  buffer[7] = _twr_radio.message_id >> 8;
397 
398  buffer[8] = TWR_RADIO_HEADER_SUB_REG;
399 
400  buffer[9] = _twr_radio.sent_subs;
401 
402  buffer[10] = sub->type;
403 
404  strncpy((char *)buffer + 11, sub->topic, TWR_RADIO_MAX_BUFFER_SIZE - 3);
405 
406  twr_spirit1_set_tx_length(11 + strlen(sub->topic) + 1);
407 
408  twr_spirit1_tx();
409 
410  _twr_radio.transmit_count = _TWR_RADIO_TX_MAX_COUNT;
411 
412  _twr_radio.state = TWR_RADIO_STATE_TX;
413 
414  return;
415  }
416 
417  uint8_t queue_item_buffer[sizeof(_twr_radio.pub_queue_buffer)];
418  size_t queue_item_length;
419  uint64_t id;
420 
421  while (twr_queue_get(&_twr_radio.rx_queue, queue_item_buffer, &queue_item_length))
422  {
423  twr_radio_id_from_buffer(queue_item_buffer, &id);
424 
425  queue_item_length -= TWR_RADIO_HEAD_SIZE;
426 
427  twr_radio_pub_decode(&id, queue_item_buffer + TWR_RADIO_HEAD_SIZE, queue_item_length);
428 
429  twr_radio_node_decode(&id, queue_item_buffer + TWR_RADIO_HEAD_SIZE, queue_item_length);
430 
431  if (queue_item_buffer[TWR_RADIO_HEAD_SIZE] == TWR_RADIO_HEADER_SUB_DATA)
432  {
433  uint8_t order = queue_item_buffer[TWR_RADIO_HEAD_SIZE + 1 + TWR_RADIO_ID_SIZE];
434 
435  if (order >= _twr_radio.subs_length)
436  {
437  return;
438  }
439 
440  twr_radio_sub_t *sub = &_twr_radio.subs[order];
441 
442  if (sub->callback != NULL)
443  {
444  uint8_t *payload = NULL;
445 
446  if (queue_item_length > 1 + TWR_RADIO_ID_SIZE + 1)
447  {
448  payload = queue_item_buffer + TWR_RADIO_HEAD_SIZE + 1 + TWR_RADIO_ID_SIZE + 1;
449  }
450 
451  sub->callback(&id, sub->topic, payload, sub->param);
452  }
453  }
454  else if (queue_item_buffer[TWR_RADIO_HEAD_SIZE] == TWR_RADIO_HEADER_PUB_INFO)
455  {
456  queue_item_buffer[queue_item_length + TWR_RADIO_HEAD_SIZE - 1] = 0;
457 
458  twr_radio_on_info(&id, (char *) queue_item_buffer + TWR_RADIO_HEAD_SIZE + 1, "", TWR_RADIO_MODE_UNKNOWN);
459  }
460  else if (queue_item_buffer[TWR_RADIO_HEAD_SIZE] == TWR_RADIO_HEADER_SUB_REG)
461  {
462  uint8_t *order = queue_item_buffer + TWR_RADIO_HEAD_SIZE + 1;
463 
464  twr_radio_sub_pt_t *pt = (twr_radio_sub_pt_t *) queue_item_buffer + TWR_RADIO_HEAD_SIZE + 2;
465 
466  char *topic = (char *) queue_item_buffer + TWR_RADIO_HEAD_SIZE + 3;
467 
468  twr_radio_on_sub(&id, order, pt, topic);
469  }
470  }
471 
472  if (twr_queue_get(&_twr_radio.pub_queue, queue_item_buffer, &queue_item_length))
473  {
474  uint8_t *buffer = twr_spirit1_get_tx_buffer();
475 
476  twr_radio_id_to_buffer(&_twr_radio.my_id, buffer);
477 
478  _twr_radio.message_id++;
479 
480  buffer[6] = _twr_radio.message_id;
481  buffer[7] = _twr_radio.message_id >> 8;
482 
483  memcpy(buffer + 8, queue_item_buffer, queue_item_length);
484 
485  twr_spirit1_set_tx_length(8 + queue_item_length);
486 
487  twr_spirit1_tx();
488 
489  _twr_radio.transmit_count = _TWR_RADIO_TX_MAX_COUNT;
490 
491  _twr_radio.state = TWR_RADIO_STATE_TX;
492  }
493 }
494 
495 static bool _twr_radio_scan_cache_push(void)
496 {
497  for (uint8_t i = 0; i < _twr_radio.scan_length; i++)
498  {
499  if (_twr_radio.scan_cache[i] == _twr_radio.peer_id)
500  {
501  return false;
502  }
503  }
504 
505  if (_twr_radio.scan_length < _TWR_RADIO_SCAN_CACHE_LENGTH)
506  {
507  _twr_radio.scan_length++;
508  }
509 
510  _twr_radio.scan_cache[_twr_radio.scan_head++] = _twr_radio.peer_id;
511 
512  if (_twr_radio.scan_head == _TWR_RADIO_SCAN_CACHE_LENGTH)
513  {
514  _twr_radio.scan_head = 0;
515  }
516 
517  return true;
518 }
519 
520 static void _twr_radio_send_ack(void)
521 {
522  uint8_t *tx_buffer = twr_spirit1_get_tx_buffer();
523 
524  if (_twr_radio.state == TWR_RADIO_STATE_TX_WAIT_ACK)
525  {
526  _twr_radio.ack_transmit_count = _twr_radio.transmit_count;
527 
528  _twr_radio.ack_tx_cache_length = twr_spirit1_get_tx_length();
529 
530  memcpy(_twr_radio.ack_tx_cache_buffer, tx_buffer, sizeof(_twr_radio.ack_tx_cache_buffer));
531 
532  _twr_radio.state = TWR_RADIO_STATE_TX_SEND_ACK;
533  }
534  else if (_twr_radio.state == TWR_RADIO_STATE_RX)
535  {
536  _twr_radio.state = TWR_RADIO_STATE_RX_SEND_ACK;
537  }
538  else
539  {
540  return;
541  }
542 
543  uint8_t *rx_buffer = twr_spirit1_get_rx_buffer();
544 
545  memcpy(tx_buffer, rx_buffer, 8);
546 
547  tx_buffer[8] = TWR_RADIO_HEADER_ACK;
548 
550 
551  _twr_radio.transmit_count = 2;
552 
553  twr_spirit1_tx();
554 }
555 
556 static void _twr_radio_go_to_state_rx_or_sleep(void)
557 {
558  if (_twr_radio.state == TWR_RADIO_STATE_TX)
559  {
560  return;
561  }
562 
563  if (_twr_radio.mode == TWR_RADIO_MODE_NODE_SLEEPING)
564  {
565  twr_tick_t now = twr_tick_get();
566 
567  if (_twr_radio.rx_timeout_sleeping > now)
568  {
569  _twr_radio.rx_timeout = _twr_radio.rx_timeout_sleeping;
570 
571  twr_spirit1_set_rx_timeout(_twr_radio.rx_timeout - now);
572 
573  twr_spirit1_rx();
574 
575  _twr_radio.state = TWR_RADIO_STATE_RX;
576  }
577  else
578  {
580 
581  _twr_radio.state = TWR_RADIO_STATE_SLEEP;
582  }
583  }
584  else
585  {
586  _twr_radio.rx_timeout = TWR_TICK_INFINITY;
587 
589 
590  twr_spirit1_rx();
591 
592  _twr_radio.state = TWR_RADIO_STATE_RX;
593  }
594 
595  twr_scheduler_plan_now(_twr_radio.task_id);
596 }
597 
598 static void _twr_radio_spirit1_event_handler(twr_spirit1_event_t event, void *event_param)
599 {
600  (void) event_param;
601 
602  if (event == TWR_SPIRIT1_EVENT_TX_DONE)
603  {
604  if (_twr_radio.transmit_count > 0)
605  {
606  _twr_radio.transmit_count--;
607  }
608 
609  if (_twr_radio.state == TWR_RADIO_STATE_TX)
610  {
611  twr_tick_t timeout = _TWR_RADIO_ACK_TIMEOUT - 50 + rand() % _TWR_RADIO_ACK_TIMEOUT;
612 
613  _twr_radio.rx_timeout = twr_tick_get() + timeout;
614 
616 
617  twr_spirit1_rx();
618 
619  _twr_radio.state = TWR_RADIO_STATE_TX_WAIT_ACK;
620 
621  _twr_radio.ack = false;
622 
623  return;
624  }
625 
626  if (_twr_radio.state == TWR_RADIO_STATE_RX_SEND_ACK)
627  {
628  if (_twr_radio.transmit_count > 0)
629  {
630  twr_spirit1_tx();
631 
632  return;
633  }
634  }
635 
636  if (_twr_radio.state == TWR_RADIO_STATE_TX_SEND_ACK)
637  {
638  if (_twr_radio.transmit_count > 0)
639  {
640  twr_spirit1_tx();
641 
642  return;
643  }
644  else
645  {
646  uint8_t *tx_buffer = twr_spirit1_get_tx_buffer();
647 
648  memcpy(tx_buffer, _twr_radio.ack_tx_cache_buffer, sizeof(_twr_radio.ack_tx_cache_buffer));
649 
650  twr_tick_t timeout = _TWR_RADIO_ACK_TIMEOUT - 50 + rand() % _TWR_RADIO_ACK_TIMEOUT;
651 
652  _twr_radio.rx_timeout = twr_tick_get() + timeout;
653 
654  _twr_radio.transmit_count = _twr_radio.ack_transmit_count;
655 
657 
658  twr_spirit1_set_tx_length(_twr_radio.ack_tx_cache_length);
659 
660  twr_spirit1_rx();
661 
662  _twr_radio.state = TWR_RADIO_STATE_TX_WAIT_ACK;
663 
664  return;
665  }
666  }
667 
668  _twr_radio_go_to_state_rx_or_sleep();
669  }
670  else if (event == TWR_SPIRIT1_EVENT_RX_TIMEOUT)
671  {
672  if (_twr_radio.state == TWR_RADIO_STATE_TX_WAIT_ACK)
673  {
674  if (_twr_radio.transmit_count > 0)
675  {
676  twr_spirit1_tx();
677 
678  _twr_radio.state = TWR_RADIO_STATE_TX;
679 
680  return;
681  }
682  else
683  {
684  if (_twr_radio.event_handler)
685  {
686  _twr_radio.event_handler(TWR_RADIO_EVENT_TX_ERROR, _twr_radio.event_param);
687  }
688  }
689 
690  }
691 
692  _twr_radio_go_to_state_rx_or_sleep();
693  }
694  else if (event == TWR_SPIRIT1_EVENT_RX_DONE)
695  {
696  size_t length = twr_spirit1_get_rx_length();
697  uint16_t message_id;
698 
699  if ((_twr_radio.rx_timeout != TWR_TICK_INFINITY) && (twr_tick_get() >= _twr_radio.rx_timeout))
700  {
701  if (_twr_radio.state == TWR_RADIO_STATE_TX_WAIT_ACK)
702  {
703  if (_twr_radio.transmit_count > 0)
704  {
705  twr_spirit1_tx();
706 
707  _twr_radio.state = TWR_RADIO_STATE_TX;
708 
709  return;
710  }
711  }
712 
713  _twr_radio_go_to_state_rx_or_sleep();
714  }
715 
716  if (length >= 9)
717  {
718  uint8_t *buffer = twr_spirit1_get_rx_buffer();
719  twr_radio_peer_t *peer;
720 
721  twr_radio_id_from_buffer(buffer, &_twr_radio.peer_id);
722 
723  message_id = (uint16_t) buffer[6];
724  message_id |= (uint16_t) buffer[7] << 8;
725 
726  // ACK check
727  if (buffer[8] == TWR_RADIO_HEADER_ACK)
728  {
729  if (_twr_radio.state == TWR_RADIO_STATE_TX_WAIT_ACK)
730  {
731  uint8_t *tx_buffer = twr_spirit1_get_tx_buffer();
732 
733  if ((_twr_radio.peer_id == _twr_radio.my_id) && (_twr_radio.message_id == message_id) )
734  {
735  _twr_radio.transmit_count = 0;
736 
737  _twr_radio.ack = true;
738 
739  if (tx_buffer[8] == TWR_RADIO_HEADER_PAIRING)
740  {
741  if (length == 15)
742  {
743  twr_radio_id_from_buffer(buffer + 9, &_twr_radio.peer_id);
744 
745  if ((_twr_radio.mode != TWR_RADIO_MODE_GATEWAY) && (_twr_radio.peer_devices[0].id != _twr_radio.peer_id))
746  {
747  _twr_radio.peer_devices[0].id = _twr_radio.peer_id;
748  _twr_radio.peer_devices[0].message_id_synced = false;
749  _twr_radio.peer_devices_length = 1;
750 
751  _twr_radio.save_peer_devices = true;
752  twr_scheduler_plan_now(_twr_radio.task_id);
753 
754  _twr_radio.sent_subs = 0;
755 
756  if (_twr_radio.event_handler)
757  {
758  _twr_radio.event_handler(TWR_RADIO_EVENT_PAIRED, _twr_radio.event_param);
759  }
760  }
761  }
762  }
763  else if (tx_buffer[8] == TWR_RADIO_HEADER_SUB_REG)
764  {
765  _twr_radio.sent_subs++;
766  }
767  else if ((length == 10) && (buffer[9] == _TWR_RADIO_ACK_SUB_REQUEST))
768  {
769  _twr_radio.sent_subs = 0;
770  }
771 
772  if (_twr_radio.sleeping_mode_rx_timeout != 0)
773  {
774  _twr_radio.rx_timeout_sleeping = twr_tick_get() + _twr_radio.sleeping_mode_rx_timeout;
775  }
776 
777  _twr_radio_go_to_state_rx_or_sleep();
778 
779  if (_twr_radio.event_handler)
780  {
781  _twr_radio.event_handler(TWR_RADIO_EVENT_TX_DONE, _twr_radio.event_param);
782  }
783  }
784 
785  }
786 
787  return;
788  }
789 
790  if (buffer[8] == TWR_RADIO_HEADER_PAIRING)
791  {
792  if (_twr_radio.pairing_mode)
793  {
794  if (length >= 9)
795  {
796  twr_radio_peer_device_add(_twr_radio.peer_id);
797  }
798  }
799 
800  peer = twr_radio_get_peer_device(_twr_radio.peer_id);
801 
802  if (peer != NULL)
803  {
804  _twr_radio_send_ack();
805 
806  uint8_t *tx_buffer = twr_spirit1_get_tx_buffer();
807 
808  twr_radio_id_to_buffer(&_twr_radio.my_id, tx_buffer + 9);
809 
811 
812  if ((length > 10) && (peer->message_id != message_id))
813  {
814  if (10 + (size_t) buffer[9] + 1 < length)
815  {
816  buffer[10 + buffer[9]] = 0;
817 
818  peer->mode = buffer[length - 1];
819 
820  buffer[length - 1] = 0;
821 
822  twr_radio_on_info(&_twr_radio.peer_id, (char *)buffer + 10, (char *)buffer + 10 + buffer[9] + 1, peer->mode);
823  }
824  }
825 
826  peer->message_id = message_id;
827 
828  peer->message_id_synced = true;
829  }
830 
831  return;
832  }
833 
834  if ((length == 15) && ((buffer[8] == TWR_RADIO_HEADER_NODE_ATTACH) || (buffer[8] == TWR_RADIO_HEADER_NODE_DETACH)))
835  {
836  uint64_t id;
837 
838  twr_radio_id_from_buffer(buffer + 9, &id);
839 
840  if (id == _twr_radio.my_id)
841  {
842  if (buffer[8] == TWR_RADIO_HEADER_NODE_ATTACH)
843  {
844  _twr_radio.pairing_request_to_gateway = true;
845 
846  twr_scheduler_plan_now(_twr_radio.task_id);
847  }
848  else if (buffer[8] == TWR_RADIO_HEADER_NODE_DETACH)
849  {
850  _twr_radio_peer_device_remove(_twr_radio.peer_id);
851 
852  if (_twr_radio.event_handler)
853  {
854  _twr_radio.event_handler(TWR_RADIO_EVENT_UNPAIRED, _twr_radio.event_param);
855  }
856  }
857  }
858 
859  _twr_radio_send_ack();
860 
861  return;
862  }
863 
864  peer = twr_radio_get_peer_device(_twr_radio.peer_id);
865 
866  if (peer != NULL)
867  {
868  if (peer->message_id != message_id)
869  {
870  bool send_subs_request = _twr_radio.mode == TWR_RADIO_MODE_GATEWAY && (!peer->message_id_synced || (peer->message_id > message_id));
871 
872  peer->message_id = message_id;
873 
874  peer->message_id_synced = false;
875 
876  if (length > 9)
877  {
878  if ((buffer[8] >= 0x15) && (buffer[8] <= 0x1d) && (length > 14))
879  {
880  uint64_t for_id;
881 
882  twr_radio_id_from_buffer(buffer + 9, &for_id);
883 
884  if (for_id != _twr_radio.my_id)
885  {
886  return;
887  }
888  }
889 
890  twr_queue_put(&_twr_radio.rx_queue, buffer, length);
891 
892  twr_scheduler_plan_now(_twr_radio.task_id);
893 
894  peer->message_id_synced = true;
895 
896  peer->rssi = twr_spirit1_get_rx_rssi();
897  }
898 
899  if (peer->message_id_synced)
900  {
901  _twr_radio_send_ack();
902 
903  if (send_subs_request)
904  {
905  uint8_t *tx_buffer = twr_spirit1_get_tx_buffer();
906 
907  tx_buffer[9] = _TWR_RADIO_ACK_SUB_REQUEST;
908 
910  }
911  }
912 
913  return;
914  }
915  }
916  else
917  {
918  if (_twr_radio.scan && (_twr_radio.event_handler != NULL) && _twr_radio_scan_cache_push())
919  {
920  _twr_radio.event_handler(TWR_RADIO_EVENT_SCAN_FIND_DEVICE, _twr_radio.event_param);
921  }
922 
923  if (_twr_radio.automatic_pairing)
924  {
925  twr_radio_peer_device_add(_twr_radio.peer_id);
926  }
927  }
928  }
929  }
930 }
931 
932 static void _twr_radio_load_peer_devices(void)
933 {
934  uint32_t address = (uint32_t) twr_eeprom_get_size() - 8;
935  uint64_t buffer[3];
936  uint32_t *pointer = (uint32_t *)buffer;
937  uint8_t length = 0;
938 
939  twr_eeprom_read(twr_eeprom_get_size() - 1, &length, 1);
940 
941  _twr_radio.peer_devices_length = 0;
942 
943  for (int i = 0; (i < length) && (i < TWR_RADIO_MAX_DEVICES); i++)
944  {
945  address -= sizeof(buffer);
946 
947  twr_eeprom_read(address, buffer, sizeof(buffer));
948 
949  pointer[2] = ~pointer[2];
950  pointer[5] = ~pointer[5];
951 
952  if ((buffer[0] != buffer[1]) && (buffer[0] != buffer[2]))
953  {
954  if (buffer[1] == buffer[2])
955  {
956  buffer[0] = buffer[1];
957 
958  _twr_radio.save_peer_devices = true;
959 
960  twr_scheduler_plan_now(_twr_radio.task_id);
961  }
962  else
963  {
964  continue;
965  }
966  }
967 
968  if (buffer[0] != 0)
969  {
970  _twr_radio.peer_devices[_twr_radio.peer_devices_length].id = buffer[0];
971  _twr_radio.peer_devices[_twr_radio.peer_devices_length].message_id_synced = false;
972  _twr_radio.peer_devices_length++;
973  }
974  }
975 }
976 
977 static void _twr_radio_save_peer_devices(void)
978 {
979  uint32_t address = (uint32_t) twr_eeprom_get_size() - 8;
980  uint64_t buffer_write[3];
981  uint32_t *pointer_write = (uint32_t *)buffer_write;
982  uint64_t buffer_read[3];
983 
984  _twr_radio.save_peer_devices = false;
985 
986  for (int i = 0; i < _twr_radio.peer_devices_length; i++)
987  {
988  buffer_write[0] = _twr_radio.peer_devices[i].id;
989  buffer_write[1] = _twr_radio.peer_devices[i].id;
990  buffer_write[2] = _twr_radio.peer_devices[i].id;
991 
992  pointer_write[2] = ~pointer_write[2];
993  pointer_write[5] = ~pointer_write[5];
994 
995  address -= sizeof(buffer_write);
996 
997  twr_eeprom_read(address, buffer_read, sizeof(buffer_read));
998 
999  if (memcmp(buffer_read, buffer_write, sizeof(buffer_write)) != 0)
1000  {
1001  if (!twr_eeprom_write(address, buffer_write, sizeof(buffer_write)))
1002  {
1003  _twr_radio.save_peer_devices = true;
1004 
1005  twr_scheduler_plan_now(_twr_radio.task_id);
1006 
1007  return;
1008  }
1009  }
1010  }
1011 
1012  if (!twr_eeprom_write(twr_eeprom_get_size() - 1, &_twr_radio.peer_devices_length, 1))
1013  {
1014  _twr_radio.save_peer_devices = true;
1015 
1016  twr_scheduler_plan_now(_twr_radio.task_id);
1017 
1018  return;
1019  }
1020 }
1021 
1022 static void _twr_radio_atsha204_event_handler(twr_atsha204_t *self, twr_atsha204_event_t event, void *event_param)
1023 {
1024  (void) event_param;
1025 
1026  if (event == TWR_ATSHA204_EVENT_SERIAL_NUMBER)
1027  {
1028  if (twr_atsha204_get_serial_number(self, &_twr_radio.my_id, sizeof(_twr_radio.my_id)))
1029  {
1030  if (_twr_radio.event_handler != NULL)
1031  {
1032  _twr_radio.event_handler(TWR_RADIO_EVENT_INIT_DONE, _twr_radio.event_param);
1033  }
1034  }
1035  else
1036  {
1037  if (_twr_radio.event_handler != NULL)
1038  {
1039  _twr_radio.event_handler(TWR_RADIO_EVENT_INIT_FAILURE, _twr_radio.event_param);
1040  }
1041  }
1042  }
1043  else if (event == TWR_ATSHA204_EVENT_ERROR)
1044  {
1045  if (_twr_radio.event_handler != NULL)
1046  {
1047  _twr_radio.event_handler(TWR_RADIO_EVENT_INIT_FAILURE, _twr_radio.event_param);
1048  }
1049  }
1050 }
1051 
1052 static bool _twr_radio_peer_device_add(uint64_t id)
1053 {
1054  if (_twr_radio.peer_devices_length + 1 == TWR_RADIO_MAX_DEVICES)
1055  {
1056  if (_twr_radio.event_handler != NULL)
1057  {
1058  _twr_radio.peer_id = id;
1059  _twr_radio.event_handler(TWR_RADIO_EVENT_ATTACH_FAILURE, _twr_radio.event_param);
1060  }
1061  return false;
1062  }
1063 
1064  if (twr_radio_is_peer_device(id))
1065  {
1066  return false;
1067  }
1068 
1069  _twr_radio.peer_devices[_twr_radio.peer_devices_length].id = id;
1070  _twr_radio.peer_devices[_twr_radio.peer_devices_length].message_id_synced = false;
1071  _twr_radio.peer_devices_length++;
1072 
1073  _twr_radio.save_peer_devices = true;
1074  twr_scheduler_plan_now(_twr_radio.task_id);
1075 
1076  if (_twr_radio.event_handler != NULL)
1077  {
1078  _twr_radio.peer_id = id;
1079  _twr_radio.event_handler(TWR_RADIO_EVENT_ATTACH, _twr_radio.event_param);
1080  }
1081 
1082  return true;
1083 }
1084 
1085 static bool _twr_radio_peer_device_remove(uint64_t id)
1086 {
1087  for (int i = 0; i < _twr_radio.peer_devices_length; i++)
1088  {
1089  if (id == _twr_radio.peer_devices[i].id)
1090  {
1091  _twr_radio.peer_devices_length--;
1092  _twr_radio.peer_devices[i].id = 0;
1093 
1094  if (i != _twr_radio.peer_devices_length)
1095  {
1096  memcpy(_twr_radio.peer_devices + i, _twr_radio.peer_devices + _twr_radio.peer_devices_length, sizeof(twr_radio_peer_t));
1097  }
1098 
1099  _twr_radio.save_peer_devices = true;
1100  twr_scheduler_plan_now(_twr_radio.task_id);
1101 
1102  if (_twr_radio.event_handler != NULL)
1103  {
1104  _twr_radio.peer_id = id;
1105  _twr_radio.event_handler(TWR_RADIO_EVENT_DETACH, _twr_radio.event_param);
1106  }
1107 
1108  return true;
1109  }
1110  }
1111 
1112  return false;
1113 }
1114 
1115 twr_radio_peer_t *twr_radio_get_peer_device(uint64_t id)
1116 {
1117  for (int i = 0; i < _twr_radio.peer_devices_length; i++)
1118  {
1119  if (id == _twr_radio.peer_devices[i].id)
1120  {
1121  return &_twr_radio.peer_devices[i];
1122  }
1123  }
1124 
1125  return NULL;
1126 }
1127 
1128 uint8_t *twr_radio_id_to_buffer(uint64_t *id, uint8_t *buffer)
1129 {
1130  buffer[0] = *id;
1131  buffer[1] = *id >> 8;
1132  buffer[2] = *id >> 16;
1133  buffer[3] = *id >> 24;
1134  buffer[4] = *id >> 32;
1135  buffer[5] = *id >> 40;
1136 
1137  return buffer + TWR_RADIO_ID_SIZE;
1138 }
1139 
1140 uint8_t *twr_radio_bool_to_buffer(bool *value, uint8_t *buffer)
1141 {
1142  *buffer = value == NULL ? TWR_RADIO_NULL_BOOL : *value;
1143 
1144  return buffer + 1;
1145 }
1146 
1147 uint8_t *twr_radio_int_to_buffer(int *value, uint8_t *buffer)
1148 {
1149  if (value == NULL)
1150  {
1151  const int null = TWR_RADIO_NULL_INT;
1152 
1153  memcpy(buffer, &null, sizeof(int));
1154  }
1155  else
1156  {
1157  memcpy(buffer, value, sizeof(int));
1158  }
1159 
1160  return buffer + sizeof(int);
1161 }
1162 
1163 uint8_t *twr_radio_uint16_to_buffer(uint16_t *value, uint8_t *buffer)
1164 {
1165  if (value == NULL)
1166  {
1167  const int null = TWR_RADIO_NULL_UINT16;
1168 
1169  memcpy(buffer, &null, sizeof(uint16_t));
1170  }
1171  else
1172  {
1173  memcpy(buffer, value, sizeof(uint16_t));
1174  }
1175 
1176  return buffer + sizeof(uint16_t);
1177 }
1178 
1179 uint8_t *twr_radio_uint32_to_buffer(uint32_t *value, uint8_t *buffer)
1180 {
1181  if (value == NULL)
1182  {
1183  const int null = TWR_RADIO_NULL_UINT32;
1184 
1185  memcpy(buffer, &null, sizeof(uint32_t));
1186  }
1187  else
1188  {
1189  memcpy(buffer, value, sizeof(uint32_t));
1190  }
1191 
1192  return buffer + sizeof(uint32_t);
1193 }
1194 
1195 uint8_t *twr_radio_float_to_buffer(float *value, uint8_t *buffer)
1196 {
1197  if (value == NULL)
1198  {
1199  const float null = TWR_RADIO_NULL_FLOAT;
1200 
1201  memcpy(buffer, &null, sizeof(float));
1202  }
1203  else
1204  {
1205  memcpy(buffer, value, sizeof(float));
1206  }
1207 
1208  return buffer + sizeof(float);
1209 }
1210 
1211 uint8_t *twr_radio_data_to_buffer(void *data, size_t length, uint8_t *buffer)
1212 {
1213  if (data == NULL)
1214  {
1215  return buffer + length;
1216  }
1217 
1218  memcpy(buffer, data, length);
1219 
1220  return buffer + length;
1221 }
1222 
1223 uint8_t *twr_radio_id_from_buffer(uint8_t *buffer, uint64_t *id)
1224 {
1225  *id = (uint64_t) buffer[0];
1226  *id |= (uint64_t) buffer[1] << 8;
1227  *id |= (uint64_t) buffer[2] << 16;
1228  *id |= (uint64_t) buffer[3] << 24;
1229  *id |= (uint64_t) buffer[4] << 32;
1230  *id |= (uint64_t) buffer[5] << 40;
1231 
1232  return buffer + TWR_RADIO_ID_SIZE;
1233 }
1234 
1235 uint8_t *twr_radio_bool_from_buffer(uint8_t *buffer, bool *value, bool **pointer)
1236 {
1237  if (*buffer == TWR_RADIO_NULL_BOOL)
1238  {
1239  *pointer = NULL;
1240  }
1241  else
1242  {
1243  *value = *(bool *) buffer;
1244  *pointer = value;
1245  }
1246 
1247  return buffer + 1;
1248 }
1249 
1250 uint8_t *twr_radio_int_from_buffer(uint8_t *buffer, int *value, int **pointer)
1251 {
1252  memcpy(value, buffer, sizeof(int));
1253 
1254  if (*value == TWR_RADIO_NULL_INT)
1255  {
1256  *pointer = NULL;
1257  }
1258  else
1259  {
1260  *pointer = value;
1261  }
1262 
1263  return buffer + sizeof(int);
1264 }
1265 
1266 uint8_t *twr_radio_uint16_from_buffer(uint8_t *buffer, uint16_t *value, uint16_t **pointer)
1267 {
1268  memcpy(value, buffer, sizeof(uint16_t));
1269 
1270  if (*value == TWR_RADIO_NULL_UINT16)
1271  {
1272  *pointer = NULL;
1273  }
1274  else
1275  {
1276  *pointer = value;
1277  }
1278 
1279  return buffer + sizeof(uint16_t);
1280 }
1281 
1282 uint8_t *twr_radio_uint32_from_buffer(uint8_t *buffer, uint32_t *value, uint32_t **pointer)
1283 {
1284  memcpy(value, buffer, sizeof(uint32_t));
1285 
1286  if (*value == TWR_RADIO_NULL_UINT32)
1287  {
1288  *pointer = NULL;
1289  }
1290  else
1291  {
1292  *pointer = value;
1293  }
1294 
1295  return buffer + sizeof(uint32_t);
1296 }
1297 
1298 uint8_t *twr_radio_float_from_buffer(uint8_t *buffer, float *value, float **pointer)
1299 {
1300  memcpy(value, buffer, sizeof(float));
1301 
1302  if (isnan(*value))
1303  {
1304  *pointer = NULL;
1305  }
1306  else
1307  {
1308  *pointer = value;
1309  }
1310 
1311  return buffer + sizeof(float);
1312 }
1313 
1314 uint8_t *twr_radio_data_from_buffer(uint8_t *buffer, void *data, size_t length)
1315 {
1316  if (data == NULL)
1317  {
1318  return buffer + length;
1319  }
1320 
1321  memcpy(data, buffer, length);
1322 
1323  return buffer + length;
1324 }
1325 
1326 typedef struct
1327 {
1328  twr_led_t *led;
1329  const char *firmware;
1330  const char *version;
1331 
1333 
1334 void _twr_radio_button_event_handler(twr_button_t *self, twr_button_event_t event, void *event_param)
1335 {
1336  (void) self;
1338 
1339  if (event == TWR_BUTTON_EVENT_PRESS)
1340  {
1341  if (param->led != NULL)
1342  {
1343  twr_led_pulse(param->led, 100);
1344  }
1345 
1346  static uint16_t event_count = 0;
1347 
1348  twr_radio_pub_push_button(&event_count);
1349 
1350  event_count++;
1351  }
1352  else if (event == TWR_BUTTON_EVENT_HOLD)
1353  {
1354  twr_radio_pairing_request(param->firmware, param->version);
1355 
1356  if (param->led != NULL)
1357  {
1358  twr_led_set_mode(param->led, TWR_LED_MODE_OFF);
1359  twr_led_pulse(param->led, 1000);
1360  }
1361  }
1362 }
1363 
1364 void twr_radio_init_pairing_button(const char *firmware, const char *version)
1365 {
1366  static twr_led_t led;
1367  static twr_button_t button;
1368  static _twr_radio_button_event_param_t param;
1369  param.led = &led;
1370  param.firmware = firmware;
1371  param.version = version;
1372 
1374  // Pass led instance as a callback parameter, so we don't need to add it to the radio structure
1375  twr_button_set_event_handler(&button, _twr_radio_button_event_handler, &param);
1376 
1377  twr_led_init(&led, TWR_GPIO_LED, false, 0);
1378 
1379 }
twr_radio_sub_pt_t
Subscribe payload type.
Definition: twr_radio.h:111
twr_button_event_t
Callback events.
Definition: twr_button.h:14
Event button hold (pressed for longer time)
Definition: twr_button.h:26
void twr_atsha204_set_event_handler(twr_atsha204_t *self, void(*event_handler)(twr_atsha204_t *, twr_atsha204_event_t, void *), void *event_param)
Set callback function.
Definition: twr_atsha204.c:29
Unknown mode.
Definition: twr_radio.h:40
void twr_led_pulse(twr_led_t *self, twr_tick_t duration)
Turn on LED for the specified duration of time.
Definition: twr_led.c:239
bool twr_atsha204_get_serial_number(twr_atsha204_t *self, void *destination, size_t size)
Get serial number.
Definition: twr_atsha204.c:59
Event is RX done.
Definition: twr_spirit1.h:24
Event serial number is available.
Definition: twr_atsha204.h:23
size_t twr_spirit1_get_rx_length(void)
Get RX buffer length.
Definition: twr_spirit1.c:196
Event button pressed.
Definition: twr_button.h:17
GPIO channel BUTTON.
Definition: twr_gpio.h:72
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
void * twr_spirit1_get_tx_buffer(void)
Get TX buffer.
Definition: twr_spirit1.c:176
void twr_radio_node_decode(uint64_t *id, uint8_t *buffer, size_t length)
Internal decode function for twr_radio.c.
void twr_button_set_event_handler(twr_button_t *self, void(*event_handler)(twr_button_t *, twr_button_event_t, void *), void *event_param)
Set callback function.
Definition: twr_button.c:66
void twr_spirit1_set_tx_length(size_t length)
Set TX buffer length.
Definition: twr_spirit1.c:181
struct twr_led_t twr_led_t
LED instance.
Definition: twr_led.h:52
Gateway mode.
Definition: twr_radio.h:43
Node sleeping mode, suitable for battery.
Definition: twr_radio.h:49
bool twr_radio_pub_push_button(uint16_t *event_count)
Publish push button event count, same as use twr_radio_pub_event_count with TWR_RADIO_PUB_EVENT_PUSH_...
Definition: twr_radio_pub.c:36
void twr_queue_clear(twr_queue_t *queue)
Clear queue.
Definition: twr_queue.c:70
void twr_spirit1_rx(void)
Enter RX state.
Definition: twr_spirit1.c:238
void twr_queue_init(twr_queue_t *queue, void *buffer, size_t size)
Initialize queue.
Definition: twr_queue.c:3
bool twr_eeprom_write(uint32_t address, const void *buffer, size_t length)
Write buffer to EEPROM area and verify it.
Definition: twr_eeprom.c:31
void twr_spirit1_sleep(void)
Enter sleep state.
Definition: twr_spirit1.c:248
twr_atsha204_event_t
Definition: twr_atsha204.h:14
bool twr_spirit1_init(void)
Initialize.
Definition: twr_spirit1.c:98
void twr_atsha204_init(twr_atsha204_t *self, twr_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize ATSHA204 driver.
Definition: twr_atsha204.c:15
LED has steady off state.
Definition: twr_led.h:31
void twr_radio_pub_queue_clear()
Clear the publish message queue.
Definition: twr_radio.c:272
void twr_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
struct twr_atsha204_t twr_atsha204_t
ATSHA204 instance.
Definition: twr_atsha204.h:29
void twr_led_init(twr_led_t *self, twr_gpio_channel_t gpio_channel, bool open_drain_output, int idle_state)
Initialize LED.
Definition: twr_led.c:75
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_button_init(twr_button_t *self, twr_gpio_channel_t gpio_channel, twr_gpio_pull_t gpio_pull, int idle_state)
Initialize button.
Definition: twr_button.c:20
bool twr_queue_get(twr_queue_t *queue, void *buffer, size_t *length)
Get queue to buffer.
Definition: twr_queue.c:45
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
void twr_spirit1_set_event_handler(void(*event_handler)(twr_spirit1_event_t, void *), void *event_param)
Set callback function.
Definition: twr_spirit1.c:170
bool twr_queue_put(twr_queue_t *queue, const void *buffer, size_t length)
Put buffer to queue.
Definition: twr_queue.c:11
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
int twr_spirit1_get_rx_rssi(void)
Get RSSI.
Definition: twr_spirit1.c:201
twr_radio_mode_t
Radio mode.
Definition: twr_radio.h:37
I2C channel I2C0.
Definition: twr_i2c.h:18
GPIO channel has pull-down.
Definition: twr_gpio.h:96
Event is RX timeout.
Definition: twr_spirit1.h:27
void twr_radio_init(twr_radio_mode_t mode)
Initialize radio.
Definition: twr_radio.c:89
void twr_radio_pub_decode(uint64_t *id, uint8_t *buffer, size_t length)
Internal decode function for twr_radio.c.
size_t twr_spirit1_get_tx_length(void)
Get TX buffer length.
Definition: twr_spirit1.c:186
bool twr_atsha204_read_serial_number(twr_atsha204_t *self)
Reqeust for serial number.
Definition: twr_atsha204.c:40
twr_spirit1_event_t
Callback events.
Definition: twr_spirit1.h:18
void twr_spirit1_tx(void)
Enter TX state.
Definition: twr_spirit1.c:228
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
struct twr_button_t twr_button_t
Button instance.
Definition: twr_button.h:32
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
void twr_spirit1_set_rx_timeout(twr_tick_t timeout)
Set TX timeout.
Definition: twr_spirit1.c:206
GPIO channel LED.
Definition: twr_gpio.h:69
void * twr_spirit1_get_rx_buffer(void)
Get RX buffer.
Definition: twr_spirit1.c:191
size_t twr_eeprom_get_size(void)
Return size of EEPROM area.
Definition: twr_eeprom.c:132
void twr_led_set_mode(twr_led_t *self, twr_led_mode_t mode)
Set LED mode.
Definition: twr_led.c:125
Event is TX done.
Definition: twr_spirit1.h:21
bool twr_eeprom_read(uint32_t address, void *buffer, size_t length)
Read buffer from EEPROM area.
Definition: twr_eeprom.c:113