BlueToe
an alternative GATT/BLE implementation
Loading...
Searching...
No Matches
ll_data_pdu_buffer.hpp
1#ifndef BLUETOE_LINK_LAYER_LL_DAAT_BUFFER_HPP
2#define BLUETOE_LINK_LAYER_LL_DAAT_BUFFER_HPP
3
4#include <cstdlib>
5#include <cstdint>
6#include <cassert>
7#include <initializer_list>
8#include <algorithm>
9
10#include <bluetoe/default_pdu_layout.hpp>
11#include "ring_buffer.hpp"
12
13namespace bluetoe {
14namespace link_layer {
15
36 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
38 {
39 public:
44
51
55 static constexpr std::size_t size = TransmitSize + ReceiveSize;
56
60 static constexpr std::size_t min_buffer_size = 29;
61
65 static constexpr std::size_t max_buffer_size = 251;
66
70 static constexpr std::size_t header_size = 2u;
71
75 static constexpr std::size_t layout_overhead = layout::data_channel_pdu_memory_size( 0 ) - header_size;
76
77 static_assert( TransmitSize >= layout_overhead + min_buffer_size,
78 "TransmitSize should at least be large enough to store one L2CAP PDU plus overheader required by the hardware." );
79
80 static_assert( ReceiveSize >= layout_overhead + min_buffer_size,
81 "ReceiveSize should at least be large enough to store one L2CAP PDU plus overheader required by the hardware." );
82
93 constexpr std::size_t max_max_rx_size() const
94 {
95 return ReceiveSize - layout_overhead;
96 }
97
103 std::size_t max_rx_size() const;
104
116 void max_rx_size( std::size_t max_size );
117
123 constexpr std::size_t max_max_tx_size() const
124 {
125 return TransmitSize - ( layout::data_channel_pdu_memory_size( 0 ) - 2 );
126 }
127
133 std::size_t max_tx_size() const;
134
146 void max_tx_size( std::size_t max_size );
147
161 std::uint8_t* raw_pdu_buffer();
162
170
181
201
206
219
224
242
249
252 protected:
270
280
290
300 private:
301 // transmit buffer followed by receive buffer at buffer_[ TransmitSize ]
302 std::uint8_t buffer_[ size ];
303
305 volatile std::size_t max_rx_size_;
306
308 volatile std::size_t max_tx_size_;
309
310 bool sequence_number_;
311 bool next_expected_sequence_number_;
312 uint8_t empty_[ layout::data_channel_pdu_memory_size( 0 ) ];
313 bool next_empty_;
314 bool empty_sequence_number_;
315
316 static constexpr std::size_t ll_header_size = 2;
317 static constexpr std::uint8_t more_data_flag = 0x10;
318 static constexpr std::uint8_t sn_flag = 0x8;
319 static constexpr std::uint8_t nesn_flag = 0x4;
320 static constexpr std::uint8_t ll_empty_id = 0x01;
321
322
323 const std::uint8_t* transmit_buffer() const
324 {
325 return &buffer_[ 0 ];
326 }
327
328 std::uint8_t* transmit_buffer()
329 {
330 return &buffer_[ 0 ];
331 }
332
333 const std::uint8_t* receive_buffer() const
334 {
335 return &buffer_[ TransmitSize ];
336 }
337
338 std::uint8_t* receive_buffer()
339 {
340 return &buffer_[ TransmitSize ];
341 }
342
343 write_buffer set_next_expected_sequence_number( read_buffer ) const;
344
345 void acknowledge( bool sequence_number );
346 };
347
348 // implementation
349 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
351 : receive_buffer_( receive_buffer() )
352 , transmit_buffer_( transmit_buffer() )
353 {
354 layout::header( empty_, 0 );
356 }
357
358 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
360 {
361 return max_rx_size_;
362 }
363
364 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
366 {
367 assert( max_size >= min_buffer_size );
368 assert( max_size <= max_buffer_size );
369 assert( max_size <= ReceiveSize - layout_overhead );
370
371 max_rx_size_ = max_size;
372 }
373
374 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
376 {
377 return max_tx_size_;
378 }
379
380 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
382 {
383 assert( max_size >= min_buffer_size );
384 assert( max_size <= max_buffer_size );
385 assert( max_size <= TransmitSize - layout_overhead );
386
387 max_tx_size_ = max_size;
388 }
389
390 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
392 {
393 max_rx_size_ = min_buffer_size;
394 receive_buffer_.reset( receive_buffer() );
395
396 max_tx_size_ = min_buffer_size;
397 transmit_buffer_.reset( transmit_buffer() );
398
399 sequence_number_ = false;
400 next_expected_sequence_number_ = false;
401 next_empty_ = false;
402 }
403
404 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
406 {
407 return &buffer_[ 0 ];
408 }
409
410 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
412 {
413 typename Radio::lock_guard lock;
414
415 return transmit_buffer_.alloc_front( transmit_buffer(), size );
416 }
417
418 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
420 {
421 static constexpr std::uint8_t header_rfu_mask = 0xe0;
422 static_cast< void >( header_rfu_mask );
423
424 // make sure, no NFU bits are set
425 std::uint16_t header = layout::header( pdu );
426 assert( ( header & header_rfu_mask ) == 0 );
427
428 typename Radio::lock_guard lock;
429
430 // add sequence number
431 if ( sequence_number_ )
432 {
433 header |= sn_flag;
434 layout::header( pdu, header );
435 }
436
437 sequence_number_ = !sequence_number_;
438
439 transmit_buffer_.push_front( transmit_buffer(), pdu );
440 }
441
442 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
444 {
445 return transmit_buffer_.next_end().size != 0;
446 }
447
448 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
450 {
451 // insert the next expected sequence for every attempt to send the PDU, because it could be that
452 // the peripheral is able to receive data, while the central is not able to.
453 std::size_t header = layout::header( buf );
454
455 header = next_expected_sequence_number_
456 ? ( header | nesn_flag )
457 : ( header & ~nesn_flag );
458
459 layout::header( buf, header );
460
461 return write_buffer( buf );
462 }
463
464 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
466 {
467 const read_buffer next = transmit_buffer_.next_end();
468
469 if ( next_empty_ )
470 {
471 // if an empty buffer have to be resend, flag that there is more data
472 if ( next.size )
473 {
474 const std::uint16_t header = layout::header( next ) | more_data_flag;
475 layout::header( next, header );
476 }
477
478 return set_next_expected_sequence_number( read_buffer{ &empty_[ 0 ], sizeof( empty_ ) } );
479 }
480 else if ( next.size == 0 )
481 {
482 // we created an PDU, so it has to have a new sequnce number
483 const std::uint16_t header = sequence_number_
484 ? sn_flag + ll_empty_id
485 : ll_empty_id;
486
487 layout::header( empty_, header );
488 next_empty_ = true;
489
490 // keep sequence number of empty in mind and increment sequence_number_
491 empty_sequence_number_ = sequence_number_;
492 sequence_number_ = !sequence_number_;
493
494 return set_next_expected_sequence_number( read_buffer{ &empty_[ 0 ], sizeof( empty_ ) } );
495 }
496
497 if ( transmit_buffer_.more_than_one() )
498 layout::header( next, layout::header( next ) | more_data_flag );
499
500 return set_next_expected_sequence_number( next );
501 }
502
503 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
505 {
506 if ( next_empty_ )
507 {
508 if ( empty_sequence_number_ != nesn )
509 next_empty_ = false;
510 }
511 else
512 {
513 const read_buffer next = transmit_buffer_.next_end();
514
515 // the transmit buffer could be empty if we receive without sending prior. That happens during testing
516 if ( next.empty() )
517 return;
518
519 const std::uint16_t header = layout::header( next );
520 if ( static_cast< bool >( header & sn_flag ) != nesn )
521 {
522 transmit_buffer_.pop_end( transmit_buffer() );
523 static_cast< Radio* >( this )->increment_transmit_packet_counter();
524 }
525 }
526 }
527
528 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
530 {
531 return allocate_transmit_buffer( max_tx_size_ + layout_overhead );
532 }
533
534 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
536 {
537 typename Radio::lock_guard lock;
538
539 return write_buffer( receive_buffer_.next_end() );
540 }
541
542 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
544 {
545 typename Radio::lock_guard lock;
546
547 receive_buffer_.pop_end( receive_buffer() );
548 }
549
550 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
552 {
553 return receive_buffer_.alloc_front( const_cast< std::uint8_t* >( receive_buffer() ), layout::data_channel_pdu_memory_size( max_rx_size_ - ll_header_size ) );
554 }
555
556 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
558 {
559 const std::uint16_t header = layout::header( pdu );
560
561 // invalid LLID
562 if ( ( header & 0x3 ) != 0 )
563 {
564 acknowledge( header & nesn_flag );
565
566 // resent PDU?
567 if ( static_cast< bool >( header & sn_flag ) == next_expected_sequence_number_ )
568 {
569 next_expected_sequence_number_ = !next_expected_sequence_number_;
570
571 if ( ( header & 0xff00 ) != 0 )
572 {
573 receive_buffer_.push_front( receive_buffer(), pdu );
574 static_cast< Radio* >( this )->increment_receive_packet_counter();
575 }
576 }
577 }
578
579 return next_transmit();
580 }
581
582 template < std::size_t TransmitSize, std::size_t ReceiveSize, typename Radio >
584 {
585 const std::uint16_t header = layout::header( pdu );
586
587 // invalid LLID
588 if ( ( header & 0x3 ) != 0 )
589 {
590 acknowledge( header & nesn_flag );
591
592 // resent PDU?
593 if ( static_cast< bool >( header & sn_flag ) == next_expected_sequence_number_ )
594 {
595 next_expected_sequence_number_ = !next_expected_sequence_number_;
596 }
597 }
598
599 return next_transmit();
600 }
601
602}
603}
604
605#endif