Giter Site home page Giter Site logo

torstenrobitzki / bluetoe Goto Github PK

View Code? Open in Web Editor NEW
138.0 17.0 29.0 11.96 MB

C++ Framework to build Bluetooth LE Server (GATT)

License: MIT License

C++ 90.43% CMake 0.44% CoffeeScript 0.03% C 9.10%
bluetooth-low-energy c-plus-plus gatt-server ble gatt

bluetoe's Introduction

Bluetoe Build Status Join the chat at https://gitter.im/TorstenRobitzki/bluetoe Language grade: C/C++

Bluetoe Logo

Putin's Invasion of Ukraine

Please consider donating to one of the funds that help victims of the war in Ukraine:

Overview

Bluetoe implements a GATT server with a very low memory footprint and a convenient C++ interface. Bluetoe makes things easy but gives you the opportunity to fiddle with all the low-level GATT details if necessary. Bluetoe's primary target is very small microcontrollers. Here is a complete example of a small GATT server that allows a client to controll an IO pin, running on a nRF52832:

#include <bluetoe/server.hpp>
#include <bluetoe/device.hpp>
#include <nrf.h>

using namespace bluetoe;

// LED1 on a nRF52 eval board
static constexpr int io_pin = 17;

static std::uint8_t io_pin_write_handler( bool state )
{
    // On an nRF52 eval board, the pin is connected to the LED's cathode. This inverts the logic.
    NRF_GPIO->OUT = state
        ? NRF_GPIO->OUT & ~( 1 << io_pin )
        : NRF_GPIO->OUT | ( 1 << io_pin );

    return error_codes::success;
}

using blinky_server = server<
    service<
        service_uuid< 0xC11169E1, 0x6252, 0x4450, 0x931C, 0x1B43A318783B >,
        characteristic<
            requires_encryption,
            free_write_handler< bool, io_pin_write_handler >
        >
    >
>;

blinky_server gatt;

device< blinky_server > gatt_srv;

int main()
{
    // Init GPIO pin
    NRF_GPIO->PIN_CNF[ io_pin ] =
        ( GPIO_PIN_CNF_DRIVE_S0H1 << GPIO_PIN_CNF_DRIVE_Pos ) |
        ( GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos );

    for ( ;; )
        gatt_srv.run( gatt );
}

Documentation

http://torstenrobitzki.github.io/bluetoe/

L2CAP

Bluetoe ships with its own fully-usable link layer based on the nRF52832. The link layer implementation is based and tested on an abstract device called a scheduled radio, and should be easy to port to similar hardware. As Bluetoe is a GATT server implementation, only parts of the link layer relevant to GATT have been implemented. Bluetoe can be easily adapted to any other existing L2CAP implementation (those based on HCI, for example).

Current State

The following table shows the list of supported GATT procedures, along with and their current and planned implementation status:

Feature Sub-Procedure Status
Server Configuration Exchange MTU implemented
Primary Service Discovery Discover All Primary Services implemented

Discover Primary Service By Service UUID implemented
Relationship Discovery Find Included Services implemented

Declare Secondary Services implemented
Characteristic Discovery Discover All Characteristic of a Service implemented

Discover Characteristic by UUID implemented
Characteristic Descriptor Discovery Discover All Characteristic Descriptors implemented
Characteristic Value Read Read Characteristic Value implemented

Read Using Characteristic UUID implemented

Read Long Characteristic Value implemented

Read Multiple Characteristic Values implemented
Characteristic Value Write Write Without Response implemented

Signed Write Without Response not planned

Write Characteristic Value implemented

Write Long Characteristic Values implemented

Characteristic Value Reliable Writes implemented
Characteristic Value Notification Notifications implemented
Characteristic Value Indication Indications implemented
Characteristic Descriptor Value Read Read Characteristic Descriptors implemented

Read Long Characteristic Descriptors implemented
Characteristic Descriptor Value Write Write Characteristic Descriptors implemented

Write Long Characteristic Descriptors implemented
Cryptography Encryption implemented

Authentication planned

This is the current state of implemented Advertising Data:

Advertising Data Format Status
Service UUID Incomplete List of 16-bit Service UUIDs implemented

Complete List of 16-bit Service UUIDs implemented

Incomplete List of 32-bit Service UUIDs not planned

Complete List of 32-bit Service UUIDs not planned

Incomplete List of 128-bit Service UUIDs implemented

Complete List of 128-bit Service UUIDs implemented
Local Name Shortened Local Name implemented

