BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
nrf52.hpp
Go to the documentation of this file.
1#ifndef BLUETOE_BINDINGS_NRF52_HPP
2#define BLUETOE_BINDINGS_NRF52_HPP
3
4#include <bluetoe/link_layer.hpp>
5#include <bluetoe/nrf.hpp>
7#include <bluetoe/ll_data_pdu_buffer.hpp>
8#include <bluetoe/security_tool_box.hpp>
9#include <bluetoe/connection_events.hpp>
10
44namespace bluetoe
45{
46 namespace nrf52_details
47 {
48 static constexpr std::uint8_t maximum_advertising_pdu_size = 0x3f;
49 // position of the connecting address (AdvA)
50 static constexpr unsigned connect_addr_offset = 2 + 6;
51
52 // after T_IFS (150µs +- 2) at maximum, a connection request will be received (34 Bytes + 1 Byte preable, 4 Bytes Access Address and 3 Bytes CRC)
53 // plus some additional 20µs
54 static constexpr std::uint32_t adv_reponse_timeout_us = 152 + 42 * 8 + 20;
55 static constexpr unsigned us_radio_rx_startup_time = 140;
56 static constexpr unsigned us_radio_tx_startup_time = 130;
57
58 // Time reserved to setup a connection event in µs
59 // time measured to setup a connection event, using GCC 8.3.1 with -O0 is 12µs
60 // the addition 31µs is to take the granularity of the sleep clock into account (32kHz)
61 // a second 31µs is add to take the same granularity of the sleep clock into account when
62 // it is used to calculate the current distance to the last anchor
63 static constexpr std::uint32_t setup_connection_event_limit_us =
64 50 + std::max( us_radio_rx_startup_time, us_radio_tx_startup_time ) + 31 + 31;
65
66 static constexpr std::uint8_t more_data_flag = 0x10;
67 static constexpr std::size_t encryption_mic_size = 4;
68
72 struct counter {
73 std::uint32_t low;
74 std::uint8_t high;
75
76 // set to zero
77 counter();
78
79 void increment();
80 void copy_to( std::uint8_t* target ) const;
81 };
82
88 class radio_hardware_without_crypto_support
89 {
90 public:
91 static int pdu_gap_required_by_encryption()
92 {
93 return 0;
94 }
95
96 static void init( void (*isr)( void* ), void* that );
97
101 static void configure_radio_channel(
102 unsigned channel );
103
107 static void configure_transmit_train(
108 const bluetoe::link_layer::write_buffer& transmit_data );
109
113 static void configure_final_transmit(
114 const bluetoe::link_layer::write_buffer& transmit_data );
115
120 static void configure_receive_train(
121 const bluetoe::link_layer::read_buffer& receive_buffer );
122
123 static void stop_radio();
124
128 static void store_timer_anchor( int offset_us );
129
138 static std::tuple< bool, bool, bool > received_pdu();
139
145 static std::uint32_t now();
146
151 static std::pair< bool, link_layer::delta_time > can_stop_connection_event_timer( std::uint32_t safety_margin_us );
152
153 static void setup_identity_resolving(
154 const std::uint8_t* )
155 {
156 }
157
158 static bool resolving_address_invalid()
159 {
160 return false;
161 }
162
163 static void set_phy(
164 bluetoe::link_layer::details::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,
165 bluetoe::link_layer::details::phy_ll_encoding::phy_ll_encoding_t transmiting_c_encoding );
166
172 static bool schedule_advertisment_event_timer(
174 std::uint32_t timeout_us,
175 std::uint32_t start_hfxo_offset );
176
177 static void schedule_connection_event_timer(
178 std::uint32_t begin_us,
179 std::uint32_t end_us,
180 std::uint32_t start_hfxo_offset );
181
182 static bool schedule_user_timer(
183 void (*isr)( void* ),
184 std::uint32_t time_us,
185 std::uint32_t max_cb_runtimer_ms );
186
187 static bool stop_user_timer();
191 static void stop_timeout_timer();
192
193 static std::uint32_t static_random_address_seed();
194
195 static void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init );
196
197 static void debug_toggle();
198
203 static bool user_timer_anchor_moved();
204
205 class lock_guard
206 {
207 public:
208 // see https://devzone.nordicsemi.com/question/47493/disable-interrupts-and-enable-interrupts-if-they-where-enabled/
209 lock_guard()
210 : context_( __get_PRIMASK() )
211 {
212 __disable_irq();
213 }
214
215 ~lock_guard()
216 {
217 __set_PRIMASK( context_ );
218 }
219
220 lock_guard( const lock_guard& ) = delete;
221 lock_guard& operator=( const lock_guard& ) = delete;
222 private:
223 const std::uint32_t context_;
224 };
225
226
227 protected:
228 static bool receive_2mbit_;
229 static bool transmit_2mbit_;
230
231 private:
232
233 // as the end of the PDU is captured and the start of the connection event
234 // then calculated based on the PDU size, HF frequency domain anchor can be negativ
235 volatile static int hf_connection_event_anchor_;
236 volatile static std::uint32_t lf_connection_event_anchor_;
237
238 // if between setting up a user timer and calling the corresponding callback,
239 // the anchor moved, inform the callback, so that the callback can schedule
240 // the next call to the new anchor
241 volatile static bool user_timer_anchor_moved_;
242 };
243
250 class radio_hardware_with_crypto_support : public radio_hardware_without_crypto_support
251 {
252 public:
253 static int pdu_gap_required_by_encryption()
254 {
255 return 1;
256 }
257
258 using radio_hardware_without_crypto_support::init;
259 static void init( std::uint8_t* encrypted_area, void (*isr)( void* ), void* that );
260
261 static void configure_transmit_train(
262 const bluetoe::link_layer::write_buffer& transmit_data );
263
264 static void configure_final_transmit(
265 const bluetoe::link_layer::write_buffer& transmit_data );
266
267 static void configure_receive_train(
268 const bluetoe::link_layer::read_buffer& receive_buffer );
269
270 static void store_timer_anchor( int offset_us );
271
272 static std::tuple< bool, bool, bool > received_pdu();
273
274 static void configure_encryption( bool receive, bool transmit );
275
276 static std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm );
277
278 static void increment_receive_packet_counter()
279 {
280 receive_counter_.increment();
281 }
282
283 static void increment_transmit_packet_counter()
284 {
285 transmit_counter_.increment();
286 }
287
288 /*
289 * @brief set the advertising address
290 */
291 static void setup_identity_resolving_address(
292 const std::uint8_t* address );
293
294 /*
295 * @brief enable identity resolving and the set the corresponding key
296 */
297 static void set_identity_resolving_key(
298 const details::identity_resolving_key_t& irk );
299
300 /*
301 * @brief returns true, if a request steams from an invalid address
302 */
303 static bool resolving_address_invalid();
304
305 private:
306 static volatile bool receive_encrypted_;
307 static volatile bool transmit_encrypted_;
308 static std::uint8_t* encrypted_area_;
309 static counter receive_counter_;
310 static counter transmit_counter_;
311 static bool identity_resolving_enabled_;
312 };
313
314 template < typename ... Options >
315 struct radio_options
316 {
317 using result = typename bluetoe::details::find_all_by_meta_type<
319 Options...
320 >::type;
321 };
322
323 template < typename ... Options >
324 struct link_layer_options
325 {
326 using result = typename bluetoe::details::find_all_by_not_meta_type<
327 bluetoe::details::binding_option_meta_type,
328 Options...
329 >::type;
330 };
331
332 template < class CallBacks, class Hardware, class Buffer, typename ... RadioOptions >
333 class nrf52_radio_base : public Buffer
334 {
335 public:
336 nrf52_radio_base()
337 {
338 low_frequency_clock_t::start_clocks();
339 Hardware::init( []( void* that ){
340 static_cast< nrf52_radio_base* >( that )->radio_interrupt_handler();
341 }, this);
342 }
343
344 nrf52_radio_base( std::uint8_t* receive_buffer )
345 {
346 low_frequency_clock_t::start_clocks();
347 Hardware::init( receive_buffer, []( void* that ){
348 static_cast< nrf52_radio_base* >( that )->radio_interrupt_handler();
349 }, this);
350 }
351
352 void schedule_advertisment(
353 unsigned channel,
354 const bluetoe::link_layer::write_buffer& advertising_data,
355 const bluetoe::link_layer::write_buffer& response_data,
357 const bluetoe::link_layer::read_buffer& receive )
358 {
359 assert( !adv_received_ );
360 assert( !adv_timeout_ );
361 assert( state_ == state::idle );
362 assert( receive.buffer && receive.size >= 2u );
363
364 bluetoe::link_layer::write_buffer advertising = advertising_data;
365 advertising.size = std::min< std::uint8_t >( advertising.size, maximum_advertising_pdu_size );
366
367 response_data_ = response_data;
368 receive_buffer_ = receive;
369 receive_buffer_.size = std::min< std::size_t >( receive.size, maximum_advertising_pdu_size );
370
371 Hardware::configure_radio_channel( channel );
372 Hardware::configure_transmit_train( advertising );
373
374 Hardware::setup_identity_resolving( receive_buffer_.buffer + connect_addr_offset );
375
376 // Advertising size + LL header + preable + access address + CRC
377 const std::uint32_t read_timeout = ( advertising.size + 2 + 1 + 4 + 3 ) * 8 + adv_reponse_timeout_us;
378
379 state_ = state::adv_transmitting;
380
381 if ( Hardware::schedule_advertisment_event_timer( when, read_timeout, hfxo_startup_value ) )
382 low_frequency_clock_t::stop_high_frequency_crystal_oscilator();
383 }
384
385 link_layer::delta_time schedule_connection_event(
386 unsigned channel,
389 bluetoe::link_layer::delta_time connection_interval )
390 {
391 assert( !end_evt_ );
392 assert( state_ == state::idle );
393 assert( start_receive < end_receive );
394
395 // in case of a call to nrf_flash_memory_access_end, evt_timeout_ will be set
396 // and needs to be consumed by the timeout handler
397 if ( evt_timeout_ )
398 return connection_interval;
399
400 // Stop all interrupts so that the calculation, that enough CPU time is available to setup everything, will not
401 // be disturbed by any interrupt.
402 lock_guard lock;
403
404 const std::uint32_t start_event = start_receive.usec();
405 // TODO: 500: must depend on receive size. This probably would depend on the maximum
406 // LL PDU size that would be expected.
407 const std::uint32_t end_event = end_receive.usec() + 500;
408
409 const auto now = Hardware::now();
410 if ( now + start_event_safety_margin_us > start_event )
411 {
412 evt_timeout_ = true;
413 return connection_interval;
414 }
415
416 receive_buffer_ = receive_buffer();
417 state_ = state::evt_wait_connect;
418
419 Hardware::configure_radio_channel( channel );
420 Hardware::configure_receive_train( receive_buffer_ );
421
422 Hardware::schedule_connection_event_timer( start_event, end_event, hfxo_startup_value );
423 low_frequency_clock_t::stop_high_frequency_crystal_oscilator();
424
425 return link_layer::delta_time( connection_interval.usec() - now );
426 }
427
428 std::pair< bool, link_layer::delta_time > disarm_connection_event()
429 {
430 lock_guard lock;
431
432 const auto result = Hardware::can_stop_connection_event_timer( start_event_safety_margin_us );
433
434 if ( result.first )
435 {
436 Hardware::stop_radio();
437 state_ = state::idle;
438 }
439
440 return result;
441 }
442
443 bool schedule_synchronized_user_timer(
445 bluetoe::link_layer::delta_time max_cb_runtime )
446 {
447 return Hardware::schedule_user_timer( []( void* that ){
448 const auto this_ = static_cast< nrf52_radio_base* >( that );
449 const auto callbacks = static_cast< CallBacks* >( this_ );
450
451 callbacks->user_timer( Hardware::user_timer_anchor_moved() );
452
453 }, timer.usec(), max_cb_runtime.usec() );
454 }
455
456 bool cancel_synchronized_user_timer()
457 {
458 return Hardware::stop_user_timer();
459 }
460
461 void set_access_address_and_crc_init( std::uint32_t access_address, std::uint32_t crc_init )
462 {
463 Hardware::set_access_address_and_crc_init( access_address, crc_init );
464 }
465
466 void run()
467 {
468 static constexpr bool single_wfi = bluetoe::details::has_option<
469 nrf::leave_run_on_interrupt, RadioOptions... >::value;
470
471 while ( !single_wfi && !adv_received_ && !adv_timeout_ && !evt_timeout_ && !end_evt_ && wake_up_ == 0 )
472 __WFI();
473
474 // For every event, but the wakeup request, the radio should be in an idle state
475 // because it's up to the event handler to defined what should happen next
476 if ( adv_received_ )
477 {
478 assert( state_ == state::idle );
479 assert( reinterpret_cast< std::uint8_t* >( NRF_RADIO->PACKETPTR ) == receive_buffer_.buffer );
480
481 receive_buffer_.size = std::min< std::size_t >(
482 receive_buffer_.size,
483 ( receive_buffer_.buffer[ 1 ] & 0x3f ) + 2 + Hardware::pdu_gap_required_by_encryption()
484 );
485 adv_received_ = false;
486
487 static_cast< CallBacks* >( this )->adv_received( receive_buffer_ );
488 }
489
490 if ( adv_timeout_ )
491 {
492 assert( state_ == state::idle );
493 adv_timeout_ = false;
494 static_cast< CallBacks* >( this )->adv_timeout();
495 }
496
497 if ( evt_timeout_ )
498 {
499 assert( state_ == state::idle );
500 evt_timeout_ = false;
501 static_cast< CallBacks* >( this )->timeout();
502 }
503
504 if ( end_evt_ )
505 {
506 assert( state_ == state::idle );
507 end_evt_ = false;
508 static_cast< CallBacks* >( this )->end_event( events_ );
509
510 events_ = link_layer::connection_event_events();
511 }
512
513 if ( request_event_cancelation_ )
514 {
515 request_event_cancelation_ = false;
516 static_cast< CallBacks* >( this )->try_event_cancelation();
517 }
518
519 if ( wake_up_ )
520 {
521 --wake_up_;
522 }
523 }
524
525 void wake_up()
526 {
527 ++wake_up_;
528 }
529
530 void request_event_cancelation()
531 {
532 request_event_cancelation_ = true;
533 }
534
535
536 std::uint32_t static_random_address_seed() const
537 {
538 return Hardware::static_random_address_seed();
539 }
540
541 void nrf_flash_memory_access_begin()
542 {
543 lock_guard lock;
544
545 Hardware::stop_radio();
546 low_frequency_clock_t::stop_high_frequency_crystal_oscilator();
547 state_ = state::idle;
548 }
549
550 void nrf_flash_memory_access_end()
551 {
552 // radio should still be in idle state, otherwise there was some interaction with the
553 // radio that was not expected by this function.
554 assert( state_ == state::idle );
555 // this kicks the CPU out of the loop in run() and requests the link layer to setup the next connection event
556 // unless, there is already a pending call to the end_event() handler.
557 evt_timeout_ = !end_evt_;
558 }
559
560 void radio_set_phy(
561 bluetoe::link_layer::details::phy_ll_encoding::phy_ll_encoding_t receiving_encoding,
562 bluetoe::link_layer::details::phy_ll_encoding::phy_ll_encoding_t transmiting_c_encoding )
563 {
564 Hardware::set_phy( receiving_encoding, transmiting_c_encoding );
565 }
566
567 using lock_guard = typename Hardware::lock_guard;
568
569 // no native white list implementation atm
570 static constexpr std::size_t radio_maximum_white_list_entries = 0;
571
575 static constexpr bool hardware_supports_2mbit = true;
576
580 static constexpr bool hardware_supports_synchronized_user_timer = true;
581
582 static constexpr unsigned connection_event_setup_time_us = nrf52_radio_base::start_event_safety_margin_us;
583
584 private:
585 using low_frequency_clock_t = typename bluetoe::details::find_by_meta_type<
586 nrf::nrf_details::sleep_clock_source_meta_type,
587 RadioOptions...,
589
590 using hfxo_startup_time_t = typename bluetoe::details::find_by_meta_type<
591 nrf::nrf_details::hfxo_startup_time_meta_type,
592 RadioOptions...,
594
595 /*
596 * The startup time of the HFXO in LF clock periods
597 */
598 static constexpr std::uint32_t hfxo_startup_value =
599 ( hfxo_startup_time_t::value + 1000000 / nrf::lfxo_clk_freq ) * nrf::lfxo_clk_freq / 1000000;
600
601 /*
602 * The startup time rounded up to the next full period of the sleep clock
603 */
604 static constexpr std::uint32_t hfxo_startup_time = hfxo_startup_value * 1000000 / nrf::lfxo_clk_freq;
605
606 /*
607 * Margin required to safetely setup the connection event in µs.
608 */
609 static constexpr std::uint32_t start_event_safety_margin_us = setup_connection_event_limit_us + hfxo_startup_time;
610
611
612 link_layer::read_buffer receive_buffer()
613 {
614 link_layer::read_buffer result = this->allocate_receive_buffer();
615 if ( result.empty() )
616 result = link_layer::read_buffer{ &empty_receive_[ 0 ], sizeof( empty_receive_ ) };
617
618 return result;
619 }
620
621 void radio_interrupt_handler()
622 {
623 if ( state_ == state::adv_transmitting )
624 {
625 // The timeout timer was already set with the start of the advertising
626 // Configure Radio to receive and then switch to transmitting
627 Hardware::configure_receive_train( receive_buffer_ );
628 state_ = state::adv_receiving;
629 }
630 else if ( state_ == state::adv_receiving )
631 {
632 bool valid_anchor, valid_pdu, valid_crc;
633 std::tie( valid_anchor, valid_pdu, valid_crc ) = Hardware::received_pdu();
634
635 if ( valid_anchor && valid_pdu && valid_crc )
636 {
637 Hardware::stop_timeout_timer();
638
639 if ( is_valid_scan_request() )
640 {
641 Hardware::configure_final_transmit( response_data_ );
642 state_ = state::adv_transmitting_response;
643
644 return;
645 }
646
647 adv_received_ = true;
648
649 // In case of an connection request, the anchor is exactly the end
650 // of the request
651 Hardware::store_timer_anchor( 0 );
652 }
653 else
654 {
655 adv_timeout_ = true;
656 }
657
658 Hardware::stop_radio();
659
660 state_ = state::idle;
661 }
662 else if ( state_ == state::adv_transmitting_response )
663 {
664 Hardware::stop_radio();
665
666 state_ = state::idle;
667 adv_timeout_ = true;
668 }
669 else if ( state_ == state::evt_wait_connect )
670 {
671 bool valid_anchor, valid_pdu, valid_crc;
672 std::tie( valid_anchor, valid_pdu, valid_crc ) = Hardware::received_pdu();
673
674 if ( valid_anchor && ( valid_pdu || valid_crc ) )
675 {
676 // switch to transmission
677 const auto trans = ( receive_buffer_.buffer == &empty_receive_[ 0 ] || !valid_crc )
678 ? this->next_transmit()
679 : ( valid_pdu
680 ? this->received( receive_buffer_ )
681 : this->acknowledge( receive_buffer_ ) );
682
683 // TODO: Hack to disable the more data flag, because this radio implementation is currently
684 // not able to do this (but it should be possible with the given hardware).
685 // Issue: #75 More Data not working
686 const_cast< std::uint8_t* >( trans.buffer )[ 0 ] = trans.buffer[ 0 ] & ~more_data_flag;
687
688 if ( trans.buffer[ 1 ] != 0 )
689 events_.last_transmitted_not_empty = true;
690
691 Hardware::configure_final_transmit( trans );
692 state_ = state::evt_transmiting_closing;
693 }
694 else
695 {
696 Hardware::stop_radio();
697 events_.error_occured = true;
698 evt_timeout_ = true;
699 state_ = state::idle;
700 }
701 }
702 else if ( state_ == state::evt_transmiting_closing )
703 {
704 // TODO: Couldn't we just capture the time at the start of the PDU?
705 // the timer was captured with the end event; the anchor is the start of the receiving.
706 // Additional to the ll PDU length there are 1 byte preamble, 4 byte access address, 2 byte LL header and 3 byte crc.
707 // Issue: #76 Taking Anchor from End of PDU
708 static constexpr std::size_t ll_pdu_overhead = 1 + 4 + 2 + 3;
709 const int total_pdu_length = ( receive_buffer_.buffer[ 1 ] + ll_pdu_overhead ) * 8;
710
711 // TODO: Anchor must also be taken, if PDU has a CRC error
712 // Issue: #76 Taking Anchor from End of PDU
713 Hardware::store_timer_anchor( -total_pdu_length );
714
715 if ( receive_buffer_.buffer[ 1 ] != 0 )
716 events_.last_received_not_empty = true;
717
718 if ( receive_buffer_.buffer[ 0 ] & more_data_flag )
719 events_.last_received_had_more_data = true;
720
721 Hardware::stop_radio();
722 state_ = state::idle;
723 end_evt_ = true;
724 }
725 else
726 {
727 assert(!"Invalid state");
728 }
729 }
730
731 bool is_valid_scan_request() const
732 {
733 static constexpr std::uint8_t scan_request_size = 12;
734 static constexpr std::uint8_t scan_request_pdu_type = 0x03;
735 static constexpr std::uint8_t pdu_type_mask = 0x0F;
736 static constexpr int pdu_header_size = 2;
737 static constexpr int addr_size = 6;
738 static constexpr std::uint8_t tx_add_mask = 0x40;
739 static constexpr std::uint8_t rx_add_mask = 0x80;
740
741 // the advertising type does not expect a scan request
742 if ( !response_data_.buffer )
743 return false;
744
745 if ( Hardware::resolving_address_invalid() )
746 return true;
747
748 if ( receive_buffer_.buffer[ 1 ] != scan_request_size )
749 return false;
750
751 if ( ( receive_buffer_.buffer[ 0 ] & pdu_type_mask ) != scan_request_pdu_type )
752 return false;
753
754 const int pdu_gap = Hardware::pdu_gap_required_by_encryption();
755
756 if ( !std::equal( &receive_buffer_.buffer[ pdu_header_size + addr_size + pdu_gap ], &receive_buffer_.buffer[ pdu_header_size + 2 * addr_size + pdu_gap ],
757 &response_data_.buffer[ pdu_header_size + pdu_gap ] ) )
758 return false;
759
760 // in the scan request, the randomness is stored in RxAdd, in the scan response, it's stored in
761 // TxAdd.
762 const bool scanner_addres_is_random = response_data_.buffer[ 0 ] & tx_add_mask;
763 if ( !static_cast< bool >( receive_buffer_.buffer[ 0 ] & rx_add_mask ) == scanner_addres_is_random )
764 return false;
765
766 const link_layer::device_address scanner( &receive_buffer_.buffer[ pdu_header_size + pdu_gap ], scanner_addres_is_random );
767
768 return static_cast< const CallBacks* >( this )->is_scan_request_in_filter( scanner );
769 }
770
771 volatile bool adv_timeout_;
772 volatile bool adv_received_;
773 volatile bool evt_timeout_;
774 volatile bool end_evt_;
775 volatile bool request_event_cancelation_;
776 volatile int wake_up_;
777
778 enum class state {
779 idle,
780 // timeout while receiving, stopping the radio, waiting for the radio to become disabled
781 adv_transmitting,
782 adv_receiving,
783 adv_transmitting_response,
784 adv_shutting_down_radio,
785 // connection event
786 evt_wait_connect,
787 evt_transmiting_closing,
788 };
789
790 volatile state state_;
791
792 link_layer::read_buffer receive_buffer_;
793 link_layer::write_buffer response_data_;
794 std::uint8_t empty_receive_[ 3 ];
795 link_layer::connection_event_events events_;
796 };
797
798 template <
799 std::size_t TransmitSize,
800 std::size_t ReceiveSize,
801 bool EnabledEncryption,
802 class CallBacks,
803 class Hardware,
804 typename ... RadioOptions
805 >
806 class nrf52_radio;
807
808 template <
809 std::size_t TransmitSize,
810 std::size_t ReceiveSize,
811 class CallBacks,
812 class Hardware,
813 typename ... RadioOptions
814 >
815 class nrf52_radio< TransmitSize, ReceiveSize, false, CallBacks, Hardware, RadioOptions... > :
816 public nrf52_radio_base< CallBacks, Hardware, bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize, nrf52_radio< TransmitSize, ReceiveSize, false, CallBacks, Hardware, RadioOptions... > >,
817 RadioOptions... >
818 {
819 public:
820 static constexpr bool hardware_supports_encryption = false;
821
822 void increment_receive_packet_counter() {}
823 void increment_transmit_packet_counter() {}
824 };
825
826 template <
827 std::size_t TransmitSize,
828 std::size_t ReceiveSize,
829 class CallBacks,
830 class Hardware,
831 typename ... RadioOptions
832 >
833 class nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > :
834 public nrf52_radio_base<
835 CallBacks,
836 Hardware,
837 bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize,
838 nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > >,
839 RadioOptions... >,
840 public security_tool_box
841 {
842 public:
843 static constexpr bool hardware_supports_lesc_pairing = true;
844 static constexpr bool hardware_supports_legacy_pairing = true;
845 static constexpr bool hardware_supports_encryption = hardware_supports_lesc_pairing || hardware_supports_legacy_pairing;
846
847 using radio_base_t = nrf52_radio_base<
848 CallBacks,
849 Hardware,
850 bluetoe::link_layer::ll_data_pdu_buffer< TransmitSize, ReceiveSize,
851 nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > >,
852 RadioOptions... >;
853
854 nrf52_radio() : radio_base_t( encrypted_message_.data )
855 {
856 }
857
858 std::pair< std::uint64_t, std::uint32_t > setup_encryption( bluetoe::details::uint128_t key, std::uint64_t skdm, std::uint32_t ivm )
859 {
860 return Hardware::setup_encryption( key, skdm, ivm );
861 }
862
866 void start_receive_encrypted()
867 {
868 Hardware::configure_encryption( true, false );
869 }
870
874 void start_transmit_encrypted()
875 {
876 Hardware::configure_encryption( true, true );
877 }
878
882 void stop_receive_encrypted()
883 {
884 Hardware::configure_encryption( false, true );
885 }
886
890 void stop_transmit_encrypted()
891 {
892 Hardware::configure_encryption( false, false );
893 }
894
895 void increment_receive_packet_counter()
896 {
897 Hardware::increment_receive_packet_counter();
898 }
899
900 void increment_transmit_packet_counter()
901 {
902 Hardware::increment_transmit_packet_counter();
903 }
904
911 void set_identity_resolving_key( const details::identity_resolving_key_t& irk )
912 {
913 Hardware::set_identity_resolving_key( irk );
914 }
915
916 private:
917 // TODO should be calculated with more accuracy base on the configuration of:
918 // - l2cap MAX MTU
919 // - implementation of Data Length Update procedure
920 struct alignas( 4 ) encrypted_message_t {
921 std::uint8_t data[ 260 ];
922 } encrypted_message_;
923 };
924
925 template < typename Server, bool EnabledEncryption, typename RadioOptions, typename LinkLayerOptions >
926 struct link_layer_factory;
927
928 template < typename Server, bool EnabledEncryption, typename ... RadioOptions, typename ... LinkLayerOptions >
929 struct link_layer_factory< Server, EnabledEncryption, std::tuple< RadioOptions... >, std::tuple< LinkLayerOptions... > >
930 {
931 using radio_hardware_t = typename details::select_type<
932 EnabledEncryption,
933 radio_hardware_with_crypto_support,
934 radio_hardware_without_crypto_support >::type;
935
936 template <
937 std::size_t TransmitSize,
938 std::size_t ReceiveSize,
939 class CallBacks
940 >
941 using radio_t = nrf52_radio< TransmitSize, ReceiveSize, EnabledEncryption, CallBacks, radio_hardware_t, RadioOptions... >;
942
943 using link_layer = bluetoe::link_layer::link_layer< Server, radio_t, LinkLayerOptions... >;
944 };
945 }
946
947 namespace link_layer {
948
950 /*
951 * specialize pdu_layout_by_radio<> for the radio that supports encryption to change the PDU layout
952 * to have that extra byte between header and body
953 */
954 template <
955 std::size_t TransmitSize,
956 std::size_t ReceiveSize,
957 class CallBacks,
958 class Hardware,
959 typename ... RadioOptions
960 >
961 struct pdu_layout_by_radio<
962 nrf52_details::nrf52_radio< TransmitSize, ReceiveSize, true, CallBacks, Hardware, RadioOptions... > >
963 {
968 using pdu_layout = bluetoe::nrf_details::encrypted_pdu_layout;
969 };
971 }
972
982 template < class Server, typename ... Options >
983 using nrf52 = typename nrf52_details::link_layer_factory<
984 Server,
985 details::requires_encryption_support_t< Server >::value,
986 typename nrf52_details::radio_options< Options... >::result,
987 typename nrf52_details::link_layer_options< Options... >::result
988 >::link_layer;
989}
990
991#endif
typename nrf52_details::link_layer_factory< Server, details::requires_encryption_support_t< Server >::value, typename nrf52_details::radio_options< Options... >::result, typename nrf52_details::link_layer_options< Options... >::result >::link_layer nrf52
binding for nRF52 microcontrollers
Definition: nrf52.hpp:988
configure the low frequency clock to run from the RC oscilator.
Definition: nrf.hpp:163
configure the high frequency crystal oscillator startup time
Definition: nrf.hpp:203