From 638f45ceea6b04093895ee2706a1a34ad259193d Mon Sep 17 00:00:00 2001 From: zhaohe Date: Tue, 30 Apr 2024 15:57:26 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E5=B7=A5=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 +- app/app.uvoptx | 186 +++++++++------- app/app.uvprojx | 20 ++ app/src/board/board.h | 6 +- app/src/board/board_ecg_sensor.c | 12 +- app/src/device_state.h | 8 +- app/src/heart_ware_sample_data_mgr.c | 108 +++++++++ app/src/heart_ware_sample_data_mgr.h | 9 + app/src/heart_wave_sample_data_pre_process.c | 107 +++++++++ app/src/heart_wave_sample_data_pre_process.h | 9 + app/src/heart_wave_sample_service.c | 227 +++---------------- app/src/heart_wave_sample_service.c.bak | 313 --------------------------- app/src/one_conduction_main.c | 23 +- 13 files changed, 412 insertions(+), 619 deletions(-) create mode 100644 app/src/heart_ware_sample_data_mgr.c create mode 100644 app/src/heart_ware_sample_data_mgr.h create mode 100644 app/src/heart_wave_sample_data_pre_process.c create mode 100644 app/src/heart_wave_sample_data_pre_process.h delete mode 100644 app/src/heart_wave_sample_service.c.bak diff --git a/.vscode/settings.json b/.vscode/settings.json index 5a21775..2095780 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -187,7 +187,8 @@ "pan_tompkins_detect.h": "c", "qrs_time_domain_zh.h": "c", "board_eeprom_driver.h": "c", - "board_power_mgr.h": "c" + "board_power_mgr.h": "c", + "heart_ware_sample_data_mgr.h": "c" }, "files.encoding": "gbk" } \ No newline at end of file diff --git a/app/app.uvoptx b/app/app.uvoptx index b4abcef..b3d3821 100644 --- a/app/app.uvoptx +++ b/app/app.uvoptx @@ -739,6 +739,30 @@ 0 0 + + 1 + 32 + 1 + 0 + 0 + 0 + .\src\heart_ware_sample_data_mgr.c + heart_ware_sample_data_mgr.c + 0 + 0 + + + 1 + 33 + 1 + 0 + 0 + 0 + .\src\heart_wave_sample_data_pre_process.c + heart_wave_sample_data_pre_process.c + 0 + 0 + @@ -749,7 +773,7 @@ 0 2 - 32 + 34 1 0 0 @@ -769,7 +793,7 @@ 0 3 - 33 + 35 1 0 0 @@ -781,7 +805,7 @@ 3 - 34 + 36 1 0 0 @@ -801,7 +825,7 @@ 0 4 - 35 + 37 1 0 0 @@ -821,7 +845,7 @@ 0 5 - 36 + 38 1 0 0 @@ -833,7 +857,7 @@ 5 - 37 + 39 1 0 0 @@ -845,7 +869,7 @@ 5 - 38 + 40 1 0 0 @@ -857,7 +881,7 @@ 5 - 39 + 41 1 0 0 @@ -869,7 +893,7 @@ 5 - 40 + 42 1 0 0 @@ -881,7 +905,7 @@ 5 - 41 + 43 1 0 0 @@ -893,7 +917,7 @@ 5 - 42 + 44 1 0 0 @@ -905,7 +929,7 @@ 5 - 43 + 45 1 0 0 @@ -925,7 +949,7 @@ 0 6 - 44 + 46 1 0 0 @@ -945,7 +969,7 @@ 0 7 - 45 + 47 1 0 0 @@ -957,7 +981,7 @@ 7 - 46 + 48 1 0 0 @@ -969,7 +993,7 @@ 7 - 47 + 49 1 0 0 @@ -981,7 +1005,7 @@ 7 - 48 + 50 1 0 0 @@ -993,7 +1017,7 @@ 7 - 49 + 51 1 0 0 @@ -1005,7 +1029,7 @@ 7 - 50 + 52 1 0 0 @@ -1017,7 +1041,7 @@ 7 - 51 + 53 1 0 0 @@ -1029,7 +1053,7 @@ 7 - 52 + 54 1 0 0 @@ -1041,7 +1065,7 @@ 7 - 53 + 55 1 0 0 @@ -1053,7 +1077,7 @@ 7 - 54 + 56 1 0 0 @@ -1065,7 +1089,7 @@ 7 - 55 + 57 1 0 0 @@ -1077,7 +1101,7 @@ 7 - 56 + 58 1 0 0 @@ -1089,7 +1113,7 @@ 7 - 57 + 59 1 0 0 @@ -1101,7 +1125,7 @@ 7 - 58 + 60 1 0 0 @@ -1113,7 +1137,7 @@ 7 - 59 + 61 1 0 0 @@ -1125,7 +1149,7 @@ 7 - 60 + 62 1 0 0 @@ -1137,7 +1161,7 @@ 7 - 61 + 63 1 0 0 @@ -1149,7 +1173,7 @@ 7 - 62 + 64 1 0 0 @@ -1161,7 +1185,7 @@ 7 - 63 + 65 1 0 0 @@ -1173,7 +1197,7 @@ 7 - 64 + 66 1 0 0 @@ -1193,7 +1217,7 @@ 0 8 - 65 + 67 1 0 0 @@ -1205,7 +1229,7 @@ 8 - 66 + 68 1 0 0 @@ -1217,7 +1241,7 @@ 8 - 67 + 69 1 0 0 @@ -1229,7 +1253,7 @@ 8 - 68 + 70 1 0 0 @@ -1241,7 +1265,7 @@ 8 - 69 + 71 1 0 0 @@ -1253,7 +1277,7 @@ 8 - 70 + 72 1 0 0 @@ -1265,7 +1289,7 @@ 8 - 71 + 73 1 0 0 @@ -1277,7 +1301,7 @@ 8 - 72 + 74 1 0 0 @@ -1289,7 +1313,7 @@ 8 - 73 + 75 1 0 0 @@ -1301,7 +1325,7 @@ 8 - 74 + 76 1 0 0 @@ -1313,7 +1337,7 @@ 8 - 75 + 77 1 0 0 @@ -1325,7 +1349,7 @@ 8 - 76 + 78 1 0 0 @@ -1337,7 +1361,7 @@ 8 - 77 + 79 1 0 0 @@ -1349,7 +1373,7 @@ 8 - 78 + 80 1 0 0 @@ -1361,7 +1385,7 @@ 8 - 79 + 81 1 0 0 @@ -1373,7 +1397,7 @@ 8 - 80 + 82 1 0 0 @@ -1385,7 +1409,7 @@ 8 - 81 + 83 1 0 0 @@ -1397,7 +1421,7 @@ 8 - 82 + 84 1 0 0 @@ -1409,7 +1433,7 @@ 8 - 83 + 85 1 0 0 @@ -1421,7 +1445,7 @@ 8 - 84 + 86 1 0 0 @@ -1433,7 +1457,7 @@ 8 - 85 + 87 1 0 0 @@ -1445,7 +1469,7 @@ 8 - 86 + 88 1 0 0 @@ -1457,7 +1481,7 @@ 8 - 87 + 89 1 0 0 @@ -1469,7 +1493,7 @@ 8 - 88 + 90 1 0 0 @@ -1481,7 +1505,7 @@ 8 - 89 + 91 1 0 0 @@ -1493,7 +1517,7 @@ 8 - 90 + 92 1 0 0 @@ -1505,7 +1529,7 @@ 8 - 91 + 93 1 0 0 @@ -1525,7 +1549,7 @@ 0 9 - 92 + 94 1 0 0 @@ -1537,7 +1561,7 @@ 9 - 93 + 95 1 0 0 @@ -1549,7 +1573,7 @@ 9 - 94 + 96 1 0 0 @@ -1561,7 +1585,7 @@ 9 - 95 + 97 1 0 0 @@ -1573,7 +1597,7 @@ 9 - 96 + 98 1 0 0 @@ -1585,7 +1609,7 @@ 9 - 97 + 99 1 0 0 @@ -1605,7 +1629,7 @@ 0 10 - 98 + 100 1 0 0 @@ -1617,7 +1641,7 @@ 10 - 99 + 101 1 0 0 @@ -1629,7 +1653,7 @@ 10 - 100 + 102 1 0 0 @@ -1649,7 +1673,7 @@ 0 11 - 101 + 103 1 0 0 @@ -1661,7 +1685,7 @@ 11 - 102 + 104 1 0 0 @@ -1673,7 +1697,7 @@ 11 - 103 + 105 1 0 0 @@ -1693,7 +1717,7 @@ 0 12 - 104 + 106 1 0 0 @@ -1705,7 +1729,7 @@ 12 - 105 + 107 1 0 0 @@ -1717,7 +1741,7 @@ 12 - 106 + 108 1 0 0 @@ -1737,7 +1761,7 @@ 0 13 - 107 + 109 1 0 0 @@ -1749,7 +1773,7 @@ 13 - 108 + 110 1 0 0 @@ -1769,7 +1793,7 @@ 0 14 - 109 + 111 1 0 0 @@ -1781,7 +1805,7 @@ 14 - 110 + 112 1 0 0 @@ -1793,7 +1817,7 @@ 14 - 111 + 113 1 0 0 @@ -1805,7 +1829,7 @@ 14 - 112 + 114 1 0 0 diff --git a/app/app.uvprojx b/app/app.uvprojx index a0827b3..df1da2f 100644 --- a/app/app.uvprojx +++ b/app/app.uvprojx @@ -538,6 +538,16 @@ 1 .\src\board\board_power_mgr.c + + heart_ware_sample_data_mgr.c + 1 + .\src\heart_ware_sample_data_mgr.c + + + heart_wave_sample_data_pre_process.c + 1 + .\src\heart_wave_sample_data_pre_process.c + @@ -4457,6 +4467,16 @@ 1 .\src\board\board_power_mgr.c + + heart_ware_sample_data_mgr.c + 1 + .\src\heart_ware_sample_data_mgr.c + + + heart_wave_sample_data_pre_process.c + 1 + .\src\heart_wave_sample_data_pre_process.c + diff --git a/app/src/board/board.h b/app/src/board/board.h index 6954a97..634db12 100644 --- a/app/src/board/board.h +++ b/app/src/board/board.h @@ -41,9 +41,9 @@ #define LIGHT_PWM_INSTANCE 1 -#define APP_BATTERY_PROTECT_LEVEL 2 // 低于此电量不能开机,保护电池 -#define APP_AUTO_STANDY_BATTERY_LEVEL 5 // 低于此电量自动待机,保持时钟 -#define APP_WORK_BATTERY_LEVEL 10 // Main初始化时候和从standy切换到work的时候,检查这个电量 +// #define APP_BATTERY_PROTECT_LEVEL 2 // 低于此电量不能开机,保护电池 +// #define APP_AUTO_STANDY_BATTERY_LEVEL 5 // 低于此电量自动待机,保持时钟 +// #define APP_WORK_BATTERY_LEVEL 10 // Main初始化时候和从standy切换到work的时候,检查这个电量 #define APP_LOW_BATTERY_WARNING_LIMIT 20 // #define LOW_BATTERY_REMINDER_DELAY_MS 3000 diff --git a/app/src/board/board_ecg_sensor.c b/app/src/board/board_ecg_sensor.c index 28d604d..6788dd6 100644 --- a/app/src/board/board_ecg_sensor.c +++ b/app/src/board/board_ecg_sensor.c @@ -18,7 +18,7 @@ static void module_tmr_cb(void *context) { // memset(&appevent, 0, sizeof(appevent)); // ZLOGI("ecg sensor %d",m_plod_state_connected_state); - if (!nrf_gpio_pin_read(ECG_PLOD_PIN)) { + if (true) { connecte_state_trigger_cnt++; m_connecte_state_last_trigger_timepoint = znordic_getpower_on_ms(); } else { @@ -39,8 +39,8 @@ static void module_tmr_cb(void *context) { // } void BoardEcgSensor_init() { - nrf_gpio_cfg_sense_input(ECG_NLOD_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_NOSENSE); - nrf_gpio_cfg_sense_input(ECG_PLOD_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_NOSENSE); // 低有效 + // nrf_gpio_cfg_sense_input(ECG_NLOD_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_NOSENSE); + // nrf_gpio_cfg_sense_input(ECG_PLOD_PIN, NRF_GPIO_PIN_PULLUP, NRF_GPIO_PIN_NOSENSE); // 低有效 app_timer_create(&module_tmr, APP_TIMER_MODE_REPEATED, module_tmr_cb); app_timer_start(module_tmr, APP_TIMER_TICKS(100), NULL); @@ -48,9 +48,9 @@ void BoardEcgSensor_init() { void BoardEcgSensor_load() { BoardAdc_load(); } void BoardEcgSensor_unload() { BoardAdc_unload(); } -int16_t BoardEcgSensor_nlod_get_connected_state() { return nrf_gpio_pin_read(ECG_NLOD_PIN); } -int16_t BoardEcgSensor_plod_get_connected_state() { return !nrf_gpio_pin_read(ECG_PLOD_PIN); } -int16_t BoardEcgSensor_plod_get_ecg_val() { return BoardAdc_get_val(ECG_ADC_CHANNEL); } +int16_t BoardEcgSensor_nlod_get_connected_state() { return true; } +int16_t BoardEcgSensor_plod_get_connected_state() { return true; } +int16_t BoardEcgSensor_plod_get_ecg_val() { return 0; } int16_t BoardEcgSensor_plod_get_connected_state_after_filter() { return plod_state_is_connected(); } int16_t BoardEcgSensor_plod_state_has_disconnected_ms() { return plod_state_has_disconnected_ms(); } diff --git a/app/src/device_state.h b/app/src/device_state.h index dd99c41..5d1e3c6 100644 --- a/app/src/device_state.h +++ b/app/src/device_state.h @@ -17,9 +17,7 @@ typedef enum { kevent_capture_little_data_block_event, // 单次采样数据回调 } app_event_type_t; -typedef struct { - uint16_t data; -} one_frame_data_t; +typedef uint16_t one_frame_t; typedef struct { app_event_type_t eventType; @@ -27,8 +25,8 @@ typedef struct { uint32_t plod_connected_accumulation_time; // 导联连接累计时间 uint8_t* capture_data_cache; // 实时采样数据,数据长度为256字节 struct { - uint32_t frameIndex; - one_frame_data_t data[LITTLE_DATA_BLOCK_FRAME_NUM]; + uint32_t frameIndex; + one_frame_t data[LITTLE_DATA_BLOCK_FRAME_NUM]; } little_data_block; } val; } app_event_t; diff --git a/app/src/heart_ware_sample_data_mgr.c b/app/src/heart_ware_sample_data_mgr.c new file mode 100644 index 0000000..f28c7a0 --- /dev/null +++ b/app/src/heart_ware_sample_data_mgr.c @@ -0,0 +1,108 @@ +#include "app_event.h" +#include "app_event_distribute.h" +#include "basic/qrs_time_domain_zh.h" +#include "board/board_ecg_sensor.h" +#include "heart_wave_sample_service.h" +#include "nrfx_timer.h" + +static uint32_t m_frame_index = 0; // 帧绝对序号 +/*********************************************************************************************************************** + * ab buffer * + ***********************************************************************************************************************/ +#define FRAME_BUFFER_SIZE (256 / sizeof(one_frame_t)) + +static one_frame_t m_capture_buffer_a[FRAME_BUFFER_SIZE]; +static one_frame_t m_capture_buffer_b[FRAME_BUFFER_SIZE]; +static one_frame_t* m_capture_buffer; +static one_frame_t m_capture_buffer_index = 0; + +static void eeprom_cache_buffer_swap() { + if (m_capture_buffer == NULL) { + m_capture_buffer = m_capture_buffer_a; + m_capture_buffer_index = 0; + return; + } + + if (m_capture_buffer == m_capture_buffer_a) { + m_capture_buffer = m_capture_buffer_b; + } else { + m_capture_buffer = m_capture_buffer_a; + } + m_capture_buffer_index = 0; + return; +} + +/*********************************************************************************************************************** + * littlebuffer * + ***********************************************************************************************************************/ +static one_frame_t m_prepare_data_cache[LITTLE_DATA_BLOCK_FRAME_NUM]; +static uint32_t m_prepare_data_cache_index; + +static inline void preview_data_cache_push_data(one_frame_t data) { + if (m_prepare_data_cache_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { + return; + } + m_prepare_data_cache[m_prepare_data_cache_index] = data; + m_prepare_data_cache_index++; +} + +static inline bool preview_data_cache_is_full(void) { + if (m_prepare_data_cache_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { + return true; + } + return false; +} +static inline void preview_data_cache_clear(void) { m_prepare_data_cache_index = 0; } +static inline void preview_data_trigger_event() { + static app_event_t event; + event.eventType = kevent_capture_little_data_block_event; + for (uint32_t i = 0; i < LITTLE_DATA_BLOCK_FRAME_NUM; i++) { + event.val.little_data_block.data[i] = m_prepare_data_cache[i]; + } + event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; + AppEvent_pushEvent(&event); +} + +/*********************************************************************************************************************** + * EXT * + ***********************************************************************************************************************/ + +void hwsd_mgr_push_one_frame(one_frame_t data) { + m_frame_index++; + + /*********************************************************************************************************************** + * EEPROM数据采样存储 * + ***********************************************************************************************************************/ + if (m_capture_buffer == NULL) eeprom_cache_buffer_swap(); + + if (m_capture_buffer_index < FRAME_BUFFER_SIZE) { + m_capture_buffer[m_capture_buffer_index++] = data; + } + + if (m_capture_buffer_index == FRAME_BUFFER_SIZE) { + app_event_t evt; + evt.eventType = kevent_capture_256data_event; + evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; + eeprom_cache_buffer_swap(); + AppEvent_pushEvent(&evt); + } + + /******************************************************************************* + * 实时采样数据事件上报 * + *******************************************************************************/ + /** + * @brief 缓存数据,并触发小数据块事件 + */ + preview_data_cache_push_data(data); + if (preview_data_cache_is_full()) { + preview_data_trigger_event(); + preview_data_cache_clear(); + } +} + +void hwsd_mgr_reset_buffer(){ + m_frame_index = 0; + m_capture_buffer = NULL; + m_capture_buffer_index = 0; + preview_data_cache_clear(); +} diff --git a/app/src/heart_ware_sample_data_mgr.h b/app/src/heart_ware_sample_data_mgr.h new file mode 100644 index 0000000..24a7e9b --- /dev/null +++ b/app/src/heart_ware_sample_data_mgr.h @@ -0,0 +1,9 @@ +#pragma once +#include + +#include "app_event.h" +#include "app_event_distribute.h" +#include "nrfx_timer.h" + +void hwsd_mgr_push_one_frame(one_frame_t data); +void hwsd_mgr_reset_buffer(); \ No newline at end of file diff --git a/app/src/heart_wave_sample_data_pre_process.c b/app/src/heart_wave_sample_data_pre_process.c new file mode 100644 index 0000000..984b197 --- /dev/null +++ b/app/src/heart_wave_sample_data_pre_process.c @@ -0,0 +1,107 @@ +#include "heart_wave_sample_data_pre_process.h" + +/*********************************************************************************************************************** + * ALGO * + ***********************************************************************************************************************/ + +typedef struct { + float value; + float efectiveFactor; +} filter_t; + +typedef struct { + float coef[2]; + float v_out[2]; +} LPFilter; +#define PI 3.14159265358979323846f + +static float Filter(filter_t* filter, float newInput) { + float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); + filter->value = newv; + return newv; +} + +void LPFilter_Init(LPFilter* filter, float cutoffFreqHz, float sampleTimeS) { + float RC = 0.0; + RC = 1.0 / (2 * PI * cutoffFreqHz); + filter->coef[0] = sampleTimeS / (sampleTimeS + RC); + filter->coef[1] = RC / (sampleTimeS + RC); + + filter->v_out[0] = 0.0; + filter->v_out[1] = 0.0; +} + +float LPFilter_Update(LPFilter* filter, float v_in) { + filter->v_out[1] = filter->v_out[0]; + filter->v_out[0] = (filter->coef[0] * v_in) + (filter->coef[1] * filter->v_out[1]); + + return (filter->v_out[0]); +} + +/** + * @brief 放大显示数据 + * + * @param val + * @param valcener + * @param amp + * @return float + */ +static float amp_display_val(uint16_t val, uint16_t valcener, float amp) { + float valf = (float)val - valcener; + valf = valf * amp; + valf += valcener; + + if (valf >= 100) { + valf = 100; + } + + if (valf <= 0) { + valf = 0; + } + return valf; +} + +uint16_t getRecommendedMagnification() { + // return 0; + uint16_t max = QRS_getMaxValueLastVal(); + if (max == 0) { + return 15; + } + // 3750.0f + if (max <= (3750 / 2)) { + return 15; + } + float af = (3750 / 2) / (max - 3750 / 2); + if (af > 15) { + return 15; + } + return af; +} + +/*********************************************************************************************************************** + * VAR * + ***********************************************************************************************************************/ +static one_frame_t m_datacache; +static one_frame_t m_displaydata; +filter_t m_filter = {0, 0.8}; +LPFilter m_lpfilter_01; +LPFilter m_lpfilter_02; + +void hwsd_pre_processer_init() { QRS_resetBuf(); } +void hwsd_pre_processer_process(one_frame_t framdata) { // + m_datacache = framdata; + m_displaydata = framdata; + /******************************************************************************* + * 显示数据计算并赋值 * + *******************************************************************************/ + // QRS_getMaxValueLastVal(); + // float lowpassf_val = LPFilter_Update(&m_lpfilter_01, framdata); + // QRS_processData(lowpassf_val); + // float val_af100 = (float)lowpassf_val / 3750.0f * 100; // 参考电压为3.6v,但信号范围为3.3v + // val_af100 = amp_val(val_af100, 50, getRecommendedMagnification()); + // val_af100 = LPFilter_Update(&m_lpfilter_02, val_af100); + // m_displaydata = m_datacache; +} + +uint16_t hwsd_pre_processer_get_display_data() { return m_displaydata; } +one_frame_t hwsd_pre_processer_get_storage_data() { return m_datacache; } diff --git a/app/src/heart_wave_sample_data_pre_process.h b/app/src/heart_wave_sample_data_pre_process.h new file mode 100644 index 0000000..bb594e4 --- /dev/null +++ b/app/src/heart_wave_sample_data_pre_process.h @@ -0,0 +1,9 @@ +#pragma once +#include + +#include "app_event.h" + +void hwsd_pre_processer_init(); +void hwsd_pre_processer_process(one_frame_t framdata); +one_frame_t hwsd_pre_processer_get_display_data(); +one_frame_t hwsd_pre_processer_get_storage_data(); diff --git a/app/src/heart_wave_sample_service.c b/app/src/heart_wave_sample_service.c index beb05ed..bb65c00 100644 --- a/app/src/heart_wave_sample_service.c +++ b/app/src/heart_wave_sample_service.c @@ -4,189 +4,31 @@ #include "app_event_distribute.h" #include "basic/qrs_time_domain_zh.h" #include "board/board_ecg_sensor.h" +#include "heart_ware_sample_data_mgr.h" +#include "heart_wave_sample_data_pre_process.h" #include "nrfx_timer.h" - -static uint16_t m_capture_buffer_a[128]; -static uint16_t m_capture_buffer_b[128]; +typedef enum { + kidle, + kprepare, + kcapture, +} capture_state_t; -static uint16_t* m_capture_buffer; -static uint16_t m_capture_buffer_index = 0; - -volatile static float m_sensor_display_data = 0; // 0->100 -static uint32_t m_start_capture_tp; -static uint32_t m_frame_index = 0; -static bool m_prepare_capture = false; - -static one_frame_data_t m_sensor_little_frame_cache[LITTLE_DATA_BLOCK_FRAME_NUM]; -static uint32_t m_little_frame_index; +static capture_state_t m_prepare_capture_state = kidle; +static uint32_t m_start_capture_tp; static nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(HEART_WAVE_SAMPLE_TMR_INSTANCE); -static void swap_buffer() { - if (m_capture_buffer == NULL) { - m_capture_buffer = m_capture_buffer_a; - m_capture_buffer_index = 0; - return; - } - - if (m_capture_buffer == m_capture_buffer_a) { - m_capture_buffer = m_capture_buffer_b; - } else { - m_capture_buffer = m_capture_buffer_a; - } - m_capture_buffer_index = 0; - return; -} -static float amp_val(uint16_t val, uint16_t valcener, float amp) { - float valf = (float)val - valcener; - valf = valf * amp; - valf += valcener; - - if (valf >= 100) { - valf = 100; - } - - if (valf <= 0) { - valf = 0; - } - return valf; -} - -typedef struct { - float value; - float efectiveFactor; -} filter_t; - -typedef struct { - float coef[2]; - float v_out[2]; -} LPFilter; -#define PI 3.14159265358979323846f - -filter_t m_filter = {0, 0.8}; - -LPFilter m_lpfilter_01; -LPFilter m_lpfilter_02; - -static float Filter(filter_t* filter, float newInput) { - float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); - filter->value = newv; - return newv; -} - -void LPFilter_Init(LPFilter* filter, float cutoffFreqHz, float sampleTimeS) { - float RC = 0.0; - RC = 1.0 / (2 * PI * cutoffFreqHz); - filter->coef[0] = sampleTimeS / (sampleTimeS + RC); - filter->coef[1] = RC / (sampleTimeS + RC); - - filter->v_out[0] = 0.0; - filter->v_out[1] = 0.0; -} - -float LPFilter_Update(LPFilter* filter, float v_in) { - filter->v_out[1] = filter->v_out[0]; - filter->v_out[0] = (filter->coef[0] * v_in) + (filter->coef[1] * filter->v_out[1]); - - return (filter->v_out[0]); -} - -/******************************************************************************* - * 小包数据上报 * - *******************************************************************************/ -static inline void prvf_little_block_cache_push_one_frame(uint16_t data) { - if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { - return; - } - m_sensor_little_frame_cache[m_little_frame_index].data = data; - m_little_frame_index++; -} - -static inline bool prvf_light_block_cache_is_full(void) { - if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { - return true; - } - return false; -} -static inline void prvf_light_block_cache_clear(void) { m_little_frame_index = 0; } -static inline void prvf_light_block_trigger_event() { - static app_event_t event; - event.eventType = kevent_capture_little_data_block_event; - for (uint32_t i = 0; i < LITTLE_DATA_BLOCK_FRAME_NUM; i++) { - event.val.little_data_block.data[i].data = m_sensor_little_frame_cache[i].data; - } - event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; - // ZLOGI("%d", event.val.little_data_block.frameIndex); - AppEvent_pushEvent(&event); -} - -// QRS_getMaxValueLastVal(); - -uint16_t getRecommendedMagnification() { - // return 0; - uint16_t max = QRS_getMaxValueLastVal(); - if (max == 0) { - return 15; - } - // 3750.0f - if (max <= (3750 / 2)) { - return 15; - } - float af = (3750 / 2) / (max - 3750 / 2); - if (af > 15) { - return 15; - } - return af; -} - void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // - uint16_t val = BoardEcgSensor_plod_get_ecg_val(); // 12bit - - /******************************************************************************* - * 显示数据计算并赋值 * - *******************************************************************************/ - - // QRS_getMaxValueLastVal(); - int16_t lowpassf_val = LPFilter_Update(&m_lpfilter_01, val); - QRS_processData(lowpassf_val); - float val_af100 = (float)lowpassf_val / 3750.0f * 100; // 参考电压为3.6v,但信号范围为3.3v - val_af100 = amp_val(val_af100, 50, getRecommendedMagnification()); - val_af100 = LPFilter_Update(&m_lpfilter_02, val_af100); - m_sensor_display_data = val_af100; - - if (m_prepare_capture) return; - - /******************************************************************************* - * 采样数据缓存 * - *******************************************************************************/ - m_frame_index++; - if (m_capture_buffer == NULL) { - swap_buffer(); - } - - if (m_capture_buffer_index < 128) { - m_capture_buffer[m_capture_buffer_index++] = val; - } - - if (m_capture_buffer_index == 128) { - app_event_t evt; - evt.eventType = kevent_capture_256data_event; - evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; - swap_buffer(); - AppEvent_pushEvent(&evt); - } - - /******************************************************************************* - * 实时采样数据事件上报 * - *******************************************************************************/ - /** - * @brief 缓存数据,并触发小数据块事件 - */ - prvf_little_block_cache_push_one_frame(val); - if (prvf_light_block_cache_is_full()) { - prvf_light_block_trigger_event(); - prvf_light_block_cache_clear(); + static uint16_t val = 25; + val++; + if (val > 75) val = 25; + + if (m_prepare_capture_state == kprepare) { + hwsd_pre_processer_process(val); + } else if (m_prepare_capture_state == kcapture) { + hwsd_pre_processer_process(val); + hwsd_mgr_push_one_frame(hwsd_pre_processer_get_storage_data()); } } @@ -214,44 +56,29 @@ void hwss_init(void) { } void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } void hwss_start_prepare_capture(void) { - m_start_capture_tp = znordic_getpower_on_s(); - m_prepare_capture = true; - m_frame_index = 0; - - swap_buffer(); - LPFilter_Init(&m_lpfilter_01, 30, 0.002); - LPFilter_Init(&m_lpfilter_02, 30, 0.002); - QRS_resetBuf(); - prvf_light_block_cache_clear(); + m_start_capture_tp = znordic_getpower_on_s(); + m_prepare_capture_state = kprepare; + hwsd_pre_processer_init(); + hwsd_mgr_reset_buffer(); nrfx_timer_enable(&m_timer); } void hwss_start_capture(void) { - m_start_capture_tp = znordic_getpower_on_s(); - m_prepare_capture = false; - // swap_buffer(); - // m_frame_index = 0; - // LPFilter_Init(&m_lpfilter_01, 30, 0.002); - // LPFilter_Init(&m_lpfilter_02, 30, 0.002); - - // QRS_resetBuf(); - - // prvf_light_block_cache_clear(); - // nrfx_timer_enable(&m_timer); + m_start_capture_tp = znordic_getpower_on_s(); + m_prepare_capture_state = kcapture; } void hwss_stop_capture(void) { + m_prepare_capture_state = kidle; nrfx_timer_disable(&m_timer); - m_frame_index = 0; - prvf_light_block_cache_clear(); + hwsd_mgr_reset_buffer(); } float hwss_read_val(void) { __disable_irq(); - float val = m_sensor_display_data; + float val = hwsd_pre_processer_get_display_data(); __enable_irq(); return val; } float hwss_read_heart_rate(void) { // return QRS_getHeartRate(); } - int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; } diff --git a/app/src/heart_wave_sample_service.c.bak b/app/src/heart_wave_sample_service.c.bak deleted file mode 100644 index d130e03..0000000 --- a/app/src/heart_wave_sample_service.c.bak +++ /dev/null @@ -1,313 +0,0 @@ -#include "heart_wave_sample_service.h" - -#include "app_event.h" -#include "app_event_distribute.h" -#include "basic/FIR.h" -#include "basic/HC_Chen_detect.h" -#include "basic/So_Chen_detect.h" -#include "basic/adaptive_algorithm.h" -#include "basic/Pan_Tompkins_detect.h" -#include "board/board_ecg_sensor.h" -#include "nrfx_timer.h" - - -static uint16_t m_capture_buffer_a[128]; -static uint16_t m_capture_buffer_b[128]; - -static uint16_t* m_capture_buffer; -static uint16_t m_capture_buffer_index = 0; - -volatile static float m_sensor_display_data = 0; // 0->100 -static uint32_t m_start_capture_tp; -static uint32_t m_frame_index = 0; - -static one_frame_data_t m_sensor_little_frame_cache[LITTLE_DATA_BLOCK_FRAME_NUM]; -static uint32_t m_little_frame_index; -static bool m_prestart_flag; - -static nrfx_timer_t m_timer = NRFX_TIMER_INSTANCE(HEART_WAVE_SAMPLE_TMR_INSTANCE); - -typedef struct { - int heartSignalCnt; - int heart_rate; - uint32_t last_qrs_point; - uint32_t time_cnt; - uint32_t origin_time_cnt; - - uint32_t index; - float index_f; -} QRS_t; - -QRS_t m_qrs; - -void QRS_reset() { - m_qrs.heartSignalCnt = 0; - m_qrs.heart_rate = 0; - m_qrs.time_cnt = 0; - m_qrs.index = 0; - m_qrs.index_f = 0; - FIR_reset_buffer(); -} - -void QRS_process(float value) { - bool isPeak = false; -#if 1 - float result = value; - SignalPoint sp; - sp.value = result; - sp.index = m_qrs.time_cnt; - SignalPoint peak = So_Chen_detect(sp, SAMPLING_RATE * 0.25f, 4, 16); - if (peak.index != -1) { - isPeak = true; - } -#endif - -#if 0 - isPeak = HC_Chen_detect(value); -#endif - -#if 0 - static const float CV_LIMIT = 50.0f; - static const float THRESHOLD_FACTOR = 3.0f; - double mean = CalculateMean(value); - double rms = CalculateRootMeanSquare(value); - double cv = CalculateCoefficientOfVariation(value); - double threshold; - if (cv > CV_LIMIT) { - threshold = rms; - } else { - threshold = rms * (cv / 100.0f) * THRESHOLD_FACTOR; - } - bool is_peak; - SignalPoint result; - result = PeakDetect(value, m_qrs.time_cnt, threshold, &is_peak); - if (result.index != -1) { - if (is_peak) { - isPeak = true; - } - } -#endif - -#if 0 - - - double result = value; - double bandpass; - double integral; - double square; - - bandpass = result; - result = Derivative(result); - result = Squar(result); - square = result; - result = MovingWindowIntegral(result); - integral = result; - - SignalPoint peak = ThresholdCalculate(m_qrs.time_cnt,value,bandpass,square,integral); - - if(peak.index != -1){ - isPeak = true; - } - -#endif - - // if (isPeak) { - // uint32_t time_diff = m_qrs.time_cnt - m_qrs.last_qrs_point; - // m_qrs.last_qrs_point = m_qrs.time_cnt; - // m_qrs.heartSignalCnt++; - // // m_qrs.heart_rate = m_qrs.heartSignalCnt; - // if (m_qrs.last_qrs_point != 0) { - // m_qrs.heart_rate = 60 * (1 / (time_diff * 1.0 / SAMPLING_RATE)); - // } - // } - - m_qrs.time_cnt++; -} - -static const void compute_heart_rate(float sample_data) { - ZASSERT(SAMPLE_RATE == 500); - m_qrs.index_f = m_frame_index / 500.0 * 360; - if ((m_qrs.index_f - m_qrs.index) > 1) { - m_qrs.index = m_qrs.index_f; - float val = sample_data; - QRS_process(FIR_filter(val)); - } -} - -static void swap_buffer() { - if (m_capture_buffer == NULL) { - m_capture_buffer = m_capture_buffer_a; - m_capture_buffer_index = 0; - return; - } - - if (m_capture_buffer == m_capture_buffer_a) { - m_capture_buffer = m_capture_buffer_b; - } else { - m_capture_buffer = m_capture_buffer_a; - } - m_capture_buffer_index = 0; - return; -} -static float amp_val(uint16_t val, uint16_t valcener, float amp) { - float valf = (float)val - valcener; - valf = valf * amp; - valf += valcener; - - if (valf >= 100) { - valf = 100; - } - - if (valf <= 0) { - valf = 0; - } - return valf; -} - -typedef struct { - float value; - float efectiveFactor; -} filter_t; - -filter_t m_filter = {0, 0.8}; - -static float Filter(filter_t* filter, float newInput) { - float newv = ((float)filter->value * (1.0f - filter->efectiveFactor)) + ((float)newInput * filter->efectiveFactor); - filter->value = newv; - return newv; -} - -/******************************************************************************* - * 小包数据上报 * - *******************************************************************************/ -static inline void prvf_little_block_cache_push_one_frame(uint16_t data) { - if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { - return; - } - m_sensor_little_frame_cache[m_little_frame_index].data = data; - m_little_frame_index++; -} - -static inline bool prvf_light_block_cache_is_full(void) { - if (m_little_frame_index >= LITTLE_DATA_BLOCK_FRAME_NUM) { - return true; - } - return false; -} -static inline void prvf_light_block_cache_clear(void) { m_little_frame_index = 0; } -static inline void prvf_light_block_trigger_event() { - static app_event_t event; - event.eventType = kevent_capture_little_data_block_event; - for (uint32_t i = 0; i < LITTLE_DATA_BLOCK_FRAME_NUM; i++) { - event.val.little_data_block.data[i].data = m_sensor_little_frame_cache[i].data; - } - event.val.little_data_block.frameIndex = m_frame_index - LITTLE_DATA_BLOCK_FRAME_NUM; - // ZLOGI("%d", event.val.little_data_block.frameIndex); - AppEvent_pushEvent(&event); -} - -void nrfx_timer_event_handler(nrf_timer_event_t event_type, void* p_context) { // - uint16_t val = BoardEcgSensor_plod_get_ecg_val(); // 12bit - float val_af100 = (float)val / 4096.0f * 100; - if (m_prestart_flag) { - compute_heart_rate(val_af100); - return; - } else { - compute_heart_rate(val_af100); - } - - /******************************************************************************* - * 显示数据计算并赋值 * - *******************************************************************************/ - - m_frame_index++; - val_af100 = amp_val(val_af100, 45, 3.5f); - val_af100 = Filter(&m_filter, val_af100); - m_sensor_display_data = val_af100; - - /******************************************************************************* - * 采样数据缓存 * - *******************************************************************************/ - if (m_capture_buffer == NULL) { - swap_buffer(); - } - - if (m_capture_buffer_index < 128) { - m_capture_buffer[m_capture_buffer_index++] = val; - } - - if (m_capture_buffer_index == 128) { - app_event_t evt; - evt.eventType = kevent_capture_256data_event; - evt.val.capture_data_cache = (uint8_t*)m_capture_buffer; - swap_buffer(); - AppEvent_pushEvent(&evt); - } - - /******************************************************************************* - * 实时采样数据事件上报 * - *******************************************************************************/ - /** - * @brief 缓存数据,并触发小数据块事件 - */ - prvf_little_block_cache_push_one_frame(val); - if (prvf_light_block_cache_is_full()) { - prvf_light_block_trigger_event(); - prvf_light_block_cache_clear(); - } -} - -void hwss_init(void) { - static bool m_timer_inited = false; - if (!m_timer_inited) { - /** - * @brief 初始化定时器 - */ - static nrfx_timer_config_t timer_cfg = { - .frequency = NRF_TIMER_FREQ_500kHz, - .mode = NRF_TIMER_MODE_TIMER, - .bit_width = NRF_TIMER_BIT_WIDTH_24, - .p_context = NULL, - .interrupt_priority = NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY, - }; - - // nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler); - ZERROR_CHECK(nrfx_timer_init(&m_timer, &timer_cfg, nrfx_timer_event_handler)); - uint32_t timer_ticks = nrfx_timer_ms_to_ticks(&m_timer, 2); // - ZASSERT(SAMPLE_RATE == 500); - nrfx_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, timer_ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, true); - m_timer_inited = true; - } -} -void hwss_uninit(void) { nrfx_timer_disable(&m_timer); } - -void hwss_pre_start_capture(void) { - m_start_capture_tp = znordic_getpower_on_s(); - swap_buffer(); - m_frame_index = 0; - - QRS_reset(); - - prvf_light_block_cache_clear(); - nrfx_timer_enable(&m_timer); - m_prestart_flag = true; -} - -void hwss_start_capture(void) { m_prestart_flag = false; } -void hwss_stop_capture(void) { - nrfx_timer_disable(&m_timer); - m_frame_index = 0; - prvf_light_block_cache_clear(); -} - -float hwss_read_val(void) { - __disable_irq(); - float val = m_sensor_display_data; - __enable_irq(); - return val; -} -float hwss_read_heart_rate(void) { // - return m_qrs.heart_rate; -} - -int hwss_has_captured_time_ms() { return (znordic_getpower_on_s() - m_start_capture_tp) * 1000; } diff --git a/app/src/one_conduction_main.c b/app/src/one_conduction_main.c index a484598..0b9ea5b 100644 --- a/app/src/one_conduction_main.c +++ b/app/src/one_conduction_main.c @@ -181,7 +181,8 @@ static void app_event_listener(void* p_event_data, uint16_t event_size) { else if (BoardEcgSensor_plod_get_connected_state_after_filter() && znordic_haspassed_ms(lasttrypoweron_time) >= LOW_BATTERY_REMINDER_DELAY_MS) { lasttrypoweron_time = znordic_getpower_on_ms(); - if (BoardBattery_get_battery_level() > APP_WORK_BATTERY_LEVEL) { + // if (BoardBattery_get_battery_level() > APP_WORK_BATTERY_LEVEL) { + if (true) { state_machine__change_to_poweroning_state(); } else { BoardLight_load(); @@ -195,9 +196,9 @@ static void app_event_listener(void* p_event_data, uint16_t event_size) { if (!znordic_rtc_has_setted()) { ENTER_DEEP_SLEEP(); } - if (APP_BATTERY_PROTECT_LEVEL > BoardBattery_get_battery_level()) { - ENTER_DEEP_SLEEP(); - } + // if (APP_BATTERY_PROTECT_LEVEL > BoardBattery_get_battery_level()) { + // ENTER_DEEP_SLEEP(); + // } } } @@ -245,10 +246,12 @@ static void app_event_listener(void* p_event_data, uint16_t event_size) { } } +#if 0 // 低电量,设备进入待机模式 else if (BoardBattery_get_battery_level() < APP_AUTO_STANDY_BATTERY_LEVEL && ds_cur_state_haspassed_ms() > 3000) { state_machine__change_to_standby_state(); } // +#endif else if (!ble_is_upload_record() && zble_module_is_connected() && zdatachannel_last_rx_data_haspassed_s() >= BLE_UNCONNECTED_OVERTIME_S) { ZLOGI("auto sleep because ble unconnected"); @@ -339,11 +342,11 @@ static void app_event_listener(void* p_event_data, uint16_t event_size) { // 单帧实时上报 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); + p_event->val.little_data_block.data[0], // + p_event->val.little_data_block.data[1], // + p_event->val.little_data_block.data[2], // + p_event->val.little_data_block.data[3], // + p_event->val.little_data_block.data[4]); } /******************************************************************************* @@ -431,7 +434,7 @@ void one_conduction_main() { BoardEcgSensor_init(); BoardLight_Init(); BoardBattery_load(); -#if 1 +#if 0 if (BoardBattery_get_battery_level() < APP_WORK_BATTERY_LEVEL) { BoardLight_load(); BoardLight_blockFlash(3, 100);