BLE: Introduce GenericGattClient and platform abstraction over ATT/GATT.

This changes introduce a platform adaptation over ATT/GATT that can be implemented by porter.
Unlike the GattClient interface, the ATT/GATT adaptation is simple, follow closely the Bluetooth specification and won't change over time.
Implementation of the GattClient interface is realized by the class GenericGattClient which accept in input a pal::GattClient.

This change will also free design space once adopted by partners, addition to the GattClient interface won't require partner support.
pull/5060/head
Vincent Coubard 2017-09-08 10:55:31 +01:00
parent 38bb6b4e52
commit daaa5b1977
7 changed files with 4126 additions and 0 deletions

View File

@ -0,0 +1,154 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef MBED_BLE_GENERIC_GATT_CLIENT
#define MBED_BLE_GENERIC_GATT_CLIENT
#include <algorithm>
#include "ble/GattClient.h"
#include "ble/pal/PalGattClient.h"
// IMPORTANT: private header. Not part of the public interface.
namespace ble {
namespace generic {
// forward declarations
struct procedure_control_block_t;
struct discovery_control_block_t;
struct read_control_block_t;
struct write_control_block_t;
struct descriptor_discovery_control_block_t;
/**
* Generic implementation of the GattClient.
* It requires a pal::GattClient injected at construction site.
* @important: Not part of the public interface of BLE API.
*/
class GenericGattClient : public GattClient {
// give access to control block classes
friend struct procedure_control_block_t;
friend struct discovery_control_block_t;
friend struct read_control_block_t;
friend struct write_control_block_t;
friend struct descriptor_discovery_control_block_t;
public:
/**
* Create a GenericGattClient from a pal::GattClient
*/
GenericGattClient(pal::GattClient* pal_client);
/**
* @see GattClient::launchServiceDiscovery
*/
virtual ble_error_t launchServiceDiscovery(
Gap::Handle_t connection_handle,
ServiceDiscovery::ServiceCallback_t service_callback,
ServiceDiscovery::CharacteristicCallback_t characteristic_callback,
const UUID& matching_service_uuid,
const UUID& matching_characteristic_uuid
);
/**
* @see GattClient::isServiceDiscoveryActive
*/
virtual bool isServiceDiscoveryActive() const;
/**
* @see GattClient::terminateServiceDiscovery
*/
virtual void terminateServiceDiscovery();
/**
* @see GattClient::read
*/
virtual ble_error_t read(
Gap::Handle_t connection_handle,
GattAttribute::Handle_t attribute_handle,
uint16_t offset
) const;
/**
* @see GattClient::write
*/
virtual ble_error_t write(
GattClient::WriteOp_t cmd,
Gap::Handle_t connection_handle,
GattAttribute::Handle_t attribute_handle,
size_t length,
const uint8_t* value
) const;
/**
* @see GattClient::onServiceDiscoveryTermination
*/
virtual void onServiceDiscoveryTermination(
ServiceDiscovery::TerminationCallback_t callback
);
/**
* @see GattClient::discoverCharacteristicDescriptors
*/
virtual ble_error_t discoverCharacteristicDescriptors(
const DiscoveredCharacteristic& characteristic,
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
);
/**
* @see GattClient::isCharacteristicDescriptorDiscoveryActive
*/
virtual bool isCharacteristicDescriptorDiscoveryActive(
const DiscoveredCharacteristic& characteristic
) const;
/**
* @see GattClient::terminateCharacteristicDescriptorDiscovery
*/
virtual void terminateCharacteristicDescriptorDiscovery(
const DiscoveredCharacteristic& characteristic
);
/**
* @see GattClient::reset
*/
virtual ble_error_t reset(void);
private:
procedure_control_block_t* get_control_block(Gap::Handle_t connection);
const procedure_control_block_t* get_control_block(Gap::Handle_t connection) const;
void insert_control_block(procedure_control_block_t* cb) const;
void remove_control_block(procedure_control_block_t* cb) const;
void on_termination(Gap::Handle_t connection_handle);
void on_server_message_received(connection_handle_t, const pal::AttServerMessage&);
void on_server_response(connection_handle_t, const pal::AttServerMessage&);
void on_server_event(connection_handle_t, const pal::AttServerMessage&);
void on_transaction_timeout(connection_handle_t);
uint16_t get_mtu(Gap::Handle_t connection) const;
pal::GattClient* const _pal_client;
ServiceDiscovery::TerminationCallback_t _termination_callback;
mutable procedure_control_block_t* control_blocks;
};
}
}
#endif /* MBED_BLE_GENERIC_GATT_CLIENT */

View File

