31#if defined(__has_include)
32#if !__has_include("common_blesvc.h")
33#error "APP_TLM_BLE = 1 requires STM32_WPAN (BLE) enabled in CubeMX: see 03 - Docs/firmware/ble.md, CubeMX configuration"
37#include "common_blesvc.h"
44#ifndef CFG_BLE_MAX_ATT_MTU
45#define CFG_BLE_MAX_ATT_MTU 23
47#define TLM_CHAR_MAX_LEN (CFG_BLE_MAX_ATT_MTU - 3)
48#define CMD_CHAR_MAX_LEN 20
50#define FLAG_KICK 0x0001u
53static const uint8_t UUID_SVC[16] = { 0x7E,0x4A,0x00,0x01, 0x2C,0x6B, 0x4F,0x8E,
54 0x9A,0x5D, 0x3B,0x1C,0x0E,0x1D,0x2F,0x30 };
55static const uint8_t UUID_TLM[16] = { 0x7E,0x4A,0x00,0x02, 0x2C,0x6B, 0x4F,0x8E,
56 0x9A,0x5D, 0x3B,0x1C,0x0E,0x1D,0x2F,0x30 };
57static const uint8_t UUID_CMD[16] = { 0x7E,0x4A,0x00,0x03, 0x2C,0x6B, 0x4F,0x8E,
58 0x9A,0x5D, 0x3B,0x1C,0x0E,0x1D,0x2F,0x30 };
60static uint16_t s_svcHdl, s_tlmHdl, s_cmdHdl;
61static volatile uint16_t s_conn = 0xFFFFu;
62static volatile uint8_t s_notify;
63static volatile uint8_t s_paramsPending;
64static osThreadId_t s_txThread;
65static uint8_t s_chunk[TLM_CHAR_MAX_LEN];
67static void uuid_lsb_first(uint8_t *dst,
const uint8_t *msb_first)
69 for (
int i = 0; i < 16; ++i) dst[i] = msb_first[15 - i];
74 if (s_txThread) (void)osThreadFlagsSet(s_txThread, FLAG_KICK);
79static SVCCTL_EvtAckStatus_t TlmSvc_EventHandler(
void *Event)
81 SVCCTL_EvtAckStatus_t ret = SVCCTL_EvtNotAck;
82 hci_event_pckt *ev = (hci_event_pckt *)(((hci_uart_pckt *)Event)->data);
83 if (ev->evt != HCI_VENDOR_SPECIFIC_DEBUG_EVT_CODE)
return ret;
85 evt_blecore_aci *ble = (evt_blecore_aci *)ev->data;
87 case ACI_GATT_ATTRIBUTE_MODIFIED_VSEVT_CODE: {
88 aci_gatt_attribute_modified_event_rp0 *am =
89 (aci_gatt_attribute_modified_event_rp0 *)ble->data;
90 if (am->Attr_Handle == (uint16_t)(s_tlmHdl + 2u)) {
91 ret = SVCCTL_EvtAckFlowEnable;
92 s_conn = am->Connection_Handle;
93 if (am->Attr_Data_Length > 0u && (am->Attr_Data[0] & COMSVC_Notification)) {
102 }
else if (am->Attr_Handle == (uint16_t)(s_cmdHdl + 1u)) {
103 ret = SVCCTL_EvtAckFlowEnable;
114 case ACI_ATT_EXCHANGE_MTU_RESP_VSEVT_CODE: {
115 aci_att_exchange_mtu_resp_event_rp0 *mr =
116 (aci_att_exchange_mtu_resp_event_rp0 *)ble->data;
118 uint16_t mtu = mr->Server_RX_MTU;
119 if (mtu > CFG_BLE_MAX_ATT_MTU) mtu = CFG_BLE_MAX_ATT_MTU;
123 case ACI_GATT_TX_POOL_AVAILABLE_VSEVT_CODE:
133static void request_link_params(uint16_t conn)
137 tBleStatus
st = aci_l2cap_connection_parameter_update_req(conn,
144 (void)aci_gatt_exchange_config(conn);
147 (void)hci_le_set_data_length(conn, 251u, 2120u);
150static void BleTxThread(
void *arg)
157 if (s_paramsPending && s_conn != 0xFFFFu) {
158 s_paramsPending = 0u;
159 request_link_params(s_conn);
164 if (maxc > TLM_CHAR_MAX_LEN) maxc = TLM_CHAR_MAX_LEN;
168 const tBleStatus
st = aci_gatt_update_char_value(s_svcHdl, s_tlmHdl, 0u,
169 (uint8_t)
n, s_chunk);
170 if (
st == BLE_STATUS_SUCCESS) {
172 }
else if (
st == BLE_STATUS_INSUFFICIENT_RESOURCES ||
st == BLE_STATUS_BUSY) {
194 SVCCTL_RegisterSvcHandler(TlmSvc_EventHandler);
197 uuid_lsb_first(uuid.Char_UUID_128, UUID_SVC);
198 st = aci_gatt_add_service(UUID_TYPE_128, (Service_UUID_t *)&uuid, PRIMARY_SERVICE,
202 uuid_lsb_first(uuid.Char_UUID_128, UUID_TLM);
203 st = aci_gatt_add_char(s_svcHdl, UUID_TYPE_128, &uuid, TLM_CHAR_MAX_LEN,
204 CHAR_PROP_NOTIFY, ATTR_PERMISSION_NONE,
205 GATT_DONT_NOTIFY_EVENTS, 0x10u, CHAR_VALUE_LEN_VARIABLE,
209 uuid_lsb_first(uuid.Char_UUID_128, UUID_CMD);
210 st = aci_gatt_add_char(s_svcHdl, UUID_TYPE_128, &uuid, CMD_CHAR_MAX_LEN,
211 CHAR_PROP_WRITE_WITHOUT_RESP | CHAR_PROP_WRITE,
212 ATTR_PERMISSION_NONE, GATT_NOTIFY_ATTRIBUTE_WRITE,
213 0x10u, CHAR_VALUE_LEN_VARIABLE, &s_cmdHdl);
216 static const osThreadAttr_t a = { .name =
"bletx", .priority = osPriorityBelowNormal,
217 .stack_size = 1024 };
218 s_txThread = osThreadNew(BleTxThread, NULL, &a);
225 s_conn = conn_handle;
236 s_paramsPending = 0u;
Phase-1 configuration: P-NUCLEO-WB55 (NUCLEO-WB55RG) + X-NUCLEO-IKS4A1 in Mode 3 (LSM6DSV16X is the s...
#define APP_BLE_CONN_INT_MIN
x1.25 ms = 15 ms (iOS minimum)
#define APP_BLE_CONN_INT_MAX
x1.25 ms = 30 ms (iOS: max >= min + 15 ms)
#define APP_BLE_SUPERV_TIMEOUT
x10 ms = 4 s
void appl_on_disconnect(void)
void appl_on_cmd_write(const uint8_t *d, uint16_t len, uint32_t now_ms)
void appl_on_connect(void)
Receive side of the ACwing Pilot link (HANDOVER_FW.md §2 and §6).
void ble_tlm_svc_init(void)
After SVCCTL_Init() and before advertising starts (APP_BLE_Init_3)
void ble_tlm_on_disconnect(void)
void ble_tlm_on_connect(uint16_t conn_handle)
"ACwing telemetry" GATT service on the STM32WB BLE stack (STM32_WPAN).
volatile uint8_t g_cpu2_ready
void tlm_ble_set_state(tlm_ble_state_t st)
uint16_t tlm_ble_peek(uint8_t *dst, uint16_t max)
Copies up to max bytes of the next notification into dst without removing them; tlm_ble_consume(n) wi...
volatile uint8_t g_dbg_ble_stall
Bench test of HANDOVER_FW.md §6 / §16.12 (debugger Live Expression): 1 = the BLE path stops on purpos...
void tlm_ble_consume(uint16_t n)
void tlm_ble_on_command(const uint8_t *data, uint16_t len)
legacy 0x01/0x02
uint16_t tlm_ble_chunk_max(void)
ATT_MTU - 3.
void tlm_ble_discard(void)
drop everything queued (consumer side)
void tlm_ble_set_mtu(uint16_t att_mtu)
void tlm_ble_set_error(uint8_t ble_status)
last non-recoverable stack error
BLE telemetry, transport-independent part (phase 2 + protocol v2).
@ TLM_BLE_OFF
BLE not compiled in or stack not started
@ TLM_BLE_CONNECTED
central connected, notifications not enabled
@ TLM_BLE_READY
service registered, advertising
#define TLM_BLE_MTU_DEFAULT
ATT_MTU before any exchange
static USBD_StatusTypeDef st(HAL_StatusTypeDef h)