From a83c9d11fa829433d8b08f9fc21bd82bee9a140f Mon Sep 17 00:00:00 2001 From: jhchun Date: Tue, 21 Jul 2026 12:19:43 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A0=84=EC=9B=90=20=EB=AA=A8=EB=93=88=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.c | 333 ++-------------------------- src/power/power_control.c | 381 ++++++++++++++++++++++++++++++++ src/{ => power}/power_control.h | 9 + src/power_control.c | 83 ------- 4 files changed, 404 insertions(+), 402 deletions(-) create mode 100644 src/power/power_control.c rename src/{ => power}/power_control.h (66%) delete mode 100644 src/power_control.c diff --git a/src/main.c b/src/main.c index b3a26fd..157844c 100644 --- a/src/main.c +++ b/src/main.c @@ -4,16 +4,10 @@ ******************************************************************************/ #include -#include #include -#include #include #include #include -#if IS_ENABLED(CONFIG_BT_SMP) -#include -#include -#endif #include "main.h" #include "debug_print.h" @@ -44,23 +38,6 @@ LOG_MODULE_REGISTER(vesiscan, LOG_LEVEL_INF); */ #define BLE_CMD_WORKQ_PRIORITY 10 -/* Devicetree GPIO Settings */ -#define POWER_HOLD_NODE DT_NODELABEL(pwr_hold) // 전원 래치 -#define POWER_BTN_NODE DT_NODELABEL(button_check) // 전원 버튼 - -/* 전원 버튼 상태머신 (5ms 폴링) */ -#define BOOT_THRESHOLD 350 // 5ms x 400 = 2초 -> 초기화 시간 고려 체감상 2초에 맞춤 -#define BOND_RESET_THRESHOLD (15000 / POWER_ON_DELAY) // 전원 ON 상태에서 15초 롱프레스 → 본드 삭제 - -/* 전원 제어 GPIO */ -static const struct gpio_dt_spec power_hold = GPIO_DT_SPEC_GET(POWER_HOLD_NODE, gpios); -static const struct gpio_dt_spec power_btn = GPIO_DT_SPEC_GET(POWER_BTN_NODE, gpios); - -/* Timer */ -static struct k_timer m_power_on_delay_timer; // 전원 버튼 폴링용 (5ms 싱글샷) -static struct k_timer m_power_off_delay_timer; // 전원 OFF 지연용 (3초 후 전원 차단) - -/* 전역 변수 */ volatile bool ble_connection_st = false; // BLE 연결 상태 volatile bool processing = false; // 센서 데이터 처리 중 플래그 bool bond_data_delete = true; // 본딩 데이터 삭제 요청 @@ -71,25 +48,11 @@ 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 power_btn_suspended; // 측정 중 전원 버튼 상태머신 일시 정지 - -/* - * BLE advertising 제어용 워크 아이템 - * - main_s()에서 k_work_submit()으로 예약하여 사용 - */ static bool resume_without_power_button; // 리셋 후 버튼 없이 복귀 static bool dfu_confirm_pending_boot; // DFU test 이미지 확인 전 자동 복귀 static bool dfu_reset_resume_request; // DFU 완료 리셋 후 자동 복귀 static uint32_t boot_reset_reason; // RESETREAS 원본 값 -static struct k_work adv_start_work; // advertising 시작 work -static struct k_work adv_stop_work; // advertising 중지 work -static struct k_work bond_reset_work; // 전원 버튼 15초 롱프레스 본드 삭제 work 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); @@ -175,50 +138,6 @@ static void ble_cmd_work_handler(struct k_work *work) } } -/* 시스템 워크큐에서 BLE advertising 시작 */ -static void adv_start_work_handler(struct k_work *work) -{ - ARG_UNUSED(work); - ble_advertising_start(); -} - -/* 시스템 워크큐에서 BLE advertising 중지 */ -static void adv_stop_work_handler(struct k_work *work) -{ - ARG_UNUSED(work); - ble_advertising_stop(); -} - -/* 전원 버튼 15초 롱프레스: BLE 본드 삭제 후 리부트 */ -static void bond_reset_work_handler(struct k_work *work) -{ - ARG_UNUSED(work); - - DBG_ERR("[BTN] 15s long press -> BLE bond reset\r\n"); - battery_timer_stop(); - ble_advertising_stop(); - -#if IS_ENABLED(CONFIG_BT_SMP) - int err = bt_unpair(BT_ID_DEFAULT, NULL); - if (err) - { - DBG_ERR("[BTN] bt_unpair failed err=%d\r\n", err); - } - else - { - bond_data_delete = true; - DBG_PRINTF("[BTN] BLE bond data deleted\r\n"); - } -#else - bond_data_delete = true; - DBG_PRINTF("[BTN] BLE bond delete skipped (BT_SMP disabled)\r\n"); -#endif - - led_set_state(LED_STATE_BOND_DELETE); // 삭제 완료 확인 주황 LED ON - k_msleep(1500); - sys_reboot(SYS_REBOOT_COLD); -} - /* BLE RX 콜백 */ static void ble_rx_handler(const uint8_t *data, uint16_t len) { @@ -280,52 +199,6 @@ static void boot_context_detect(void) } } -static void power_hold_init(void) -{ -#if defined(CONFIG_BOOTLOADER_MCUBOOT) - // DFU 이미지 확인 전 전원 유지 - dfu_confirm_pending_boot = !boot_is_img_confirmed(); -#else - dfu_confirm_pending_boot = false; -#endif - - // 리셋 복귀/DFU 확인 대기 시 즉시 래치 - gpio_pin_configure_dt(&power_hold, (resume_without_power_button || dfu_confirm_pending_boot || dfu_reset_resume_request) ? GPIO_OUTPUT_ACTIVE : GPIO_OUTPUT_INACTIVE); -} - -/* 전원 ON/OFF 제어 - P0.08 핀으로 물리적 전원 래치/해제 */ -static void power_control_handler(on_off_cont_t device_power_st, const char *reason) -{ - 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, - device_on ? 1U : 0U, - gpio_pin_get_dt(&power_btn), - cnt_s, - power_btn_suspended ? 1U : 0U, - ble_dfu_advertising_is_enabled() ? 1U : 0U, - dfu_confirm_pending_boot ? 1U : 0U, - dfu_reset_resume_request ? 1U : 0U);*/ - gpio_pin_set_dt(&power_hold, 0); // P0.08 LOW → 전원 래치 해제 → 전원 차단 - } - else - { - gpio_pin_set_dt(&power_hold, 1); // P0.08 HIGH → 전원 유지 - } -} - -/* GPIO 초기화 */ -static void gpio_init(void) -{ - gpio_pin_configure_dt(&power_btn, GPIO_INPUT); // 전원 버튼(P1.08) 입력 설정 - DBG_PRINTF("[INIT] HW - GPIO OK (POWER BTN=%d)\r\n", gpio_pin_get_dt(&power_btn)); - -} - -/* 기본 설정값 로드 */ static void load_default_config(void) { // 기본 문자열 길이 제한 @@ -369,160 +242,9 @@ static void load_default_config(void) DBG_CORE("[INIT] Default (S/N=%s)\r\n", SERIAL_NO); } -/* 전원 OFF 타임아웃 콜백 */ -static void t_power_off_timeout_handler(struct k_timer *timer) -{ - ARG_UNUSED(timer); - DBG_ERR("[PWR] OFF timeout reason=%s\r\n", power_off_pending_reason); - led_set_state(LED_STATE_OFF); - power_control_handler(OFF, "off-timeout"); -} - -/* 슬립 모드 / 전원 OFF: LED 표시 후 3초 뒤 전원 차단 */ -static void power_off_schedule(const char *reason, led_state_t led_state) -{ - power_off_pending_reason = reason ? reason : "unknown"; - //DBG_ERR("[PWR] OFF scheduled reason = %s\r\n", power_off_pending_reason); - led_set_state(led_state); - k_timer_start(&m_power_off_delay_timer, K_MSEC(POWER_OFF_DELAY), K_NO_WAIT); -} - -void sleep_mode_enter_reason(const char *reason) -{ - power_off_schedule(reason, LED_STATE_POWER_ON); -} - -void sleep_mode_enter(void) -{ - sleep_mode_enter_reason("sleep_mode_enter"); -} - -void device_power_off(void) -{ - device_power_off_reason("device_power_off"); -} - -void device_power_off_reason(const char *reason) -{ - power_off_schedule(reason, LED_STATE_POWER_OFF); -} - -void device_power_keep_on(void) -{ - k_timer_stop(&m_power_off_delay_timer); - device_on = true; - boot_btn_released = (gpio_pin_get_dt(&power_btn) != 1); - cnt_s = 0; - power_control_handler(ON, "keep-on"); -} - -void power_button_suspend(bool suspend) -{ - // 측정 시간이 긴 커맨드 처리 중에만 버튼 폴링 판단 잠시 멈춤 - power_btn_suspended = suspend; - cnt_s = 0; -} - -static void main_s(struct k_timer *timer) -{ - ARG_UNUSED(timer); - - bool button_pressed = (gpio_pin_get_dt(&power_btn) == 1); - - if (power_btn_suspended) - { - k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); - return; - } - - // 부팅 시퀀스 (OFF → ON) - if (!device_on) - { - if (!button_pressed) // 버튼 놓음 → 2초 미만이면 전원 OFF - { - //DBG_PRINTF("[BTN] Short press (%d) -> OFF\r\n", cnt_s); - power_control_handler(OFF, "boot-button-released-before-latch"); - cnt_s = 0; - } - else // 버튼 계속 누르고 있음 - { - cnt_s++; - - if (cnt_s == BOOT_THRESHOLD) // 2초 도달: 래치 + 부팅 완료 - { - device_on = true; - // cnt_s는 리셋하지 않음: 부팅 누름을 놓기 전(!boot_btn_released)까지 15초 본드 삭제 카운트를 연속 유지(놓는 순간 아래 분기에서 0으로 리셋) - power_control_handler(ON, "button-2s-latch"); - led_set_state(LED_STATE_ADVERTISING); - k_work_submit(&adv_start_work); - battery_timer_start(); - m_reset_status = 1; - } - } - } - /* 전원 OFF 시퀀스 (ON → OFF) */ - else - { - if (!boot_btn_released) // 부팅 때 누른 버튼을 아직 안 놓음 - { - if (!button_pressed) // 놓음 → 이후부터 새 누름을 전원 OFF로 인식 - { - boot_btn_released = true; - cnt_s = 0; - } - else // 전원 ON부터 계속 유지 중 → 15초 넘으면 본드 삭제 + 리부트 - { - cnt_s++; - - if ((cnt_s >= BOND_RESET_THRESHOLD) && !bond_reset_pending) - { - bond_reset_pending = true; - k_work_submit(&bond_reset_work); - return; - } - } - } - else if (button_pressed) // 켜진 뒤 새로 누름 → 2초 이상이면 자동 전원 OFF - { - cnt_s++; - - if (cnt_s >= BOOT_THRESHOLD) - { - battery_timer_stop(); - k_work_submit(&adv_stop_work); - device_on = false; - boot_btn_released = false; - cnt_s = 0; - sleep_mode_enter_reason("button-long-press"); - return; - } - } - else // 버튼 놓음 → 카운터 리셋 - { - if (cnt_s > 0) - { - DBG_PRINTF("[BTN] Short press (%d) -> ignored\r\n", cnt_s); - } - cnt_s = 0; - } - } - - k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); -} - -/* 타이머 초기화 / 시작 */ +/* 타이머 초기화 */ static void timers_init(void) { - // 전원 상태머신 타이머 - k_timer_init(&m_power_on_delay_timer, main_s, NULL); - k_timer_init(&m_power_off_delay_timer, t_power_off_timeout_handler, NULL); - - // BLE advertising work - k_work_init(&adv_start_work, adv_start_work_handler); - k_work_init(&adv_stop_work, adv_stop_work_handler); - - // 전원 버튼 15초 롱프레스 본드 삭제 work - k_work_init(&bond_reset_work, bond_reset_work_handler); // DFU 업로드 무진행 감시 work k_work_init_delayable(&dfu_watchdog_work, dfu_watchdog_handler); @@ -531,8 +253,6 @@ static void timers_init(void) 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); - // 전원 제어 타이머 - power_timer_init(); // DFU 업로드 상태를 LED에 반영 mgmt_callback_register(&dfu_status_callback); @@ -541,13 +261,7 @@ static void timers_init(void) mgmt_callback_register(&smp_cmd_status_callback); } -/* 전원 버튼 폴링 시작 (5ms 후 main_s 콜백) */ -static void timers_start(void) -{ - k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); -} -/* DFU 업로드가 멈춘 채(청크 무진행) 링크만 살아있는 경우 강제 disconnect 후 SMP 재광고(10분 타임아웃) 전환 - 초록 LED 무한 점등/무한 대기 방지 */ static void dfu_watchdog_handler(struct k_work *work) { ARG_UNUSED(work); @@ -639,29 +353,6 @@ static enum mgmt_cb_return smp_cmd_status_cb(uint32_t event, enum mgmt_cb_return return MGMT_CB_OK; } -static void resume_device_after_soft_reset(void) -{ - // 일반 버튼 부팅이면 skip - if (!resume_without_power_button && !dfu_confirm_pending_boot && !dfu_reset_resume_request) - { - return; - } - - // 리셋 복귀나 DFU test 부팅은 버튼 없이도 ON 상태로 복구 - device_on = true; - cnt_s = 0; - boot_btn_released = (gpio_pin_get_dt(&power_btn) != 1); - m_reset_status = 1; - - // 정상 ON 상태 서비스 재시작 - power_control_handler(ON, "resume-after-reset"); - led_set_state(LED_STATE_ADVERTISING); - battery_timer_start(); - k_work_submit(&adv_start_work); - - DBG_CORE("[BOOT] Resume after resetreas=0x%08x\r\n", boot_reset_reason); -} - static void confirm_running_image(void) { #if defined(CONFIG_BOOTLOADER_MCUBOOT) @@ -746,12 +437,13 @@ int main(void) boot_context_detect(); // 하드웨어 기본 초기화 - power_hold_init(); - cnt_s = 0; - - // 버튼 부팅 기본 상태 - device_on = false; - boot_btn_released = false; +#if defined(CONFIG_BOOTLOADER_MCUBOOT) + dfu_confirm_pending_boot = !boot_is_img_confirmed(); +#else + dfu_confirm_pending_boot = false; +#endif + power_control_latch_init(resume_without_power_button || dfu_confirm_pending_boot || dfu_reset_resume_request); + power_control_reset_state(); confirm_running_image(); DBG_CORE("\r\n========================================\r\n"); @@ -761,7 +453,7 @@ int main(void) DBG_CORE("[INIT] HW Init\r\n"); // 기본 하드웨어/센서 초기화 - gpio_init(); + power_control_init(); timers_init(); log_mcuboot_state(); load_default_config(); @@ -778,7 +470,10 @@ int main(void) { DBG_CORE("[INIT] BLE - ble/nus OK\r\n"); // 소프트 리셋 후 서비스 복구 - resume_device_after_soft_reset(); + if (resume_without_power_button || dfu_confirm_pending_boot || dfu_reset_resume_request) + { + power_control_resume_after_reset(boot_reset_reason); + } // BLE 준비까지 확인한 뒤 DFU test 이미지를 확정 confirm_running_image(); } @@ -792,7 +487,7 @@ int main(void) DBG_CORE("========================================\r\n"); // 전원 버튼 상태머신 시작 (부팅 시 버튼이 눌려있는 상태) - timers_start(); + power_control_start(); // 메인 루프 - idle for (;;) diff --git a/src/power/power_control.c b/src/power/power_control.c new file mode 100644 index 0000000..1afbbb8 --- /dev/null +++ b/src/power/power_control.c @@ -0,0 +1,381 @@ +/******************************************************************************* + * @file power_control.c + * @brief Device power sequence control + ******************************************************************************/ +#include +#include +#include +#if IS_ENABLED(CONFIG_BT_SMP) +#include +#include +#endif + +#include "main.h" +#include "power_control.h" +#include "debug_print.h" +#include "led_control.h" +#include "ble_service.h" +#include "battery_adc.h" + +#define POWER_HOLD_NODE DT_NODELABEL(pwr_hold) // 전원 래치 +#define POWER_BTN_NODE DT_NODELABEL(button_check) // 전원 버튼 +#define POWER_LOOP_INTERVAL 20 // 전원 시퀀스 타이머 간격(ms) +#define BOOT_THRESHOLD 350 // power button hold threshold +#define BOND_RESET_THRESHOLD (15000 / POWER_ON_DELAY) // 15s long press bond reset + +static const struct gpio_dt_spec power_hold = GPIO_DT_SPEC_GET(POWER_HOLD_NODE, gpios); // 전원 유지 출력 +static const struct gpio_dt_spec power_btn = GPIO_DT_SPEC_GET(POWER_BTN_NODE, gpios); // 전원 버튼 입력 + +static struct k_timer m_power_on_delay_timer; // 전원 버튼 상태머신 타이머 +static struct k_timer m_power_off_delay_timer; // 전원 OFF 지연 타이머 +static struct k_timer m_power_timer; // 전원 시퀀스 반복 타이머 + +static struct k_work adv_start_work; // advertising 시작 work +static struct k_work adv_stop_work; // advertising 중지 work +static struct k_work bond_reset_work; // 전원 버튼 15초 롱프레스 본드 삭제 work + +static uint16_t cnt_s; // power button hold counter +static bool device_on; // power latch state +static bool boot_btn_released; // 부팅 후 버튼을 놓았는지 여부 +static bool power_btn_suspended; // 측정 중 버튼 상태머신 일시 정지 +static const char *power_off_pending_reason = "none"; // 예약된 전원 OFF 사유 +static bool bond_reset_pending; // 본드 삭제 work 중복 예약 방지 +static uint8_t p_order; // 전원 시퀀스 단계 +static bool lock_check = false; // power sequence lock flag + +/* 시스템 워크에서 BLE advertising 시작 */ +static void adv_start_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + ble_advertising_start(); +} + +/* 시스템 워크에서 BLE advertising 중지 */ +static void adv_stop_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + ble_advertising_stop(); +} + +/* 전원 버튼 15초 롱프레스: BLE 본드 삭제 후 리부팅 */ +static void bond_reset_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + + DBG_ERR("[BTN] 15s long press -> BLE bond reset\r\n"); + battery_timer_stop(); + ble_advertising_stop(); + +#if IS_ENABLED(CONFIG_BT_SMP) + int err = bt_unpair(BT_ID_DEFAULT, NULL); + if (err) + { + DBG_ERR("[BTN] bt_unpair failed err=%d\r\n", err); + } + else + { + bond_data_delete = true; + DBG_PRINTF("[BTN] BLE bond data deleted\r\n"); + } +#else + bond_data_delete = true; + DBG_PRINTF("[BTN] BLE bond delete skipped (BT_SMP disabled)\r\n"); +#endif + + led_set_state(LED_STATE_BOND_DELETE); + k_msleep(1500); + sys_reboot(SYS_REBOOT_COLD); +} + +/* 부팅 직후 전원 래치를 유지할지 결정 */ +void power_control_latch_init(bool keep_on) +{ + gpio_pin_configure_dt(&power_hold, keep_on ? GPIO_OUTPUT_ACTIVE : GPIO_OUTPUT_INACTIVE); +} + +/* 전원 버튼 상태머신 초기값 */ +void power_control_reset_state(void) +{ + cnt_s = 0; + device_on = false; + boot_btn_released = false; + power_btn_suspended = false; + bond_reset_pending = false; + power_off_pending_reason = "none"; +} + +/* POWER_HOLD 핀으로 실제 전원 래치 ON/OFF 제어 */ +static void power_control_handler(on_off_cont_t device_power_st, const char *reason) +{ + ARG_UNUSED(reason); + + if (device_power_st == OFF) + { + gpio_pin_set_dt(&power_hold, 0); + } + else + { + gpio_pin_set_dt(&power_hold, 1); + } +} + +/* 전원 버튼 GPIO 초기화 */ +static void power_gpio_init(void) +{ + gpio_pin_configure_dt(&power_btn, GPIO_INPUT); + DBG_PRINTF("[INIT] HW - GPIO OK (POWER BTN=%d)\r\n", gpio_pin_get_dt(&power_btn)); +} + +/* 전원 OFF 타임아웃 콜백 */ +static void t_power_off_timeout_handler(struct k_timer *timer) +{ + ARG_UNUSED(timer); + DBG_ERR("[PWR] OFF timeout reason=%s\r\n", power_off_pending_reason); + led_set_state(LED_STATE_OFF); + power_control_handler(OFF, "off-timeout"); +} + +/* sleep/전원 OFF: LED 표시 후 지연 시간 뒤 전원 차단 */ +static void power_off_schedule(const char *reason, led_state_t led_state) +{ + power_off_pending_reason = reason ? reason : "unknown"; + led_set_state(led_state); + k_timer_start(&m_power_off_delay_timer, K_MSEC(POWER_OFF_DELAY), K_NO_WAIT); +} + +/* 사유를 포함한 sleep 모드 진입 요청 */ +void sleep_mode_enter_reason(const char *reason) +{ + power_off_schedule(reason, LED_STATE_POWER_ON); +} + +/* 기본 sleep 모드 진입 요청 */ +void sleep_mode_enter(void) +{ + sleep_mode_enter_reason("sleep_mode_enter"); +} + +/* 기본 전원 OFF 요청 */ +void device_power_off(void) +{ + device_power_off_reason("device_power_off"); +} + +/* 사유를 포함한 전원 OFF 요청 */ +void device_power_off_reason(const char *reason) +{ + power_off_schedule(reason, LED_STATE_POWER_OFF); +} + +/* 외부 명령 처리 후 전원 래치 유지 */ +void device_power_keep_on(void) +{ + k_timer_stop(&m_power_off_delay_timer); + device_on = true; + boot_btn_released = (gpio_pin_get_dt(&power_btn) != 1); + cnt_s = 0; + power_control_handler(ON, "keep-on"); +} + +/* 긴 측정 중 전원 버튼 상태머신 일시 정지 */ +void power_button_suspend(bool suspend) +{ + power_btn_suspended = suspend; + cnt_s = 0; +} + +/* 전원 버튼 상태머신 */ +static void main_s(struct k_timer *timer) +{ + ARG_UNUSED(timer); + + // 버튼 입력은 눌림 상태가 1 + bool button_pressed = (gpio_pin_get_dt(&power_btn) == 1); + + // 측정 중에는 버튼 판단을 멈추고 다음 주기에 다시 확인 + if (power_btn_suspended) + { + k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); + return; + } + + // 전원 OFF 상태: 버튼을 충분히 누르면 전원 래치 + if (!device_on) + { + if (!button_pressed) // 2초 미만으로 놓으면 전원 유지 실패 처리 + { + power_control_handler(OFF, "boot-button-released-before-latch"); + cnt_s = 0; + } + else + { + cnt_s++; + + if (cnt_s == BOOT_THRESHOLD) // 임계 시간 도달 시 전원 ON 확정 + { + device_on = true; + power_control_handler(ON, "button-2s-latch"); + led_set_state(LED_STATE_ADVERTISING); + k_work_submit(&adv_start_work); + battery_timer_start(); + m_reset_status = 1; + } + } + } + else + { + // 전원 ON 상태: 부팅 때 누른 버튼을 먼저 놓아야 새 입력으로 봄 + if (!boot_btn_released) + { + if (!button_pressed) // 부팅 때 누른 버튼을 놓으면 이후 새 입력으로 판단 + { + boot_btn_released = true; + cnt_s = 0; + } + else + { + cnt_s++; + + if ((cnt_s >= BOND_RESET_THRESHOLD) && !bond_reset_pending) // 부팅 버튼 15초 유지 시 본드 삭제 + { + bond_reset_pending = true; + k_work_submit(&bond_reset_work); + return; + } + } + } + else if (button_pressed) // ON 상태에서 새로 길게 누르면 전원 OFF + { + cnt_s++; + + if (cnt_s >= BOOT_THRESHOLD) + { + battery_timer_stop(); + k_work_submit(&adv_stop_work); + device_on = false; + boot_btn_released = false; + cnt_s = 0; + sleep_mode_enter_reason("button-long-press"); + return; + } + } + else + { + // 버튼을 놓으면 짧은 입력은 무시하고 카운터를 초기화한다. + if (cnt_s > 0) + { + DBG_PRINTF("[BTN] Short press (%d) -> ignored\r\n", cnt_s); + } + cnt_s = 0; + } + } + + k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); +} + +/* 전원 시퀀스 타이머 만료 콜백 */ +static void power_loop_expiry(struct k_timer *timer) +{ + power_loop(timer); +} + +/* 슬립 진입 전 처리 중 플래그 정리 */ +int device_sleep_mode(void) +{ + k_msleep(2); + DBG_PRINTF("Device_Sleep_Mode OK!\r\n"); + k_msleep(10); + processing = false; + return 0; +} + +/* 최초 전원 활성화 시퀀스 시작 */ +int device_activated(void) +{ + p_order = 0; + lock_check = true; + power_timer_start(); + return 0; +} + +/* 전원 활성화 단계 처리 - 필요 시 다음 타이머 예약 */ +void power_loop(struct k_timer *timer) +{ + power_timer_stop(); + + // 센서 초기화는 각 측정 함수에서 필요 시 수행 + p_order = 2; + + if (p_order < 2) + { + p_order++; + power_timer_start(); + } + else + { + DBG_PRINTF("[PWR] Device Activated OK!\r\n"); + } +} + +/* 소프트 리셋/복귀 후 전원 시퀀스 다시 시작 */ +int device_reactivated(void) +{ + // 필요 시 복귀 전용 초기화 추가 + k_msleep(10); + lock_check = true; + p_order = 0; + power_timer_start(); + return 0; +} + +/* 전원 시퀀스 타이머 1회 예약 */ +void power_timer_start(void) +{ + k_timer_start(&m_power_timer, K_MSEC(POWER_LOOP_INTERVAL), K_NO_WAIT); +} + +/* 예약된 전원 시퀀스 타이머 중지 */ +void power_timer_stop(void) +{ + k_timer_stop(&m_power_timer); +} + +/* 전원 시퀀스 타이머 콜백 등록 */ +void power_timer_init(void) +{ + k_timer_init(&m_power_timer, power_loop_expiry, NULL); +} + +/* 전원 관련 타이머/work 초기화 */ +void power_control_init(void) +{ + power_gpio_init(); + k_timer_init(&m_power_on_delay_timer, main_s, NULL); + k_timer_init(&m_power_off_delay_timer, t_power_off_timeout_handler, NULL); + k_work_init(&adv_start_work, adv_start_work_handler); + k_work_init(&adv_stop_work, adv_stop_work_handler); + k_work_init(&bond_reset_work, bond_reset_work_handler); + power_timer_init(); +} + +/* 전원 버튼 상태머신 시작 */ +void power_control_start(void) +{ + k_timer_start(&m_power_on_delay_timer, K_MSEC(POWER_ON_DELAY), K_NO_WAIT); +} + +/* 소프트 리셋/DFU 리셋 후 버튼 없이 ON 상태 복구 */ +void power_control_resume_after_reset(uint32_t reset_reason) +{ + device_on = true; + cnt_s = 0; + boot_btn_released = (gpio_pin_get_dt(&power_btn) != 1); + m_reset_status = 1; + + power_control_handler(ON, "resume-after-reset"); + led_set_state(LED_STATE_ADVERTISING); + battery_timer_start(); + k_work_submit(&adv_start_work); + + DBG_CORE("[BOOT] Resume after resetreas=0x%08x\r\n", reset_reason); +} \ No newline at end of file diff --git a/src/power_control.h b/src/power/power_control.h similarity index 66% rename from src/power_control.h rename to src/power/power_control.h index 2f95a69..b8cc22d 100644 --- a/src/power_control.h +++ b/src/power/power_control.h @@ -5,8 +5,17 @@ #ifndef POWER_CONTROL_H__ #define POWER_CONTROL_H__ +#include +#include +#include + #include "main.h" +void power_control_latch_init(bool keep_on); +void power_control_reset_state(void); +void power_control_init(void); +void power_control_start(void); +void power_control_resume_after_reset(uint32_t reset_reason); int device_sleep_mode(void); int device_activated(void); int device_reactivated(void); diff --git a/src/power_control.c b/src/power_control.c deleted file mode 100644 index 1303ce3..0000000 --- a/src/power_control.c +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * @file power_control.c - * @brief Device power sequence control - * - * Power-up sequence state machine with k_timer (single-shot 20ms intervals) - ******************************************************************************/ -#include -#include "main.h" -#include "power_control.h" -#include "debug_print.h" - -#define POWER_LOOP_INTERVAL 20 /* ms */ - -static struct k_timer m_power_timer; -static uint8_t p_order; -static bool lock_check = false; - -extern volatile bool processing; - -static void power_loop_expiry(struct k_timer *timer) -{ - power_loop(timer); -} - -int device_sleep_mode(void) -{ - k_msleep(2); - DBG_PRINTF("Device_Sleep_Mode OK!\r\n"); - k_msleep(10); - processing = false; - return 0; -} - -int device_activated(void) -{ - p_order = 0; - lock_check = true; - power_timer_start(); - return 0; -} - -void power_loop(struct k_timer *timer) -{ - power_timer_stop(); - - // Sensor init not needed - imu_read_direct() handles it per measurement - p_order = 2; - - if (p_order < 2) - { - p_order++; - power_timer_start(); - } - else - { - DBG_PRINTF("[PWR] Device Activated OK!\r\n"); - } -} - -int device_reactivated(void) -{ - // sw_i2c_init_once() will be added in Stage 3 - k_msleep(10); - lock_check = true; - p_order = 0; - power_timer_start(); - return 0; -} - -void power_timer_start(void) -{ - k_timer_start(&m_power_timer, K_MSEC(POWER_LOOP_INTERVAL), K_NO_WAIT); -} - -void power_timer_stop(void) -{ - k_timer_stop(&m_power_timer); -} - -void power_timer_init(void) -{ - k_timer_init(&m_power_timer, power_loop_expiry, NULL); -}