BLE RX 단일 슬롯에서 8-depth 링버퍼로 변경
- 연결 직후 초기화 명령이 몰릴 때, 앞 명령 처리 중 도착한 명령이 drop: command busy로 버려지던 문제 해결- 큐가 가득 찰 때만 drop: queue full로 처리
This commit is contained in:
+50
-45
@@ -28,6 +28,7 @@
|
|||||||
LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF);
|
LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF);
|
||||||
|
|
||||||
#define BLE_CMD_MAX_LEN 256
|
#define BLE_CMD_MAX_LEN 256
|
||||||
|
#define BLE_CMD_QUEUE_DEPTH 8 // RX 명령 링버퍼 깊이(버스트 흡수)
|
||||||
#define BLE_CMD_WORKQ_STACK_SZ 8192
|
#define BLE_CMD_WORKQ_STACK_SZ 8192
|
||||||
#define DFU_RESUME_MAGIC 0xD5U
|
#define DFU_RESUME_MAGIC 0xD5U
|
||||||
#define DFU_RESUME_GPREGRET_REG 1U
|
#define DFU_RESUME_GPREGRET_REG 1U
|
||||||
@@ -123,15 +124,20 @@ static struct mgmt_callback smp_cmd_status_callback = {
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* BLE RX 콜백 안에서 무거운 일을 바로 처리하지 않기 위해 별도 work queue를 둠
|
* BLE RX 콜백 안에서 무거운 일을 바로 처리하지 않기 위해 별도 work queue를 둠
|
||||||
* - 명령 하나가 끝날 때까지 다음 명령 drop : 확인 필요
|
* - 연결 직후 초기화 버스트 등 명령이 몰릴 때 대비해 링버퍼(FIFO)로 흡수
|
||||||
|
* - 큐가 가득 차면(BLE_CMD_QUEUE_DEPTH) 그 때만 drop
|
||||||
*/
|
*/
|
||||||
static struct k_work_q ble_cmd_work_q;
|
static struct k_work_q ble_cmd_work_q;
|
||||||
K_THREAD_STACK_DEFINE(ble_cmd_workq_stack, BLE_CMD_WORKQ_STACK_SZ);
|
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_work ble_cmd_work; // BLE 명령 처리 work
|
||||||
static struct k_spinlock ble_cmd_lock; // RX 공유 버퍼 보호
|
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 명령 길이
|
// RX 명령 링버퍼: 들어온 순서대로 쌓고 워커가 순차 처리 (head=꺼낼 위치, tail=넣을 위치)
|
||||||
static bool ble_cmd_pending; // 처리 대기 명령 있음
|
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)
|
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 로컬 복사본
|
// work queue 로컬 복사본
|
||||||
uint8_t local_buf[BLE_CMD_MAX_LEN];
|
uint8_t local_buf[BLE_CMD_MAX_LEN];
|
||||||
uint16_t local_len = 0U;
|
uint16_t local_len;
|
||||||
|
|
||||||
// 공유 RX 명령 슬롯 보호: 현재 구조는 한 번에 한 명령만 보관
|
// 큐가 빌 때까지 head에서 하나씩 꺼내 순차 처리 (dispatch는 락 밖에서)
|
||||||
k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock);
|
for (;;)
|
||||||
if (ble_cmd_pending)
|
|
||||||
{
|
{
|
||||||
local_len = ble_cmd_len;
|
k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock);
|
||||||
memcpy(local_buf, ble_cmd_buf, local_len);
|
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 시작 */
|
/* 시스템 워크큐에서 BLE advertising 시작 */
|
||||||
@@ -220,30 +227,27 @@ static void ble_rx_handler(const uint8_t *data, uint16_t len)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 공유 RX 명령 슬롯 보호: 현재 구조는 한 번에 한 명령만 보관
|
// 공유 RX 큐 보호: tail 슬롯에 명령 적재 (FIFO)
|
||||||
k_spinlock_key_t key = k_spin_lock(&ble_cmd_lock);
|
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);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 명령 버퍼 복사
|
// 명령 버퍼 복사
|
||||||
memcpy(ble_cmd_buf, data, len);
|
memcpy(ble_cmd_q_buf[ble_cmd_q_tail], data, len);
|
||||||
ble_cmd_len = len;
|
ble_cmd_q_len[ble_cmd_q_tail] = len;
|
||||||
ble_cmd_pending = true;
|
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);
|
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);
|
int err = k_work_submit_to_queue(&ble_cmd_work_q, &ble_cmd_work);
|
||||||
if (err < 0)
|
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);
|
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)
|
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",
|
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",
|
reason ? reason : "unknown",
|
||||||
power_off_pending_reason,
|
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,
|
power_btn_suspended ? 1U : 0U,
|
||||||
ble_dfu_advertising_is_enabled() ? 1U : 0U,
|
ble_dfu_advertising_is_enabled() ? 1U : 0U,
|
||||||
dfu_confirm_pending_boot ? 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 → 전원 래치 해제 → 전원 차단
|
gpio_pin_set_dt(&power_hold, 0); // P0.08 LOW → 전원 래치 해제 → 전원 차단
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -331,10 +336,12 @@ static void load_default_config(void)
|
|||||||
{
|
{
|
||||||
serial_len = SERIAL_NO_LENGTH;
|
serial_len = SERIAL_NO_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hw_len > HW_NO_LENGTH)
|
if (hw_len > HW_NO_LENGTH)
|
||||||
{
|
{
|
||||||
hw_len = HW_NO_LENGTH;
|
hw_len = HW_NO_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passkey_len > PASSKEY_LENGTH)
|
if (passkey_len > PASSKEY_LENGTH)
|
||||||
{
|
{
|
||||||
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);
|
k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* DFU 업로드가 멈춘 채(청크 무진행) 링크만 살아있는 경우, 연결을 강제로 끊어
|
/* DFU 업로드가 멈춘 채(청크 무진행) 링크만 살아있는 경우 강제 disconnect 후 SMP 재광고(10분 타임아웃) 전환 - 초록 LED 무한 점등/무한 대기 방지 */
|
||||||
* SMP 재광고(10분 타임아웃)로 전환한다. 초록 LED 무한 점등/무한 대기 방지. */
|
|
||||||
static void dfu_watchdog_handler(struct k_work *work)
|
static void dfu_watchdog_handler(struct k_work *work)
|
||||||
{
|
{
|
||||||
ARG_UNUSED(work);
|
ARG_UNUSED(work);
|
||||||
|
|
||||||
if (ble_is_connected())
|
if (ble_is_connected())
|
||||||
{
|
{
|
||||||
DBG_PRINTF("[DFU] upload stalled (%ds), forcing disconnect\r\n",
|
DBG_PRINTF("[DFU] upload stalled (%ds), forcing disconnect\r\n", DFU_STALL_TIMEOUT_SEC);
|
||||||
DFU_STALL_TIMEOUT_SEC);
|
|
||||||
(void)ble_disconnect_active();
|
(void)ble_disconnect_active();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user