/* mbed Microcontroller Library * Copyright (c) 2006-2020 ARM Limited * * SPDX-License-Identifier: Apache-2.0 * * 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. */ #include "mbed.h" #include "platform/CriticalSectionLock.h" #include "hal/us_ticker_api.h" #include "platform/mbed_assert.h" #include "ble/BLE.h" #include "ble/driver/CordioHCIDriver.h" #include "source/pal/PalAttClient.h" #include "source/pal/PalSecurityManager.h" #include "source/pal/PalGap.h" #include "source/pal/PalSigningMonitor.h" #include "source/pal/PalAttClientToGattClient.h" #include "source/BLEInstanceBaseImpl.h" #include "source/GattServerImpl.h" #include "source/PalSecurityManagerImpl.h" #include "source/PalAttClientImpl.h" #include "source/PalGenericAccessServiceImpl.h" #include "source/PalGapImpl.h" #include "wsf_types.h" #include "wsf_msg.h" #include "wsf_os.h" #include "wsf_buf.h" #include "wsf_timer.h" #include "hci_handler.h" #include "dm_handler.h" #include "l2c_handler.h" #include "att_handler.h" #include "smp_handler.h" #include "l2c_api.h" #include "att_api.h" #include "smp_api.h" #include "hci_drv.h" #include "bstream.h" using namespace std::chrono; /*! WSF handler ID */ wsfHandlerId_t stack_handler_id; /* WSF heap allocation */ uint8_t *SystemHeapStart; uint32_t SystemHeapSize; /** * Weak definition of ble_cordio_get_hci_driver. * A runtime error is generated if the user does not define any * ble_cordio_get_hci_driver. */ MBED_WEAK ble::CordioHCIDriver &ble_cordio_get_hci_driver() { MBED_ASSERT("No HCI driver"); printf("Please provide an implementation for the HCI driver"); ble::CordioHCIDriver *bad_instance = nullptr; return *bad_instance; } /** * Low level HCI interface between Cordio stack and the port. */ extern "C" uint16_t hci_mbed_os_drv_write(uint8_t type, uint16_t len, uint8_t *pData) { return ble_cordio_get_hci_driver().write(type, len, pData); } extern "C" void hci_mbed_os_start_reset_sequence(void) { ble_cordio_get_hci_driver().start_reset_sequence(); } extern "C" void hci_mbed_os_handle_reset_sequence(uint8_t *msg) { ble_cordio_get_hci_driver().handle_reset_sequence(msg); } /* * This function will signal to the user code by calling signalEventsToProcess. * It is registered and called into the Wsf Stack. */ extern "C" MBED_WEAK void wsf_mbed_ble_signal_event(void) { BLE::Instance().signalEventsToProcess(); } /** * BLE-API requires an implementation of the following function in order to * obtain its transport handle. */ ble::BLEInstanceBase *ble::createBLEInstance() { return (&(ble::impl::BLEInstanceBase::deviceInstance())); } namespace ble { namespace impl { BLEInstanceBase::BLEInstanceBase(CordioHCIDriver &hci_driver) : initialization_status(NOT_INITIALIZED), _event_queue(), _last_update_us(0) { _hci_driver = &hci_driver; stack_setup(); } BLEInstanceBase::~BLEInstanceBase() = default; /** * The singleton which represents the BLE transport for the BLE. */ BLEInstanceBase &BLEInstanceBase::deviceInstance() { static BLEInstanceBase instance( ble_cordio_get_hci_driver() ); return instance; } ble_error_t BLEInstanceBase::init( FunctionPointerWithContext<::BLE::InitializationCompleteCallbackContext *> initCallback ) { switch (initialization_status) { case NOT_INITIALIZED: _timer.reset(); _timer.start(); _event_queue.initialize(this); _init_callback = initCallback; start_stack_reset(); return BLE_ERROR_NONE; case INITIALIZING: return BLE_ERROR_INITIALIZATION_INCOMPLETE; case INITIALIZED: return BLE_ERROR_NONE; default: return BLE_ERROR_UNSPECIFIED; } } bool BLEInstanceBase::hasInitialized() const { return initialization_status == INITIALIZED; } ble_error_t BLEInstanceBase::shutdown() { if (initialization_status != INITIALIZED) { return BLE_ERROR_INITIALIZATION_INCOMPLETE; } initialization_status = NOT_INITIALIZED; _hci_driver->terminate(); #if BLE_FEATURE_GATT_SERVER getGattServer().reset(); #endif #if BLE_FEATURE_GATT_CLIENT getGattClient().reset(); #endif // BLE_FEATURE_GATT_CLIENT getGap().reset(); _event_queue.clear(); return BLE_ERROR_NONE; } const char *BLEInstanceBase::getVersion() { static const char version[] = "generic-cordio"; return version; } ble::impl::Gap &BLEInstanceBase::getGapImpl() { static ble::impl::PalGenericAccessService cordio_gap_service; static ble::impl::Gap gap( _event_queue, ble::impl::PalGap::get_gap(), cordio_gap_service, ble::impl::PalSecurityManager::get_security_manager() ); return gap; } ble::Gap &BLEInstanceBase::getGap() { auto &impl = getGapImpl(); static ble::Gap gap(&impl); return gap; } const ble::Gap &BLEInstanceBase::getGap() const { auto &self = const_cast<BLEInstanceBase &>(*this); return const_cast<const ble::Gap &>(self.getGap()); }; #if BLE_FEATURE_GATT_SERVER ble::impl::GattServer &BLEInstanceBase::getGattServerImpl() { return ble::impl::GattServer::getInstance(); } ble::GattServer &BLEInstanceBase::getGattServer() { auto &impl = getGattServerImpl(); static ble::GattServer server(&impl); return server; } const ble::GattServer &BLEInstanceBase::getGattServer() const { auto &self = const_cast<BLEInstanceBase &>(*this); return const_cast<const ble::GattServer &>(self.getGattServer()); } #endif // BLE_FEATURE_GATT_SERVER #if BLE_FEATURE_GATT_CLIENT ble::impl::GattClient &BLEInstanceBase::getGattClientImpl() { static ble::impl::GattClient gatt_client(getPalGattClient()); return gatt_client; } ble::GattClient &BLEInstanceBase::getGattClient() { auto &impl = getGattClientImpl(); static ble::GattClient gatt_client(&impl); impl.setInterface(&gatt_client); return gatt_client; } PalGattClient &BLEInstanceBase::getPalGattClient() { static PalAttClientToGattClient pal_gatt_client(impl::PalAttClient::get_client()); return pal_gatt_client; } #endif // BLE_FEATURE_GATT_CLIENT #if BLE_FEATURE_SECURITY ble::impl::SecurityManager &BLEInstanceBase::getSecurityManagerImpl() { // Creation of a proxy monitor to let the security manager register to // the gatt client and gatt server. static struct : ble::PalSigningMonitor { void set_signing_event_handler(PalSigningMonitorEventHandler *handler) final { #if BLE_FEATURE_GATT_CLIENT BLEInstanceBase::deviceInstance().getGattClientImpl().set_signing_event_handler(handler); #endif // BLE_FEATURE_GATT_CLIENT #if BLE_FEATURE_GATT_SERVER BLEInstanceBase::deviceInstance().getGattServerImpl().set_signing_event_handler(handler); #endif // BLE_FEATURE_GATT_SERVER } } signing_event_monitor; static ble::impl::SecurityManager m_instance( ble::impl::PalSecurityManager::get_security_manager(), getGapImpl(), signing_event_monitor ); return m_instance; } ble::SecurityManager &BLEInstanceBase::getSecurityManager() { static ble::SecurityManager m_instance(&getSecurityManagerImpl()); return m_instance; } const ble::SecurityManager &BLEInstanceBase::getSecurityManager() const { const BLEInstanceBase &self = const_cast<BLEInstanceBase &>(*this); return const_cast<const ble::SecurityManager &>(self.getSecurityManager()); } #endif // BLE_FEATURE_SECURITY void BLEInstanceBase::waitForEvent() { static Timeout nextTimeout; timestamp_t nextTimestamp; bool_t pTimerRunning; callDispatcher(); if (wsfOsReadyToSleep()) { // setup an mbed timer for the next cordio timeout nextTimestamp = (timestamp_t) (WsfTimerNextExpiration(&pTimerRunning) * WSF_MS_PER_TICK); if (pTimerRunning) { nextTimeout.attach(timeoutCallback, milliseconds(nextTimestamp)); } } } void BLEInstanceBase::processEvents() { callDispatcher(); } void BLEInstanceBase::stack_handler(wsfEventMask_t event, wsfMsgHdr_t *msg) { if (msg == nullptr) { return; } #if BLE_FEATURE_SECURITY if (ble::impl::PalSecurityManager::get_security_manager().sm_handler(msg)) { return; } #endif // BLE_FEATURE_SECURITY switch (msg->event) { case DM_RESET_CMPL_IND: { ::BLE::InitializationCompleteCallbackContext context = { ::BLE::Instance(), BLE_ERROR_NONE }; #if BLE_FEATURE_EXTENDED_ADVERTISING // initialize extended module if supported if (HciGetLeSupFeat() & HCI_LE_SUP_FEAT_LE_EXT_ADV) { #if BLE_ROLE_BROADCASTER DmExtAdvInit(); #endif // BLE_ROLE_BROADCASTER #if BLE_ROLE_OBSERVER DmExtScanInit(); #endif // BLE_ROLE_OBSERVER #if BLE_ROLE_CENTRAL DmExtConnMasterInit(); #endif // BLE_ROLE_CENTRAL #if BLE_ROLE_PERIPHERAL DmExtConnSlaveInit(); #endif // BLE_ROLE_PERIPHERAL } #endif // BLE_FEATURE_EXTENDED_ADVERTISING #if BLE_FEATURE_GATT_SERVER deviceInstance().getGattServerImpl().initialize(); #endif deviceInstance().initialization_status = INITIALIZED; _init_callback.call(&context); } break; #if MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS case DM_UNHANDLED_CMD_CMPL_EVT_IND: { // upcast to unhandled command complete event to access the payload hciUnhandledCmdCmplEvt_t *unhandled = (hciUnhandledCmdCmplEvt_t *) msg; if (unhandled->hdr.status == HCI_SUCCESS && unhandled->hdr.param == HCI_OPCODE_LE_TEST_END) { // unhandled events are not parsed so we need to parse the payload ourselves uint8_t status; uint16_t packet_number; status = unhandled->param[0]; BYTES_TO_UINT16(packet_number, unhandled->param + 1); _hci_driver->handle_test_end(status == 0, packet_number); return; } } break; #endif // MBED_CONF_CORDIO_ROUTE_UNHANDLED_COMMAND_COMPLETE_EVENTS default: ble::impl::PalGap::gap_handler(msg); break; } } void BLEInstanceBase::device_manager_cb(dmEvt_t *dm_event) { if (dm_event->hdr.status == HCI_SUCCESS && dm_event->hdr.event == DM_CONN_DATA_LEN_CHANGE_IND) { // this event can only happen after a connection has been established therefore gap is present ble::PalGapEventHandler *handler; handler = ble::impl::PalGap::get_gap().get_event_handler(); if (handler) { handler->on_data_length_change( dm_event->hdr.param, dm_event->dataLenChange.maxTxOctets, dm_event->dataLenChange.maxRxOctets ); } return; } BLEInstanceBase::deviceInstance().stack_handler(0, &dm_event->hdr); } /* * AttServerInitDeInitCback callback is used to Initialize/Deinitialize * the CCC Table of the ATT Server when a remote peer requests to Open * or Close the connection. */ void BLEInstanceBase::connection_handler(dmEvt_t *dm_event) { dmConnId_t connId = (dmConnId_t) dm_event->hdr.param; switch (dm_event->hdr.event) { case DM_CONN_OPEN_IND: /* set up CCC table with uninitialized (all zero) values */ AttsCccInitTable(connId, nullptr); break; case DM_CONN_CLOSE_IND: /* clear CCC table on connection close */ AttsCccClearTable(connId); break; default: break; } } void BLEInstanceBase::timeoutCallback() { wsf_mbed_ble_signal_event(); } void BLEInstanceBase::stack_setup() { MBED_ASSERT(_hci_driver != nullptr); wsfHandlerId_t handlerId; buf_pool_desc_t buf_pool_desc = _hci_driver->get_buffer_pool_description(); // use the buffer for the WSF heap SystemHeapStart = buf_pool_desc.buffer_memory; SystemHeapSize = buf_pool_desc.buffer_size; // Initialize buffers with the ones provided by the HCI driver uint16_t bytes_used = WsfBufInit(buf_pool_desc.pool_count, (wsfBufPoolDesc_t *) buf_pool_desc.pool_description); // Raise assert if not enough memory was allocated MBED_ASSERT(bytes_used != 0); SystemHeapStart += bytes_used; SystemHeapSize -= bytes_used; // This warning will be raised if we've allocated too much memory if (bytes_used < buf_pool_desc.buffer_size) { MBED_WARNING1(MBED_MAKE_ERROR(MBED_MODULE_BLE, MBED_ERROR_CODE_INVALID_SIZE), "Too much memory allocated for Cordio memory pool, reduce buf_pool_desc.buffer_size by value below.", buf_pool_desc.buffer_size - bytes_used); } WsfTimerInit(); // Note: SecInit required for RandInit. SecInit(); SecRandInit(); #if BLE_FEATURE_SECURITY SecAesInit(); SecCmacInit(); SecEccInit(); #endif handlerId = WsfOsSetNextHandler(HciHandler); HciHandlerInit(handlerId); handlerId = WsfOsSetNextHandler(DmHandler); #if BLE_ROLE_BROADCASTER DmAdvInit(); #endif #if BLE_ROLE_OBSERVER DmScanInit(); #endif #if BLE_FEATURE_CONNECTABLE DmConnInit(); #endif #if BLE_ROLE_CENTRAL DmConnMasterInit(); #endif #if BLE_ROLE_PERIPHERAL DmConnSlaveInit(); #endif #if BLE_FEATURE_SECURITY DmSecInit(); #endif #if BLE_FEATURE_PHY_MANAGEMENT DmPhyInit(); #endif #if BLE_FEATURE_SECURE_CONNECTIONS DmSecLescInit(); #endif #if BLE_FEATURE_PRIVACY DmPrivInit(); #endif DmHandlerInit(handlerId); #if BLE_ROLE_PERIPHERAL handlerId = WsfOsSetNextHandler(L2cSlaveHandler); L2cSlaveHandlerInit(handlerId); #endif #if BLE_FEATURE_CONNECTABLE L2cInit(); #endif #if BLE_ROLE_PERIPHERAL L2cSlaveInit(); #endif #if BLE_ROLE_CENTRAL L2cMasterInit(); #endif #if BLE_FEATURE_ATT handlerId = WsfOsSetNextHandler(AttHandler); AttHandlerInit(handlerId); #if BLE_FEATURE_GATT_SERVER AttsInit(); AttsIndInit(); #if BLE_FEATURE_SECURITY AttsAuthorRegister(impl::GattServer::atts_auth_cb); #endif #if BLE_FEATURE_SIGNING AttsSignInit(); #endif #endif // BLE_FEATURE_GATT_SERVER #if BLE_FEATURE_GATT_CLIENT AttcInit(); #if BLE_FEATURE_SIGNING AttcSignInit(); #endif #endif // BLE_FEATURE_GATT_CLIENT #endif // BLE_FEATURE_ATT #if BLE_FEATURE_SECURITY handlerId = WsfOsSetNextHandler(SmpHandler); SmpHandlerInit(handlerId); #if BLE_ROLE_PERIPHERAL SmprInit(); #if BLE_FEATURE_SECURE_CONNECTIONS SmprScInit(); #endif #endif #if BLE_ROLE_CENTRAL SmpiInit(); #if BLE_FEATURE_SECURE_CONNECTIONS SmpiScInit(); #endif #endif // BLE_ROLE_CENTRAL #endif // BLE_FEATURE_SECURITY stack_handler_id = WsfOsSetNextHandler(&BLEInstanceBase::stack_handler); HciSetMaxRxAclLen(MBED_CONF_CORDIO_RX_ACL_BUFFER_SIZE); DmRegister(BLEInstanceBase::device_manager_cb); #if BLE_FEATURE_CONNECTABLE DmConnRegister(DM_CLIENT_ID_APP, BLEInstanceBase::device_manager_cb); #endif #if BLE_FEATURE_GATT_SERVER AttConnRegister(BLEInstanceBase::connection_handler); #endif #if BLE_FEATURE_ATT #if BLE_FEATURE_GATT_CLIENT AttRegister((attCback_t) impl::PalAttClient::att_client_handler); #else AttRegister((attCback_t) ble::GattServer::att_cb); #endif // BLE_FEATURE_GATT_CLIENT #endif } void BLEInstanceBase::start_stack_reset() { _hci_driver->initialize(); DmDevReset(); } void BLEInstanceBase::callDispatcher() { // process the external event queue _event_queue.process(); _last_update_us += (uint64_t) _timer.elapsed_time().count(); _timer.reset(); uint64_t last_update_ms = (_last_update_us / 1000); wsfTimerTicks_t wsf_ticks = (last_update_ms / WSF_MS_PER_TICK); if (wsf_ticks > 0) { WsfTimerUpdate(wsf_ticks); _last_update_us -= (last_update_ms * 1000); } wsfOsDispatcher(); static LowPowerTimeout nextTimeout; CriticalSectionLock critical_section; if (wsfOsReadyToSleep()) { // setup an mbed timer for the next Cordio timeout bool_t pTimerRunning; timestamp_t nextTimestamp = (timestamp_t) (WsfTimerNextExpiration(&pTimerRunning) * WSF_MS_PER_TICK); if (pTimerRunning) { nextTimeout.attach(timeoutCallback, milliseconds(nextTimestamp)); } else { critical_section.disable(); _hci_driver->on_host_stack_inactivity(); } } } CordioHCIDriver *BLEInstanceBase::_hci_driver = nullptr; FunctionPointerWithContext<::BLE::InitializationCompleteCallbackContext *> BLEInstanceBase::_init_callback; } // namespace impl } // namespace ble