Complete Local Name implemented
Flags Flags implemented
Manufacturer Specific Data Manufacturer Specific Data planned
TX Power Level TX Power Level planned
Secure Simple Pairing Out of Band not planned
Security Manager Out of Band not planned
Security Manager TK Value not planned
Slave Connection Interval Range not planned
Service Solicitation not planned
Service Data not planned
Appearance Appearance implemented
LE Role LE Role planned

This is the current state of the Link Layer implementation:

Aspect Feature Status
Roles Slave Role implemented

Master Role not planned
Advertising connectable undirected advertising implemented

connectable directed advertising implemented

non-connectable undirected advertising implemented

scannable undirected advertising implemented
Device Filtering implemented
Connections Single Connection implemented

Multiple Connection not planned
Connection Slave Latency planned
Feature Support LE Encryption implemented

Connection Parameters Request Procedure implemented

Extended Reject Indication planned

Slave-initiated Features Exchange planned

LE Ping implemented

LE Data Packet Length Extension planned

LL Privacy not planned

Extended Scanner Filter Policies not planned


Pull requests are welcome.

Dependencies

  • Boost for Unit tests
  • CMake for build
  • A decent C++ compiler supporting C++11

Current Measurements

All measurements were done without any traffic and a slave latency of 0. Average current was measured using various connection intervals.

nRF52840 blinky without encryption

  • Calibrated RC Sleep Clock (500ppm) (13608 Bytes binary size)

    • 546µA average at 7.5ms
    • 283µA average at 15ms
    • 155µA average at 30ms
  • Crystal Oscilator Sleep Clock (20ppm) (13364 Bytes binary size)

    • 526µA average at 7.5ms
    • 207µA average at 15ms
    • 143µA average at 30ms
    • 22.4µA average at 660ms

nRF52840 blinky with encryption

  • Calibrated RC Sleep Clock (500ppm) (22848 Bytes binary size)

    • 613µA average at 7.5ms
    • 211µA average at 30ms
    • 113µA average at 660ms
  • Crystal Oscilator Sleep Clock (20ppm) (22608 Bytes binary size)

    • 589µA average at 7.5ms
    • 197µA average at 30ms
  • Synthesized Sleep Clock (40ppm) (22596 Bytes binary size)

    • 1.09mA average at 7.5ms
    • 776µA average at 30ms
  • Old radio implementation (40ppm) (22212 Bytes binary size)

    • 1.08mA average at 7.5ms
    • 874µA average at 15ms
    • 770µA average at 30ms
    • 674µA average at 660ms

nRF52820 blinky with encryption

  • Calibrated RC Sleep Clock (500ppm / 1ms HFXO startup time) (21880 Bytes binary size)

    • 347µA average at 15ms
    • 217µA average at 30ms
    • 94µA average at 660ms
  • Calibrated RC Sleep Clock (500ppm / 0.3ms HFXO startup time) (21880 Bytes binary size)

    • 316µA average at 15ms
    • 103µA average at 660ms

bluetoe's People

Contributors

codecat avatar cvionis avatar gitter-badger avatar jonasknarbakk avatar kaofishy avatar lgtm-com[bot] avatar obruns avatar torstenrobitzki avatar xnlcasad avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bluetoe's Issues

MIC Error while receiving retransmitted PDU from Master

If the connection is encrypted, currently, if a the CRC of a received PDU is correct, but the MIC is incorrect, the last PDU is resent.

This might happen, if the master did not received the acknowledgment for a PDU and thus resends a PDU. In this case, the receive packet counter would have been incremented and would result in a MIC error computed by the radios CCM hardware. This case could be detected by looking at the PDUs sequence number. If that indicates that the PDU was resend, the MIC error is ok. Otherwise, the connection should be closed (if CRC is correct).

This applies to the current nrf51 binding.

link_layer::disconnect

link_layer::disconnect does not wait just until the send out PDU gets acknowledged, but until the connection timeout is reached.

Make Optional ATT PDUs Optional

Bluetoe implements currently all 4.2 ATT PDUs. If the optional PDUs could be disabled, the overall program size should become smaller.

Scan Response

Currently, a GATT server does not respond to a scan request.

catch wrong arguments

Passing an argument that is meant to be a parameter for a template should be caught as error when passing to an other template. For example when passing an appearance::mouse server option to a service, this should yield an error.

bluetoe::link_layer::buffer_sizes defaults depend on PDU layout

Currently, the default transmit and receive buffer size is 59, which is 2 * minimum PDU size + 1 to allow effective usage of pdu_ring_buffer<>. If the minimum PDU size is larger due to overhead between header and body (as for the nrf51/52), fragmentation can cause an exhausting of the buffer (when both pointers point in the middle of the buffer).

