mirror of https://github.com/ARMmbed/mbed-os.git
363 lines
11 KiB
C++
363 lines
11 KiB
C++
/*******************************************************************************
|
|
* 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,
|
|
(BLEProtocol::AddressType_t) scanReport->addrType);
|
|
}
|
|
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();
|
|
}
|