@ -0,0 +1,687 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BLE_PAL_ATTCLIENT_H_
#define BLE_PAL_ATTCLIENT_H_
#include "ble/UUID.h"
#include "ble/BLETypes.h"
#include "ble/ArrayView.h"
#include "ble/blecommon.h"
#include "platform/Callback.h"
#include "AttServerMessage.h"
namespace ble {
namespace pal {
/**
* Send attribute protocol requests to an ATT server. It also handle reception
* of ATT response and server indication/notification.
*
* Every request send and response or response event received is for a specified
* connection.
*
* @warning This class should not be used outside mbed BLE, availability is not
* guaranteed for all ports.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F
*/
struct AttClient {
/**
* Initialization of the instance. An implementation can use this function
* to initialise the subsystems needed to realize the ATT operations of this
* interface.
*
* This function has to be called before any other operations.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*/
virtual ble_error_t initialize() = 0;
/**
* Termination of the instance. An implementation can use this function
* to release the subsystems initialised to realise the ATT operations of
* this interface.
*
* After a call to this function, initialise should be called again to
* allow usage of the interface.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*/
virtual ble_error_t terminate() = 0;
/**
* Send an exchange MTU request which negotiate the size of the MTU used by
* the connection.
*
* First the client send to the server the maximum rx mtu that it can receive
* then the client reply with the maximum rx mtu it can receive.
*
* The mtu choosen for the connection is the minimum of the client Rx mtu
* and server Rx mtu values.
*
* If an error occured then the mtu used remains the default value.
*
* @param connection The handle of the connection to send this request to.
*
* @return BLE_ERROR_NONE if the request has been succesfully sent or the
* appropriate error otherwise.
*
* @see ble::pal::AttExchangeMTUResponse The type of response received from
* the server
* @see ble::pal::AttErrorResponse::REQUEST_NOT_SUPPORTED The error code
* returned by the server in case of error.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.2.1
*/
virtual ble_error_t exchange_mtu_request(connection_handle_t connection) = 0;
/**
* Acquire the size of the mtu for a given connection.
*
* @param connection The handle of the connection for which the the MTU size
* should be acquired.
*
* @param mtu_size Output parameter which will contain the MTU size.
*
* @return BLE_ERROR_NONE if the MTU size has been acquired or the
* appropriate error otherwise.
*/
virtual ble_error_t get_mtu_size(
connection_handle_t connection_handle,
uint16_t& mtu_size
) = 0;
/**
* Send a find information request to a server in order to obtain the
* mapping of attribute handles with their associated types.
*
* The server will reply with a ble::pal::AttFindInformationResponse
* containing at least one [attribute handle, attribute type] pair. If the
* last handle in the response is not equal to the end handle of the finding
* range then this request can be issued again with an updated range (begin
* equal to last handle received + 1) to discover the remaining attributes.
*
* To discover the whole ATT server, the first find information request
* should have a discovery range of [0x0001 - 0xFFFF].
*
* The server can send a ble::pal::AttErrorResponse with the code
* ble::pal::AttErrorResponse::ATTRIBUTE_NOT_FOUND if no attributes have
* been found in the range specified. The attribute handle in the response
* is then equal to the first handle of the discovery range.
*
* If the range is malformed the server will reply a
* ble::pal::AttErrorResponse with the error code ble::pal::INVALID_HANDLE.
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param discovery_range The attribute range where handle-type informations
* should be discovered.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.3.1
*/
virtual ble_error_t find_information_request(
connection_handle_t connection_handle,
attribute_handle_range_t discovery_range
) = 0;
/**
* Send a Find By Type Value Request which retrieve the handles of attributes
* that have known 16-bit UUID attribute type and known attribute value.
*
* The server should reply with a ble::pal::AttFindByTypeValueResponse
* containing the handle (or handle range in case of grouping attributes) of
* the attribute found.
*
* If not all attributes can be contained in the response it is necessary to
* send again this request with an updated range to continue the discovery.
*
* The server can send a ble::pal::AttErrorResponse with the code
* ble::pal::AttErrorResponse::ATTRIBUTE_NOT_FOUND if no attributes have
* been found in the range specified. The attribute handle in the response
* is then equal to the first handle of the discovery range.
*
* If the range is malformed the server will reply a
* ble::pal::AttErrorResponse with the error code ble::pal::INVALID_HANDLE.
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param discovery_range The handle range where attributes with type and
* value are searched.
* @param type The type of attribute to find (it is a 16 bit UUID).
* @param value The value of the attributes to found.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.3.3
*/
virtual ble_error_t find_by_type_value_request(
connection_handle_t connection_handle,
attribute_handle_range_t discovery_range,
uint16_t type,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send a Read By Type Request used to obtain the values of attributes where
* the attribute type is known but the handle is not known.
*
* If attributes with the type requested are present in the range, the server
* should reply with a ble::pal::AttReadByTypeResponse. If the response does
* not cover the full range, the request should be sent again with an updated
* range.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::ATTRIBUTE_NOT_FOUND: If there is no
* attributes matching type in the range.
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If the range is
* invalid.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption.
* - ble::pal::AttErrorResponse::READ_NOT_PERMITTED: If the attribute
* value cannot be read.
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param read_range The handle range where attributes with the given type
* should be read.
* @param type The type of attributes to read.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.1
*/
virtual ble_error_t read_by_type_request(
connection_handle_t connection_handle,
attribute_handle_range_t read_range,
const UUID& type
) = 0;
/**
* Send a Read Request to read the value of an attribute in the server.
*
* In case of success, the server will reply with a ble::pal::AttReadResponse.
* containing the value of the attribute. If the length of the value in the
* response is equal to (mtu - 1) then the remaining part of the value can
* be obtained by a read_blob_request.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If the attribute handle
* is invalid.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption.
* - ble::pal::AttErrorResponse::READ_NOT_PERMITTED: If the attribute
* value cannot be read.
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handle The handle of the attribute to read.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.3
*/
virtual ble_error_t read_request(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle
) = 0;
/**
* Send a read blob request to a server to read a part of the value of an
* attribute at a given offset.
*
* In case of success, the server will reply with a ble::pal::AttReadBlobResponse
* containing the value read. If the value of the attribute starting at the
* offset requested is longer than (mtu - 1) octets then only the first
* (mtu - 1) octets will be present in the response.
* The remaining octets can be acquired by another Read Blob Request with an
* updated index.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If the attribute handle
* is invalid.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption.
* - ble::pal::AttErrorResponse::READ_NOT_PERMITTED: If the attribute
* value cannot be read.
* - ble::pal::AttErrorResponse::INVALID_OFFSET: If the offset is greater
* than the attribute length.
* - ble::pal::AttErrorResponse::ATTRIBUTE_NOT_LONG: If the attribute
* value has a length that is less than or equal to (mtu - 1).
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handle The handle of the attribute to read.
* @param offset The offset of the first octet to read.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.5
*/
virtual ble_error_t read_blob_request(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
uint16_t offset
) = 0;
/**
* Send a read multiple request to the server. It is used to read two or more
* attributes values at once.
*
* In case of success, the server will reply with a
* ble::pal::AttReadMultipleResponse containing the concatenation of the
* values read. Given that values are concatained, all attributes values
* should be of fixed size except for the last one. The concatained value
* is also truncated to (mtu - 1) if it doesn't fit in the response.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If any of the attribute
* handle is invalid.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient to read any of the attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient to read any of the attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size to read any of the
* attributes.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption required to read any of the attributes.
* - ble::pal::AttErrorResponse::READ_NOT_PERMITTED: If any of the
* attributes value cannot be read.
* The first attribute causing the error is reporter in the handle_in_error
* field in the error response.
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handles Set of attribute handles to read.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.7
*/
virtual ble_error_t read_multiple_request(
connection_handle_t connection_handle,
const ArrayView<const attribute_handle_t>& attribute_handles
) = 0;
/**
* Send a read by group type request to the server. It is used to get
* informations about grouping attribute of a given type on a server.
*
* The server will reply with a ble::pal::ReadByGroupTypeResponse containing
* informations about the grouping attribute found. Informations are:
* - handle of the grouping attribute.
* - last handle of the group .
* - attribute value.
*
* If the last handle received is not the last handle of the discovery range
* then it is necessary to send another request with a discovery range
* updated to: [last handle + 1 : end].
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If the range of handle
* provided is invalid.
* - ble::pal::AttErrorResponse::UNSUPPORTED_GROUP_TYPE: if the group type
* is not a supported grouping attribute.
* - ble::pal::AttErrorResponse::ATTRIBUTE_NOT_FOUND: If no attribute with
* the given type exists within the range provided.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient to read the requested attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient to read the requested attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size to read the requested
* attributes.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption required to read the requested attributes.
* - ble::pal::AttErrorResponse::READ_NOT_PERMITTED: If any of the
* attributes value cannot be read.
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param read_range Range where this request apply.
* @param group_type Type of the grouping attribute to find and read.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.9
*/
virtual ble_error_t read_by_group_type_request(
connection_handle_t connection_handle,
attribute_handle_range_t read_range,
const UUID& group_type
) = 0;
/**
* Send a write request to the server to write the value of an attribute.
*
* In case of success, the server will reply with a
* ble::pal::AttWriteResponse to acknowledge that the write operation went
* well.
*
* If the attribute value has a variable length, then the attribute value
* shall be truncated or lengthened to match the length of the value in the
* request.
*
* If the attribute value has a fixed length and the Attribute Value parameter length
* is less than or equal to the length of the attribute value, the octets of the
* attribute value parameter length shall be written; all other octets in this attribute
* value shall be unchanged.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If the handle to write is
* invalid.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient to write the requested attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient to write the requested attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size to write the requested
* attributes.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption required to write the requested attributes.
* - ble::pal::AttErrorResponse::WRITE_NOT_PERMITTED: If the attribute
* value cannot be written due to permission.
* - ble::pal::AttErrorResponse::INVALID_ATTRIBUTE_VALUE_LENGTH: If the
* value to write exceeds the maximum valid length or of the attribute
* value; whether the attribute has a variable length value or a fixed
* length value.
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handle Handle of the attribute to write.
* @param value Value to write. It can't be longer than (mtu - 3).
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.5.1
*/
virtual ble_error_t write_request(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send a write command to the server. A write command is similar to a write
* request except that it won't receive any response from the server
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handle Handle of the attribute to write.
* @param value Value to write. It can't be longer than (mtu - 3).
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.5.3
*/
virtual ble_error_t write_command(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send a signed write command to the server. Behaviour is similar to a write
* command except that 12 bytes of the mtu are reserved for the authentication
* signature.
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handle Handle of the attribute to write.
* @param value Value to write. It can't be longer than (mtu - 15).
*
* @note the authentication signature to send with this request is
* computed by the implementation following the rules defined in BLUETOOTH
* SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.3.1.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.5.4
*/
virtual ble_error_t signed_write_command(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
const ArrayView<const uint8_t>& value
) = 0;
/**
* The Prepare Write Request is used to request the server to prepare to
* write the value of an attribute. The client can send multiple prepare
* write request which will be put in a queue until the client send an
* Execute Write Request which will execute sequentially the write request
* in the queue.
*
* In case of success the server will respond with a
* ble::pal::AttPrepareWriteResponse containing the values (attribute handle,
* offset and value) present in the write request.
*
* If a prepare write request is rejected by the server, the state queue of
* the prepare write request queue remains unaltered.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_HANDLE: If the handle to write is
* invalid.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHENTICATION: If the client
* security is not sufficient to write the requested attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_AUTHORIZATION: If the client
* authorization is not sufficient to write the requested attribute.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION_KEY_SIZE: If the
* client has an insufficient encryption key size to write the requested
* attributes.
* - ble::pal::AttErrorResponse::INSUFFICIENT_ENCRYPTION: If the client
* has not enabled encryption required to write the requested attributes.
* - ble::pal::AttErrorResponse::WRITE_NOT_PERMITTED: If the attribute
* value cannot be written due to permission.
* - ble::pal::PREPARE_QUEUE_FULL: If the queue of prepare write request
* is full.
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param attribute_handle The handle of the attribute to be written.
* @param offset The offset of the first octet to be written.
* @param value The value of the attribute to be written. It can't be longer
* than (mtu - 5).
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.6.1
*
*/
virtual ble_error_t prepare_write_request(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
uint16_t offset,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send an Execute Write Request to the server. This request will instruct
* the server to execute or cancel the prepare write requests currently held
* in the prepare queue from this client.
*
* If the execute parameter is set to true, the server should execute the
* request held in the queue. If the parameter is equal to false then the
* server should cancel the requests in the queue.
*
* In case of success, the server will respond with a
* ble::pal::AttExecuteWriteResponse indicating that the request was correctly
* handled.
*
* In case of error, the server will send a ble::pal::AttErrorResponse. The
* error code depends on the situation:
* - ble::pal::AttErrorResponse::INVALID_OFFSET: If the value offset is
* greater than the current length of the attribute to write.
* - ble::pal::AttErrorResponse::INVALID_ATTRIBUTE_VALUE_LENGTH: If the
* length of the value write exceeds the length of the attribute value
* about to be written.
* Higher layer can also set an application error code (0x80 - 0x9F).
*
* The error response will contains the attribute handle which as caused the
* error and the remaining of the prepare queue is discarded. The state of
* the attributes that were to be written from the prepare queue is not
* defined in this case.
*
* @param connection_handle The handle of the connection to send this
* request to.
* @param execute Boolean indicating if the prepare queue should be executed
* or cleared.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or an
* appropriate error otherwise.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.6.3
*/
virtual ble_error_t execute_write_request(
connection_handle_t connection_handle,
bool execute
) = 0;
/**
* Register a callback which will handle messages from the server.
*
* @param cb The callback object which will handle messages from the server.
* It accept two parameters in input: The handle of the connection where the
* message was received and the message received. Real type of the message
* can be obtained from its opcode.
*/
void when_server_message_received(
mbed::Callback<void(connection_handle_t, const AttServerMessage&)> cb
) {
_server_message_cb = cb;
}
/**
* Register a callback handling transaction timeout.
*
* @param cb The callback handling timeout of a transaction. It accepts as
* a parameter the connection handle involved in the timeout.
*
* @note No more attribute protocol requests, commands, indication or
* notification shall be sent over a connection implied in a transaction
* timeout. To send a new ATT message, the conenction should be
* reestablished.
*/
void when_transaction_timeout(
mbed::Callback<void(connection_handle_t)> cb
) {
_transaction_timeout_cb = cb;
}
protected:
AttClient() { }
virtual ~AttClient() { }
/**
* Upon server message reception an implementation shall call this function.
*
* @param connection_handle The handle of the connection which has received
* the server message.
* @param server_message The message received from the server.
*/
void on_server_event(
connection_handle_t connection_handle,
const AttServerMessage& server_message
) {
if (_server_message_cb) {
_server_message_cb(connection_handle, server_message);
}
}
/**
* Upon transaction timeout an implementation shall call this function.
*
* @param connection_handle The handle of the connection of the transaction
* which has times out.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.3.3
*/
void on_transaction_timeout(
connection_handle_t connection_handle
) {
if (_transaction_timeout_cb) {
_transaction_timeout_cb(connection_handle);
}
}
private:
/**
* Callback called when the client receive a message from the server.
*/
mbed::Callback<void(connection_handle_t, const AttServerMessage&)> _server_message_cb;
/**
* Callback called when a transaction times out.
*/
mbed::Callback<void(connection_handle_t)> _transaction_timeout_cb;
// Disallow copy construction and copy assignment.
AttClient(const AttClient&);
AttClient& operator=(const AttClient&);
};
} // namespace pal
} // namespace ble
#endif /* BLE_PAL_ATTCLIENT_H_ */

View File

@ -0,0 +1,297 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BLE_PAL_ATTCLIENTTOGATTCLIENTADAPTER_H_
#define BLE_PAL_ATTCLIENTTOGATTCLIENTADAPTER_H_
#include "AttClient.h"
#include "PalGattClient.h"
namespace ble {
namespace pal {
/**
* Adapt a pal::AttClient into a pal::GattClient.
*
* This class let vendors define their abstraction layer in term of an AttClient
* and adapt any AttClient into a GattClient.
*/
class AttClientToGattClientAdapter : public GattClient {
public:
static const uint16_t END_ATTRIBUTE_HANDLE = 0xFFFF;
static const uint16_t SERVICE_TYPE_UUID = 0x2800;
static const uint16_t INCLUDE_TYPE_UUID = 0x2802;
static const uint16_t CHARACTERISTIC_TYPE_UUID = 0x2803;
/**
* Construct an instance of GattClient from an instance of AttClient.
* @param client The client to adapt.
*/
AttClientToGattClientAdapter(AttClient& client) :
GattClient(), _client(client) {
_client.when_server_message_received(
mbed::callback(this, &AttClientToGattClientAdapter::on_server_event)
);
_client.when_transaction_timeout(
mbed::callback(
this, &AttClientToGattClientAdapter::on_transaction_timeout
)
);
}
/**
* @see ble::pal::GattClient::exchange_mtu
*/
virtual ble_error_t exchange_mtu(connection_handle_t connection) {
return _client.exchange_mtu_request(connection);
}
/**
* @see ble::pal::GattClient::get_mtu_size
*/
virtual ble_error_t get_mtu_size(
connection_handle_t connection_handle,
uint16_t& mtu_size
) {
return _client.get_mtu_size(connection_handle, mtu_size);
}
/**
* @see ble::pal::GattClient::discover_primary_service
*/
virtual ble_error_t discover_primary_service(
connection_handle_t connection,
attribute_handle_t discovery_range_begining
) {
return _client.read_by_group_type_request(
connection,
attribute_handle_range(discovery_range_begining, END_ATTRIBUTE_HANDLE),
SERVICE_TYPE_UUID
);
}
/**
* @see ble::pal::GattClient::discover_primary_service_by_service_uuid
*/
virtual ble_error_t discover_primary_service_by_service_uuid(
connection_handle_t connection_handle,
attribute_handle_t discovery_range_begining,
const UUID& uuid
) {
return _client.find_by_type_value_request(
connection_handle,
attribute_handle_range(discovery_range_begining, END_ATTRIBUTE_HANDLE),
SERVICE_TYPE_UUID,
ArrayView<const uint8_t>(
uuid.getBaseUUID(),
(uuid.shortOrLong() == UUID::UUID_TYPE_SHORT) ? 2 : UUID::LENGTH_OF_LONG_UUID
)
);
}
/**
* @see ble::pal::GattClient::find_included_service
*/
virtual ble_error_t find_included_service(
connection_handle_t connection_handle,
attribute_handle_range_t service_range
) {
return _client.read_by_type_request(
connection_handle,
service_range,
INCLUDE_TYPE_UUID
);
}
/**
* @see ble::pal::GattClient::discover_characteristics_of_a_service
*/
virtual ble_error_t discover_characteristics_of_a_service(
connection_handle_t connection_handle,
attribute_handle_range_t discovery_range
) {
return _client.read_by_type_request(
connection_handle,
discovery_range,
CHARACTERISTIC_TYPE_UUID
);
}
/**
* @see ble::pal::GattClient::discover_characteristics_descriptors
*/
virtual ble_error_t discover_characteristics_descriptors(
connection_handle_t connection_handle,
attribute_handle_range_t descriptors_discovery_range
) {
return _client.find_information_request(
connection_handle,
descriptors_discovery_range
);
}
/**
* @see ble::pal::GattClient::read_attribute_value
*/
virtual ble_error_t read_attribute_value(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle
) {
return _client.read_request(
connection_handle,
attribute_handle
);
}
/**
* @see ble::pal::GattClient::read_using_characteristic_uuid
*/
virtual ble_error_t read_using_characteristic_uuid(
connection_handle_t connection_handle,
attribute_handle_range_t read_range,
const UUID& uuid
) {
return _client.read_by_type_request(
connection_handle,
read_range,
uuid
);
}
/**
* @see ble::pal::GattClient::read_attribute_blob
*/
virtual ble_error_t read_attribute_blob(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
uint16_t offset
) {
return _client.read_blob_request(
connection_handle,
attribute_handle,
offset
);
}
/**
* @see ble::pal::GattClient::read_multiple_characteristic_values
*/
virtual ble_error_t read_multiple_characteristic_values(
connection_handle_t connection_handle,
const ArrayView<const attribute_handle_t>& characteristic_value_handles
) {
return _client.read_multiple_request(
connection_handle,
characteristic_value_handles
);
}
/**
* @see ble::pal::GattClient::write_without_response
*/
virtual ble_error_t write_without_response(
connection_handle_t connection_handle,
attribute_handle_t characteristic_value_handle,
const ArrayView<const uint8_t>& value
) {
return _client.write_command(
connection_handle,
characteristic_value_handle,
value
);
}
/**
* @see ble::pal::GattClient::signed_write_without_response
*/
virtual ble_error_t signed_write_without_response(
connection_handle_t connection_handle,
attribute_handle_t characteristic_value_handle,
const ArrayView<const uint8_t>& value
) {
return _client.signed_write_command(
connection_handle,
characteristic_value_handle,
value
);
}
/**
* @see ble::pal::GattClient::write_attribute
*/
virtual ble_error_t write_attribute(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
const ArrayView<const uint8_t>& value
) {
return _client.write_request(
connection_handle,
attribute_handle,
value
);
}
/**
* @see ble::pal::GattClient::queue_prepare_write
*/
virtual ble_error_t queue_prepare_write(
connection_handle_t connection_handle,
attribute_handle_t characteristic_value_handle,
const ArrayView<const uint8_t>& value,
uint16_t offset
) {
return _client.prepare_write_request(
connection_handle,
characteristic_value_handle,
offset,
value
);
}
/**
* @see ble::pal::GattClient::execute_write_queue
*/
virtual ble_error_t execute_write_queue(
connection_handle_t connection_handle,
bool execute
) {
return _client.execute_write_request(connection_handle, execute);
}
/**
* @see ble::pal::GattClient::initialize
*/
virtual ble_error_t initialize() {
return _client.initialize();
}
/**
* @see ble::pal::GattClient::terminate
*/
virtual ble_error_t terminate() {
return _client.initialize();
}
private:
AttClient& _client;
};
} // namespace pal
} // namespace ble
#endif /* BLE_PAL_ATTCLIENTTOGATTCLIENTADAPTER_H_ */

View File

@ -0,0 +1,772 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BLE_PAL_ATT_SERVER_MESSAGE_H_
#define BLE_PAL_ATT_SERVER_MESSAGE_H_
#include "ble/BLETypes.h"
#include "ble/ArrayView.h"
namespace ble {
namespace pal {
/**
* Operation code defined for attribute operations
* @note see: BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.8
*/
struct AttributeOpcode {
enum Code {
ERROR_RESPONSE = 0x01, /// Opcode of an AttErrorResponse
EXCHANGE_MTU_REQUEST = 0x02,
EXCHANGE_MTU_RESPONSE = 0x03, /// OpCode of an AttExchangeMTUResponse
FIND_INFORMATION_REQUEST = 0x04,
FIND_INFORMATION_RESPONSE = 0x05, /// OpCode of an AttFindInformationResponse
FIND_BY_TYPE_VALUE_REQUEST = 0x06,
FIND_BY_VALUE_TYPE_RESPONSE = 0x07, /// OpCode of an AttFindByTypeValueResponse
READ_BY_TYPE_REQUEST = 0x08,
READ_BY_TYPE_RESPONSE = 0x09, /// Opcode of an AttReadByTypeResponse
READ_REQUEST = 0x0A,
READ_RESPONSE = 0x0B, /// Opcode of an AttReadResponse
READ_BLOB_REQUEST = 0x0C,
READ_BLOB_RESPONSE = 0x0D, /// Opcode of an AttReadBlobResponse
READ_MULTIPLE_REQUEST = 0x0E,
READ_MULTIPLE_RESPONSE = 0x0F, /// Opcode of an AttReadMultipleResponse
READ_BY_GROUP_TYPE_REQUEST = 0x10,
READ_BY_GROUP_TYPE_RESPONSE = 0x11, /// Opcode of an AttReadByGroupTypeResponse
WRITE_REQUEST = 0x12,
WRITE_RESPONSE = 0x13, /// Opcode of an AttWriteResponse
WRITE_COMMAND = 0x52,
SIGNED_WRITE_COMMAND = 0xD2,
PREPARE_WRITE_REQUEST = 0x16,
PREPARE_WRITE_RESPONSE = 0x17, /// Opcode of an AttPrepareWriteResponse
EXECUTE_WRITE_REQUEST = 0x18,
EXECUTE_WRITE_RESPONSE = 0x19, /// Opcode of an AttExecuteWriteResponse
HANDLE_VALUE_NOTIFICATION = 0x1B,
HANDLE_VALUE_INDICATION = 0x1D
};
/**
* Construct an AttributeOpcode from a Code.
*/
AttributeOpcode(Code value) : _value(value) { }
/**
* Equality comparison operator between two AttributeOpcode
*/
friend bool operator==(AttributeOpcode lhs, AttributeOpcode rhs) {
return lhs._value == rhs._value;
}
/**
* Non equality comparison operator between two AttributeOpcode
*/
friend bool operator!=(AttributeOpcode lhs, AttributeOpcode rhs) {
return lhs._value != rhs._value;
}
/**
* implicit cast to uint8_t.
* Allows AttributeOpcode to be used in switch statements.
*/
operator uint8_t() const {
return _value;
}
private:
uint8_t _value;
};
/**
* Base class for Attribute Server Message.
* The correct type of the instance can be determined with the attribute opcode.
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.3.1
*/
struct AttServerMessage {
/**
* Op code used to identify the type of the attribute response.
*/
const AttributeOpcode opcode;
protected:
/**
* Construction of an AttResponse is reserved for descendent of the class
*/
AttServerMessage(AttributeOpcode opcode_) : opcode(opcode_) { }
};
/**
* Response to a request which can't be performed
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.1.1
* for details about error response.
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.9
* which details possible error response by requests.
*/
struct AttErrorResponse : public AttServerMessage {
/**
* Construct an attribute error response.
*
* @param request_opcode_ The Attribute opcode of the request that generated
* the error.
* @param handle_in_error_ The attribute handle that generated this error
* response.
* @param error_code The reason why the request has generated an error.
*/
AttErrorResponse(
AttributeOpcode request_opcode_,
attribute_handle_t handle_in_error_,
uint8_t error_code_
) : AttServerMessage(AttributeOpcode::ERROR_RESPONSE),
request_opcode(request_opcode_),
handle_in_error(handle_in_error_), error_code(error_code_) {
}
/**
* Construct an attribute error response in the case where there was no
* attribute handle in the original response or if the request is not
* supported.
*
* @param request_opcode_ The Attribute opcode of the request that generated
* the error.
* @param error_code The reason why the request has generated an error.
*/
AttErrorResponse(
AttributeOpcode request_opcode_,
uint8_t error_code_
) : AttServerMessage(AttributeOpcode::ERROR_RESPONSE),
request_opcode(request_opcode_),
handle_in_error(0x0000), error_code(error_code_) {
}
/**
* The opcode of the request that generated this error response.
*/
const AttributeOpcode request_opcode;
/**
* The attribute handle that generated this error response.
* If there was no attribute handle in the original request or if the
* request is not supported, then this field is equal to 0x0000.
*/
const attribute_handle_t handle_in_error;
/**
* The reason why the request has generated an error response
*/
const uint8_t error_code;
/**
* List of Error codes for the ATT protocol
*/
enum AttributeErrorCode {
/** The attribute handle given was not valid on this server. */
INVALID_HANDLE = 0x01,
/** The attribute cannot be read. */
READ_NOT_PERMITTED = 0x02,
/** The attribute cannot be written. */
WRITE_NOT_PERMITTED = 0x03,
/** The attribute PDU was invalid. */
INVALID_PDU = 0x04,
/** The attribute requires authentication before it can be read or
* written.
*/
INSUFFICIENT_AUTHENTICATION = 0x05,
/** Attribute server does not support the request received from the
* client.
*/
REQUEST_NOT_SUPPORTED = 0x06,
/** Offset specified was past the end of the attribute. */
INVALID_OFFSET = 0x07,
/** The attribute requires authorization before it can be read or written. */
INSUFFICIENT_AUTHORIZATION = 0x08,
/** Too many prepare writes have been queued. */
PREPARE_QUEUE_FULL = 0x09,
/** No attribute found within the given attribute handle range. */
ATTRIBUTE_NOT_FOUND = 0x0A,
/** The attribute cannot be read using the Read Blob Request. */
ATTRIBUTE_NOT_LONG = 0x0B,
/** The Encryption Key Size used for encrypting this link is
* insufficient.
*/
INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0C,
/** The attribute value length is invalid for the operation. */
INVALID_ATTRIBUTE_VALUE_LENGTH = 0x0D,
/** The attribute request that was requested has encountered an error
* that was unlikely, and therefore could not be completed as requested.
*/
UNLIKELY_ERROR = 0x0E,
/** The attribute requires encryption before it can be read or written. */
INSUFFICIENT_ENCRYPTION = 0x0F,
/** The attribute type is not a supported grouping attribute as defined
* by a higher layer specification.
*/
UNSUPPORTED_GROUP_TYPE = 0x10,
/** Insufficient Resources to complete the request. */
INSUFFICIENT_RESOURCES = 0x11,
/* 0x12 - 0x7F => reserved for future use */
/* 0x80 - 0x9F => Application Error */
/* 0xA0 0xDF => Reserved for future use */
/* 0xE0 - 0xFF Common Profile and service Error Codes */
/** The Write Request Rejected error code is used when a requested write
* operation cannot be fulfilled for reasons other than permissions.
*/
WRITE_REQUEST_REJECTED = 0xFC,
/** The Client Characteristic Configuration Descriptor Improperly
* Configured error code is used when a Client Characteristic
* Configuration descriptor is not configured according to the
* requirements of the profile or service.
*/
CLIENT_CHARACTERISTIC_CONFIGURATION_DESCRIPTOR_IMPROPERLY_CONFIGURED = 0xFD,
/** The Procedure Already in Progress error code is used when a profile
* or service request cannot be serviced because an operation that has
* been previously triggered is still in progress
*/
PROCEDURE_ALREADY_IN_PROGRESS = 0xFE,
/** The Out of Range error code is used when an attribute value is out
* of range as defined by a profile or service specification.
*/
OUT_OF_RANGE = 0xFF
};
};
/**
* The Exchange MTU Request is used by the client to inform the server of the
* clients maximum receive MTU size and request the server to respond with its
* maximum rx MTU size.
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.2.2
*/
struct AttExchangeMTUResponse : public AttServerMessage {
/**
* Construct an exchange mtu response containing the max rx mtu of the
* server.
*
* @param server_rx_mtu_ The max rx mtu the server can handle.
*/
AttExchangeMTUResponse(uint16_t server_rx_mtu_) :
AttServerMessage(AttributeOpcode::EXCHANGE_MTU_RESPONSE),
server_rx_mtu(server_rx_mtu_) {
}
/**
* The max rx mtu the server can handle.
*/
const uint16_t server_rx_mtu;
};
/**
* The Find Information Response is sent in reply to a received Find Information
* Request and contains information about this server.
*
* The Find Information Response contains a sequence of handle-uuid pairs in
* ascending order if attribute handles.
*
* This class has to be subclassed by an implementation specific class defining
* the member function size and the subscript operator.
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.3.2
*/
struct AttFindInformationResponse : public AttServerMessage {
/** handle-uuid pair */
struct information_data_t {
attribute_handle_t handle;
UUID uuid;
};
/**
* Base constructor, setup the OpCode of the response.
*/
AttFindInformationResponse() :
AttServerMessage(AttributeOpcode::FIND_INFORMATION_RESPONSE) {
}
/**
* virtual destructor to overide if the sub class needs it.
*/
virtual ~AttFindInformationResponse() { }
/**
* Returns the number of information_data_t present in the response.
*/
virtual size_t size() const = 0;
/**
* Access to information_data_t elements present in the response.
* @note Out of range access is undefined.
*/
virtual information_data_t operator[](size_t index) const = 0;
};
/**
* Find by type value responses are sent in response to find by type value
* request.
*
* The response contains a sequence of Found Attribute Handle, Group End Handle
* pair where:
* - Found Attribute Handle is the handle of an attribute matching the type
* and the value requested.
* - Group End Handle is the end of the attribute group if the attribute found
* is a grouping attribute or the same value as Found Attribute Handle if
* the attribute is not a grouping attribute.
*
* This class should be subclassed by an implementation specific class defining
* the member function size and the subscript operator.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.3.4
*/
struct AttFindByTypeValueResponse : public AttServerMessage {
/**
* Base constructor, setup the OpCode of the response.
*/
AttFindByTypeValueResponse() :
AttServerMessage(AttributeOpcode::FIND_BY_VALUE_TYPE_RESPONSE) {
}
/**
* virtual destructor to overide if the sub class needs it.
*/
virtual ~AttFindByTypeValueResponse() { }
/**
* Returns the number of attribute_handle_range_t present in the response.
*/
virtual std::size_t size() const = 0;
/**
* Access to the attribute range present in the response.
* @note Out of range access is undefined.
*/
virtual attribute_handle_range_t operator[](size_t index) const = 0;
};
/**
* Response to a Read By Type request.
*
* It contains a list of handle-value pairs where:
* - handle is the handle of the attribute matching the rype requested.
* - value is the value of the attribute found. If the value is longer than
* (mtu - 4) then it can be truncated and read blob request should be used
* to read the remaining octet of the attribute.
*
* This class has to be subclassed by an implementation specific class defining
* the member function size and the subscript operator.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.2
*/
struct AttReadByTypeResponse : public AttServerMessage {
/**
* handle-value pair
*/
struct attribute_data_t {
attribute_handle_t handle;
ArrayView<const uint8_t> value;
};
/**
* Base constructor, setup the OpCode of the response.
*/
AttReadByTypeResponse() :
AttServerMessage(AttributeOpcode::READ_BY_TYPE_RESPONSE) {
}
/**
* virtual destructor to overide if the sub class needs it.
*/
virtual ~AttReadByTypeResponse() { }
/**
* Return the number of attribute_data_t presents in the response.
*/
virtual size_t size() const = 0;
/**
* Return the attribute data at index.
* @note Out of range access is undefined.
*/
virtual attribute_data_t operator[](size_t index) const = 0;
};
/**
* The read response is sent in reply to a received Read Request and contains
* the value of the attribute that has been read.
*
* The attribute value shall be set to the value of the attribute identified by
* the attribute handle in the request. If the attribute value is longer than
* (ATT_MTU-1) then the first (ATT_MTU-1) octets shall be included in this
* response.
*
* @note The Read Blob Request would be used to read the remaining octets of a
* long attribute value.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.4
*/
struct AttReadResponse : public AttServerMessage {
/**
* Construct a Read Response from an array of bytes.
*/
AttReadResponse(ArrayView<const uint8_t> data_) :
AttServerMessage(AttributeOpcode::READ_RESPONSE), _data(data_) {
}
/**
* Return the number of octets presents in the response.
*/
size_t size() const {
return _data.size();
}
/**
* Return the octet at the specified index.
* @note Out of range access is undefined.
*/
uint8_t operator[](size_t index) const {
return _data[index];
}
/**
* Return the pointer to the actual data
*/
const uint8_t* data() const {
return _data.data();
}
private:
const ArrayView<const uint8_t> _data;
};
/**
* The Read Blob Response is sent in reply to a received Read Blob Request and
* contains part of the value of the attribute that has been read.
*
* If the offset requested is equal to the length of the attribute then the
* response contains no data and the size of the data returned is equal to 0.
*
* If the value of the attribute starting at the offset requested is longer than
* (mtu - 1) octets then the first (mtu - 1) will be present in the response.
* The remaining octets will be acquired by another Read Blob Request with an
* updated index.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.6
*/
struct AttReadBlobResponse : public AttServerMessage {
/**
* Construct a read blob response from the value responded.
*/
AttReadBlobResponse(ArrayView<const uint8_t> data_) :
AttServerMessage(AttributeOpcode::READ_BLOB_RESPONSE), _data(data_) {
}
/**
* Return the number of octets presents in the response value.
*/
size_t size() const {
return _data.size();
}
/**
* Return the octet of the value read at the specified index.
* @note Out of range access is undefined.
*/
uint8_t operator[](size_t index) const {
return _data[index];
}
/**
* Return the pointer to the actual data
*/
const uint8_t* data() const {
return _data.data();
}
private:
const ArrayView<const uint8_t> _data;
};
/**
* Response to a Read Multiple Request. It contains the values of the attributes
* that have been read.
*
* If the set of values that has been read is longer than (mtu - 1) then only
* the first (mtu - 1) octets are included in the response.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.8
*/
struct AttReadMultipleResponse : public AttServerMessage {
/**
* Construct a Resd Multiple Response from the set of value received.
*/
AttReadMultipleResponse(ArrayView<const uint8_t> data_) :
AttServerMessage(AttributeOpcode::READ_MULTIPLE_RESPONSE), _data(data_) {
}
/**
* Return the number of octets presents in the response set of value.
*/
size_t size() const {
return _data.size();
}
/**
* Return the octet of the set of value read at the specified index.
* @note Out of range access is undefined.
*/
uint8_t operator[](size_t index) const {
return _data[index];
}
private:
const ArrayView<const uint8_t> _data;
};
/**
* The Read By Group Type Response is sent in reply to a received Read By
* Group Type Request and contains the handles and values of the attributes that
* have been read.
*
* The response is a list of group range-value pair where:
* - group range: The range of the group found where begin is the grouping
* attribute handle and end is the handle of the end of the group.
* - value: The value of the grouping attribute.
*
* This class has to be subclassed by an implementation specific class defining
* the member function size and the subscript operator.
*
* @note The value responded can be trucated if it doesn't fit in the response,
* in that case a Read Blob Request could be used to read the remaining octets.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.4.10
*/
struct AttReadByGroupTypeResponse : public AttServerMessage {
/**
* Data read from the grouping attribute.
* It includes the range of the group and the value of the attribute.
*/
struct attribute_data_t {
attribute_handle_range_t group_range;
ArrayView<const uint8_t> value;
};
/**
* Base constructor, setup the OpCode of the response.
*/
AttReadByGroupTypeResponse() :
AttServerMessage(AttributeOpcode::READ_BY_GROUP_TYPE_RESPONSE) {
}
/**
* virtual destructor to overide if the sub class needs it.
*/
virtual ~AttReadByGroupTypeResponse() { }
/**
* Return the number of attribute_data_t present in the response.
*/
virtual size_t size() const = 0;
/**
* Return the attribute data read at the index specified.
* @note Out of range access is undefined.
*/
virtual attribute_data_t operator[](size_t index) const = 0;
};
/**
* The Write Response is sent in reply to a valid Write Request and
* acknowledges that the attribute has been successfully written.
* It is just a placeholder which indicates the client that the write request
* was successful.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.5.2
*/
struct AttWriteResponse : public AttServerMessage {
/**
* Construct a write response.
*/
AttWriteResponse() : AttServerMessage(AttributeOpcode::WRITE_RESPONSE) { }
};
/**
* Response to a Prepare Write Request. It acknowledges the client that the
* value has been successfully received and placed in the write queue.
*
* The response contains the same values as the one present in the request.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.6.2
*/
struct AttPrepareWriteResponse : public AttServerMessage {
/**
* Construct a prepare write response.
* @param handle_ The handle of the attribute to be written.
* @param offset_: The offset of the first octet to be writen.
* @param value_: The value of the attribute to be written at the offset
* indicated.
*/
AttPrepareWriteResponse(
attribute_handle_t handle_,
uint16_t offset_,
ArrayView<const uint8_t> value_
) : AttServerMessage(AttributeOpcode::PREPARE_WRITE_RESPONSE),
attribute_handle(handle_),
offset(offset_),
partial_value(value_) {
}
/**
* The handle of the attribute to be written.
*/
const attribute_handle_t attribute_handle;
/**
* The offset of the first octet to be writen.
*/
const uint16_t offset;
/**
* The value of the attribute to be written at the offset indicated.
*/
const ArrayView<const uint8_t> partial_value;
};
/**
* The Execute Write Response is sent in response to a received Execute Write
* Request.
*
* It is just a placeholder which indicates the client that the execution of the
* write request has been successfull.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.6.4
*/
struct AttExecuteWriteResponse : public AttServerMessage {
/**
* Construct an execute write response object.
*/
AttExecuteWriteResponse() :
AttServerMessage(AttributeOpcode::EXECUTE_WRITE_RESPONSE) {
}
};
/**
* Notification of an attribute's value sent by the server.
*
* It contains the handle of the attribute and its value.
*
* If the attribute value is longer than (mtu - 3) then the value is truncated
* to (mtu - 3) octets to fit in the response and the client will have to use
* a read blob request to read the remaining octets of the attribute.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.7.1
*/
struct AttHandleValueNotification : public AttServerMessage {
/**
* Construct an Handle Value Notification from the attribute handle and its
* value notified.
*/
AttHandleValueNotification(
attribute_handle_t attribute_handle,
ArrayView<const uint8_t> attribute_value
) : AttServerMessage(AttributeOpcode::HANDLE_VALUE_NOTIFICATION),
attribute_handle(attribute_handle),
attribute_value(attribute_value) {
}
/**
* Handle of the attribute
*/
const attribute_handle_t attribute_handle;
/**
* The current value of the attribute.
*/
const ArrayView<const uint8_t> attribute_value;
};
/**
* Indication of an attribute's value sent by the server.
*
* It contains the handle of the attribute and its value. The client should
* respond with and handle value confirmation.
*
* If the attribute value is longer than (mtu - 3) then the value is truncated
* to (mtu - 3) octets to fit in the response and the client will have to use
* a read blob request to read the remaining octets of the attribute.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.4.7.2
*/
struct AttHandleValueIndication : public AttServerMessage {
/**
* Construct an Handle Value Indication from the attribute handle and its
* value indicated.
*/
AttHandleValueIndication(
attribute_handle_t handle, ArrayView<const uint8_t> value
) : AttServerMessage(AttributeOpcode::HANDLE_VALUE_INDICATION),
attribute_handle(handle), attribute_value(value) {
}
/**
* Handle of the attribute
*/
const attribute_handle_t attribute_handle;
/**
* The current value of the attribute.
*/
const ArrayView<const uint8_t> attribute_value;
};
} // namespace pal
} // namespace ble
#endif /* BLE_PAL_ATT_SERVER_MESSAGE_H_ */

View File

@ -0,0 +1,642 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BLE_PAL_GATT_CLIENT_H_
#define BLE_PAL_GATT_CLIENT_H_
#include "ble/UUID.h"
#include "ble/BLETypes.h"
#include "ble/ArrayView.h"
#include "ble/blecommon.h"
#include "platform/Callback.h"
#include "AttServerMessage.h"
namespace ble {
namespace pal {
/**
* Adaptation layer for a GATT client.
*
* Define the primitive necessary to implement a proper GATT client. These
* primitives are sometime GATT procedure, ATT procedure or a bit of both.
*
* In general, discovery procedures follow strictly GATT formulation while
* attribute manipulation procedures (read/write) follow the ATT formulation
* to avoid multiple identical implementation for characteristic values and
* characteristic descriptors value, it also fill a hole leave by the
* specification which doesn't define any GATT procedure to get the UUID of an
* included service with a 128 bit UUID.
*
* Complementary informations around ATT procedures can be found in the Section
* 3.4 of the Vol3, Part F of the Bluetooth specification while more informations
* around the GATT procedures can be found in the Section 4 of the Vol 3, Part
* G of the Bluetooth specification.
*
* Complete and compliant Gatt Client used by developer is realized at an higher
* level using the primitives defined in this adaptation layer.
*
* If a stack expose the complete ATT layer then it is possible to provide an
* implementation for GattClient by subclassing the AttClient class and use
* the class AttClientToGattClientAdapter
*/
class GattClient {
public:
/**
* Initialisation of the instance. An implementation can use this function
* to initialise the subsystems needed to realize the operations of this
* interface.
*
* This function has to be called before any other operations.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*/
virtual ble_error_t initialize() = 0;
/**
* Termination of the instance. An implementation can use this function
* to release the subsystems initialised to realise the operations of
* this interface.
*
* After a call to this function, initialise should be called again to
* allow usage of the interface.
*
* @return BLE_ERROR_NONE if the request has been successfully sent or the
* appropriate error otherwise.
*/
virtual ble_error_t terminate() = 0;
/**
* Negotiate the mtu to use by this connection.
* First the client send to the server the maximum rx mtu that it can receive
* then the client reply with the maximum rx mtu it can receive.
* The mtu chosen for the connection is the minimum of the client Rx mtu
* and server Rx mtu values.
*
* If an error occurred then the mtu used remains the default value.
*
* The server will reply to this request with an AttExchangeMTUResponse in
* case of success or AttErrorResponse in case of failure.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.3.1
*
* @param connection The handle of the connection to send this request to.
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t exchange_mtu(connection_handle_t connection) = 0;
/**
* Acquire the size of the mtu for a given connection.
*
* @param connection The handle of the connection for which the the MTU size
* should be acquired.
*
* @param mtu_size Output parameter which will contain the MTU size.
*
* @return BLE_ERROR_NONE if the MTU size has been acquired or the
* appropriate error otherwise.
*/
virtual ble_error_t get_mtu_size(
connection_handle_t connection_handle,
uint16_t& mtu_size
) = 0;
/**
* Discover primary services in the range [begin - 0xFFFF].
*
* If services exists in the range provided, the server will reply with a
* ReadByGoupType response where for each attribute_data exposed:
* - attribute_handle is the service attribute handle
* - end_group_handle is the last handle of the service
* - attribute_value is the UUID of the service.
*
* If the end of the range is not reached, this procedure can be relaunched
* with the last handle of the last service discovered plus one as the
* beginning of the discovery range.
*
* If there is not services left to discover in the range, the server can
* either:
* * Reply with an ErrorResponse with the Error code set to ATTRIBUTE_NOT_FOUND
* * Set the end handle of the last service to 0xFFFF.
*
* @note This function realize a partial implementation of the Discover All
* Primary Services procedure. The complete implementation of the procedure
* is realized at an higher level.
* @note This function issue a Read By Group Type ATT request where the
* type parameter is equal to Primary Service and the Ending Handle parameter
* is equal to 0xFFFF.
* @note BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.4.1
*
* @param connection The handle of the connection to send this request to.
* @param begin The beginning of the discovery range.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t discover_primary_service(
connection_handle_t connection,
attribute_handle_t discovery_range_begining
) = 0;
/**
* Discover primary services by UUID in the range [discovery_range_begining - 0xFFFF].
*
* If services exists in the range provided, the server will reply with a
* FindByTypeValueResponse containing the attribute range of each service
* discovered.
*
* If the end of the range is not reached, this procedure can be relaunched
* with the last handle of the last service discovered plus one as the
* beginning of the discovery range.
*
* If there is not services left to discover in the range, the server can
* either:
* * Reply with an ErrorResponse with the Error code set to ATTRIBUTE_NOT_FOUND
* * Set the end handle of the last service to 0xFFFF.
*
* @note This function realize a partial implementation of the Discover
* Primary Service by Service UUID procedure. The complete implementation of
* the procedure is realized at an higher level.
* @note This function issue a Find By Type Value ATT request where the
* type parameter is equal to Primary Service and the Ending Handle
* parameter is equal to 0xFFFF.
* @note BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.4.2
*
* @param connection The handle of the connection to send this request to.
* @param begin The beginning of the discovery range.
* @param uuid The UUID of the service to discover.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t discover_primary_service_by_service_uuid(
connection_handle_t connection_handle,
attribute_handle_t discovery_range_beginning,
const UUID& uuid
) = 0;
/**
* Find included services within a service.
*
* If services are included in the service range then the server will reply
* with a ReadByTypeResponse where for each attribute record:
* - attribute_handle The handle where the service is included within the
* service definition.
* - attribute_data Contains two handles defining the range of the included.
* If the service found have a 16 bit uuid then its UUID is also included
* in the attribute data.
*
* If the end of the service range is not reached, this procedure can be
* relaunched with the handle of the last included service discovered plus
* one as the beginning of the new discovery range.
*
* The procedure is complete when either:
* - The server reply with an ErrorResponse with the Error code set to
* ATTRIBUTE_NOT_FOUND
* - An included service handle returned is equal to the end of the range.
*
* If the service UUID is a 128 bits one then it is necessary to issue a read
* attribute request on the first handle of the service discovered to get it.
*
* @note This function realize a partial implementation of the Find Included
* Services procedure. The complete implementation of the procedure is
* realized at an higher level.
* @note This function issue a Read By Type ATT request where the
* type parameter is equal to Include.
* @note BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.5.1
*
* @param connection The handle of the connection to send this request to.
* @param service_range The range of the service where service inclusion has
* to be discovered.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t find_included_service(
connection_handle_t connection_handle,
attribute_handle_range_t service_range
) = 0;
/**
* Find characteristic declarations within a service definition.
*
* If characteristic declarations are found within the range then the server
* should reply with a ReadByTypeResponse where for each attribute record:
* - attribute_handle is the handle of the characteristic definition
* - attribute_data contains the the following values attached to the
* characteristic :
* + properties: the properties of the characteristic.
* + value handle: the handle of the value of the characteristic.
* + uuid: the UUID of the characteristic.
*
* The procedure is considered complete when the server send an ErrorResponse
* with the ErrorCode set to ATTRIBUTE_NOT_FOUND or a ReadByType response
* has an attribute_handle set to the end of the discovery range.
*
* If the procedure is not complete after a server response, it should be
* relaunched with an updated range starting at the last attribute_handle
* discovered plus one.
*
* @note This function realize a partial implementation of the Discover All
* Characteristics of a Service procedure. The complete implementation of
* the procedure is realized at an higher level.
* @note This function issue a Read By Type ATT request where the type
* parameter is equal to Characteristic.
* @note BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.6.1
*
* @note The GATT procedure Discover Characteristics by UUID is implemented
* at a higher level using this function as a base.
*
* @param connection The handle of the connection to send this request to.
* @param discovery_range The range of attributes where the characteristics
* are discovered. It should be contained within a service.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t discover_characteristics_of_a_service(
connection_handle_t connection_handle,
attribute_handle_range_t discovery_range
) = 0;
/**
* Discover characteristic descriptors of a characteristic.
*
* If descriptors are found within the range provided then the server should
* reply with a FindInformationResponse containing a list of
* attribute_handle_t, UUID pairs where the attribute handle is the
* descriptor handle and UUID is the UUID of the descriptor.
*
* The procedure is complete when the server send an ErrorResponse with the
* error code ATTRIBUTE_NOT_FOUND or the FindInformationResponse has an
* attribute handle that is equal to the end handle of the discovery range.
*
* @note This function realize a partial implementation of the Discover All
* Characteristics Descriptors procedure. The complete implementation of
* the procedure is realized at an higher level.
* @note This function issue a Find Information ATT request..
* @note BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.7.1
*
* @note It should be possible to use this function to issue a regular
* ATT Find Information Request.
*
* @param connection The handle of the connection to send this request to.
* @param descriptors_discovery_range The range of attributes where the
* descriptors are discovered. The first handle shall be no less than the
* characteristic value handle plus one and the last handle shall be no more
* than the last handle of the characteristic.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t discover_characteristics_descriptors(
connection_handle_t connection_handle,
attribute_handle_range_t descriptors_discovery_range
) = 0;
/**
* Read the value of an attribute.
*
* The server will reply with an AttReadResponse. In case of error, the
* server will reply with an AttErrorResponse.
*
* @note This function issue an ATT Read Request.
*
* @note: This function is the base function for the read Characteristic
* Value and Read Characteristic Descriptor GATT procedures. It can also
* be used to read the 128 bit UUID of a service discovered with
* find_included_service.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.8.1
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.12.1
*
* @param connection The handle of the connection to send this request to.
* @param attribute_handle Handle of the attribute to read.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t read_attribute_value(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle
) = 0;
/**
* Read a characteristic value using its UUID (type).
*
* The server will respond a ReadByTypeResponse containing a sequence of
* attribute handle and attribute value pairs.
* To read remaining attributes, the client should launch a new request
* with an updated range.
*
* The procedure is considered complete when the server respond with an
* ErrorResponse containing the ErrorCode ATTRIBUTE_NOT_FOUND or when an
* handle in the ReadByTypeResponse is equal to the end of the discovered
* range.
*
* @note This function realize a partial implementation of the Read Using
* Characteristics Characteristic procedure. The complete implementation of
* the procedure is realized at an higher level.
* @note This function issue a Read By Type ATT request.
* @note BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.8.2
*
* @note It should be possible to use this function to issue a regular
* ATT Read By Type Request.
*
* @param connection The handle of the connection to send this request to.
* @param attribute_range Range of the handle where an attribute with
* uuid as type is present.
* @param uuid UUID of the characteristic(s) to read.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t read_using_characteristic_uuid(
connection_handle_t connection_handle,
attribute_handle_range_t read_range,
const UUID& uuid
) = 0;
/**
* Read a partial value of an attribute.
*
* The server will respond with a ReadBlobResponse containing the data read
* or an ErrorResponse in case of error.
*
* The procedure is not complete as long as the value in response have the
* same size as the mtu minus one. If the procedure is not complete, it can
* be launch again with an updated offset to read the remaining part of the
* attribute value.
*
* @note This function issue an ATT Read Blob Request.
*
* @note: This function is the base function for the Read Long
* Characteristic Value and Read Long Characteristic Descriptor GATT
* procedures.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.8.3
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.12.2
*
* @param connection_handle The handle of the connection to send this request to.
* @param attribute_handle Handle of the attribute to read.
* @param offset Beginning offset for the read operation.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t read_attribute_blob(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
uint16_t offset
) = 0;
/**
* Read atomically multiple characteristics values.
*
* The server will respond with a ReadMultiple response containing the
* concatenation of the values of the characteristics.
*
* @note values might be truncated
*
* In case of error, the server should respond a with an ErrorResponse.
*
* @note This function issue an ATT Read Multiple Request.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.8.4
*
* @param connection_handle The handle of the connection to send this request to.
* @param characteristic_value_handles Handle of the characteristic values
* to read.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t read_multiple_characteristic_values(
connection_handle_t connection_handle,
const ArrayView<const attribute_handle_t>& characteristic_value_handles
) = 0;
/**
* Send a write command to the server.
*
* @note This function issue an ATT Write Command.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.1
*
* @param connection_handle The handle of the connection to send this request to.
* @param attribute_handle Handle of the attribute to write.
* @param value The value to write.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t write_without_response(
connection_handle_t connection_handle,
attribute_handle_t characteristic_value_handle,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send a Signed Write without Response command to the server.
*
* @note This function issue an ATT Write Command with the signed flag and
* the signature.
*
* @note signature is calculated by the stack.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.2
*
* @param connection_handle The handle of the connection to send this request to.
* @param attribute_handle Handle of the attribute to write.
* @param value The value to write.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t signed_write_without_response(
connection_handle_t connection_handle,
attribute_handle_t characteristic_value_handle,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send a write request to the server.
*
* The server should respond with a WriteResponse in case of success or an
* ErrorResponse in case of error.
*
* @note This function issue an ATT Write Request.
*
* @note: This function is the base function for the Write Characteristic
* Value and Write Characteristic Descriptors GATT procedures.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.3
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.12.3
*
* @param connection_handle The handle of the connection to send this request to.
* @param attribute_handle Handle of the attribute to write.
* @param value The value to write.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t write_attribute(
connection_handle_t connection_handle,
attribute_handle_t attribute_handle,
const ArrayView<const uint8_t>& value
) = 0;
/**
* Send a prepare write request to the server.
*
* The write request will go into a queue until the client execute or cancel
* the request with an execute write request which will write all the values
* in the queue atomically.
*
* The server should respond with a PrepareWriteResponse containing the
* content of the request in case of success and an ErrorResponse in case of
* error.
*
* If an ErrorResponse is received it doesn't invalidate what is already in
* the queue.
*
* @note This function issue an ATT Prepare Write Request.
*
* @note: This function is one of the base function for the Write Long
* Characteristic Value and Reliable Writes GATT procedures.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.4
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.5
*
* @param connection_handle The handle of the connection to send this request to.
* @param attribute_handle Handle of the attribute to write.
* @param value The value to write.
* @param offset offset where the value should be written.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t queue_prepare_write(
connection_handle_t connection_handle,
attribute_handle_t characteristic_value_handle,
const ArrayView<const uint8_t>& value,
uint16_t offset
) = 0;
/**
* Send a request to the server to execute the queue of prepared write
* requests.
*
* The server should respond with an ExecuteWriteResponse in case of success
* and an Error response in case of failure.
*
* @note This function issue an ATT Execute Write Request.
*
* @note: This function is one of the base function for the Write Long
* Characteristic Value and Reliable Writes GATT procedures.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.4
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.9.5
*
* @param connection_handle The handle of the connection to send this request to.
* @param execute If true, execute the write request queue otherwise cancel it.
*
* @return BLE_ERROR_NONE or an appropriate error.
*/
virtual ble_error_t execute_write_queue(
connection_handle_t connection_handle,
bool execute
) = 0;
/**
* Register a callback which will handle messages from the server.
*
* @param cb The callback object which will handle messages from the server.
* It accept two parameters in input: The handle of the connection where the
* message was received and the message received. Real type of the message
* can be obtained from its opcode.
*/
void when_server_message_received(
mbed::Callback<void(connection_handle_t, const AttServerMessage&)> cb
) {
_server_message_cb = cb;
}
/**
* Register a callback handling transaction timeout.
*
* @param cb The callback handling timeout of a transaction. It accepts as
* a parameter the connection handle involved in the timeout.
*
* @note No more attribute protocol requests, commands, indication or
* notification shall be sent over a connection implied in a transaction
* timeout. To send a new ATT message, the conenction should be
* reestablished.
*/
void when_transaction_timeout(
mbed::Callback<void(connection_handle_t)> cb
) {
_transaction_timeout_cb = cb;
}
protected:
GattClient() { }
virtual ~GattClient() { }
/**
* Upon server message reception an implementation shall call this function.
*
* @param connection_handle The handle of the connection which has received
* the server message.
* @param server_message The message received from the server.
*/
void on_server_event(
connection_handle_t connection_handle,
const AttServerMessage& server_message
) {
if (_server_message_cb) {
_server_message_cb(connection_handle, server_message);
}
}
/**
* Upon transaction timeout an implementation shall call this function.
*
* @param connection_handle The handle of the connection of the transaction
* which has times out.
*
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F Section 3.3.3
* @note see BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part G Section 4.4.14
*/
void on_transaction_timeout(
connection_handle_t connection_handle
) {
if (_transaction_timeout_cb) {
_transaction_timeout_cb(connection_handle);
}
}
private:
/**
* Callback called when the client receive a message from the server.
*/
mbed::Callback<void(connection_handle_t, const AttServerMessage&)> _server_message_cb;
/**
* Callback called when a transaction times out.
*/
mbed::Callback<void(connection_handle_t)> _transaction_timeout_cb;
// Disallow copy construction and copy assignment.
GattClient(const GattClient&);
GattClient& operator=(const GattClient&);
};
} // namespace pal
} // namespace ble
#endif /* BLE_PAL_GATT_CLIENT_H_ */

View File

@ -0,0 +1,232 @@
/* mbed Microcontroller Library
* Copyright (c) 2017-2017 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef BLE_PAL_SIMPLEATTSERVERMESSAGE_H_
#define BLE_PAL_SIMPLEATTSERVERMESSAGE_H_
#include "AttServerMessage.h"
namespace ble {
namespace pal {
/**
* Simple implementation of ble::pal::AttFindInformationResponse.
* It should fit for any vendor stack exposing a proper ATT interface.
*/
struct SimpleAttFindInformationResponse : public AttFindInformationResponse {
/**
* Format of the UUID in the response.
*/
enum Format {
FORMAT_16_BIT_UUID = 0x01,//!< FORMAT_16_BIT_UUID
FORMAT_128_BIT_UUID = 0x02//!< FORMAT_128_BIT_UUID
};
/**
* Construct an AttFindInformationResponse from format and an array of bytes
* containing the information data.
* @param format The format of the information data.
* @param information_data The information data whose format is determined
* by the Format field
*/
SimpleAttFindInformationResponse(
Format format, ArrayView<const uint8_t> information_data
) : AttFindInformationResponse(),
_format(format), _information_data(information_data),
_item_size(information_data_item_size()) {
}
/**
* @see ble::pal::AttFindInformationResponse::size
*/
virtual size_t size() const {
return _information_data.size() / _item_size;
}
/**
* @see ble::pal::AttFindInformationResponse::operator[]
*/
virtual information_data_t operator[](size_t index) const {
const uint8_t* item = &_information_data[index * _item_size];
information_data_t result;
memcpy(&result.handle, item, sizeof(result.handle));
if (_format == FORMAT_16_BIT_UUID) {
uint16_t short_uuid = 0;
memcpy(&short_uuid, item + 2, sizeof(short_uuid));
result.uuid = UUID(short_uuid);
} else {
result.uuid = UUID(item + 2, UUID::LSB);
}
return result;
}
private:
size_t information_data_item_size() const {
return sizeof(attribute_handle_t) + ((_format == FORMAT_16_BIT_UUID) ? 2 : 16);
}
const Format _format;
const ArrayView<const uint8_t> _information_data;
const size_t _item_size;
};
/**
* Simple implementation of ble::pal::AttFindByTypeValueResponse.
* It should fit for any vendor stack exposing a proper ATT interface.
*/
struct SimpleAttFindByTypeValueResponse : public AttFindByTypeValueResponse {
/**
* Construct a AttFindByTypeValueResponse from a raw array containing the
* Handle Informations.
* @param handles raw array containing one or more Handle Informations.
*/
SimpleAttFindByTypeValueResponse(ArrayView<const uint8_t> handles) :
AttFindByTypeValueResponse(), _handles(handles) {
}
/**
* @see ble::pal::AttFindByTypeValueResponse::size
*/
virtual std::size_t size() const {
return _handles.size() / item_size;
}
/**
* @see ble::pal::AttFindByTypeValueResponse::operator[]
*/
virtual attribute_handle_range_t operator[](size_t index) const {
attribute_handle_range_t result;
const uint8_t* item = &_handles[index * item_size];
memcpy(&result.begin, item, sizeof(result.begin));
memcpy(&result.end, item + sizeof(result.begin), sizeof(result.end));
return result;
}
private:
static const size_t item_size = 4;
const ArrayView<const uint8_t> _handles;
};
/**
* Simple implementation of ble::pal::AttReadByTypeResponse.
* It should fit for any vendor stack exposing a proper ATT interface.
*/
struct SimpleAttReadByTypeResponse : public AttReadByTypeResponse {
/**
* Construct an AttReadByTypeResponse from the size of each attribute
* handle-value pair and a list of attribute data.
* @param element_size The size of each attribute-handle pair.
* @param attribute_data Raw bytes array containing the list of attribute
* data.
*/
SimpleAttReadByTypeResponse(
uint8_t element_size, ArrayView<const uint8_t> attribute_data
) : AttReadByTypeResponse(),
_attribute_data(attribute_data), _element_size(element_size) {
}
/**
* @see ble::pal::AttReadByTypeResponse::size
*/
virtual size_t size() const {
return _attribute_data.size() / _element_size;
}
/**
* @see ble::pal::AttReadByTypeResponse::operator[]
*/
virtual attribute_data_t operator[](size_t index) const {
const uint8_t* item = &_attribute_data[index * _element_size];
uint16_t handle;
memcpy(&handle, item, sizeof(handle));
attribute_data_t result = {
handle,
ArrayView<const uint8_t>(
item + sizeof(handle),
_element_size - sizeof(handle)
)
};
return result;
}
private:
ArrayView<const uint8_t> _attribute_data;
uint8_t _element_size;
};
/**
* Simple implementation of ble::pal::AttReadByGroupTypeResponse.
* It should fit for any vendor stack exposing a proper ATT interface.
*/
struct SimpleAttReadByGroupTypeResponse : public AttReadByGroupTypeResponse {
/**
* Construct an instance of AttReadByGroupTypeResponse from the size of each
* attribute data and a byte array containing the list of attribute data.
* @param element_size The size of each Attribute Data
* @param attribute_data Byte array containing the list of Attribute Data.
*/
SimpleAttReadByGroupTypeResponse(
uint8_t element_size, ArrayView<const uint8_t> attribute_data
) : AttReadByGroupTypeResponse(),
_attribute_data(attribute_data), _element_size(element_size) {
}
/**
* @see ble::pal::AttReadByGroupTypeResponse::size
*/
virtual size_t size() const {
return _attribute_data.size() / _element_size;
}
/**
* @see ble::pal::AttReadByGroupTypeResponse::operator[]
*/
virtual attribute_data_t operator[](size_t index) const {
const uint8_t* item = &_attribute_data[index * _element_size];
uint16_t begin;
uint16_t end;
memcpy(&begin, item, sizeof(begin));
memcpy(&end, item + sizeof(begin), sizeof(end));
attribute_data_t result = {
{ begin, end },
ArrayView<const uint8_t>(
item + sizeof(begin) + sizeof(end),
_element_size - (sizeof(begin) + sizeof(end))
)
};
return result;
}
private:
ArrayView<const uint8_t> _attribute_data;
uint8_t _element_size;
};
} // namespace pal
} // namespace ble
#endif /* BLE_PAL_SIMPLEATTSERVERMESSAGE_H_ */

File diff suppressed because it is too large Load Diff