provide API for bonding

As bonds are stored persistent, Bluetoe can not store them but has to provide an API to store and retrieve bonding information. Following information must be stored / retrieved:

  • Peripheral MAC address
  • Central MAC address
  • Long Term Key
  • Identity Resolution Key
  • State of CCCDs
  • Optional: The last notified / indicated value of characteristics with CCCD
  • Method used to exchange LTKs (MITM protected, LESC, none...)
  • What else?

The API might require a template, where the Bluetoe could provide certain, compile time known values, like the number of CCCDs, etc.

Link Layer race condition?

while testing a bootloader example, there was a situation, where the ATT_write_request and ATT_write_reponse suddenly started to take place in a single connection event. The error code at the end of last ATT_write_request was 0x83 which is buffer_overrun_attempt on the application layer and indicates that the bootloader received more data the what was send from the bootloader client.

repeated_link_layer_pdus.pcapng.zip

Link Layer Encryption requires support for Pairing

Currently, it is not possible to have a GATT server, that requires_encryption and to run that on a binding, that does not support any pairing. There might be use cases, where a long term key might already exists and can be used without any required pairing.

Link Layer: Missing indication for Extended Reject Indication support

The link layer shows support for Connection Parameters Request Procedure. According to Core Spec 4.2: Vol. 6, Part B, 4.6.2:

A Controller that supports Connection Parameters Request Procedure shall support the following sections within this document:
• LL_REJECT_IND_EXT
...

The Bluetoe link layer indicates support for Connection Parameters Request Procedure, so it would also have to indicate support for Extended Reject Indication.

Compiling a simple example results in static assertion

I just built bluetoe code on my Ubuntu 18.04 box. The build went fine.

Next, I copied simple_server.cpp to mysvr.cpp in a new directory.

Here is my simple command to build it:
g++
-I$ThirdParty/bluetoe
-I$ThirdParty/bluetoe/bluetoe/utility/include
mysvr.cpp -o mysvr

I still need to link with libraries but that will come once I overcome my problem.

When I try to compile, I am getting the following assertion from server.hpp:

static_assert( number_of_client_configs != 0, "there is no characteristic that is configured for notification or indication" );

Is it something that I am doing wrong?

Thanks
Peter

Warning when using control point with "write without response" and ...

Applying the following options to a characteristic:

    bluetoe::characteristic<
        control_point_uuid,
        bluetoe::mixin_write_notification_control_point_handler<
            ble_handler,
            &ble_handler::control_point_write,
            control_point_uuid
        >,
        bluetoe::mixin_read_handler<
            ble_handler,
            &ble_handler::control_point_read
        >,
        bluetoe::notify,
        bluetoe::write_without_response,
        bluetoe::no_read_access
    >

results in a warning:

/Users/todi/ble_spi/bluetoe/bluetoe/characteristic.hpp:484:104: error: enum constant in boolean context [-Werror=int-in-bool-context]
                 count_by_meta_type< client_characteristic_configuration_parameter, Options... >::count ? 1 : 0 };
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~

This should not happen! Warning occurred, when adding the write_without_response option to the characteristic. client_characteristic_configuration_parameter has a meta type of client_characteristic_configuration_parameter, which seems to be not correct to me.

Read by Group Type Request should not return lists that contain gaps

In order for the GATT Discover All Primary Services procedure to work correctly, Read by Group Type Request should not return lists that contains gaps. Group Type Request is used to discover services, and can return only services of the same UUID length. If the server contains mixed 16-bit and 128-bit UUIDs, the server shall not assemble lists where two services are contain, where a service of the other kind would be in the middle.

For example, a server containing a 16-bit UUID service, followed by a 128-bit UUID service, followed by a 16-bit UUID service again, the server should not put both 16-bit UUID services into one Read by Group Type Response.

Decouple notification/indication_output from Client Characteristic Configuration

Right now server::notification_output()/server::indication_output() seems to check for CCCD bits regardless of whether it's actually used by the client, and from my understanding of the spec (3.3.3.3) it is entirely optional for either the client or the server to implement the descriptor (since a client can just drop the notification/indication if it doesn't want to handle it).

