diff --git a/project/ble_peripheral/ble_app_bladder_patch/command/cmd_common.h b/project/ble_peripheral/ble_app_bladder_patch/command/cmd_common.h index bae5703..e8c2cad 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/command/cmd_common.h +++ b/project/ble_peripheral/ble_app_bladder_patch/command/cmd_common.h @@ -29,7 +29,7 @@ extern uint8_t ble_bin_buffer[]; extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value); extern void ascii_format_data(uint8_t *buffer, const char *tag, const char *ascii, size_t length); extern void format_data(uint8_t *buffer, const char *tag, const uint16_t *data_array, size_t length); -extern void dr_binary_tx_safe(const uint8_t *buffer, uint16_t length); /* length: word count */ +extern uint32_t dr_binary_tx_safe(const uint8_t *buffer, uint16_t length); /* length: word count */ extern void dr_sd_delay_ms(uint32_t ms); extern volatile bool data_tx_in_progress; diff --git a/project/ble_peripheral/ble_app_bladder_patch/command/dr_util.c b/project/ble_peripheral/ble_app_bladder_patch/command/dr_util.c index 41d45bc..517e66e 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/command/dr_util.c +++ b/project/ble_peripheral/ble_app_bladder_patch/command/dr_util.c @@ -12,7 +12,7 @@ extern void single_format_data(uint8_t *buffer, const char *tag, uint16_t value); extern void format_data(uint8_t *buffer, const char *tag, uint16_t *data, uint8_t length); extern uint8_t ble_bin_buffer[]; -extern void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length); +extern uint32_t dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length); void dr_ble_return_1(const char *tag, uint16_t value) { diff --git a/project/ble_peripheral/ble_app_bladder_patch/command/parser.h b/project/ble_peripheral/ble_app_bladder_patch/command/parser.h index 458e904..6928f04 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/command/parser.h +++ b/project/ble_peripheral/ble_app_bladder_patch/command/parser.h @@ -24,7 +24,7 @@ *----------------------------------------------------------------------------*/ typedef struct { void (*log)(const char *fmt, ...); - void (*tx_bin)(const uint8_t *buf, uint16_t len); /* len: word (uint16) count */ + uint32_t (*tx_bin)(const uint8_t *buf, uint16_t len); /* len: word (uint16) count */ bool crc_check; } dr_platform_if_t; diff --git a/project/ble_peripheral/ble_app_bladder_patch/main.c b/project/ble_peripheral/ble_app_bladder_patch/main.c index 2beed84..1668e54 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/main.c +++ b/project/ble_peripheral/ble_app_bladder_patch/main.c @@ -229,9 +229,12 @@ volatile bool ble_connection_st; /* BLE connection state (1=co volatile bool data_tx_in_progress = false; /* Binary TX in progress flag */ /* -- BLE TX async retry state -- */ -static volatile bool s_tx_pending = false; /* TX retry pending */ -static uint8_t s_tx_pending_buf[BLE_NUS_MAX_DATA_LEN] = {0}; /* Pending packet (with CRC) */ -static uint16_t s_tx_pending_len = 0; /* Pending packet length */ +#define BLE_TX_PENDING_QUEUE_SIZE 8U +static uint8_t s_tx_pending_buf[BLE_TX_PENDING_QUEUE_SIZE][BLE_NUS_MAX_DATA_LEN] = {{0}}; /* Pending packets (with CRC) */ +static uint16_t s_tx_pending_len[BLE_TX_PENDING_QUEUE_SIZE] = {0}; /* Pending packet lengths */ +static volatile uint8_t s_tx_pending_head = 0; /* Next packet to retry */ +static volatile uint8_t s_tx_pending_tail = 0; /* Next enqueue slot */ +static volatile uint8_t s_tx_pending_count = 0; /* Queued packet count */ char m_static_passkey[PASSKEY_LENGTH] = DEFAULT_PASSKEY; /* Static passkey (6 digits, loaded from FDS) */ char SERIAL_NO[SERIAL_NO_LENGTH] = {0}; /* Serial number (used as BLE device name) */ @@ -562,47 +565,88 @@ extern void maa_async_abort(void); static volatile uint8_t pending_cmd_buf[BLE_NUS_MAX_DATA_LEN] = {0}; static volatile uint8_t pending_cmd_len = 0; +static bool ble_tx_pending_has_data(void) +{ + return (s_tx_pending_count > 0); +} + +static void ble_tx_pending_clear(void) +{ + s_tx_pending_head = 0; + s_tx_pending_tail = 0; + s_tx_pending_count = 0; +} + +static bool ble_tx_pending_enqueue(uint8_t const *p_data, uint16_t len) +{ + if (s_tx_pending_count >= BLE_TX_PENDING_QUEUE_SIZE) + { + return false; + } + + memcpy(s_tx_pending_buf[s_tx_pending_tail], p_data, len); + s_tx_pending_len[s_tx_pending_tail] = len; + s_tx_pending_tail = (uint8_t)((s_tx_pending_tail + 1U) % BLE_TX_PENDING_QUEUE_SIZE); + s_tx_pending_count++; + return true; +} + +static void ble_tx_pending_pop(void) +{ + if (s_tx_pending_count == 0) + { + return; + } + + s_tx_pending_len[s_tx_pending_head] = 0; + s_tx_pending_head = (uint8_t)((s_tx_pending_head + 1U) % BLE_TX_PENDING_QUEUE_SIZE); + s_tx_pending_count--; +} + static bool ble_retry_pending_tx(void) { uint16_t send_len; uint32_t err; + bool freed_slot = false; - if (!s_tx_pending) + if (!ble_tx_pending_has_data()) { return true; } if (ble_connection_st != BLE_CONNECTED_ST) { - s_tx_pending = false; - s_tx_pending_len = 0; + ble_tx_pending_clear(); return false; } - send_len = s_tx_pending_len; - err = ble_nus_data_send(&m_nus, s_tx_pending_buf, &send_len, m_conn_handle); + while (ble_tx_pending_has_data()) + { + send_len = s_tx_pending_len[s_tx_pending_head]; + err = ble_nus_data_send(&m_nus, s_tx_pending_buf[s_tx_pending_head], &send_len, m_conn_handle); - if (err == NRF_SUCCESS) - { - s_tx_pending = false; - s_tx_pending_len = 0; - return true; - } - if (err == NRF_ERROR_RESOURCES) - { - return false; - } - if (err == NRF_ERROR_INVALID_STATE || err == NRF_ERROR_NOT_FOUND) - { - DBG_PRINTF("[BLE TX] Pending send aborted\r\n"); - s_tx_pending = false; - s_tx_pending_len = 0; - return false; + if (err == NRF_SUCCESS) + { + ble_tx_pending_pop(); + freed_slot = true; + continue; + } + if (err == NRF_ERROR_RESOURCES) + { + return freed_slot; + } + if (err == NRF_ERROR_INVALID_STATE || err == NRF_ERROR_NOT_FOUND) + { + DBG_PRINTF("[BLE TX] Pending send aborted\r\n"); + ble_tx_pending_clear(); + return false; + } + + DBG_PRINTF("[BLE TX] Pending err:0x%X\r\n", err); + ble_tx_pending_pop(); + freed_slot = true; } - DBG_PRINTF("[BLE TX] Pending err:0x%X\r\n", err); - s_tx_pending = false; - s_tx_pending_len = 0; - return false; + return true; } /** @@ -652,7 +696,7 @@ static void nus_data_handler(ble_nus_evt_t * p_evt) else if (p_evt->type == BLE_NUS_EVT_TX_RDY) { /* First drain any queued packet that previously hit NRF_ERROR_RESOURCES. */ - if (s_tx_pending) + if (ble_tx_pending_has_data()) { if (!ble_retry_pending_tx()) { @@ -1072,7 +1116,7 @@ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context) m_tx_in_progress = false; maa_async_abort(); // Prevent hang caused by async measurement state - s_tx_pending = false; // Clear pending TX + ble_tx_pending_clear(); // Clear pending TX /* Adjust advertising duration at runtime based on disconnect reason */ (void)sd_ble_gap_adv_stop(m_advertising.adv_handle); @@ -1554,16 +1598,16 @@ void param_error(const char *cmd) dr_binary_tx_safe(ble_bin_buffer, 3); } -void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length) +uint32_t dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length) { uint32_t err_code; static uint8_t tx_buffer[BLE_NUS_MAX_DATA_LEN] = {0}; uint16_t send_len; uint16_t total_len; - if (ble_connection_st == 0) return; + if (ble_connection_st == 0) return NRF_ERROR_INVALID_STATE; - if (length * sizeof(uint16_t) > (BLE_NUS_MAX_DATA_LEN - 2)) return; + if (length * sizeof(uint16_t) > (BLE_NUS_MAX_DATA_LEN - 2)) return NRF_ERROR_DATA_SIZE; if (ble_connection_st == BLE_CONNECTED_ST) { @@ -1573,37 +1617,48 @@ void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length) tx_buffer[length * sizeof(uint16_t) + 1] = (uint8_t)((crc >> 8) & 0xFF); total_len = length * sizeof(uint16_t) + 2; + + if (ble_tx_pending_has_data()) + { + if (!ble_tx_pending_enqueue(tx_buffer, total_len)) + { + DBG_PRINTF("[BLE TX] Pending queue full, dropping new packet\r\n"); + return NRF_ERROR_NO_MEM; + } + + return NRF_ERROR_RESOURCES; + } + send_len = total_len; err_code = ble_nus_data_send(&m_nus, tx_buffer, &send_len, m_conn_handle); if (err_code == NRF_SUCCESS) { - return; + return NRF_SUCCESS; } else if (err_code == NRF_ERROR_RESOURCES) { - if (s_tx_pending) + if (!ble_tx_pending_enqueue(tx_buffer, total_len)) { - DBG_PRINTF("[BLE TX] Pending queue busy, dropping new packet\r\n"); - return; + DBG_PRINTF("[BLE TX] Pending queue full, dropping new packet\r\n"); + return NRF_ERROR_NO_MEM; } - memcpy(s_tx_pending_buf, tx_buffer, total_len); - s_tx_pending_len = total_len; - s_tx_pending = true; - return; + return NRF_ERROR_RESOURCES; } else if (err_code == NRF_ERROR_INVALID_STATE || err_code == NRF_ERROR_NOT_FOUND) { DBG_PRINTF("[BLE TX] Disconnected\r\n"); - return; + return err_code; } else { DBG_PRINTF("[BLE TX] Err:0x%X\r\n", err_code); - return; + return err_code; } } + + return NRF_ERROR_INVALID_STATE; } /*============================================================================== diff --git a/project/ble_peripheral/ble_app_bladder_patch/main.h b/project/ble_peripheral/ble_app_bladder_patch/main.h index a97e674..019cfd6 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/main.h +++ b/project/ble_peripheral/ble_app_bladder_patch/main.h @@ -43,8 +43,9 @@ * - VBTFW0115 260518 jhChun * : Added mtb? command (reb:+raa:+rim:, 6ch piezo + ICM42670 FIFO at 25 Hz). * : rim: packet format and FIFO sample cap/filter options (app_raw). +* - VBTFW0116 260522 jhChun : Expanded BLE TX pending slots from 1 → 8 to reduce ADC data packet loss when the TX queue is full ------------------------------------------------------------------------- */ -#define FIRMWARE_VERSION "VBTFW0115" +#define FIRMWARE_VERSION "VBTFW0116" /*============================================================================== * Data Length Constants @@ -141,7 +142,7 @@ void data_tx_handler(char const *p_data_to_send); /* Safe binary data BLE transmission (CRC16 appended, with retry logic) * @param ble_bin_buff Binary buffer to transmit * @param length Data length in uint16_t words (actual bytes = length x 2) */ -void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length); +uint32_t dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length); /* SoftDevice-compatible delay (nrf_delay_ms wrapper) */ void dr_sd_delay_ms(uint32_t ms); diff --git a/project/ble_peripheral/ble_app_bladder_patch/measurement/adc121s051/dr_adc121s051.c b/project/ble_peripheral/ble_app_bladder_patch/measurement/adc121s051/dr_adc121s051.c index 1529fb0..1656774 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/measurement/adc121s051/dr_adc121s051.c +++ b/project/ble_peripheral/ble_app_bladder_patch/measurement/adc121s051/dr_adc121s051.c @@ -605,7 +605,7 @@ uint32_t dr_adc_get_vref(void) *============================================================================*/ /* External BLE NUS functions and variables from main.c */ -extern void dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length); +extern uint32_t dr_binary_tx_safe(uint8_t const *ble_bin_buff, uint16_t length); extern void dr_sd_delay_ms(uint32_t ms); /* Platform interface (log function) */ @@ -1163,6 +1163,17 @@ static maa_async_ctx_t g_maa_ctx = { .state = MAA_ASYNC_IDLE }; /* (reb+red merged protocol) */ +typedef enum { + MAA_ASYNC_TX_RETRY = 0, + MAA_ASYNC_TX_DONE, + MAA_ASYNC_TX_MORE +} maa_async_tx_result_t; + +static bool maa_async_tx_accepted(uint32_t err_code) +{ + return (err_code == NRF_SUCCESS || err_code == NRF_ERROR_RESOURCES); +} + /** * @brief Capture one channel (internal helper) */ @@ -1192,10 +1203,11 @@ static dr_adc_err_t maa_async_capture_channel(uint8_t ch) * reb: tag(4) + num_samples(2) + data(up to 238 bytes) * If <= 100 samples (200B), the channel completes in this single packet */ -static void maa_async_send_header(void) +static bool maa_async_send_header(void) { dr_maa_channel_t *ch = &g_maa_ctx.channels[g_maa_ctx.current_ch]; uint8_t *buf = g_maa_ctx.ble_buffer; + uint32_t tx_err; uint16_t total_data_bytes = ch->num_samples * 2; @@ -1214,7 +1226,12 @@ static void maa_async_send_header(void) buf[dst_idx++] = (uint8_t)(sample & 0xFF); } - dr_binary_tx_safe(buf, dst_idx / 2); + tx_err = dr_binary_tx_safe(buf, dst_idx / 2); + if (!maa_async_tx_accepted(tx_err)) + { + return false; + } + dr_sd_delay_ms(MAA_ASYNC_POST_REB_MS); g_maa_ctx.current_pkt = 0; @@ -1229,21 +1246,24 @@ static void maa_async_send_header(void) { g_maa_ctx.state = MAA_ASYNC_TX_DATA; } + + return true; } /** * @brief Send next red: data packet - * @return true if more packets to send, false if done with current channel + * @return TX result: retry, current channel done, or more packets remain */ -static bool maa_async_send_data_packet(void) +static maa_async_tx_result_t maa_async_send_data_packet(void) { dr_maa_channel_t *ch = &g_maa_ctx.channels[g_maa_ctx.current_ch]; uint8_t *buf = g_maa_ctx.ble_buffer; uint16_t total_data_bytes = ch->num_samples * 2; + uint32_t tx_err; if (g_maa_ctx.data_offset >= total_data_bytes) { - return false; /* All data sent */ + return MAA_ASYNC_TX_DONE; /* All data sent */ } uint16_t pkt_idx = g_maa_ctx.current_pkt; @@ -1265,7 +1285,12 @@ static bool maa_async_send_data_packet(void) buf[dst_idx++] = (uint8_t)(sample & 0xFF); } - dr_binary_tx_safe(buf, dst_idx / 2); + tx_err = dr_binary_tx_safe(buf, dst_idx / 2); + if (!maa_async_tx_accepted(tx_err)) + { + return MAA_ASYNC_TX_RETRY; + } + dr_sd_delay_ms(MAA_ASYNC_POST_RED_MS); g_maa_ctx.data_offset += chunk_size; @@ -1273,15 +1298,16 @@ static bool maa_async_send_data_packet(void) //ADC_LOG("maa_async: CH%u red:%u (%u/%u bytes)", g_maa_ctx.current_ch, pkt_idx, g_maa_ctx.data_offset, total_data_bytes); - return (g_maa_ctx.data_offset < total_data_bytes); + return (g_maa_ctx.data_offset < total_data_bytes) ? MAA_ASYNC_TX_MORE : MAA_ASYNC_TX_DONE; } /** * @brief Send raa: completion marker */ -static void maa_async_send_completion(uint16_t status) +static bool maa_async_send_completion(uint16_t status) { uint8_t *buf = g_maa_ctx.ble_buffer; + uint32_t tx_err; /* Wait for previous TX to complete before sending raa: */ dr_sd_delay_ms(MAA_ASYNC_PRE_RAA_MS); @@ -1290,7 +1316,11 @@ static void maa_async_send_completion(uint16_t status) buf[4] = (uint8_t)(status >> 8); buf[5] = (uint8_t)(status & 0xFF); - dr_binary_tx_safe(buf, 3); + tx_err = dr_binary_tx_safe(buf, 3); + if (!maa_async_tx_accepted(tx_err)) + { + return false; + } //if (g_plat.log) g_plat.log("-------------------------------------------------------------------------------------\r\n"); @@ -1307,6 +1337,8 @@ static void maa_async_send_completion(uint16_t status) g_maa_ctx.on_complete_cb = NULL; /* one-shot: prevent re-entry */ cb(); } + + return true; } /*============================================================================== @@ -1397,7 +1429,8 @@ dr_adc_err_t maa_async_start(uint8_t freq_option, uint16_t delay_us, uint16_t nu dr_piezo_power_off(); /* Send CH0 header - this will trigger TX_RDY for subsequent packets */ - maa_async_send_header(); + g_maa_ctx.state = MAA_ASYNC_TX_HEADER; + (void)maa_async_send_header(); return DR_ADC_OK; } @@ -1412,8 +1445,16 @@ bool maa_async_on_tx_ready(void) switch (g_maa_ctx.state) { case MAA_ASYNC_TX_DATA: + { + maa_async_tx_result_t tx_result; + /* Send next data packet */ - if (!maa_async_send_data_packet()) + tx_result = maa_async_send_data_packet(); + if (tx_result == MAA_ASYNC_TX_RETRY) + { + return true; + } + if (tx_result == MAA_ASYNC_TX_DONE) { /* Current channel done, move to next */ g_maa_ctx.current_ch++; @@ -1422,22 +1463,20 @@ bool maa_async_on_tx_ready(void) { /* All channels done */ g_maa_ctx.state = MAA_ASYNC_COMPLETE; - maa_async_send_completion(0x0000); - return false; + return maa_async_send_completion(0x0000) ? false : true; } else { /* all channels already captured, send header directly */ - g_maa_ctx.state = MAA_ASYNC_CAPTURING; - maa_async_send_header(); + g_maa_ctx.state = MAA_ASYNC_TX_HEADER; + (void)maa_async_send_header(); } } return true; + } case MAA_ASYNC_TX_HEADER: - /* Header sent, start sending data */ - g_maa_ctx.state = MAA_ASYNC_TX_DATA; - maa_async_send_data_packet(); + (void)maa_async_send_header(); return true; case MAA_ASYNC_CAPTURING: @@ -1445,6 +1484,8 @@ bool maa_async_on_tx_ready(void) return true; case MAA_ASYNC_COMPLETE: + return maa_async_send_completion(0x0000) ? false : true; + case MAA_ASYNC_IDLE: default: return false; diff --git a/project/ble_peripheral/ble_app_bladder_patch/pca10056/s140/arm5_no_packs/ble_app_bladder_patch_s140.uvoptx b/project/ble_peripheral/ble_app_bladder_patch/pca10056/s140/arm5_no_packs/ble_app_bladder_patch_s140.uvoptx index 749690e..dbea7d1 100644 --- a/project/ble_peripheral/ble_app_bladder_patch/pca10056/s140/arm5_no_packs/ble_app_bladder_patch_s140.uvoptx +++ b/project/ble_peripheral/ble_app_bladder_patch/pca10056/s140/arm5_no_packs/ble_app_bladder_patch_s140.uvoptx @@ -1156,7 +1156,7 @@ 1 1 1 - 0 + 1 0 0 ..\..\..\main.c