1#ifndef BLUETOE_LINK_LAYER_L_L2CAP_SDU_BUFFER_HPP
2#define BLUETOE_LINK_LAYER_L_L2CAP_SDU_BUFFER_HPP
4#include <bluetoe/buffer.hpp>
5#include <bluetoe/codes.hpp>
6#include <bluetoe/bits.hpp>
17 template <
class BufferedRadio, std::
size_t MTUSize >
83 using layout =
typename BufferedRadio::layout;
86 static constexpr std::uint16_t pdu_type_mask = 0x0003;
87 static constexpr std::uint16_t pdu_type_link_layer = 0x0003;
88 static constexpr std::uint16_t pdu_type_start = 0x0002;
89 static constexpr std::uint16_t pdu_type_continuation = 0x0001;
91 static constexpr std::size_t header_size = BufferedRadio::header_size;
92 static constexpr std::size_t layout_overhead = BufferedRadio::layout_overhead;
93 static constexpr std::size_t l2cap_header_size = 4u;
94 static constexpr std::size_t overall_overhead = header_size + layout_overhead + l2cap_header_size;
95 static constexpr std::size_t ll_overhead = header_size + layout_overhead;
97 void add_to_receive_buffer(
const std::uint8_t*,
const std::uint8_t* );
100 std::uint8_t receive_buffer_[ MTUSize + overall_overhead ];
101 std::uint16_t receive_size_;
102 std::size_t receive_buffer_used_;
108 std::uint8_t transmit_buffer_[ MTUSize + overall_overhead ];
109 std::uint16_t transmit_size_;
110 std::size_t transmit_buffer_used_;
117 template <
class BufferedRadio >
118 class ll_l2cap_sdu_buffer< BufferedRadio, bluetoe::details::default_att_mtu_size > :
public BufferedRadio
128 static constexpr std::size_t header_size = BufferedRadio::header_size;
129 static constexpr std::size_t layout_overhead = BufferedRadio::layout_overhead;
130 static constexpr std::size_t l2cap_header_size = 4u;
131 static constexpr std::size_t overall_overhead = header_size + layout_overhead + l2cap_header_size;
132 static constexpr std::size_t ll_overhead = header_size + layout_overhead;
136 template <
class BufferedRadio, std::
size_t MTUSize >
137 ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::ll_l2cap_sdu_buffer()
139 , receive_buffer_used_( 0 )
140 , transmit_size_( 0 )
141 , transmit_buffer_used_( 0 )
145 template <
class BufferedRadio, std::
size_t MTUSize >
148 assert( payload_size <= MTUSize );
150 if ( transmit_buffer_used_ != 0 || transmit_size_ != 0 )
151 return {
nullptr, 0 };
153 return { transmit_buffer_, payload_size + overall_overhead };
156 template <
class BufferedRadio, std::
size_t MTUSize >
161 return this->allocate_transmit_buffer( payload_size + ll_overhead );
164 template <
class BufferedRadio, std::
size_t MTUSize >
167 const auto body = layout::body( buffer );
168 const std::size_t size = bluetoe::details::read_16bit( body.first ) + overall_overhead;
170 transmit_buffer_used_ = 0;
171 transmit_size_ = size;
176 template <
class BufferedRadio, std::
size_t MTUSize >
179 this->commit_transmit_buffer( buffer );
182 template <
class BufferedRadio, std::
size_t MTUSize >
188 if ( receive_buffer_used_ != 0 && receive_size_ == 0 )
189 return { receive_buffer_, receive_buffer_used_ };
191 for (
auto pdu = this->next_received(); pdu.size; pdu = this->next_received() )
193 const std::uint16_t header = layout::header( pdu );
194 const std::uint16_t type = header & pdu_type_mask;
197 if ( type == pdu_type_link_layer )
201 const auto body = layout::body( pdu );
202 const std::size_t body_size = body.second - body.first;
204 if ( type == pdu_type_start )
206 if ( body_size >= l2cap_header_size )
208 const std::uint16_t l2cap_size = bluetoe::details::read_16bit( body.first );
211 if ( l2cap_size + l2cap_header_size == body_size )
214 if ( l2cap_size <= MTUSize )
216 receive_size_ = l2cap_size + overall_overhead;
217 add_to_receive_buffer( pdu.buffer, pdu.buffer + pdu.size );
223 add_to_receive_buffer( body.first, body.second );
227 this->free_received();
230 if ( receive_buffer_used_ != 0 && receive_size_ == 0 )
231 return { receive_buffer_, receive_buffer_used_ };
234 return {
nullptr, 0 };
237 template <
class BufferedRadio, std::
size_t MTUSize >
240 const std::size_t copy_size = std::min< std::size_t >( receive_size_, end - begin );
242 std::copy( begin, end, &receive_buffer_[ receive_buffer_used_ ] );
243 receive_buffer_used_ += copy_size;
244 receive_size_ -= copy_size;
247 template <
class BufferedRadio, std::
size_t MTUSize >
248 void ll_l2cap_sdu_buffer< BufferedRadio, MTUSize >::try_send_pdus()
250 while ( transmit_size_ )
252 const bool first_fragment = transmit_buffer_used_ == 0;
256 const std::size_t overhead = first_fragment ? 0 : ll_overhead;
257 const auto buffer = this->allocate_transmit_buffer( std::min( transmit_size_ + overhead, this->max_tx_size() ) );
259 if ( buffer.size == 0 )
262 if ( first_fragment )
265 const auto copy_size = std::min< std::size_t >( buffer.size, transmit_size_ );
267 std::copy( &transmit_buffer_[ 0 ], &transmit_buffer_[ copy_size ], buffer.buffer );
268 layout::header( buffer, pdu_type_start | ( ( copy_size - ll_overhead ) << 8 ) );
270 transmit_size_ -= copy_size;
271 transmit_buffer_used_ += copy_size;
276 const auto body = layout::body( buffer );
277 const auto copy_size = std::min< std::size_t >( std::distance( body.first, body.second ), transmit_size_ );
279 std::copy( &transmit_buffer_[ transmit_buffer_used_ ], &transmit_buffer_[ transmit_buffer_used_+ copy_size ], body.first );
280 layout::header( buffer, pdu_type_continuation | ( copy_size << 8 ) );
282 transmit_size_ -= copy_size;
283 transmit_buffer_used_ += copy_size;
286 this->commit_transmit_buffer( buffer );
289 transmit_buffer_used_ = 0;
292 template <
class BufferedRadio, std::
size_t MTUSize >
295 if (receive_buffer_used_)
297 receive_buffer_used_ = 0;
302 this->free_received();
308 template <
class BufferedRadio >
311 return this->allocate_transmit_buffer( size + overall_overhead );
314 template <
class BufferedRadio >
317 return this->allocate_transmit_buffer( size + ll_overhead );
320 template <
class BufferedRadio >
323 return this->commit_transmit_buffer( buffer );
326 template <
class BufferedRadio >
329 return this->commit_transmit_buffer( buffer );
332 template <
class BufferedRadio >
335 return this->next_received();
338 template <
class BufferedRadio >
341 return this->free_received();
buffer responsible for fragment or defragment L2CAP SDUs
Definition: ll_l2cap_sdu_buffer.hpp:19
read_buffer allocate_l2cap_transmit_buffer(std::size_t payload_size)
allocate a L2CAP buffer that is ready to be filled by the L2CAP layer
Definition: ll_l2cap_sdu_buffer.hpp:146
void free_ll_l2cap_received()
removes the oldest PDU from the receive buffer.
Definition: ll_l2cap_sdu_buffer.hpp:293
write_buffer next_ll_l2cap_received()
returns the oldest link layer PDU or L2CAP SDU out of the receive buffer.
Definition: ll_l2cap_sdu_buffer.hpp:183
read_buffer allocate_ll_transmit_buffer(std::size_t payload_size)
allocates a LL buffer that is suitable for the given payload size
Definition: ll_l2cap_sdu_buffer.hpp:157
typename BufferedRadio::layout layout
radio layout assumed by the buffer
Definition: ll_l2cap_sdu_buffer.hpp:83
void commit_l2cap_transmit_buffer(read_buffer buffer)
schedules the given buffer to be send by the radio
Definition: ll_l2cap_sdu_buffer.hpp:165
void commit_ll_transmit_buffer(read_buffer buffer)
schedules the given buffer to be send by the radio
Definition: ll_l2cap_sdu_buffer.hpp:177
type suitable to store the location and size of a chunk of memory that can be used to receive from th...
Definition: buffer.hpp:18
type suitable to store the location and size of a chunk of memory that can be used to transmit to the...
Definition: buffer.hpp:85