Nice to have for simple servers (also I had spent a few hours trying to figure out why I kept getting empty notifications and indications but that's neither here nor there).

better default buffer sizes

With the new SM update, hardware required overheads in the memory usage are introduced. The current default for buffer sizes just takes the protocol requirements into account.

This will lead to the need to manually define the buffer sizes, if the choosen hardware binding introduces an overhead.

In any case, there should be a default, that defines just the minimum buffer sizes for the choosen configuration.

may_require_encryption enforces encryption

Looks like may_require_encryption is not working as intended. If a server used the may_require_encryption option, every access to a characteristic value is responded with "Insufficient Authentication".

attribute_handle<> might cost ~600 byte flash memory

The new attribute_handle<> feature costs ~600 bytes in flash if applied on a small size example, even when the feature is not used. Maybe it is possible to create some short cuts that can be used when the feature is not used.

change CI

Travis CI seems to have a fixed maximum runtime of 10 minutes. Running make with -j results in build failures during the compilation of the tests (out of memory).

A new CI should:

  • enable us to build the tests with several compilers and versions.
  • build the documentation and store them on github.
  • let us install cross compilers (and required vendor-libraries) to build examples.
  • let us save the example binaries for beeing tested (minor).
  • should be affordable by our sponsor (~10€/Month).

If we host a CI server on our own, we could add additional hardware to do integration tests with different hardware bindings (but maybe this shouldn't be scope of this issue).

[nrf52] copy important functions to RAM

Idea: Maybe it could save some power to copy some of the functions that are involved in handling empty connection events to RAM to run fast (due to not having wait states) and thus to keep the CPU more in sleep.

advertising does not work on nrf52 when optimizations are enabled

If built with something different from -O0 device crashes with the below stack trace.

(gdb) bt
#0 0x00004568 in _exit ()
#1 0x000034a2 in abort ()
#2 0x000034c8 in __assert_func ()

#3 0x00002b70 in bluetoe::nrf51_details::scheduled_radio_base::schedule_advertisment (this=this@entry=0x2000012c <gatt_srv+156>, channel=channel@entry=38, advertising_data=..., response_data=...,
when=..., receive=...) at /Users/nlopezcasad/work/bluetoe/bluetoe/bindings/nrf51.cpp:307

#4 0x00000b5e in bluetoe::link_layer::details::advertiser<bluetoe::link_layer::link_layer<bluetoe::server<bluetoe::server_name<((char const*)(& blink_name))>, bluetoe::service<bluetoe::service_uuid<3
239143905ul, 25170u, 17488u, 37660u, 29977313048635ull>, bluetoe::characteristic<bluetoe::free_write_handler<bool, io_pin_write_handler> > > >, bluetoe::nrf51_details::scheduled_radio>, std::tuple<>,
std::tuplebluetoe::link_layer::connectable_undirected_advertising >::handle_adv_timeout(void) (this=0x20000154 <gatt_srv+196>)
at /Users/nlopezcasad/work/bluetoe/examples/nrf52/../../bluetoe/link_layer/advertising.hpp:979

#5 0x0000314a in bluetoe::nrf51_details::scheduled_radio_base::run (this=this@entry=0x2000012c <gatt_srv+156>) at /Users/nlopezcasad/work/bluetoe/bluetoe/bindings/nrf51.cpp:662

#6 0x0000160a in bluetoe::link_layer::link_layer<bluetoe::server<bluetoe::server_name<(char const*)(&blink_name)>, bluetoe::service<bluetoe::service_uuid<3239143905ul, 25170u, 17488u, 37660u, 2997731
3048635ull>, bluetoe::characteristic<bluetoe::free_write_handler<bool, io_pin_write_handler> > > >, bluetoe::nrf51_details::scheduled_radio>::run (this=0x20000090 <gatt_srv>, server=...)
at /Users/nlopezcasad/work/bluetoe/examples/nrf52/../../bluetoe/link_layer/link_layer.hpp:390

#7 main () at /Users/nlopezcasad/work/bluetoe/examples/nrf52/blinky.cpp:42
(gdb)

Characteristics discovery not working with server::l2cap_input

Hi there,

I'm trying to use your library through an HCI host, basically I'm instantiating a bluetoe::server class and pass the advertising and L2CAP data back and forth with my own link layer through l2cap_input. I've got advertising working, and I can connect and discover all the services, however I have not been able to get characteristics discovery working. When an client sends Read By Type Request with 0x2803 for characteristics declarations, the server instance invariably returns an error response with code 0x0a (Attribute Not Found).

I have tried all the server examples and none of them seems to work.

Tony

error: ambiguous template instantiation for ...

using arm-none-eabi-gcc version 8.3.1 20190703, with C++ version 17 or 2a, the following snipped:

#include <bluetoe/server.hpp>
#include <bluetoe/service.hpp>
#include <bluetoe/characteristic.hpp>

using s = typename bluetoe::details::remove_if_equal<
    std::tuple<
        std::tuple<
            bluetoe::details::characteristic_declaration_parameter,
            bluetoe::characteristic_uuid<745866312, 46925, 19597, 45443, 208696923798549>,
            bluetoe::details::empty_meta_type<bluetoe::details::characteristic_declaration_parameter>
        >,
        std::tuple<
            bluetoe::details::characteristic_value_declaration_parameter,
            bluetoe::characteristic_uuid<745866312, 46925, 19597, 45443, 208696923798549>,
            bluetoe::fixed_uint8_value<8>
        >,
        std::tuple<bluetoe::details::characteristic_user_description_parameter>,
        std::tuple<bluetoe::details::client_characteristic_configuration_parameter>,
        std::tuple<bluetoe::details::descriptor_parameter>
    >,
    std::tuple<bluetoe::details::wildcard>
>::type;

results in the following error message:

/Users/todi/bootloader_poc/bluetoe/bluetoe/utility/include/bluetoe/meta_tools.hpp: In instantiation of 'struct bluetoe::details::remove_if_equal<std::tuple<std::tuple<bluetoe::details::characteristic_user_description_parameter>, std::tuple<bluetoe::details::client_characteristic_configuration_parameter>, std::tuple<bluetoe::details::descriptor_parameter> >, std::tuple<bluetoe::details::wildcard> >':
/Users/todi/bootloader_poc/bluetoe/bluetoe/utility/include/bluetoe/meta_tools.hpp:170:17:   recursively required from 'struct bluetoe::details::remove_if_equal<std::tuple<std::tuple<bluetoe::details::characteristic_value_declaration_parameter, bluetoe::characteristic_uuid<745866312, 46925, 19597, 45443, 208696923798549>, bluetoe::fixed_value<unsigned char, 8> >, std::tuple<bluetoe::details::characteristic_user_description_parameter>, std::tuple<bluetoe::details::client_characteristic_configuration_parameter>, std::tuple<bluetoe::details::descriptor_parameter> >, std::tuple<bluetoe::details::wildcard> >'
/Users/todi/bootloader_poc/bluetoe/bluetoe/utility/include/bluetoe/meta_tools.hpp:170:17:   required from 'struct bluetoe::details::remove_if_equal<std::tuple<std::tuple<bluetoe::details::characteristic_declaration_parameter, bluetoe::characteristic_uuid<745866312, 46925, 19597, 45443, 208696923798549>, bluetoe::details::empty_meta_type<bluetoe::details::characteristic_declaration_parameter> >, std::tuple<bluetoe::details::characteristic_value_declaration_parameter, bluetoe::characteristic_uuid<745866312, 46925, 19597, 45443, 208696923798549>, bluetoe::fixed_value<unsigned char, 8> >, std::tuple<bluetoe::details::characteristic_user_description_parameter>, std::tuple<bluetoe::details::client_characteristic_configuration_parameter>, std::tuple<bluetoe::details::descriptor_parameter> >, std::tuple<bluetoe::details::wildcard> >'
/Users/todi/bootloader_poc/source/bootloader.cpp:23:2:   required from here
/Users/todi/bootloader_poc/bluetoe/bluetoe/utility/include/bluetoe/meta_tools.hpp:170:17: error: ambiguous template instantiation for 'struct bluetoe::details::remove_if_equal<std::tuple<std::tuple<bluetoe::details::characteristic_user_description_parameter> >, std::tuple<bluetoe::details::wildcard> >'
         >::type type;
                 ^~~~

compilation terminated due to -Wfatal-errors.
With the same compiler, using C++ version 11 or 14 does not trigger this error.

general HCI layer

Connecting HCI over a generalized transport (USB, SPI, UART...) to a bluetoe::server<> instance.

We can start this on a separated branch. Separating the transport will help in making the part of the library testable. I would suggest to add new folders named hci to the ./bluetoe and ./tests folder.

I don't think that reusing bluetoe::link_layer::link_layer would make sense, when we are implementing L2CAP over HCI.

applying `server_name<>` as a service argument

applying server_name<> as a service argument does not yield a compilation error. Instead, the option in not applied and silently ignored.

If this option is given as an option to a service, this has to result in a compilation error.

Enable address sanitizer

Compiling and running all unit tests with clangs address sanitizer enabled flags some test as being bogus (-fsanitize=address). All tests should run with address sanitizer enabled, without any errors.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.