mbed-os
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
Diff: features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalAttClient.h
- Revision:
- 0:b74591d5ab33
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalAttClient.h Mon Dec 11 17:54:04 2017 +0000 @@ -0,0 +1,622 @@ +/* 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 CORDIO_PAL_ATT_CLIENT_ +#define CORDIO_PAL_ATT_CLIENT_ + +#include "ble/pal/AttClient.h" +#include "ble/pal/SimpleAttServerMessage.h" +#include "att_api.h" +#include "att_defs.h" + +namespace ble { +namespace pal { +namespace vendor { +namespace cordio { + +class CordioAttClient : public ::ble::pal::AttClient { + +public: + CordioAttClient() : ::ble::pal::AttClient() { } + virtual ~CordioAttClient() { } + + /** + * @see ble::pal::AttClient::exchange_mtu_request + */ + virtual ble_error_t exchange_mtu_request(connection_handle_t connection) + { + AttcMtuReq(connection, pAttCfg->mtu); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::GattClient::get_mtu_size + */ + virtual ble_error_t get_mtu_size( + connection_handle_t connection_handle, + uint16_t& mtu_size + ) { + mtu_size = AttGetMtu(connection_handle); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::find_information_request + */ + virtual ble_error_t find_information_request( + connection_handle_t connection_handle, + attribute_handle_range_t discovery_range + ) { + AttcFindInfoReq( + connection_handle, + discovery_range.begin, + discovery_range.end, + false + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::find_by_type_value_request + */ + 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 + ) { + AttcFindByTypeValueReq( + connection_handle, + discovery_range.begin, + discovery_range.end, + type, + value.size(), + const_cast<uint8_t*>(value.data()), + false + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::read_by_type_request + */ + virtual ble_error_t read_by_type_request( + connection_handle_t connection_handle, + attribute_handle_range_t read_range, + const UUID& type + ) { + AttcReadByTypeReq( + connection_handle, + read_range.begin, + read_range.end, + type.getLen(), + const_cast<uint8_t*>(type.getBaseUUID()), + false + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::read_request + */ + virtual ble_error_t read_request( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle + ) { + AttcReadReq(connection_handle, attribute_handle); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::read_blob_request + */ + virtual ble_error_t read_blob_request( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + uint16_t offset + ) { + AttcReadLongReq( + connection_handle, + attribute_handle, + offset, + false + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::read_multiple_request + */ + virtual ble_error_t read_multiple_request( + connection_handle_t connection_handle, + const ArrayView<const attribute_handle_t>& attribute_handles + ) { + AttcReadMultipleReq( + connection_handle, + attribute_handles.size(), + const_cast<uint16_t*>(attribute_handles.data()) + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::read_by_group_type_request + */ + virtual ble_error_t read_by_group_type_request( + connection_handle_t connection_handle, + attribute_handle_range_t read_range, + const UUID& group_type + ) { + AttcReadByGroupTypeReq( + connection_handle, + read_range.begin, + read_range.end, + group_type.getLen(), + const_cast<uint8_t*>(group_type.getBaseUUID()), + false + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::write_request + */ + virtual ble_error_t write_request( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView<const uint8_t>& value + ) { + AttcWriteReq( + connection_handle, + attribute_handle, + value.size(), + const_cast<uint8_t*>(value.data()) + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::write_command + */ + virtual ble_error_t write_command( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView<const uint8_t>& value + ) { + AttcWriteCmd( + connection_handle, + attribute_handle, + value.size(), + const_cast<uint8_t*>(value.data()) + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::signed_write_command + */ + virtual ble_error_t signed_write_command( + connection_handle_t connection_handle, + attribute_handle_t attribute_handle, + const ArrayView<const uint8_t>& value + ) { + AttcSignedWriteCmd( + connection_handle, + attribute_handle, + /* sign counter from flash or AttsGetSignCounter() ? */ 0, + value.size(), + const_cast<uint8_t*>(value.data()) + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::prepare_write_request + */ + 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 + ) { + AttcPrepareWriteReq( + connection_handle, + attribute_handle, + offset, + value.size(), + const_cast<uint8_t*>(value.data()), + false, + false + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::execute_write_request + */ + virtual ble_error_t execute_write_request( + connection_handle_t connection_handle, + bool execute + ) { + AttcExecuteWriteReq( + connection_handle, + execute + ); + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::initialize + */ + virtual ble_error_t initialize() + { + return BLE_ERROR_NONE; + } + + /** + * @see ble::pal::AttClient::terminate + */ + virtual ble_error_t terminate() + { + return BLE_ERROR_NONE; + } + + // singleton of the ARM Cordio client + static CordioAttClient& get_client() + { + static CordioAttClient _client; + return _client; + } + +private: + // convert an array of byte to an uint16_t + static uint16_t to_uint16_t(const uint8_t* array) + { + uint16_t result; + memcpy(&result, array, sizeof(result)); + return result; + } + + /** + * Type of an event handler. + * @param The event to handle + * @return true if the event has been handled and false otherwise. + */ + typedef bool (*event_handler_t)(const attEvt_t*); + +public: + /** + * Callback which handle attEvt_t and forward them to on_server_event. + */ + static void att_client_handler(const attEvt_t* event) + { + // all handlers are stored in a static array + static const event_handler_t handlers[] = { + &timeout_event_handler, + &event_handler<ErrorResponseConverter>, + &event_handler<ExchangeMtuResponseConverter>, + &event_handler<FindInformationResponseConverter>, + &event_handler<FindByTypeValueResponseConverter>, + &event_handler<ReadByTypeResponseConverter>, + &event_handler<ReadResponseConverter>, + &event_handler<ReadBlobResponseConverter>, + &event_handler<ReadMultipleResponseConverter>, + &event_handler<ReadBygroupTypeResponseConverter>, + &event_handler<WriteResponseConverter>, + &event_handler<PrepareWriteResponseConverter>, + &event_handler<ExecuteWriteResponseConverter>, + &event_handler<HandleValueIndicationConverter>, + &event_handler<HandleValueNotificationConverter> + }; + + // event->hdr.param: connection handle + // event->header.event: opcode from the request + // event->header.status: success or error code ... + // event->pValue: starting after opcode for response; starting after opcode + handle for server initiated responses. + // event->handle: handle for server initiated responses + + // traverse all handlers and execute them with the event in input. + // exit if an handler has handled the event. + for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) { + if (handlers[i](event)) { + return; + } + } + } + +private: + /** + * Event handler generator. + * @tparam Description of an event converter. It contains two static member + * function: + * - bool can_convert(const attEvt_t* event): return true if the event can + * be converted by the converter + * - <undefined> convert(const attEvt_t* event): return the + * AttServerMessage converted from event. + * @param event + * @return + */ + template<typename T> + static bool event_handler(const attEvt_t* event) + { + if (T::can_convert(event)) { + generated_handler(event, T::convert); + return true; + } + return false; + } + + static bool timeout_event_handler(const attEvt_t* event) + { + if(event->hdr.status != ATT_ERR_TIMEOUT) { + return false; + } + + get_client().on_transaction_timeout(event->hdr.param); + return true; + } + + template<typename ResultType> + static void generated_handler( + const attEvt_t* event, ResultType (*convert)(const attEvt_t*) + ) { + get_client().on_server_event( + event->hdr.param, + convert(event) + ); + } + + /** + * Traits defining can_convert for non ErrorResponse events. + */ + template<uint8_t RequestID> + struct ResponseConverter { + static bool can_convert(const attEvt_t* event) + { + if(event->hdr.status == ATT_SUCCESS && event->hdr.event == RequestID) { + return true; + } + return false; + } + }; + + /** + * Converter for an AttErrorResponse. + */ + struct ErrorResponseConverter { + static bool can_convert(const attEvt_t* event) + { + if(event->hdr.status != ATT_SUCCESS) { + return true; + } + return false; + } + + static AttErrorResponse convert(const attEvt_t* event) + { + return AttErrorResponse( + static_cast<AttributeOpcode::Code>(event->hdr.event * 2), + event->handle, + event->hdr.status + ); + } + }; + + /** + * Converter for an AttExchangeMTUResponse. + */ + struct ExchangeMtuResponseConverter { + static bool can_convert(const attEvt_t* event) + { + if(event->hdr.status == ATT_SUCCESS && + event->hdr.event == ATT_MTU_UPDATE_IND) { + return true; + } + return false; + } + + static AttExchangeMTUResponse convert(const attEvt_t* event) + { + return AttExchangeMTUResponse(event->mtu); + } + }; + + /** + * Converter for a SimpleAttFindInformationResponse. + */ + struct FindInformationResponseConverter : ResponseConverter<ATTC_FIND_INFO_RSP> { + static SimpleAttFindInformationResponse convert(const attEvt_t* event) + { + return SimpleAttFindInformationResponse( + static_cast<SimpleAttFindInformationResponse::Format>(event->pValue[0]), + make_const_ArrayView( + event->pValue + 1, + event->valueLen - 1 + ) + ); + } + }; + + /** + * Converter for a SimpleAttFindByTypeValueResponse. + */ + struct FindByTypeValueResponseConverter : ResponseConverter<ATTC_FIND_BY_TYPE_VALUE_RSP> { + static SimpleAttFindByTypeValueResponse convert(const attEvt_t* event) + { + return SimpleAttFindByTypeValueResponse( + make_const_ArrayView( + event->pValue, + event->valueLen + ) + ); + } + }; + + /** + * Converter for a SimpleAttReadByTypeResponse. + */ + struct ReadByTypeResponseConverter : ResponseConverter<ATTC_READ_BY_TYPE_RSP> { + static SimpleAttReadByTypeResponse convert(const attEvt_t* event) + { + return SimpleAttReadByTypeResponse( + event->pValue[0], + make_const_ArrayView( + event->pValue + 1, + event->valueLen - 1 + ) + ); + } + }; + + /** + * Converter for a AttReadResponse. + */ + struct ReadResponseConverter : ResponseConverter<ATTC_READ_RSP> { + static AttReadResponse convert(const attEvt_t* event) + { + return AttReadResponse( + make_const_ArrayView( + event->pValue, + event->valueLen + ) + ); + } + }; + + /** + * Converter for a AttReadBlobResponse. + */ + struct ReadBlobResponseConverter : ResponseConverter<ATTC_READ_LONG_RSP> { + static AttReadBlobResponse convert(const attEvt_t* event) + { + return AttReadBlobResponse( + make_const_ArrayView( + event->pValue, + event->valueLen + ) + ); + } + }; + + /** + * Converter for a AttReadMultipleResponse. + */ + struct ReadMultipleResponseConverter : ResponseConverter<ATTC_READ_MULTIPLE_RSP> { + static AttReadMultipleResponse convert(const attEvt_t* event) + { + return AttReadMultipleResponse( + make_const_ArrayView( + event->pValue, + event->valueLen + ) + ); + } + }; + + /** + * Converter for a SimpleAttReadByGroupTypeResponse. + */ + struct ReadBygroupTypeResponseConverter : ResponseConverter<ATTC_READ_BY_GROUP_TYPE_RSP> { + static SimpleAttReadByGroupTypeResponse convert(const attEvt_t* event) + { + return SimpleAttReadByGroupTypeResponse( + event->pValue[0], + make_const_ArrayView( + event->pValue + 1, + event->valueLen - 1 + ) + ); + } + }; + + /** + * Converter for a AttWriteResponse. + */ + struct WriteResponseConverter : ResponseConverter<ATTC_WRITE_RSP> { + static AttWriteResponse convert(const attEvt_t* event) + { + return AttWriteResponse(); + } + }; + + /** + * Converter for a AttPrepareWriteResponse. + */ + struct PrepareWriteResponseConverter : ResponseConverter<ATTC_PREPARE_WRITE_RSP> { + static AttPrepareWriteResponse convert(const attEvt_t* event) + { + // WARNING: Not sure if correct, the stack erase the length parameter + return AttPrepareWriteResponse( + event->handle, + to_uint16_t(event->pValue + 2), + // FIXME: the stack set the lenght to 0, the data won't be seen ... + make_const_ArrayView( + event->pValue + 4, + event->valueLen + ) + ); + } + }; + + /** + * Converter for a AttExecuteWriteResponse. + */ + struct ExecuteWriteResponseConverter : ResponseConverter<ATTC_EXECUTE_WRITE_RSP> { + static AttExecuteWriteResponse convert(const attEvt_t* event) + { + return AttExecuteWriteResponse(); + } + }; + + /** + * Converter for a AttHandleValueNotification. + */ + struct HandleValueNotificationConverter : ResponseConverter<ATTC_HANDLE_VALUE_NTF> { + static AttHandleValueNotification convert(const attEvt_t* event) + { + return AttHandleValueNotification( + event->handle, + make_const_ArrayView( + event->pValue, + event->valueLen + ) + ); + } + }; + + /** + * Converter for a AttHandleValueIndication. + */ + struct HandleValueIndicationConverter : ResponseConverter<ATTC_HANDLE_VALUE_IND> { + static AttHandleValueIndication convert(const attEvt_t* event) + { + return AttHandleValueIndication( + event->handle, + make_const_ArrayView( + event->pValue, + event->valueLen + ) + ); + } + }; +}; + +} // cordio +} // vendor +} // pal +} // ble + +#endif /* CORDIO_PAL_ATT_CLIENT_ */