1#ifndef BLUETOE_SERVICES_BOOTLOADER_HPP 
    2#define BLUETOE_SERVICES_BOOTLOADER_HPP 
    4#include <bluetoe/service.hpp> 
    5#include <bluetoe/mixin.hpp> 
   19    namespace bootloader {
 
   23            struct handler_meta_type {};
 
   24            struct memory_region_meta_type {};
 
   25            struct page_size_meta_type {};
 
   32        template < std::
size_t PageSize >
 
   36            typedef details::page_size_meta_type meta_type;
 
   37            static constexpr std::size_t value = PageSize;
 
   47        template < std::u
intptr_t Start, std::u
intptr_t End >
 
   53        template < 
typename ... Regions >
 
   57        template < std::uintptr_t Start, std::uintptr_t End, 
typename ... Regions >
 
   60            static bool acceptable( std::uintptr_t start, std::uintptr_t end )
 
   62                return ( start >= Start && end <= End )
 
   66            typedef details::memory_region_meta_type meta_type;
 
   72            static bool acceptable( std::uintptr_t, std::uintptr_t )
 
   77            typedef details::memory_region_meta_type meta_type;
 
   84        template < 
typename UserHandler >
 
   87            typedef UserHandler                 user_handler;
 
   88            typedef details::handler_meta_type  meta_type;
 
   95        template < 
class Server >
 
  131            buffer_overrun_attempt
 
  156            template < std::
size_t PageSize >
 
  166                std::uint32_t free_size()
 const 
  168                    return state_ == filling
 
  173                template < 
class Handler >
 
  174                void set_start_address( std::uintptr_t address, Handler& h, std::uint32_t checksum, std::uint16_t cons )
 
  176                    assert( state_ == idle );
 
  178                    ptr_            = address % PageSize;
 
  179                    addr_           = address - ptr_;
 
  183                    h.read_mem( addr_, ptr_, &buffer_[ 0 ] );
 
  186                template < 
class Handler >
 
  187                std::size_t write_data( std::size_t write_size, 
const std::uint8_t* value, Handler& h )
 
  189                    assert( state_ == filling );
 
  190                    assert( ptr_ != PageSize );
 
  192                    const std::size_t copy_size = std::min( PageSize - ptr_, write_size );
 
  193                    std::copy( value, value + copy_size, &buffer_[ ptr_ ] );
 
  194                    crc_ = h.checksum32( &buffer_[ ptr_ ], copy_size, crc_ );
 
  198                    if ( ptr_ == PageSize )
 
  206                template < 
class Handler >
 
  207                bool flush( Handler& h )
 
  209                    if ( state_ != filling || ptr_ == 0 )
 
  215                    if ( PageSize !=  ptr_ )
 
  216                        h.read_mem( addr_ + ptr_, PageSize - ptr_, &buffer_[ ptr_ ] );
 
  218                    h.start_flash( addr_, &buffer_[ 0 ], PageSize );
 
  223                std::uint32_t crc()
 const 
  236                    return state_ == idle;
 
  239                std::uint16_t consecutive()
 const 
  250                std::uintptr_t  addr_;
 
  253                std::uint8_t    buffer_[ PageSize ];
 
  254                std::uint16_t   consecutive_;
 
  257            enum opcode : std::uint8_t
 
  268                undefined_opcode = 0xff
 
  271            enum data_code : std::uint8_t
 
  276            template < 
typename UserHandler, 
typename MemRegions, std::
size_t PageSize >
 
  277            class controller : 
public UserHandler
 
  281                    : opcode( undefined_opcode )
 
  285                    , in_flash_mode( false )
 
  292                std::uintptr_t read_address( 
const std::uint8_t* rend )
 
  294                    std::uintptr_t result = 0;
 
  295                    for ( 
const std::uint8_t* rbegin = rend + 
sizeof( std::uint8_t* ); rbegin != rend; --rbegin )
 
  297                        result = result << 8;
 
  298                        result |= *( rbegin -1 );
 
  304                std::pair< std::uint8_t, bool > bootloader_write_control_point( std::size_t write_size, 
const std::uint8_t* value )
 
  306                    if ( write_size < 1 )
 
  313                    case opc_get_version:
 
  317                            if ( write_size != 1 )
 
  320                            in_flash_mode = 
false;
 
  324                            for ( 
auto& buffer : buffers_ )
 
  330                            if ( write_size != 1 + 2 * 
sizeof( std::uint8_t* ) )
 
  333                                                 start_address = read_address( value +1 );
 
  334                            const std::uintptr_t end_address   = read_address( value +1 + 
sizeof( std::uint8_t* ) );
 
  336                            if ( start_address > end_address || !MemRegions::acceptable( start_address,end_address ) )
 
  339                            check_sum = this->public_checksum32( start_address, end_address - start_address );
 
  342                    case opc_start_flash:
 
  344                            if ( write_size != 1 + 
sizeof( std::uint8_t* ) )
 
  347                            start_address = read_address( value +1 );
 
  348                            check_sum     = this->checksum32( start_address );
 
  352                            in_flash_mode = 
true;
 
  354                            if ( !MemRegions::acceptable( start_address, start_address ) )
 
  357                            for ( 
auto& buffer : buffers_ )
 
  360                            buffers_[next_buffer_].set_start_address( start_address, *
this, check_sum, consecutive_ );
 
  365                            if ( !in_flash_mode )
 
  366                                return request_error( invalid_state );
 
  368                            if ( !buffers_[next_buffer_].flush( *
this ) )
 
  369                                return request_error( invalid_state );
 
  376                            if ( write_size != 1 + 
sizeof( std::uint8_t* ) )
 
  379                            const std::uintptr_t start_address = read_address( value +1 );
 
  381                            this->run( start_address );
 
  386                            if ( write_size != 1 )
 
  394                            error         = error_codes::success;
 
  395                            start_address = read_address( value +1 );
 
  396                            end_address   = read_address( value +1 + 
sizeof( std::uint8_t* ) );
 
  397                            check_sum     = this->checksum32( start_address );
 
  399                            if ( start_address > end_address || !MemRegions::acceptable( start_address,end_address ) )
 
  402                            if ( start_address != end_address )
 
  404                                this->data_indication_call_back();
 
  411                        return std::pair< std::uint8_t, bool >{ att_error_codes::invalid_opcode, 
false };
 
  417                std::uint8_t bootloader_read_control_point( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
 
  419                    assert( read_size >= 20 );
 
  420                    *out_buffer = opcode;
 
  424                    case opc_get_version:
 
  426                            const std::pair< const std::uint8_t*, std::size_t > version = this->get_version();
 
  427                            out_size = std::min( read_size, version.second + 1 );
 
  429                            *out_buffer = opc_get_version;
 
  430                            std::copy( version.first, version.first + out_size - 1, out_buffer + 1 );
 
  435                            bluetoe::details::write_32bit( out_buffer + 1, check_sum );
 
  436                            out_size = 
sizeof( std::uint8_t ) + 
sizeof( std::uint32_t );
 
  441                            std::uint8_t* out = out_buffer;
 
  443                            *out = 
sizeof( std::uint8_t* );
 
  445                            out = bluetoe::details::write_32bit( out, PageSize );
 
  446                            out = bluetoe::details::write_32bit( out, number_of_concurrent_flashs );
 
  448                            out_size = out - out_buffer;
 
  451                    case opc_start_flash:
 
  453                            std::uint8_t* out = out_buffer;
 
  455                            *out = read_size + 3;
 
  457                            out = bluetoe::details::write_32bit( out, buffers_[next_buffer_].crc() );
 
  459                            out_size = out - out_buffer;
 
  467                            std::uint8_t* out = out_buffer;
 
  469                            out = bluetoe::details::write_32bit( out, buffers_[next_buffer_].crc() );
 
  470                            out = bluetoe::details::write_16bit( out, buffers_[next_buffer_].consecutive() );
 
  472                            out_size = out - out_buffer;
 
  477                            std::uint8_t* out = out_buffer;
 
  479                            out = bluetoe::details::write_32bit( out, check_sum );
 
  480                            *out = 
static_cast< std::uint8_t 
>( error );
 
  483                            out_size = out - out_buffer;
 
  491                std::uint8_t bootloader_write_data( std::size_t write_size, 
const std::uint8_t* value )
 
  493                    if ( !in_flash_mode )
 
  494                        return no_operation_in_progress;
 
  496                    if ( write_size == 0 )
 
  499                    if ( buffers_[ next_buffer_ ].free_size() == 0 && !find_next_buffer( start_address ) )
 
  500                        return buffer_overrun_attempt;
 
  504                        const std::size_t moved = buffers_[ next_buffer_ ].write_data( write_size, value, *
this );
 
  508                        start_address   += moved;
 
  510                        if ( write_size && !find_next_buffer( start_address ) )
 
  511                            return buffer_overrun_attempt;
 
  517                std::uint8_t bootloader_read_data( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
 
  519                    if ( opcode == opc_read )
 
  521                        out_size  = std::min( read_size, end_address - start_address );
 
  523                        error     = this->public_read_mem( start_address, out_size, out_buffer );
 
  525                        if ( error == error_codes::success )
 
  527                            check_sum = this->checksum32( out_buffer, out_size, check_sum );
 
  528                            start_address += out_size;
 
  535                        if ( start_address == end_address || error != error_codes::success )
 
  537                            this->control_point_notification_call_back();
 
  541                            this->data_indication_call_back();
 
  548                std::uint8_t bootloader_progress_data( std::size_t read_size, std::uint8_t* out_buffer, std::size_t& out_size )
 
  550                    buffers_[used_buffer_].free();
 
  552                    assert( read_size >= out_size );
 
  554                    out_buffer = bluetoe::details::write_32bit( out_buffer, buffers_[used_buffer_].crc() );
 
  555                    out_buffer = bluetoe::details::write_16bit( out_buffer, buffers_[used_buffer_].consecutive() );
 
  558                    *out_buffer = read_size + 3;
 
  561                    used_buffer_ = ( used_buffer_ + 1 ) % number_of_concurrent_flashs;
 
  566                template < 
class Server >
 
  569                    server.template notify< progress_uuid >();
 
  572                template < 
class Server >
 
  573                void bootloader_control_point_notification( Server& server )
 
  575                    server.template notify< control_point_uuid >();
 
  578                template < 
class Server >
 
  579                void bootloader_data_indication( Server& server )
 
  581                    server.template indicate< data_uuid >();
 
  585                std::uint32_t free_size()
 const 
  587                    std::uint32_t result = 0;
 
  589                    for ( 
const auto& b : buffers_ )
 
  590                        result += b.free_size();
 
  595                bool find_next_buffer( std::size_t start_address )
 
  597                    const auto next = ( next_buffer_ + 1 ) % number_of_concurrent_flashs;
 
  599                    if ( buffers_[ next ].empty() )
 
  602                        buffers_[ next ].set_start_address( start_address, *
this, buffers_[ next_buffer_ ].crc(), consecutive_ );
 
  611                std::pair< std::uint8_t, bool > request_error( std::uint8_t code )
 
  613                    opcode          = undefined_opcode;
 
  614                    in_flash_mode   = 
false;
 
  616                    return std::pair< std::uint8_t, bool >{ code, 
false };
 
  620                std::uintptr_t                  start_address;
 
  621                std::uintptr_t                  end_address;
 
  623                std::uint32_t                   check_sum;
 
  626                static constexpr std::size_t    number_of_concurrent_flashs = 2;
 
  627                unsigned                        next_buffer_;
 
  628                unsigned                        used_buffer_;
 
  629                std::uint16_t                   consecutive_;
 
  630                flash_buffer< PageSize >        buffers_[number_of_concurrent_flashs];
 
  633            template < 
typename ... Options >
 
  634            struct calculate_service {
 
  635                using page_size    = 
typename bluetoe::details::find_by_meta_type< page_size_meta_type, Options... >::type;
 
  637                static_assert( !std::is_same< bluetoe::details::no_such_type, page_size >::value,
 
  638                    "Please use page_size<> to define the block size of the flash." );
 
  640                using mem_regions  = 
typename bluetoe::details::find_by_meta_type< memory_region_meta_type, Options... >::type;
 
  642                static_assert( !std::is_same< bluetoe::details::no_such_type, mem_regions >::value,
 
  643                    "Please use white_list or black_list, to define accessable memory regions." );
 
  645                using user_handler = 
typename bluetoe::details::find_by_meta_type< handler_meta_type, Options... >::type;
 
  647                static_assert( !std::is_same< bluetoe::details::no_such_type, user_handler >::value,
 
  648                    "To use the bootloader, please provide a handler<> that fullfiles the requirements documented with bootloader_handler_prototype." );
 
  650                using implementation = controller< typename user_handler::user_handler, mem_regions, page_size::value >;
 
  660                            implementation, &implementation::bootloader_read_control_point
 
  669                            implementation, &implementation::bootloader_write_data
 
  672                            implementation, &implementation::bootloader_read_data
 
  681                            implementation, &implementation::bootloader_progress_data
 
  691        template < 
typename UserHandler, 
typename MemRegions, std::
size_t PageSize >
 
  692        using controller = details::controller< UserHandler, MemRegions, PageSize >;
 
  728            void read_mem( std::uintptr_t address, std::size_t size, std::uint8_t* destination );
 
  733            std::uint32_t 
checksum32( std::uintptr_t start_addr, std::size_t size );
 
  738            std::uint32_t 
checksum32( 
const std::uint8_t* start_addr, std::size_t size, std::uint32_t old_crc );
 
  780    template < 
typename ... Options >
 
void end_flash(Server &srv)
inform the bootloader, that an asynchrone flash operations is finished
Definition: bootloader.hpp:96
 
error_codes
range of error codes that can be used by the user handler to indicate the cause of an error
Definition: bootloader.hpp:137
 
att_error_codes
error codes that are used by the bootloader on the ATT layer
Definition: bootloader.hpp:124
 
typename bootloader::details::calculate_service< Options... >::type bootloader_service
Implementation of a bootloader service.
Definition: bootloader.hpp:781
 
Prototype for a handler, that adapts the bootloader service to the actual hardware.
Definition: bootloader.hpp:700
 
void data_indication_call_back()
technical required function, that have to call bootloader_data_indication(), with the instance of the...
 
std::uint32_t public_checksum32(std::uintptr_t start_addr, std::size_t size)
version of checksum function, that will be directly called by the execution of the Get CRC procedure.
 
void control_point_notification_call_back()
technical required function, that have to call bootloader_control_point_notification(),...
 
std::uint32_t checksum32(std::uintptr_t start_addr)
 
std::pair< const std::uint8_t *, std::size_t > get_version()
 
bootloader::error_codes start_flash(std::uintptr_t address, const std::uint8_t *values, std::size_t size)
 
bootloader::error_codes run(std::uintptr_t start_addr)
 
std::uint32_t checksum32(const std::uint8_t *start_addr, std::size_t size, std::uint32_t old_crc)
 
std::uint32_t checksum32(std::uintptr_t start_addr, std::size_t size)
 
bootloader::error_codes public_read_mem(std::uintptr_t address, std::size_t size, std::uint8_t *destination)
 
bootloader::error_codes reset()
 
void read_mem(std::uintptr_t address, std::size_t size, std::uint8_t *destination)
 
A characteristic is a typed value that is accessable by a GATT client hosted by a GATT server.
Definition: characteristic.hpp:160
 
a 128-Bit UUID used to identify a service.
Definition: service.hpp:57
 
a service with zero or more characteristics
Definition: service.hpp:150
 
@ invalid_offset
Definition: codes.hpp:189
 
@ success
Definition: codes.hpp:154
 
@ application_error_start
Definition: codes.hpp:245
 
@ invalid_attribute_value_length
Definition: codes.hpp:219
 
requireded parameter to define, how the bootloader can access memory and flash
Definition: bootloader.hpp:85
 
denoting a memory range with it's start address and endaddress (exklusive)
Definition: bootloader.hpp:48
 
required parameter to define the size of a page
Definition: bootloader.hpp:34
 
a list of all memory regions that are flashable by the bootloader
Definition: bootloader.hpp:54
 
a 128-Bit UUID used to identify a characteristic.
Definition: characteristic.hpp:62
 
adds the ability to indicate this characteristic.
Definition: characteristic_value.hpp:110
 
Definition: characteristic_value.hpp:1071
 
Definition: characteristic_value.hpp:1093
 
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
 
adds the ability to notify this characteristic.
Definition: characteristic_value.hpp:89
 
sets the Write Without Response Characteristic Property bit.
Definition: characteristic_value.hpp:190