From 44c20b8a7be9d6fd9dba4d33d9c361f28cdce4a0 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Tue, 14 Jul 2020 18:05:18 +0200 Subject: [PATCH] stm32-sx1280: advertise only every advertising interval max --- port/stm32-sx1280/README.md | 13 +- port/stm32-sx1280/Src/main.c | 4 +- port/stm32-sx1280/controller/controller.c | 2 + port/stm32-sx1280/controller/ll_sx1280.c | 185 ++++++++++++++-------- port/stm32-sx1280/port/btstack_port.c | 4 +- 5 files changed, 129 insertions(+), 79 deletions(-) diff --git a/port/stm32-sx1280/README.md b/port/stm32-sx1280/README.md index b2acf8c78..3f4cdb535 100644 --- a/port/stm32-sx1280/README.md +++ b/port/stm32-sx1280/README.md @@ -21,9 +21,9 @@ The Makefile project compiles gatt_counter, gatt_streamer_server, hog_mouse and ## Limitation ### Advertising State: -- Advertises as fast as possible, back to back - Only Connectable Advertising supported - Only fixed public BD_ADDR of 33:33:33:33:33:33 is used +- Scan response not supported ### Connection State: - Only a single packet is sent in each Connection Interval @@ -49,12 +49,13 @@ For the FMLR-80-P-STL4E module, just run make. You can upload the .elf file crea ## TODO ### General -- only advertise with advertising interval -- support other adv types -- indicate random address in adertising pdus -- allow to set random BD_ADDR via HCI command -- handle Connection Param Update +- handle disconnect for gatt streamer demo - multiple packets per connection interval +- handle Connection Param Update +- indicate random address in advertising pdus +- allow to set random BD_ADDR via HCI command +- support other adv types +- support scan requests - handle Encryption ## Low Power diff --git a/port/stm32-sx1280/Src/main.c b/port/stm32-sx1280/Src/main.c index 953702c96..b8c8261bf 100644 --- a/port/stm32-sx1280/Src/main.c +++ b/port/stm32-sx1280/Src/main.c @@ -65,7 +65,7 @@ static void MX_SPI2_Init(void); static void MX_TIM2_Init(void); static void MX_LPTIM1_Init(void); /* USER CODE BEGIN PFP */ -void ble_rx(void); +void btstack_port(void); /* USER CODE END PFP */ @@ -118,7 +118,7 @@ int main(void) // Enable SX1280 Clock HAL_GPIO_WritePin(RF_TXCO_GPIO_Port, RF_TXCO_Pin, GPIO_PIN_SET); - ble_rx(); + btstack_port(); /* USER CODE END 2 */ diff --git a/port/stm32-sx1280/controller/controller.c b/port/stm32-sx1280/controller/controller.c index 2924def41..f2d59837b 100644 --- a/port/stm32-sx1280/controller/controller.c +++ b/port/stm32-sx1280/controller/controller.c @@ -35,6 +35,8 @@ * */ +#define BTSTACK_FILE__ "controller.c" + #define DEBUG #include diff --git a/port/stm32-sx1280/controller/ll_sx1280.c b/port/stm32-sx1280/controller/ll_sx1280.c index 91b28cb88..181ab7d7e 100644 --- a/port/stm32-sx1280/controller/ll_sx1280.c +++ b/port/stm32-sx1280/controller/ll_sx1280.c @@ -35,6 +35,8 @@ * */ +#define BTSTACK_FILE__ "ll_sx1280.c" + #define DEBUG #include @@ -151,6 +153,7 @@ typedef enum { RADIO_RX_ERROR, RADIO_TX_TIMEOUT, RADIO_W4_TX_DONE_TO_RX, + RADIO_W4_TIMER, } radio_state_t; // Link Layer State @@ -291,7 +294,8 @@ static struct { uint8_t adv_data[31]; // adv param - uint8_t adv_map; + uint8_t adv_map; + uint32_t adv_interval_us; // next expected sequence number volatile uint8_t next_expected_sequence_number; @@ -338,6 +342,9 @@ static uint8_t ll_outgoing_hci_event[258]; static bool ll_send_disconnected; static bool ll_send_connection_complete; +// prototypes +static void radio_set_timer(uint32_t anchor_offset_us); + // memory pool for acl-le pdus static ll_pdu_t * btstack_memory_ll_pdu_get(void){ @@ -398,6 +405,32 @@ static void next_channel(void){ select_channel(ctx.channel); } +static void ll_advertising_statemachine(void){ + switch ( radio_state) { + case RADIO_RX_ERROR: + case RADIO_LOWPOWER: + // find next channel + while (ctx.channel < 40){ + ctx.channel++; + if ((ctx.adv_map & (1 << (ctx.channel - 37))) != 0) { + // Set Channel + select_channel(ctx.channel); + radio_state = RADIO_W4_TX_DONE_TO_RX; + send_adv(); + break; + } + if (ctx.channel >= 40){ + // Set timer + radio_state = RADIO_W4_TIMER; + radio_set_timer(ctx.adv_interval_us); + } + } + break; + default: + break; + } +} + static void start_advertising(void){ Radio.SetAutoTx(AUTO_RX_TX_OFFSET); @@ -418,10 +451,15 @@ static void start_advertising(void){ // Set AccessAddress for ADV packets Radio.SetBleAdvertizerAccessAddress( ); + radio_state = RADIO_LOWPOWER; ll_state = LL_STATE_ADVERTISING; - // dummy channel + // prepare ctx.channel = 36; + ctx.anchor_ticks = HAL_LPTIM_ReadCounter(&hlptim1); + + // and get started + ll_advertising_statemachine(); } static void start_hopping(void){ @@ -434,16 +472,16 @@ static void start_hopping(void){ Radio.SetPacketParams( &packetParams ); } -static void stop_timer_for_sync_hop(void){ +static void radio_stop_timer(void){ __HAL_LPTIM_DISABLE_IT(&hlptim1, LPTIM_IT_CMPM); __HAL_LPTIM_CLEAR_FLAG(&hlptim1, LPTIM_IT_CMPM); } -static void set_timer_for_sync_hop(void){ +static void radio_set_timer(uint32_t anchor_offset_us){ // stop - stop_timer_for_sync_hop(); - // set timer - uint16_t timeout_ticks = ctx.anchor_ticks + US_TO_TICKS(ctx.conn_interval_us - SYNC_HOP_DELAY_US); + radio_stop_timer(); + // set timer for next radio event relative to anchor + uint16_t timeout_ticks = ctx.anchor_ticks + US_TO_TICKS(anchor_offset_us); __HAL_LPTIM_COMPARE_SET(&hlptim1, timeout_ticks); __HAL_LPTIM_ENABLE_IT(&hlptim1, LPTIM_IT_CMPM); } @@ -451,7 +489,7 @@ static void set_timer_for_sync_hop(void){ static void ll_terminate(void){ ll_state = LL_STATE_STANDBY; // stop sync hop timer - stop_timer_for_sync_hop(); + radio_stop_timer(); // free outgoing tx packet if ((ctx.tx_pdu != NULL) && (ctx.tx_pdu != &ll_tx_packet)){ btstack_memory_ll_pdu_free(ctx.tx_pdu); @@ -463,58 +501,73 @@ static void ll_terminate(void){ ll_send_disconnected = true; } -static void sync_next_hop(void){ +static void radio_timer_handler(void){ uint16_t t0 = HAL_LPTIM_ReadCounter(&hlptim1); - // check supervision timeout - ctx.time_without_any_packets_us += ctx.conn_interval_us; - if (ctx.time_without_any_packets_us > ctx.supervision_timeout_us) { - printf("Supervision timeout\n\n"); - ll_terminate(); - return; + switch (ll_state){ + case LL_STATE_CONNECTED: + // check supervision timeout + ctx.time_without_any_packets_us += ctx.conn_interval_us; + if (ctx.time_without_any_packets_us > ctx.supervision_timeout_us) { + printf("Supervision timeout\n\n"); + ll_terminate(); + return; + } + + // prepare next connection event + ctx.connection_event++; + ctx.anchor_ticks += US_TO_TICKS(ctx.conn_interval_us); + + ctx.packet_nr_in_connection_event = 0; + next_channel(); + + if (ctx.channel_map_update_pending && (ctx.channel_map_update_instant == ctx.connection_event)) { + hopping_set_channel_map( &h, (const uint8_t *) &ctx.channel_map_update_map ); + ctx.channel_map_update_pending = false; + } + + if ( ctx.conn_param_update_pending && ((ctx.conn_param_update_instant) == ctx.connection_event) ) { + ctx.conn_interval_us = ctx.conn_param_update_interval_us; + ctx.conn_latency = ctx.conn_param_update_latency; + ctx.supervision_timeout_us = ctx.conn_param_update_timeout_us; + ctx.conn_param_update_pending = false; + + radio_stop_timer(); + ctx.synced = false; + } + + // restart radio timer (might get overwritten by first packet) + radio_set_timer(ctx.conn_interval_us - SYNC_HOP_DELAY_US); + + receive_master(); + + printf("--SYNC-Ch %02u-Event %04u - t %08u--\n", ctx.channel, ctx.connection_event, t0); + break; + case LL_STATE_ADVERTISING: + // send adv on all configured channels + ctx.channel = 36; + ctx.anchor_ticks = t0; + radio_stop_timer(); + ll_advertising_statemachine(); + radio_state = RADIO_LOWPOWER; + break; + default: + break; } - // prepare next connection event - ctx.connection_event++; - ctx.anchor_ticks += US_TO_TICKS(ctx.conn_interval_us); - - ctx.packet_nr_in_connection_event = 0; - next_channel(); - - if (ctx.channel_map_update_pending && (ctx.channel_map_update_instant == ctx.connection_event)) { - hopping_set_channel_map( &h, (const uint8_t *) &ctx.channel_map_update_map ); - ctx.channel_map_update_pending = false; - } - - if ( ctx.conn_param_update_pending && ((ctx.conn_param_update_instant) == ctx.connection_event) ) { - ctx.conn_interval_us = ctx.conn_param_update_interval_us; - ctx.conn_latency = ctx.conn_param_update_latency; - ctx.supervision_timeout_us = ctx.conn_param_update_timeout_us; - ctx.conn_param_update_pending = false; - - stop_timer_for_sync_hop(); - ctx.synced = false; - } - - // restart sync next hop timer (might get overwritten by first packet) - set_timer_for_sync_hop(); - - receive_master(); - - printf("--SYNC-Ch %02u-Event %04u - t %08u--\n", ctx.channel, ctx.connection_event, t0); } void HAL_LPTIM_CompareMatchCallback(LPTIM_HandleTypeDef *hlptim){ UNUSED(hlptim); - sync_next_hop(); + radio_timer_handler(); } void HAL_LPTIM_AutoReloadMatchCallback(LPTIM_HandleTypeDef *hlptim){ UNUSED(hlptim); static uint32_t time_seconds = 0; time_seconds += 2; - printf("Time: %4u s\n", time_seconds); + // printf("Time: %4u s\n", time_seconds); } /** Radio IRQ handlers */ @@ -602,7 +655,7 @@ static void radio_on_rx_done(void ){ if (ctx.packet_nr_in_connection_event == 0){ ctx.anchor_ticks = packet_start_ticks; ctx.synced = true; - set_timer_for_sync_hop(); + radio_set_timer(ctx.conn_interval_us - SYNC_HOP_DELAY_US); } ctx.packet_nr_in_connection_event++; @@ -667,8 +720,9 @@ void ll_init(void){ // set test bd addr 33:33:33:33:33:33 memset(ctx.bd_addr_le, 0x33, 6); - // default channels + // default channels, advertising interval ctx.adv_map = 0x7; + ctx.adv_interval_us = 1280000; } void ll_radio_on(void){ @@ -737,7 +791,6 @@ static void ll_handle_conn_ind(ll_pdu_t * rx_packet){ // convert to us ctx.conn_interval_us = ctx.conn_interval_1250us * 1250; ctx.supervision_timeout_us = ctx.supervision_timeout_10ms * 10000; - ctx.connection_event = 0; ctx.packet_nr_in_connection_event = 0; ctx.next_expected_sequence_number = 0; @@ -905,7 +958,7 @@ uint8_t ll_set_scan_enable(uint8_t le_scan_enable, uint8_t filter_duplicates){ static uint8_t ll_start_advertising(void){ // COMMAND DISALLOWED if wrong state. if (ll_state != LL_STATE_STANDBY) return ERROR_CODE_COMMAND_DISALLOWED; - printf("Start Advertising on channels 0x%0x\n", ctx.adv_map); + log_info("Start Advertising on channels 0x%0x, interval %lu us", ctx.adv_map, ctx.adv_interval_us); start_advertising(); return ERROR_CODE_SUCCESS; } @@ -929,9 +982,20 @@ uint8_t ll_set_advertise_enable(uint8_t le_adv_enable){ uint8_t ll_set_advertising_parameters(uint16_t advertising_interval_min, uint16_t advertising_interval_max, uint8_t advertising_type, uint8_t own_address_type, uint8_t peer_address_types, uint8_t * peer_address, uint8_t advertising_channel_map, uint8_t advertising_filter_policy){ + + // validate channel map if (advertising_channel_map == 0) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; if ((advertising_channel_map & 0xf8) != 0) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; + + // validate advertising interval + if (advertising_interval_min < 0x20) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; + if (advertising_interval_min > 0x4000) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; + if (advertising_interval_max < 0x20) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; + if (advertising_interval_max > 0x4000) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; + if (advertising_interval_min > advertising_interval_max) return ERROR_CODE_INVALID_HCI_COMMAND_PARAMETERS; + ctx.adv_map = advertising_channel_map; + ctx.adv_interval_us = advertising_interval_max * 625; // TODO: validate other params // TODO: process other params @@ -981,27 +1045,8 @@ void ll_execute_once(void){ switch ( ll_state ){ case LL_STATE_ADVERTISING: - switch ( radio_state) { - case RADIO_RX_ERROR: - case RADIO_LOWPOWER: - // find next channel - while (ctx.adv_map != 0){ - ctx.channel++; - if ((ctx.adv_map & (1 << (ctx.channel - 37))) != 0) { - // Set Channel - select_channel(ctx.channel); - radio_state = RADIO_W4_TX_DONE_TO_RX; - send_adv(); - break; - } - if (ctx.channel >= 40){ - ctx.channel = 36; - } - } - break; - default: - break; - } + ll_advertising_statemachine(); + break; default: break; } diff --git a/port/stm32-sx1280/port/btstack_port.c b/port/stm32-sx1280/port/btstack_port.c index cc9d7b86b..1f6d01991 100644 --- a/port/stm32-sx1280/port/btstack_port.c +++ b/port/stm32-sx1280/port/btstack_port.c @@ -35,6 +35,8 @@ * */ +#define BTSTACK_FILE__ "btstack_port.c" + #define DEBUG #include @@ -67,7 +69,7 @@ void hal_cpu_enable_irqs(void){} void hal_cpu_enable_irqs_and_sleep(void){} void btstack_main(void); -void ble_rx( void ){ +void btstack_port(void){ // test code // lptim1_calibration();