mbed-os
Dependents: cobaLCDJoyMotor_Thread odometry_omni_3roda_v3 odometry_omni_3roda_v1 odometry_omni_3roda_v2 ... more
Diff: features/FEATURE_BLE/targets/TARGET_Maxim/MaximBLE.cpp
- Revision:
- 0:b74591d5ab33
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/features/FEATURE_BLE/targets/TARGET_Maxim/MaximBLE.cpp Mon Dec 11 17:54:04 2017 +0000 @@ -0,0 +1,361 @@ +/******************************************************************************* + * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES + * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of Maxim Integrated + * Products, Inc. shall not be used except as stated in the Maxim Integrated + * Products, Inc. Branding Policy. + * + * The mere transfer of this software does not imply any licenses + * of trade secrets, proprietary technology, copyrights, patents, + * trademarks, maskwork rights, or any other form of intellectual + * property whatsoever. Maxim Integrated Products, Inc. retains all + * ownership rights. + ******************************************************************************* + */ + +#include "mbed.h" +#include "us_ticker_api.h" +#include "MaximBLE.h" +#include "wsf_types.h" +#include "wsf_msg.h" +#include "wsf_os.h" +#include "wsf_buf.h" +#include "wsf_sec.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 "hci_vs.h" + +/* Number of WSF buffer pools */ +#define WSF_BUF_POOLS 5 + +/*! Free memory for pool buffers. */ +static uint8_t mainBufMem[1040]; + +/*! Default pool descriptor. */ +static wsfBufPoolDesc_t mainPoolDesc[WSF_BUF_POOLS] = +{ + { 16, 8 }, + { 32, 4 }, + { 64, 2 }, + { 128, 2 }, + { 272, 1 } +}; + +/* Store the Event signalling */ +bool isEventsSignaled = false; + +/*! WSF handler ID */ +wsfHandlerId_t maximHandlerId; +static volatile int reset_complete; + +#ifdef BLE_HCI_UART +static DigitalIn _rts(BT_CTS); +static DigitalIn _cts(BT_RTS); +static DigitalIn _clk(BT_CLK); +static DigitalOut _shutdown(BT_RST, 0); +static Serial _uart(BT_TX, BT_RX, 115200); +#else +/* Current mbed SPI API does not support HW slave selects. Configured in HCI driver. */ +static DigitalOut _csn(HCI_CSN, 1); +static SPI _spi(HCI_MOSI, HCI_MISO, HCI_SCK, HCI_CSN); +static DigitalOut _rst(HCI_RST, 0); +static InterruptIn _irq(HCI_IRQ); +#endif + +/** + * The singleton which represents the MaximBLE transport for the BLE. + */ +static MaximBLE deviceInstance; + +extern "C" { + +/* + * This function will signal to the user code by calling signalEventsToProcess. + * It is registered and called into the Wsf Stack. + */ +void wsf_mbed_ble_signal_event(void) +{ + if (isEventsSignaled == false) { + isEventsSignaled = true; + deviceInstance.signalEventsToProcess(::BLE::DEFAULT_INSTANCE); + } +} + +} + +/** + * BLE-API requires an implementation of the following function in order to + * obtain its transport handle. + */ +BLEInstanceBase *createBLEInstance(void) +{ + return (&deviceInstance); +} + +MaximBLE::MaximBLE(void) : initialized(false), instanceID(BLE::DEFAULT_INSTANCE) +{ +} + +MaximBLE::~MaximBLE(void) +{ +} + +const char *MaximBLE::getVersion(void) +{ + static char versionString[32]; + + strncpy(versionString, "unknown", sizeof(versionString)); + + return versionString; +} + +static void DmCback(dmEvt_t *pDmEvt) +{ + dmEvt_t *pMsg; + + if ((pMsg = (dmEvt_t*)WsfMsgAlloc(sizeof(dmEvt_t))) != NULL) + { + memcpy(pMsg, pDmEvt, sizeof(dmEvt_t)); + WsfMsgSend(maximHandlerId, pMsg); + } +} + +static void maximHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg) +{ + if (pMsg != NULL) + { + switch(pMsg->event) + { + case DM_RESET_CMPL_IND: + reset_complete = 1; + break; + case DM_ADV_START_IND: + break; + case DM_ADV_STOP_IND: + MaximGap::getInstance().advertisingStopped(); + break; + case DM_SCAN_REPORT_IND: + { + hciLeAdvReportEvt_t *scanReport = (hciLeAdvReportEvt_t*)pMsg; + MaximGap::getInstance().processAdvertisementReport( scanReport->addr, + scanReport->rssi, + (scanReport->eventType == DM_ADV_SCAN_RESPONSE) ? true : false, + (GapAdvertisingParams::AdvertisingType_t)scanReport->eventType, + scanReport->len, + scanReport->pData); + } + break; + case DM_CONN_OPEN_IND: + { + hciLeConnCmplEvt_t *connOpen = (hciLeConnCmplEvt_t*)pMsg; + MaximGap::getInstance().setConnectionHandle(connOpen->handle); + Gap::ConnectionParams_t params = { connOpen->connInterval, connOpen->connInterval, connOpen->connLatency, connOpen->supTimeout }; + Gap::AddressType_t ownAddrType; + Gap::Address_t ownAddr; + MaximGap::getInstance().getAddress(&ownAddrType, ownAddr); + MaximGap::getInstance().processConnectionEvent(connOpen->handle, + Gap::PERIPHERAL, + (Gap::AddressType_t)connOpen->addrType, + connOpen->peerAddr, + ownAddrType, + ownAddr, + ¶ms); + } + break; + case DM_CONN_CLOSE_IND: + { + hciDisconnectCmplEvt_t *connClose = (hciDisconnectCmplEvt_t*)pMsg; + MaximGap::getInstance().setConnectionHandle(DM_CONN_ID_NONE); + MaximGap::getInstance().processDisconnectionEvent(connClose->handle, (Gap::DisconnectionReason_t)connClose->reason); + } + break; + case DM_HW_ERROR_IND: + { + hciHwErrorEvt_t *error = (hciHwErrorEvt_t*)pMsg; + printf("HCI Hardware Error 0x%02x occurred\n", error->code); + } + break; + default: + break; + } + } +} + +static void AppServerConnCback(dmEvt_t *pDmEvt) +{ + dmConnId_t connId = (dmConnId_t)pDmEvt->hdr.param; + + switch (pDmEvt->hdr.event) + { + case DM_CONN_OPEN_IND: + /* set up CCC table with uninitialized (all zero) values */ + AttsCccInitTable(connId, NULL); + break; + case DM_CONN_CLOSE_IND: + /* clear CCC table on connection close */ + AttsCccClearTable(connId); + break; + default: + break; + } +} + +ble_error_t MaximBLE::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext<BLE::InitializationCompleteCallbackContext *> initCallback) +{ + wsfHandlerId_t handlerId; + + /* init OS subsystems */ + WsfTimerInit(1); + WsfBufInit(sizeof(mainBufMem), mainBufMem, WSF_BUF_POOLS, mainPoolDesc); + WsfSecInit(); + + /* init stack */ + handlerId = WsfOsSetNextHandler(HciHandler); + HciHandlerInit(handlerId); + + handlerId = WsfOsSetNextHandler(DmHandler); + DmAdvInit(); + DmScanInit(); + DmConnInit(); + DmConnSlaveInit(); + DmSecInit(); + DmHandlerInit(handlerId); + + handlerId = WsfOsSetNextHandler(L2cSlaveHandler); + L2cSlaveHandlerInit(handlerId); + L2cInit(); + L2cMasterInit(); + L2cSlaveInit(); + + handlerId = WsfOsSetNextHandler(AttHandler); + AttHandlerInit(handlerId); + AttsInit(); + AttsIndInit(); + AttcInit(); + + handlerId = WsfOsSetNextHandler(SmpHandler); + SmpHandlerInit(handlerId); + SmpiInit(); + SmprInit(); + + /* store handler ID */ + maximHandlerId = WsfOsSetNextHandler(maximHandler); + + /* init HCI */ +#ifdef BLE_HCI_UART + hciDrvInit(BT_TX, BT_RST, BT_CLK); +#else + _irq.disable_irq(); + _irq.rise(hciDrvIsr); + _irq.fall(NULL); + hciDrvInit(HCI_CSN, HCI_RST, HCI_IRQ); +#endif + + /* Register for stack callbacks */ + DmRegister(DmCback); + DmConnRegister(DM_CLIENT_ID_APP, DmCback); + AttConnRegister(AppServerConnCback); + + /* Reset the device */ + reset_complete = 0; + DmDevReset(); + + while (!reset_complete) { + callDispatcher(); + } + + initialized = true; + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_NONE + }; + initCallback.call(&context); + return BLE_ERROR_NONE; +} + +ble_error_t MaximBLE::shutdown(void) +{ + return BLE_ERROR_NOT_IMPLEMENTED; +} + +void MaximBLE::waitForEvent(void) +{ + static LowPowerTimeout nextTimeout; + timestamp_t nextTimestamp; + bool_t pTimerRunning; + + callDispatcher(); + + if (wsfOsReadyToSleep()) { + // setup an mbed timer for the next Wicentric timeout + nextTimestamp = (timestamp_t)WsfTimerNextExpiration(&pTimerRunning) * 1000; + if (pTimerRunning) { + nextTimeout.attach_us(timeoutCallback, nextTimestamp); + } + + // go to sleep + if (hciDrvReadyToSleep()) { + // go to deep sleep + deepsleep(); + hciDrvResume(); + } + else { + sleep(); + } + } +} + +void MaximBLE::processEvents() +{ + if (isEventsSignaled) { + isEventsSignaled = false; + callDispatcher(); + } +} + +void MaximBLE::timeoutCallback(void) +{ + wsf_mbed_ble_signal_event(); +} + +void MaximBLE::callDispatcher(void) +{ + static uint32_t lastTimeUs = us_ticker_read(); + uint32_t currTimeUs, deltaTimeMs; + + // Update the current Wicentric time + currTimeUs = us_ticker_read(); + deltaTimeMs = (currTimeUs - lastTimeUs) / 1000; + if (deltaTimeMs > 0) { + WsfTimerUpdate(deltaTimeMs); + lastTimeUs += deltaTimeMs * 1000; + } + + wsfOsDispatcher(); +}