Skip to content
Snippets Groups Projects

BLE advertisement support for MicroPython

Merged schneider requested to merge schneider/mp-ble-adv into master
Files
8
+ 264
0
#include "ble_api.h"
#include "epicardium.h"
#include "modules/log.h"
#include "modules/config.h"
#include "wsf_types.h"
#include "util/bstream.h"
#include "wsf_msg.h"
#include "wsf_trace.h"
#include "app_api.h"
#include "app_db.h"
#include "svc_ch.h"
#include "profiles/gap_api.h"
#include <stdio.h>
#include <string.h>
#define DEFAULT_ADV_INTERVAL_US 500000
/*! configurable parameters for advertising */
static appAdvCfg_t bleAdvCfg = {
{ 0, 0 }, /*! Advertising durations in ms */
{ DEFAULT_ADV_INTERVAL_US / 625,
0 } /*! Advertising intervals in 0.625 ms units */
};
static bool tainted;
/**************************************************************************************************
Advertising Data
**************************************************************************************************/
/* clang-format off */
/*! advertising data, discoverable mode */
static const uint8_t bleAdvDataDisc[] = {
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_LIMITED_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
3,
DM_ADV_TYPE_APPEARANCE,
UINT16_TO_BYTES(CH_APPEAR_WATCH),
/*! service UUID list */
17,
DM_ADV_TYPE_128_UUID_PART,
CARD10_UUID_SUFFIX,
0x0,
CARD10_UUID_PREFIX,
2, /*! length */
DM_ADV_TYPE_TX_POWER, /*! AD type */
0, /*! tx power */
};
/*! advertising data, discoverable mode with HID service*/
static const uint8_t bleAdvDataDiscHID[] = {
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_LIMITED_DISC | /*! flags */
DM_FLAG_LE_BREDR_NOT_SUP,
3,
DM_ADV_TYPE_APPEARANCE,
UINT16_TO_BYTES(CH_APPEAR_WATCH),
/*! service UUID list */
17,
DM_ADV_TYPE_128_UUID_PART,
CARD10_UUID_SUFFIX,
0x0,
CARD10_UUID_PREFIX,
3, /*! length */
DM_ADV_TYPE_16_UUID_PART, /*! AD type */
UINT16_TO_BYTES(ATT_UUID_HID_SERVICE)
};
/*! scan data, discoverable mode */
uint8_t bleScanDataDisc[] = {
/*! device name */
14, /*! length */
DM_ADV_TYPE_LOCAL_NAME, /*! AD type */
'c','a','r','d','1','0','-','0','0','0','0','0','0',
3, /*! length */
DM_ADV_TYPE_16_SOLICIT, /*! AD type */
UINT16_TO_BYTES(ATT_UUID_CURRENT_TIME_SERVICE),
};
/* clang-format on */
/*! advertising data, connectable mode */
static const uint8_t bleAdvDataConn[] = {
/*! flags */
2, /*! length */
DM_ADV_TYPE_FLAGS, /*! AD type */
DM_FLAG_LE_BREDR_NOT_SUP,
};
static uint8_t advertising_mode = APP_MODE_NONE;
static uint8_t advertising_mode_target = APP_MODE_NONE;
void ble_adv_proc_msg(bleMsg_t *pMsg)
{
switch (pMsg->hdr.event) {
case DM_ADV_START_IND:
LOG_INFO(
"ble",
"Advertisement started %u %u",
advertising_mode,
advertising_mode_target
);
if (advertising_mode != advertising_mode_target ||
advertising_mode_target == APP_MODE_NONE) {
AppAdvStop();
}
break;
case DM_ADV_STOP_IND:
LOG_INFO(
"ble",
"Advertisement stopped %u %u",
advertising_mode,
advertising_mode_target
);
if (advertising_mode != advertising_mode_target) {
advertising_mode = advertising_mode_target;
AppAdvStart(advertising_mode);
}
break;
case DM_CONN_CLOSE_IND:
/* Stack overwrites advertising mode after connection close.
* Force our desired mode.
*/
advertising_mode = APP_MODE_NONE;
AppAdvStop();
break;
};
}
void ble_adv_init(void)
{
char buf[32];
char a, b, c, d, e, f, K;
/* clang-format off */
int result = epic_config_get_string("ble_mac", buf, sizeof(buf));
if (result == 0) {
if (sscanf(buf,
"%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
&K, &K, &K, &K, &K, &K,
&a, &b, &c, &d, &e, &f) == 12) {
bleScanDataDisc[9] = a;
bleScanDataDisc[10] = b;
bleScanDataDisc[11] = c;
bleScanDataDisc[12] = d;
bleScanDataDisc[13] = e;
bleScanDataDisc[14] = f;
}
}
/* clang-format on */
pAppAdvCfg = (appAdvCfg_t *)&bleAdvCfg;
}
void ble_adv_setup(void)
{
/* set advertising and scan response data for discoverable mode */
if (config_get_boolean_with_default("ble_hid_enable", false)) {
AppAdvSetData(
APP_ADV_DATA_DISCOVERABLE,
sizeof(bleAdvDataDiscHID),
(uint8_t *)bleAdvDataDiscHID
);
} else {
AppAdvSetData(
APP_ADV_DATA_DISCOVERABLE,
sizeof(bleAdvDataDisc),
(uint8_t *)bleAdvDataDisc
);
}
AppAdvSetData(
APP_SCAN_DATA_DISCOVERABLE,
sizeof(bleScanDataDisc),
(uint8_t *)bleScanDataDisc
);
/* set advertising and scan response data for connectable mode */
AppAdvSetData(
APP_ADV_DATA_CONNECTABLE,
sizeof(bleAdvDataConn),
(uint8_t *)bleAdvDataConn
);
AppAdvSetData(APP_SCAN_DATA_CONNECTABLE, 0, NULL);
bleAdvCfg.advInterval[0] = DEFAULT_ADV_INTERVAL_US / 625;
}
void ble_adv_set_interval(uint32_t interval_us)
{
bleAdvCfg.advInterval[0] = interval_us / 625;
tainted = true;
}
void ble_adv_stop(void)
{
if (advertising_mode != APP_MODE_NONE) {
advertising_mode_target = APP_MODE_NONE;
advertising_mode = APP_MODE_NONE;
AppAdvStop();
}
}
static void adv_start(uint8_t mode)
{
if (advertising_mode != APP_MODE_NONE) {
/* We need to stop advertising in between or the
* adv set will not be changed.
* Also need to wait for the stop operation to finish
* before we can start again
* Also need to set the variables first as we don't
* have a lock on the stack.*/
advertising_mode_target = mode;
advertising_mode = APP_MODE_NONE;
AppAdvStop();
} else {
advertising_mode = mode;
advertising_mode_target = mode;
AppAdvStart(advertising_mode);
}
tainted = false;
}
void ble_adv_start(uint8_t mode)
{
adv_start(mode);
tainted = true;
}
void ble_adv_discoverable(bool discoverable)
{
if (discoverable) {
if (advertising_mode != APP_MODE_DISCOVERABLE || tainted) {
LOG_INFO("ble", "Making bondable and discoverable");
adv_start(APP_MODE_DISCOVERABLE);
}
} else {
/* TODO: This does way more than the function name indicates */
if (AppDbCheckBonded()) {
if (advertising_mode != APP_MODE_CONNECTABLE ||
tainted) {
LOG_INFO("ble", "Bonded. Making connectable");
adv_start(APP_MODE_CONNECTABLE);
}
} else {
LOG_INFO("ble", "Not bonded. Stop advertising");
ble_adv_stop();
}
}
}
Loading