#include #include "app_event.h" #include "app_event_distribute.h" #include "basic/device_version_info_mgr.h" #include "ble_cmd_process_service.h" #include "board/board_adc_module_ctrl.h" #include "board/board_battery_state.h" #include "board/board_beep_ctrl.h" #include "board/board_ecg_sensor.h" #include "board/board_light_ctrl.h" #include "config.h" #include "display_manager.h" #include "heart_wave_sample_service.h" #include "one_conduction_board.h" #include "sample_data_manager.h" #include "zble_module.h" #include "zdatachannel_service.h" #include "znordic.h" /******************************************************************************* * GLOBAL * *******************************************************************************/ APP_TIMER_DEF(m_state_machine_driver_tmr); // 状态机驱动定时器 // APP_TIMER_DEF(m_plod_state_event_detect_tmr); // 导联连接状态检测定时器 // APP_TIMER_DEF(m_charge_event_detect_tmr); // 充电事件检测 static int m_cur_fd; static sample_data_filename_t sampledata_file_name; #define SCHED_MAX_EVENT_DATA_SIZE MAX(sizeof(app_event_t), APP_TIMER_SCHED_EVENT_DATA_SIZE) /******************************************************************************* * 函数声明 * *******************************************************************************/ // 业务事件处理函数 /******************************************************************************* * 事件生成器 * *******************************************************************************/ // static void m_charge_event_detect_tmr_cb(void* p_context) { // // static app_event_t appevent; // memset(&appevent, 0, sizeof(appevent)); // static bool ischarging = false; // } static void state_machine_driver_tmr_cb(void* p_context) { // static app_event_t appevent; appevent.eventType = kevent_tmr_scheduler_event; AppEvent_pushEvent(&appevent); } /******************************************************************************* * 事件处理 * *******************************************************************************/ static bool m_poweronflag; static void power_on() { if (m_poweronflag) { return; } BoardBeepCtrl_load(); BoardEcgSensor_load(); BoardBattery_load(); hwss_init(); sample_data_mgr_init(); dsp_mgr_init(); ble_cmder_init(); ble_cmder_start_adv(); m_poweronflag = true; } static void power_off() { if (!m_poweronflag) return; dsp_mgr_uninit(); sample_data_mgr_uninit(); hwss_uninit(); BoardEcgSensor_unload(); BoardBattery_unload(); BoardLight_unload(); BoardBeepCtrl_unload(); ble_cmder_stop_adv(); ble_cmder_uninit(); m_poweronflag = false; } /******************************************************************************* * 状态切换方法 * *******************************************************************************/ /** * @brief 切换到充电中状态 */ static void state_machine__change_to_charging_state() { // if (ds_now_state() == kdevice_state_home) { // 已开机 DO Nothing } else if (ds_now_state() == kdevice_state_standby) { power_on(); } else { ZASSERT(false); } // 切换到充电显示页面 dsp_mgr_change_to_chargingPage(); ds_change_to_state(kdevice_state_charging); } /** * @brief 切换到待机状态 */ static void state_machine__change_to_standby_state() { ZLOGI_BLOCK("change to standby"); power_off(); ds_change_to_state(kdevice_state_standby); } /** * @brief 切换到开机中画面 */ static void state_machine__change_to_poweroning_state() { power_on(); dsp_mgr_change_to_welcome(); ds_change_to_state(kdevice_state_poweron); } /** * @brief 切换到首页 */ static void state_machine__change_to_home_state() { ds_change_to_state(kdevice_state_home); dsp_mgr_change_to_main(); } void ENTER_DEEP_SLEEP() { // 进入深度睡眠前,使能唤醒引脚 BoardEcgSensor_set_sence_state(); BoardBattery_sence_gpio_init_before_sleep(); // nrf_sdh_disable_request(); app_timer_stop_all(); // nrf_sdh_disable_request(); sd_power_system_off(); NVIC_SystemReset(); } static void app_event_listener(void* p_event_data, uint16_t event_size) { if (!p_event_data) return; app_event_t* p_event = (app_event_t*)p_event_data; if (ds_now_state() != kdevice_state_standby) { if (zdatachannel_is_connected()) { BoardLight_setGreenLightEffect(kLightEffect_slowFlash); } else { BoardLight_setGreenLightEffect(kLightEffect_quickFlash); } } /******************************************************************************* * 待机状态 * *******************************************************************************/ if (ds_now_state() == kdevice_state_standby) { ZLOGI("standby......"); // 充电事件触发 --> 切换到充电页面 if (BoardBattery_get_charging_state()) { state_machine__change_to_charging_state(); } // 导联连接事件触发 --> 切换到开机中页面 else if (BoardEcgSensor_plod_get_connected_state()) { state_machine__change_to_poweroning_state(); } // 10秒后,如果RTC未被设置过,则进入超低功耗 else if (ds_cur_state_haspassed_ms() >= 2000) { if (!znordic_rtc_has_setted()) { ENTER_DEEP_SLEEP(); } } } /******************************************************************************* * 充电状态 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_charging) { if (!BoardBattery_get_charging_state()) { state_machine__change_to_standby_state(); } } /******************************************************************************* * 开机中 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_poweron) { if (ds_cur_state_haspassed_ms() >= 1500) { state_machine__change_to_home_state(); } } /******************************************************************************* * 首页 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_home) { // 如果用户长时间不操作,自动切换到待机状态 if (!zdatachannel_is_connected() && // !BoardEcgSensor_plod_get_connected_state_after_filter() && // BoardEcgSensor_plod_state_has_disconnected_ms() >= 3000 && // ds_cur_state_haspassed_ms() >= AUTOMATIC_SLEEP_TIME) { state_machine__change_to_standby_state(); } // 如果用户继续保持静止,切换到采集页面 else if (BoardEcgSensor_plod_get_connected_state_after_filter() && ds_cur_state_haspassed_ms() > 1500) { // dsp_mgr_change_to_preparePage ds_change_to_state(kdevice_state_keep_still); dsp_mgr_change_to_preparePage(); } // ZLOGI("bt:%d plod:%d has_disc:%d state:%d", zdatachannel_is_connected(), BoardEcgSensor_plod_get_connected_state_after_filter(), plod_state_has_disconnected_ms(), ds_cur_state_haspassed_ms()); } /******************************************************************************* * 保持静止页面 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_keep_still) { if (!BoardEcgSensor_plod_get_connected_state_after_filter()) { // 如果用户未保持静止,切换到首页 state_machine__change_to_home_state(); } else { /******************************************************************************* * 页面加载中 * *******************************************************************************/ if (ds_cur_state_haspassed_ms() >= (KEEP_STILL_OVERTIME_MS_1P5 * 5)) { /** * @brief * * 1. 启动采样定时器 * 2. 切换状态 * 3. 切换页面 */ ds_change_to_state(kdevice_state_sampling); dsp_mgr_change_to_sampling(0, 0); hwss_start_capture(); static ztm_t tm; memset(&sampledata_file_name, 0, sizeof(sampledata_file_name)); znordic_rtc_gettime(&tm); sample_capture_state_reset(); sampledata_file_name.year = tm.tm_year + 1900 - 2000; sampledata_file_name.month = tm.tm_mon + 1; sampledata_file_name.day = tm.tm_mday; sampledata_file_name.hour = tm.tm_hour; sampledata_file_name.min = tm.tm_min; sampledata_file_name.sec = tm.tm_sec; m_cur_fd = sample_data_mgr_open(&sampledata_file_name, kwrflag_write_only); BoardBeepCtrl_setEffect(kBoardBeepEffect_oneShortBeep); } else if (ds_cur_state_haspassed_ms() >= (KEEP_STILL_OVERTIME_MS_1P5 * 4)) { if (dsp_mgr_preparePage_get_progress() != 4) { dsp_mgr_preparePage_set_progress(4); } } else if (ds_cur_state_haspassed_ms() >= (KEEP_STILL_OVERTIME_MS_1P5 * 3)) { if (dsp_mgr_preparePage_get_progress() != 3) { dsp_mgr_preparePage_set_progress(3); } } else if (ds_cur_state_haspassed_ms() >= (KEEP_STILL_OVERTIME_MS_1P5 * 2)) { if (dsp_mgr_preparePage_get_progress() != 2) { dsp_mgr_preparePage_set_progress(2); } } else if (ds_cur_state_haspassed_ms() >= (KEEP_STILL_OVERTIME_MS_1P5 * 1)) { if (dsp_mgr_preparePage_get_progress() != 1) { dsp_mgr_preparePage_set_progress(1); } } } } /******************************************************************************* * 采样页面逻辑 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_sampling) { /******************************************************************************* * 采样数据存储 * *******************************************************************************/ if (p_event->eventType == kevent_capture_256data_event) { if (hwss_has_captured_time_ms() <= (MAX_STORAGE_TIMEOUT_S * 1000)) { sample_data_mgr_write(m_cur_fd, p_event->val.capture_data_cache, 256); } } /******************************************************************************* * 实时采样数据上报 * *******************************************************************************/ if (p_event->eventType == kevent_capture_little_data_block_event) { // 单帧实时上报 ZASSERT(LITTLE_DATA_BLOCK_FRAME_NUM == 5); ble_cmder_try_report_one_sample_data(p_event->val.little_data_block.frameIndex, // p_event->val.little_data_block.data[0].data, // p_event->val.little_data_block.data[1].data, // p_event->val.little_data_block.data[2].data, // p_event->val.little_data_block.data[3].data, // p_event->val.little_data_block.data[4].data); } /******************************************************************************* * 采样足30秒事件捕获 * *******************************************************************************/ if (hwss_has_captured_time_ms() >= (SAMPLE_MIN_TIME_S * 1000)) { if (!sample_capture_state_get()->is_over30s) { BoardBeepCtrl_setEffect(kBoardBeepEffect_oneShortBeep); sample_capture_state_set_is_over30s(true); } } /******************************************************************************* * 采样结束判定 * *******************************************************************************/ bool capture_end = false; if (hwss_has_captured_time_ms() >= (MAX_STORAGE_TIMEOUT_S * 1000)) { capture_end = true; } else if (p_event->eventType == kplod_disconnected_event) { ble_cmder_try_report_sensor_drop_event(0x01, 0); capture_end = true; } if (capture_end) { if (sample_capture_state_get()->is_over30s) { sample_data_mgr_close(m_cur_fd); dsp_mgr_change_to_sampleSuc(); BoardBeepCtrl_setEffect(kBoardBeepEffect_oneShortBeep); ds_change_to_state(kdevice_state_sampling_complete); hwss_stop_capture(); } else { // 采样不足三十秒 // 停止采样 hwss_stop_capture(); // 关闭文件 sample_data_mgr_close(m_cur_fd); // 删除文件 sample_data_mgr_delete_file(&sampledata_file_name); // 切换到采集出错页面 dsp_mgr_change_to_samplingError(); BoardBeepCtrl_setEffect(kBoardBeepEffect_threeShortBeep); ds_change_to_state(kdevice_state_sampling_error); } } } /******************************************************************************* * 采样完成页面 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_sampling_complete) { if (ds_cur_state_haspassed_ms() >= 3000) { ZLOGI("ds_cur_state_haspassed_ms() %d> 3000", ds_cur_state_haspassed_ms()); state_machine__change_to_home_state(); ble_cmder_report_sample_finish_event(); } } /******************************************************************************* * 采样错误页面 * *******************************************************************************/ else if (ds_now_state() == kdevice_state_sampling_error) { if ((ds_cur_state_haspassed_ms() >= 3000) || // (ds_cur_state_haspassed_ms() >= 1000 && BoardEcgSensor_plod_get_connected_state_after_filter())) { ZLOGI("ds_cur_state_haspassed_ms() %d> 3000", ds_cur_state_haspassed_ms()); state_machine__change_to_home_state(); ble_cmder_report_sample_finish_event(); } } } /******************************************************************************* * MAIN_CODE * *******************************************************************************/ void one_conduction_main() { BoardBeepCtrl_init(); AppEvent_regListener(app_event_listener); BoardBattery_init(); BoardEcgSensor_init(); BoardLight_Init(); BoardLight_load(); ZERROR_CHECK(app_timer_create(&m_state_machine_driver_tmr, APP_TIMER_MODE_REPEATED, state_machine_driver_tmr_cb)); ZERROR_CHECK(app_timer_start(m_state_machine_driver_tmr, APP_TIMER_TICKS(300), NULL)); state_machine__change_to_poweroning_state(); znordic_loop(); }