BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
advertising.hpp
Go to the documentation of this file.
1#ifndef BLUETOE_LINK_LAYER_ADVERTISING_HPP
2#define BLUETOE_LINK_LAYER_ADVERTISING_HPP
3
5#include <bluetoe/default_pdu_layout.hpp>
6#include <bluetoe/address.hpp>
7#include <bluetoe/buffer.hpp>
8#include <bluetoe/delta_time.hpp>
9#include <bluetoe/ll_meta_types.hpp>
10
21namespace bluetoe {
22namespace link_layer {
23
24 namespace details {
25 struct advertising_type_meta_type {};
26 struct advertising_startup_meta_type {};
27 struct advertising_interval_meta_type {};
28 struct advertising_channel_map_meta_type {};
29
30 template < unsigned long long AdvertisingIntervalMilliSeconds >
31 struct check_advertising_interval_parameter {
32 static_assert( AdvertisingIntervalMilliSeconds >= 20, "the advertising interval must be greater than or equal to 20ms." );
33 static_assert( AdvertisingIntervalMilliSeconds <= 10240, "the advertising interval must be smaller than or equal to 10.24s." );
34
35 typedef void type;
36 };
37
38 struct advertising_type_base {
39 static constexpr std::uint8_t header_txaddr_field = 0x40;
40 static constexpr std::uint8_t header_rxaddr_field = 0x80;
41 static constexpr std::size_t advertising_pdu_header_size = 2;
42 static constexpr std::uint8_t adv_ind_pdu_type_code = 0;
43 static constexpr std::uint8_t adv_direct_ind_pdu_type_code= 1;
44 static constexpr std::uint8_t adv_nonconn_ind_pdu_type_code= 2;
45 static constexpr std::uint8_t adv_scan_ind_pdu_type_code = 6;
46 static constexpr std::uint8_t scan_response_pdu_type_code = 4;
47 static constexpr std::size_t address_length = 6;
48 static constexpr std::size_t maximum_adv_request_size = 34;
49
50 static constexpr std::size_t max_advertising_data_size = 31;
51 static constexpr std::size_t max_scan_response_data_size = 31;
52
53 static constexpr std::size_t max_advertising_pdu_size = max_advertising_data_size + address_length;
54 static constexpr std::size_t max_scan_response_pdu_size = max_scan_response_data_size + address_length;
55
56 template < typename Layout >
57 static bool is_valid_scan_request( const read_buffer& receive, const device_address& addr )
58 {
59 static constexpr std::size_t scan_request_size = 2 * address_length;
60 static constexpr std::uint8_t scan_request_code = 0x03;
61
62 const std::uint16_t header = Layout::header( receive );
63
64 bool result = receive.size == Layout::data_channel_pdu_memory_size( scan_request_size )
65 && ( ( header >> 8 ) & 0x3f ) == scan_request_size
66 && ( header & 0x0f ) == scan_request_code;
67
68 if ( result )
69 {
70 const auto body = Layout::body( receive );
71 result = result && std::equal( &body.begin[ address_length ], &body.begin[ 2 * address_length ], addr.begin() );
72 result = result && addr.is_random() == ( ( header & header_rxaddr_field ) != 0 );
73 }
74
75 return result;
76 }
77
78 template < typename Layout >
79 static bool is_valid_connect_request( const read_buffer& receive, const device_address& addr )
80 {
81 static constexpr std::size_t connect_request_size = 34;
82 static constexpr std::uint8_t connect_request_code = 0x05;
83
84 if ( receive.size != Layout::data_channel_pdu_memory_size( connect_request_size ) )
85 return false;
86
87 const std::uint16_t header = Layout::header( receive );
88 const auto body = Layout::body( receive ).first;
89
90 bool result = ( ( header >> 8 ) & 0x3f ) == connect_request_size
91 && ( header & 0x0f ) == connect_request_code;
92
93 result = result && std::equal( &body[ address_length ], &body[ 2 * address_length ], addr.begin() );
94 result = result && addr.is_random() == ( ( header & header_rxaddr_field ) != 0 );
95
96 return result;
97 }
98
99 template < typename Layout >
100 static std::size_t fill_empty_scan_response_data( const device_address& addr, read_buffer adv_response_buffer )
101 {
102 std::uint16_t header = scan_response_pdu_type_code;
103
104 if ( addr.is_random() )
105 header |= header_txaddr_field;
106
107 static constexpr std::size_t empty_ad_size = 2;
108 std::size_t adv_response_size = advertising_pdu_header_size + address_length + empty_ad_size;
109 header |= ( adv_response_size - advertising_pdu_header_size ) << 8;
110
111 const auto body = Layout::body( adv_response_buffer );
112
113 std::copy( addr.begin(), addr.end(), body.first );
114
115 // add aditional empty AD to be visible to Nordic sniffer.
116 // Some stacks do not recognize the response without this empty AD.
117 body.first[ adv_response_size - 2 ] = 0;
118 body.first[ adv_response_size - 1 ] = 0;
119
120 Layout::header( adv_response_buffer, header );
121
122 return adv_response_size;
123 }
124 };
125 }
126
127
147 {
148 public:
160 template < typename Type >
162
164 struct meta_type :
165 details::advertising_type_meta_type,
166 details::valid_link_layer_option_meta_type {};
167
168 template < typename LinkLayer, typename Advertiser >
169 class impl : protected details::advertising_type_base
170 {
171 protected:
172 read_buffer fill_advertising_data()
173 {
175 const device_address& addr = link_layer().local_address();
176
177 // prevent assert() in layout_t::body
178 adv_size_ = address_length;
179
180 const auto buffer = advertiser().advertising_buffer();
181 std::uint16_t header = adv_ind_pdu_type_code;
182 std::uint8_t* body = layout_t::body( buffer ).first;
183
184 if ( addr.is_random() )
185 header |= header_txaddr_field;
186
187 const std::size_t size =
188 address_length
189 + link_layer().fill_l2cap_advertising_data( &body[ address_length ], max_advertising_data_size );
190
191 header |= size << 8;
192 adv_size_ = layout_t::data_channel_pdu_memory_size( size );
193
194 std::copy( addr.begin(), addr.end(), body );
195 layout_t::header( buffer, header );
196
197 fill_scan_response_data();
198 return buffer;
199 }
200
201 read_buffer get_advertising_data()
202 {
203 return advertiser().advertising_buffer();
204 }
205
206 read_buffer get_scan_response_data()
207 {
208 return advertiser().scan_response_buffer();
209 }
210
211 bool is_valid_scan_request( const read_buffer& receive ) const
212 {
213 using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;
214 return details::advertising_type_base::is_valid_scan_request< layout_t >( receive, link_layer().local_address() );
215 }
216
217 bool is_valid_connect_request( const read_buffer& receive ) const
218 {
219 using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;
220 return details::advertising_type_base::is_valid_connect_request< layout_t >( receive, link_layer().local_address() );
221 }
222
223 private:
224
225 static constexpr std::size_t maximum_adv_send_size = max_advertising_data_size + address_length;
226
227 void fill_scan_response_data()
228 {
229 using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;
230 const device_address& addr = link_layer().local_address();
231
232 const auto buffer = advertiser().scan_response_buffer();
233
234 std::uint16_t header = scan_response_pdu_type_code;
235 std::uint8_t* body = layout_t::body( buffer ).first;
236
237 if ( addr.is_random() )
238 header |= header_txaddr_field;
239
240 const std::size_t size =
241 address_length
242 + link_layer().fill_l2cap_scan_response_data( &body[ address_length ], max_scan_response_data_size );
243
244 header |= size << 8;
245 adv_response_size_ = layout_t::data_channel_pdu_memory_size( size );
246
247 std::copy( addr.begin(), addr.end(), body );
248 layout_t::header( buffer, header );
249 }
250
251 LinkLayer& link_layer()
252 {
253 return static_cast< LinkLayer& >( *this );
254 }
255
256 const LinkLayer& link_layer() const
257 {
258 return static_cast< const LinkLayer& >( *this );
259 }
260
261 Advertiser& advertiser()
262 {
263 return static_cast< Advertiser& >( *this );
264 }
265
266 std::size_t adv_size_;
267 std::size_t adv_response_size_;
268
269 };
271 };
272
285 {
286 public:
298 template < typename Type >
300
308
310 struct meta_type :
311 details::advertising_type_meta_type,
312 details::valid_link_layer_option_meta_type {};
313
314 template < typename LinkLayer, typename Advertiser >
315 class impl : protected details::advertising_type_base
316 {
317 public:
318 void directed_advertising_address( const device_address& addr )
319 {
320 bool address_valid = addr != device_address();
321 bool start_advertising = !addr_valid_ && address_valid;
322
323 addr_ = addr;
324 addr_valid_ = address_valid;
325
326 if ( start_advertising && started_ )
327 advertiser().handle_start_advertising();
328 }
329
330 protected:
331 impl()
332 : addr_valid_( false )
333 , started_( false )
334 {
335 }
336
337 read_buffer fill_advertising_data()
338 {
339 if ( !addr_valid_ )
340 {
341 started_ = true;
342 return read_buffer{ nullptr, 0 };
343 }
344
345 const device_address& addr = link_layer().local_address();
346 using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;
347
348 const auto buffer = advertiser().advertising_buffer();
349
350 std::uint8_t* const adv_data = buffer.buffer;
351 std::uint16_t header = adv_direct_ind_pdu_type_code;
352
353 if ( addr.is_random() )
354 header |= header_txaddr_field;
355
356 if ( addr_.is_random() )
357 header |= header_rxaddr_field;
358
359 header |= ( 2 * address_length ) << 8;
360
361 layout_t::header( adv_data, header );
362
363 const auto body = layout_t::body( buffer );
364 std::copy( addr.begin(), addr.end(), &body.first[ 0 ] );
365 std::copy( addr_.begin(), addr_.end(), &body.first[ address_length ] );
366
367 return buffer;
368 }
369
370 read_buffer get_advertising_data()
371 {
372 return addr_valid_ ? advertiser().advertising_buffer() : read_buffer{ nullptr, 0 };
373 }
374
375 read_buffer get_scan_response_data() const
376 {
377 return read_buffer{ nullptr, 0 };
378 }
379
380 bool is_valid_scan_request( const read_buffer& ) const
381 {
382 return false;
383 }
384
385 bool is_valid_connect_request( const read_buffer& receive ) const
386 {
387 using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;
388
389 bool result = details::advertising_type_base::is_valid_connect_request< layout_t >( receive, link_layer().local_address() );
390 const auto body = layout_t::body( receive ).first;
391 const auto header = layout_t::header( receive );
392
393 result = result && std::equal( &body[ 0 ], &body[ address_length ], addr_.begin() ) && addr_valid_;
394 result = result && addr_.is_random() == ( ( header & header_txaddr_field ) != 0 );
395
396 return result;
397 }
398
399 private:
400
401 static constexpr std::size_t max_advertising_data_size = 2 * address_length;
402
403 LinkLayer& link_layer()
404 {
405 return static_cast< LinkLayer& >( *this );
406 }
407
408 const LinkLayer& link_layer() const
409 {
410 return static_cast< const LinkLayer& >( *this );
411 }
412
413 Advertiser& advertiser()
414 {
415 return static_cast< Advertiser& >( *this );
416 }
417
418 device_address addr_;
419 bool addr_valid_;
420 bool started_;
421 };
423 };
424
433 {
445 template < typename Type >
447
449 struct meta_type :
450 details::advertising_type_meta_type,
451 details::valid_link_layer_option_meta_type {};
452
453 template < typename LinkLayer, typename Advertiser >
454 class impl : protected details::advertising_type_base
455 {
456 protected:
457
458 read_buffer fill_advertising_data()
459 {
461
462 fill_scan_response_data();
463 const device_address& addr = link_layer().local_address();
464
465 const auto buffer = advertiser().advertising_buffer();
466
467 std::uint16_t header = adv_scan_ind_pdu_type_code;
468 std::uint8_t* body = layout_t::body( buffer ).first;
469
470 if ( addr.is_random() )
471 header |= header_txaddr_field;
472
473 const std::size_t size =
474 address_length
475 + link_layer().fill_l2cap_advertising_data( &body[ address_length ], max_advertising_data_size );
476
477 header |= size << 8;
478 adv_size_ = layout_t::data_channel_pdu_memory_size( size );
479
480 layout_t::header( buffer, header );
481 std::copy( addr.begin(), addr.end(), body );
482
483 return buffer;
484 }
485
486 read_buffer get_advertising_data()
487 {
488 return read_buffer{ advertiser().advertising_buffer().buffer, adv_size_ };
489 }
490
491 read_buffer get_scan_response_data()
492 {
493 return read_buffer{ advertiser().scan_response_buffer().buffer, adv_response_size_ };
494 }
495
496 bool is_valid_scan_request( const read_buffer& receive ) const
497 {
498 return details::advertising_type_base::is_valid_scan_request( receive, link_layer().local_address() );
499 }
500
501 bool is_valid_connect_request( const read_buffer& ) const
502 {
503 return false;
504 }
505
506 private:
507 static constexpr std::size_t max_advertising_data_size = 31;
508 static constexpr std::size_t maximum_adv_send_size = max_advertising_data_size + address_length;
509
510 void fill_scan_response_data()
511 {
512 using layout_t = typename pdu_layout_by_radio< typename LinkLayer::radio_t >::pdu_layout;
513
514 adv_response_size_ = fill_empty_scan_response_data< layout_t >(
515 link_layer().local_address(), advertiser().scan_response_buffer() );
516 }
517
518 LinkLayer& link_layer()
519 {
520 return static_cast< LinkLayer& >( *this );
521 }
522
523 const LinkLayer& link_layer() const
524 {
525 return static_cast< const LinkLayer& >( *this );
526 }
527
528 Advertiser& advertiser()
529 {
530 return static_cast< Advertiser& >( *this );
531 }
532
533 std::size_t adv_size_;
534 std::size_t adv_response_size_;
535 };
537 };
538
547 {
559 template < typename Type >
561
563 struct meta_type :
564 details::advertising_type_meta_type,
565 details::valid_link_layer_option_meta_type {};
566
567 template < typename LinkLayer, typename Advertiser >
568 class impl : protected details::advertising_type_base
569 {
570 protected:
571 read_buffer fill_advertising_data()
572 {
573 const device_address& addr = link_layer().local_address();
575
576 const auto buffer = advertiser().advertising_buffer();
577
578 std::uint16_t header = adv_nonconn_ind_pdu_type_code;
579 std::uint8_t* body = layout_t::body( buffer ).first;
580
581 if ( addr.is_random() )
582 header |= header_txaddr_field;
583
584 const std::size_t size =
585 address_length
586 + link_layer().fill_l2cap_advertising_data( &body[ address_length ], max_advertising_data_size );
587
588 header |= size << 8;
589
590 adv_size_ = layout_t::data_channel_pdu_memory_size( size );
591
592 layout_t::header( buffer, header );
593 std::copy( addr.begin(), addr.end(), body );
594
595 return buffer;
596 }
597
598 read_buffer get_advertising_data()
599 {
600 return advertiser().advertising_buffer();
601 }
602
603 read_buffer get_scan_response_data() const
604 {
605 return read_buffer{ nullptr, 0 };
606 }
607
608 bool is_valid_scan_request( const read_buffer& ) const
609 {
610 return false;
611 }
612
613 bool is_valid_connect_request( const read_buffer& ) const
614 {
615 return false;
616 }
617
618 private:
619 static constexpr std::size_t max_advertising_data_size = 31;
620
621 LinkLayer& link_layer()
622 {
623 return static_cast< LinkLayer& >( *this );
624 }
625
626 Advertiser& advertiser()
627 {
628 return static_cast< Advertiser& >( *this );
629 }
630
631 std::size_t adv_size_;
632 };
634 };
635
645 {
646 public:
648 struct meta_type :
649 details::advertising_startup_meta_type,
650 details::valid_link_layer_option_meta_type {};
651
652 template < typename Advertiser >
653 struct impl
654 {
655 bool begin_of_advertising_events() const
656 {
657 return true;
658 }
659
660 bool continued_advertising_events() const
661 {
662 return true;
663 }
664
665 void end_of_advertising_events()
666 {
667 }
668 };
670 };
671
684 {
685 public:
693
698 void start_advertising( unsigned count );
699
704
706 struct meta_type :
707 details::advertising_startup_meta_type,
708 details::valid_link_layer_option_meta_type {};
709
710 template < typename Advertiser >
711 class impl
712 {
713 public:
714 impl()
715 : started_( false )
716 , enabled_( false )
717 , count_( 0 )
718 {}
719
720 void start_advertising()
721 {
722 const bool start = !enabled_;
723
724 count_ = 0;
725 enabled_ = true;
726
727 if ( start && started_ )
728 static_cast< Advertiser& >( *this ).handle_start_advertising();
729 }
730
735 void start_advertising( unsigned count )
736 {
737 assert( count );
738
739 const bool start = !enabled_;
740
741 count_ = count;
742 enabled_ = true;
743
744 if ( start && started_ )
745 static_cast< Advertiser& >( *this ).handle_start_advertising();
746 }
747
751 void stop_advertising()
752 {
753 enabled_ = false;
754 count_ = 0;
755 }
756
757 protected:
758 bool begin_of_advertising_events()
759 {
760 bool result = enabled_;
761
762 if ( count_ )
763 {
764 --count_;
765 if ( count_ == 0 )
766 enabled_ = false;
767 }
768
769 started_ = true;
770 return result;
771 }
772
773 bool continued_advertising_events()
774 {
775 bool result = enabled_ && started_;
776
777 if ( count_ )
778 {
779 --count_;
780 if ( count_ == 0 )
781 enabled_ = false;
782 }
783
784 return result;
785 }
786
787 void end_of_advertising_events()
788 {
789 started_ = false;
790 enabled_ = false;
791 }
792 private:
793 volatile bool started_;
794 volatile bool enabled_;
795 volatile unsigned count_;
796 };
798 };
799
803 template < std::uint16_t AdvertisingIntervalMilliSeconds, typename = typename details::check_advertising_interval_parameter< AdvertisingIntervalMilliSeconds >::type >
805 {
807 struct meta_type :
808 details::advertising_interval_meta_type,
809 details::valid_link_layer_option_meta_type {};
815 protected:
817 {
818 return delta_time( AdvertisingIntervalMilliSeconds * 1000 );
819 }
820 };
821
829 {
830 public:
832 : interval_( delta_time::msec( 100 ) )
833 {
834 }
835
839 void advertising_interval_ms( unsigned interval_ms )
840 {
841 if ( interval_ms >= 20 and interval_ms <= 10240 )
842 interval_ = delta_time::msec( interval_ms );
843 }
844
849 {
850 if ( interval >= delta_time::msec( 20 ) and interval <= delta_time::msec( 10240 ) )
851 interval_ = interval;
852 }
853
858 {
859 return interval_;
860 }
861
863 struct meta_type :
864 details::advertising_interval_meta_type,
865 details::valid_link_layer_option_meta_type {};
866 private:
867 delta_time interval_;
869 };
870
871 namespace details {
872 struct advertising_channel_map_base {
873 static constexpr unsigned first_advertising_channel = 37;
874 static constexpr unsigned last_advertising_channel = 39;
875 };
876 }
877
889 struct variable_advertising_channel_map : details::advertising_channel_map_base
890 {
895 {
896 assert( channel >= first_advertising_channel );
897 assert( channel <= last_advertising_channel );
898
899 channel -= first_advertising_channel;
900 map_ = map_ | ( 1 << channel );
901
902 current_channel_index_ = first_channel_index();
903 }
904
911 {
912 assert( channel >= first_advertising_channel );
913 assert( channel <= last_advertising_channel );
914
915 channel -= first_advertising_channel;
916 map_ = map_ & ~( 1 << channel );
917
918 if ( map_ )
919 current_channel_index_ = first_channel_index();
920 }
921
923 struct meta_type :
924 details::advertising_channel_map_meta_type,
925 details::valid_link_layer_option_meta_type {};
926 protected:
927 variable_advertising_channel_map()
928 : current_channel_index_( 0 )
929 , map_( 0x7 )
930 {}
931
932 unsigned current_channel() const
933 {
934 return current_channel_index_ + first_advertising_channel;
935 }
936
937 void next_channel()
938 {
939 assert( map_ != 0 );
940
941 ++current_channel_index_;
942
943 // seek next position in map that is set to 1
944 for ( ; ( 1u << current_channel_index_ ) == 0 && ( 1u << current_channel_index_ ) <= map_; ++current_channel_index_ )
945 ;
946
947 if ( ( 1u << current_channel_index_ ) > map_ )
948 current_channel_index_ = first_channel_index();
949 }
950
951 bool first_channel_selected() const
952 {
953 return current_channel_index_ == first_channel_index();
954 }
955
956 private:
957 unsigned first_channel_index() const
958 {
959 unsigned result = 0;
960 for ( ; ( map_ & ( 1 << result ) ) == 0; ++result )
961 ;
962
963 return result;
964 }
965
966 unsigned current_channel_index_;
967 unsigned map_;
969 };
970
976 struct all_advertising_channel_map : details::advertising_channel_map_base
977 {
979 struct meta_type :
980 details::advertising_channel_map_meta_type,
981 details::valid_link_layer_option_meta_type {};
982
983 protected:
985 : current_channel_index_( first_advertising_channel )
986 {}
987
988 unsigned current_channel() const
989 {
990 return current_channel_index_;
991 }
992
993 void next_channel()
994 {
995 current_channel_index_ = current_channel_index_ == last_advertising_channel
996 ? first_advertising_channel
997 : current_channel_index_ + 1;
998 }
999
1000 bool first_channel_selected() const
1001 {
1002 return current_channel_index_ == this->first_advertising_channel;
1003 }
1004
1005 private:
1006 unsigned current_channel_index_;
1008 };
1009
1010 namespace details {
1011 /*
1012 * Type to implement the single and multiple adverting type advertisings
1013 */
1014 template < typename LinkLayer, typename Options, typename ... Advertisings >
1015 class advertiser;
1016
1017 struct advertiser_base_base
1018 {
1019 static constexpr std::uint32_t advertising_radio_access_address = 0x8E89BED6;
1020 static constexpr std::uint32_t advertising_crc_init = 0x555555;
1021 };
1022
1023 template < typename LinkLayer, typename ... Options >
1024 class advertiser_base :
1025 public advertiser_base_base,
1026 public bluetoe::details::find_by_meta_type<
1027 details::advertising_interval_meta_type,
1028 Options..., advertising_interval< 100 > >::type,
1029 public bluetoe::details::find_by_meta_type<
1030 details::advertising_channel_map_meta_type,
1031 Options..., all_advertising_channel_map >::type
1032 {
1033 public:
1034 /*
1035 * link layer raw_pdu_buffer() is devided into 3 sections:
1036 * - advertising_buffer()
1037 * - scan_response_buffer()
1038 * - advertising_receive_buffer()
1039 */
1040 read_buffer advertising_buffer()
1041 {
1043
1044 return read_buffer{
1045 base_link_layer().raw_pdu_buffer(),
1046 layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size ) };
1047 }
1048
1049 read_buffer scan_response_buffer()
1050 {
1052
1053 return read_buffer{
1054 base_link_layer().raw_pdu_buffer()
1055 + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size ),
1056 layout_t::data_channel_pdu_memory_size( advertising_type_base::max_scan_response_pdu_size ) };
1057 }
1058
1059 read_buffer advertising_receive_buffer()
1060 {
1062
1063 return read_buffer{
1064 base_link_layer().raw_pdu_buffer()
1065 + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size )
1066 + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_scan_response_pdu_size ),
1067 layout_t::data_channel_pdu_memory_size( advertising_type_base::maximum_adv_request_size ) };
1068 }
1069
1070 static constexpr std::size_t maximum_required_advertising_buffer()
1071 {
1073
1074 return layout_t::data_channel_pdu_memory_size( advertising_type_base::max_advertising_pdu_size )
1075 + layout_t::data_channel_pdu_memory_size( advertising_type_base::max_scan_response_pdu_size )
1076 + layout_t::data_channel_pdu_memory_size( advertising_type_base::maximum_adv_request_size );
1077 };
1078
1079 protected:
1080 advertiser_base()
1081 : adv_perturbation_( 0 )
1082 {
1083 }
1084
1085 delta_time next_adv_event()
1086 {
1087 if ( !this->first_channel_selected() )
1088 return delta_time::now();
1089
1090 adv_perturbation_ = ( adv_perturbation_ + 7 ) % ( max_adv_perturbation_ + 1 );
1091
1092 return this->current_advertising_interval() + delta_time::msec( adv_perturbation_ );
1093 }
1094
1095 LinkLayer& base_link_layer()
1096 {
1097 return static_cast< LinkLayer& >( *this );
1098 }
1099
1100 private:
1101 static constexpr unsigned max_adv_perturbation_ = 10;
1102
1103 unsigned adv_perturbation_;
1104 };
1105
1106 template < typename LinkLayer, typename Advertising, typename ... Options >
1107 struct start_stop_implementation :
1108 bluetoe::details::find_by_meta_type<
1109 advertising_startup_meta_type,
1110 Options...,
1111 auto_start_advertising
1112 >::type::template impl<
1113 advertiser<
1114 LinkLayer,
1115 std::tuple< Options... >,
1116 Advertising
1117 >
1118 > {};
1119
1120 /*
1121 * Implementation for a single advertising type
1122 */
1123 template < typename LinkLayer, typename ... Options, typename Advertising >
1124 class advertiser< LinkLayer, std::tuple< Options... >, std::tuple< Advertising > > :
1125 public Advertising::template impl< LinkLayer, advertiser< LinkLayer, std::tuple< Options... >, std::tuple< Advertising > > >,
1126 public advertiser_base< LinkLayer, Options... >,
1127 public start_stop_implementation< LinkLayer, std::tuple< Advertising >, Options... >
1128 {
1129 public:
1130
1131 /*
1132 * Send out, first advertising
1133 */
1134 void handle_start_advertising()
1135 {
1136 const read_buffer advertising_data = this->fill_advertising_data();
1137 const read_buffer response_data = this->get_scan_response_data();
1138
1139 if ( !advertising_data.empty() && this->begin_of_advertising_events() )
1140 {
1141 this->base_link_layer().set_access_address_and_crc_init(
1142 this->advertising_radio_access_address,
1143 this->advertising_crc_init );
1144
1145 this->base_link_layer().schedule_advertisment(
1146 this->current_channel(),
1147 write_buffer( advertising_data ),
1148 write_buffer( response_data ),
1150 this->advertising_receive_buffer() );
1151 }
1152 }
1153
1154 void handle_stop_advertising()
1155 {
1156 this->end_of_advertising_events();
1157 }
1158
1159 /*
1160 * handling incomming PDU
1161 */
1162 bool handle_adv_receive( read_buffer receive, device_address& remote_address )
1163 {
1164 if ( this->is_valid_connect_request( receive ) )
1165 {
1167
1168 const std::uint8_t* const body = layout_t::body( receive ).first;
1169 const std::uint16_t header = layout_t::header( receive );
1170
1171 remote_address = device_address( &body[ 0 ], header & 0x40 );
1172
1173 if ( this->base_link_layer().is_connection_request_in_filter( remote_address ) )
1174 return true;
1175 }
1176
1177 handle_adv_timeout();
1178
1179 return false;
1180 }
1181
1182 void handle_adv_timeout()
1183 {
1184 const read_buffer advertising_data = this->base_link_layer().l2cap_adverting_data_or_scan_response_data_changed()
1185 ? this->fill_advertising_data()
1186 : this->get_advertising_data();
1187
1188 const read_buffer response_data = this->get_scan_response_data();
1189
1190 if ( !advertising_data.empty() && this->continued_advertising_events() )
1191 {
1192 this->next_channel();
1193
1194 this->base_link_layer().schedule_advertisment(
1195 this->current_channel(),
1196 write_buffer( advertising_data ),
1197 write_buffer( response_data ),
1198 this->next_adv_event(),
1199 this->advertising_receive_buffer() );
1200 }
1201 }
1202
1203 };
1204
1205 /*
1206 * Default
1207 */
1208 template < typename LinkLayer, typename ... Options >
1209 class advertiser< LinkLayer, std::tuple< Options... >, std::tuple<> > :
1210 public advertiser< LinkLayer, std::tuple< Options... >, std::tuple< connectable_undirected_advertising > >
1211 {
1212 };
1213
1214 template < typename LinkLayer, typename Options, typename Advertiser, typename ... Types >
1215 class multipl_advertiser_base;
1216
1217 template < typename LinkLayer, typename Options, typename Advertiser >
1218 class multipl_advertiser_base< LinkLayer, Options, Advertiser >
1219 {
1220 protected:
1221 read_buffer fill_advertising_data( unsigned )
1222 {
1223 return read_buffer{ nullptr, 0 };
1224 }
1225
1226 read_buffer get_advertising_data( unsigned )
1227 {
1228 return read_buffer{ nullptr, 0 };
1229 }
1230
1231 read_buffer get_scan_response_data( unsigned )
1232 {
1233 return read_buffer{ nullptr, 0 };
1234 }
1235
1236 bool is_valid_scan_request( const read_buffer&, unsigned ) const
1237 {
1238 return false;
1239 }
1240
1241 bool is_valid_connect_request( const read_buffer&, unsigned ) const
1242 {
1243 return false;
1244 }
1245 };
1246
1247 template < typename LinkLayer, typename Options, typename Advertiser, typename Type, typename ... Types >
1248 class multipl_advertiser_base< LinkLayer, Options, Advertiser, Type, Types... > :
1249 public Type::template impl< LinkLayer, Advertiser >,
1250 public multipl_advertiser_base< LinkLayer, Options, Advertiser, Types... >
1251 {
1252 protected:
1253
1254 read_buffer fill_advertising_data( unsigned selected )
1255 {
1256 return selected == 0
1257 ? adv_type::fill_advertising_data()
1258 : tail_type::fill_advertising_data( selected -1 );
1259 }
1260
1261 read_buffer get_advertising_data( unsigned selected )
1262 {
1263 return selected == 0
1264 ? adv_type::get_advertising_data()
1265 : tail_type::get_advertising_data( selected -1 );
1266 }
1267
1268 read_buffer get_scan_response_data( unsigned selected )
1269 {
1270 return selected == 0
1271 ? adv_type::get_scan_response_data()
1272 : tail_type::get_scan_response_data( selected -1 );
1273 }
1274
1275 bool is_valid_scan_request( const read_buffer& b, unsigned selected ) const
1276 {
1277 return selected == 0
1278 ? adv_type::is_valid_scan_request( b )
1279 : tail_type::is_valid_scan_request( b, selected -1 );
1280 }
1281
1282 bool is_valid_connect_request( const read_buffer& b, unsigned selected ) const
1283 {
1284 return selected == 0
1285 ? adv_type::is_valid_connect_request( b )
1286 : tail_type::is_valid_connect_request( b, selected -1 );
1287 }
1288
1289 private:
1290 using adv_type = typename Type::template impl< LinkLayer, Advertiser >;
1291 using tail_type = multipl_advertiser_base< LinkLayer, Options, Advertiser, Types... >;
1292 };
1293
1294 /*
1295 * Wrapper around multiple advertising types
1296 */
1297 template < typename LinkLayer, typename ... Options, typename FirstAdv, typename SecondAdv, typename ... Advertisings >
1298 class advertiser< LinkLayer, std::tuple< Options... >, std::tuple< FirstAdv, SecondAdv, Advertisings... > > :
1299 public advertiser_base< LinkLayer, Options... >,
1300 public multipl_advertiser_base<
1301 LinkLayer,
1302 std::tuple< Options... >,
1303 advertiser< LinkLayer, std::tuple< Options... >, std::tuple< FirstAdv, SecondAdv, Advertisings... > >,
1304 FirstAdv, SecondAdv, Advertisings...
1305 >,
1306 public start_stop_implementation< LinkLayer, std::tuple< FirstAdv, SecondAdv, Advertisings... >, Options... >
1307 {
1308 public:
1309 advertiser()
1310 : selected_( 0 )
1311 , proposal_( 0 )
1312 {
1313 }
1314
1315 void handle_start_advertising()
1316 {
1317 selected_ = proposal_;
1318 const read_buffer advertising_data = this->fill_advertising_data( selected_ );
1319 const read_buffer response_data = this->get_scan_response_data( selected_ );
1320
1321 if ( !advertising_data.empty() && this->begin_of_advertising_events() )
1322 {
1323 this->base_link_layer().set_access_address_and_crc_init(
1324 this->advertising_radio_access_address,
1325 this->advertising_crc_init );
1326
1327 this->base_link_layer().schedule_advertisment(
1328 this->current_channel(),
1329 write_buffer( advertising_data ),
1330 write_buffer( response_data ),
1332 this->advertising_receive_buffer() );
1333 }
1334 }
1335
1336 void handle_stop_advertising()
1337 {
1338 this->end_of_advertising_events();
1339 }
1340
1341 bool handle_adv_receive( read_buffer receive, device_address& remote_address )
1342 {
1343 if ( this->is_valid_connect_request( receive, selected_ ) )
1344 {
1346
1347 const std::uint8_t* const body = layout_t::body( receive ).first;
1348 const std::uint16_t header = layout_t::header( receive );
1349
1350 remote_address = device_address( &body[ 0 ], header & 0x40 );
1351
1352 if ( this->base_link_layer().is_connection_request_in_filter( remote_address ) )
1353 return true;
1354 }
1355
1356 handle_adv_timeout();
1357
1358 return false;
1359 }
1360
1361 void handle_adv_timeout()
1362 {
1363 const bool fill_data = selected_ != proposal_
1364 || this->base_link_layer().l2cap_adverting_data_or_scan_response_data_changed();
1365
1366 selected_ = proposal_;
1367 const read_buffer advertising_data = fill_data
1368 ? this->fill_advertising_data( selected_ )
1369 : this->get_advertising_data( selected_ );
1370
1371 const read_buffer response_data = this->get_scan_response_data( selected_ );
1372
1373 if ( !advertising_data.empty() && this->continued_advertising_events() )
1374 {
1375 this->next_channel();
1376
1377 this->base_link_layer().schedule_advertisment(
1378 this->current_channel(),
1379 write_buffer( advertising_data ),
1380 write_buffer( response_data ),
1381 this->next_adv_event(),
1382 this->advertising_receive_buffer() );
1383 }
1384 }
1385
1386 /*
1387 * this is the true implementation of all the documentated function within the advertising types
1388 */
1389 template < typename Type >
1390 void change_advertising()
1391 {
1392 proposal_ = bluetoe::details::index_of< Type, FirstAdv, SecondAdv, Advertisings... >::value;
1393 assert( proposal_ != sizeof...(Advertisings) + 2 );
1394 }
1395
1396 private:
1397
1398 unsigned selected_;
1399 unsigned proposal_;
1400 };
1401
1403 template < typename LinkLayer, typename ... Options >
1404 using select_advertiser_implementation =
1405 advertiser<
1406 LinkLayer,
1407 std::tuple< Options... >,
1408 typename bluetoe::details::find_all_by_meta_type< advertising_type_meta_type,
1409 Options... >::type >;
1411 }
1412}
1413}
1414#endif