mbed-os
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
features/FEATURE_BLE/targets/TARGET_CORDIO/CordioPalAttClient.h
- Committer:
- be_bryan
- Date:
- 2017-12-11
- Revision:
- 0:b74591d5ab33
File content as of revision 0:b74591d5ab33:
/* 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_ */