Maxim Integrated Bluetooth LE Library

Dependents:   BLE_Thermometer MAXWSNENV_demo

Committer:
enginerd
Date:
Thu Oct 06 22:02:31 2016 +0000
Revision:
5:5b87f64ce81e
Parent:
2:03b194d1fc90
Added new required method.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
enginerd 0:b562096246b3 1 /*******************************************************************************
enginerd 0:b562096246b3 2 * Copyright (C) 2016 Maxim Integrated Products, Inc., All Rights Reserved.
enginerd 0:b562096246b3 3 *
enginerd 0:b562096246b3 4 * Permission is hereby granted, free of charge, to any person obtaining a
enginerd 0:b562096246b3 5 * copy of this software and associated documentation files (the "Software"),
enginerd 0:b562096246b3 6 * to deal in the Software without restriction, including without limitation
enginerd 0:b562096246b3 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
enginerd 0:b562096246b3 8 * and/or sell copies of the Software, and to permit persons to whom the
enginerd 0:b562096246b3 9 * Software is furnished to do so, subject to the following conditions:
enginerd 0:b562096246b3 10 *
enginerd 0:b562096246b3 11 * The above copyright notice and this permission notice shall be included
enginerd 0:b562096246b3 12 * in all copies or substantial portions of the Software.
enginerd 0:b562096246b3 13 *
enginerd 0:b562096246b3 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
enginerd 0:b562096246b3 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
enginerd 0:b562096246b3 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
enginerd 0:b562096246b3 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
enginerd 0:b562096246b3 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
enginerd 0:b562096246b3 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
enginerd 0:b562096246b3 20 * OTHER DEALINGS IN THE SOFTWARE.
enginerd 0:b562096246b3 21 *
enginerd 0:b562096246b3 22 * Except as contained in this notice, the name of Maxim Integrated
enginerd 0:b562096246b3 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
enginerd 0:b562096246b3 24 * Products, Inc. Branding Policy.
enginerd 0:b562096246b3 25 *
enginerd 0:b562096246b3 26 * The mere transfer of this software does not imply any licenses
enginerd 0:b562096246b3 27 * of trade secrets, proprietary technology, copyrights, patents,
enginerd 0:b562096246b3 28 * trademarks, maskwork rights, or any other form of intellectual
enginerd 0:b562096246b3 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
enginerd 0:b562096246b3 30 * ownership rights.
enginerd 0:b562096246b3 31 *******************************************************************************
enginerd 0:b562096246b3 32 */
enginerd 0:b562096246b3 33
enginerd 0:b562096246b3 34 #include "mbed.h"
enginerd 0:b562096246b3 35 #include "us_ticker_api.h"
enginerd 0:b562096246b3 36 #include "MaximBLE.h"
enginerd 0:b562096246b3 37 #include "wsf_types.h"
enginerd 0:b562096246b3 38 #include "wsf_msg.h"
enginerd 0:b562096246b3 39 #include "wsf_os.h"
enginerd 0:b562096246b3 40 #include "wsf_buf.h"
enginerd 0:b562096246b3 41 #include "wsf_sec.h"
enginerd 0:b562096246b3 42 #include "wsf_timer.h"
enginerd 0:b562096246b3 43 #include "hci_handler.h"
enginerd 0:b562096246b3 44 #include "dm_handler.h"
enginerd 0:b562096246b3 45 #include "l2c_handler.h"
enginerd 0:b562096246b3 46 #include "att_handler.h"
enginerd 0:b562096246b3 47 #include "smp_handler.h"
enginerd 0:b562096246b3 48 #include "l2c_api.h"
enginerd 0:b562096246b3 49 #include "att_api.h"
enginerd 0:b562096246b3 50 #include "smp_api.h"
enginerd 0:b562096246b3 51 #include "hci_drv.h"
enginerd 0:b562096246b3 52 #include "hci_vs.h"
enginerd 0:b562096246b3 53
enginerd 0:b562096246b3 54 /* Number of WSF buffer pools */
enginerd 0:b562096246b3 55 #define WSF_BUF_POOLS 4
enginerd 0:b562096246b3 56
enginerd 0:b562096246b3 57 /*! Free memory for pool buffers. */
enginerd 0:b562096246b3 58 static uint8_t mainBufMem[768];
enginerd 0:b562096246b3 59
enginerd 0:b562096246b3 60 /*! Default pool descriptor. */
enginerd 0:b562096246b3 61 static wsfBufPoolDesc_t mainPoolDesc[WSF_BUF_POOLS] =
enginerd 0:b562096246b3 62 {
enginerd 0:b562096246b3 63 { 16, 8 },
enginerd 0:b562096246b3 64 { 32, 4 },
enginerd 0:b562096246b3 65 { 64, 2 },
enginerd 0:b562096246b3 66 { 128, 2 }
enginerd 0:b562096246b3 67 };
enginerd 0:b562096246b3 68
enginerd 0:b562096246b3 69 /*! WSF handler ID */
enginerd 0:b562096246b3 70 wsfHandlerId_t maximHandlerId;
enginerd 0:b562096246b3 71 static volatile int reset_complete;
enginerd 0:b562096246b3 72
enginerd 0:b562096246b3 73 /* Current mbed SPI API does not support HW slave selects. Configured in HCI driver. */
enginerd 0:b562096246b3 74 static DigitalOut _csn(HCI_CSN, 1);
Jeremy Brodt 2:03b194d1fc90 75 static SPI _spi(HCI_MOSI, HCI_MISO, HCI_SCK, HCI_CSN);
enginerd 0:b562096246b3 76 static DigitalOut _rst(HCI_RST, 0);
enginerd 0:b562096246b3 77 static InterruptIn _irq(HCI_IRQ);
enginerd 0:b562096246b3 78
enginerd 0:b562096246b3 79 /**
enginerd 0:b562096246b3 80 * The singleton which represents the MaximBLE transport for the BLE.
enginerd 0:b562096246b3 81 */
enginerd 0:b562096246b3 82 static MaximBLE deviceInstance;
enginerd 0:b562096246b3 83
enginerd 0:b562096246b3 84 /**
enginerd 0:b562096246b3 85 * BLE-API requires an implementation of the following function in order to
enginerd 0:b562096246b3 86 * obtain its transport handle.
enginerd 0:b562096246b3 87 */
enginerd 0:b562096246b3 88 BLEInstanceBase *createBLEInstance(void)
enginerd 0:b562096246b3 89 {
enginerd 0:b562096246b3 90 return (&deviceInstance);
enginerd 0:b562096246b3 91 }
enginerd 0:b562096246b3 92
enginerd 0:b562096246b3 93 MaximBLE::MaximBLE(void) : initialized(false), instanceID(BLE::DEFAULT_INSTANCE)
enginerd 0:b562096246b3 94 {
enginerd 0:b562096246b3 95 }
enginerd 0:b562096246b3 96
enginerd 0:b562096246b3 97 MaximBLE::~MaximBLE(void)
enginerd 0:b562096246b3 98 {
enginerd 0:b562096246b3 99 }
enginerd 0:b562096246b3 100
enginerd 0:b562096246b3 101 const char *MaximBLE::getVersion(void)
enginerd 0:b562096246b3 102 {
enginerd 0:b562096246b3 103 static char versionString[32];
enginerd 0:b562096246b3 104
enginerd 0:b562096246b3 105 strncpy(versionString, "unknown", sizeof(versionString));
enginerd 0:b562096246b3 106
enginerd 0:b562096246b3 107 return versionString;
enginerd 0:b562096246b3 108 }
enginerd 0:b562096246b3 109
enginerd 0:b562096246b3 110 static void DmCback(dmEvt_t *pDmEvt)
enginerd 0:b562096246b3 111 {
enginerd 0:b562096246b3 112 dmEvt_t *pMsg;
enginerd 0:b562096246b3 113
enginerd 0:b562096246b3 114 if ((pMsg = (dmEvt_t*)WsfMsgAlloc(sizeof(dmEvt_t))) != NULL)
enginerd 0:b562096246b3 115 {
enginerd 0:b562096246b3 116 memcpy(pMsg, pDmEvt, sizeof(dmEvt_t));
enginerd 0:b562096246b3 117 WsfMsgSend(maximHandlerId, pMsg);
enginerd 0:b562096246b3 118 }
enginerd 0:b562096246b3 119 }
enginerd 0:b562096246b3 120
enginerd 0:b562096246b3 121 static void maximHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg)
enginerd 0:b562096246b3 122 {
enginerd 0:b562096246b3 123 if (pMsg != NULL)
enginerd 0:b562096246b3 124 {
enginerd 0:b562096246b3 125 switch(pMsg->event)
enginerd 0:b562096246b3 126 {
enginerd 0:b562096246b3 127 case DM_RESET_CMPL_IND:
enginerd 0:b562096246b3 128 reset_complete = 1;
enginerd 0:b562096246b3 129 break;
enginerd 0:b562096246b3 130 case DM_ADV_START_IND:
enginerd 0:b562096246b3 131 break;
enginerd 0:b562096246b3 132 case DM_ADV_STOP_IND:
enginerd 0:b562096246b3 133 MaximGap::getInstance().advertisingStopped();
enginerd 0:b562096246b3 134 break;
enginerd 0:b562096246b3 135 case DM_SCAN_REPORT_IND:
enginerd 0:b562096246b3 136 {
enginerd 0:b562096246b3 137 hciLeAdvReportEvt_t *scanReport = (hciLeAdvReportEvt_t*)pMsg;
enginerd 0:b562096246b3 138 MaximGap::getInstance().processAdvertisementReport( scanReport->addr,
enginerd 0:b562096246b3 139 scanReport->rssi,
enginerd 0:b562096246b3 140 (scanReport->eventType == DM_ADV_SCAN_RESPONSE) ? true : false,
enginerd 0:b562096246b3 141 (GapAdvertisingParams::AdvertisingType_t)scanReport->eventType,
enginerd 0:b562096246b3 142 scanReport->len,
enginerd 0:b562096246b3 143 scanReport->pData);
enginerd 0:b562096246b3 144 }
enginerd 0:b562096246b3 145 break;
enginerd 0:b562096246b3 146 case DM_CONN_OPEN_IND:
enginerd 0:b562096246b3 147 {
enginerd 0:b562096246b3 148 hciLeConnCmplEvt_t *connOpen = (hciLeConnCmplEvt_t*)pMsg;
enginerd 0:b562096246b3 149 MaximGap::getInstance().setConnectionHandle(connOpen->handle);
enginerd 0:b562096246b3 150 Gap::ConnectionParams_t params = { connOpen->connInterval, connOpen->connInterval, connOpen->connLatency, connOpen->supTimeout };
enginerd 0:b562096246b3 151 Gap::AddressType_t ownAddrType;
enginerd 0:b562096246b3 152 Gap::Address_t ownAddr;
enginerd 0:b562096246b3 153 MaximGap::getInstance().getAddress(&ownAddrType, ownAddr);
enginerd 0:b562096246b3 154 MaximGap::getInstance().processConnectionEvent(connOpen->handle,
enginerd 0:b562096246b3 155 Gap::PERIPHERAL,
enginerd 0:b562096246b3 156 (Gap::AddressType_t)connOpen->addrType,
enginerd 0:b562096246b3 157 connOpen->peerAddr,
enginerd 0:b562096246b3 158 ownAddrType,
enginerd 0:b562096246b3 159 ownAddr,
enginerd 0:b562096246b3 160 &params);
enginerd 0:b562096246b3 161 }
enginerd 0:b562096246b3 162 break;
enginerd 0:b562096246b3 163 case DM_CONN_CLOSE_IND:
enginerd 0:b562096246b3 164 {
enginerd 0:b562096246b3 165 hciDisconnectCmplEvt_t *connClose = (hciDisconnectCmplEvt_t*)pMsg;
enginerd 0:b562096246b3 166 MaximGap::getInstance().setConnectionHandle(DM_CONN_ID_NONE);
enginerd 0:b562096246b3 167 MaximGap::getInstance().processDisconnectionEvent(connClose->handle, (Gap::DisconnectionReason_t)connClose->reason);
enginerd 0:b562096246b3 168 }
enginerd 0:b562096246b3 169 break;
enginerd 0:b562096246b3 170 case DM_HW_ERROR_IND:
enginerd 0:b562096246b3 171 {
enginerd 0:b562096246b3 172 hciHwErrorEvt_t *error = (hciHwErrorEvt_t*)pMsg;
enginerd 0:b562096246b3 173 printf("HCI Hardware Error 0x%02x occurred\n", error->code);
enginerd 0:b562096246b3 174 }
enginerd 0:b562096246b3 175 break;
enginerd 0:b562096246b3 176 default:
enginerd 0:b562096246b3 177 break;
enginerd 0:b562096246b3 178 }
enginerd 0:b562096246b3 179 }
enginerd 0:b562096246b3 180 }
enginerd 0:b562096246b3 181
enginerd 0:b562096246b3 182 static void AppServerConnCback(dmEvt_t *pDmEvt)
enginerd 0:b562096246b3 183 {
enginerd 0:b562096246b3 184 dmConnId_t connId = (dmConnId_t)pDmEvt->hdr.param;
enginerd 0:b562096246b3 185
enginerd 0:b562096246b3 186 switch (pDmEvt->hdr.event)
enginerd 0:b562096246b3 187 {
enginerd 0:b562096246b3 188 case DM_CONN_OPEN_IND:
enginerd 0:b562096246b3 189 /* set up CCC table with uninitialized (all zero) values */
enginerd 0:b562096246b3 190 AttsCccInitTable(connId, NULL);
enginerd 0:b562096246b3 191 break;
enginerd 0:b562096246b3 192 case DM_CONN_CLOSE_IND:
enginerd 0:b562096246b3 193 /* clear CCC table on connection close */
enginerd 0:b562096246b3 194 AttsCccClearTable(connId);
enginerd 0:b562096246b3 195 break;
enginerd 0:b562096246b3 196 default:
enginerd 0:b562096246b3 197 break;
enginerd 0:b562096246b3 198 }
enginerd 0:b562096246b3 199 }
enginerd 0:b562096246b3 200
enginerd 0:b562096246b3 201 ble_error_t MaximBLE::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext<BLE::InitializationCompleteCallbackContext *> initCallback)
enginerd 0:b562096246b3 202 {
enginerd 0:b562096246b3 203 wsfHandlerId_t handlerId;
enginerd 0:b562096246b3 204
enginerd 0:b562096246b3 205 /* init OS subsystems */
enginerd 0:b562096246b3 206 WsfTimerInit(1);
enginerd 0:b562096246b3 207 WsfBufInit(sizeof(mainBufMem), mainBufMem, WSF_BUF_POOLS, mainPoolDesc);
enginerd 0:b562096246b3 208 WsfSecInit();
enginerd 0:b562096246b3 209
enginerd 0:b562096246b3 210 /* init stack */
enginerd 0:b562096246b3 211 handlerId = WsfOsSetNextHandler(HciHandler);
enginerd 0:b562096246b3 212 HciHandlerInit(handlerId);
enginerd 0:b562096246b3 213
enginerd 0:b562096246b3 214 handlerId = WsfOsSetNextHandler(DmHandler);
enginerd 0:b562096246b3 215 DmAdvInit();
enginerd 0:b562096246b3 216 DmScanInit();
enginerd 0:b562096246b3 217 DmConnInit();
enginerd 0:b562096246b3 218 DmConnSlaveInit();
enginerd 0:b562096246b3 219 DmSecInit();
enginerd 0:b562096246b3 220 DmHandlerInit(handlerId);
enginerd 0:b562096246b3 221
enginerd 0:b562096246b3 222 handlerId = WsfOsSetNextHandler(L2cSlaveHandler);
enginerd 0:b562096246b3 223 L2cSlaveHandlerInit(handlerId);
enginerd 0:b562096246b3 224 L2cInit();
enginerd 0:b562096246b3 225 L2cMasterInit();
enginerd 0:b562096246b3 226 L2cSlaveInit();
enginerd 0:b562096246b3 227
enginerd 0:b562096246b3 228 handlerId = WsfOsSetNextHandler(AttHandler);
enginerd 0:b562096246b3 229 AttHandlerInit(handlerId);
enginerd 0:b562096246b3 230 AttsInit();
enginerd 0:b562096246b3 231 AttsIndInit();
enginerd 0:b562096246b3 232 AttcInit();
enginerd 0:b562096246b3 233
enginerd 0:b562096246b3 234 handlerId = WsfOsSetNextHandler(SmpHandler);
enginerd 0:b562096246b3 235 SmpHandlerInit(handlerId);
enginerd 0:b562096246b3 236 SmpiInit();
enginerd 0:b562096246b3 237 SmprInit();
enginerd 0:b562096246b3 238
enginerd 0:b562096246b3 239 /* store handler ID */
enginerd 0:b562096246b3 240 maximHandlerId = WsfOsSetNextHandler(maximHandler);
enginerd 0:b562096246b3 241
enginerd 0:b562096246b3 242 /* init HCI */
enginerd 0:b562096246b3 243 _irq.disable_irq();
enginerd 0:b562096246b3 244 _irq.rise(hciDrvIsr);
enginerd 0:b562096246b3 245 _irq.fall(NULL);
enginerd 0:b562096246b3 246 hciDrvInit(HCI_CSN, HCI_RST, HCI_IRQ);
enginerd 0:b562096246b3 247
enginerd 0:b562096246b3 248 /* Register for stack callbacks */
enginerd 0:b562096246b3 249 DmRegister(DmCback);
enginerd 0:b562096246b3 250 DmConnRegister(DM_CLIENT_ID_APP, DmCback);
enginerd 0:b562096246b3 251 AttConnRegister(AppServerConnCback);
enginerd 0:b562096246b3 252
enginerd 0:b562096246b3 253 /* Reset the device */
enginerd 0:b562096246b3 254 reset_complete = 0;
enginerd 0:b562096246b3 255 DmDevReset();
enginerd 0:b562096246b3 256
enginerd 0:b562096246b3 257 while (!reset_complete) {
enginerd 0:b562096246b3 258 callDispatcher();
enginerd 0:b562096246b3 259 }
enginerd 0:b562096246b3 260
enginerd 0:b562096246b3 261 initialized = true;
enginerd 0:b562096246b3 262 BLE::InitializationCompleteCallbackContext context = {
enginerd 0:b562096246b3 263 BLE::Instance(instanceID),
enginerd 0:b562096246b3 264 BLE_ERROR_NONE
enginerd 0:b562096246b3 265 };
enginerd 0:b562096246b3 266 initCallback.call(&context);
enginerd 0:b562096246b3 267 return BLE_ERROR_NONE;
enginerd 0:b562096246b3 268 }
enginerd 0:b562096246b3 269
enginerd 0:b562096246b3 270 ble_error_t MaximBLE::shutdown(void)
enginerd 0:b562096246b3 271 {
enginerd 0:b562096246b3 272 return BLE_ERROR_NOT_IMPLEMENTED;
enginerd 0:b562096246b3 273 }
enginerd 0:b562096246b3 274
enginerd 0:b562096246b3 275 void MaximBLE::waitForEvent(void)
enginerd 0:b562096246b3 276 {
enginerd 0:b562096246b3 277 static LowPowerTimeout nextTimeout;
enginerd 0:b562096246b3 278 timestamp_t nextTimestamp;
enginerd 0:b562096246b3 279 bool_t pTimerRunning;
enginerd 0:b562096246b3 280
enginerd 0:b562096246b3 281 callDispatcher();
enginerd 0:b562096246b3 282
enginerd 0:b562096246b3 283 if (wsfOsReadyToSleep()) {
enginerd 0:b562096246b3 284 // setup an mbed timer for the next Wicentric timeout
enginerd 0:b562096246b3 285 nextTimestamp = (timestamp_t)WsfTimerNextExpiration(&pTimerRunning) * 1000;
enginerd 0:b562096246b3 286 if (pTimerRunning) {
enginerd 0:b562096246b3 287 nextTimeout.attach_us(timeoutCallback, nextTimestamp);
enginerd 0:b562096246b3 288 }
enginerd 0:b562096246b3 289
enginerd 0:b562096246b3 290 // go to sleep
enginerd 0:b562096246b3 291 if (hciDrvReadyToSleep()) {
enginerd 0:b562096246b3 292 // go to deep sleep
enginerd 0:b562096246b3 293 deepsleep();
enginerd 0:b562096246b3 294 hciDrvResume();
enginerd 0:b562096246b3 295 }
enginerd 0:b562096246b3 296 else {
enginerd 0:b562096246b3 297 sleep();
enginerd 0:b562096246b3 298 }
enginerd 0:b562096246b3 299 }
enginerd 0:b562096246b3 300 }
enginerd 0:b562096246b3 301
enginerd 5:5b87f64ce81e 302 void MaximBLE::processEvents()
enginerd 5:5b87f64ce81e 303 {
enginerd 5:5b87f64ce81e 304 callDispatcher();
enginerd 5:5b87f64ce81e 305 }
enginerd 5:5b87f64ce81e 306
enginerd 0:b562096246b3 307 void MaximBLE::timeoutCallback(void)
enginerd 0:b562096246b3 308 {
enginerd 0:b562096246b3 309 // do nothing. just an interrupt for wake up.
enginerd 0:b562096246b3 310 }
enginerd 0:b562096246b3 311
enginerd 0:b562096246b3 312 void MaximBLE::callDispatcher(void)
enginerd 0:b562096246b3 313 {
enginerd 0:b562096246b3 314 static uint32_t lastTimeUs = us_ticker_read();
enginerd 0:b562096246b3 315 uint32_t currTimeUs, deltaTimeMs;
enginerd 0:b562096246b3 316
enginerd 0:b562096246b3 317 // Update the current Wicentric time
enginerd 0:b562096246b3 318 currTimeUs = us_ticker_read();
enginerd 0:b562096246b3 319 deltaTimeMs = (currTimeUs - lastTimeUs) / 1000;
enginerd 0:b562096246b3 320 if (deltaTimeMs > 0) {
enginerd 0:b562096246b3 321 WsfTimerUpdate(deltaTimeMs);
enginerd 0:b562096246b3 322 lastTimeUs += deltaTimeMs * 1000;
enginerd 0:b562096246b3 323 }
enginerd 0:b562096246b3 324
enginerd 0:b562096246b3 325 wsfOsDispatcher();
enginerd 0:b562096246b3 326 }