1#ifndef BLUETOE_L2CAP_HPP
2#define BLUETOE_L2CAP_HPP
8#include <bluetoe/codes.hpp>
10#include <bluetoe/bits.hpp>
32 static constexpr std::uint16_t channel_id = 42;
33 static constexpr std::size_t minimum_channel_mtu_size = bluetoe::details::default_att_mtu_size;
34 static constexpr std::size_t maximum_channel_mtu_size = bluetoe::details::default_att_mtu_size;
36 template <
typename ConnectionData >
37 void l2cap_input(
const std::uint8_t* input, std::size_t in_size, std::uint8_t* output, std::size_t& out_size, ConnectionData& );
39 template <
typename ConnectionData >
40 void l2cap_output( std::uint8_t* output, std::size_t& out_size, ConnectionData& );
42 template <
class PreviousData >
43 using channel_data_t = PreviousData;
46 template <
typename CurrentMaximum,
typename Channel >
47 struct maximum_min_channel_mtu_size
51 ( CurrentMaximum::value > Channel::minimum_channel_mtu_size ),
53 std::integral_constant< std::size_t, Channel::minimum_channel_mtu_size >
57 template <
typename CurrentMaximum,
typename Channel >
58 struct maximum_max_channel_mtu_size
62 ( CurrentMaximum::value > Channel::maximum_channel_mtu_size ),
64 std::integral_constant< std::size_t, Channel::maximum_channel_mtu_size >
68 template <
typename ComposedData,
typename Channel >
69 struct add_channel_data
71 using type =
typename Channel::template channel_data_t< ComposedData >;
74 static constexpr std::size_t l2cap_layer_header_size = 4u;
96 template <
class LinkLayer,
class ChannelData,
class ... Channels >
97 class l2cap :
public derive_from< std::tuple< Channels... > >
103 template <
class ConnectionDetails >
104 bool handle_l2cap_input(
const std::uint8_t* input, std::size_t in_size, ConnectionDetails& connection );
110 template <
class ConnectionDetails >
111 void transmit_pending_l2cap_output( ConnectionDetails& connection );
118 static constexpr std::size_t minimum_mtu_size = fold<
119 std::tuple< Channels... >,
120 maximum_min_channel_mtu_size,
121 std::integral_constant< std::size_t, 0 >
124 static constexpr std::size_t maximum_mtu_size = fold<
125 std::tuple< Channels... >,
126 maximum_max_channel_mtu_size,
127 std::integral_constant< std::size_t, 0 >
130 static_assert( maximum_mtu_size >= minimum_mtu_size,
"maximum_mtu_size have to be greater than minimum_mtu_size" );
132 using connection_data_t =
typename fold<
133 std::tuple< Channels... >,
139 template <
class ConnectionDetails >
140 bool transmit_single_pending_l2cap_output( ConnectionDetails& connection );
142 template <
class ConnectionDetails >
143 struct l2cap_input_handler
145 l2cap_input_handler( l2cap* t, std::uint16_t ci,
const std::uint8_t* i, std::size_t is, std::uint8_t* o, std::size_t os, ConnectionDetails& c )
157 template<
typename Channel >
160 if ( channel_id == Channel::channel_id )
162 static_cast< Channel&
>( *that ).l2cap_input( input, in_size, output, out_size, connection );
168 std::uint16_t channel_id;
169 const std::uint8_t* input;
171 std::uint8_t* output;
172 std::size_t out_size;
173 ConnectionDetails& connection;
177 template <
typename ConnectionDetails >
178 class l2cap_output_handler
181 l2cap_output_handler( l2cap* t, std::uint8_t* out, std::size_t s, ConnectionDetails& c )
190 template<
typename Channel >
196 static_cast< Channel&
>( *that ).l2cap_output( output, out_size, connection );
197 channel_id = Channel::channel_id;
202 std::uint8_t* output;
204 std::size_t out_size;
205 std::uint16_t channel_id;
206 ConnectionDetails& connection;
209 LinkLayer& link_layer()
211 return static_cast< LinkLayer&
>( *this );
217 template <
class LinkLayer,
class ChannelData,
class ... Channels >
218 template <
class ConnectionDetails >
219 bool l2cap< LinkLayer, ChannelData, Channels... >::handle_l2cap_input(
const std::uint8_t* input, std::size_t in_size, ConnectionDetails& connection )
222 if ( in_size < l2cap_layer_header_size )
225 const std::uint16_t size = read_16bit( input );
226 const std::uint16_t channel_id = read_16bit( input + 2 );
228 if ( in_size != size + l2cap_layer_header_size )
231 auto output = link_layer().allocate_l2cap_output_buffer( maximum_mtu_size );
232 if ( output.first == 0 )
235 assert( output.second );
237 l2cap_input_handler< ConnectionDetails > handler(
238 this, channel_id, input + l2cap_layer_header_size, in_size - l2cap_layer_header_size,
239 output.second + l2cap_layer_header_size, maximum_mtu_size, connection );
241 for_< Channels... >::template each< l2cap_input_handler< ConnectionDetails >& >( handler );
243 if ( handler.handled && handler.out_size )
245 write_16bit( output.second, handler.out_size );
246 write_16bit( output.second + 2, channel_id );
247 link_layer().commit_l2cap_output_buffer( { handler.out_size + l2cap_layer_header_size, output.second } );
253 template <
class LinkLayer,
class ChannelData,
class ... Channels >
254 template <
class ConnectionDetails >
255 void l2cap< LinkLayer, ChannelData, Channels... >::transmit_pending_l2cap_output( ConnectionDetails& connection )
257 for (
bool cont = transmit_single_pending_l2cap_output( connection ); cont;
258 cont = transmit_single_pending_l2cap_output( connection ) )
262 template <
class LinkLayer,
class ChannelData,
class ... Channels >
263 template <
class ConnectionDetails >
264 bool l2cap< LinkLayer, ChannelData, Channels... >::transmit_single_pending_l2cap_output( ConnectionDetails& connection )
266 auto output = link_layer().allocate_l2cap_output_buffer( maximum_mtu_size );
267 if ( output.first == 0 )
270 assert( output.second );
272 l2cap_output_handler< ConnectionDetails > handler(
273 this, output.second + l2cap_layer_header_size, output.first - l2cap_layer_header_size, connection );
275 for_< Channels... >::template each< l2cap_output_handler< ConnectionDetails >& >( handler );
277 if ( handler.out_size )
279 write_16bit( output.second, handler.out_size );
280 write_16bit( output.second + 2, handler.channel_id );
281 link_layer().commit_l2cap_output_buffer( { handler.out_size + l2cap_layer_header_size, output.second } );
284 return handler.out_size;