From bbb027ba884571c4533ce6239c4299c2d8fc673a Mon Sep 17 00:00:00 2001 From: schneider <schneider@blinkenlichts.net> Date: Thu, 25 Jun 2020 02:13:50 +0200 Subject: [PATCH] feat(ble): epicardium support for retrieving scan reports --- epicardium/ble/ble_main.c | 100 +++++++++++++++++++++++++++-- epicardium/ble/stack.c | 15 ++--- epicardium/epicardium.h | 61 +++++++++++++++--- epicardium/modules/hardware.c | 2 +- lib/sdk/Libraries/BTLE/meson.build | 1 + pycardium/modules/sys_ble.c | 2 +- 6 files changed, 156 insertions(+), 25 deletions(-) diff --git a/epicardium/ble/ble_main.c b/epicardium/ble/ble_main.c index c8fef1f66..ceb399bca 100644 --- a/epicardium/ble/ble_main.c +++ b/epicardium/ble/ble_main.c @@ -45,10 +45,15 @@ #include "api/interrupt-sender.h" #include "modules/log.h" +#define SCAN_REPORTS_NUM 16 + static bool active; static uint8_t advertising_mode = APP_MODE_NONE; static uint8_t advertising_mode_target = APP_MODE_NONE; static enum ble_event_type ble_event; +static struct epic_scan_report scan_reports[SCAN_REPORTS_NUM]; +static int scan_reports_head; +static int scan_reports_tail; /************************************************************************************************** Macros @@ -188,6 +193,15 @@ static const uint8_t bleAdvDataConn[] = DM_FLAG_LE_BREDR_NOT_SUP, }; +static const appMasterCfg_t scannerMasterCfg = +{ + 420, /*! The scan interval, in 0.625 ms units */ + 420, /*! The scan window, in 0.625 ms units */ + 0, /*! The scan duration in ms */ + DM_DISC_MODE_NONE, /*! The GAP discovery mode */ + DM_SCAN_TYPE_PASSIVE + /*!< The scan type (active or passive) */ +}; /************************************************************************************************** Client Characteristic Configuration Descriptors @@ -472,15 +486,45 @@ static void bleSetup(bleMsg_t *pMsg) active = true; /* TODO: Sadly, not advertising leads to a higher current consumption... */ - epic_ble_set_bondable(false); + epic_ble_set_mode(false, false); } -void epic_ble_set_bondable(bool bondable) +void epic_ble_set_mode(bool bondable, bool scanner) { if(!active) { return; } + if(scanner && bondable) { + /* TODO: return error */ + return; + } + + if(scanner) { + if(advertising_mode != APP_MODE_NONE) { + advertising_mode_target = APP_MODE_NONE; + advertising_mode = APP_MODE_NONE; + AppAdvStop(); + } + + dmConnId_t connId; + if ((connId = AppConnIsOpen()) != DM_CONN_ID_NONE) { + AppConnClose(connId); + } + + /* Normal scanning filters out duplicates. We don't + * want that for now... */ + //AppScanStart(scannerMasterCfg.discMode, scannerMasterCfg.scanType, scannerMasterCfg.scanDuration); + DmScanSetInterval(HCI_SCAN_PHY_LE_1M_BIT, &pAppMasterCfg->scanInterval, + &pAppMasterCfg->scanWindow); + DmScanStart(HCI_SCAN_PHY_LE_1M_BIT, scannerMasterCfg.discMode, + &scannerMasterCfg.scanType, FALSE, scannerMasterCfg.scanDuration, 0); + + return; + } else { + AppScanStop(); + } + if(bondable) { /* We need to stop advertising in between or the * adv set will not be changed. @@ -576,6 +620,48 @@ static void bleHandleNumericComparison(dmSecCnfIndEvt_t *pCnfInd) trigger_event(BLE_EVENT_HANDLE_NUMERIC_COMPARISON); } +int epic_ble_get_scan_report(struct epic_scan_report *rpt) +{ + if(scan_reports_head == scan_reports_tail) { + return -ENOENT; + } + + int new_tail = (scan_reports_tail + 1) % SCAN_REPORTS_NUM; + *rpt = scan_reports[new_tail]; + scan_reports_tail = new_tail; + return 0; +} + +static void scannerScanReport(dmEvt_t *pMsg) +{ + struct epic_scan_report *scan_report; + + int next_head = (scan_reports_head + 1) % SCAN_REPORTS_NUM; + if(next_head == scan_reports_tail) { + trigger_event(BLE_EVENT_SCAN_REPORT); + return; + } + scan_reports_head = next_head; + scan_report = &scan_reports[scan_reports_head]; + + memset(scan_report->data, 0, sizeof(scan_report->data)); + memccpy(scan_report->data, pMsg->scanReport.pData, pMsg->scanReport.len, sizeof(scan_report->data)); + scan_report->len = pMsg->scanReport.len; + scan_report->rssi = pMsg->scanReport.rssi; + scan_report->eventType = pMsg->scanReport.eventType; + scan_report->addrType = pMsg->scanReport.addrType; + memcpy(scan_report->addr, pMsg->scanReport.addr, BDA_ADDR_LEN); + + scan_report->directAddrType = pMsg->scanReport.directAddrType; + memcpy(scan_report->directAddr, pMsg->scanReport.directAddr, BDA_ADDR_LEN); + trigger_event(BLE_EVENT_SCAN_REPORT); + + if((scan_reports_head + 1) % SCAN_REPORTS_NUM == scan_reports_tail) { + LOG_WARN("ble", "Application missing scan results"); + } +} + + /*************************************************************************************************/ /*! * \brief Process messages from the event handler. @@ -610,10 +696,9 @@ static void bleProcMsg(bleMsg_t *pMsg) case DM_ADV_START_IND: LOG_INFO("ble", "Advertisement started %u %u", advertising_mode, advertising_mode_target); - if(advertising_mode != advertising_mode_target) { + if(advertising_mode != advertising_mode_target || advertising_mode_target == APP_MODE_NONE) { AppAdvStop(); } - break; case DM_ADV_STOP_IND: @@ -719,6 +804,10 @@ static void bleProcMsg(bleMsg_t *pMsg) bleHandleNumericComparison(&pMsg->dm.cnfInd); break; + case DM_SCAN_REPORT_IND: + scannerScanReport((dmEvt_t *)pMsg); + break; + case DM_HW_ERROR_IND: LOG_ERR("ble", "HW Error"); break; @@ -749,6 +838,7 @@ static void BleHandlerInit(void) pAppSlaveCfg = (appSlaveCfg_t *) &bleSlaveCfg; pAppSecCfg = (appSecCfg_t *) &bleSecCfg; pAppUpdateCfg = (appUpdateCfg_t *) &bleUpdateCfg; + pAppMasterCfg = (appMasterCfg_t *) &scannerMasterCfg; /* Initialize application framework */ AppSlaveInit(); @@ -779,7 +869,7 @@ static void BleHandler(wsfEventMask_t event, wsfMsgHdr_t *pMsg) if (pMsg->event >= DM_CBACK_START && pMsg->event <= DM_CBACK_END) { - LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, dm_events[pMsg->event - DM_CBACK_START]); + if(pMsg->event != DM_SCAN_REPORT_IND) LOG_INFO("ble", "Ble got evt %d: %s", pMsg->event, dm_events[pMsg->event - DM_CBACK_START]); /* process advertising and connection-related messages */ AppSlaveProcDmMsg((dmEvt_t *) pMsg); diff --git a/epicardium/ble/stack.c b/epicardium/ble/stack.c index a7896b68f..3d24b0c59 100644 --- a/epicardium/ble/stack.c +++ b/epicardium/ble/stack.c @@ -130,11 +130,7 @@ void StackInit(void) .freeMemAvail = LL_MEMORY_FOOTPRINT }; -#ifdef DATS_APP_USE_LEGACY_API memUsed = LlInitControllerExtInit(&ll_init_cfg); -#else /* DATS_APP_USE_LEGACY_API */ - memUsed = LlInitControllerExtInit(&ll_init_cfg); -#endif /* DATS_APP_USE_LEGACY_API */ if(memUsed != LL_MEMORY_FOOTPRINT) { printf("Controller memory mismatch 0x%x != 0x%x\n", (unsigned int)memUsed, @@ -142,6 +138,11 @@ void StackInit(void) } #endif + SecInit(); + SecRandInit(); + SecAesInit(); + SecCmacInit(); + SecEccInit(); /* card10: * These calls register a queue for callbacks in the OS abstraction @@ -153,14 +154,10 @@ void StackInit(void) handlerId = WsfOsSetNextHandler(HciHandler); HciHandlerInit(handlerId); - SecInit(); - SecAesInit(); - SecCmacInit(); - SecEccInit(); - handlerId = WsfOsSetNextHandler(DmHandler); DmDevVsInit(0); DmAdvInit(); + DmScanInit(); DmConnInit(); DmConnSlaveInit(); DmSecInit(); diff --git a/epicardium/epicardium.h b/epicardium/epicardium.h index 2ab3126f3..2ad191349 100644 --- a/epicardium/epicardium.h +++ b/epicardium/epicardium.h @@ -149,10 +149,11 @@ typedef _Bool bool; #define API_CONFIG_GET_BOOLEAN 0x132 #define API_CONFIG_SET_STRING 0x133 -#define API_BLE_GET_COMPARE_VALUE 0x140 -#define API_BLE_COMPARE_RESPONSE 0x141 -#define API_BLE_SET_BONDABLE 0x142 -#define API_BLE_GET_EVENT 0x143 +#define API_BLE_GET_COMPARE_VALUE 0x140 +#define API_BLE_COMPARE_RESPONSE 0x141 +#define API_BLE_SET_MODE 0x142 +#define API_BLE_GET_EVENT 0x143 +#define API_BLE_GET_SCAN_REPORT 0x144 /* clang-format on */ @@ -2036,7 +2037,7 @@ API(API_USB_CDCACM, int epic_usb_cdcacm(void)); /** * Takes a gpio pin specified with the gpio module and transmits - * the led data. The format `GG:RR:BB` is expected. + * the led data. The format ``GG:RR:BB`` is expected. * * :param uint8_t pin: The gpio pin to be used for data. * :param uint8_t * pixels: The buffer, in which the pixel data is stored. @@ -2135,9 +2136,29 @@ enum ble_event_type { BLE_EVENT_PAIRING_FAILED = 2, /** A pairing procedure has successfully completed */ BLE_EVENT_PAIRING_COMPLETE = 3, + /** New scan data is available */ + BLE_EVENT_SCAN_REPORT = 4, }; +/** + * Scan report data. Bases on ``hciLeAdvReportEvt_t`` from BLE stack. + * + * TODO: 64 bytes for data is an arbitrary number ATM */ +struct epic_scan_report +{ + uint8_t data[64]; /*!< \brief advertising or scan response data. */ + uint8_t len; /*!< \brief length of advertising or scan response data. */ + int8_t rssi; /*!< \brief RSSI. */ + uint8_t eventType; /*!< \brief Advertising event type. */ + uint8_t addrType; /*!< \brief Address type. */ + uint8_t addr[6]; /*!< \brief Device address. */ + + /* \brief direct fields */ + uint8_t directAddrType; /*!< \brief Direct advertising address type. */ + uint8_t directAddr[6]; /*!< \brief Direct advertising address. */ +}; + /** * **Interrupt Service Routine** for :c:data:`EPIC_INT_BLE` * @@ -2202,22 +2223,44 @@ API(API_BLE_GET_COMPARE_VALUE, uint32_t epic_ble_get_compare_value(void)); API(API_BLE_COMPARE_RESPONSE, void epic_ble_compare_response(bool confirmed)); /** - * Allow or disallow new bondings to happen + * Set the desired mode of the BLE stack. + * + * There are three allowed modes: + * + * - Peripheral which is not bondable (bondable = ``false``, scanner = ``false``). + * - Peripheral which is bondable (bondable = ``true``, scanner = ``false``). + * - Observer which scans for advertisements (bondable = ``false``, scanner = ``true``). * * By default the card10 will not allow new bondings to be made. New * bondings have to explicitly allowed by calling this function. * - * While bonadable the card10 will change its advertisements to + * While bondable the card10 will change its advertisements to * indicate to scanning hosts that it is available for discovery. * + * When scanning is active, :c:data:`BLE_EVENT_SCAN_REPORT` events will be sent + * and the scan reports can be fetched using :c:func:`epic_ble_get_scan_report`. + * * When switching applications new bondings are automatically - * disallowed. + * disallowed and scanning is stopped. * * :param bool bondable: `true` if new bondings should be allowed. + * :param bool scanner: `true` if scanning should be turned on. * * .. versionadded:: 1.16 */ -API(API_BLE_SET_BONDABLE, void epic_ble_set_bondable(bool bondable)); +API(API_BLE_SET_MODE, void epic_ble_set_mode(bool bondable, bool scanner)); +/** + * Retrieve a scan report from the queue of scan reports. + * + * :param struct epic_scan_report* rpt: Pointer where the report will be stored. + * + * :return: `0` on success or a negative value if an error occured. Possible + * errors: + * + * - ``-ENOENT``: No scan report available + * + */ +API(API_BLE_GET_SCAN_REPORT, int epic_ble_get_scan_report(struct epic_scan_report *rpt)); #endif /* _EPICARDIUM_H */ diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c index 1168f5a75..92dff16ea 100644 --- a/epicardium/modules/hardware.c +++ b/epicardium/modules/hardware.c @@ -292,7 +292,7 @@ int hardware_reset(void) /* * BLE */ - epic_ble_set_bondable(false); + epic_ble_set_mode(false, false); return 0; } diff --git a/lib/sdk/Libraries/BTLE/meson.build b/lib/sdk/Libraries/BTLE/meson.build index 6dd10ee6a..0f301cf18 100644 --- a/lib/sdk/Libraries/BTLE/meson.build +++ b/lib/sdk/Libraries/BTLE/meson.build @@ -421,6 +421,7 @@ ble_compileargs = [ '-DINIT_BROADCASTER', '-DINIT_PERIPHERAL', '-DINIT_ENCRYPTED', + '-DINIT_OBSERVER', ] if get_option('ble_trace') diff --git a/pycardium/modules/sys_ble.c b/pycardium/modules/sys_ble.c index d262ce410..34278be17 100644 --- a/pycardium/modules/sys_ble.c +++ b/pycardium/modules/sys_ble.c @@ -33,7 +33,7 @@ static MP_DEFINE_CONST_FUN_OBJ_0(ble_get_event_obj, mp_ble_get_event); static mp_obj_t mp_ble_set_bondable(mp_obj_t bondable_obj) { bool bondable = mp_obj_is_true(bondable_obj); - epic_ble_set_bondable(bondable); + epic_ble_set_mode(bondable, false); return mp_const_none; } static MP_DEFINE_CONST_FUN_OBJ_1(ble_set_bondable_obj, mp_ble_set_bondable); -- GitLab