diff --git a/src/app_nvs.c b/src/app_nvs.c index 0bb02e1..318514b 100644 --- a/src/app_nvs.c +++ b/src/app_nvs.c @@ -19,11 +19,13 @@ #define APP_NVS_KEY_HW_NO "hw" #define APP_NVS_KEY_SERIAL_NO "serial" #define APP_NVS_KEY_PASSKEY "passkey" +#define APP_NVS_KEY_PASSKEY_CHANGED "passkey_changed" /* 패스키 1회 변경 완료 플래그 */ #define APP_NVS_FULL_KEY_PIEZO "vesiscan/piezo" #define APP_NVS_FULL_KEY_HW_NO "vesiscan/hw" #define APP_NVS_FULL_KEY_SERIAL_NO "vesiscan/serial" #define APP_NVS_FULL_KEY_PASSKEY "vesiscan/passkey" +#define APP_NVS_FULL_KEY_PASSKEY_CHANGED "vesiscan/passkey_changed" /* 값 0은 변경 가능, 값 1은 변경 차단 */ static piezo_config_t *m_piezo_cfg; static app_nvs_piezo_validate_fn m_piezo_validate; @@ -122,6 +124,18 @@ static int app_nvs_settings_set(const char *name, size_t len, return read_exact(read_cb, cb_arg, m_static_passkey, PASSKEY_LENGTH, APP_NVS_KEY_PASSKEY); } + if (settings_name_steq(name, APP_NVS_KEY_PASSKEY_CHANGED, &next) && (next == NULL)) + { + /* 저장된 변경 완료 플래그 복원 */ + if (len != sizeof(m_passkey_changed)) + { + DBG_ERR("[NVS] passkey_changed size mismatch (%u)\r\n", (uint32_t)len); + return -EINVAL; + } + + return read_exact(read_cb, cb_arg, &m_passkey_changed, sizeof(m_passkey_changed), APP_NVS_KEY_PASSKEY_CHANGED); + } + return -ENOENT; } @@ -220,3 +234,19 @@ int app_nvs_save_passkey(const char *passkey) return 0; #endif } + +int app_nvs_save_passkey_changed(uint8_t changed) +{ +#if IS_ENABLED(CONFIG_SETTINGS) + /* 패스키 변경 성공 후 재부팅해도 재변경 차단 */ + int err = settings_save_one(APP_NVS_FULL_KEY_PASSKEY_CHANGED, &changed, sizeof(changed)); + if (err) + { + DBG_ERR("[NVS] passkey_changed save failed err=%d\r\n", err); + } + return err; +#else + ARG_UNUSED(changed); + return 0; +#endif +} diff --git a/src/app_nvs.h b/src/app_nvs.h index e22267e..c8b43dc 100644 --- a/src/app_nvs.h +++ b/src/app_nvs.h @@ -20,5 +20,6 @@ int app_nvs_save_piezo(const piezo_config_t *cfg); int app_nvs_save_hw_no(const char *hw_no); int app_nvs_save_serial_no(const char *serial_no); int app_nvs_save_passkey(const char *passkey); +int app_nvs_save_passkey_changed(uint8_t changed); #endif /* APP_NVS_H__ */ diff --git a/src/main.c b/src/main.c index 6cdc90f..75f6c63 100644 --- a/src/main.c +++ b/src/main.c @@ -67,10 +67,11 @@ uint8_t m_reset_status = 1; /* 리셋 상태 코드 */ char SERIAL_NO[SERIAL_NO_BUF_SIZE]; /* 시리얼 번호 */ char HW_NO[HW_NO_BUF_SIZE]; /* 하드웨어 번호 */ char m_static_passkey[PASSKEY_BUF_SIZE]; /* BLE 정적 패스키 */ +uint8_t m_passkey_changed; /* 패스키 변경은 출고 후 1회만 허용 */ static uint16_t cnt_s; /* 전원 버튼 폴링 카운터 (5ms 단위) */ static bool device_on = false; /* 디바이스 전원 상태 (래치 완료 여부) */ -static bool boot_btn_released = false; /* 부팅 후 버튼 놓았는지 여부 */ +static bool boot_btn_released = false; /* 부팅 후 버튼 놓았는지 여부 */ static bool power_btn_suspended; /* 측정 중 전원 버튼 상태머신 일시 정지 */ /* @@ -310,6 +311,9 @@ static void load_default_config(void) memset(m_static_passkey, 0, sizeof(m_static_passkey)); memcpy(m_static_passkey, DEFAULT_PASSKEY, passkey_len); + /* NVS 로드 전 기본값은 변경 가능 상태 */ + m_passkey_changed = 0U; + /* 기본 상태값 */ m_reset_status = 1; bond_data_delete = true; diff --git a/src/main.h b/src/main.h index 559ccfb..5c9de4e 100644 --- a/src/main.h +++ b/src/main.h @@ -74,6 +74,7 @@ extern volatile bool processing; extern char SERIAL_NO[SERIAL_NO_BUF_SIZE]; extern char HW_NO[HW_NO_BUF_SIZE]; extern char m_static_passkey[PASSKEY_BUF_SIZE]; +extern uint8_t m_passkey_changed; extern bool bond_data_delete; extern uint32_t m_life_cycle; extern uint8_t m_reset_status; diff --git a/src/parser.c b/src/parser.c index 7598aeb..f53113e 100644 --- a/src/parser.c +++ b/src/parser.c @@ -9,6 +9,11 @@ ******************************************************************************/ #include #include +#include +#if IS_ENABLED(CONFIG_BT_SMP) +#include +#include +#endif #include #include @@ -131,6 +136,12 @@ int piezo_config_init(void) return 0; } +static void reboot_after_response(void) +{ + k_msleep(100); + sys_reboot(SYS_REBOOT_COLD); +} + /*============================================================================== * CRC16 (CRC-CCITT, Nordic SDK 호환) *============================================================================*/ @@ -697,6 +708,77 @@ static int cmd_msn(const uint8_t *data, uint8_t data_len) return 1; } +static int cmd_msq(const uint8_t *data, uint8_t data_len) +{ + ARG_UNUSED(data); + ARG_UNUSED(data_len); + + int err = send_response_u16("rsq:", 0x0000); + if (err) + { + DBG_ERR("[CMD] msq tx failed err=%d\r\n", err); + } + + DBG_PRINTF("[CMD] msq -> power off\r\n"); + sleep_mode_enter(); + return 1; +} + +static int cmd_mss(const uint8_t *data, uint8_t data_len) +{ + ARG_UNUSED(data); + ARG_UNUSED(data_len); + + int err = send_response_u16("rss:", 0x0000); + if (err) + { + DBG_ERR("[CMD] mss tx failed err=%d\r\n", err); + } + + DBG_PRINTF("[CMD] mss -> reboot\r\n"); + reboot_after_response(); + return 1; +} + +static int cmd_msr(const uint8_t *data, uint8_t data_len) +{ + uint16_t status = 0x0000; + + ARG_UNUSED(data); + ARG_UNUSED(data_len); + +#if IS_ENABLED(CONFIG_BT_SMP) + int err = bt_unpair(BT_ID_DEFAULT, NULL); + if (err) + { + status = (uint16_t)(-err); + DBG_ERR("[CMD] msr bt_unpair failed err=%d\r\n", err); + } + else + { + bond_data_delete = true; + DBG_PRINTF("[CMD] msr bond data deleted\r\n"); + } +#else + bond_data_delete = true; + DBG_PRINTF("[CMD] msr bond delete skipped (BT_SMP disabled)\r\n"); +#endif + + int tx_err = send_response_u16("rsr:", status); + if (tx_err) + { + DBG_ERR("[CMD] msr tx failed err=%d\r\n", tx_err); + } + + if (status == 0x0000) + { + DBG_PRINTF("[CMD] msr -> reboot\r\n"); + reboot_after_response(); + } + + return 1; +} + /* msp? → IMU 1회 측정 → rsp: + accel XYZ + gyro XYZ (각 int16 빅엔디안) */ static int cmd_msp(const uint8_t *data, uint8_t data_len) { @@ -1328,15 +1410,38 @@ static int cmd_mpz(const uint8_t *data, uint8_t data_len) return 1; } - memset(m_static_passkey, 0, sizeof(m_static_passkey)); - memcpy(m_static_passkey, data, PASSKEY_LENGTH); - int err = app_nvs_save_passkey(m_static_passkey); + if (m_passkey_changed != 0U) + { + /* 패스키가 변경된 경우 다시 바꿀 수 없음(FFFF 반환) */ + send_response_u16("rpz:", 0xFFFF); + DBG_PRINTF("[CMD] mpz: passkey already changed\r\n"); + return 1; + } + + /* NVS 저장이 모두 성공한 뒤 RAM 값 확정 */ + char new_passkey[PASSKEY_BUF_SIZE]; + memset(new_passkey, 0, sizeof(new_passkey)); + memcpy(new_passkey, data, PASSKEY_LENGTH); + + int err = app_nvs_save_passkey(new_passkey); if (err) { send_response_u16("rpz:", 0xFFFD); return 1; } + /* 변경 완료 플래그 세트 : 다음 mpz? 명령 차단 */ + err = app_nvs_save_passkey_changed(1U); + if (err) + { + send_response_u16("rpz:", 0xFFFD); + return 1; + } + + memset(m_static_passkey, 0, sizeof(m_static_passkey)); + memcpy(m_static_passkey, new_passkey, PASSKEY_LENGTH); + m_passkey_changed = 1U; + send_response_ascii("rpz:", m_static_passkey, PASSKEY_LENGTH); DBG_PRINTF("[CMD] mpz updated\r\n"); return 1; @@ -1396,6 +1501,9 @@ typedef struct static const cmd_entry_t cmd_table[] = { + { "msq?", cmd_msq }, + { "mss?", cmd_mss }, + { "msr?", cmd_msr }, { "msn?", cmd_msn }, { "mls?", cmd_mls }, { "msp?", cmd_msp },