/******************************************************************************* * 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 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(); }