mbed-os/features/FEATURE_BLE/targets/TARGET_Maxim/MaximBLE.cpp

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,
&params);
}
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();
}