Newer
Older
#include "ble_api.h"
#include "epicardium.h"
#include "modules/log.h"
#include "FreeRTOS.h"
#include "queue.h"
#include <stdint.h>
#define BLE_EVENT_QUEUE_SIZE 10
static QueueHandle_t ble_event_queue;
static uint8_t ble_event_queue_buffer
[sizeof(struct epic_ble_event) * BLE_EVENT_QUEUE_SIZE];
static StaticQueue_t ble_event_queue_data;
static uint8_t adv_data_buf[HCI_ADV_DATA_LEN];
static uint8_t sr_data_buf[HCI_ADV_DATA_LEN];
static dmEvt_t connection_open_event;
static bool connection_open;
int epic_ble_free_event(struct epic_ble_event *e)
{
if (e->data) {
if (e->type == BLE_EVENT_ATT_WRITE) {
ble_epic_att_api_free_att_write_data(e->att_write);
} else {
// Generic free
WsfBufFree(e->data);
}
}
return 0;
}
void ble_epic_ble_api_trigger_event(enum epic_ble_event_type type, void *data)
{
bool enabled;
epic_interrupt_is_enabled(EPIC_INT_BLE, &enabled);
struct epic_ble_event e = { .type = type, .data = data };
if (type == BLE_EVENT_DM_EVENT) {
dmEvt_t *dm_event = data;
if (dm_event->hdr.event == DM_CONN_OPEN_IND) {
connection_open = true;
}
if (dm_event->hdr.event == DM_CONN_CLOSE_IND) {
connection_open = false;
}
}
if (!connection_open &&
(type == BLE_EVENT_ATT_EVENT || type == BLE_EVENT_DM_EVENT)) {
// Don't forward DM and ATT events until epicardium is done setting up
// the connection
epic_ble_free_event(&e);
return;
}
if (enabled) {
if (xQueueSend(ble_event_queue, &e, 0) != pdTRUE) {
/* Print a warning if the app is missing events. Missing scan results
* is considered OK though, as they are queued and periodic. */
if (type != BLE_EVENT_SCAN_REPORT) {
LOG_WARN(
"ble",
"Application missed event %u",
type
);
}
epic_ble_free_event(&e);
epic_ble_free_event(&e);
}
}
int epic_ble_get_event(struct epic_ble_event *e)
{
if (xQueueReceive(ble_event_queue, e, 0) != pdTRUE) {
return -ENOENT;
}
return uxQueueMessagesWaiting(ble_event_queue);
}
void ble_epic_ble_api_init(void)
{
ble_event_queue = xQueueCreateStatic(
BLE_EVENT_QUEUE_SIZE,
sizeof(struct epic_ble_event),
ble_event_queue_buffer,
&ble_event_queue_data
);
ble_epic_att_api_init();
}
static void send_dm_event(dmEvt_t *dm_event)
{
dmEvt_t *e = WsfBufAlloc(sizeof(*e));
if (e) {
memcpy(e, dm_event, sizeof(*e));
ble_epic_ble_api_trigger_event(BLE_EVENT_DM_EVENT, e);
} else {
LOG_WARN("ble", "could not allocate dm event");
}
}
void ble_epic_dm_api_event(dmEvt_t *dm_event)
{
if (dm_event->hdr.event == DM_CONN_OPEN_IND) {
/* Cache the connection open indication until
* epicardium is done dicovering services. */
memcpy(&connection_open_event,
dm_event,
sizeof(connection_open_event));
} else {
send_dm_event(dm_event);
}
}
void ble_epic_disc_cfg_complete(void)
{
send_dm_event(&connection_open_event);
}
void epic_ble_close_connection(uint8_t connId)
{
AppConnClose(connId);
}
int epic_ble_is_connection_open(void)
{
return AppConnIsOpen();
}
int epic_ble_set_device_name(const uint8_t *buf, uint16_t len)
{
return epic_ble_atts_set_attr(GAP_DN_HDL, buf, len);
}
int epic_ble_get_device_name(uint8_t **buf, uint16_t *len)
{
uint8_t ret = AttsGetAttr(GAP_DN_HDL, len, buf);
return ret;
}
int epic_ble_advertise(
int interval_us,
const uint8_t *adv_data,
size_t adv_data_len,
const uint8_t *sr_data,
size_t sr_data_len,
bool connectable
) {
if (adv_data_len > sizeof(adv_data_buf)) {
adv_data_len = sizeof(adv_data_buf);
}
if (sr_data_len > sizeof(sr_data_buf)) {
sr_data_len = sizeof(sr_data_buf);
}
memcpy(adv_data_buf, adv_data, adv_data_len);
memcpy(sr_data_buf, sr_data, sr_data_len);
ble_adv_set_interval(interval_us);
if (connectable) {
AppAdvSetData(
APP_ADV_DATA_CONNECTABLE, adv_data_len, adv_data_buf
);
AppAdvSetData(
APP_SCAN_DATA_CONNECTABLE, sr_data_len, sr_data_buf
);
ble_adv_start(APP_MODE_CONNECTABLE);
} else {
AppAdvSetData(
APP_ADV_DATA_DISCOVERABLE, adv_data_len, adv_data_buf
);
AppAdvSetData(
APP_SCAN_DATA_DISCOVERABLE, sr_data_len, sr_data_buf
);
ble_adv_start(APP_MODE_DISCOVERABLE);
}
return 0;
}