From aeacbb0e971fe56b26af152d12246b68b6ad7724 Mon Sep 17 00:00:00 2001 From: 1624952103 Date: Wed, 10 Jun 2026 16:12:50 +0800 Subject: [PATCH] =?utf8?q?=E6=9B=B4=E6=96=B0=E8=8E=B7=E5=8F=96=E8=A1=80?= =?utf8?q?=E5=8E=8B=E5=92=8Cecg=E6=88=BF=E9=A2=A4=E6=B5=8B=E8=AF=95?= =?utf8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c | 28 ++++++- code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h | 20 ++++- .../PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.c | 32 +++++++- .../PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.h | 5 ++ .../PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.c | 74 ++++++++++++++++--- .../PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.h | 5 ++ .../ppg/pah831x/pah_sensor/pah831x_comm.c | 6 +- .../ppg/pah831x/pah_sensor/pah831x_main.c | 39 ++++++++++ .../ppg/pah831x/pah_sensor/pah831x_main.h | 3 + 9 files changed, 189 insertions(+), 23 deletions(-) diff --git a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c index ce80a1caf..ee2880931 100644 --- a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c +++ b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.c @@ -137,10 +137,20 @@ uint8_t ppg_get_hrv(void) return hrv; } -void ppg_get_bp(int *sbp,int *dbp) +void ppg_get_ecg_bp(int *sbp, int *dbp, uint8_t *status) { + if (sbp != NULL) { + *sbp = 0; + } + if (dbp != NULL) { + *dbp = 0; + } + if (status != NULL) { + *status = PPG_ECG_BP_STATUS_MEASURING; + } + #if defined PPG_PAH831X - pah8311_get_bp(sbp,dbp); + pah831x_get_ecg_bp(sbp, dbp, status); #endif } @@ -170,6 +180,20 @@ uint32_t ppg_read_ecg_raw(int32_t *buf, uint32_t buf_len) #endif } +void ppg_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result) +{ + if (ecg_hr != NULL) { + *ecg_hr = 0; + } + if (afib_result != NULL) { + *afib_result = PPG_ECG_AFIB_RESULT_INVALID; + } + +#if defined PPG_PAH831X + pah831x_get_ecg_afib(ecg_hr, afib_result); +#endif +} + uint8_t ppg_get_wear_status(void) { uint8_t wear_status = 0; diff --git a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h index 13704351c..423779c97 100644 --- a/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h +++ b/code/sdk/zhihui/drivers/ppg/hal/ppg_hal.h @@ -35,6 +35,9 @@ extern "C" { #define PPG_CHIP_ID 0 #endif + +#define PPG_ECG_AFIB_RESULT_INVALID 0xFF + typedef uint32_t PPG_CMD_TYPE_T ; typedef enum{ @@ -69,8 +72,6 @@ void ppg_set_factory_log_switch(uint8_t cmd); uint8_t ppg_get_factory_log_switch(void); uint8_t ppg_get_hrv(void); -void ppg_get_bp(int *sbp,int *dbp); - //输入校准血压 void ppg_set_bp_cali_data(int *sbp,int *dbp); @@ -84,6 +85,21 @@ bool is_ppg_bp_need_cali(void); * 开始/停止 ecgbp、ecgafib、ecgraw 时驱动内部自动清缓冲。 */ uint32_t ppg_read_ecg_raw(int32_t *buf, uint32_t buf_len); +/* 获取 ECG 房颤测试结果。 + * ecg_hr: ECG 心率(bpm),测量过程中持续更新; + * afib_result: 房颤结论,测试未完成时为 0xFF + * 0 窦性心律 1 不确定(不规则) 2 可能房颤 + * 3 不确定(信号/特征) 4 心率过低 5 心率过高 */ +void ppg_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result); + +#define PPG_ECG_BP_STATUS_MEASURING 0 /* 测量中 */ +#define PPG_ECG_BP_STATUS_WEAK_SIGNAL 1 /* ECG已停止,疑似信号弱,请重新测试 */ + +/* 获取 ECG 血压测量结果。 + * sbp/dbp: 收缩压/舒张压,未出结果时为 0; + * status: 0 测量中 1 ECG已停止(疑似信号弱,请重新测试) */ +void ppg_get_ecg_bp(int *sbp, int *dbp, uint8_t *status); + #ifdef __cplusplus #if __cplusplus } diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.c b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.c index 6c365cd1b..5ee975cbe 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.c +++ b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.c @@ -53,15 +53,14 @@ typedef struct static bool need_log_header = true; static main_ecg_afib_state_s _state; -static float alg_value =0.0f; - #define K_sampling_rate 256 static uint16_t ECG_FS = 256; // ECG Afib function support : 128, 256 , 512 ,1024 Hz static uint16_t ECG_time = 30; // Sec static uint8_t ReadyFlag = 0; static uint8_t AFIB_ReadyFlag = 0; -static uint8_t ecg_afib_result = 0; +static uint8_t ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; +static uint8_t ecg_afib_hr = 0; static uint16_t ecg_ready_count = 0; static int32_t ecg_frame_count = 0; @@ -168,7 +167,11 @@ uint8_t is_touched //if(is_touched) { ecg_afib_algorithm_process(&_state.pxialg_data, _state.pxialg_data.nf_ppg_channel); - *alg_value_out = (uint8_t) alg_value ; + if (_state.has_got_AFIB) { + *alg_value_out = ecg_afib_result; + } else { + *alg_value_out = PAH_ECG_AFIB_RESULT_INVALID; + } } *got_AFIB = _state.has_got_AFIB; @@ -265,6 +268,7 @@ static uint8_t run_afib_pxialg(uint32_t duration, const uint32_t* ecg_data, uint ECG_Analysis_Process(_state.pxialg_buffer_hrv, touch_flag, ecg_data[j], interval_time); } float HR =ECG_Analysis_Get_HR(_state.pxialg_buffer_hrv); + ecg_afib_hr = (uint8_t)HR; ALG_PRINT("ECG Heart Rate = %d \n", (int)HR); #endif // ENABLE_PXI_ALG_ECG_HRD @@ -311,6 +315,7 @@ static uint8_t run_afib_pxialg(uint32_t duration, const uint32_t* ecg_data, uint #if 1 // Use ECG HRV realtime HR. for get mean HR int16_t mean_hr = 0; mean_hr = PXIAFIB_ComputeMeanHR(_state.pxialg_state_afib); //need to instead hrv lib hr. + ecg_afib_hr = (uint8_t)mean_hr; ALG_PRINT("mean_hr=%d\n", mean_hr); #endif //for check p,r,t number @@ -398,6 +403,8 @@ void ecg_afib_algorithm_init(void) _state.pxialg_has_init = false; need_log_header = true; AFIB_ReadyFlag = 0; + ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; + ecg_afib_hr = 0; _state.has_got_AFIB=0; _state.has_time_out=0; _state.pxialg_data.frame_count = 0 ; @@ -417,3 +424,20 @@ void ecg_afib_algorithm_init(void) } #endif // ENABLE_PXI_ALG_ECG_AFIB } + +uint8_t pah_ecg_afib_get_result(void) +{ +#if defined(ENABLE_PXI_ALG_ECG_AFIB) + if (!_state.has_got_AFIB) { + return PAH_ECG_AFIB_RESULT_INVALID; + } + return ecg_afib_result; +#else + return PAH_ECG_AFIB_RESULT_INVALID; +#endif +} + +uint8_t pah_ecg_afib_get_hr(void) +{ + return ecg_afib_hr; +} diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.h b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.h index 10d69c978..b88020e9a 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.h +++ b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_AFIB/V2022/pah_ecg_afib_alg.h @@ -39,6 +39,11 @@ void ecg_afib_algorithm_init(void); void ecg_afib_algorithm_close(void); +#define PAH_ECG_AFIB_RESULT_INVALID 0xFF + +uint8_t pah_ecg_afib_get_hr(void); +uint8_t pah_ecg_afib_get_result(void); + #endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.c b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.c index 1d47ae1b6..6fa70eebf 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.c +++ b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.c @@ -62,6 +62,7 @@ static struct ECG_result ecg_result; static int alg_value[2]; static uint16_t ecg_ready_count = 0; +static uint8_t ecg_bp_hr = 0; int ppg_pf_output; @@ -359,6 +360,7 @@ static uint8_t run_ecg_bp_pxialg(uint32_t duration, const uint32_t* ecg_data, co ECG_Analysis_Process(_state.pxialg_buffer_hrv, touch_flag, ecg_data[j], interval_time); } HR =ECG_Analysis_Get_HR(_state.pxialg_buffer_hrv); + ecg_bp_hr = (uint8_t)HR; ALG_PRINT("ECG Heart Rate = %d ready_flag = %d\n", (int)HR,ecg_result.ready_flag); #endif // ENABLE_PXI_ALG_ECG_HRD @@ -443,6 +445,13 @@ static uint8_t run_ecg_bp_pxialg(uint32_t duration, const uint32_t* ecg_data, co void ecg_bp_algorithm_init(void) { #if defined(ENABLE_PXI_ALG_ECG_BP) + BP_ReadyFlag = 0; + _state.has_got_BP = 0; + _state.has_time_out = 0; + ecg_bp_hr = 0; + alg_value[0] = 0; + alg_value[1] = 0; + if (_state.pxialg_has_init) { _state.pxialg_has_init = false; @@ -454,9 +463,6 @@ void ecg_bp_algorithm_init(void) free(_state.pxialg_buffer_bp); memset(&ecg_result,0,sizeof(ecg_result)); need_log_header = true; - BP_ReadyFlag = 0; - _state.has_got_BP = 0; - _state.has_time_out = 0; _state.pxialg_data.frame_count = 0 ; LOG_PRINT("ecg_bp_algorithm_init \n"); } @@ -480,11 +486,64 @@ void ecg_bp_algorithm_close(void) BP_ReadyFlag = 0; _state.has_got_BP = 0; _state.has_time_out = 0; + ecg_bp_hr = 0; need_log_header = true; _state.pxialg_data.frame_count = 0 ; } #endif // ENABLE_PXI_ALG_ECG_BP } + +uint8_t pah_ecg_bp_get_status(void) +{ +#if defined(ENABLE_PXI_ALG_ECG_BP) + if (_state.has_time_out) { + return PAH_ECG_BP_STATUS_WEAK_SIGNAL; + } + return PAH_ECG_BP_STATUS_MEASURING; +#else + return PAH_ECG_BP_STATUS_MEASURING; +#endif +} + +void pah_ecg_bp_get_bp(int *sbp, int *dbp) +{ + int out_sbp = 0; + int out_dbp = 0; + + if (sbp != NULL) { + *sbp = 0; + } + if (dbp != NULL) { + *dbp = 0; + } + if (sbp == NULL && dbp == NULL) { + return; + } + +#if defined(ENABLE_PXI_ALG_ECG_BP) + if (_state.has_got_BP == 0) { + return; + } + + if (cal_mode == ECG_PPG_BP_CALI) { + out_sbp = NoCal_SBP; + out_dbp = NoCal_DBP; + NoCal_SBP = 0; + NoCal_DBP = 0; + } else { + out_sbp = alg_value[0]; + out_dbp = alg_value[1]; + } +#endif + + if (sbp != NULL) { + *sbp = out_sbp; + } + if (dbp != NULL) { + *dbp = out_dbp; + } +} + bool get_bp_cal_data(int* cal_data) { cal_data[0]=calibration_bp[0]; @@ -496,12 +555,5 @@ bool get_bp_cal_data(int* cal_data) void pah8311_get_bp(int *sbp,int *dbp) { - if(sbp == NULL || dbp == NULL) - return; - - *sbp = NoCal_SBP; - *dbp = NoCal_DBP; - - NoCal_SBP = 0; - NoCal_DBP = 0; + pah_ecg_bp_get_bp(sbp, dbp); } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.h b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.h index 9ecc16b03..6cf4a94dc 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.h +++ b/code/sdk/zhihui/drivers/ppg/pah831x/PXI_ALG/ECG_PPG_BP/v3070/pah_ecg_bp_alg.h @@ -54,6 +54,11 @@ void ecg_bp_algorithm_close(void); bool get_bp_cal_data(int* cal_data); +#define PAH_ECG_BP_STATUS_MEASURING 0 /* 测量中 */ +#define PAH_ECG_BP_STATUS_WEAK_SIGNAL 1 /* ECG已停止,疑似信号弱,请重新测试 */ + +uint8_t pah_ecg_bp_get_status(void); +void pah_ecg_bp_get_bp(int *sbp, int *dbp); #endif // header guard diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_comm.c b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_comm.c index b1c3f1a53..7fb04b44e 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_comm.c +++ b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_comm.c @@ -33,14 +33,13 @@ static uint8_t _curr_bank = 0xFF; pah_ret pah_comm_i2c_write( uint8_t addr, const uint8_t *data, size_t write_size) { // DEBUG_PRINT("Write { 0x%02X, 0x%02X }\n",addr, data[0]); - custom_i2c_write_reg(PAH831X_DEFAULT_I2C_SLAVE_ADDR, addr, 1, data, write_size, PAH831X_I2C_BUS); - return PAH_RET_SUCCESS; + return custom_i2c_write_reg(PAH831X_DEFAULT_I2C_SLAVE_ADDR, addr, 1, data, write_size, PAH831X_I2C_BUS); } pah_ret pah_comm_i2c_read( uint8_t addr, uint8_t *data, size_t read_size) { // DEBUG_PRINT("Read { 0x%02X }, Length =%d\n",addr,read_size); - custom_i2c_read_regs(PAH831X_DEFAULT_I2C_SLAVE_ADDR, addr, 1, data, read_size,PAH831X_I2C_BUS); + return custom_i2c_read_regs(PAH831X_DEFAULT_I2C_SLAVE_ADDR, addr, 1, data, read_size,PAH831X_I2C_BUS); // if(read_size==2) // { // DEBUG_PRINT("Read { 0x%02X }, Data { 0x%02X, 0x%02x }\n",addr, data[0],data[1]); @@ -49,7 +48,6 @@ pah_ret pah_comm_i2c_read( uint8_t addr, uint8_t *data, size_t read_size) // { // DEBUG_PRINT("Read {0x%02X }, Data { 0x%02x }\n", addr, data[0]); // } - return PAH_RET_SUCCESS; } void pah_delay_ms( uint32_t ms) diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c index 402298954..29603f9ab 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c +++ b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.c @@ -29,6 +29,7 @@ #endif #include "pah831x_factory_test_v3.h" #include "pah_ecg_afib_alg.h" +#include "pah_ecg_bp_alg.h" #include "pah_ecg_raw.h" //============================================================================ // Macro @@ -151,6 +152,9 @@ static uint8_t ppg_work_status = 0 ; static uint8_t ret_hrs = 0; static uint8_t ret_spo2 = 0; static uint8_t ret_hrv = 0; +static uint8_t ret_ecg_afib_hr = 0; +static uint8_t ret_ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; +static uint8_t ret_ecg_bp_status = PAH_ECG_BP_STATUS_MEASURING; static uint8_t ret_wear = 0; static ecg_data_out _ecg_data_out_alg; @@ -1460,6 +1464,9 @@ static void pah831x_ecg_bp_timer_handler(void) CalValue_in , CalValue1_in ); + + ret_ecg_bp_status = pah_ecg_bp_get_status(); + // LOG_PRINT("got_time_out =%d\n",got_time_out); // LOG_PRINT("got_BP =%d\n",got_BP); // LOG_PRINT("_ecg_data_out_alg.is_touched =%d\n",_ecg_data_out_alg.is_touched); @@ -1536,6 +1543,10 @@ static void pah831x_ecg_afib_timer_handler(void) &got_time_out, _ecg_data_out_alg.is_touched ); + + ret_ecg_afib_hr = pah_ecg_afib_get_hr(); + ret_ecg_afib_result = pah_ecg_afib_get_result(); + clear_ecg_data_ready(); } if((get_ecg_enable())!=(ppg_work_status)){ @@ -1740,6 +1751,9 @@ void pah831x_hr_start(void) void pah831x_ecg_bp_start(uint8_t cmd) { + ret_ecg_bp_status = PAH_ECG_BP_STATUS_MEASURING; + ecg_param_init = 0; + if(cmd == 0) { calibration_mode = ECG_PPG_BP_CALI; @@ -1795,6 +1809,8 @@ void pah831x_wear_start(void) void pah831x_ecg_afib_start(void) { + ret_ecg_afib_hr = 0; + ret_ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; pah831x_sensor_init(); pah831x_sensor_start(PAH831X_WORK_POLLING ,PAH831X_INIT_ALWAYS_RUN,PAH831X_PPG_REG_SETTING_IDLE ,PAH831X_ECG_REG_SETTING_1,256,3.91f ); ecg_afib_algorithm_init(); @@ -1841,6 +1857,8 @@ void pah831x_hrv_stop(void) void pah831x_ecgbp_stop(void) { + ret_ecg_bp_status = PAH_ECG_BP_STATUS_MEASURING; + pah_sensor_stop(); ecg_bp_algorithm_close(); @@ -1960,6 +1978,9 @@ void pah831x_sensor_stop(void) ret_spo2 = 0; ret_hrv = 0; ret_wear = 0; + ret_ecg_afib_hr = 0; + ret_ecg_afib_result = PAH_ECG_AFIB_RESULT_INVALID; + ret_ecg_bp_status = PAH_ECG_BP_STATUS_MEASURING; history_wear_status = -1; memset(acc_data, 0, sizeof(acc_data)); @@ -2146,6 +2167,24 @@ uint8_t pah831x_get_hrv(void) return ret_hrv; } +void pah831x_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result) +{ + if (ecg_hr != NULL) { + *ecg_hr = ret_ecg_afib_hr; + } + if (afib_result != NULL) { + *afib_result = ret_ecg_afib_result; + } +} + +void pah831x_get_ecg_bp(int *sbp, int *dbp, uint8_t *status) +{ + pah_ecg_bp_get_bp(sbp, dbp); + if (status != NULL) { + *status = ret_ecg_bp_status; + } +} + uint8_t pah831x_get_wear_status(void) { return ret_wear; diff --git a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h index 6d4c424af..abf20499a 100644 --- a/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h +++ b/code/sdk/zhihui/drivers/ppg/pah831x/pah_sensor/pah831x_main.h @@ -369,6 +369,9 @@ uint8_t pah831x_get_spo2(void); uint8_t pah831x_get_hrv(void); +void pah831x_get_ecg_afib(uint8_t *ecg_hr, uint8_t *afib_result); + +void pah831x_get_ecg_bp(int *sbp, int *dbp, uint8_t *status); void pah8311_get_bp(int *sbp,int *dbp); -- 2.17.1