Compare commits

...

3 Commits

Author SHA1 Message Date
jh.chun 281aa36f32 DFU 진행 watchdog
- 앱만 멈추고 BLE 링크가 유지되는 경우 대비
- DFU 업로드 중 30초동안 CHUNK가 오지 않는 경우 강제 disconnect 후 SMP로 재광고(초록 LED 점멸, 10분 타임아웃)
- 초록 LED 무한 점등 상황 방지
2026-07-14 16:10:45 +09:00
jh.chun 7fb01e3968 DFU(SMP) 전환 시 10분 타임아웃 추가
- SMP UUID로 광고 시 일반 NUS 스캔이 불가능
- DFU가 시작되지 못한 채 방치되는 경우 대비
2026-07-14 14:44:15 +09:00
jh.chun e39b0c1810 BLE 명령으로 본딩 정보 삭제 및 재부팅 시 본딩 정보 삭제 후 주황 LED ON 추가
- 전원 버튼 롱프레스를 통한 본딩 정보 삭제와 동일한 LED 상태
2026-07-14 14:40:14 +09:00
4 changed files with 55 additions and 16 deletions
+24 -3
View File
@@ -406,7 +406,8 @@ static void adv_timeout_handler(struct k_work *work)
{
ARG_UNUSED(work);
if (!ble_connection_st && !advertising_unlimited && !dfu_advertising_mode)
// 미연결 상태에서만 발동하므로 DFU 광고도 동일하게 10분 후 종료(연결 중이면 발동 안 함)
if (!ble_connection_st && !advertising_unlimited)
{
DBG_PRINTF("[BLE] Advertising timeout\r\n");
(void)ble_advertising_stop();
@@ -558,7 +559,15 @@ static void disconnected(struct bt_conn *conn, uint8_t reason)
}
ble_connection_st = false;
advertising_unlimited = ble_disconnect_reason_uses_unlimited_adv(reason);
if (dfu_advertising_mode)
{
// DFU 광고는 미연결 10분 타임아웃 적용
advertising_unlimited = false;
}
else
{
advertising_unlimited = ble_disconnect_reason_uses_unlimited_adv(reason);
}
DBG_CORE("[BLE] Disconnected reason=0x%02x adv=%s\r\n",
reason,
advertising_unlimited ? "unlimited" : "10min");
@@ -747,7 +756,7 @@ int ble_advertising_start(void)
}
k_work_cancel_delayable(&adv_timeout_work);
if (!advertising_unlimited && !dfu_advertising_mode)
if (!advertising_unlimited) // DFU 광고 포함, 미연결 10분 시 전원 OFF
{
k_work_schedule(&adv_timeout_work, K_MSEC(APP_ADV_DURATION * 10));
}
@@ -797,11 +806,23 @@ int ble_dfu_advertising_enable(void)
return ble_advertising_start();
}
/* DFU 진입용 disconnect */
bool ble_dfu_advertising_is_enabled(void)
{
return dfu_advertising_mode;
}
/* DFU watchdog */
int ble_disconnect_active(void)
{
if (current_conn == NULL)
{
return -ENOTCONN;
}
return bt_conn_disconnect(current_conn, BT_HCI_ERR_REMOTE_USER_TERM_CONN);
}
int ble_data_send(const uint8_t *data, uint16_t len)
{
int err;
+1
View File
@@ -34,5 +34,6 @@ int ble_data_send(const uint8_t *data, uint16_t len);
int ble_dfu_advertising_enable(void);
bool ble_dfu_advertising_is_enabled(void);
bool ble_is_connected(void);
int ble_disconnect_active(void);
#endif /* BLE_SERVICE_H__ */
+3
View File
@@ -14,6 +14,7 @@
#include "debug_print.h"
#include "ble_service.h"
#include "cmd_device.h"
#include "led_control.h"
/*
* msq: power off
@@ -81,8 +82,10 @@ int cmd_msr(const uint8_t *data, uint8_t data_len)
}
else
{
led_set_state(LED_STATE_BOND_DELETE); // 삭제 완료 확인 주황 LED ON
bond_data_delete = true;
DBG_PRINTF("[CMD] msr bond data deleted\r\n");
k_msleep(1500);
}
#else
bond_data_delete = true;
+27 -13
View File
@@ -31,6 +31,7 @@ LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF);
#define BLE_CMD_WORKQ_STACK_SZ 8192
#define DFU_RESUME_MAGIC 0xD5U
#define DFU_RESUME_GPREGRET_REG 1U
#define DFU_STALL_TIMEOUT_SEC 30 // DFU 업로드 무진행 시 강제 disconnect 임계
#define IMG_MGMT_ID_STATE 0U
#define IMG_MGMT_ID_UPLOAD 1U
/*
@@ -88,6 +89,8 @@ static struct k_work bond_reset_work; // 전원 버튼 15초 롱프레스
static bool dfu_led_active; // DFU 업로드 중 초록 LED ON
static const char *power_off_pending_reason = "none";
static bool bond_reset_pending; // 본드 삭제 work 중복 예약 방지
static struct k_work_delayable dfu_watchdog_work; // DFU 업로드 무진행 감시 work
static void dfu_watchdog_handler(struct k_work *work);
static enum mgmt_cb_return dfu_status_cb(uint32_t event,
enum mgmt_cb_return prev_status,
@@ -524,6 +527,9 @@ static void timers_init(void)
// 전원 버튼 15초 롱프레스 본드 삭제 work
k_work_init(&bond_reset_work, bond_reset_work_handler);
// DFU 업로드 무진행 감시 work
k_work_init_delayable(&dfu_watchdog_work, dfu_watchdog_handler);
// BLE 명령 처리 work queue
k_work_init(&ble_cmd_work, ble_cmd_work_handler);
k_work_queue_start(&ble_cmd_work_q, ble_cmd_workq_stack, K_THREAD_STACK_SIZEOF(ble_cmd_workq_stack), BLE_CMD_WORKQ_PRIORITY, NULL);
@@ -544,13 +550,21 @@ static void timers_start(void)
k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT);
}
static enum mgmt_cb_return dfu_status_cb(uint32_t event,
enum mgmt_cb_return prev_status,
int32_t *rc,
uint16_t *group,
bool *abort_more,
void *data,
size_t data_size)
/* DFU 업로드가 멈춘 채(청크 무진행) 링크만 살아있는 경우, 연결을 강제로 끊어
* 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);
(void)ble_disconnect_active();
}
}
static enum mgmt_cb_return dfu_status_cb(uint32_t event, enum mgmt_cb_return prev_status, int32_t *rc, uint16_t *group, bool *abort_more, void *data, size_t data_size)
{
ARG_UNUSED(prev_status);
ARG_UNUSED(rc);
@@ -563,19 +577,19 @@ static enum mgmt_cb_return dfu_status_cb(uint32_t event,
{
case MGMT_EVT_OP_IMG_MGMT_DFU_STARTED:
case MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK:
// DFU 업로드 중에는 초록 LED ON
dfu_led_active = true;
led_ble_solid();
led_ble_solid(); // DFU 업로드 중에는 초록 LED ON
// 청크가 올 때마다 무진행 감시 타이머 리셋
k_work_reschedule(&dfu_watchdog_work, K_SECONDS(DFU_STALL_TIMEOUT_SEC));
break;
case MGMT_EVT_OP_IMG_MGMT_DFU_PENDING:
// 업로드 완료 후 리셋 전까지 초록 LED ON
dfu_led_active = true;
led_ble_solid();
led_ble_solid(); // 업로드 완료 후 리셋 전까지 초록 LED ON
k_work_cancel_delayable(&dfu_watchdog_work); // 업로드 완료: 감시 종료
// DFU 리셋 후 버튼 없이 전원 ON
#if NRF_POWER_HAS_GPREGRET
nrf_power_gpregret_set(NRF_POWER, DFU_RESUME_GPREGRET_REG, DFU_RESUME_MAGIC);
nrf_power_gpregret_set(NRF_POWER, DFU_RESUME_GPREGRET_REG, DFU_RESUME_MAGIC); // DFU 리셋 후 버튼 없이 전원 ON
#endif
break;