Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_radio.c
1 #include <bc_radio.h>
2 #include <bc_queue.h>
3 #include <bc_atsha204.h>
4 #include <bc_scheduler.h>
5 #include <bc_eeprom.h>
6 #include <bc_i2c.h>
7 #include <bc_radio_pub.h>
8 #include <bc_radio_node.h>
9 #include <math.h>
10 
11 #define _BC_RADIO_SCAN_CACHE_LENGTH 4
12 #define _BC_RADIO_ACK_TIMEOUT 100
13 #define _BC_RADIO_SLEEP_RX_TIMEOUT 100
14 #define _BC_RADIO_TX_MAX_COUNT 6
15 #define _BC_RADIO_ACK_SUB_REQUEST 0x11
16 
17 typedef enum
18 {
19  BC_RADIO_STATE_SLEEP = 0,
20  BC_RADIO_STATE_TX = 1,
21  BC_RADIO_STATE_RX = 2,
22  BC_RADIO_STATE_TX_WAIT_ACK = 3,
23  BC_RADIO_STATE_RX_SEND_ACK = 4,
24  BC_RADIO_STATE_TX_SEND_ACK = 5,
25 
26 } bc_radio_state_t;
27 
28 static struct
29 {
30  bc_radio_mode_t mode;
31  bc_atsha204_t atsha204;
32  bc_radio_state_t state;
33  uint64_t my_id;
34  uint16_t message_id;
35  int transmit_count;
36  void (*event_handler)(bc_radio_event_t, void *);
37  void *event_param;
38  bc_scheduler_task_id_t task_id;
39  bool pairing_request_to_gateway;
40  const char *firmware;
41  const char *firmware_version;
42  bool pairing_mode;
43 
44  bc_queue_t pub_queue;
45  bc_queue_t rx_queue;
46  uint8_t pub_queue_buffer[BC_RADIO_PUB_QUEUE_BUFFER_SIZE];
47  uint8_t rx_queue_buffer[BC_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  bc_tick_t rx_timeout;
53  bool ack;
54 
55  bc_radio_peer_t peer_devices[BC_RADIO_MAX_DEVICES];
56  int peer_devices_length;
57 
58  uint64_t peer_id;
59 
60  bc_tick_t sleeping_mode_rx_timeout;
61  bc_tick_t rx_timeout_sleeping;
62 
63  bool scan;
64  uint64_t scan_cache[_BC_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  bc_radio_sub_t *subs;
72  int subs_length;
73  int sent_subs;
74 
75 } _bc_radio;
76 
77 static void _bc_radio_task(void *param);
78 static void _bc_radio_go_to_state_rx_or_sleep(void);
79 static void _bc_radio_spirit1_event_handler(bc_spirit1_event_t event, void *event_param);
80 static void _bc_radio_load_peer_devices(void);
81 static void _bc_radio_save_peer_devices(void);
82 static void _bc_radio_atsha204_event_handler(bc_atsha204_t *self, bc_atsha204_event_t event, void *event_param);
83 static bool _bc_radio_peer_device_add(uint64_t id);
84 static bool _bc_radio_peer_device_remove(uint64_t id);
85 
86 __attribute__((weak)) void bc_radio_on_info(uint64_t *id, char *firmware, char *version, bc_radio_mode_t mode) { (void) id; (void) firmware; (void) version; (void) mode;}
87 __attribute__((weak)) void bc_radio_on_sub(uint64_t *id, uint8_t *order, bc_radio_sub_pt_t *pt, char *topic) { (void) id; (void) order; (void) pt; (void) topic; }
88 
90 {
91  memset(&_bc_radio, 0, sizeof(_bc_radio));
92 
93  _bc_radio.mode = mode;
94 
95  bc_atsha204_init(&_bc_radio.atsha204, BC_I2C_I2C0, 0x64);
96  bc_atsha204_set_event_handler(&_bc_radio.atsha204, _bc_radio_atsha204_event_handler, NULL);
97  bc_atsha204_read_serial_number(&_bc_radio.atsha204);
98 
99  bc_queue_init(&_bc_radio.pub_queue, _bc_radio.pub_queue_buffer, sizeof(_bc_radio.pub_queue_buffer));
100  bc_queue_init(&_bc_radio.rx_queue, _bc_radio.rx_queue_buffer, sizeof(_bc_radio.rx_queue_buffer));
101 
102  bc_spirit1_init();
103  bc_spirit1_set_event_handler(_bc_radio_spirit1_event_handler, NULL);
104 
105  _bc_radio_load_peer_devices();
106 
107  _bc_radio.task_id = bc_scheduler_register(_bc_radio_task, NULL, BC_TICK_INFINITY);
108 
109  _bc_radio_go_to_state_rx_or_sleep();
110 }
111 
112 void bc_radio_set_event_handler(void (*event_handler)(bc_radio_event_t, void *), void *event_param)
113 {
114  _bc_radio.event_handler = event_handler;
115  _bc_radio.event_param = event_param;
116 }
117 
118 void bc_radio_listen(bc_tick_t timeout)
119 {
120  _bc_radio.rx_timeout_sleeping = bc_tick_get() + timeout;
121 
122  bc_scheduler_plan_now(_bc_radio.task_id);
123 }
124 
125 void bc_radio_pairing_request(const char *firmware, const char *version)
126 {
127  if ((_bc_radio.firmware != NULL) || (_bc_radio.firmware_version != NULL))
128  {
129  return;
130  }
131 
132  _bc_radio.firmware = firmware;
133 
134  _bc_radio.firmware_version = version;
135 
136  _bc_radio.pairing_request_to_gateway = true;
137 
138  bc_scheduler_plan_now(_bc_radio.task_id);
139 }
140 
141 void bc_radio_pairing_mode_start(void)
142 {
143  _bc_radio.pairing_mode = true;
144 }
145 
146 void bc_radio_pairing_mode_stop(void)
147 {
148  _bc_radio.pairing_mode = false;
149 }
150 
151 bool bc_radio_peer_device_add(uint64_t id)
152 {
153 
154  if (!_bc_radio_peer_device_add(id))
155  {
156  return false;
157  }
158 
159  uint8_t buffer[1 + BC_RADIO_ID_SIZE];
160 
161  buffer[0] = BC_RADIO_HEADER_NODE_ATTACH;
162 
163  bc_radio_id_to_buffer(&id, buffer + 1);
164 
165  bc_queue_put(&_bc_radio.pub_queue, buffer, sizeof(buffer));
166 
167  bc_scheduler_plan_now(_bc_radio.task_id);
168 
169  return true;
170 }
171 
172 bool bc_radio_peer_device_remove(uint64_t id)
173 {
174  if (!_bc_radio_peer_device_remove(id))
175  {
176  return false;
177  }
178 
179  uint8_t buffer[1 + BC_RADIO_ID_SIZE];
180 
181  buffer[0] = BC_RADIO_HEADER_NODE_DETACH;
182 
183  bc_radio_id_to_buffer(&id, buffer + 1);
184 
185  bc_queue_put(&_bc_radio.pub_queue, buffer, sizeof(buffer));
186 
187  bc_scheduler_plan_now(_bc_radio.task_id);
188 
189  return true;
190 }
191 
192 bool bc_radio_peer_device_purge_all(void)
193 {
194  for (int i = _bc_radio.peer_devices_length -1; i > -1 ; i--)
195  {
196  if (_bc_radio.peer_devices[i].id != 0)
197  {
198  if (!bc_radio_peer_device_remove(_bc_radio.peer_devices[i].id))
199  {
200  return false;
201  }
202  }
203  }
204  return true;
205 }
206 
207 void bc_radio_get_peer_id(uint64_t *id, int length)
208 {
209  int i;
210  for (i = 0; (i < _bc_radio.peer_devices_length) && (i < length); i++)
211  {
212  id[i] = _bc_radio.peer_devices[i].id;
213  }
214  for (;i < length; i++)
215  {
216  id[i] = 0;
217  }
218 }
219 
220 void bc_radio_scan_start(void)
221 {
222  memset(_bc_radio.scan_cache, 0x00, sizeof(_bc_radio.scan_cache));
223  _bc_radio.scan_length = 0;
224  _bc_radio.scan_head = 0;
225  _bc_radio.scan = true;
226 }
227 
228 void bc_radio_scan_stop(void)
229 {
230  _bc_radio.scan = false;
231 }
232 
233 void bc_radio_automatic_pairing_start(void)
234 {
235  _bc_radio.automatic_pairing = true;
236 }
237 
238 void bc_radio_automatic_pairing_stop(void)
239 {
240  _bc_radio.automatic_pairing = false;
241 }
242 
243 uint64_t bc_radio_get_my_id(void)
244 {
245  return _bc_radio.my_id;
246 }
247 
248 uint64_t bc_radio_get_event_id(void)
249 {
250  return _bc_radio.peer_id;
251 }
252 
253 bool bc_radio_is_peer_device(uint64_t id)
254 {
255  for (int i = 0; i < _bc_radio.peer_devices_length; i++)
256  {
257  if (id == _bc_radio.peer_devices[i].id)
258  {
259  return true;
260  }
261  }
262  return false;
263 }
264 
265 bool bc_radio_pub_queue_put(const void *buffer, size_t length)
266 {
267  if (!bc_queue_put(&_bc_radio.pub_queue, buffer, length))
268  {
269  return false;
270  }
271 
272  bc_scheduler_plan_now(_bc_radio.task_id);
273 
274  return true;
275 }
276 
277 void bc_radio_set_subs(bc_radio_sub_t *subs, int length)
278 {
279  _bc_radio.subs = subs;
280 
281  _bc_radio.subs_length = length;
282 
283  _bc_radio.sent_subs = 0;
284 }
285 
286 bool bc_radio_send_sub_data(uint64_t *id, uint8_t order, void *payload, size_t size)
287 {
288  uint8_t qbuffer[1 + BC_RADIO_ID_SIZE + BC_RADIO_NODE_MAX_BUFFER_SIZE];
289 
290  if (size > BC_RADIO_NODE_MAX_BUFFER_SIZE - 1)
291  {
292  return false;
293  }
294 
295  qbuffer[0] = BC_RADIO_HEADER_SUB_DATA;
296 
297  uint8_t *pqbuffer = bc_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 bc_radio_pub_queue_put(qbuffer, 1 + BC_RADIO_ID_SIZE + 1 + size);
312 }
313 
314 void bc_radio_set_rx_timeout_for_sleeping_node(bc_tick_t timeout)
315 {
316  _bc_radio.sleeping_mode_rx_timeout = timeout;
317 }
318 
319 static void _bc_radio_task(void *param)
320 {
321  (void) param;
322 
323  if (_bc_radio.my_id == 0)
324  {
325  bc_atsha204_read_serial_number(&_bc_radio.atsha204);
326 
328 
329  return;
330  }
331 
332  if ((_bc_radio.state != BC_RADIO_STATE_RX) && (_bc_radio.state != BC_RADIO_STATE_SLEEP))
333  {
335 
336  return;
337  }
338 
339  if (_bc_radio.save_peer_devices)
340  {
341  _bc_radio_save_peer_devices();
342  }
343 
344  if (_bc_radio.pairing_request_to_gateway)
345  {
346  _bc_radio.pairing_request_to_gateway = false;
347 
348  size_t len_firmware = strlen(_bc_radio.firmware);
349 
350  size_t len = len_firmware + strlen(_bc_radio.firmware_version);
351 
352  if (len > BC_RADIO_MAX_BUFFER_SIZE - 5)
353  {
354  return;
355  }
356 
357  uint8_t *buffer = bc_spirit1_get_tx_buffer();
358 
359  bc_radio_id_to_buffer(&_bc_radio.my_id, buffer);
360 
361  _bc_radio.message_id++;
362 
363  buffer[6] = _bc_radio.message_id;
364  buffer[7] = _bc_radio.message_id >> 8;
365 
366  buffer[8] = BC_RADIO_HEADER_PAIRING;
367  buffer[9] = len_firmware;
368 
369  strncpy((char *)buffer + 10, _bc_radio.firmware, BC_RADIO_MAX_BUFFER_SIZE - 2);
370  strncpy((char *)buffer + 10 + len_firmware + 1, _bc_radio.firmware_version, BC_RADIO_MAX_BUFFER_SIZE - 2 - len_firmware - 1);
371 
372  buffer[10 + len + 1] = _bc_radio.mode;
373 
374  bc_spirit1_set_tx_length(10 + len + 2);
375 
376  bc_spirit1_tx();
377 
378  _bc_radio.transmit_count = _BC_RADIO_TX_MAX_COUNT;
379 
380  _bc_radio.state = BC_RADIO_STATE_TX;
381 
382  return;
383  }
384 
385  if (_bc_radio.ack && (_bc_radio.sent_subs != _bc_radio.subs_length))
386  {
387  uint8_t *buffer = bc_spirit1_get_tx_buffer();
388 
389  bc_radio_sub_t *sub = &_bc_radio.subs[_bc_radio.sent_subs];
390 
391  bc_radio_id_to_buffer(&_bc_radio.my_id, buffer);
392 
393  _bc_radio.message_id++;
394 
395  buffer[6] = _bc_radio.message_id;
396  buffer[7] = _bc_radio.message_id >> 8;
397 
398  buffer[8] = BC_RADIO_HEADER_SUB_REG;
399 
400  buffer[9] = _bc_radio.sent_subs;
401 
402  buffer[10] = sub->type;
403 
404  strncpy((char *)buffer + 11, sub->topic, BC_RADIO_MAX_BUFFER_SIZE - 3);
405 
406  bc_spirit1_set_tx_length(11 + strlen(sub->topic) + 1);
407 
408  bc_spirit1_tx();
409 
410  _bc_radio.transmit_count = _BC_RADIO_TX_MAX_COUNT;
411 
412  _bc_radio.state = BC_RADIO_STATE_TX;
413 
414  return;
415  }
416 
417  uint8_t queue_item_buffer[sizeof(_bc_radio.pub_queue_buffer)];
418  size_t queue_item_length;
419  uint64_t id;
420 
421  while (bc_queue_get(&_bc_radio.rx_queue, queue_item_buffer, &queue_item_length))
422  {
423  bc_radio_id_from_buffer(queue_item_buffer, &id);
424 
425  queue_item_length -= BC_RADIO_HEAD_SIZE;
426 
427  bc_radio_pub_decode(&id, queue_item_buffer + BC_RADIO_HEAD_SIZE, queue_item_length);
428 
429  bc_radio_node_decode(&id, queue_item_buffer + BC_RADIO_HEAD_SIZE, queue_item_length);
430 
431  if (queue_item_buffer[BC_RADIO_HEAD_SIZE] == BC_RADIO_HEADER_SUB_DATA)
432  {
433  uint8_t order = queue_item_buffer[BC_RADIO_HEAD_SIZE + 1 + BC_RADIO_ID_SIZE];
434 
435  if (order >= _bc_radio.subs_length)
436  {
437  return;
438  }
439 
440  bc_radio_sub_t *sub = &_bc_radio.subs[order];
441 
442  if (sub->callback != NULL)
443  {
444  uint8_t *payload = NULL;
445 
446  if (queue_item_length > 1 + BC_RADIO_ID_SIZE + 1)
447  {
448  payload = queue_item_buffer + BC_RADIO_HEAD_SIZE + 1 + BC_RADIO_ID_SIZE + 1;
449  }
450 
451  sub->callback(&id, sub->topic, payload, sub->param);
452  }
453  }
454  else if (queue_item_buffer[BC_RADIO_HEAD_SIZE] == BC_RADIO_HEADER_PUB_INFO)
455  {
456  queue_item_buffer[queue_item_length + BC_RADIO_HEAD_SIZE - 1] = 0;
457 
458  bc_radio_on_info(&id, (char *) queue_item_buffer + BC_RADIO_HEAD_SIZE + 1, "", BC_RADIO_MODE_UNKNOWN);
459  }
460  else if (queue_item_buffer[BC_RADIO_HEAD_SIZE] == BC_RADIO_HEADER_SUB_REG)
461  {
462  uint8_t *order = queue_item_buffer + BC_RADIO_HEAD_SIZE + 1;
463 
464  bc_radio_sub_pt_t *pt = (bc_radio_sub_pt_t *) queue_item_buffer + BC_RADIO_HEAD_SIZE + 2;
465 
466  char *topic = (char *) queue_item_buffer + BC_RADIO_HEAD_SIZE + 3;
467 
468  bc_radio_on_sub(&id, order, pt, topic);
469  }
470  }
471 
472  if (bc_queue_get(&_bc_radio.pub_queue, queue_item_buffer, &queue_item_length))
473  {
474  uint8_t *buffer = bc_spirit1_get_tx_buffer();
475 
476  bc_radio_id_to_buffer(&_bc_radio.my_id, buffer);
477 
478  _bc_radio.message_id++;
479 
480  buffer[6] = _bc_radio.message_id;
481  buffer[7] = _bc_radio.message_id >> 8;
482 
483  memcpy(buffer + 8, queue_item_buffer, queue_item_length);
484 
485  bc_spirit1_set_tx_length(8 + queue_item_length);
486 
487  bc_spirit1_tx();
488 
489  _bc_radio.transmit_count = _BC_RADIO_TX_MAX_COUNT;
490 
491  _bc_radio.state = BC_RADIO_STATE_TX;
492  }
493 }
494 
495 static bool _bc_radio_scan_cache_push(void)
496 {
497  for (uint8_t i = 0; i < _bc_radio.scan_length; i++)
498  {
499  if (_bc_radio.scan_cache[i] == _bc_radio.peer_id)
500  {
501  return false;
502  }
503  }
504 
505  if (_bc_radio.scan_length < _BC_RADIO_SCAN_CACHE_LENGTH)
506  {
507  _bc_radio.scan_length++;
508  }
509 
510  _bc_radio.scan_cache[_bc_radio.scan_head++] = _bc_radio.peer_id;
511 
512  if (_bc_radio.scan_head == _BC_RADIO_SCAN_CACHE_LENGTH)
513  {
514  _bc_radio.scan_head = 0;
515  }
516 
517  return true;
518 }
519 
520 static void _bc_radio_send_ack(void)
521 {
522  uint8_t *tx_buffer = bc_spirit1_get_tx_buffer();
523 
524  if (_bc_radio.state == BC_RADIO_STATE_TX_WAIT_ACK)
525  {
526  _bc_radio.ack_transmit_count = _bc_radio.transmit_count;
527 
528  _bc_radio.ack_tx_cache_length = bc_spirit1_get_tx_length();
529 
530  memcpy(_bc_radio.ack_tx_cache_buffer, tx_buffer, sizeof(_bc_radio.ack_tx_cache_buffer));
531 
532  _bc_radio.state = BC_RADIO_STATE_TX_SEND_ACK;
533  }
534  else if (_bc_radio.state == BC_RADIO_STATE_RX)
535  {
536  _bc_radio.state = BC_RADIO_STATE_RX_SEND_ACK;
537  }
538  else
539  {
540  return;
541  }
542 
543  uint8_t *rx_buffer = bc_spirit1_get_rx_buffer();
544 
545  memcpy(tx_buffer, rx_buffer, 8);
546 
547  tx_buffer[8] = BC_RADIO_HEADER_ACK;
548 
550 
551  _bc_radio.transmit_count = 2;
552 
553  bc_spirit1_tx();
554 }
555 
556 static void _bc_radio_go_to_state_rx_or_sleep(void)
557 {
558  if (_bc_radio.mode == BC_RADIO_MODE_NODE_SLEEPING)
559  {
560  bc_tick_t now = bc_tick_get();
561 
562  if (_bc_radio.rx_timeout_sleeping > now)
563  {
564  _bc_radio.rx_timeout = _bc_radio.rx_timeout_sleeping;
565 
566  bc_spirit1_set_rx_timeout(_bc_radio.rx_timeout - now);
567 
568  bc_spirit1_rx();
569 
570  _bc_radio.state = BC_RADIO_STATE_RX;
571  }
572  else
573  {
575 
576  _bc_radio.state = BC_RADIO_STATE_SLEEP;
577  }
578  }
579  else
580  {
581  _bc_radio.rx_timeout = BC_TICK_INFINITY;
582 
584 
585  bc_spirit1_rx();
586 
587  _bc_radio.state = BC_RADIO_STATE_RX;
588  }
589 
590  bc_scheduler_plan_now(_bc_radio.task_id);
591 }
592 
593 static void _bc_radio_spirit1_event_handler(bc_spirit1_event_t event, void *event_param)
594 {
595  (void) event_param;
596 
597  if (event == BC_SPIRIT1_EVENT_TX_DONE)
598  {
599  if (_bc_radio.transmit_count > 0)
600  {
601  _bc_radio.transmit_count--;
602  }
603 
604  if (_bc_radio.state == BC_RADIO_STATE_TX)
605  {
606  bc_tick_t timeout = _BC_RADIO_ACK_TIMEOUT - 50 + rand() % _BC_RADIO_ACK_TIMEOUT;
607 
608  _bc_radio.rx_timeout = bc_tick_get() + timeout;
609 
610  bc_spirit1_set_rx_timeout(timeout);
611 
612  bc_spirit1_rx();
613 
614  _bc_radio.state = BC_RADIO_STATE_TX_WAIT_ACK;
615 
616  _bc_radio.ack = false;
617 
618  return;
619  }
620 
621  if (_bc_radio.state == BC_RADIO_STATE_RX_SEND_ACK)
622  {
623  if (_bc_radio.transmit_count > 0)
624  {
625  bc_spirit1_tx();
626 
627  return;
628  }
629  }
630 
631  if (_bc_radio.state == BC_RADIO_STATE_TX_SEND_ACK)
632  {
633  if (_bc_radio.transmit_count > 0)
634  {
635  bc_spirit1_tx();
636 
637  return;
638  }
639  else
640  {
641  uint8_t *tx_buffer = bc_spirit1_get_tx_buffer();
642 
643  memcpy(tx_buffer, _bc_radio.ack_tx_cache_buffer, sizeof(_bc_radio.ack_tx_cache_buffer));
644 
645  bc_tick_t timeout = _BC_RADIO_ACK_TIMEOUT - 50 + rand() % _BC_RADIO_ACK_TIMEOUT;
646 
647  _bc_radio.rx_timeout = bc_tick_get() + timeout;
648 
649  _bc_radio.transmit_count = _bc_radio.ack_transmit_count;
650 
651  bc_spirit1_set_rx_timeout(timeout);
652 
653  bc_spirit1_set_tx_length(_bc_radio.ack_tx_cache_length);
654 
655  bc_spirit1_rx();
656 
657  _bc_radio.state = BC_RADIO_STATE_TX_WAIT_ACK;
658 
659  return;
660  }
661  }
662 
663  _bc_radio_go_to_state_rx_or_sleep();
664  }
665  else if (event == BC_SPIRIT1_EVENT_RX_TIMEOUT)
666  {
667  if (_bc_radio.state == BC_RADIO_STATE_TX_WAIT_ACK)
668  {
669  if (_bc_radio.transmit_count > 0)
670  {
671  bc_spirit1_tx();
672 
673  _bc_radio.state = BC_RADIO_STATE_TX;
674 
675  return;
676  }
677  else
678  {
679  if (_bc_radio.event_handler)
680  {
681  _bc_radio.event_handler(BC_RADIO_EVENT_TX_ERROR, _bc_radio.event_param);
682  }
683  }
684 
685  }
686 
687  _bc_radio_go_to_state_rx_or_sleep();
688  }
689  else if (event == BC_SPIRIT1_EVENT_RX_DONE)
690  {
691  size_t length = bc_spirit1_get_rx_length();
692  uint16_t message_id;
693 
694  if ((_bc_radio.rx_timeout != BC_TICK_INFINITY) && (bc_tick_get() >= _bc_radio.rx_timeout))
695  {
696  if (_bc_radio.state == BC_RADIO_STATE_TX_WAIT_ACK)
697  {
698  if (_bc_radio.transmit_count > 0)
699  {
700  bc_spirit1_tx();
701 
702  _bc_radio.state = BC_RADIO_STATE_TX;
703 
704  return;
705  }
706  }
707 
708  _bc_radio_go_to_state_rx_or_sleep();
709  }
710 
711  if (length >= 9)
712  {
713  uint8_t *buffer = bc_spirit1_get_rx_buffer();
714  bc_radio_peer_t *peer;
715 
716  bc_radio_id_from_buffer(buffer, &_bc_radio.peer_id);
717 
718  message_id = (uint16_t) buffer[6];
719  message_id |= (uint16_t) buffer[7] << 8;
720 
721  // ACK check
722  if (buffer[8] == BC_RADIO_HEADER_ACK)
723  {
724  if (_bc_radio.state == BC_RADIO_STATE_TX_WAIT_ACK)
725  {
726  uint8_t *tx_buffer = bc_spirit1_get_tx_buffer();
727 
728  if ((_bc_radio.peer_id == _bc_radio.my_id) && (_bc_radio.message_id == message_id) )
729  {
730  _bc_radio.transmit_count = 0;
731 
732  _bc_radio.ack = true;
733 
734  if (tx_buffer[8] == BC_RADIO_HEADER_PAIRING)
735  {
736  if (length == 15)
737  {
738  bc_radio_id_from_buffer(buffer + 9, &_bc_radio.peer_id);
739 
740  if ((_bc_radio.mode != BC_RADIO_MODE_GATEWAY) && (_bc_radio.peer_devices[0].id != _bc_radio.peer_id))
741  {
742  _bc_radio.peer_devices[0].id = _bc_radio.peer_id;
743  _bc_radio.peer_devices[0].message_id_synced = false;
744  _bc_radio.peer_devices_length = 1;
745 
746  _bc_radio.save_peer_devices = true;
747  bc_scheduler_plan_now(_bc_radio.task_id);
748 
749  _bc_radio.sent_subs = 0;
750 
751  if (_bc_radio.event_handler)
752  {
753  _bc_radio.event_handler(BC_RADIO_EVENT_PAIRED, _bc_radio.event_param);
754  }
755  }
756  }
757  }
758  else if (tx_buffer[8] == BC_RADIO_HEADER_SUB_REG)
759  {
760  _bc_radio.sent_subs++;
761  }
762  else if ((length == 10) && (buffer[9] == _BC_RADIO_ACK_SUB_REQUEST))
763  {
764  _bc_radio.sent_subs = 0;
765  }
766 
767  if (_bc_radio.sleeping_mode_rx_timeout != 0)
768  {
769  _bc_radio.rx_timeout_sleeping = bc_tick_get() + _bc_radio.sleeping_mode_rx_timeout;
770  }
771 
772  _bc_radio_go_to_state_rx_or_sleep();
773 
774  if (_bc_radio.event_handler)
775  {
776  _bc_radio.event_handler(BC_RADIO_EVENT_TX_DONE, _bc_radio.event_param);
777  }
778  }
779 
780  }
781 
782  return;
783  }
784 
785  if (buffer[8] == BC_RADIO_HEADER_PAIRING)
786  {
787  if (_bc_radio.pairing_mode)
788  {
789  if (length >= 9)
790  {
791  bc_radio_peer_device_add(_bc_radio.peer_id);
792  }
793  }
794 
795  peer = bc_radio_get_peer_device(_bc_radio.peer_id);
796 
797  if (peer != NULL)
798  {
799  _bc_radio_send_ack();
800 
801  uint8_t *tx_buffer = bc_spirit1_get_tx_buffer();
802 
803  bc_radio_id_to_buffer(&_bc_radio.my_id, tx_buffer + 9);
804 
806 
807  if ((length > 10) && (peer->message_id != message_id))
808  {
809  if (10 + (size_t) buffer[9] + 1 < length)
810  {
811  buffer[10 + buffer[9]] = 0;
812 
813  peer->mode = buffer[length - 1];
814 
815  buffer[length - 1] = 0;
816 
817  bc_radio_on_info(&_bc_radio.peer_id, (char *)buffer + 10, (char *)buffer + 10 + buffer[9] + 1, peer->mode);
818  }
819  }
820 
821  peer->message_id = message_id;
822 
823  peer->message_id_synced = true;
824  }
825 
826  return;
827  }
828 
829  if ((length == 15) && ((buffer[8] == BC_RADIO_HEADER_NODE_ATTACH) || (buffer[8] == BC_RADIO_HEADER_NODE_DETACH)))
830  {
831  uint64_t id;
832 
833  bc_radio_id_from_buffer(buffer + 9, &id);
834 
835  if (id == _bc_radio.my_id)
836  {
837  if (buffer[8] == BC_RADIO_HEADER_NODE_ATTACH)
838  {
839  _bc_radio.pairing_request_to_gateway = true;
840 
841  bc_scheduler_plan_now(_bc_radio.task_id);
842  }
843  else if (buffer[8] == BC_RADIO_HEADER_NODE_DETACH)
844  {
845  _bc_radio_peer_device_remove(_bc_radio.peer_id);
846 
847  if (_bc_radio.event_handler)
848  {
849  _bc_radio.event_handler(BC_RADIO_EVENT_UNPAIRED, _bc_radio.event_param);
850  }
851  }
852  }
853 
854  _bc_radio_send_ack();
855 
856  return;
857  }
858 
859  peer = bc_radio_get_peer_device(_bc_radio.peer_id);
860 
861  if (peer != NULL)
862  {
863  if (peer->message_id != message_id)
864  {
865  bool send_subs_request = _bc_radio.mode == BC_RADIO_MODE_GATEWAY && (!peer->message_id_synced || (peer->message_id > message_id));
866 
867  peer->message_id = message_id;
868 
869  peer->message_id_synced = false;
870 
871  if (length > 9)
872  {
873  if ((buffer[8] >= 0x15) && (buffer[8] <= 0x1d) && (length > 14))
874  {
875  uint64_t for_id;
876 
877  bc_radio_id_from_buffer(buffer + 9, &for_id);
878 
879  if (for_id != _bc_radio.my_id)
880  {
881  return;
882  }
883  }
884 
885  bc_queue_put(&_bc_radio.rx_queue, buffer, length);
886 
887  bc_scheduler_plan_now(_bc_radio.task_id);
888 
889  peer->message_id_synced = true;
890 
891  peer->rssi = bc_spirit1_get_rx_rssi();
892  }
893 
894  if (peer->message_id_synced)
895  {
896  _bc_radio_send_ack();
897 
898  if (send_subs_request)
899  {
900  uint8_t *tx_buffer = bc_spirit1_get_tx_buffer();
901 
902  tx_buffer[9] = _BC_RADIO_ACK_SUB_REQUEST;
903 
905  }
906  }
907 
908  return;
909  }
910  }
911  else
912  {
913  if (_bc_radio.scan && (_bc_radio.event_handler != NULL) && _bc_radio_scan_cache_push())
914  {
915  _bc_radio.event_handler(BC_RADIO_EVENT_SCAN_FIND_DEVICE, _bc_radio.event_param);
916  }
917 
918  if (_bc_radio.automatic_pairing)
919  {
920  bc_radio_peer_device_add(_bc_radio.peer_id);
921  }
922  }
923  }
924  }
925 }
926 
927 static void _bc_radio_load_peer_devices(void)
928 {
929  uint32_t address = (uint32_t) bc_eeprom_get_size() - 8;
930  uint64_t buffer[3];
931  uint32_t *pointer = (uint32_t *)buffer;
932  uint8_t length = 0;
933 
934  bc_eeprom_read(bc_eeprom_get_size() - 1, &length, 1);
935 
936  _bc_radio.peer_devices_length = 0;
937 
938  for (int i = 0; (i < length) && (i < BC_RADIO_MAX_DEVICES); i++)
939  {
940  address -= sizeof(buffer);
941 
942  bc_eeprom_read(address, buffer, sizeof(buffer));
943 
944  pointer[2] = ~pointer[2];
945  pointer[5] = ~pointer[5];
946 
947  if ((buffer[0] != buffer[1]) && (buffer[0] != buffer[2]))
948  {
949  if (buffer[1] == buffer[2])
950  {
951  buffer[0] = buffer[1];
952 
953  _bc_radio.save_peer_devices = true;
954 
955  bc_scheduler_plan_now(_bc_radio.task_id);
956  }
957  else
958  {
959  continue;
960  }
961  }
962 
963  if (buffer[0] != 0)
964  {
965  _bc_radio.peer_devices[_bc_radio.peer_devices_length].id = buffer[0];
966  _bc_radio.peer_devices[_bc_radio.peer_devices_length].message_id_synced = false;
967  _bc_radio.peer_devices_length++;
968  }
969  }
970 }
971 
972 static void _bc_radio_save_peer_devices(void)
973 {
974  uint32_t address = (uint32_t) bc_eeprom_get_size() - 8;
975  uint64_t buffer_write[3];
976  uint32_t *pointer_write = (uint32_t *)buffer_write;
977  uint64_t buffer_read[3];
978 
979  _bc_radio.save_peer_devices = false;
980 
981  for (int i = 0; i < _bc_radio.peer_devices_length; i++)
982  {
983  buffer_write[0] = _bc_radio.peer_devices[i].id;
984  buffer_write[1] = _bc_radio.peer_devices[i].id;
985  buffer_write[2] = _bc_radio.peer_devices[i].id;
986 
987  pointer_write[2] = ~pointer_write[2];
988  pointer_write[5] = ~pointer_write[5];
989 
990  address -= sizeof(buffer_write);
991 
992  bc_eeprom_read(address, buffer_read, sizeof(buffer_read));
993 
994  if (memcmp(buffer_read, buffer_write, sizeof(buffer_write)) != 0)
995  {
996  if (!bc_eeprom_write(address, buffer_write, sizeof(buffer_write)))
997  {
998  _bc_radio.save_peer_devices = true;
999 
1000  bc_scheduler_plan_now(_bc_radio.task_id);
1001 
1002  return;
1003  }
1004  }
1005  }
1006 
1007  if (!bc_eeprom_write(bc_eeprom_get_size() - 1, &_bc_radio.peer_devices_length, 1))
1008  {
1009  _bc_radio.save_peer_devices = true;
1010 
1011  bc_scheduler_plan_now(_bc_radio.task_id);
1012 
1013  return;
1014  }
1015 }
1016 
1017 static void _bc_radio_atsha204_event_handler(bc_atsha204_t *self, bc_atsha204_event_t event, void *event_param)
1018 {
1019  (void) event_param;
1020 
1021  if (event == BC_ATSHA204_EVENT_SERIAL_NUMBER)
1022  {
1023  if (bc_atsha204_get_serial_number(self, &_bc_radio.my_id, sizeof(_bc_radio.my_id)))
1024  {
1025  if (_bc_radio.event_handler != NULL)
1026  {
1027  _bc_radio.event_handler(BC_RADIO_EVENT_INIT_DONE, _bc_radio.event_param);
1028  }
1029  }
1030  else
1031  {
1032  if (_bc_radio.event_handler != NULL)
1033  {
1034  _bc_radio.event_handler(BC_RADIO_EVENT_INIT_FAILURE, _bc_radio.event_param);
1035  }
1036  }
1037  }
1038  else if (event == BC_ATSHA204_EVENT_ERROR)
1039  {
1040  if (_bc_radio.event_handler != NULL)
1041  {
1042  _bc_radio.event_handler(BC_RADIO_EVENT_INIT_FAILURE, _bc_radio.event_param);
1043  }
1044  }
1045 }
1046 
1047 static bool _bc_radio_peer_device_add(uint64_t id)
1048 {
1049  if (_bc_radio.peer_devices_length + 1 == BC_RADIO_MAX_DEVICES)
1050  {
1051  if (_bc_radio.event_handler != NULL)
1052  {
1053  _bc_radio.peer_id = id;
1054  _bc_radio.event_handler(BC_RADIO_EVENT_ATTACH_FAILURE, _bc_radio.event_param);
1055  }
1056  return false;
1057  }
1058 
1059  if (bc_radio_is_peer_device(id))
1060  {
1061  return false;
1062  }
1063 
1064  _bc_radio.peer_devices[_bc_radio.peer_devices_length].id = id;
1065  _bc_radio.peer_devices[_bc_radio.peer_devices_length].message_id_synced = false;
1066  _bc_radio.peer_devices_length++;
1067 
1068  _bc_radio.save_peer_devices = true;
1069  bc_scheduler_plan_now(_bc_radio.task_id);
1070 
1071  if (_bc_radio.event_handler != NULL)
1072  {
1073  _bc_radio.peer_id = id;
1074  _bc_radio.event_handler(BC_RADIO_EVENT_ATTACH, _bc_radio.event_param);
1075  }
1076 
1077  return true;
1078 }
1079 
1080 static bool _bc_radio_peer_device_remove(uint64_t id)
1081 {
1082  for (int i = 0; i < _bc_radio.peer_devices_length; i++)
1083  {
1084  if (id == _bc_radio.peer_devices[i].id)
1085  {
1086  _bc_radio.peer_devices_length--;
1087 
1088  if (i != _bc_radio.peer_devices_length)
1089  {
1090  memcpy(_bc_radio.peer_devices + i, _bc_radio.peer_devices + _bc_radio.peer_devices_length, sizeof(bc_radio_peer_t));
1091  }
1092 
1093  _bc_radio.save_peer_devices = true;
1094  bc_scheduler_plan_now(_bc_radio.task_id);
1095 
1096  if (_bc_radio.event_handler != NULL)
1097  {
1098  _bc_radio.peer_id = id;
1099  _bc_radio.event_handler(BC_RADIO_EVENT_DETACH, _bc_radio.event_param);
1100  }
1101 
1102  return true;
1103  }
1104  }
1105 
1106  return false;
1107 }
1108 
1109 bc_radio_peer_t *bc_radio_get_peer_device(uint64_t id)
1110 {
1111  for (int i = 0; i < _bc_radio.peer_devices_length; i++)
1112  {
1113  if (id == _bc_radio.peer_devices[i].id)
1114  {
1115  return &_bc_radio.peer_devices[i];
1116  }
1117  }
1118 
1119  return NULL;
1120 }
1121 
1122 uint8_t *bc_radio_id_to_buffer(uint64_t *id, uint8_t *buffer)
1123 {
1124  buffer[0] = *id;
1125  buffer[1] = *id >> 8;
1126  buffer[2] = *id >> 16;
1127  buffer[3] = *id >> 24;
1128  buffer[4] = *id >> 32;
1129  buffer[5] = *id >> 40;
1130 
1131  return buffer + BC_RADIO_ID_SIZE;
1132 }
1133 
1134 uint8_t *bc_radio_bool_to_buffer(bool *value, uint8_t *buffer)
1135 {
1136  *buffer = value == NULL ? BC_RADIO_NULL_BOOL : *value;
1137 
1138  return buffer + 1;
1139 }
1140 
1141 uint8_t *bc_radio_int_to_buffer(int *value, uint8_t *buffer)
1142 {
1143  if (value == NULL)
1144  {
1145  const int null = BC_RADIO_NULL_INT;
1146 
1147  memcpy(buffer, &null, sizeof(int));
1148  }
1149  else
1150  {
1151  memcpy(buffer, value, sizeof(int));
1152  }
1153 
1154  return buffer + sizeof(int);
1155 }
1156 
1157 uint8_t *bc_radio_uint16_to_buffer(uint16_t *value, uint8_t *buffer)
1158 {
1159  if (value == NULL)
1160  {
1161  const int null = BC_RADIO_NULL_UINT16;
1162 
1163  memcpy(buffer, &null, sizeof(uint16_t));
1164  }
1165  else
1166  {
1167  memcpy(buffer, value, sizeof(uint16_t));
1168  }
1169 
1170  return buffer + sizeof(uint32_t);
1171 }
1172 
1173 uint8_t *bc_radio_uint32_to_buffer(uint32_t *value, uint8_t *buffer)
1174 {
1175  if (value == NULL)
1176  {
1177  const int null = BC_RADIO_NULL_UINT32;
1178 
1179  memcpy(buffer, &null, sizeof(uint32_t));
1180  }
1181  else
1182  {
1183  memcpy(buffer, value, sizeof(uint32_t));
1184  }
1185 
1186  return buffer + sizeof(uint32_t);
1187 }
1188 
1189 uint8_t *bc_radio_float_to_buffer(float *value, uint8_t *buffer)
1190 {
1191  if (value == NULL)
1192  {
1193  const float null = BC_RADIO_NULL_FLOAT;
1194 
1195  memcpy(buffer, &null, sizeof(float));
1196  }
1197  else
1198  {
1199  memcpy(buffer, value, sizeof(float));
1200  }
1201 
1202  return buffer + sizeof(float);
1203 }
1204 
1205 uint8_t *bc_radio_data_to_buffer(void *data, size_t length, uint8_t *buffer)
1206 {
1207  if (data == NULL)
1208  {
1209  return buffer + length;
1210  }
1211 
1212  memcpy(buffer, data, length);
1213 
1214  return buffer + length;
1215 }
1216 
1217 uint8_t *bc_radio_id_from_buffer(uint8_t *buffer, uint64_t *id)
1218 {
1219  *id = (uint64_t) buffer[0];
1220  *id |= (uint64_t) buffer[1] << 8;
1221  *id |= (uint64_t) buffer[2] << 16;
1222  *id |= (uint64_t) buffer[3] << 24;
1223  *id |= (uint64_t) buffer[4] << 32;
1224  *id |= (uint64_t) buffer[5] << 40;
1225 
1226  return buffer + BC_RADIO_ID_SIZE;
1227 }
1228 
1229 uint8_t *bc_radio_bool_from_buffer(uint8_t *buffer, bool *value, bool **pointer)
1230 {
1231  if (*buffer == BC_RADIO_NULL_BOOL)
1232  {
1233  *pointer = NULL;
1234  }
1235  else
1236  {
1237  *value = *(bool *) buffer;
1238  *pointer = value;
1239  }
1240 
1241  return buffer + 1;
1242 }
1243 
1244 uint8_t *bc_radio_int_from_buffer(uint8_t *buffer, int *value, int **pointer)
1245 {
1246  memcpy(value, buffer, sizeof(int));
1247 
1248  if (*value == BC_RADIO_NULL_INT)
1249  {
1250  *pointer = NULL;
1251  }
1252  else
1253  {
1254  *pointer = value;
1255  }
1256 
1257  return buffer + sizeof(int);
1258 }
1259 
1260 uint8_t *bc_radio_uint16_from_buffer(uint8_t *buffer, uint16_t *value, uint16_t **pointer)
1261 {
1262  memcpy(value, buffer, sizeof(uint16_t));
1263 
1264  if (*value == BC_RADIO_NULL_UINT16)
1265  {
1266  *pointer = NULL;
1267  }
1268  else
1269  {
1270  *pointer = value;
1271  }
1272 
1273  return buffer + sizeof(uint16_t);
1274 }
1275 
1276 uint8_t *bc_radio_uint32_from_buffer(uint8_t *buffer, uint32_t *value, uint32_t **pointer)
1277 {
1278  memcpy(value, buffer, sizeof(uint32_t));
1279 
1280  if (*value == BC_RADIO_NULL_UINT32)
1281  {
1282  *pointer = NULL;
1283  }
1284  else
1285  {
1286  *pointer = value;
1287  }
1288 
1289  return buffer + sizeof(uint32_t);
1290 }
1291 
1292 uint8_t *bc_radio_float_from_buffer(uint8_t *buffer, float *value, float **pointer)
1293 {
1294  memcpy(value, buffer, sizeof(float));
1295 
1296  if (isnan(*value))
1297  {
1298  *pointer = NULL;
1299  }
1300  else
1301  {
1302  *pointer = value;
1303  }
1304 
1305  return buffer + sizeof(float);
1306 }
1307 
1308 uint8_t *bc_radio_data_from_buffer(uint8_t *buffer, void *data, size_t length)
1309 {
1310  if (data == NULL)
1311  {
1312  return buffer + length;
1313  }
1314 
1315  memcpy(data, buffer, length);
1316 
1317  return buffer + length;
1318 }
1319 
1320 typedef struct
1321 {
1322  bc_led_t *led;
1323  const char *firmware;
1324  const char *version;
1325 
1327 
1328 void _bc_radio_button_event_handler(bc_button_t *self, bc_button_event_t event, void *event_param)
1329 {
1330  (void) self;
1332 
1333  if (event == BC_BUTTON_EVENT_PRESS)
1334  {
1335  if (param->led != NULL)
1336  {
1337  bc_led_pulse(param->led, 100);
1338  }
1339 
1340  static uint16_t event_count = 0;
1341 
1342  bc_radio_pub_push_button(&event_count);
1343 
1344  event_count++;
1345  }
1346  else if (event == BC_BUTTON_EVENT_HOLD)
1347  {
1348  bc_radio_pairing_request(param->firmware, param->version);
1349 
1350  if (param->led != NULL)
1351  {
1352  bc_led_set_mode(param->led, BC_LED_MODE_OFF);
1353  bc_led_pulse(param->led, 1000);
1354  }
1355  }
1356 }
1357 
1358 void bc_radio_init_pairing_button(const char *firmware, const char *version)
1359 {
1360  static bc_led_t led;
1361  static bc_button_t button;
1362  static _bc_radio_button_event_param_t param;
1363  param.led = &led;
1364  param.firmware = firmware;
1365  param.version = version;
1366 
1368  // Pass led instance as a callback parameter, so we don't need to add it to the radio structure
1369  bc_button_set_event_handler(&button, _bc_radio_button_event_handler, &param);
1370 
1371  bc_led_init(&led, BC_GPIO_LED, false, 0);
1372 
1373 }
void * bc_spirit1_get_tx_buffer(void)
Get TX buffer.
Definition: bc_spirit1.c:176
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
bool bc_atsha204_read_serial_number(bc_atsha204_t *self)
Reqeust for serial number.
Definition: bc_atsha204.c:40
bool bc_spirit1_init(void)
Initialize.
Definition: bc_spirit1.c:98
void bc_spirit1_tx(void)
Enter TX state.
Definition: bc_spirit1.c:228
GPIO channel LED.
Definition: bc_gpio.h:69
void bc_spirit1_rx(void)
Enter RX state.
Definition: bc_spirit1.c:238
size_t bc_spirit1_get_tx_length(void)
Get TX buffer length.
Definition: bc_spirit1.c:186
I2C channel I2C0.
Definition: bc_i2c.h:18
LED has steady off state.
Definition: bc_led.h:31
Unknown mode.
Definition: bc_radio.h:40
bc_atsha204_event_t
Definition: bc_atsha204.h:14
Event button pressed.
Definition: bc_button.h:17
bool bc_radio_pub_push_button(uint16_t *event_count)
Publish push button event count, same as use bc_radio_pub_event_count with BC_RADIO_PUB_EVENT_PUSH_BU...
Definition: bc_radio_pub.c:36
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_radio_init(bc_radio_mode_t mode)
Initialize radio.
Definition: bc_radio.c:89
struct bc_led_t bc_led_t
LED instance.
Definition: bc_led.h:52
void bc_spirit1_sleep(void)
Enter sleep state.
Definition: bc_spirit1.c:248
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
void bc_spirit1_set_event_handler(void(*event_handler)(bc_spirit1_event_t, void *), void *event_param)
Set callback function.
Definition: bc_spirit1.c:170
void bc_led_set_mode(bc_led_t *self, bc_led_mode_t mode)
Set LED mode.
Definition: bc_led.c:125
bc_radio_mode_t
Radio mode.
Definition: bc_radio.h:37
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
bool bc_eeprom_write(uint32_t address, const void *buffer, size_t length)
Write buffer to EEPROM area and verify it.
Definition: bc_eeprom.c:31
Event serial number is available.
Definition: bc_atsha204.h:23
bc_button_event_t
Callback events.
Definition: bc_button.h:14
void bc_radio_pub_decode(uint64_t *id, uint8_t *buffer, size_t length)
Internal decode function for bc_radio.c.
Definition: bc_radio_pub.c:267
GPIO channel BUTTON.
Definition: bc_gpio.h:72
bool bc_queue_get(bc_queue_t *queue, void *buffer, size_t *length)
Get queue to buffer.
Definition: bc_queue.c:45
Event button hold (pressed for longer time)
Definition: bc_button.h:26
void bc_radio_node_decode(uint64_t *id, uint8_t *buffer, size_t length)
Internal decode function for bc_radio.c.
struct bc_atsha204_t bc_atsha204_t
ATSHA204 instance.
Definition: bc_atsha204.h:29
void bc_led_init(bc_led_t *self, bc_gpio_channel_t gpio_channel, bool open_drain_output, int idle_state)
Initialize LED.
Definition: bc_led.c:75
Gateway mode.
Definition: bc_radio.h:43
void bc_queue_init(bc_queue_t *queue, void *buffer, size_t size)
Initialize queue.
Definition: bc_queue.c:3
bool bc_eeprom_read(uint32_t address, void *buffer, size_t length)
Read buffer from EEPROM area.
Definition: bc_eeprom.c:113
Event is RX timeout.
Definition: bc_spirit1.h:27
size_t bc_spirit1_get_rx_length(void)
Get RX buffer length.
Definition: bc_spirit1.c:196
GPIO channel has pull-down.
Definition: bc_gpio.h:90
bool bc_atsha204_get_serial_number(bc_atsha204_t *self, void *destination, size_t size)
Get serial number.
Definition: bc_atsha204.c:59
size_t bc_eeprom_get_size(void)
Return size of EEPROM area.
Definition: bc_eeprom.c:132
void bc_atsha204_set_event_handler(bc_atsha204_t *self, void(*event_handler)(bc_atsha204_t *, bc_atsha204_event_t, void *), void *event_param)
Set callback function.
Definition: bc_atsha204.c:29
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
Event is RX done.
Definition: bc_spirit1.h:24
bool bc_queue_put(bc_queue_t *queue, const void *buffer, size_t length)
Put buffer to queue.
Definition: bc_queue.c:11
void bc_button_set_event_handler(bc_button_t *self, void(*event_handler)(bc_button_t *, bc_button_event_t, void *), void *event_param)
Set callback function.
Definition: bc_button.c:66
void bc_spirit1_set_rx_timeout(bc_tick_t timeout)
Set TX timeout.
Definition: bc_spirit1.c:206
void * bc_spirit1_get_rx_buffer(void)
Get RX buffer.
Definition: bc_spirit1.c:191
Event is TX done.
Definition: bc_spirit1.h:21
void bc_led_pulse(bc_led_t *self, bc_tick_t duration)
Turn on LED for the specified duration of time.
Definition: bc_led.c:239
struct bc_button_t bc_button_t
Button instance.
Definition: bc_button.h:32
bc_radio_sub_pt_t
Subscribe payload type.
Definition: bc_radio.h:111
void bc_atsha204_init(bc_atsha204_t *self, bc_i2c_channel_t i2c_channel, uint8_t i2c_address)
Initialize ATSHA204 driver.
Definition: bc_atsha204.c:15
void bc_spirit1_set_tx_length(size_t length)
Set TX buffer length.
Definition: bc_spirit1.c:181
void bc_scheduler_plan_current_now(void)
Schedule current task for immediate execution.
Definition: bc_scheduler.c:139
void bc_button_init(bc_button_t *self, bc_gpio_channel_t gpio_channel, bc_gpio_pull_t gpio_pull, int idle_state)
Initialize button.
Definition: bc_button.c:20
Node sleeping mode, suitable for battery.
Definition: bc_radio.h:49
int bc_spirit1_get_rx_rssi(void)
Get RSSI.
Definition: bc_spirit1.c:201
bc_spirit1_event_t
Callback events.
Definition: bc_spirit1.h:18