BLE RX 단일 슬롯에서 8-depth 링버퍼로 변경
- 연결 직후 초기화 명령이 몰릴 때, 앞 명령 처리 중 도착한 명령이 drop: command busy로 버려지던 문제 해결- 큐가 가득 찰 때만 drop: queue full로 처리
This commit is contained in:
+40
-35
@@ -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");
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 일반 스레드 문맥 명령 처리
|
||||
//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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user