BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
characteristic_value.hpp
1#ifndef BLUETOE_CHARACTERISTIC_VALUE_HPP
2#define BLUETOE_CHARACTERISTIC_VALUE_HPP
3
5#include <bluetoe/attribute.hpp>
6#include <bluetoe/codes.hpp>
7#include <bluetoe/meta_types.hpp>
8#include <type_traits>
9#include <climits>
10#include <cstring>
11
12namespace bluetoe {
13
14 namespace details {
15 // type defines the value of a characteristic
16 struct characteristic_value_meta_type {};
17 // type is a valid parameter to a characteristic
18 struct characteristic_parameter_meta_type {};
19 // type is a characteristic read handler
20 struct characteristic_value_read_handler_meta_type {};
21 // type is a characteristic write handler
22 struct characteristic_value_write_handler_meta_type {};
23
24 struct characteristic_value_declaration_parameter {};
25 struct client_characteristic_configuration_parameter {};
26 struct characteristic_subscription_call_back_meta_type {};
27 }
28
49 using meta_type = details::valid_characteristic_option_meta_type;
51 };
52
71 using meta_type = details::valid_characteristic_option_meta_type;
73 };
74
89 struct notify {
91 struct meta_type :
92 details::client_characteristic_configuration_parameter,
93 details::characteristic_parameter_meta_type,
94 details::valid_characteristic_option_meta_type {};
96 };
97
110 struct indicate {
112 struct meta_type :
113 details::client_characteristic_configuration_parameter,
114 details::characteristic_parameter_meta_type,
115 details::valid_characteristic_option_meta_type {};
117 };
118
129 template < typename UUID, typename Server >
130 static void on_subscription( std::uint16_t flags, Server& srv )
131 {
132 if ( flags & details::client_characteristic_configuration_notification_enabled )
133 srv.template notify< UUID >();
134 }
135
136 struct meta_type :
137 details::characteristic_subscription_call_back_meta_type,
138 details::characteristic_parameter_meta_type,
139 details::valid_characteristic_option_meta_type {};
141 };
142
153 template < typename UUID, typename Server >
154 static void on_subscription( std::uint16_t flags, Server& srv )
155 {
156 if ( flags & details::client_characteristic_configuration_indication_enabled )
157 srv.template indicate< UUID >();
158 }
159
160 struct meta_type :
161 details::characteristic_subscription_call_back_meta_type,
162 details::characteristic_parameter_meta_type,
163 details::valid_characteristic_option_meta_type {};
165 };
166
168 struct default_on_characteristic_subscription {
169 template < typename UUID, typename Server >
170 static void on_subscription( std::uint16_t, Server& ) {}
171
172 struct meta_type :
173 details::characteristic_subscription_call_back_meta_type,
174 details::characteristic_parameter_meta_type,
175 details::valid_characteristic_option_meta_type {};
176 };
192 struct meta_type :
193 details::characteristic_parameter_meta_type,
194 details::valid_characteristic_option_meta_type {};
196 };
197
209 struct meta_type :
210 details::characteristic_parameter_meta_type,
211 details::valid_characteristic_option_meta_type {};
213 };
214
215 namespace details {
216 template < bool RequiresEncryption >
217 struct encryption_requirements;
218
219 template <>
220 struct encryption_requirements< false > {
221 static attribute_access_result check( const connection_security_attributes& ) {
222 return attribute_access_result::success;
223 }
224 };
225
226 template <>
227 struct encryption_requirements< true > {
228 static attribute_access_result check( const connection_security_attributes& attr )
229 {
230 if ( attr.is_encrypted )
231 return attribute_access_result::success;
232
233 return attr.pairing_status == device_pairing_status::no_key
234 ? attribute_access_result::insufficient_authentication
235 : attribute_access_result::insufficient_encryption;
236 }
237 };
238
239 /*
240 * Base for value_implementations, providing common attributes and tests
241 */
242 template < typename ... Options >
243 struct value_impl_base
244 {
245 static constexpr bool has_only_write_without_response = details::has_option< only_write_without_response, Options... >::value;
246 };
247 }
248
252 template < typename T, T* Ptr >
254 {
255 public:
260 template < typename ... Options >
261 class value_impl : public details::value_impl_base< Options... >
262 {
263 public:
264 static constexpr bool has_read_access = !details::has_option< no_read_access, Options... >::value;
265 static constexpr bool has_write_access = !std::is_const< T >::value && !details::has_option< no_write_access, Options... >::value;
266 static constexpr bool has_write_without_response = details::has_option< write_without_response, Options... >::value;
267 static constexpr bool has_notification = details::has_option< notify, Options... >::value;
268 static constexpr bool has_indication = details::has_option< indicate, Options... >::value;
269
270 template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption >
271 static details::attribute_access_result characteristic_value_access( details::attribute_access_arguments& args, std::size_t )
272 {
273 const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );
274
275 if ( security_result != details::attribute_access_result::success )
276 return security_result;
277
278 if ( args.type == details::attribute_access_type::read )
279 {
280 return characteristic_value_read_access( args, std::integral_constant< bool, has_read_access >() );
281 }
282 else if ( args.type == details::attribute_access_type::write )
283 {
284 return characteristic_value_write_access( args, std::integral_constant< bool, has_write_access >() );
285 }
286
287 return details::attribute_access_result::write_not_permitted;
288 }
289
290 /*
291 * Used to find this characteristic for notification
292 */
293 static constexpr bool is_this( const void* value )
294 {
295 return value == Ptr;
296 }
297
298 private:
299 static constexpr details::attribute_access_result characteristic_value_read_access( details::attribute_access_arguments& args, const std::true_type& )
300 {
301 return details::attribute_value_read_access( args, static_cast< const std::uint8_t* >( static_cast< const void* >( Ptr ) ), sizeof( T ) );
302 }
303
304 static constexpr details::attribute_access_result characteristic_value_read_access( details::attribute_access_arguments&, const std::false_type& )
305 {
306 return details::attribute_access_result::read_not_permitted;
307 }
308
309 static details::attribute_access_result characteristic_value_write_access( details::attribute_access_arguments& args, const std::true_type& )
310 {
311 if ( args.buffer_offset > sizeof( T ) )
312 return details::attribute_access_result::invalid_offset;
313
314 if ( args.buffer_size + args.buffer_offset > sizeof( T ) )
315 return details::attribute_access_result::invalid_attribute_value_length;
316
317 args.buffer_size = std::min< std::size_t >( args.buffer_size, sizeof( T ) - args.buffer_offset );
318
319 std::uint8_t* const ptr = static_cast< std::uint8_t* >( static_cast< void* >( Ptr ) );
320 std::copy( args.buffer, args.buffer + args.buffer_size, ptr + args.buffer_offset );
321
322 return details::attribute_access_result::success;
323 }
324
325 static constexpr details::attribute_access_result characteristic_value_write_access( details::attribute_access_arguments&, const std::false_type& )
326 {
327 return details::attribute_access_result::write_not_permitted;
328 }
329
330 };
331
332 struct meta_type :
333 details::characteristic_value_meta_type,
334 details::characteristic_value_declaration_parameter,
335 details::valid_characteristic_option_meta_type {};
337 };
338
344 template < class T, T Value >
345 struct fixed_value {
349 template < typename ... Options >
350 class value_impl : public details::value_impl_base< Options... >
351 {
352 public:
353 static constexpr bool has_read_access = !details::has_option< no_read_access, Options... >::value;
354 static constexpr bool has_write_access = false;
355 static constexpr bool has_write_without_response = false;
356 static constexpr bool has_notification = details::has_option< notify, Options... >::value;
357 static constexpr bool has_indication = details::has_option< indicate, Options... >::value;
358
359 template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption >
360 static details::attribute_access_result characteristic_value_access( details::attribute_access_arguments& args, std::size_t )
361 {
362 const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );
363
364 if ( security_result != details::attribute_access_result::success )
365 return security_result;
366
367 if ( !has_read_access )
368 return details::attribute_access_result::read_not_permitted;
369
370 if ( args.type != details::attribute_access_type::read )
371 return details::attribute_access_result::write_not_permitted;
372
373 if ( args.buffer_offset > sizeof( T ) )
374 return details::attribute_access_result::invalid_offset;
375
376 args.buffer_size = std::min< std::size_t >( args.buffer_size, sizeof( T ) - args.buffer_offset );
377
378 // copy data
379 std::uint8_t* output = args.buffer;
380 for ( auto i = args.buffer_offset; i != args.buffer_offset + args.buffer_size; ++i, ++output )
381 *output = ( Value >> ( 8 * i ) ) & 0xff;
382
383 return details::attribute_access_result::success;
384 }
385
386 static constexpr bool is_this( const void* )
387 {
388 return false;
389 }
390 };
391
392 struct meta_type :
393 details::characteristic_value_meta_type,
394 details::characteristic_value_declaration_parameter,
395 details::valid_characteristic_option_meta_type {};
397 };
398
403 template < std::uint8_t Value >
405
410 template < std::uint16_t Value >
412
413
418 template < std::uint32_t Value >
420
427 template < class Text >
429 {
433 template < typename ... Options >
434 class value_impl : public details::value_impl_base< Options... >
435 {
436 public:
437 static constexpr bool has_read_access = true;
438 static constexpr bool has_write_access = false;
439 static constexpr bool has_write_without_response = false;
440 static constexpr bool has_notification = false;
441 static constexpr bool has_indication = false;
442
443 template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption >
444 static details::attribute_access_result characteristic_value_access( details::attribute_access_arguments& args, std::size_t )
445 {
446 const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );
447
448 if ( security_result != details::attribute_access_result::success )
449 return security_result;
450
451 if ( args.type != details::attribute_access_type::read )
452 return details::attribute_access_result::write_not_permitted;
453
454 const char* value = static_cast< const char* >( static_cast< const void* >( Text::value() ) );
455 std::size_t length = Text::size();
456
457 if ( args.buffer_offset > length )
458 return details::attribute_access_result::invalid_offset;
459
460 args.buffer_size = std::min< std::size_t >( args.buffer_size, length - args.buffer_offset );
461
462 // copy data
463 std::copy( value + args.buffer_offset, value + args.buffer_offset + args.buffer_size, args.buffer );
464
465 return details::attribute_access_result::success;
466 }
467
468 static constexpr bool is_this( const void* )
469 {
470 return false;
471 }
472
473 };
474
475 struct meta_type :
476 details::characteristic_value_meta_type,
477 details::characteristic_value_declaration_parameter,
478 details::valid_characteristic_option_meta_type {};
480 };
481
485 template < const char* const Name >
486 struct cstring_value : cstring_wrapper< cstring_value< Name > >
487 {
489 static constexpr char const * name = Name;
490
491 static constexpr char const * value()
492 {
493 return name;
494 }
495
496 static constexpr std::size_t size()
497 {
498 return std::strlen( name );
499 }
501 };
502
509 template < const std::uint8_t* const Value, std::size_t Size >
510 struct fixed_blob_value : cstring_wrapper< fixed_blob_value< Value, Size > >
511 {
513 static constexpr std::uint8_t const * value()
514 {
515 return Value;
516 }
517
518 static constexpr std::size_t size()
519 {
520 return Size;
521 }
523 };
524
525 namespace details {
526 template < class T >
527 struct invoke_read_handler {
528 template < class Server >
529 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* server )
530 {
531 return T::template call_read_handler< Server >( offset, read_size, out_buffer, out_size, server );
532 }
533 };
534
535 template <>
536 struct invoke_read_handler< no_such_type > {
537 template < class Server >
538 static constexpr std::uint8_t call_read_handler( std::size_t, std::size_t, std::uint8_t*, std::size_t&, void* )
539 {
541 }
542 };
543
544 template < class T >
545 struct invoke_write_handler {
546 template < class Server, std::size_t ClientCharacteristicIndex >
547 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& config, void* server )
548 {
549 return T::template call_write_handler< Server, ClientCharacteristicIndex >( offset, write_size, value, config, server );
550 }
551 };
552
553 template <>
554 struct invoke_write_handler< no_such_type > {
555 template < class Server, std::size_t ClientCharacteristicIndex >
556 static constexpr std::uint8_t call_write_handler( std::size_t, std::size_t, const std::uint8_t*, const details::client_characteristic_configuration&, void* )
557 {
559 }
560 };
561
562 struct value_handler_base {
563
564 template < typename ... Options >
565 class value_impl : public details::value_impl_base< Options... >
566 {
567 public:
568 using read_handler_type = typename find_by_meta_type< characteristic_value_read_handler_meta_type, Options... >::type;
569 using write_handler_type = typename find_by_meta_type< characteristic_value_write_handler_meta_type, Options... >::type;
570 static constexpr bool no_read = has_option< no_read_access, Options... >::value;
571 static constexpr bool no_write = has_option< no_write_access, Options... >::value;
572
573 static constexpr bool has_read_handler = !std::is_same< read_handler_type, no_such_type >::value;
574 static constexpr bool has_read_access = has_read_handler && !no_read;
575 static constexpr bool has_write_access = !std::is_same< write_handler_type, no_such_type >::value;
576 static constexpr bool has_write_without_response = details::has_option< write_without_response, Options... >::value;
577 static constexpr bool has_notification = has_option< notify, Options... >::value;
578 static constexpr bool has_indication = has_option< indicate, Options... >::value;
579
580 static_assert( !( no_write && ( has_write_access || has_write_without_response ) ), "There is no point in providing a write_handler and disabling write by using no_write_access" );
581
582 static_assert( !has_notification || ( has_notification && has_read_handler ), "When enabling notification, the characteristic needs to have a read_handler" );
583 static_assert( !has_indication || ( has_indication && has_read_handler ), "When enabling indications, the characteristic needs to have a read_handler" );
584
585 static_assert( has_read_access || has_write_access || has_notification || has_indication, "Ups!");
586
587 template < class Server, std::size_t ClientCharacteristicIndex, bool RequiresEncryption >
588 static attribute_access_result characteristic_value_access( attribute_access_arguments& args, std::size_t /* attribute_index */ )
589 {
590 const auto security_result = details::encryption_requirements< RequiresEncryption >::check( args.connection_security );
591
592 if ( security_result != details::attribute_access_result::success )
593 return security_result;
594
595 if ( args.type == attribute_access_type::read )
596 {
597 return static_cast< attribute_access_result >(
598 invoke_read_handler< read_handler_type >::template call_read_handler< Server >( args.buffer_offset, args.buffer_size, args.buffer, args.buffer_size, args.server ) );
599 }
600 else if ( args.type == attribute_access_type::write )
601 {
602 return static_cast< attribute_access_result >(
603 invoke_write_handler< write_handler_type >::template call_write_handler< Server, ClientCharacteristicIndex >( args.buffer_offset, args.buffer_size, args.buffer, args.client_config, args.server ) );
604 }
605 else
606 {
607 return attribute_access_result::request_not_supported;
608 }
609 }
610
611 static constexpr bool is_this( const void* /* value */ )
612 {
613 return false;
614 }
615 };
616
617 struct meta_type :
618 characteristic_value_meta_type,
619 characteristic_value_declaration_parameter,
620 details::valid_characteristic_option_meta_type {};
621 };
622
623 template < typename T >
624 inline std::pair< std::uint8_t, T > deserialize( std::size_t write_size, const std::uint8_t* value )
625 {
626 static_assert( CHAR_BIT == 8, "needs porting!" );
627
628 if ( write_size != sizeof( T ) )
629 return std::pair< std::uint8_t, T >{ error_codes::invalid_attribute_value_length, 0 };
630
631 T result = 0;
632
633 for ( const std::uint8_t* v = value + sizeof( T ); v != value; --v )
634 {
635 result = ( result << 8 ) | *( v - 1 );
636 }
637
638 return std::pair< std::uint8_t, T >{ error_codes::success, result };
639 }
640
641 template <>
642 inline std::pair< std::uint8_t, bool > deserialize( std::size_t write_size, const std::uint8_t* value )
643 {
644 if ( write_size != 1 )
645 return std::make_pair( error_codes::invalid_attribute_value_length, false );
646
647 if ( *value == 0 )
648 {
649 return std::pair< std::uint8_t, bool >{ error_codes::success, false };
650 }
651 else if ( *value == 1 )
652 {
653 return std::pair< std::uint8_t, bool >{ error_codes::success, true };
654 }
655
656 return std::pair< std::uint8_t, bool >{ error_codes::out_of_range, false };
657 }
658 }
659
690 template < std::uint8_t (*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >
691 struct free_read_blob_handler : details::value_handler_base
692 {
694 template < class Server >
695 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
696 {
697 return F( offset, read_size, out_buffer, out_size );
698 }
699
700 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
702 };
703
733 template < std::uint8_t (*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >
734 struct free_read_handler : details::value_handler_base
735 {
737 template < class Server >
738 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
739 {
740 return offset == 0
741 ? F( read_size, out_buffer, out_size )
742 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
743 }
744
745 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
747 };
748
776 template < std::uint8_t (*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) >
777 struct free_write_blob_handler : details::value_handler_base
778 {
780 template < class Server, std::size_t ClientCharacteristicIndex >
781 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
782 {
783 return F( offset, write_size, value );
784 }
785
786 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
788 };
789
813 template < std::uint8_t (*F)( std::size_t write_size, const std::uint8_t* value ) >
814 struct free_raw_write_handler : details::value_handler_base
815 {
817 template < class Server, std::size_t ClientCharacteristicIndex >
818 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
819 {
820 return offset == 0
821 ? F( write_size, value )
822 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
823 }
824
825 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
827 };
828
829 template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >
830 struct read_blob_handler : details::value_handler_base
831 {
833 template < class Server >
834 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
835 {
836 return (O.*F)( offset, read_size, out_buffer, out_size );
837 }
838
839 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
841 };
842
843 template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const >
844 struct read_blob_handler_c : details::value_handler_base
845 {
847 template < class Server >
848 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
849 {
850 return (O.*F)( offset, read_size, out_buffer, out_size );
851 }
852
853 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
855 };
856
857 template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile >
858 struct read_blob_handler_v : details::value_handler_base
859 {
861 template < class Server >
862 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
863 {
864 return (O.*F)( offset, read_size, out_buffer, out_size );
865 }
866
867 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
869 };
870
871 template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile >
872 struct read_blob_handler_cv : details::value_handler_base
873 {
875 template < class Server >
876 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
877 {
878 return (O.*F)( offset, read_size, out_buffer, out_size );
879 }
880
881 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
883 };
884
885 template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >
886 struct read_handler : details::value_handler_base
887 {
889 template < class Server >
890 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
891 {
892 return offset == 0
893 ? (O.*F)( read_size, out_buffer, out_size )
894 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
895 }
896
897 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
899 };
900
901 template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const >
902 struct read_handler_c : details::value_handler_base
903 {
905 template < class Server >
906 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
907 {
908 return offset == 0
909 ? (O.*F)( read_size, out_buffer, out_size )
910 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
911 }
912
913 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
915 };
916
917 template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) volatile >
918 struct read_handler_v : details::value_handler_base
919 {
921 template < class Server >
922 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
923 {
924 return offset == 0
925 ? (O.*F)( read_size, out_buffer, out_size )
926 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
927 }
928
929 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
931 };
932
933 template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) const volatile >
934 struct read_handler_cv : details::value_handler_base
935 {
937 template < class Server >
938 static constexpr std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* )
939 {
940 return offset == 0
941 ? (O.*F)( read_size, out_buffer, out_size )
942 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
943 }
944
945 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
947 };
948
949 template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) >
950 struct write_blob_handler : details::value_handler_base
951 {
953 template < class Server, std::size_t ClientCharacteristicIndex >
954 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
955 {
956 return (O.*F)( offset, write_size, value );
957 }
958
959 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
961 };
962
963 template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) const >
964 struct write_blob_handler_c : details::value_handler_base
965 {
967 template < class Server, std::size_t ClientCharacteristicIndex >
968 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
969 {
970 return (O.*F)( offset, write_size, value );
971 }
972
973 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
975 };
976
977 template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) volatile >
978 struct write_blob_handler_v : details::value_handler_base
979 {
981 template < class Server, std::size_t ClientCharacteristicIndex >
982 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
983 {
984 return (O.*F)( offset, write_size, value );
985 }
986
987 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
989 };
990
991 template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) const volatile >
992 struct write_blob_handler_cv : details::value_handler_base
993 {
995 template < class Server, std::size_t ClientCharacteristicIndex >
996 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
997 {
998 return (O.*F)( offset, write_size, value );
999 }
1000
1001 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1003 };
1004
1005 template < class Obj, Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) >
1006 struct write_handler : details::value_handler_base
1007 {
1009 template < class Server, std::size_t ClientCharacteristicIndex >
1010 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
1011 {
1012 return offset == 0
1013 ? (O.*F)( write_size, value )
1014 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
1015 }
1016
1017 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1019 };
1020
1021 template < class Obj, const Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) const >
1022 struct write_handler_c : details::value_handler_base
1023 {
1025 template < class Server, std::size_t ClientCharacteristicIndex >
1026 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
1027 {
1028 return offset == 0
1029 ? (O.*F)( write_size, value )
1030 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
1031 }
1032
1033 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1035 };
1036
1037 template < class Obj, volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) volatile >
1038 struct write_handler_v : details::value_handler_base
1039 {
1041 template < class Server, std::size_t ClientCharacteristicIndex >
1042 static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
1043 {
1044 return offset == 0
1045 ? (O.*F)( write_size, value )
1046 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
1047 }
1048
1049 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1051 };
1052
1053 template < class Obj, const volatile Obj& O, std::uint8_t (Obj::*F)( std::size_t write_size, const std::uint8_t* value ) const volatile >
1054 struct write_handler_cv : details::value_handler_base
1055 {
1057 template < class Server, std::size_t ClientCharacteristicIndex >
1058 static constexpr std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
1059 {
1060 return offset == 0
1061 ? (O.*F)( write_size, value )
1062 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
1063 }
1064
1065 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1067 };
1068
1069 template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >
1070 struct mixin_read_handler : details::value_handler_base
1071 {
1073 template < class Server >
1074 static std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* server )
1075 {
1076 assert( server );
1077 static_assert( std::is_convertible< Server*, Mixin* >::value, "Use bluetoe::mixin<> to mixin an instance of the mixin_read_handler into the server." );
1078
1079 Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );
1080
1081 return offset == 0
1082 ? (mixin.*F)( read_size, out_buffer, out_size )
1083 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
1084
1085 }
1086
1087 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
1089 };
1090
1091 template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t write_size, const std::uint8_t* value ) >
1092 struct mixin_write_handler : details::value_handler_base
1093 {
1095 template < class Server, std::size_t ClientCharacteristicIndex >
1096 static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* server )
1097 {
1098 assert( server );
1099 static_assert( std::is_convertible< Server*, Mixin* >::value, "Use bluetoe::mixin<> to mixin an instance of the mixin_write_handler into the server." );
1100
1101 Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );
1102
1103 return offset == 0
1104 ? (mixin.*F)( write_size, value )
1105 : static_cast< std::uint8_t >( error_codes::attribute_not_long );
1106 }
1107
1108 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1110 };
1111
1112 template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size ) >
1113 struct mixin_read_blob_handler : details::value_handler_base
1114 {
1116 template < class Server >
1117 static std::uint8_t call_read_handler( std::size_t offset, std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size, void* server )
1118 {
1119 assert( server );
1120 static_assert( std::is_convertible< Server*, Mixin* >::value, "Use bluetoe::mixin<> to mixin an instance of the mixin_read_blob_handler into the server." );
1121
1122 Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );
1123 return (mixin.*F)( offset, read_size, out_buffer, out_size );
1124 }
1125
1126 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_read_handler_meta_type {};
1128 };
1129
1130 template < class Mixin, std::uint8_t (Mixin::*F)( std::size_t offset, std::size_t write_size, const std::uint8_t* value ) >
1131 struct mixin_write_blob_handler : details::value_handler_base
1132 {
1134 template < class Server, std::size_t ClientCharacteristicIndex >
1135 static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* server )
1136 {
1137 assert( server );
1138 static_assert( std::is_convertible< Server*, Mixin* >::value, "Use bluetoe::mixin<> to mixin an instance of the mixin_write_blob_handler into the server." );
1139
1140 Mixin& mixin = static_cast< Mixin& >( *static_cast< Server* >( server ) );
1141 return (mixin.*F)( offset, write_size, value );
1142 }
1143
1144 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1146 };
1147
1157 template < class Mixin, std::pair< std::uint8_t, bool > (Mixin::*F)( std::size_t write_size, const std::uint8_t* value ), typename IndicationUUID >
1158 struct mixin_write_indication_control_point_handler : details::value_handler_base
1159 {
1161 template < class Server, std::size_t >
1162 static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& config, void* server_ptr )
1163 {
1164 assert( server_ptr );
1165 static_assert( std::is_convertible< Server*, Mixin* >::value, "Use bluetoe::mixin<> to mixin an instance of the mixin_write_handler into the server." );
1166
1167 if ( offset != 0 )
1168 return static_cast< std::uint8_t >( error_codes::attribute_not_long );
1169
1170 // we have a void pointer, the type of the server and the server is derived from the mixin
1171 Server& server = *static_cast< Server* >( server_ptr );
1172 Mixin& mixin = static_cast< Mixin& >( server );
1173
1174 // as this is a indication control point, this thingy must be configured for indications
1175 if ( !server.template configured_for_indications< IndicationUUID >( config ) )
1177
1178 const std::pair< std::uint8_t, bool > result = (mixin.*F)( write_size, value );
1179
1180 if ( result.second )
1182
1183 return static_cast< std::uint8_t >( result.first );
1184 }
1185
1186 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1188 };
1189
1196 template < class Mixin, std::pair< std::uint8_t, bool > (Mixin::*F)( std::size_t write_size, const std::uint8_t* value ), typename NotificationUUID >
1197 struct mixin_write_notification_control_point_handler : details::value_handler_base
1198 {
1200 template < class Server, std::size_t >
1201 static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& config, void* server_ptr )
1202 {
1203 assert( server_ptr );
1204 static_assert( std::is_convertible< Server*, Mixin* >::value, "Use bluetoe::mixin<> to mixin an instance of the mixin_write_handler into the server." );
1205
1206 if ( offset != 0 )
1207 return static_cast< std::uint8_t >( error_codes::attribute_not_long );
1208
1209 // we have a void pointer, the type of the server and the server is derived from the mixin
1210 Server& server = *static_cast< Server* >( server_ptr );
1211 Mixin& mixin = static_cast< Mixin& >( server );
1212
1213 // as this is a notification control point, this thingy must be configured for notification
1214 if ( !server.template configured_for_notifications< NotificationUUID >( config ) )
1216
1217 const std::pair< std::uint8_t, bool > result = (mixin.*F)( write_size, value );
1218
1219 if ( result.second )
1221
1222 return static_cast< std::uint8_t >( result.first );
1223 }
1224
1225 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1227 };
1228
1251 template < typename T, std::uint8_t (*F)( T ) >
1252 struct free_write_handler : details::value_handler_base
1253 {
1255 template < class Server, std::size_t ClientCharacteristicIndex >
1256 static std::uint8_t call_write_handler( std::size_t offset, std::size_t write_size, const std::uint8_t* value, const details::client_characteristic_configuration& , void* )
1257 {
1258 if ( offset != 0 )
1259 return static_cast< std::uint8_t >( error_codes::attribute_not_long );
1260
1261 const std::pair< std::uint8_t, T > deserialized_value = details::deserialize< T >( write_size, value );
1262
1263 if ( deserialized_value.first != error_codes::success )
1264 return deserialized_value.first;
1265
1266 return (*F)( deserialized_value.second );
1267 }
1268
1269 struct meta_type : details::value_handler_base::meta_type, details::characteristic_value_write_handler_meta_type {};
1271 };
1272
1278}
1279
1280#endif
a very simple device to bind a characteristic to a global variable to provide access to the character...
Definition: characteristic_value.hpp:254
Root of the declaration of a GATT server.
Definition: server.hpp:85
@ out_of_range
Definition: codes.hpp:256
@ success
Definition: codes.hpp:154
@ write_not_permitted
Definition: codes.hpp:169
@ attribute_not_long
Definition: codes.hpp:209
@ invalid_attribute_value_length
Definition: codes.hpp:219
@ cccd_improperly_configured
Definition: codes.hpp:269
@ read_not_permitted
Definition: codes.hpp:164
the basic security attributes of a connection
Definition: pairing_status.hpp:24
a constant string characteristic with the value Name
Definition: characteristic_value.hpp:487
a constant string characteristic value
Definition: characteristic_value.hpp:429
A fixed length and fixed value, read-only characteristic value.
Definition: characteristic_value.hpp:511
provides a characteristic with a fixed, read-only value
Definition: characteristic_value.hpp:345
binds a free function as a write handler for the given characteristic
Definition: characteristic_value.hpp:815
binds a free function as a read handler for the given characteristic
Definition: characteristic_value.hpp:692
binds a free function as a read handler for the given characteristic
Definition: characteristic_value.hpp:735
binds a free function as a write handler for the given characteristic
Definition: characteristic_value.hpp:778
binds a free function as a write handler for the given characteristic
Definition: characteristic_value.hpp:1253
queues a indication of a characteristic as soon, as it was configured for indication.
Definition: characteristic_value.hpp:151
adds the ability to indicate this characteristic.
Definition: characteristic_value.hpp:110
Definition: characteristic_value.hpp:1114
Definition: characteristic_value.hpp:1071
Definition: characteristic_value.hpp:1132
Definition: characteristic_value.hpp:1093
characteristic value binding for a control point
Definition: characteristic_value.hpp:1159
characteristic value binding for a control point
Definition: characteristic_value.hpp:1198
class to be mixed into the server instance
Definition: mixin.hpp:78
if added as option to a characteristic, read access is removed from the characteristic
Definition: characteristic_value.hpp:47
if added as option to a characteristic, write access is removed from the characteristic
Definition: characteristic_value.hpp:69
queues a notification of a characteristic as soon, as it was configured for notification.
Definition: characteristic_value.hpp:127
adds the ability to notify this characteristic.
Definition: characteristic_value.hpp:89
set only the Write Without Response Characteristic Property bit.
Definition: characteristic_value.hpp:207
Definition: characteristic_value.hpp:845
Definition: characteristic_value.hpp:873
Definition: characteristic_value.hpp:859
Definition: characteristic_value.hpp:831
Definition: characteristic_value.hpp:903
Definition: characteristic_value.hpp:935
Definition: characteristic_value.hpp:919
Definition: characteristic_value.hpp:887
Definition: characteristic_value.hpp:965
Definition: characteristic_value.hpp:993
Definition: characteristic_value.hpp:979
Definition: characteristic_value.hpp:951
Definition: characteristic_value.hpp:1023
Definition: characteristic_value.hpp:1055
Definition: characteristic_value.hpp:1039
Definition: characteristic_value.hpp:1007
sets the Write Without Response Characteristic Property bit.
Definition: characteristic_value.hpp:190