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;