From 3f2c2e774baea1a7e9149ae2343b4ac361519e07 Mon Sep 17 00:00:00 2001 From: jhchun Date: Thu, 16 Jul 2026 17:24:53 +0900 Subject: [PATCH] =?UTF-8?q?BLE=20RX=20=EB=8B=A8=EC=9D=BC=20=EC=8A=AC?= =?UTF-8?q?=EB=A1=AF=EC=97=90=EC=84=9C=208-depth=20=EB=A7=81=EB=B2=84?= =?UTF-8?q?=ED=8D=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 연결 직후 초기화 명령이 몰릴 때, 앞 명령 처리 중 도착한 명령이 drop: command busy로 버려지던 문제 해결 - 큐가 가득 찰 때만 drop: queue full로 처리 --- src/main.c | 95 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 50 insertions(+), 45 deletions(-) diff --git a/src/main.c b/src/main.c index 26a47ff..ab125f0 100644 --- a/src/main.c +++ b/src/main.c @@ -28,6 +28,7 @@ LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF); #define BLE_CMD_MAX_LEN 256 +#define BLE_CMD_QUEUE_DEPTH 8 // RX 명령 링버퍼 깊이(버스트 흡수) #define BLE_CMD_WORKQ_STACK_SZ 8192 #define DFU_RESUME_MAGIC 0xD5U #define DFU_RESUME_GPREGRET_REG 1U @@ -123,15 +124,20 @@ static struct mgmt_callback smp_cmd_status_callback = { /* * BLE RX 콜백 안에서 무거운 일을 바로 처리하지 않기 위해 별도 work queue를 둠 - * - 명령 하나가 끝날 때까지 다음 명령 drop : 확인 필요 + * - 연결 직후 초기화 버스트 등 명령이 몰릴 때 대비해 링버퍼(FIFO)로 흡수 + * - 큐가 가득 차면(BLE_CMD_QUEUE_DEPTH) 그 때만 drop */ static struct k_work_q ble_cmd_work_q; K_THREAD_STACK_DEFINE(ble_cmd_workq_stack, BLE_CMD_WORKQ_STACK_SZ); static struct k_work ble_cmd_work; // BLE 명령 처리 work -static struct k_spinlock ble_cmd_lock; // RX 공유 버퍼 보호 -static uint8_t ble_cmd_buf[BLE_CMD_MAX_LEN];// RX 명령 복사 버퍼 -static uint16_t ble_cmd_len; // RX 명령 길이 -static bool ble_cmd_pending; // 처리 대기 명령 있음 +static struct k_spinlock ble_cmd_lock; // RX 큐 보호 + +// RX 명령 링버퍼: 들어온 순서대로 쌓고 워커가 순차 처리 (head=꺼낼 위치, tail=넣을 위치) +static uint8_t ble_cmd_q_buf[BLE_CMD_QUEUE_DEPTH][BLE_CMD_MAX_LEN]; // 명령 데이터 +static uint16_t ble_cmd_q_len[BLE_CMD_QUEUE_DEPTH]; // 각 명령 길이 +static uint8_t ble_cmd_q_head; // 다음에 꺼낼 슬롯 +static uint8_t ble_cmd_q_tail; // 다음에 넣을 슬롯 +static uint8_t ble_cmd_q_count; // 큐에 쌓인 명령 수 static void ble_cmd_work_handler(struct k_work *work) { @@ -139,32 +145,33 @@ static void ble_cmd_work_handler(struct k_work *work) // work queue 로컬 복사본 uint8_t local_buf[BLE_CMD_MAX_LEN]; - uint16_t local_len = 0U; + uint16_t local_len; - // 공유 RX 명령 슬롯 보호: 현재 구조는 한 번에 한 명령만 보관 - k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock); - if (ble_cmd_pending) + // 큐가 빌 때까지 head에서 하나씩 꺼내 순차 처리 (dispatch는 락 밖에서) + for (;;) { - local_len = ble_cmd_len; - memcpy(local_buf, ble_cmd_buf, local_len); + k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock); + if (ble_cmd_q_count == 0U) + { + k_spin_unlock(&ble_cmd_lock, key); + break; + } + local_len = ble_cmd_q_len[ble_cmd_q_head]; + memcpy(local_buf, ble_cmd_q_buf[ble_cmd_q_head], local_len); + ble_cmd_q_head = (uint8_t)((ble_cmd_q_head + 1U) % BLE_CMD_QUEUE_DEPTH); + ble_cmd_q_count--; + k_spin_unlock(&ble_cmd_lock, key); + + if (local_len == 0U) + { + DBG_ERR("[BLE RX] worker: empty\r\n"); + continue; + } + + // 일반 스레드 문맥 명령 처리 + //DBG_CORE("[BLE RX] worker dispatch len=%u\r\n", local_len); + ble_cmd_dispatch(local_buf, local_len); } - k_spin_unlock(&ble_cmd_lock, key); - - if (local_len == 0U) - { - DBG_ERR("[BLE RX] worker: empty\r\n"); - return; - } - - // 일반 스레드 문맥 명령 처리 - //DBG_CORE("[BLE RX] worker dispatch len=%u\r\n", local_len); - ble_cmd_dispatch(local_buf, local_len); - - // 명령 처리 완료 표시 - key = k_spin_lock(&ble_cmd_lock); - ble_cmd_pending = false; - ble_cmd_len = 0U; - k_spin_unlock(&ble_cmd_lock, key); } /* 시스템 워크큐에서 BLE advertising 시작 */ @@ -220,30 +227,27 @@ static void ble_rx_handler(const uint8_t *data, uint16_t len) return; } - // 공유 RX 명령 슬롯 보호: 현재 구조는 한 번에 한 명령만 보관 + // 공유 RX 큐 보호: tail 슬롯에 명령 적재 (FIFO) k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock); - if (ble_cmd_pending) + if (ble_cmd_q_count >= BLE_CMD_QUEUE_DEPTH) { k_spin_unlock(&ble_cmd_lock, key); - DBG_ERR("[BLE RX] drop: command busy\r\n"); + DBG_ERR("[BLE RX] drop: queue full\r\n"); return; } // 명령 버퍼 복사 - memcpy(ble_cmd_buf, data, len); - ble_cmd_len = len; - ble_cmd_pending = true; + memcpy(ble_cmd_q_buf[ble_cmd_q_tail], data, len); + ble_cmd_q_len[ble_cmd_q_tail] = len; + ble_cmd_q_tail = (uint8_t)((ble_cmd_q_tail + 1U) % BLE_CMD_QUEUE_DEPTH); + ble_cmd_q_count++; k_spin_unlock(&ble_cmd_lock, key); - // 명령 처리 work 예약 + // 명령 처리 work 예약 (워커는 큐가 빌 때까지 처리하므로 중복 예약은 무해) + // 실패해도 항목은 큐에 유효하게 남아 있고, 다음 RX의 submit이 함께 처리하므로 롤백하지 않음 int err = k_work_submit_to_queue(&ble_cmd_work_q, &ble_cmd_work); if (err < 0) { - // 예약 실패 시 pending 복구 - key = k_spin_lock(&ble_cmd_lock); - ble_cmd_pending = false; - ble_cmd_len = 0U; - k_spin_unlock(&ble_cmd_lock, key); DBG_ERR("[BLE RX] queue submit fail err=%d\r\n", err); } } @@ -293,6 +297,7 @@ static void power_control_handler(on_off_cont_t device_power_st, const char *rea { if (device_power_st == OFF) { + /* DBG_ERR("[PWR] OFF latch release reason=%s pending=%s device_on=%u btn=%d cnt=%u suspended=%u dfu_adv=%u dfu_confirm=%u dfu_resume=%u\r\n", reason ? reason : "unknown", power_off_pending_reason, @@ -302,7 +307,7 @@ static void power_control_handler(on_off_cont_t device_power_st, const char *rea power_btn_suspended ? 1U : 0U, ble_dfu_advertising_is_enabled() ? 1U : 0U, dfu_confirm_pending_boot ? 1U : 0U, - dfu_reset_resume_request ? 1U : 0U); + dfu_reset_resume_request ? 1U : 0U);*/ gpio_pin_set_dt(&power_hold, 0); // P0.08 LOW → 전원 래치 해제 → 전원 차단 } else @@ -331,10 +336,12 @@ static void load_default_config(void) { serial_len = SERIAL_NO_LENGTH; } + if (hw_len > HW_NO_LENGTH) { hw_len = HW_NO_LENGTH; } + if (passkey_len > PASSKEY_LENGTH) { passkey_len = PASSKEY_LENGTH; @@ -539,16 +546,14 @@ static void timers_start(void) k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); } -/* DFU 업로드가 멈춘 채(청크 무진행) 링크만 살아있는 경우, 연결을 강제로 끊어 - * SMP 재광고(10분 타임아웃)로 전환한다. 초록 LED 무한 점등/무한 대기 방지. */ +/* DFU 업로드가 멈춘 채(청크 무진행) 링크만 살아있는 경우 강제 disconnect 후 SMP 재광고(10분 타임아웃) 전환 - 초록 LED 무한 점등/무한 대기 방지 */ static void dfu_watchdog_handler(struct k_work *work) { ARG_UNUSED(work); if (ble_is_connected()) { - DBG_PRINTF("[DFU] upload stalled (%ds), forcing disconnect\r\n", - DFU_STALL_TIMEOUT_SEC); + DBG_PRINTF("[DFU] upload stalled (%ds), forcing disconnect\r\n", DFU_STALL_TIMEOUT_SEC); (void)ble_disconnect_active(); } }