Wirepas SDK
ble_scanner/app.c
/* Copyright 2018 Wirepas Ltd. All Rights Reserved.
*
* See file LICENSE.txt for full license details.
*
*/
/*
* \file app.c
* \brief This file is a template for using Bluetooth Scanner feature
*
* \note Send a number to a node, to start listening to Eddystone beacons.
* "numbers" of theses Beacon will be forwarded to Sink.
*/
#include "api.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <sl_list.h>
#define MAX_BLE_PKT_SIZE 37
#define SET_NUM_BTLE_EP 10
#define DATA_EP 1
#define EXECUTION_TIME_US 100
static uint8_t m_btle_forwarded;
sl_list_head_t m_btle_queue;
#define BLE_SCAN_QUEUE_SIZE 8
typedef struct {
sl_list_t list;
uint8_t btle_data[MAX_BLE_PKT_SIZE];
uint8_t btle_length;
uint8_t btle_type;
uint8_t btle_rssi;
} ble_data_t;
ble_data_t m_ble_data[BLE_SCAN_QUEUE_SIZE];
/* Number of BT beacon to be forwarded to sink */
static uint8_t m_num_ble;
#define NODE_ROLE \
app_lib_settings_create_role(APP_LIB_SETTINGS_ROLE_HEADNODE, APP_LIB_SETTINGS_ROLE_FLAG_LL)
#define BEACON_RX_CHAN APP_LIB_BEACON_RX_CHANNEL_ALL
const uint8_t EDDYSTONE_OFFSET = 0x9;
const uint8_t EDDYSTONE_LEN = 0x3; /* Length */
const uint8_t EDDYSTONE_TYPE = 0x3; /* Service List */
const uint8_t EDDYSTONE_UUID[] = {0xAA, 0xFE}; /* Eddystone ID */
static void send_data(ble_data_t * beacon)
{
app_lib_data_to_send_t data_to_send;
data_to_send.bytes = (const uint8_t *)(beacon->btle_data);
data_to_send.num_bytes = beacon->btle_length;
data_to_send.src_endpoint = DATA_EP;
data_to_send.dest_endpoint = DATA_EP;
data_to_send.qos = APP_LIB_DATA_QOS_HIGH;
data_to_send.delay = 0;
lib_data->sendData(&data_to_send);
}
static uint32_t process_ble_beacon(void)
{
ble_data_t * beacon = NULL;
size_t routeToSink = 0;
lib_state->getRouteCount(&routeToSink);
/* When we enable scanner feature, we loose connectivity:
* the time needed to move to a BT advertisement channel
* it's better to avoid sending data during this time */
if (routeToSink)
{
/* we got a route to the sink */
/* Check if we have a BT Beacon to Forward */
do
{
lib_system->enterCriticalSection();
beacon = (ble_data_t *)sl_list_pop_front(&m_btle_queue);
lib_system->exitCriticalSection();
if (beacon != NULL)
{
send_data(beacon);
/* Free entry in Beacon Queue */
beacon->btle_length = 0;
m_btle_forwarded++;
}
} while ((beacon != NULL) && (m_btle_forwarded < m_num_ble));
}
if (m_btle_forwarded >= m_num_ble)
{
/* We got enough BLE Beacons */
lib_beacon_rx->stopScanner();
}
/* Beacon Queue is now empty */
}
static void BLEdataReceivedCb(const app_lib_beacon_rx_received_t * packet)
{
uint16_t offset = EDDYSTONE_OFFSET;
ble_data_t * data = NULL;
/* Here, some filtering should be implemented to avoid processing
* every Bluetooth Beacon
* As an example, we filter the incoming Bluetooth beacon to process
* only Eddystone URL beacon.
* They can be recognized by there special header at address 9 to 12
* in the Beacon payload received.
*/
if ((packet->payload[offset++] == EDDYSTONE_LEN ) &&
(packet->payload[offset++] == EDDYSTONE_TYPE) &&
(packet->payload[offset++] == EDDYSTONE_UUID[0]) &&
(packet->payload[offset] == EDDYSTONE_UUID[1]))
{
/* Look for a free place to store incoming Eddystone Beacon */
for (uint8_t idx=0; idx<BLE_SCAN_QUEUE_SIZE; idx++)
{
if (m_ble_data[idx].btle_length == 0)
{
data = &m_ble_data[idx];
break;
}
}
/* No free place, discard the oldest and use it */
if (data == NULL)
{
data = (ble_data_t *)sl_list_pop_front(&m_btle_queue);
}
if (data == NULL)
{
return; /* Should not occur */
}
data->btle_length = packet->length;
data->btle_type = packet->type;
data->btle_rssi = packet->rssi;
memcpy(data->btle_data,
packet->payload,
data->btle_length);
sl_list_push_back(&m_btle_queue, (sl_list_t *)data);
/* BLE Beacon received, run periodic work as soon as possible */
lib_system->setPeriodicCb(process_ble_beacon,
0,
EXECUTION_TIME_US);
}
else
{
/* Nothing:
* It's not an Eddystone beacon, and we do not process it */
}
}
static app_lib_data_receive_res_e dataReceivedCb(
{
bool btle_started = lib_beacon_rx->isScannerStarted();
if ((data->num_bytes != 1) ||
(data->dest_endpoint != SET_NUM_BTLE_EP))
{
// Data was not for this application
}
// Parse decimal digits a number of BT Beacon wanted
m_num_ble = data->bytes[0];
m_btle_forwarded = 0;
if ((!btle_started)&&(m_num_ble>0))
{
for (uint8_t idx=0; idx<BLE_SCAN_QUEUE_SIZE; idx++)
{
m_ble_data[idx].btle_length = 0;
}
sl_list_init(&m_btle_queue);
// Start BT Sanner now, until we forward m_num_ble beacon to the sink.
lib_beacon_rx->startScanner(BEACON_RX_CHAN);
}
// Data handled successfully
}
void App_init(const app_global_functions_t * functions)
{
// Basic configuration of the node with a unique node address
{
// Could not configure the node
// It should not happen except if one of the config value is invalid
return;
}
// Configure node as Headnode or Subnode, low-latency
// This call force the role, and prevent RemoteAPI to change it
lib_settings->setNodeRole(NODE_ROLE);
// Set callback for received BT Beacon.
// This callback will be call in Interrupt Context !
lib_beacon_rx->setBeaconReceivedCb(BLEdataReceivedCb);
// Set callback for received unicast messages
lib_data->setDataReceivedCb(dataReceivedCb);
// Start the stack
lib_state->startStack();
}
app_lib_beacon_rx_received_t::type
uint8_t type
Definition: beacon_rx.h:54
app_lib_data_to_send_t::num_bytes
size_t num_bytes
Definition: data.h:293
sl_list_head_t
Definition: sl_list.h:55
app_lib_data_to_send_t
A struct for lib_data->sendData().
Definition: data.h:288
app_lib_beacon_rx_received_t::length
uint8_t length
Definition: beacon_rx.h:56
sl_list_init
void sl_list_init(sl_list_head_t *list_head)
sl_list_pop_front
sl_list_t * sl_list_pop_front(sl_list_head_t *list_head)
node_configuration.h
app_lib_data_to_send_t::dest_address
app_addr_t dest_address
Definition: data.h:295
APP_RES_OK
@ APP_RES_OK
Definition: app.h:204
app_lib_data_to_send_t::tracking_id
app_lib_data_tracking_id_t tracking_id
Definition: data.h:303
app_lib_beacon_rx_received_t::payload
uint8_t * payload
Definition: beacon_rx.h:60
app_lib_data_to_send_t::qos
app_lib_data_qos_e qos
Definition: data.h:305
APP_LIB_DATA_RECEIVE_RES_NOT_FOR_APP
@ APP_LIB_DATA_RECEIVE_RES_NOT_FOR_APP
Definition: data.h:191
APP_LIB_DATA_RECEIVE_RES_HANDLED
@ APP_LIB_DATA_RECEIVE_RES_HANDLED
Definition: data.h:188
app_lib_data_to_send_t::delay
uint32_t delay
Definition: data.h:299
configureNodeFromBuildParameters
__STATIC_INLINE app_res_e configureNodeFromBuildParameters()
Wrapper on top of configureNode to get parameters from build system and hardcoded values from chip (f...
Definition: node_configuration.h:233
app_lib_data_to_send_t::flags
uint8_t flags
Definition: data.h:307
app_lib_beacon_rx_received_t
BLE structure received from network. Used in callback function set with lib_beacon_rx->setBeaconRecei...
Definition: beacon_rx.h:51
app_lib_data_receive_res_e
app_lib_data_receive_res_e
Return value of data reception callback.
Definition: data.h:184
app_lib_data_to_send_t::src_endpoint
uint8_t src_endpoint
Definition: data.h:309
app_lib_data_to_send_t::dest_endpoint
uint8_t dest_endpoint
Definition: data.h:311
app_lib_data_to_send_t::bytes
const uint8_t * bytes
Definition: data.h:291
APP_LIB_SYSTEM_STOP_PERIODIC
#define APP_LIB_SYSTEM_STOP_PERIODIC
Constant to stop periodic callback.
Definition: system.h:46
sl_list_t
Definition: sl_list.h:63
APP_ADDR_ANYSINK
@ APP_ADDR_ANYSINK
Definition: app.h:236
APP_LIB_DATA_NO_TRACKING_ID
#define APP_LIB_DATA_NO_TRACKING_ID
When sending data and no tracking of packet is requested, this ID may be used.
Definition: data.h:60
app_lib_data_received_t
Struct passed to data reception callback functions.
Definition: data.h:244
sl_list_push_back
void sl_list_push_back(sl_list_head_t *list_head, sl_list_t *element)
app_lib_beacon_rx_received_t::rssi
int8_t rssi
Definition: beacon_rx.h:58
app_global_functions_t
List of global functions, passed to App_entrypoint()
Definition: app.h:157
APP_LIB_DATA_QOS_HIGH
@ APP_LIB_DATA_QOS_HIGH
Definition: data.h:93
sl_list.h
APP_LIB_DATA_SEND_FLAG_NONE
@ APP_LIB_DATA_SEND_FLAG_NONE
Definition: data.h:102
api.h