276 lines
No EOL
7.7 KiB
C
276 lines
No EOL
7.7 KiB
C
#include <SystemK.h>
|
|
#include "esp_log.h"
|
|
/* BLE */
|
|
#include "esp_nimble_hci.h"
|
|
#include "nimble/nimble_port.h"
|
|
#include "nimble/nimble_port_freertos.h"
|
|
#include "host/ble_hs.h"
|
|
#include "host/util/util.h"
|
|
#include "console/console.h"
|
|
#include "services/gap/ble_svc_gap.h"
|
|
|
|
static const char *TAG = "BLE";
|
|
static bool Host_And_Controller_Synced = false;
|
|
static bool Is_Scanning_And_Advertising = false;
|
|
|
|
static uint8_t Advertising_Data[BLE_KTAG_PACKET_TOTAL_SIZE] = {0x1E, 0xFF, 0xFF, 0xFF, 'K', 'T', 'a', 'g'};
|
|
|
|
// Forward declarations of NimBLE functions.
|
|
void ble_store_config_init(void);
|
|
static int ble_gap_event(struct ble_gap_event *event, void *arg);
|
|
|
|
/**
|
|
* Initiates the GAP general discovery procedure.
|
|
*/
|
|
static void ble_scan(void)
|
|
{
|
|
uint8_t own_addr_type;
|
|
struct ble_gap_disc_params disc_params;
|
|
int rc;
|
|
|
|
/* Figure out address to use while advertising (no privacy for now) */
|
|
rc = ble_hs_id_infer_auto(0, &own_addr_type);
|
|
if (rc != 0)
|
|
{
|
|
KLOG_ERROR(TAG, "Error determining address type; rc=%d", rc);
|
|
return;
|
|
}
|
|
|
|
/* Tell the controller not to filter duplicates; we want to process
|
|
* repeated advertisements from the same device.
|
|
*/
|
|
disc_params.filter_duplicates = 0;
|
|
|
|
/**
|
|
* Perform a passive scan. I.e., don't send follow-up scan requests to
|
|
* each advertiser.
|
|
*/
|
|
disc_params.passive = 1;
|
|
|
|
/* Use defaults for the rest of the parameters. */
|
|
disc_params.itvl = BLE_GAP_SCAN_ITVL_MS(40);
|
|
disc_params.window = BLE_GAP_SCAN_WIN_MS(30);
|
|
disc_params.filter_policy = 0;
|
|
disc_params.limited = 0;
|
|
|
|
rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params, ble_gap_event, NULL);
|
|
if (rc != 0)
|
|
{
|
|
KLOG_ERROR(TAG, "Error initiating GAP discovery procedure; rc=%d", rc);
|
|
}
|
|
}
|
|
|
|
static void ble_advertise(void)
|
|
{
|
|
struct ble_gap_adv_params adv_params;
|
|
|
|
int rc = ble_gap_adv_set_data((const uint8_t *)&Advertising_Data, sizeof(Advertising_Data));
|
|
if (rc != 0)
|
|
{
|
|
KLOG_ERROR(TAG, "Error setting advertisement data; rc=%d", rc);
|
|
return;
|
|
}
|
|
|
|
/* Begin advertising. */
|
|
memset(&adv_params, 0, sizeof adv_params);
|
|
adv_params.conn_mode = BLE_GAP_CONN_MODE_NON;
|
|
adv_params.disc_mode = BLE_GAP_DISC_MODE_NON;
|
|
|
|
// N.B. High duty-cycle mode requires modification to NimBLE, or you will get an "Error enabling advertisement; rc=530"
|
|
// adv_params.high_duty_cycle = 1;
|
|
// adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(20);
|
|
// adv_params.itvl_max = BLE_GAP_ADV_ITVL_MS(25);
|
|
|
|
adv_params.itvl_min = BLE_GAP_ADV_ITVL_MS(32);
|
|
adv_params.itvl_max = BLE_GAP_ADV_ITVL_MS(37);
|
|
|
|
rc = ble_gap_adv_start(BLE_OWN_ADDR_PUBLIC, NULL, BLE_HS_FOREVER,
|
|
&adv_params, ble_gap_event, NULL);
|
|
if (rc != 0)
|
|
{
|
|
KLOG_ERROR(TAG, "Error enabling advertisement; rc=%d", rc);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// https://mynewt.apache.org/latest/network/ble_setup/ble_sync_cb.html#reset
|
|
static void ble_on_reset(int reason)
|
|
{
|
|
KLOG_ERROR(TAG, "Resetting state for reason %d.", reason);
|
|
Host_And_Controller_Synced = false;
|
|
}
|
|
|
|
// https://mynewt.apache.org/latest/network/ble_setup/ble_sync_cb.html#sync
|
|
static void ble_on_sync(void)
|
|
{
|
|
KLOG_INFO(TAG, "Host and controller synchronized.");
|
|
|
|
/* Make sure we have proper identity address set (public preferred) */
|
|
int rc = ble_hs_util_ensure_addr(0);
|
|
assert(rc == 0);
|
|
|
|
Host_And_Controller_Synced = true;
|
|
}
|
|
|
|
/**
|
|
* The NimBLE host executes this callback when a GAP event occurs. The
|
|
* application associates a GAP event callback with each connection that is
|
|
* established. KTag uses the same callback for all connections.
|
|
*
|
|
* @param event The event being signalled.
|
|
* @param arg Application-specified argument; unused by KTag.
|
|
*
|
|
* @return 0 if the application successfully handled the
|
|
* event; nonzero on failure. The semantics
|
|
* of the return code is specific to the
|
|
* particular GAP event being signalled.
|
|
*/
|
|
static int ble_gap_event(struct ble_gap_event *event, void *arg)
|
|
{
|
|
struct ble_hs_adv_fields fields;
|
|
int rc;
|
|
|
|
switch (event->type)
|
|
{
|
|
case BLE_GAP_EVENT_DISC:
|
|
rc = ble_hs_adv_parse_fields(&fields, event->disc.data,
|
|
event->disc.length_data);
|
|
if (rc != 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
BLE_Packet_T *packet = BLE_DecodeKTagPacket(event->disc.data,
|
|
event->disc.length_data,
|
|
&(event->disc.addr.val[0]),
|
|
event->disc.rssi);
|
|
|
|
if (packet != NULL)
|
|
{
|
|
if (packet->Generic.type == BLE_PACKET_TYPE_CONSOLE)
|
|
{
|
|
packet->Console.console_data[BLE_KTAG_PACKET_DATA_SIZE - 1] = '\0';
|
|
HW_Execute_Console_Command(packet->Console.console_data);
|
|
}
|
|
else
|
|
{
|
|
KEvent_T packet_received_event = {.ID = KEVENT_BLE_PACKET_RECEIVED, .Data = packet};
|
|
Post_KEvent(&packet_received_event);
|
|
}
|
|
}
|
|
return 0;
|
|
|
|
case BLE_GAP_EVENT_ADV_COMPLETE:
|
|
KLOG_INFO(TAG, "Advertise complete; reason=%d", event->adv_complete.reason);
|
|
ble_advertise();
|
|
return 0;
|
|
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void ble_host_task(void *param)
|
|
{
|
|
KLOG_INFO(TAG, "BLE Host Task Started");
|
|
|
|
// This function will return only after nimble_port_stop() is called:
|
|
nimble_port_run();
|
|
|
|
nimble_port_freertos_deinit();
|
|
}
|
|
|
|
void Initialize_BLE(void)
|
|
{
|
|
KLOG_INFO(TAG, "Initializing BLE...");
|
|
|
|
esp_err_t ret = nimble_port_init();
|
|
if (ret != ESP_OK)
|
|
{
|
|
KLOG_ERROR(TAG, "Failed to initialize NimBLE for reason %d.", ret);
|
|
return;
|
|
}
|
|
/* Configure the host. */
|
|
ble_hs_cfg.reset_cb = ble_on_reset;
|
|
ble_hs_cfg.sync_cb = ble_on_sync;
|
|
ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
|
|
|
|
ble_store_config_init();
|
|
|
|
nimble_port_freertos_init(ble_host_task);
|
|
}
|
|
|
|
void Disable_BLE(void)
|
|
{
|
|
KLOG_INFO(TAG, "Disabling BLE...");
|
|
|
|
esp_err_t ret = nimble_port_deinit();
|
|
|
|
if (ret != ESP_OK)
|
|
{
|
|
KLOG_ERROR(TAG, "Failed to deinitialize NimBLE for reason %d.", ret);
|
|
}
|
|
else
|
|
{
|
|
KLOG_INFO(TAG, "NimBLE deinitialized--BLE disabled.");
|
|
}
|
|
}
|
|
|
|
SystemKResult_T BLE_GetMyAddress(uint8_t *BD_ADDR)
|
|
{
|
|
/* Try to load a public address. */
|
|
int result = ble_hs_id_copy_addr(BLE_ADDR_PUBLIC, BD_ADDR, NULL);
|
|
if (result == BLE_HS_ENOADDR)
|
|
{
|
|
return SYSTEMK_RESULT_NOT_IMPLEMENTED;
|
|
}
|
|
else
|
|
{
|
|
return SYSTEMK_RESULT_SUCCESS;
|
|
}
|
|
}
|
|
|
|
SystemKResult_T BLE_SetAdvertisingData(BLE_AdvertisingData_T *data)
|
|
{
|
|
SystemKResult_T result = SYSTEMK_RESULT_SUCCESS;
|
|
|
|
if (data->length > BLE_MAX_ADVERTISING_BYTES)
|
|
{
|
|
result = SYSTEMK_RESULT_TOO_MANY_DATA;
|
|
}
|
|
else if (data->length < BLE_KTAG_PACKET_TOTAL_SIZE)
|
|
{
|
|
result = SYSTEMK_RESULT_TOO_FEW_DATA;
|
|
}
|
|
else
|
|
{
|
|
memcpy(Advertising_Data, data, BLE_KTAG_PACKET_TOTAL_SIZE);
|
|
}
|
|
|
|
if (Is_Scanning_And_Advertising == true)
|
|
{
|
|
// Restart advertising to put the new data into the advertisement.
|
|
ble_gap_adv_stop();
|
|
ble_advertise();
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
SystemKResult_T BLE_ScanAndAdvertise(void)
|
|
{
|
|
SystemKResult_T result = SYSTEMK_RESULT_NOT_READY;
|
|
|
|
if (Host_And_Controller_Synced == true)
|
|
{
|
|
if (Is_Scanning_And_Advertising == false)
|
|
{
|
|
ble_scan();
|
|
ble_advertise();
|
|
Is_Scanning_And_Advertising = true;
|
|
}
|
|
result = SYSTEMK_RESULT_SUCCESS;
|
|
}
|
|
|
|
return result;
|
|
} |