Compare commits

..

9 Commits

Author SHA1 Message Date
jh.chun 9f252c7bef BLE 연결 해제 헬퍼 함수 및 에러별 분기 처리 2026-04-21 16:54:51 +09:00
jh.chun be1ca58bd6 버전 업데이트 2026-04-21 16:52:21 +09:00
jh.chun e20e8f5665 전원 버튼 타이머 조건 변경 2026-04-21 16:51:54 +09:00
jh.chun 2bff259fa3 코드 정리 2026-04-21 14:59:47 +09:00
jh.chun c72349cf13 NUS characteristic: MITM 인증 완료된 연결만 접근 가능하도록 수정
- SEC_OPEN -> SEC_MITM
- 기존에는 SoftDevice 레벨에서 인증 전 write를 차단하지 않음
2026-04-21 14:08:57 +09:00
jh.chun a0aa180ef1 DFU characteristic: MITM 인증 완료된 연결만 접근 가능하도록 수정
- SEC_OPEN -> SEC_MITM
- 기존에는 페어링 완료 전에도 DFU characteristic write 가능, BLE SMP 타임아웃(30초) 전에 wirte하면 부트로더로 재부팅되어 인증 없이 DFU 모드 진입 가능했음
2026-04-21 14:08:02 +09:00
jh.chun e9eb89f203 DFU 진입 시 주변 장치 및 타이머 정리 추가
- PREPARE 이벤트 시 타이머(메인, 배터리/온도) 중지 및 비동기 측정 중단 및 상태 리셋, Piezo 전원 차단
- 정리하지 않는 경우 Piezo TX 비정상 신호 출력/Flash 데이터 깨질 가능성 존재
2026-04-21 10:51:02 +09:00
jh.chun 790e3a1b82 미사용 변수 삭제 2026-04-21 09:56:24 +09:00
jh.chun 50a8e68cf4 BLE 인증 전 NUS 명령 실행 방지
- GAP 연결 시 PROD 모드에서 ble_connection_st 조기 활성화 제거(보안 인증 후 활성화)
- nus_data_handler()에 인증 상태 검증 가드 추가(ble_connection_st가 0인 경우 받지 않고 즉시 리턴)
2026-04-21 09:41:12 +09:00
5 changed files with 73 additions and 31 deletions
@@ -216,9 +216,9 @@ uint32_t ble_dfu_buttonless_char_add(ble_dfu_buttonless_t * p_dfu)
add_char_params.is_var_len = true; add_char_params.is_var_len = true;
add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT; add_char_params.max_len = BLE_GATT_ATT_MTU_DEFAULT;
add_char_params.cccd_write_access = SEC_OPEN; add_char_params.cccd_write_access = SEC_MITM;
add_char_params.write_access = SEC_OPEN; add_char_params.write_access = SEC_MITM;
add_char_params.read_access = SEC_OPEN; add_char_params.read_access = SEC_MITM;
return characteristic_add(p_dfu->service_handle, &add_char_params, &p_dfu->control_point_char); return characteristic_add(p_dfu->service_handle, &add_char_params, &p_dfu->control_point_char);
} }
@@ -283,8 +283,8 @@ uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
add_char_params.char_props.write = 1; add_char_params.char_props.write = 1;
add_char_params.char_props.write_wo_resp = 1; add_char_params.char_props.write_wo_resp = 1;
add_char_params.read_access = SEC_OPEN; add_char_params.read_access = SEC_MITM;
add_char_params.write_access = SEC_OPEN; add_char_params.write_access = SEC_MITM;
err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles); err_code = characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->rx_handles);
if (err_code != NRF_SUCCESS) if (err_code != NRF_SUCCESS)
@@ -302,9 +302,9 @@ uint32_t ble_nus_init(ble_nus_t * p_nus, ble_nus_init_t const * p_nus_init)
add_char_params.is_var_len = true; add_char_params.is_var_len = true;
add_char_params.char_props.notify = 1; add_char_params.char_props.notify = 1;
add_char_params.read_access = SEC_OPEN; add_char_params.read_access = SEC_MITM;
add_char_params.write_access = SEC_OPEN; add_char_params.write_access = SEC_MITM;
add_char_params.cccd_write_access = SEC_OPEN; add_char_params.cccd_write_access = SEC_MITM;
return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles); return characteristic_add(p_nus->service_handle, &add_char_params, &p_nus->tx_handles);
/**@snippet [Adding proprietary characteristic to the SoftDevice] */ /**@snippet [Adding proprietary characteristic to the SoftDevice] */
@@ -115,8 +115,6 @@
#include "dr_piezo.h" /* Piezo ultrasound driver */ #include "dr_piezo.h" /* Piezo ultrasound driver */
#include "led_control.h" /* LED direct control driver */ #include "led_control.h" /* LED direct control driver */
/*============================================================================== /*==============================================================================
* Build Configuration * Build Configuration
*============================================================================*/ *============================================================================*/
@@ -157,7 +155,6 @@
#define POWER_ON_DELAY 5 /* Power button polling interval (5ms) */ #define POWER_ON_DELAY 5 /* Power button polling interval (5ms) */
#define POWER_OFF_DELAY 3000 /* Power-off delay: 3s after LED indication */ #define POWER_OFF_DELAY 3000 /* Power-off delay: 3s after LED indication */
#define POWER_RESET_DELAY 2000 /* Reset delay: 2s */ #define POWER_RESET_DELAY 2000 /* Reset delay: 2s */
#define LED_NUM 24 /* LED pin number */
/*============================================================================== /*==============================================================================
* BLE Instances (statically allocated via SoftDevice macros) * BLE Instances (statically allocated via SoftDevice macros)
@@ -193,14 +190,11 @@ static uint8_t c_addr[6] = {0}; /* Connected peer BLE a
static char * roles_str[] = {"INVALID_ROLE", "CENTRAL", "PERIPHERAL"}; static char * roles_str[] = {"INVALID_ROLE", "CENTRAL", "PERIPHERAL"};
/*==============================================================================
* Global Variables
* IEC 62304 §5.5.3: all global buffers zero-initialized for deterministic startup
*============================================================================*/
volatile uint8_t Sj_type; /* Command type identifier */
bool power_off_duble_prohibit = false; /* Power-off double prevention flag */ bool power_off_duble_prohibit = false; /* Power-off double prevention flag */
volatile bool power_state = false; /* Power state tracking */
/*==============================================================================
* Extern Variables and Functions
*============================================================================*/
/* -- External module flags (defined in main_timer/power_control) -- */ /* -- External module flags (defined in main_timer/power_control) -- */
extern bool go_device_power_off; /* Power-off request flag */ extern bool go_device_power_off; /* Power-off request flag */
extern bool go_sleep_mode_enter; /* Sleep mode entry request flag */ extern bool go_sleep_mode_enter; /* Sleep mode entry request flag */
@@ -212,6 +206,14 @@ extern bool info4; /* Device info transmission complete flag
extern uint8_t add_cycle; /* Additional measurement cycle counter */ extern uint8_t add_cycle; /* Additional measurement cycle counter */
extern bool motion_raw_data_enabled; /* Motion raw data streaming enabled */ extern bool motion_raw_data_enabled; /* Motion raw data streaming enabled */
/* -- External module functions (used in DFU prepare / disconnect cleanup) -- */
extern void maa_async_abort(void);
extern bool maa_async_on_tx_ready(void);
extern bool maa_async_is_busy(void);
extern void dr_piezo_power_off(void);
extern void battery_timer_stop(void);
extern void main_timer_stop(void);
uint16_t cnt_s; /* Power button polling counter (5ms units, 150=0.75s) */ uint16_t cnt_s; /* Power button polling counter (5ms units, 150=0.75s) */
char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN] = {0}; /* BLE text transmission buffer */ char ble_tx_buffer[BLE_NUS_MAX_DATA_LEN] = {0}; /* BLE text transmission buffer */
uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] = {0}; /* BLE binary response buffer */ uint8_t ble_bin_buffer[BLE_NUS_MAX_DATA_LEN] = {0}; /* BLE binary response buffer */
@@ -485,6 +487,10 @@ static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
{ {
case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE: case BLE_DFU_EVT_BOOTLOADER_ENTER_PREPARE:
DBG_PRINTF("[DFU] Prepare\r\n"); DBG_PRINTF("[DFU] Prepare\r\n");
maa_async_abort();
dr_piezo_power_off();
battery_timer_stop();
main_timer_stop();
break; break;
case BLE_DFU_EVT_BOOTLOADER_ENTER: case BLE_DFU_EVT_BOOTLOADER_ENTER:
DBG_PRINTF("[DFU] Enter\r\n"); DBG_PRINTF("[DFU] Enter\r\n");
@@ -494,7 +500,6 @@ static void ble_dfu_evt_handler(ble_dfu_buttonless_evt_type_t event)
break; break;
case BLE_DFU_EVT_RESPONSE_SEND_ERROR: case BLE_DFU_EVT_RESPONSE_SEND_ERROR:
DBG_PRINTF("[DFU] Error\r\n"); DBG_PRINTF("[DFU] Error\r\n");
APP_ERROR_CHECK(false);
break; break;
default: default:
break; break;
@@ -553,10 +558,6 @@ static void nrf_qwr_error_handler(uint32_t nrf_error)
APP_ERROR_HANDLER(nrf_error); APP_ERROR_HANDLER(nrf_error);
} }
/* Async MAA TX complete handler (forward declarations) */
extern bool maa_async_on_tx_ready(void);
extern bool maa_async_is_busy(void);
extern void maa_async_abort(void);
/* 2026-03-17: Prevent blocking in BLE callback -- buffer command for main loop processing */ /* 2026-03-17: Prevent blocking in BLE callback -- buffer command for main loop processing */
static volatile uint8_t pending_cmd_buf[BLE_NUS_MAX_DATA_LEN] = {0}; static volatile uint8_t pending_cmd_buf[BLE_NUS_MAX_DATA_LEN] = {0};
@@ -573,6 +574,11 @@ static void nus_data_handler(ble_nus_evt_t * p_evt)
{ {
if (p_evt->type == BLE_NUS_EVT_RX_DATA) if (p_evt->type == BLE_NUS_EVT_RX_DATA)
{ {
if (!ble_connection_st)
{
return; /* Reject command before security is established */
}
cmd_type_t = CMD_BLE; cmd_type_t = CMD_BLE;
ble_got_new_data = true; ble_got_new_data = true;
@@ -1048,11 +1054,14 @@ static void ble_evt_handler(ble_evt_t const * p_ble_evt, void * p_context)
break; break;
case BLE_GAP_EVT_CONNECTED: case BLE_GAP_EVT_CONNECTED:
DBG_PRINTF("[BLE] Connected\r\n"); DBG_PRINTF("[BLE] GAP Connected\r\n");
#if FEATURE_SECURE_CONNECTION #if FEATURE_SECURE_CONNECTION
ble_connection_st = 1; if (BLE_DEV_MODE)
battery_timer_start(); {
ble_connection_st = 1;
battery_timer_start();
}
#endif #endif
m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle; m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
@@ -1624,7 +1633,7 @@ static void main_s(void * p_context)
go_device_power_off = true; go_device_power_off = true;
main_timer_start(); main_timer_start();
} }
else if (cnt_s > 250 || (m_reset_status == 2)) /* 250 x 5ms = 1.25s + α */ else if (cnt_s >= 250 || (m_reset_status == 2)) /* 250 x 5ms = 1.25s + α */
{ {
DBG_PRINTF("[BTN] Boot (cnt=%d)\r\n", cnt_s); DBG_PRINTF("[BTN] Boot (cnt=%d)\r\n", cnt_s);
device_reset = false; device_reset = false;
@@ -36,8 +36,9 @@
* : Improved low-battery detection and automatic power-off handling. * : Improved low-battery detection and automatic power-off handling.
* : Updated BLE security, bonding, and advertising timeout behavior. * : Updated BLE security, bonding, and advertising timeout behavior.
* : Cleaned up command parsing and removed unused project files. * : Cleaned up command parsing and removed unused project files.
* - VBTFW0111 260421 jhChun
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
#define FIRMWARE_VERSION "VBTFW0103" #define FIRMWARE_VERSION "VBTFW0111"
/*============================================================================== /*==============================================================================
* Data Length Constants * Data Length Constants
@@ -20,6 +20,22 @@ static struct {
bool bonds_delete_pending; bool bonds_delete_pending;
} m_state = {0}; } m_state = {0};
static const char * sec_error_name(pm_sec_error_code_t error)
{
switch (error) {
case PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING:
return "PIN_OR_KEY_MISSING";
case PM_CONN_SEC_ERROR_MIC_FAILURE:
return "MIC_FAILURE";
case PM_CONN_SEC_ERROR_DISCONNECT:
return "DISCONNECT";
case PM_CONN_SEC_ERROR_SMP_TIMEOUT:
return "SMP_TIMEOUT";
default:
return "UNKNOWN";
}
}
/** /**
* @brief Initialize BLE security * @brief Initialize BLE security
*/ */
@@ -102,8 +118,9 @@ void ble_security_quick_pm_handler(pm_evt_t const *p_evt)
// DEV mode: do not forward security failure events to SDK handler (prevent disconnect) // DEV mode: do not forward security failure events to SDK handler (prevent disconnect)
if (m_state.dev_mode && p_evt->evt_id == PM_EVT_CONN_SEC_FAILED) { if (m_state.dev_mode && p_evt->evt_id == PM_EVT_CONN_SEC_FAILED) {
DBG_PRINTF("Security failed: error=%d\r\n", DBG_PRINTF("Security failed: error=%d (%s)\r\n",
p_evt->params.conn_sec_failed.error); p_evt->params.conn_sec_failed.error,
sec_error_name(p_evt->params.conn_sec_failed.error));
DBG_PRINTF("DEV: Ignoring sec failure, keeping connection\r\n"); DBG_PRINTF("DEV: Ignoring sec failure, keeping connection\r\n");
return; return;
} }
@@ -129,8 +146,9 @@ void ble_security_quick_pm_handler(pm_evt_t const *p_evt)
break; break;
case PM_EVT_CONN_SEC_FAILED: case PM_EVT_CONN_SEC_FAILED:
DBG_PRINTF("Security failed: error=%d\r\n", DBG_PRINTF("Security failed: error=%d (%s)\r\n",
p_evt->params.conn_sec_failed.error); p_evt->params.conn_sec_failed.error,
sec_error_name(p_evt->params.conn_sec_failed.error));
if (m_state.dev_mode) { if (m_state.dev_mode) {
// DEV mode: ignore security failure, keep connection // DEV mode: ignore security failure, keep connection
@@ -138,6 +156,20 @@ void ble_security_quick_pm_handler(pm_evt_t const *p_evt)
break; break;
} }
if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_DISCONNECT) {
// The peer/link already disconnected before security finished.
// There is no live connection to repair; BLE_GAP_EVT_DISCONNECTED
// will restart advertising.
DBG_PRINTF("Security ended by disconnect; waiting for reconnect\r\n");
break;
}
if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_SMP_TIMEOUT) {
// The SDK cannot start another SMP procedure on this link.
pm_handler_disconnect_on_sec_failure(p_evt);
break;
}
if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING) { if (p_evt->params.conn_sec_failed.error == PM_CONN_SEC_ERROR_PIN_OR_KEY_MISSING) {
// Key missing: attempt re-pairing, fall back to disconnect on failure // Key missing: attempt re-pairing, fall back to disconnect on failure
err_code = pm_conn_secure(p_evt->conn_handle, true); err_code = pm_conn_secure(p_evt->conn_handle, true);