#include "device_ctrl_service.h" #include "app_event_distribute.h" #include "board/board_battery_state.h" #include "board/board_beep_ctrl.h" #include "board/board_button.h" #include "board/board_light_ctrl.h" #include "board/board_sdcard_driver.h" #include "heart_wave_sample_service.h" #include "sample_data_manager_service.h" #include "zble_module.h" #include "zdatachannel_service.h" // APP_TIMER_DEF(m_state_machine_driver_tmr); // 状态机驱动定时器 static device_state_t m_device_state = kdevice_state_standby; // 设备状态 static uint32_t m_change_to_cur_state_tp = 0; // 切换到当前状态的时间戳 static int m_sample_data_fd = -1; // 采集数据文件描述符 /******************************************************************************* * 函数列表 * *******************************************************************************/ void DeviceCtrl_change_to_state(device_state_t state); uint32_t DeviceCtrl_cur_state_haspassed_ms(); device_state_t DeviceCtrl_now_state(); /******************************************************************************* * 事件路由 * *******************************************************************************/ static void state_machine_driver_tmr_cb(void* p_context) { // static app_event_t appevent; appevent.eventType = kevent_tmr_scheduler; AppEvent_pushEvent(&appevent); } /** * @brief 按键事件处理 */ static void board_button_cb(ButtonIndex_t pin_no, ButtonAction_t button_action) { // static app_event_t event; event.eventType = button_action == kButtonAction_push ? kevent_button_push_event : kevent_button_release_event; AppEvent_pushEvent(&event); } static void zble_event_listener(zble_event_t* ble_event) { // static app_event_t event; if (ble_event->eventType == kzble_event_connected) { event.eventType = kevent_ble_connect_event; AppEvent_pushEvent(&event); } else if (ble_event->eventType == kzble_event_disconnected) { event.eventType = kevent_ble_disconnect_event; AppEvent_pushEvent(&event); } } /******************************************************************************* * 事件处理 * *******************************************************************************/ static bool m_ispoweron = false; static bool m_drop_state_triggered = false; static void poweroff() { if (!m_ispoweron) return; BoardBeepCtrl_unload(); BoardLight_unload(); BoardBattery_unload(); BoardButton_unload(); SampleDataMgr_unloadDriver(); hwss_unload(); DeviceCtrl_change_to_state(kdevice_state_standby); zble_module_stop_adv(); BoardLight_setGreenLightEffect(kLightEffect_close); // 进入深度睡眠前,使能唤醒引脚 BoardButton_enable_sense(); app_timer_stop_all(); // 系统进入深度睡眠 sd_power_system_off(); NVIC_SystemReset(); m_ispoweron = false; } static void poweron() { if (m_ispoweron) { return; } BoardBeepCtrl_load(); BoardLight_load(); BoardBattery_load(); BoardButton_load(); SampleDataMgr_loadDriver(); hwss_load(); DeviceCtrl_change_to_state(kdevice_state_ready); zble_module_start_adv(); BoardLight_setGreenLightEffect(kLightEffect_slowFlash); m_ispoweron = true; } static sample_data_filename_t* cratefilename() { static ztm_t tm; static sample_data_filename_t sampledata_file_name; memset(&sampledata_file_name, 0, sizeof(sampledata_file_name)); znordic_rtc_gettime(&tm); 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; return &sampledata_file_name; } static void prvf_change_to_standby_state() { poweroff(); DeviceCtrl_change_to_state(kdevice_state_standby); } static void prvf_change_to_ready_state() { poweron(); DeviceCtrl_change_to_state(kdevice_state_ready); BoardBeepCtrl_setEffect(kBoardBeepEffect_oneShortBeep); } static const char* dropstate(uint8_t drop0, uint8_t drop1) { static char state[128]; sprintf(state, "drop0:%d%d%d%d-%d%d%d%d drop1:%d%d%d%d-%d%d%d%d", // drop0 & 0x80 ? 1 : 0, drop0 & 0x40 ? 1 : 0, drop0 & 0x20 ? 1 : 0, drop0 & 0x10 ? 1 : 0, // drop0 & 0x08 ? 1 : 0, drop0 & 0x04 ? 1 : 0, drop0 & 0x02 ? 1 : 0, drop0 & 0x01 ? 1 : 0, // drop1 & 0x80 ? 1 : 0, drop1 & 0x40 ? 1 : 0, drop1 & 0x20 ? 1 : 0, drop1 & 0x10 ? 1 : 0, // drop1 & 0x08 ? 1 : 0, drop1 & 0x04 ? 1 : 0, drop1 & 0x02 ? 1 : 0, drop1 & 0x01 ? 1 : 0 // ); return state; } static void prvf_change_to_sample_state() { // if (m_device_state == kdevice_state_sampling) { return; } DeviceCtrl_change_to_state(kdevice_state_sampling); } static void app_event_listener(void* p_event_data, uint16_t event_size) { // app_event_t* event = (app_event_t*)p_event_data; static bool inited; if (!inited) { nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_NOPULL); inited = true; } ZLOGI("button %d", nrf_gpio_pin_read(BUTTON_PIN)); /******************************************************************************* * 状态无关事件处理 * *******************************************************************************/ if (event->eventType == kevent_ble_connect_event) { BoardLight_setGreenLightEffect(kLightEffect_open); return; } else if (event->eventType == kevent_ble_disconnect_event) { BoardLight_setGreenLightEffect(kLightEffect_slowFlash); return; } /******************************************************************************* * 状态机 * *******************************************************************************/ // ZLOGI("state %d", m_device_state); if (m_device_state == kdevice_state_standby) { // 休眠模式现在是深度睡眠,所以永远不会触发这个回调 } // else if (m_device_state == kdevice_state_ready) { if (!zble_module_is_connected() && DeviceCtrl_cur_state_haspassed_ms() > APP_AUTO_SLEEP_TIMEOUT_MS) { ZLOGI("auto sleep"); prvf_change_to_standby_state(); } if (event->eventType == kevent_start_sample_cmd_event) { ZLOGI("start sample"); // SD卡连接到单片机 SampleDataMgr_changeToLocalMode(); // 创建文件 m_sample_data_fd = SampleDataMgr_open(cratefilename(), kwrflag_write_only); ZASSERT(m_sample_data_fd > 0); // 切换到采集状态 prvf_change_to_sample_state(); // 开始采集 hwss_start_capture(); { static app_event_t event; event.eventType = kevent_sample_start_event; AppEvent_pushEvent(&event); } BoardBeepCtrl_setEffect(kBoardBeepEffect_oneShortBeep); } } // else if (m_device_state == kdevice_state_sampling) { // 采集的字节长度超过最大字节长度,停止采集 if (event->eventType == kevent_capture_data_block_event) { SampleDataMgr_write(m_sample_data_fd, (uint8_t*)event->val.block_sensor_data.data, event->val.block_sensor_data.len); } uint8_t drop0 = hwss_get_drop_state0(); uint8_t drop1 = hwss_get_drop_state1(); if ((drop0 || drop1) && event->eventType == kevent_tmr_scheduler) { ZLOGI("[%d] drop %s", znordic_getpower_on_ms(), dropstate(drop0, drop1)); } bool stopcapture = false; if (SampleDataMgr_getFileSizeByFd(m_sample_data_fd) > SDCARD_MAX_FILE_SIZE) { ZLOGI("stop sample because file size is too large"); stopcapture = true; } else if (event->eventType == kevent_stop_sample_cmd_event) { ZLOGI("stop sample because stop sample event"); stopcapture = true; } if (stopcapture) { // 关闭文件 SampleDataMgr_close(m_sample_data_fd); // SD卡连接到外部typec SampleDataMgr_changeToExtMode(); // 停止采集 hwss_stop_capture(); // 切换到待机状态 prvf_change_to_ready_state(); { static app_event_t event; event.eventType = kevent_sample_stop_event; AppEvent_pushEvent(&event); } } } } void DeviceCtrl_startSample() { ZLOGI("start sample"); static app_event_t event; event.eventType = kevent_start_sample_cmd_event; AppEvent_pushEvent(&event); } void DeviceCtrl_stopSample() { ZLOGI("stop sample"); static app_event_t event; event.eventType = kevent_stop_sample_cmd_event; AppEvent_pushEvent(&event); } /******************************************************************************* * EXTERN * *******************************************************************************/ void DeviceCtrl_init() { // 蜂鸣器初始化 BoardBeepCtrl_init(); // 板载指示灯初始化 BoardLight_Init(); // 按键初始化 BoardButton_Init(board_button_cb); // 电池初始化 BoardBattery_init(); // SD卡初始化 SampleDataMgr_init(); // 心电采集服务初始化 hwss_init(); // 注册事件监听 AppEvent_regListener(app_event_listener); // 监听蓝牙事件 zble_module_reglistener(zble_event_listener); // 切换到待机状态 prvf_change_to_ready_state(); 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(100), NULL)); // 200HZ采样 } /******************************************************************************* * UTILS * *******************************************************************************/ void DeviceCtrl_change_to_state(device_state_t state) { ZLOGI("change state from %s to %s", ds2str(m_device_state), ds2str(state)); m_device_state = state; m_change_to_cur_state_tp = znordic_getpower_on_ms(); } uint32_t DeviceCtrl_cur_state_haspassed_ms() { return znordic_haspassed_ms(m_change_to_cur_state_tp); } device_state_t DeviceCtrl_now_state() { return m_device_state; } #if 0 static void DeviceCtrl_test() { /** * @brief * 1. 测试蜂鸣器 * 2. 测试按键 * 3. 测试LED * 4. 测试指示灯 * . SD卡 * 5. 测试电池电量采集 */ #if 0 //蜂鸣器测试 BoardBeepCtrl_init(); BoardBeepCtrl_load(); BoardBeepCtrl_setEffect(kBoardBeepEffect_continuousShortBeep); #endif #if 1 // BoardButton_Init(board_button_cb); #endif #if 0 BoardLight_Init(); BoardLight_load(); BoardLight_setGreenLightEffect(kLightEffect_slowFlash); #endif #if 0 Board_sdcardInit(); Board_sdcardConnectToInternal(); Board_sdcardConnectToExt(); Board_sdcardConnectToInternal(); Board_sdcardConnectToExt(); #endif #if 0 sample_data_mgr_init(); sample_data_mgr_loadDriver(); sample_data_mgr_change_to_local_mode(); sample_data_filename_t filename; int fd = sample_data_mgr_open(&filename, kwrflag_write_only); sample_data_mgr_write(fd, "123456", 6); sample_data_mgr_close(fd); sample_data_mgr_change_to_ext_mode(); #endif #if 1 // 蜂鸣器测试 #endif } #endif