From: penglei <1624952103@qq.com> Date: Tue, 24 Dec 2024 13:12:24 +0000 (+0800) Subject: 添加u8,l22 底层驱动 X-Git-Url: http://git.snicker.com.cn/?a=commitdiff_plain;h=dbf25246f880193f1acaa67ba0c014b01639d368;p=mirrors%2FFD230.git 添加u8,l22 底层驱动 --- diff --git a/code/sdk/application/brandy/brandy_standard/service_init.c b/code/sdk/application/brandy/brandy_standard/service_init.c index d6ce281ce..37ca92674 100644 --- a/code/sdk/application/brandy/brandy_standard/service_init.c +++ b/code/sdk/application/brandy/brandy_standard/service_init.c @@ -77,6 +77,15 @@ #ifdef CONFIG_OTA_UPDATE_SUPPORT #include "upg.h" #endif +#ifdef SUPPORT_AT_HX3509 +#include "hx3509_at_cmd.h" +#endif +#ifdef SUPPORT_AT_LQBP002TA +#include "lqbp_at_cmd.h" +#endif +#ifdef SUPPORT_AT_CHARGE +#include "charge_at_cmd.h" +#endif static void register_at_service(void) { #ifdef SUPPORT_AT_GRAPHIC @@ -170,6 +179,21 @@ static void register_at_service(void) at_cmd_table_t *rtc_table = get_rtc_cmd_table(&rtc_cmd_count); at_cmd_add_moudle(rtc_table, rtc_cmd_count); #endif +#ifdef SUPPORT_AT_HX3509 + uint32_t hx3509_cmd_count; + at_cmd_table_t *hx3509_table = get_hx3509_cmd_table(&hx3509_cmd_count); + at_cmd_add_moudle(hx3509_table, hx3509_cmd_count); +#endif +#ifdef SUPPORT_AT_LQBP002TA + uint32_t lqbp002ta_cmd_count; + at_cmd_table_t *lqbp002ta_table = get_lqbp002ta_cmd_table(&lqbp002ta_cmd_count); + at_cmd_add_moudle(lqbp002ta_table, lqbp002ta_cmd_count); +#endif +#ifdef SUPPORT_AT_CHARGE + uint32_t charge_cmd_count; + at_cmd_table_t *charge_table = get_charge_cmd_table(&charge_cmd_count); + at_cmd_add_moudle(charge_table, charge_cmd_count); +#endif } #ifdef CONFIG_OTA_UPDATE_SUPPORT diff --git a/code/sdk/application/brandy/brandy_standard/thread_pri_init.c b/code/sdk/application/brandy/brandy_standard/thread_pri_init.c index 9b37131b7..30847a3ed 100644 --- a/code/sdk/application/brandy/brandy_standard/thread_pri_init.c +++ b/code/sdk/application/brandy/brandy_standard/thread_pri_init.c @@ -119,6 +119,10 @@ #include "nv.h" #include "nv_upg.h" +#ifdef ENABLE_LQBP002TA +#include "lqbp_service.h" +#endif + #define EMMC_BASE_ADDR 0x52062000 #define TASK_PRIORITY_APP (osPriority_t)(17) #define TICK_TEN_MS (10U) @@ -514,6 +518,9 @@ uapi_pm_remove_sleep_veto(PM_ID_DEBUG); uapi_cywee_service_init(); #endif + #ifdef ENABLE_LQBP002TA + uapi_lqbp_service_init(); + #endif } #endif diff --git a/code/sdk/build/config/target_config/brandy/config.py b/code/sdk/build/config/target_config/brandy/config.py index df3a3bfaa..7c009aade 100644 --- a/code/sdk/build/config/target_config/brandy/config.py +++ b/code/sdk/build/config/target_config/brandy/config.py @@ -430,7 +430,7 @@ target = { 'FT_SINGLE_UART', # 'WEARABLE_LOG_DEBUG', 'SUPPORT_RC_CALIBRATION', - 'PPG_HX3695', + #'PPG_HX3695', 'VIB_USE_PWM', 'CONFIG_PWM_SUPPORT', # 'ACC_LIS2DOC', @@ -466,6 +466,8 @@ target = { 'SUPPORT_AUTO_OTA_SERVER', 'CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE=1', 'TPTYPE_CST86XX', + 'PPG_VC9202', + 'ROTARYENCODER_HX3507', 'NANDFLASH_DS35X' ], 'ram_component': [ @@ -497,7 +499,10 @@ target = { # "hid_service", "gnss", "gnss_sample", - "cywee" + "cywee", + "lqbp002ta", + "ppg_sensor_vc9202", + "charge_ic" ], 'image_analysis': False, 'fs_image_path':'evb', @@ -532,7 +537,8 @@ target = { 'defines': [ 'BOARD_W9', 'FT_SINGLE_UART', - 'SUPPORT_AUTO_OTA_SERVER', + 'SUPPORT_AUTO_OTA_SERVER', + 'CFG_FLASH_SIZE=8', 'CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE=1', 'TPTYPE_CST86XX', 'GNSS_UART1', @@ -546,6 +552,7 @@ target = { #自定义配置项,选择硬件及功能参数 'defines': [ 'BOARD_W9', + 'CFG_FLASH_SIZE=8', 'FT_SINGLE_UART', 'NANDFLASH_F35UQA' ] @@ -556,6 +563,7 @@ target = { 'defines': [ 'BOARD_W9', 'FT_SINGLE_UART', + 'CFG_FLASH_SIZE=8', 'GPIO_POWERON_FLASH', 'NANDFLASH_F35UQA' ] @@ -567,7 +575,7 @@ target = { 'FT_SINGLE_UART', # 'WEARABLE_LOG_DEBUG', 'SUPPORT_RC_CALIBRATION', - 'PPG_HX3695', + #'PPG_HX3695', 'VIB_USE_PWM', 'CONFIG_PWM_SUPPORT', # 'ACC_LIS2DOC', @@ -603,7 +611,9 @@ target = { 'GPS_CAT1_RESET_TEST', 'TPTYPE_CST86XX', 'TEST_4G_UI', - 'NANDFLASH_F35UQA' + 'NANDFLASH_F35UQA', + 'PPG_VC921X', + 'ROTARYENCODER_HX3509' ], 'ram_component': [ #'baidumapsdk', @@ -634,7 +644,9 @@ target = { # "blemoder", # "factorytest_service", # "hid_service", - "cywee" + "cywee", + "charge_ic", + "ppg_sensor_vc921x", ], 'image_analysis': False, 'fs_image_path':'evb', diff --git a/code/sdk/drivers/boards/brandy_evb/board_config/board_lt22.h b/code/sdk/drivers/boards/brandy_evb/board_config/board_lt22.h index 4b23b3101..ec77f3cd7 100644 --- a/code/sdk/drivers/boards/brandy_evb/board_config/board_lt22.h +++ b/code/sdk/drivers/boards/brandy_evb/board_config/board_lt22.h @@ -11,6 +11,10 @@ #include "gpio_porting.h" #include "platform_types.h" +#ifdef PPG_VC921X +extern void ppg_int_callback(pin_t pin, uintptr_t param); +#endif + /** * @addtogroup connectivity_config_boards @@ -76,9 +80,15 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = { { HAL_PIO_FUNC_EMMC, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_HGPIO14 { HAL_PIO_FUNC_EMMC, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_DISABLE }, // S_HGPIO15 emmc clk #endif + { HAL_PIO_FUNC_SPI0, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO0 NC +#ifdef BOARD_L22 + { HAL_PIO_FUNC_I2C2_M3, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO1 I2C2 SCL Sensor 6è½´ 指南针 心率 + { HAL_PIO_FUNC_I2C2_M3, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO2 I2C2 SDA Sensor +#else { HAL_PIO_FUNC_SPI0, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO1 NC { HAL_PIO_FUNC_SPI0, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO2 NC +#endif { HAL_PIO_FUNC_SPI0, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO3 NC // #if (defined BRANDY_PRODUCT_EVB4) @@ -98,8 +108,13 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = { { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO12 I2C0 SDA { HAL_PIO_FUNC_I2C1_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO13 I2C1 SCL touch i2c { HAL_PIO_FUNC_I2C1_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO14 I2C1 SDA - { HAL_PIO_FUNC_I2C2_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO15 I2C2 SCL Sensor 6è½´ 指南针 心率 - { HAL_PIO_FUNC_I2C2_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO16 I2C2 SDA Sensor +#ifdef BOARD_L22 + { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO15 I2C2 SCL Sensor 6è½´ 指南针 心率 + { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE }, // S_MGPIO16 I2C2 SDA Sensor +#else + { HAL_PIO_FUNC_I2C2_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO15 I2C2 SCL Sensor 6è½´ 指南针 心率 + { HAL_PIO_FUNC_I2C2_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO16 I2C2 SDA Sensor +#endif { HAL_PIO_FUNC_I2C3_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO17 i2c3 SCL smart pa\ 预留马达控制 \安全芯片 { HAL_PIO_FUNC_I2C3_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO18 I2C3 SDA { HAL_PIO_FUNC_UART1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_DISABLE }, // S_MGPIO19 uart1 tx @@ -313,6 +328,9 @@ const hal_gpio_config_t g_gpio_function_config[PIN_MAX_NUMBER] = { /**S_AGPIO_L32 GPO gps reset*/ // { S_AGPIO_L32, HAL_GPIO_DIRECTION_OUTPUT, HAL_GPIO_LEVEL_LOW, 0, NULL }, +#ifdef PPG_VC921X + { S_AGPIO_R6, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, ppg_int_callback}, +#endif }; /** diff --git a/code/sdk/drivers/boards/brandy_evb/board_config/board_u8.h b/code/sdk/drivers/boards/brandy_evb/board_config/board_u8.h index 6387590c3..f188974e3 100644 --- a/code/sdk/drivers/boards/brandy_evb/board_config/board_u8.h +++ b/code/sdk/drivers/boards/brandy_evb/board_config/board_u8.h @@ -11,6 +11,10 @@ #include "gpio_porting.h" #include "platform_types.h" +#ifdef PPG_VC9202 +extern void ppg_int_callback(pin_t pin, uintptr_t param); +#endif + #ifdef ENABLE_CYWEE extern void cywee_int_callback(pin_t pin, uintptr_t param); #endif @@ -313,6 +317,11 @@ const hal_gpio_config_t g_gpio_function_config[PIN_MAX_NUMBER] = { #ifdef SUPPORT_A5133_SERVICE //{ S_AGPIO_L28, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, a5133_cko_isr_callback}, #endif + +#ifdef PPG_VC9202 + { S_AGPIO_R6, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_RISING_EDGE, ppg_int_callback}, +#endif + }; /** * @} diff --git a/code/sdk/zhihui/drivers/CMakeLists.txt b/code/sdk/zhihui/drivers/CMakeLists.txt index 039208b13..db812e45f 100644 --- a/code/sdk/zhihui/drivers/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/CMakeLists.txt @@ -6,6 +6,8 @@ add_subdirectory_if_exist(acc) add_subdirectory_if_exist(mag) add_subdirectory_if_exist(ppg) +add_subdirectory_if_exist(ppg/vc9202) +add_subdirectory_if_exist(ppg/vc921x) add_subdirectory_if_exist(vibrator) add_subdirectory_if_exist(slip) add_subdirectory_if_exist(slip/cat1Service) @@ -14,3 +16,6 @@ add_subdirectory_if_exist(vibrator/service) add_subdirectory_if_exist(cywee) add_subdirectory_if_exist(a5133) add_subdirectory_if_exist(entest) +add_subdirectory_if_exist(barometer) +add_subdirectory_if_exist(charge) +add_subdirectory_if_exist(charge/hp4570) diff --git a/code/sdk/zhihui/drivers/barometer/CMakeLists.txt b/code/sdk/zhihui/drivers/barometer/CMakeLists.txt new file mode 100644 index 000000000..24a0ffc8e --- /dev/null +++ b/code/sdk/zhihui/drivers/barometer/CMakeLists.txt @@ -0,0 +1,44 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "lqbp002ta") + +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/driver/lqbp002ta.c + ${CMAKE_CURRENT_SOURCE_DIR}/service/lqbp_at_cmd.c + ${CMAKE_CURRENT_SOURCE_DIR}/service/lqbp_service.c +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/driver + ${CMAKE_CURRENT_SOURCE_DIR}/service +) +set(PUBLIC_DEFINES + SUPPORT_AT_LQBP002TA + ENABLE_LQBP002TA +) + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS + -Wno-incompatible-function-pointer-types + -Wno-unused-function +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +build_component() \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/barometer/driver/lqbp002ta.c b/code/sdk/zhihui/drivers/barometer/driver/lqbp002ta.c new file mode 100644 index 000000000..930518b46 --- /dev/null +++ b/code/sdk/zhihui/drivers/barometer/driver/lqbp002ta.c @@ -0,0 +1,496 @@ +#include "lqbp002ta.h" +#include "custom_utils.h" +#include "platform_core.h" + +#define LQBP002TA_I2C_BUS I2C_BUS_2 + +static struct LQBP002TA_t LQBP002TA = {0}; +static struct LQBP002TA_t *p_LQBP002TA = NULL; + +void LQBP002TA_write(uint8_t hwadr, uint8_t regadr, uint8_t val); +uint8_t LQBP002TA_read(uint8_t hwadr, uint8_t regadr); +void LQBP002TA_get_calib_param(void); + +/***************************************************************************** + Function: LQBP002TA_write + Description: this function will write data to specofic register through software I2C bus + Input: uint8_t hwadr hardware I2C address + uint8_t regadr register address + uint8_t val write-in value + Output: + Return: + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_write(uint8_t hwadr, uint8_t regadr, uint8_t val) +{ + // SoftI2C_start(); + // SoftI2C_write_byte(hwadr << 1); + // SoftI2C_write_byte(regadr); + // SoftI2C_write_byte(val); + // SoftI2C_stop(); + custom_i2c_write_reg(hwadr, regadr, 1, &val, 1, LQBP002TA_I2C_BUS); +} + +/***************************************************************************** + Function: LQBP002TA_read + Description: this function will read register data through software I2C bus + Input: uint8_t hwadr hardware I2C address + uint8_t regadr register address + Output: + Return: uint8_t readout value + Calls: + Called By: +*****************************************************************************/ +uint8_t LQBP002TA_read(uint8_t hwadr, uint8_t regadr) +{ + uint8_t val = 0; + // SoftI2C_start(); + // SoftI2C_write_byte(hwadr << 1); + // SoftI2C_write_byte(regadr); + // SoftI2C_start(); + // SoftI2C_write_byte((hwadr << 1)|0x01); + // val = SoftI2C_read_byte(1); + // SoftI2C_stop(); + custom_i2c_read_regs(hwadr, regadr, 1, &val, 1, LQBP002TA_I2C_BUS); + return val; +} + +void read_chip_id(void) +{ + p_LQBP002TA->chip_id = LQBP002TA_read(HW_ADR, 0x0D); + //printf("check chip id =0x%x\n",p_LQBP002TA->chip_id); +} + +uint8_t is_LQBP002TA(void) +{ + if(p_LQBP002TA->chip_id == 0x11) + return 1; + else + return 0; +} + +/***************************************************************************** + Function: LQBP002TA_init + Description: initialization + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_init(void) +{ + p_LQBP002TA = &LQBP002TA; /* read Chip Id */ + p_LQBP002TA->i32rawPressure = 0; + p_LQBP002TA->i32rawTemperature = 0; + // p_LQBP002TA->chip_id = 0x11; + read_chip_id(); + + LQBP002TA_get_calib_param(); + // sampling rate = 2Hz; Pressure oversample = 4; + LQBP002TA_rateset(PRESSURE_SENSOR,2, 4); + // sampling rate = 2Hz; Temperature oversample = 2; + LQBP002TA_rateset(TEMPERATURE_SENSOR,2, 2); + //Start background measurement + +} + +/***************************************************************************** + Function: LQBP002TA_rateset + Description: set sample rate and over sample rate per second for specific sensor + Input: uint8_t u8OverSmpl oversample rate Maximal = 128 + uint8_t u8SmplRate sample rate(Hz) Maximal = 128 + uint8_t iSensor 0: Pressure; 1: Temperature + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_rateset(uint8_t iSensor, uint8_t u8SmplRate, uint8_t u8OverSmpl) +{ + uint8_t reg = 0; + int32_t i32kPkT = 0; + switch(u8SmplRate) + { + case 2: + reg |= (1<<4); + break; + case 4: + reg |= (2<<4); + break; + case 8: + reg |= (3<<4); + break; + case 16: + reg |= (4<<4); + break; + case 32: + reg |= (5<<4); + break; + case 64: + reg |= (6<<4); + break; + case 128: + reg |= (7<<4); + break; + case 1: + default: + break; + } + switch(u8OverSmpl) + { + case 2: + reg |= 1; + i32kPkT = 1572864; + break; + case 4: + reg |= 2; + i32kPkT = 3670016; + break; + case 8: + reg |= 3; + i32kPkT = 7864320; + break; + case 16: + i32kPkT = 253952; + reg |= 4; + break; + case 32: + i32kPkT = 516096; + reg |= 5; + break; + case 64: + i32kPkT = 1040384; + reg |= 6; + break; + case 128: + i32kPkT = 2088960; + reg |= 7; + break; + case 1: + default: + i32kPkT = 524288; + break; + } + + if(iSensor == PRESSURE_SENSOR) + { + p_LQBP002TA->i32kP = i32kPkT; + //printf("i32kP : %d \n",p_LQBP002TA->i32kP); + LQBP002TA_write(HW_ADR, 0x06, reg); + if(u8OverSmpl > 8) + { + reg = LQBP002TA_read(HW_ADR, 0x09); + //printf("0x09 : %x \n",reg); + LQBP002TA_write(HW_ADR, 0x09, reg | 0x04); + } + else + { + reg = LQBP002TA_read(HW_ADR, 0x09); + //printf("0x09 : %x \n",reg); + LQBP002TA_write(HW_ADR, 0x09, reg & (~0x04)); + } + } + if(iSensor == TEMPERATURE_SENSOR) + { + p_LQBP002TA->i32kT = i32kPkT; + //printf("i32kT : %d \n",p_LQBP002TA->i32kT); + if(is_LQBP002TA()) + LQBP002TA_write(HW_ADR, 0x07, reg); + else + LQBP002TA_write(HW_ADR, 0x07, reg|0x80); //Using mems temperature + if(u8OverSmpl > 8) + { + reg = LQBP002TA_read(HW_ADR, 0x09); + //printf("0x09 : %x \n",reg); + LQBP002TA_write(HW_ADR, 0x09, reg | 0x08); + } + else + { + reg = LQBP002TA_read(HW_ADR, 0x09); + //printf("0x09 : %x \n",reg); + LQBP002TA_write(HW_ADR, 0x09, reg & (~0x08)); + } + } +} + +/***************************************************************************** + Function: LQBP002TA_get_calib_param + Description: obtain the calibrated coefficient + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_get_calib_param(void) +{ + uint8_t h; + uint8_t m; + uint8_t l; + h = LQBP002TA_read(HW_ADR, 0x10); + l = LQBP002TA_read(HW_ADR, 0x11); + p_LQBP002TA->calib_param.c0 = (int16_t)h<<4 | l>>4; + p_LQBP002TA->calib_param.c0 = (p_LQBP002TA->calib_param.c0&0x0800)?(0xF000|p_LQBP002TA->calib_param.c0):p_LQBP002TA->calib_param.c0; + //printf("0x10 : %x \n",h); + //printf("0x11 : %x \n",l); + //printf("c0 : %d \n",p_LQBP002TA->calib_param.c0); + + h = LQBP002TA_read(HW_ADR, 0x11); + l = LQBP002TA_read(HW_ADR, 0x12); + + p_LQBP002TA->calib_param.c1 = (int16_t)(h&0x0F)<<8 | l; + p_LQBP002TA->calib_param.c1 = (p_LQBP002TA->calib_param.c1&0x0800)?(0xF000|p_LQBP002TA->calib_param.c1):p_LQBP002TA->calib_param.c1; + //printf("0x11 : %x \n",h); + //printf("0x12 : %x \n",l); + //printf("c1 : %d \n",p_LQBP002TA->calib_param.c1); + + h = LQBP002TA_read(HW_ADR, 0x13); + m = LQBP002TA_read(HW_ADR, 0x14); + l = LQBP002TA_read(HW_ADR, 0x15); + p_LQBP002TA->calib_param.c00 = (int32_t)h<<12 | (int32_t)m<<4 | (int32_t)l>>4; + p_LQBP002TA->calib_param.c00 = (p_LQBP002TA->calib_param.c00&0x080000)?(0xFFF00000|p_LQBP002TA->calib_param.c00):p_LQBP002TA->calib_param.c00; + //printf("0x13 : %x \n",h); + //printf("0x14 : %x \n",m); + //printf("0x15 : %x \n",l); + //printf("c00 : %d \n",p_LQBP002TA->calib_param.c00); + + h = LQBP002TA_read(HW_ADR, 0x15); + m = LQBP002TA_read(HW_ADR, 0x16); + l = LQBP002TA_read(HW_ADR, 0x17); + p_LQBP002TA->calib_param.c10 = (int32_t)(h&0x0F)<<16 | (int32_t)m<<8 | l; + p_LQBP002TA->calib_param.c10 = (p_LQBP002TA->calib_param.c10&0x080000)?(0xFFF00000|p_LQBP002TA->calib_param.c10):p_LQBP002TA->calib_param.c10; + //printf("0x15 : %x \n",h); + //printf("0x16 : %x \n",m); + //printf("0x17 : %x \n",l); + //printf("c10 : %d \n",p_LQBP002TA->calib_param.c10); + + h = LQBP002TA_read(HW_ADR, 0x18); + l = LQBP002TA_read(HW_ADR, 0x19); + p_LQBP002TA->calib_param.c01 = (int16_t)h<<8 | l; + //printf("0x18 : %x \n",h); + //printf("0x19 : %x \n",l); + //printf("c01 : %d \n",p_LQBP002TA->calib_param.c01); + + h = LQBP002TA_read(HW_ADR, 0x1A); + l = LQBP002TA_read(HW_ADR, 0x1B); + p_LQBP002TA->calib_param.c11 = (int16_t)h<<8 | l; + //printf("0x1A : %x \n",h); + //printf("0x1B : %x \n",l); + //printf("c11 : %d \n",p_LQBP002TA->calib_param.c11); + + h = LQBP002TA_read(HW_ADR, 0x1C); + l = LQBP002TA_read(HW_ADR, 0x1D); + p_LQBP002TA->calib_param.c20 = (int16_t)h<<8 | l; + //printf("0x1C : %x \n",h); + //printf("0x1D : %x \n",l); + //printf("c20 : %d \n",p_LQBP002TA->calib_param.c20); + + h = LQBP002TA_read(HW_ADR, 0x1E); + l = LQBP002TA_read(HW_ADR, 0x1F); + p_LQBP002TA->calib_param.c21 = (int16_t)h<<8 | l; + //printf("0x1E : %x \n",h); + //printf("0x1F : %x \n",l); + //printf("c21 : %d \n",p_LQBP002TA->calib_param.c21); + + h = LQBP002TA_read(HW_ADR, 0x20); + l = LQBP002TA_read(HW_ADR, 0x21); + p_LQBP002TA->calib_param.c30 = (int16_t)h<<8 | l; + //printf("0x20 : %x \n",h); + //printf("0x21 : %x \n",l); + //printf("c30 : %d \n",p_LQBP002TA->calib_param.c30); + + if(is_LQBP002TA()) + { + h = LQBP002TA_read(HW_ADR, 0x22); + l = LQBP002TA_read(HW_ADR, 0x23); + p_LQBP002TA->calib_param.c31 = (int16_t)h << 4 | l >> 4; + p_LQBP002TA->calib_param.c31 = (p_LQBP002TA->calib_param.c31 & 0x0800) ? (0xF000 | p_LQBP002TA->calib_param.c31) : p_LQBP002TA->calib_param.c31; + //printf("0x22 : %x \n",h); + //printf("0x23 : %x \n",l); + //printf("c31 : %d \n",p_LQBP002TA->calib_param.c31); + h = LQBP002TA_read(HW_ADR, 0x23); + l = LQBP002TA_read(HW_ADR, 0x24); + p_LQBP002TA->calib_param.c40 = (int16_t)(h & 0x0F) << 8 | l; + p_LQBP002TA->calib_param.c40 = (p_LQBP002TA->calib_param.c40 & 0x0800) ? (0xF000 | p_LQBP002TA->calib_param.c40) : p_LQBP002TA->calib_param.c40; + //printf("0x23 : %x \n",h); + //printf("0x24 : %x \n",l); + //printf("c40 : %d \n",p_LQBP002TA->calib_param.c40); + } +} + +/***************************************************************************** + Function: LQBP002TA_start_temperature + Description: start one measurement for temperature + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_start_temperature(void) +{ + LQBP002TA_write(HW_ADR, 0x08, 0x02); +} + +/***************************************************************************** + Function: LQBP002TA_start_pressure + Description: start one measurement for pressure + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ + +void LQBP002TA_start_pressure(void) +{ + LQBP002TA_write(HW_ADR, 0x08, 0x01); +} +/***************************************************************************** + Function: LQBP002TA_start_continuous + Description: Select mode for the continuously measurement + Input: uint8_t mode 1: pressure; 2: temperature; 3: pressure and temperature + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_start_continuous(uint8_t mode) +{ + LQBP002TA_write(HW_ADR, 0x08, mode+4); +} + +void LQBP002TA_stop(void) +{ + LQBP002TA_write(HW_ADR, 0x08, 0); +} + +/***************************************************************************** + Function: LQBP002TA_get_raw_temp + Description:obtain the original temperature value and turn them into 32bits-integer + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_get_raw_temp(void) +{ + uint8_t h,m,l; + + h = LQBP002TA_read(HW_ADR, 0x03); + m = LQBP002TA_read(HW_ADR, 0x04); + l = LQBP002TA_read(HW_ADR, 0x05); + //printf("0x03 : %x \n",h); + //printf("0x04 : %x \n",m); + //printf("0x05 : %x \n",l); + + p_LQBP002TA->i32rawTemperature = (int32_t)h<<16 | (int32_t)m<<8 | (int32_t)l; + p_LQBP002TA->i32rawTemperature= (p_LQBP002TA->i32rawTemperature&0x800000) ? (0xFF000000|p_LQBP002TA->i32rawTemperature) : p_LQBP002TA->i32rawTemperature; + //printf("i32rawTemperature : %d \n",p_LQBP002TA->i32rawTemperature); +} + +/***************************************************************************** + Function: LQBP002TA_get_raw_pressure + Description: obtain the original pressure value and turn them into 32bits-integer + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +void LQBP002TA_get_raw_pressure(void) +{ + uint8_t h,m,l; + + h = LQBP002TA_read(HW_ADR, 0x00); + m = LQBP002TA_read(HW_ADR, 0x01); + l = LQBP002TA_read(HW_ADR, 0x02); + //printf("0x00 : %x \n",h); + //printf("0x01 : %x \n",m); + //printf("0x02 : %x \n",l); + p_LQBP002TA->i32rawPressure = (int32_t)h<<16 | (int32_t)m<<8 | (int32_t)l; + p_LQBP002TA->i32rawPressure= (p_LQBP002TA->i32rawPressure&0x800000) ? (0xFF000000|p_LQBP002TA->i32rawPressure) : p_LQBP002TA->i32rawPressure; + //printf("i32rawPressure : %d \n",p_LQBP002TA->i32rawPressure); +} + +/***************************************************************************** + Function: LQBP002TA_get_temperature + Description: return calibrated temperature value base on original value. + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ +float LQBP002TA_get_temperature(void) +{ + float fTCompensate; + volatile float fTsc = (float)p_LQBP002TA->i32rawTemperature / (float)p_LQBP002TA->i32kT; + //printf("i32rawTemperature : %d , i32kT : %f ,fTsc : %f\n",p_LQBP002TA->i32rawTemperature,(float)p_LQBP002TA->i32kT,fTsc); + fTCompensate = (float)p_LQBP002TA->calib_param.c0 * 0.5f + ((float)p_LQBP002TA->calib_param.c1) * (float)fTsc; + //printf("(float)p_LQBP002TA->calib_param.c0 * 0.5f : %f\n",(float)p_LQBP002TA->calib_param.c0 * 0.5f); + //printf("((float)p_LQBP002TA->calib_param.c1) * fTsc : %f\n",((float)p_LQBP002TA->calib_param.c1) * fTsc); + //printf("fTsc : %f\n",fTsc); + printf("fTCompensate : %f\n",fTCompensate); + return fTCompensate; +} + +/***************************************************************************** + Function: LQBP002TA_get_pressure + Description: return calibrated pressure value base on original value. + Input: void + Output: + Return: void + Calls: + Called By: +*****************************************************************************/ + +float LQBP002TA_get_pressure(void) +{ + float fTsc, fPsc; + float qua2, qua3; + float fPCompensate; + + fTsc = p_LQBP002TA->i32rawTemperature / (float)p_LQBP002TA->i32kT; + fPsc = p_LQBP002TA->i32rawPressure / (float)p_LQBP002TA->i32kP; + qua2 = p_LQBP002TA->calib_param.c10 + fPsc * (p_LQBP002TA->calib_param.c20 + fPsc* (p_LQBP002TA->calib_param.c30+ fPsc * p_LQBP002TA->calib_param.c40)); + + if(is_LQBP002TA()) + qua3 = fTsc * fPsc * (p_LQBP002TA->calib_param.c11 + fPsc * (p_LQBP002TA->calib_param.c21+ fPsc * p_LQBP002TA->calib_param.c31)); + else + qua3 = fTsc * fPsc * (p_LQBP002TA->calib_param.c11 + fPsc * p_LQBP002TA->calib_param.c21); + fPCompensate = p_LQBP002TA->calib_param.c00 + fPsc * qua2 + fTsc * p_LQBP002TA->calib_param.c01 + qua3; + printf("fPCompensate : %f\n",fPCompensate); + return fPCompensate; +} + +uint8_t lqbp002ta_check_exist(void) +{ + read_chip_id(); + return is_LQBP002TA(); +} + +void lqbp002ta_start(void) +{ + LQBP002TA_init(); + LQBP002TA_start_continuous(CONTINUOUS_P_AND_T); +} + +void lqbp002ta_check(void) +{ + float fSplTemp = 0.0f; + float fSplPressure = 0.0f; + LQBP002TA_get_raw_temp(); + LQBP002TA_get_raw_pressure(); + fSplTemp = LQBP002TA_get_temperature(); + fSplPressure = LQBP002TA_get_pressure(); +} + + +void lqbp002ta_stop(void) +{ + LQBP002TA_stop(); +} diff --git a/code/sdk/zhihui/drivers/barometer/driver/lqbp002ta.h b/code/sdk/zhihui/drivers/barometer/driver/lqbp002ta.h new file mode 100644 index 000000000..989afd32a --- /dev/null +++ b/code/sdk/zhihui/drivers/barometer/driver/lqbp002ta.h @@ -0,0 +1,62 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-16 20:03:01 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-17 21:05:56 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/LQBP002TA/driver/lqbp002ta.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE; + */ +#ifndef LQBP002TA_H +#define LQBP002TA_H + +#include "stdint.h" + +#define HW_ADR 0x77 +#define CONTINUOUS_PRESSURE 1 +#define CONTINUOUS_TEMPERATURE 2 +#define CONTINUOUS_P_AND_T 3 +#define PRESSURE_SENSOR 0 +#define TEMPERATURE_SENSOR 1 + + +struct LQBP002TA_calib_param_t { + int16_t c0; + int16_t c1; + int32_t c00; + int32_t c10; + int16_t c01; + int16_t c11; + int16_t c20; + int16_t c21; + int16_t c30; + int16_t c31; + int16_t c40; +}; + +struct LQBP002TA_t { + struct LQBP002TA_calib_param_t calib_param;/**= LQBP002TA_MAX_ARGC) { + return LQBP002TA_FAILED; + } + } else { + argv[*argc][pos] = para[i]; + pos++; + if (pos >= LQBP002TA_MAX_ARGV_LEN) { + return LQBP002TA_FAILED; + } + } + } + if (pos != 0) { + *argc += 1; + } + + return LQBP002TA_SUCCESS; +} + +static uint32_t lqbp002ta_start_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(strCommonCmd); + UNUSED(paraLen); + UNUSED(para); + do_lqbp_service_check_msg(LQBP_SERVICE_CMD_START_CHECK); + return ERRCODE_SUCC; +} +static uint32_t lqbp002ta_stop_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(strCommonCmd); + UNUSED(paraLen); + UNUSED(para); + do_lqbp_service_check_msg(LQBP_SERVICE_CMD_STOP_CHECK); + return ERRCODE_SUCC; +} +static const at_cmd_table_t g_lqbp002ta_cmd[] = { + { (char *)"AT^LQBPTESTSTART", lqbp002ta_start_test, (char *)"1" }, + { (char *)"AT^LQBPTESTSTOP", lqbp002ta_stop_test, (char *)"1" }, +}; + +at_cmd_table_t *get_lqbp002ta_cmd_table(uint32_t *cmd_count) +{ + *cmd_count = ARRAY_COUNT(g_lqbp002ta_cmd); + return (at_cmd_table_t *)g_lqbp002ta_cmd; +} diff --git a/code/sdk/zhihui/drivers/barometer/service/lqbp_at_cmd.h b/code/sdk/zhihui/drivers/barometer/service/lqbp_at_cmd.h new file mode 100644 index 000000000..2c06b3b51 --- /dev/null +++ b/code/sdk/zhihui/drivers/barometer/service/lqbp_at_cmd.h @@ -0,0 +1,40 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-16 20:49:19 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-17 14:25:16 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/LQBP002TA/service/lqbp002ta_at_cmd.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Provides at cmd register func \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-07-20, Create file. \n + */ +#ifndef LQBP002TA_AT_PROCESS_H +#define LQBP002TA_AT_PROCESS_H + +#include +#include +#include "errcode.h" +#include "soc_osal.h" +#include "at_cmd_api.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +at_cmd_table_t *get_lqbp002ta_cmd_table(uint32_t *cmd_count); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif diff --git a/code/sdk/zhihui/drivers/barometer/service/lqbp_service.c b/code/sdk/zhihui/drivers/barometer/service/lqbp_service.c new file mode 100644 index 000000000..82cea70b3 --- /dev/null +++ b/code/sdk/zhihui/drivers/barometer/service/lqbp_service.c @@ -0,0 +1,173 @@ + +#include "debug_print.h" +#include "soc_osal.h" +#include "tcxo.h" +#include "irmalloc.h" +#include "errcode.h" +#include "common_def.h" +#include "tcxo.h" +#include "input_app.h" +#include "cmsis_os2.h" +#include "custom_utils.h" +#include "lqbp002ta.h" +#include "lqbp_service.h" +// #include "custom_runtime.h" +/*** + * 其他cmd在Header里定义,对外开放 +*/ +#define LQBP_SERVICE_CMD_TIMER_CHECK 0x11 + +#define LQBP_CHECK_MS 30 + +static bool g_lqbp_service_initialled = false; + +osTimerId_t g_lqbp_service_timer = NULL; + +static bool g_lqbp_sensor_exist = false; + +static bool g_bat_timer_is_running = false; + +static unsigned long g_app_queue= 0xFFFFFFFF; + +static bool lqbp_service_running_stat = false; + +static void lqbp_service_check_timer_callback(void* data); + +static void lqbp_service_timer_start_check(uint32_t rtc_ms) +{ + + if (g_bat_timer_is_running ) + osTimerStop(g_lqbp_service_timer); + + if (lqbp_service_running_stat == true) + osTimerStart(g_lqbp_service_timer, rtc_ms); + + g_bat_timer_is_running = true; + +} +void do_lqbp_service_check_msg(int cmd); + +static void lqbp_service_check_timer_callback(void * data) +{ + unused(data); + + g_bat_timer_is_running = false; + + if(lqbp_service_running_stat == true){ + // mmc5603_check(); //此处只能直接加到timer callback中,采用queue的话,新能跟不上,系统资源会挂掉。 + do_lqbp_service_check_msg(LQBP_SERVICE_CMD_TIMER_CHECK); + // lqbp_service_timer_start_check(lqbp_CHECK_MS); + } + + + +} +void uapi_lqbp_service_deinit(void) +{ + /* Stop the time and clear the pin map */ + osTimerStop(g_lqbp_service_timer); + osTimerDelete(g_lqbp_service_timer); + + g_bat_timer_is_running = false; + g_lqbp_service_timer = NULL; +} + + + +void do_lqbp_service_check_msg(int cmd) +{ + int ret; + if (g_lqbp_sensor_exist == false) + return ; + common_notify_mail_t mail = {0}; + mail.comm.app = cmd; + ret = osal_msg_queue_write_copy(g_app_queue, (void *)&mail, + sizeof(common_notify_mail_t), 0); + if (ret != OSAL_SUCCESS) { + PRINT("Error lqbp Check MSG 0x%02X send failed! err=0x%x! \r\n",cmd, ret); + } + +} + +static void lqbp_service_check_task(void const *arg) +{ + unused(arg); + int32_t ret; + common_notify_mail_t mail; + uint32_t msgsize = (uint32_t)sizeof(common_notify_mail_t); + while (1) { + ret = osal_msg_queue_read_copy(g_app_queue, (void *)&mail, &msgsize, + OSAL_MSGQ_WAIT_FOREVER); + if (ret != OSAL_SUCCESS) { + continue; + } + + if (mail.comm.app == LQBP_SERVICE_CMD_TIMER_CHECK) { + lqbp002ta_check(); + }else if (mail.comm.app == LQBP_SERVICE_CMD_START_CHECK){ + lqbp002ta_start(); + LOS_Mdelay(30); + lqbp_service_running_stat = true; + lqbp_service_timer_start_check(LQBP_CHECK_MS); + }else if (mail.comm.app == LQBP_SERVICE_CMD_STOP_CHECK){ + lqbp_service_running_stat = false; + osTimerStop(g_lqbp_service_timer); + lqbp002ta_stop(); + LOS_Mdelay(20); + } + + + } +} +void create_lqbp_queue(void) +{ + + if (osal_msg_queue_create("lqbp_service_queue", APP_BOARD_MSG_COUNT, &g_app_queue, + 0, sizeof(common_notify_mail_t)) != ERRCODE_SUCC) { + PRINT("[lqbp][service] app create mail fail\n"); + } +} + +#define LQBP_BOARD_TASK_SIZE 0x1000 +errcode_t uapi_lqbp_service_init(void) +{ + PRINT("uapi_lqbp_service_init !\r\n"); + + if(!lqbp002ta_check_exist()) + { + //TODO 设置气压计检测是否存在标识 + PRINT("lqbp002ta not found!\r\n"); + return ERRCODE_FAIL; + } + g_lqbp_sensor_exist = true; + + app_task_definition_t taskcfg={0}; + taskcfg.create_queue_handle = create_lqbp_queue; + taskcfg.attr.name="lqbp_service"; + taskcfg.attr.priority = osPriorityBelowNormal4; + taskcfg.attr.stack_size = LQBP_BOARD_TASK_SIZE; + taskcfg.func = lqbp_service_check_task; + taskcfg.use_mem = USE_EXTEND_MEM; + + errcode_t ret=uapi_create_osThread_custom(&taskcfg); + if(ret != ERRCODE_SUCC) + { + PRINT("create lqbp_service failed %d!\r\n",ret); + return ERRCODE_FAIL; + } + + g_lqbp_service_timer = osTimerNew((osTimerFunc_t)lqbp_service_check_timer_callback, osTimerPeriodic, NULL, NULL); + + + return ERRCODE_SUCC; +} + +// void lqbp_service_service_resume(void) +// { +// MMC_LOG("lqbp_service_service resume!\r\n"); +// lqbp_service_check_timer_callback(0); +// } +// void lqbp_service_service_suspend(void) +// { +// MMC_LOG("lqbp_service_service suspend!\r\n"); +// } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/barometer/service/lqbp_service.h b/code/sdk/zhihui/drivers/barometer/service/lqbp_service.h new file mode 100644 index 000000000..85ea7f697 --- /dev/null +++ b/code/sdk/zhihui/drivers/barometer/service/lqbp_service.h @@ -0,0 +1,45 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-16 20:48:55 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-17 14:27:18 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/LQBP002TA/service/lqbp002ta_service.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Test adc header \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-08-16, Create file. \n + */ + +#ifndef LQBP_SERVICE_H__ +#define LQBP_SERVICE_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" +#include "errcode.h" + + +#define LQBP_SERVICE_CMD_START_CHECK 0x12 +#define LQBP_SERVICE_CMD_STOP_CHECK 0x13 + +errcode_t uapi_lqbp_service_init(void); +void uapi_lqbp_service_deinit(void); +void do_lqbp_service_check_msg(int cmd); + + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/charge/CMakeLists.txt b/code/sdk/zhihui/drivers/charge/CMakeLists.txt new file mode 100644 index 000000000..b100dae71 --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/CMakeLists.txt @@ -0,0 +1,46 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "charge_ic") + +set(SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/hp4570/hp4570.c + ${CMAKE_CURRENT_SOURCE_DIR}/service/charge_at_cmd.c + ${CMAKE_CURRENT_SOURCE_DIR}/service/charge_service.c +) + +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/hp4570/ + ${CMAKE_CURRENT_SOURCE_DIR}/service/ + +) + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES + TARGET_NAME="${TARGET_COMMAND}" + BUILD_TIME="${BUILD_TIME}" +) + +set(PUBLIC_DEFINES +SUPPORT_AT_CHARGE +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +build_component() diff --git a/code/sdk/zhihui/drivers/charge/hp4570/hp4570.c b/code/sdk/zhihui/drivers/charge/hp4570/hp4570.c new file mode 100644 index 000000000..be4a803c8 --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/hp4570/hp4570.c @@ -0,0 +1,766 @@ +#include "hp4570.h" +#include "custom_utils.h" +#include "platform_core.h" + + +#define INPUT_PARA_FAIL_RETURN(value, min, max) \ + do { \ + if (value < min || value > max) \ + return INVALID_INPUT; \ + } while (0) + +#define INVALID_INPUT_RETURN(value, index, array, array_size) \ + do { \ + for(index = 0 ; index < array_size; index++){ \ + if(value == array[index]) \ + break; \ + } \ + if(index == array_size) \ + return INVALID_INPUT; \ + } while (0) + +#define SET_BIT(value, mask, code, shift) \ + do { \ + value &= ~mask; \ + value |= (code << shift); \ + } while (0) + +#define SET_ENABLE(en, value, mask, en_code, shift) \ + do { \ + if (en) \ + SET_BIT(value, mask, en_code, shift); \ + else \ + SET_BIT(value, mask, !en_code, shift); \ + } while (0) + + +struct CHIP_STATE{ + bool vin_fault; + bool tshut; + bool vbat_ovp; + bool safety_mode; + bool ntc_hot; + bool ntc_cold; +}hp45xxx_chip_state; + +uint8_t hp45xxx_i2c_addr = 0; + +#define SUCCESS 0 +#define FAIL 1 +#define I2C_ERROR 1 +#define INVALID_INPUT 1 + +#ifdef BOARD_L22 +#define HP4570_I2C_BUS I2C_BUS_0 +#elif defined BOARD_U8 +#define HP4570_I2C_BUS I2C_BUS_3 +#endif + +bool hp45xxx_write_reg(uint8_t reg, uint8_t value) +{ + return custom_i2c_write_reg(hp45xxx_i2c_addr, reg, 1, &value, 1, HP4570_I2C_BUS); + +} + +bool hp45xxx_read_reg(uint8_t reg, uint8_t *value) +{ + return custom_i2c_read_regs(hp45xxx_i2c_addr, reg, 1, value, 1, HP4570_I2C_BUS); +} + +// Initialize HP4570 chip +bool hp45xxx_init(uint8_t chip_ver){ + switch (chip_ver){ + case HP4570K: + hp45xxx_i2c_addr = HP4570K_I2C_ADDR; + break; + default: + hp45xxx_i2c_addr = HP45XXX_I2C_ADDR; + break; + } + if(hp45xxx_identify(chip_ver) != SUCCESS) + { + printf("hp45xxx_identify(chip_ver) failed !!!! \n"); + return FAIL; + } + printf("hp45xxx_identify(chip_ver) succed !!!! \n"); + // hp45xxx_reg_rst(); + // Add initialization code here, such as configuring registers + hp45xxx_set_ceb_en(true); + if( hp45xxx_set_chrg_vbat_mV(4012.5) + // && + // hp45xxx_set_chrg_ipre_mA(34) && + // hp45xxx_set_chrg_ichg_mA(200) && + // hp45xxx_set_chrg_iterm_mA(34) && + // hp45xxx_set_iindpm_mA(1000) && + // hp45xxx_set_vin_min_mV(3800) + ) + return SUCCESS; + return FAIL; +} + +bool hp45xxx_identify(uint8_t chip_ver){ + uint8_t vid_value[2]; + uint8_t pid_value[2]; + uint8_t chip_ver_value; + hp45xxx_read_reg(HP45XXX_REG_VID_LSB, &vid_value[0]); + hp45xxx_read_reg(HP45XXX_REG_VID_MSB, &vid_value[1]); + hp45xxx_read_reg(HP45XXX_REG_PID_LSB, &pid_value[0]); + hp45xxx_read_reg(HP45XXX_REG_PID_MSB, &pid_value[1]); + hp45xxx_read_reg(HP45XXX_REG_CHIP_VER, &chip_ver_value); + // printf("vid_value[0] : 0x%x , vid_value[1] : 0x%x , pid_value[0] : 0x%x,pid_value[1] : 0x%x chip_ver_value : 0x%x\n",vid_value[0],vid_value[1],pid_value[0],pid_value[1],chip_ver_value); + if((vid_value[0]!=HP45XXX_REG_VID_LSB_DEF)|| + (vid_value[1]!=HP45XXX_REG_VID_MSB_DEF)|| + (pid_value[0]!=HP45XXX_REG_PID_LSB_DEF)|| + (pid_value[1]!=HP45XXX_REG_PID_MSB_DEF)|| + (chip_ver_value != chip_ver)) + return FAIL; + return SUCCESS; +} + +void hp45xxx_entry_shipmode(void){ + hp45xxx_set_batfet_dis(true); +} + +void hp45xxx_reg_rst(void){ + // Write 1 will auto be 0 + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1, HP45XXX_REG_RST_RESET << HP45XXX_REG_RST_BIT_SHIFT); +} + +void hp45xxx_wdt_rst(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL1, &value); + // Write 1 will auto be 0 and timer will reset,after watchdog fault,Only write 1 will restart timer + SET_BIT(value, HP45XXX_WDT_RST_MASK, HP45XXX_WDT_RST_RESET, HP45XXX_WDT_RST_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1,value); +} + +void hp45xxx_vsys_rst(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL5, &value); + SET_BIT(value, HP45XXX_VSYS_RST_MASK, HP45XXX_VSYS_RST_RESET, HP45XXX_VSYS_RST_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5,value); +} + +bool hp45xxx_set_vindpm_mV(uint16_t voltage){ + uint8_t value; + uint8_t vin_min_code; + INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VIN_MIN_MIN_mV,HP45XXX_VIN_MIN_MAX_mV); + hp45xxx_read_reg(HP45XXX_REG_DPM_SET, &value); + vin_min_code = (uint8_t)((voltage - HP45XXX_VIN_MIN_OFFSET_mV)/HP45XXX_VIN_MIN_STEP_mV); + SET_BIT(value, HP45XXX_VIN_MIN_MASK, vin_min_code, HP45XXX_VIN_MIN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_DPM_SET, value); + return SUCCESS; +} + +bool hp45xxx_set_iindpm_mA(uint16_t current){ + uint8_t value; + uint8_t iindpm_code; + INPUT_PARA_FAIL_RETURN(current,HP45XXX_IINDPM_MIN_mA,HP45XXX_IINDPM_MAX_mA); + hp45xxx_read_reg(HP45XXX_REG_DPM_SET, &value); + iindpm_code = (uint8_t)((current - HP45XXX_IINDPM_OFFSET_mA)/HP45XXX_IINDPM_STEP_mA); + SET_BIT(value, HP45XXX_IINDPM_MASK, iindpm_code, HP45XXX_IINDPM_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_DPM_SET, value); + return SUCCESS; +} + +bool hp45xxx_set_trst_dgl_mS(uint32_t time){ + uint8_t value; + uint8_t trst_dgl_code; + INVALID_INPUT_RETURN(time, trst_dgl_code, hp45xxx_trst_dgl_time, HP45XXX_NUM_TRST_DGL_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value); + SET_BIT(value, HP45XXX_TRST_DGL_MASK, trst_dgl_code, HP45XXX_TRST_DGL_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0, value); + return SUCCESS; +} + +bool hp45xxx_set_trst_dur_mS(uint16_t time){ + uint8_t value; + uint8_t trst_dur_code; + INVALID_INPUT_RETURN(time, trst_dur_code, hp45xxx_trst_dur_time, HP45XXX_NUM_TRST_DUR_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value); + SET_BIT(value, HP45XXX_TRST_DUR_MASK, trst_dur_code, HP45XXX_TRST_DUR_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0,value); + return SUCCESS; +} + +void hp45xxx_set_hiz_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value); + SET_ENABLE(en, value, HP45XXX_EN_HIZ_MASK, HP45XXX_EN_HIZ_ENABLE, HP45XXX_EN_HIZ_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0,value); +} + +void hp45xxx_set_ceb_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value); + SET_ENABLE(en, value, HP45XXX_CEB_MASK, HP45XXX_CEB_ENABLE, HP45XXX_CEB_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0, value); +} + +bool hp45xxx_set_vbat_uvlo_mV(uint16_t voltage){ + uint8_t value; + uint8_t vbat_uvlo_code; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value); + INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VBAT_UVLO_MIN_mV,HP45XXX_VBAT_UVLO_MAX_mV); + vbat_uvlo_code = (uint8_t)((voltage - HP45XXX_VBAT_UVLO_OFFSET_mV)/HP45XXX_VBAT_UVLO_STEP_mV); + SET_BIT(value, HP45XXX_VBAT_UVLO_MASK, vbat_uvlo_code, HP45XXX_VBAT_UVLO_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0, value); + return SUCCESS; +} + +bool hp45xxx_set_chrg_ichg_mA(uint16_t current){ + uint8_t value; + uint8_t ichg_code; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL1, &value); + INPUT_PARA_FAIL_RETURN(current,HP45XXX_ICHG_MIN_mA,HP45XXX_ICHG_MAX_mA); + ichg_code = (uint8_t)((current - HP45XXX_ICHG_OFFSET_mA)/HP45XXX_ICHG_STEP_mA); + SET_BIT(value, HP45XXX_ICHG_MASK, ichg_code, HP45XXX_ICHG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1, value); + return SUCCESS; +} + +bool hp4570i_set_chrg_ichg_mA(uint16_t current){ + uint8_t value; + uint8_t ichg_code; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL1, &value); + INPUT_PARA_FAIL_RETURN(current,HP4570I_ICHG_MIN_mA,HP4570I_ICHG_MAX_mA); + ichg_code = (uint8_t)((current - HP4570I_ICHG_OFFSET_mA)/HP4570I_ICHG_STEP_mA); + SET_BIT(value, HP45XXX_ICHG_MASK, ichg_code, HP45XXX_ICHG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1, value); + return SUCCESS; +} + +bool hp45xxx_set_ibatfet_ocp_mA(uint16_t current){ + uint8_t value; + uint8_t ibatfet_ocp_code; + hp45xxx_read_reg(HP45XXX_REG_IDSG_ITERM_SET, &value); + INPUT_PARA_FAIL_RETURN(current,HP45XXX_IBATFET_OCP_MIN_mA,HP45XXX_IBATFET_OCP_MAX_mA); + ibatfet_ocp_code = (uint8_t)((current - HP45XXX_IBATFET_OCP_OFFSET_mA)/HP45XXX_IBATFET_OCP_STEP_mA); + SET_BIT(value, HP45XXX_IBATFET_OCP_MASK, ibatfet_ocp_code, HP45XXX_IBATFET_OCP_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_IDSG_ITERM_SET,value); + return SUCCESS; +} + +bool hp45xxx_set_chrg_iterm_mA(uint8_t current){ + uint8_t value; + uint8_t iterm_code; + hp45xxx_read_reg(HP45XXX_REG_IDSG_ITERM_SET, &value); + INPUT_PARA_FAIL_RETURN(current,HP45XXX_ITERM_MIN_mA,HP45XXX_ITERM_MAX_mA); + iterm_code = (uint8_t)((current - HP45XXX_ITERM_OFFSET_mA)/HP45XXX_ITERM_STEP_mA); + SET_BIT(value, HP45XXX_ITERM_MASK, iterm_code, HP45XXX_ITERM_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_IDSG_ITERM_SET,value); + return SUCCESS; +} + +bool hp45xxx_set_chrg_vbat_mV(float voltage){ + uint8_t value; + uint8_t vbatreg_code; + hp45xxx_read_reg(HP45XXX_REG_BAT_VOL_SET, &value); + INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VBATREG_MIN_mV,HP45XXX_VBATREG_MAX_mV); + vbatreg_code = (uint8_t)((voltage - HP45XXX_VBATREG_OFFSET_mV)/HP45XXX_VBATREG_STEP_mV); + SET_BIT(value, HP45XXX_VBATREG_MASK, vbatreg_code, HP45XXX_VBATREG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_BAT_VOL_SET,value); + return SUCCESS; +} + +bool hp45xxx_set_chrg_vpre_mV(uint8_t voltage){ + uint8_t value0; + uint8_t value1; + uint8_t vbat_pre_code; + INVALID_INPUT_RETURN(voltage, vbat_pre_code, hp45xxx_vbat_pre_voltage, HP45XXX_NUM_VBAT_PRE_VAL); + hp45xxx_read_reg(HP45XXX_REG_BAT_VOL_SET, value0); + hp45xxx_read_reg(HP45XXX_REG_VIPRE, value1); + SET_BIT(value0, HP45XXX_VBAT_PRE_0_MASK, (vbat_pre_code & 0x1), HP45XXX_VBAT_PRE_0_BIT_SHIFT); + SET_BIT(value1, HP45XXX_VBAT_PRE_1_MASK, (vbat_pre_code & 0x2)>>1, HP45XXX_VBAT_PRE_1_BIT_SHIFT); + (hp45xxx_write_reg(HP45XXX_REG_BAT_VOL_SET,value0) & hp45xxx_write_reg(HP45XXX_REG_VIPRE,value1)); + return SUCCESS; +} + +bool hp45xxx_set_chrg_vre_mV(uint8_t voltage){ + uint8_t value; + uint8_t vre_chg_code; + INVALID_INPUT_RETURN(voltage, vre_chg_code, hp45xxx_vre_chg_voltage, HP45XXX_NUM_VRE_CHG_VAL); + hp45xxx_read_reg(HP45XXX_REG_BAT_VOL_SET, &value); + SET_BIT(value, HP45XXX_VRE_CHG_MASK, vre_chg_code, HP45XXX_VRE_CHG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_BAT_VOL_SET,value); + return SUCCESS; +} + +void hp45xxx_set_wdt_dsg_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + SET_ENABLE(en, value, HP45XXX_EN_WDT_DSG_MASK, HP45XXX_EN_WDT_DSG_ENABLE, HP45XXX_EN_WDT_DSG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value); +} + +void hp45xxx_set_wdt_timer_en(bool en){ + uint8_t value; + uint32_t wdt_timer_code; + if(!en) + hp45xxx_set_wdt_timer_mS(HP45XXX_WDT_TIMER_DIS); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + value &= HP45XXX_WDT_TIMER_MASK; + if(value >> HP45XXX_WDT_TIMER_BIT_SHIFT == HP45XXX_WDT_TIMER_DIS) + // do nothing + return; + wdt_timer_code = (HP45XXX_REG_SYS_CTRL2_DEF & HP45XXX_WDT_TIMER_MASK) >> HP45XXX_WDT_TIMER_BIT_SHIFT; + SET_BIT(value, HP45XXX_WDT_TIMER_MASK, wdt_timer_code, HP45XXX_WDT_TIMER_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2,value); +} + +bool hp45xxx_set_wdt_timer_mS(uint32_t time){ + uint8_t value; + uint8_t wdt_timer_code; + INVALID_INPUT_RETURN(time, wdt_timer_code, hp45xxx_watchdog_time, HP45XXX_NUM_WDT_TIMER_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + SET_BIT(value, HP45XXX_WDT_TIMER_MASK, wdt_timer_code, HP45XXX_WDT_TIMER_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2,value); + return SUCCESS; +} + +void hp45xxx_set_chrg_term_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + SET_ENABLE(en, value, HP45XXX_EN_TERM_MASK, HP45XXX_EN_TERM_ENABLE, HP45XXX_EN_TERM_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value); +} + +void hp45xxx_set_chrg_timer_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + SET_ENABLE(en, value, HP45XXX_EN_TIMER_MASK, HP45XXX_EN_TIMER_ENABLE, HP45XXX_EN_TIMER_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value); +} + +bool hp45xxx_set_chrg_timer_hour(uint8_t time){ + uint8_t value; + uint8_t chg_timer_code; + INVALID_INPUT_RETURN(time, chg_timer_code, hp45xxx_fast_chg_time, HP45XXX_NUM_CHG_TIMER_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + SET_BIT(value, HP45XXX_CHG_TIMER_MASK, chg_timer_code, HP45XXX_CHG_TIMER_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2,value); + return SUCCESS; +} + +// when TERM_TMR is enabled, the IC will not suspend the charge current after the charge termination +void hp45xxx_set_chrg_term_tmr(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value); + SET_ENABLE(en, value, HP45XXX_TERM_TMR_MASK, HP45XXX_TERM_TMR_ENABLE, HP45XXX_TERM_TMR_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value); +} + +void hp45xxx_set_ntc_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_NTC_EN_MASK, HP45XXX_NTC_EN_ENABLE, HP45XXX_NTC_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +void hp45xxx_set_chrg_tmr2x_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_TMR2X_EN_MASK, HP45XXX_TMR2X_EN_ENABLE, HP45XXX_TMR2X_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +// when set 1, enter ship mode w/o vbus, the bit will be set to 0 after exiting ship mode +bool hp45xxx_set_batfet_dis(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_BATFET_DIS_MASK, HP45XXX_BATFET_DIS_ENABLE, HP45XXX_BATFET_DIS_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); + return SUCCESS; +} + +void hp45xxx_set_int_pg_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_PG_INT_CONTROL_MASK, HP45XXX_PG_INT_CONTROL_ENABLE, HP45XXX_PG_INT_CONTROL_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +void hp45xxx_set_int_chrg_done_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_CHG_DONE_INT_EN_MASK, HP45XXX_CHG_DONE_INT_EN_ENABLE, HP45XXX_CHG_DONE_INT_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +// Include: not charge to CC, Pre into CC ,CC into CV, not charge into CC(Auto recharge) +void hp45xxx_set_int_chrg_stat_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_CHG_STAT_INT_EN_MASK, HP45XXX_CHG_STAT_INT_EN_ENABLE, HP45XXX_CHG_STAT_INT_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +void hp45xxx_set_int_ntc_transition_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_NTC_TRANSITION_EN_MASK, HP45XXX_NTC_TRANSITION_EN_ENABLE, HP45XXX_NTC_TRANSITION_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +void hp45xxx_set_int_batovp_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value); + SET_ENABLE(en, value, HP45XXX_BATOVP_INT_EN_MASK, HP45XXX_BATOVP_INT_EN_ENABLE, HP45XXX_BATOVP_INT_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value); +} + +void hp45xxx_set_pcb_otp_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value); + SET_ENABLE(en, value, HP45XXX_EN_PCB_OTP_MASK, HP45XXX_EN_PCB_OTP_ENABLE, HP45XXX_EN_PCB_OTP_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4, value); +} + +void hp45xxx_set_vindpm_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value); + SET_ENABLE(en, value, HP45XXX_VINDPM_EN_MASK, HP45XXX_VINDPM_EN_ENABLE, HP45XXX_VINDPM_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4, value); +} + +bool hp45xxx_set_thermal_reg_degree(uint8_t degree){ + uint8_t value; + uint8_t thermal_reg_code; + INVALID_INPUT_RETURN(degree, thermal_reg_code, hp45xxx_thermal_reg_degree, HP45XXX_NUM_THERMAL_REG_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value); + SET_BIT(value, HP45XXX_THERMAL_REG_MASK, thermal_reg_code, HP45XXX_THERMAL_REG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4, value); + return SUCCESS; +} + +bool hp45xxx_set_vsys_reg_mV(float voltage){ + uint8_t value; + uint8_t vsys_reg_code; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value); + INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VSYS_REG_MIN_mV,HP45XXX_VSYS_REG_MAX_mV); + vsys_reg_code = (uint8_t)((voltage - HP45XXX_VSYS_REG_OFFSET_mV)/HP45XXX_VSYS_REG_STEP_mV); + SET_BIT(value, HP45XXX_VSYS_REG_MASK, vsys_reg_code, HP45XXX_VSYS_REG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4,value); + return SUCCESS; +} + +bool hp45xxx_set_ship_dgl_mS(uint16_t time){ + uint8_t value; + uint8_t ship_dgl_code; + INVALID_INPUT_RETURN(time, ship_dgl_code, hp45xxx_ship_dgl_time, HP45XXX_NUM_SHIP_DGL_VAL); + SET_BIT(value, HP45XXX_SHIP_DGL_MASK, ship_dgl_code, HP45XXX_SHIP_DGL_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_CHIP_STAT1, value); + return SUCCESS; +} + +bool hp45xxx_set_vin_exit_ship_tset_mS(uint16_t time){ + uint8_t value; + uint8_t in_exit_ship_tset_code; + INVALID_INPUT_RETURN(time, in_exit_ship_tset_code, hp45xxx_ship_dgl_time, HP45XXX_NUM_IN_EXIT_SHIP_TSET_VAL); + hp45xxx_read_reg(HP45XXX_REG_VIPRE, &value); + SET_BIT(value, HP45XXX_IN_EXIT_SHIP_TSET_MASK, in_exit_ship_tset_code, HP45XXX_IN_EXIT_SHIP_TSET_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_VIPRE, value); + return SUCCESS; +} + +bool hp45xxx_set_chrg_ipre_mA(uint16_t current){ + uint8_t value; + uint8_t ipre_code; + hp45xxx_read_reg(HP45XXX_REG_VIPRE, &value); + INPUT_PARA_FAIL_RETURN(current,HP45XXX_IPRE_MIN_mA,HP45XXX_IPRE_MAX_mA); + ipre_code = (uint8_t)((current - HP45XXX_IPRE_OFFSET_mA)/HP45XXX_IPRE_STEP_mA); + SET_BIT(value, HP45XXX_IPRE_MASK, ipre_code, HP45XXX_IPRE_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_VIPRE,value); + return SUCCESS; +} + +void hp45xxx_set_rst_vin_entry_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_EXT_CTRL, &value); + SET_ENABLE(en, value, HP45XXX_VINDPM_EN_MASK, HP45XXX_VIN_ENTRY_RST_EN_ENABLE, HP45XXX_VIN_ENTRY_RST_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_EXT_CTRL, value); +} + +bool hp45xxx_set_chrg_idead_mA(uint16_t current){ + uint8_t value; + uint8_t ideadbat_code; + hp45xxx_read_reg(HP45XXX_REG_EXT_CTRL, &value); + INPUT_PARA_FAIL_RETURN(current,HP45XXX_IDEADBAT_MIN_mA,HP45XXX_IDEADBAT_MAX_mA); + ideadbat_code = (uint8_t)((current - HP45XXX_IDEADBAT_OFFSET_mA)/HP45XXX_IDEADBAT_STEP_mA); + SET_BIT(value, HP45XXX_IDEADBAT_MASK, ideadbat_code, HP45XXX_IDEADBAT_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_EXT_CTRL,value); + return SUCCESS; +} + +bool hp45xxx_set_en_iindpm_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_EXT_CTRL, &value); + SET_ENABLE(en, value, HP45XXX_EN_IINDPM_MASK, HP45XXX_EN_IINDPM_ENABLE, HP45XXX_EN_IINDPM_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5, value); + return SUCCESS; +} + +bool hp45xxx_set_key_wk_time_mS(uint16_t time){ + uint8_t value; + uint8_t key_wk_set_code; + INVALID_INPUT_RETURN(time, key_wk_set_code, hp45xxx_key_wk_set_time, HP45XXX_NUM_KEY_WK_SET_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL5, &value); + SET_BIT(value, HP45XXX_KEY_WK_SET_MASK, key_wk_set_code, HP45XXX_KEY_WK_SET_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5, value); + return SUCCESS; +} + +bool hp45xxx_set_t_hiccup_mS(uint16_t time){ + uint8_t value; + uint8_t t_hiccup_code; + INVALID_INPUT_RETURN(time, t_hiccup_code, hp45xxx_key_wk_set_time, HP45XXX_NUM_T_HICCUP_VAL); + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL5, &value); + SET_BIT(value, HP45XXX_T_HICCUP_MASK, t_hiccup_code, HP45XXX_T_HICCUP_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5, value); + return SUCCESS; +} + +void hp45xxx_set_wdt_vsys_rst_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL6, &value); + SET_ENABLE(en, value, HP45XXX_WDT_VSYS_RST_MASK, HP45XXX_WDT_VSYS_RST_ENABLE, HP45XXX_WDT_VSYS_RST_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL6, value); +} + +void hp45xxx_set_ship_dgl_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL6, &value); + SET_ENABLE(en, value, HP45XXX_EN_SHIP_DGL_MASK, HP45XXX_EN_SHIP_DGL_ENABLE, HP45XXX_EN_SHIP_DGL_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL6, value); +} + +void hp45xxx_set_wdt_chg_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value); + SET_ENABLE(en, value, HP45XXX_EN_WDT_CHG_MASK, HP45XXX_EN_WDT_CHG_ENABLE, HP45XXX_EN_WDT_CHG_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value); +} + +void hp45xxx_set_rst_pwrkey_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value); + SET_ENABLE(en, value, HP45XXX_EN_PWRKEY_RST_MASK, HP45XXX_EN_PWRKEY_RST_ENABLE, HP45XXX_EN_PWRKEY_RST_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value); +} + +void hp45xxx_set_rst_vsys_wvbus_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value); + SET_ENABLE(en, value, HP45XXX_VSYS_RST_WVBUS_MASK, HP45XXX_VSYS_RST_WVBUS_ENABLE, HP45XXX_VSYS_RST_WVBUS_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value); +} + +void hp45xxx_set_pwrkey_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value); + SET_ENABLE(en, value, HP45XXX_PWRKEY_EN_MASK, HP45XXX_PWRKEY_EN_ENABLE, HP45XXX_PWRKEY_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value); +} + +void hp45xxx_set_vbus_wk_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value); + SET_ENABLE(en, value, HP45XXX_VBUS_WK_EN_MASK, HP45XXX_VBUS_WK_EN_ENABLE, HP45XXX_VBUS_WK_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value); +} + +void hp45xxx_set_pwrkey_wk_en(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value); + if(en){ + SET_BIT(value, HP45XXX_PWRKEY_WK_EN_MASK, HP45XXX_PWRKEY_WK_EN_ENABLE, HP45XXX_PWRKEY_WK_EN_BIT_SHIFT); + // Note: bit 2 must be 1 + value |= (HP45XXX_PWRKEY_EN_ENABLE << HP45XXX_PWRKEY_EN_BIT_SHIFT); + }else + SET_BIT(value, HP45XXX_PWRKEY_WK_EN_MASK, !HP45XXX_PWRKEY_WK_EN_ENABLE, HP45XXX_PWRKEY_WK_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value); +} + +bool hp45xxx_set_watchdog_int_enable(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_INT0_ENABLE, &value); + SET_ENABLE(en, value, HP45XXX_WATCHDOG_INT_EN_MASK, HP45XXX_WATCHDOG_INT_EN_ENABLE, HP45XXX_WATCHDOG_INT_EN_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_INT0_ENABLE, value); + return SUCCESS; +} + +bool hp45xxx_set_chg_safety_expired_enable(bool en){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_INT0_ENABLE, &value); + SET_ENABLE(en, value, HP45XXX_CHG_SAFETY_EXPIRED_MASK, HP45XXX_CHG_SAFETY_EXPIRED_ENABLE, HP45XXX_CHG_SAFETY_EXPIRED_BIT_SHIFT); + hp45xxx_write_reg(HP45XXX_REG_INT0_ENABLE, value); + return SUCCESS; +} + +bool hp45xxx_read_status_wdt_fault(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return (value & HP45XXX_WDT_FAULT_MASK) ? true : false; +} + +bool hp45xxx_read_chrg_stat_not_chrg(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_NOT_CHRG) ? true : false; +} + +bool hp45xxx_read_chrg_stat_dead_chrg(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_DEAD_CHRG) ? true : false; +} + +bool hp45xxx_read_chrg_stat_pre_chrg(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_PRE_CHRG) ? true : false; +} + +bool hp45xxx_read_chrg_stat_fast_chrg(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_FAST_CHRG) ? true : false; +} + +bool hp45xxx_read_chrg_stat_chrg_done(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_CHRG_DONE) ? true : false; +} + +bool hp45xxx_read_status_vindpm(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return (value & HP45XXX_VIN_DPM_STAT_MASK) ? true : false; +} + +bool hp45xxx_read_status_vbus_pg(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return (value & HP45XXX_VBUS_PG_STAT_MASK) ? true : false; +} + +bool hp45xxx_read_status_thermal(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value); + return (value & HP45XXX_THERM_STAT_MASK) ? true : false; +} + +void hp45xxx_update_status_chip_stat1(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT1, &value); + if(value & HP45XXX_VIN_FAULT_MASK) + hp45xxx_chip_state.vin_fault |= true; + if(value & HP45XXX_TSHUT_MASK) + hp45xxx_chip_state.tshut |= true; + if(value & HP45XXX_VBAT_OVP_MASK) + hp45xxx_chip_state.vbat_ovp |= true; + if(value & HP45XXX_SAFETY_MODE_MASK) + hp45xxx_chip_state.safety_mode |= true; + hp45xxx_chip_state.ntc_hot = (value & HP45XXX_NTC_HOT_MASK) ? true : false; + hp45xxx_chip_state.ntc_cold = (value & HP45XXX_NTC_COLD_MASK) ? true : false; +} + +void hp45xxx_clear_status_chip_stat1(void){ + hp45xxx_chip_state.vin_fault = false; + hp45xxx_chip_state.tshut = false; + hp45xxx_chip_state.vbat_ovp = false; + hp45xxx_chip_state.safety_mode = false; +} + +bool hp45xxx_read_status_vin_fault(void){ + hp45xxx_update_status_chip_stat1(); + return hp45xxx_chip_state.vin_fault; +} + +bool hp45xxx_read_status_tshut(void){ + hp45xxx_update_status_chip_stat1(); + return hp45xxx_chip_state.tshut; +} + +bool hp45xxx_read_status_vbat_ovp(void){ + hp45xxx_update_status_chip_stat1(); + return hp45xxx_chip_state.vbat_ovp; +} + +bool hp45xxx_read_status_safety_mode(void){ + hp45xxx_update_status_chip_stat1(); + return hp45xxx_chip_state.safety_mode; +} + +bool hp45xxx_read_status_ntc_hot(void){ + hp45xxx_update_status_chip_stat1(); + return hp45xxx_chip_state.ntc_hot; +} + +bool hp45xxx_read_status_ntc_cold(void){ + hp45xxx_update_status_chip_stat1(); + return hp45xxx_chip_state.ntc_cold; +} + +bool hp45xxx_read_status_iindpm(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT2, &value); + return (value & HP45XXX_IIN_DPM_STAT_MASK) ? true : false; +} + +bool hp45xxx_read_status_vin_entry_rst(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value); + if(value & HP45XXX_ENTRY_RST_STAT_MASK){ + hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_ENTRY_RST_STAT_MASK); + return true; + } + return false; +} + +bool hp45xxx_read_status_pwrkey_rst(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value); + if(value & HP45XXX_PWRKEY_RST_STAT_MASK){ + hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_PWRKEY_RST_STAT_MASK); + return true; + } + return false; +} + +bool hp45xxx_read_status_hiccup_latch(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value); + if(value & HP45XXX_HICCUP_LATCH_STAT_MASK){ + hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_HICCUP_LATCH_STAT_MASK); + return true; + } + return false; +} + +bool hp45xxx_read_status_pwrkey_wk(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value); + if(value & HP45XXX_PWRKEY_WK_MASK){ + hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_PWRKEY_WK_MASK); + return true; + } + return false; +} + +bool hp45xxx_read_status_vbus_wk(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value); + if(value & HP45XXX_VBUS_WK_MASK){ + hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_VBUS_WK_MASK); + return true; + } + return false; +} + +bool hp45xxx_read_status_watchdog_int(void){ + uint8_t value; + hp45xxx_read_reg(HP45XXX_REG_INT0_STAT, &value); + return (value & HP45XXX_WATCHDOG_INT_MASK) ? true : false; +} \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/charge/hp4570/hp4570.h b/code/sdk/zhihui/drivers/charge/hp4570/hp4570.h new file mode 100644 index 000000000..57d9318c4 --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/hp4570/hp4570.h @@ -0,0 +1,505 @@ +/** + * @file HP4570.h + * @brief This is the header file containing the HP4570 I2C Settings and Control. + Includes API for computations related to configuring HP4570 Registers + and Functions to Control the HP4570 Family IC. + * @author Hypower Applications + * @date June 26, 2023 + * + * Copyright (C) 2023 Hypower Microelectronics (Wuxi) Co., Ltd. All rights reserved. + * + * THIS SOFTWARE IS PROVIDED BY HYPOWER MICROELECTRONICS "AS IS" AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL HYPOWER MICROELECTRONICS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, + * OR PROFITS;OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef HP4570_CHARGER_H +#define HP4570_CHARGER_H + +#include +#include +#include "chip_io.h" + +// for example +// Avoid using "X", x stands for General Condition +enum hp45xxx_chip_ver { + HP4570A,// all default, package typeA + HP4570B,// all default, package typeB + HP4570I = 0x0A,// different ichg range and step + HP4570J,// different default charge enable + HP4570K,// different i2c address + HP4580A = 0x10,// just different name + HP4570C9 = 0x02,// just different name +}; + + +// 7-bit Slave Address +#define HP45XXX_I2C_ADDR 0x07 +#define HP4570K_I2C_ADDR 0x3F + +// Register address definitions +#define HP45XXX_REG_DPM_SET 0x00 +#define HP45XXX_REG_SYS_CTRL0 0x01 +#define HP45XXX_REG_SYS_CTRL1 0x02 +#define HP45XXX_REG_IDSG_ITERM_SET 0x03 +#define HP45XXX_REG_BAT_VOL_SET 0x04 +#define HP45XXX_REG_SYS_CTRL2 0x05 +#define HP45XXX_REG_SYS_CTRL3 0x06 +#define HP45XXX_REG_SYS_CTRL4 0x07 +#define HP45XXX_REG_CHIP_STAT0 0x08 +#define HP45XXX_REG_CHIP_STAT1 0x09 +#define HP45XXX_REG_CHIP_STAT2 0x0B +#define HP45XXX_REG_VIPRE 0x0C +#define HP45XXX_REG_EXT_CTRL 0x0D +#define HP45XXX_REG_SYS_CTRL5 0x15 +#define HP45XXX_REG_SYS_CTRL6 0x19 +#define HP45XXX_REG_SYS_CTRL7 0x1B +#define HP45XXX_REG_SYS_WAKE_UP_SRC 0x1E +#define HP45XXX_REG_INT0_ENABLE 0x50 +#define HP45XXX_REG_INT0_STAT 0x58 +#define HP45XXX_REG_VID_LSB 0x60 +#define HP45XXX_REG_VID_MSB 0x61 +#define HP45XXX_REG_PID_LSB 0x62 +#define HP45XXX_REG_PID_MSB 0x63 +#define HP45XXX_REG_CHIP_VER 0x64 + +#ifndef GENMASK +#define GENMASK(h, l) (((uint8_t) -1 >> (7 - (h))) & ~((1U << (l)) - 1)) +#endif + +#define HP45XXX_VIN_MIN_MASK GENMASK(7, 4) +#define HP45XXX_VIN_MIN_STEP_mV 100 +#define HP45XXX_VIN_MIN_OFFSET_mV 3800 +#define HP45XXX_VIN_MIN_MIN_mV 3800 +#define HP45XXX_VIN_MIN_MAX_mV 4700 +#define HP45XXX_VIN_MIN_BIT_SHIFT 4 + +#define HP45XXX_IINDPM_MASK GENMASK(2, 0) +#define HP45XXX_IINDPM_STEP_mA 100 +#define HP45XXX_IINDPM_OFFSET_mA 100 +#define HP45XXX_IINDPM_MIN_mA 100 +#define HP45XXX_IINDPM_MAX_mA 900 +#define HP45XXX_IINDPM_BIT_SHIFT 0 + +#define HP45XXX_NUM_TRST_DGL_VAL 4 +#define HP45XXX_TRST_DGL_MASK GENMASK(7, 6) +#define HP45XXX_TRST_DGL_BIT_SHIFT 6 + +#define HP45XXX_NUM_TRST_DUR_VAL 2 +#define HP45XXX_TRST_DUR_MASK BIT(5) +#define HP45XXX_TRST_DUR_BIT_SHIFT 5 + +#define HP45XXX_EN_HIZ_MASK BIT(4) +#define HP45XXX_EN_HIZ_ENABLE 1 +#define HP45XXX_EN_HIZ_BIT_SHIFT 4 + +#define HP45XXX_CEB_MASK BIT(3) +#define HP45XXX_CEB_ENABLE 0 +#define HP45XXX_CEB_BIT_SHIFT 3 + +#define HP45XXX_VBAT_UVLO_MASK GENMASK(2, 0) +#define HP45XXX_VBAT_UVLO_STEP_mV 100 +#define HP45XXX_VBAT_UVLO_OFFSET_mV 2400 +#define HP45XXX_VBAT_UVLO_MIN_mV 2400 +#define HP45XXX_VBAT_UVLO_MAX_mV 3100 +#define HP45XXX_VBAT_UVLO_DEF_mV 2800 +#define HP45XXX_VBAT_UVLO_BIT_SHIFT 0 + +#define HP45XXX_REG_RST_MASK BIT(7) +#define HP45XXX_REG_RST_RESET 1 +#define HP45XXX_REG_RST_BIT_SHIFT 7 + +#define HP45XXX_WDT_RST_MASK BIT(6) +#define HP45XXX_WDT_RST_RESET 1 +#define HP45XXX_WDT_RST_BIT_SHIFT 6 + +#define HP45XXX_ICHG_MASK GENMASK(5, 0) +#define HP45XXX_ICHG_STEP_mA 8 +#define HP45XXX_ICHG_OFFSET_mA 8 +#define HP45XXX_ICHG_MIN_mA 8 +#define HP45XXX_ICHG_MAX_mA 512 +#define HP4570I_ICHG_STEP_mA 8 +#define HP4570I_ICHG_OFFSET_mA 8 +#define HP4570I_ICHG_MIN_mA 8 +#define HP4570I_ICHG_MAX_mA 512 +#define HP45XXX_ICHG_BIT_SHIFT 0 + +#define HP45XXX_IBATFET_OCP_MASK GENMASK(7, 4) +#define HP45XXX_IBATFET_OCP_STEP_mA 200 +#define HP45XXX_IBATFET_OCP_OFFSET_mA 200 +#define HP45XXX_IBATFET_OCP_MIN_mA 200 +#define HP45XXX_IBATFET_OCP_MAX_mA 3200 +#define HP45XXX_IBATFET_OCP_BIT_SHIFT 4 + +#define HP45XXX_ITERM_MASK GENMASK(3, 0) +#define HP45XXX_ITERM_STEP_mA 2 +#define HP45XXX_ITERM_OFFSET_mA 1 +#define HP45XXX_ITERM_MIN_mA 1 +#define HP45XXX_ITERM_MAX_mA 31 +#define HP45XXX_ITERM_BIT_SHIFT 0 + +#define HP45XXX_VBATREG_MASK GENMASK(7, 2) +#define HP45XXX_VBATREG_STEP_mV 12.5 +#define HP45XXX_VBATREG_OFFSET_mV 4000 +#define HP45XXX_VBATREG_MIN_mV 4000 +#define HP45XXX_VBATREG_MAX_mV 4500 +#define HP45XXX_VBATREG_BIT_SHIFT 2 + +#define HP45XXX_NUM_VBAT_PRE_VAL 4 +#define HP45XXX_VBAT_PRE_0_MASK BIT(1) +#define HP45XXX_VBAT_PRE_1_MASK BIT(4) +#define HP45XXX_VBAT_PRE_0_BIT_SHIFT 1 +#define HP45XXX_VBAT_PRE_1_BIT_SHIFT 4 + +#define HP45XXX_NUM_VRE_CHG_VAL 2 +#define HP45XXX_VRE_CHG_MASK BIT(0) +#define HP45XXX_VRE_CHG_BIT_SHIFT 0 + +#define HP45XXX_EN_WDT_DSG_MASK BIT(7) +#define HP45XXX_EN_WDT_DSG_ENABLE 1 +#define HP45XXX_EN_WDT_DSG_BIT_SHIFT 7 + +#define HP45XXX_NUM_WDT_TIMER_VAL 4 +#define HP45XXX_WDT_TIMER_MASK GENMASK(6, 5) +#define HP45XXX_WDT_TIMER_DIS 0 +#define HP45XXX_WDT_TIMER_BIT_SHIFT 5 + +#define HP45XXX_EN_TERM_MASK BIT(4) +#define HP45XXX_EN_TERM_ENABLE 1 +#define HP45XXX_EN_TERM_BIT_SHIFT 4 + +#define HP45XXX_EN_TIMER_MASK BIT(3) +#define HP45XXX_EN_TIMER_ENABLE 1 +#define HP45XXX_EN_TIMER_BIT_SHIFT 3 + +#define HP45XXX_NUM_CHG_TIMER_VAL 4 +#define HP45XXX_CHG_TIMER_MASK GENMASK(2, 1) +#define HP45XXX_CHG_TIMER_BIT_SHIFT 1 + +#define HP45XXX_TERM_TMR_MASK BIT(0) +#define HP45XXX_TERM_TMR_ENABLE 1 +#define HP45XXX_TERM_TMR_BIT_SHIFT 0 + +#define HP45XXX_NTC_EN_MASK BIT(7) +#define HP45XXX_NTC_EN_ENABLE 1 +#define HP45XXX_NTC_EN_BIT_SHIFT 7 + +#define HP45XXX_TMR2X_EN_MASK BIT(6) +#define HP45XXX_TMR2X_EN_ENABLE 1 +#define HP45XXX_TMR2X_EN_BIT_SHIFT 6 + +#define HP45XXX_BATFET_DIS_MASK BIT(5) +#define HP45XXX_BATFET_DIS_ENABLE 1 +#define HP45XXX_BATFET_DIS_BIT_SHIFT 5 + +#define HP45XXX_PG_INT_CONTROL_MASK BIT(4) +#define HP45XXX_PG_INT_CONTROL_ENABLE 0 +#define HP45XXX_PG_INT_CONTROL_BIT_SHIFT 4 + +#define HP45XXX_CHG_DONE_INT_EN_MASK BIT(3) +#define HP45XXX_CHG_DONE_INT_EN_ENABLE 0 +#define HP45XXX_CHG_DONE_INT_EN_BIT_SHIFT 3 + +#define HP45XXX_CHG_STAT_INT_EN_MASK BIT(2) +#define HP45XXX_CHG_STAT_INT_EN_ENABLE 0 +#define HP45XXX_CHG_STAT_INT_EN_BIT_SHIFT 2 + +#define HP45XXX_NTC_TRANSITION_EN_MASK BIT(1) +#define HP45XXX_NTC_TRANSITION_EN_ENABLE 0 +#define HP45XXX_NTC_TRANSITION_EN_BIT_SHIFT 1 + +#define HP45XXX_BATOVP_INT_EN_MASK BIT(0) +#define HP45XXX_BATOVP_INT_EN_ENABLE 0 +#define HP45XXX_BATOVP_INT_EN_BIT_SHIFT 0 + +#define HP45XXX_EN_PCB_OTP_MASK BIT(7) +#define HP45XXX_EN_PCB_OTP_ENABLE 0 +#define HP45XXX_EN_PCB_OTP_BIT_SHIFT 7 + +#define HP45XXX_VINDPM_EN_MASK BIT(6) +#define HP45XXX_VINDPM_EN_ENABLE 1 +#define HP45XXX_VINDPM_EN_BIT_SHIFT 6 + +#define HP45XXX_NUM_THERMAL_REG_VAL 4 +#define HP45XXX_THERMAL_REG_MASK GENMASK(5, 4) +#define HP45XXX_THERMAL_REG_BIT_SHIFT 4 + +#define HP45XXX_VSYS_REG_MASK GENMASK(2, 0) +#define HP45XXX_VSYS_REG_STEP_mV 100 +#define HP45XXX_VSYS_REG_OFFSET_mV 4250 +#define HP45XXX_VSYS_REG_MIN_mV 4250 +#define HP45XXX_VSYS_REG_MAX_mV 4950 +#define HP45XXX_VSYS_REG_BIT_SHIFT 0 + +#define HP45XXX_CHRG_STAT_MASK GENMASK(5, 3) +#define HP45XXX_CHRG_STAT_BIT_SHIFT 3 +#define HP45XXX_CHRG_STAT_NOT_CHRG 0 +#define HP45XXX_CHRG_STAT_DEAD_CHRG (BIT(5) | BIT(3)) +#define HP45XXX_CHRG_STAT_PRE_CHRG BIT(3) +#define HP45XXX_CHRG_STAT_FAST_CHRG BIT(4) +#define HP45XXX_CHRG_STAT_CHRG_DONE (BIT(4) | BIT(3)) + +#define HP45XXX_WDT_FAULT_MASK BIT(7) +#define HP45XXX_VIN_DPM_STAT_MASK BIT(2) +#define HP45XXX_VBUS_PG_STAT_MASK BIT(1) +#define HP45XXX_THERM_STAT_MASK BIT(0) + +#define HP45XXX_NUM_SHIP_DGL_VAL 4 +#define HP45XXX_SHIP_DGL_MASK GENMASK(7, 6) +#define HP45XXX_SHIP_DGL_BIT_SHIFT 6 + +#define HP45XXX_VIN_FAULT_MASK BIT(5) +#define HP45XXX_TSHUT_MASK BIT(4) +#define HP45XXX_VBAT_OVP_MASK BIT(3) +#define HP45XXX_SAFETY_MODE_MASK BIT(2) +#define HP45XXX_NTC_HOT_MASK BIT(1) +#define HP45XXX_NTC_COLD_MASK BIT(0) + +#define HP45XXX_IIN_DPM_STAT_MASK BIT(6) + +#define HP45XXX_NUM_IN_EXIT_SHIP_TSET_VAL 2 +#define HP45XXX_IN_EXIT_SHIP_TSET_MASK BIT(5) +#define HP45XXX_IN_EXIT_SHIP_TSET_BIT_SHIFT 5 + +#define HP45XXX_IPRE_MASK GENMASK(3, 0) +#define HP45XXX_IPRE_STEP_mA 2 +#define HP45XXX_IPRE_OFFSET_mA 1 +#define HP45XXX_IPRE_MIN_mA 1 +#define HP45XXX_IPRE_MAX_mA 31 +#define HP45XXX_IPRE_BIT_SHIFT 0 + +#define HP45XXX_VIN_ENTRY_RST_EN_MASK BIT(4) +#define HP45XXX_VIN_ENTRY_RST_EN_ENABLE 1 +#define HP45XXX_VIN_ENTRY_RST_EN_BIT_SHIFT 4 + +#define HP45XXX_IDEADBAT_MASK GENMASK(3, 0) +#define HP45XXX_IDEADBAT_STEP_mA 2 +#define HP45XXX_IDEADBAT_OFFSET_mA 1 +#define HP45XXX_IDEADBAT_MIN_mA 1 +#define HP45XXX_IDEADBAT_MAX_mA 31 +#define HP45XXX_IDEADBAT_BIT_SHIFT 0 + +#define HP45XXX_VSYS_RST_MASK BIT(7) +#define HP45XXX_VSYS_RST_RESET 1 +#define HP45XXX_VSYS_RST_BIT_SHIFT 7 + +#define HP45XXX_EN_IINDPM_MASK BIT(5) +#define HP45XXX_EN_IINDPM_ENABLE 1 +#define HP45XXX_EN_IINDPM_BIT_SHIFT 5 + +#define HP45XXX_NUM_KEY_WK_SET_VAL 2 +#define HP45XXX_KEY_WK_SET_MASK BIT(2) +#define HP45XXX_KEY_WK_SET_BIT_SHIFT 2 + +#define HP45XXX_NUM_T_HICCUP_VAL 2 +#define HP45XXX_T_HICCUP_MASK BIT(0) +#define HP45XXX_T_HICCUP_BIT_SHIFT 0 + +#define HP45XXX_WDT_VSYS_RST_MASK BIT(3) +#define HP45XXX_WDT_VSYS_RST_ENABLE 1 +#define HP45XXX_WDT_VSYS_RST_BIT_SHIFT 3 + +#define HP45XXX_EN_SHIP_DGL_MASK BIT(2) +#define HP45XXX_EN_SHIP_DGL_ENABLE 1 +#define HP45XXX_EN_SHIP_DGL_BIT_SHIFT 2 + +#define HP45XXX_EN_WDT_CHG_MASK BIT(7) +#define HP45XXX_EN_WDT_CHG_ENABLE 1 +#define HP45XXX_EN_WDT_CHG_BIT_SHIFT 7 + +#define HP45XXX_EN_PWRKEY_RST_MASK BIT(5) +#define HP45XXX_EN_PWRKEY_RST_ENABLE 1 +#define HP45XXX_EN_PWRKEY_RST_BIT_SHIFT 5 + +#define HP45XXX_VSYS_RST_WVBUS_MASK BIT(4) +#define HP45XXX_VSYS_RST_WVBUS_ENABLE 1 +#define HP45XXX_VSYS_RST_WVBUS_BIT_SHIFT 4 + +#define HP45XXX_PWRKEY_EN_MASK BIT(2) +#define HP45XXX_PWRKEY_EN_ENABLE 1 +#define HP45XXX_PWRKEY_EN_BIT_SHIFT 2 + +#define HP45XXX_VBUS_WK_EN_MASK BIT(1) +#define HP45XXX_VBUS_WK_EN_ENABLE 1 +#define HP45XXX_VBUS_WK_EN_BIT_SHIFT 1 + +#define HP45XXX_PWRKEY_WK_EN_MASK BIT(0) +#define HP45XXX_PWRKEY_WK_EN_ENABLE 1 +#define HP45XXX_PWRKEY_WK_EN_BIT_SHIFT 0 + +#define HP45XXX_ENTRY_RST_STAT_MASK BIT(7) +#define HP45XXX_PWRKEY_RST_STAT_MASK BIT(5) +#define HP45XXX_HICCUP_LATCH_STAT_MASK BIT(4) +#define HP45XXX_PWRKEY_WK_MASK BIT(1) +#define HP45XXX_VBUS_WK_MASK BIT(0) + +#define HP45XXX_WATCHDOG_INT_EN_MASK BIT(7) +#define HP45XXX_WATCHDOG_INT_EN_ENABLE 0 +#define HP45XXX_WATCHDOG_INT_EN_BIT_SHIFT 7 + +#define HP45XXX_CHG_SAFETY_EXPIRED_MASK BIT(1) +#define HP45XXX_CHG_SAFETY_EXPIRED_ENABLE 0 +#define HP45XXX_CHG_SAFETY_EXPIRED_BIT_SHIFT 1 + +#define HP45XXX_WATCHDOG_INT_MASK BIT(7) + +static const uint32_t hp45xxx_trst_dgl_time[HP45XXX_NUM_TRST_DGL_VAL] = { + 80000, 120000, 160000, 200000 +}; +static const uint16_t hp45xxx_trst_dur_time[HP45XXX_NUM_TRST_DUR_VAL] = { + 2000, 4000 +}; +static const uint16_t hp45xxx_vbat_pre_voltage[HP45XXX_NUM_VBAT_PRE_VAL] = { + 2800, 3000, 3200, 3300 +}; +static const uint8_t hp45xxx_vre_chg_voltage[HP45XXX_NUM_VRE_CHG_VAL] = { + 100, 200 +}; +static const uint32_t hp45xxx_watchdog_time[HP45XXX_NUM_WDT_TIMER_VAL] = { + 0, 40000, 80000, 160000 +}; +static const uint8_t hp45xxx_fast_chg_time[HP45XXX_NUM_CHG_TIMER_VAL] = { + 3, 5, 8, 12 +}; +static const uint8_t hp45xxx_thermal_reg_degree[HP45XXX_NUM_THERMAL_REG_VAL] = { + 80, 100, 120, 130 +}; +static const uint16_t hp45xxx_ship_dgl_time[HP45XXX_NUM_SHIP_DGL_VAL] = { + 1000, 2000, 4000, 8000 +}; +static const uint16_t hp45xxx_in_exit_ship_tset_time[HP45XXX_NUM_IN_EXIT_SHIP_TSET_VAL] = { + 50, 2000 +}; +static const uint16_t hp45xxx_key_wk_set_time[HP45XXX_NUM_KEY_WK_SET_VAL] = { + 2000, 200 +}; +static const uint16_t hp45xxx_t_hiccup_time[HP45XXX_NUM_T_HICCUP_VAL] = { + 256, 512 +}; + +//Default value for a register. +#define HP45XXX_REG_DPM_SET_DEF 0x84 +#define HP45XXX_REG_SYS_CTRL0_DEF 0xA4 +#define HP45XXX_REG_SYS_CTRL1_DEF 0x00 +#define HP45XXX_REG_IDSG_ITERM_SET_DEF 0x91 +#define HP45XXX_REG_BAT_VOL_SET_DEF 0x43 +#define HP45XXX_REG_SYS_CTRL2_DEF 0x3A +#define HP45XXX_REG_SYS_CTRL3_DEF 0x40 +#define HP45XXX_REG_SYS_CTRL4_DEF 0x24 +#define HP45XXX_REG_CHIP_STAT1_DEF 0x00 +#define HP45XXX_REG_VIPRE_DEF 0x01 +#define HP45XXX_REG_EXT_CTRL_DEF 0x11 +#define HP45XXX_REG_SYS_CTRL5_DEF 0x31 +#define HP45XXX_REG_SYS_CTRL6_DEF 0x0C +#define HP45XXX_REG_SYS_CTRL7_DEF 0xB6 +#define HP45XXX_REG_INT0_ENABLE_DEF 0x4C +#define HP45XXX_REG_INT0_STAT_DEF 0x00 +#define HP45XXX_REG_VID_LSB_DEF 0xC6 +#define HP45XXX_REG_VID_MSB_DEF 0x34 +#define HP45XXX_REG_PID_LSB_DEF 0x81 +#define HP45XXX_REG_PID_MSB_DEF 0x00 + +#define HP4570J_REG_SYS_CTRL0_DEF 0xAC + +// Function Declarations +bool hp45xxx_init(uint8_t chip_ver); +bool hp45xxx_identify(uint8_t chip_ver); + +void hp45xxx_set_pwrkey_en(bool en);// PWRKEY function enable control +bool hp45xxx_set_trst_dgl_mS(uint32_t time);// Pull INT low to disconnect the battery then auto on + +void hp45xxx_reg_rst(void);// Register reset +void hp45xxx_wdt_rst(void);// Watchdog timer reset +void hp45xxx_vsys_rst(void);// VSYS reset +void hp45xxx_set_rst_vin_entry_en(bool en);// VIN 4 pulse Reset Enable +void hp45xxx_set_rst_pwrkey_en(bool en);// VSYS reset enable PWRKEY operation Enable +void hp45xxx_set_rst_vsys_wvbus_en(bool en);// VSYS reset operation when VBUS is present + +void hp45xxx_entry_shipmode(void); +bool hp45xxx_set_batfet_dis(bool en);// BATFET force off +void hp45xxx_set_vbus_wk_en(bool en);// VBUS plug in to exit ship mode +void hp45xxx_set_pwrkey_wk_en(bool en);// PWRKEY be low to exit ship mode +bool hp45xxx_set_vin_exit_ship_tset_mS(uint16_t time);// IN Port Power Good Time Setting for Exit Shipmode +bool hp45xxx_set_key_wk_time_mS(uint16_t time);// KEY wake up time set +void hp45xxx_set_ship_dgl_en(bool en);// Enter ship mode deglitch enable control +bool hp45xxx_set_ship_dgl_mS(uint16_t time);// Enter ship mode deglitch time + + +void hp45xxx_set_hiz_en(bool en);// VBUS power path Hi-Z mode enable +void hp45xxx_set_ceb_en(bool en);// Enable or disable charging function + +bool hp45xxx_set_vsys_reg_mV(float voltage);// VSYS regulation +bool hp45xxx_set_trst_dur_mS(uint16_t time);// VSYS off time before auto on +void hp45xxx_set_vindpm_en(bool en); +void hp45xxx_set_iindpm_en(bool en); +bool hp45xxx_set_vindpm_mV(uint16_t voltage); +bool hp45xxx_set_iindpm_mA(uint16_t current); + +bool hp45xxx_set_chrg_vpre_mV(uint8_t voltage);// Battery pre-charge voltage set +bool hp45xxx_set_chrg_vbat_mV(float voltage); +bool hp45xxx_set_chrg_vre_mV(uint8_t voltage);// Battery re-charge voltage set +bool hp45xxx_set_chrg_idead_mA(uint16_t current); +bool hp45xxx_set_chrg_ipre_mA(uint16_t current);// Battery pre-charge current set +bool hp45xxx_set_chrg_ichg_mA(uint16_t current); +bool hp4570i_set_chrg_ichg_mA(uint16_t current); +bool hp45xxx_set_chrg_iterm_mA(uint8_t current); +void hp45xxx_set_chrg_term_en(bool en);// Termination is allowed or not +void hp45xxx_set_chrg_term_tmr(bool en);// Termination timer control +void hp45xxx_set_chrg_timer_en(bool en);// Safety timer set during charging +bool hp45xxx_set_chrg_timer_hour(uint8_t time);// Fast charging mode timer set +void hp45xxx_set_chrg_tmr2x_en(bool en);// Safety timer double during DPM/Thermal + +bool hp45xxx_set_ibatfet_ocp_mA(uint16_t current); +bool hp45xxx_set_vbat_uvlo_mV(uint16_t voltage);// Battery UVLO falling threshold,hys is about =150mV +bool hp45xxx_set_t_hiccup_mS(uint16_t time);// Hiccup timer set + +void hp45xxx_set_wdt_timer_en(bool en);// If watchdog timer already enable, function will do noting, otherwise will set as default +bool hp45xxx_set_wdt_timer_mS(uint32_t time); +void hp45xxx_set_wdt_chg_en(bool en);// Watchdog timer function enable control during charging +void hp45xxx_set_wdt_dsg_en(bool en);// Watchdog timer function enable control during discharging +void hp45xxx_set_wdt_vsys_rst_en(bool en);// Watch dog fault VSYS reset enable control + +void hp45xxx_set_ntc_en(bool en);// NTC enable during charging +void hp45xxx_set_pcb_otp_en(bool en);// PCB_OTP enable +bool hp45xxx_set_thermal_reg_degree(uint8_t degree);// Die temp control by Thermal loop + +void hp45xxx_set_int_pg_en(bool en);// Power good int enable control +void hp45xxx_set_int_chrg_done_en(bool en);// Charge complete int enable control +void hp45xxx_set_int_chrg_stat_en(bool en);// Charging status dynamic change int enable control +void hp45xxx_set_int_ntc_transition_en(bool en);// Battery temp region change int enable control +void hp45xxx_set_int_batovp_en(bool en);// Battery OVP int enable control +void hp45xxx_set_int_wdt_en(bool en);// Watch dog time expire int enable control +void hp45xxx_set_int_chg_safety_expired_en(bool en);// Charger enter safety int enable control + +bool hp45xxx_read_chrg_stat_not_chrg(void); +bool hp45xxx_read_chrg_stat_dead_chrg(void); +bool hp45xxx_read_chrg_stat_pre_chrg(void); +bool hp45xxx_read_chrg_stat_fast_chrg(void); +bool hp45xxx_read_chrg_stat_chrg_done(void); + +bool hp45xxx_read_status_wdt_fault(void);// Watchdog timer expired 1: Expired; 0: Not Expired +bool hp45xxx_read_status_vindpm(void);// 1: In DPM; 0: Not DPM +bool hp45xxx_read_status_vbus_pg(void);// 1: Power Good; 0: Not Good +bool hp45xxx_read_status_thermal(void);// 1: In thermal; 0: Not thermal +bool hp45xxx_read_status_vin_fault(void);// 1: Input fault ovp or bad source plug out; 0: normal +bool hp45xxx_read_status_tshut(void);// 1: Thermal shutdown; 0: Normal +bool hp45xxx_read_status_vbat_ovp(void);// 1: BAT_OVP; 0: Not BAT_OVP +bool hp45xxx_read_status_safety_mode(void);// Charger safety timer expired 1: Expired; 0: Not Expired +bool hp45xxx_read_status_ntc_hot(void);// 1: Hot; 0: Not hot +bool hp45xxx_read_status_ntc_cold(void);// 1: Cold; 0: Not cold +bool hp45xxx_read_status_iindpm(void);// 1: In DPM; 0: Not DPM +bool hp45xxx_read_status_vin_entry_rst(void);// VIN_ENTRY_RST once happenned +bool hp45xxx_read_status_pwrkey_rst(void);// PWRKEY reset once happened +bool hp45xxx_read_status_hiccup_latch(void);// Hiccup once happened +bool hp45xxx_read_status_pwrkey_wk(void);// PWRKEY 2S low time wake up from ship mode +bool hp45xxx_read_status_vbus_wk(void);// VBUS plug in wake up from ship mode +bool hp45xxx_read_status_watchdog_int(void);// Watch dog time expire IRQ + +#endif // HP4570_CHARGER_H \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.c b/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.c new file mode 100644 index 000000000..41d45a67e --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.c @@ -0,0 +1,99 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-23 15:11:01 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-24 21:09:51 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/charge/HP4570/service/charge_at_cmd.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +#include "at_cmd_api.h" +#include "pm_control.h" +#include "debug_print.h" +#include "hp4570.h" +#include "custom_utils.h" + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) +#define CHARGE_MAX_ARGC 8 +#define CHARGE_MAX_ARGV_LEN 64 + +#define CHARGE_SUCCESS 0 +#define CHARGE_FAILED (-1) + +static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen, + uint8_t argv[CHARGE_MAX_ARGC][CHARGE_MAX_ARGV_LEN], uint32_t* argc) +{ + uint32_t pos = 0; + *argc = 0; + + for (uint32_t i = 0; i < paraLen; i++) { + if ((para[i] == ' ' || para[i] == '\n') && pos != 0) { + argv[*argc][pos] = '\0'; + *argc += 1; + pos = 0; + if (*argc >= CHARGE_MAX_ARGC) { + return CHARGE_FAILED; + } + } else { + argv[*argc][pos] = para[i]; + pos++; + if (pos >= CHARGE_MAX_ARGV_LEN) { + return CHARGE_FAILED; + } + } + } + if (pos != 0) { + *argc += 1; + } + + return CHARGE_SUCCESS; +} + +static uint8_t g_charge_test_started = 0; +static uint32_t hp4570_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(strCommonCmd); + uint8_t argv[CHARGE_MAX_ARGC][CHARGE_MAX_ARGV_LEN] = { 0 }; + uint32_t argc = 0; + + int ret = ConvertCmdToParam(para, paraLen, argv, &argc); + if (ret != CHARGE_SUCCESS) { + PRINT("CHARGETEST ATCMD Convert Command Failed\n"); + return ERRCODE_FAIL; + } + + if (argc != 1) { + PRINT("CHARGETEST ATCMD Set Parameter Failed argc %d\n",argc); + return ERRCODE_FAIL; + } + uint8_t start = (uint8_t)atoi((char*)argv[0]); + if (start == 1) + { + // if (g_CHARGE_test_started == 1) + // { + // PRINT("SKIP CHARGEtest start, already started\r\n"); + // return 0; + // } + hp45xxx_init(HP4570C9); + g_charge_test_started = 1; + }else if (start == 2){ + if (g_charge_test_started == 0) + { + PRINT("SKIP CHARGEtest stop, already stopped\r\n"); + return 0; + } + // ots_stop(); + g_charge_test_started = 0 ; + }else{ + custom_exit_lpm(); + } + return ERRCODE_SUCC; +} +static const at_cmd_table_t g_charge_cmd[] = { + { (char *)"AT^CHARGETEST", hp4570_test, (char *)"1" }, +}; + +at_cmd_table_t *get_charge_cmd_table(uint32_t *cmd_count) +{ + *cmd_count = ARRAY_COUNT(g_charge_cmd); + return (at_cmd_table_t *)g_charge_cmd; +} diff --git a/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h b/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h new file mode 100644 index 000000000..e54f7befc --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h @@ -0,0 +1,40 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-18 10:23:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-24 17:58:19 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/rotary_encoder/hx3509/hx3509_at_cmd.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Provides at cmd register func \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-07-20, Create file. \n + */ +#ifndef HX3509_AT_PROCESS_H +#define HX3509_AT_PROCESS_H + +#include +#include +#include "errcode.h" +#include "soc_osal.h" +#include "at_cmd_api.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +at_cmd_table_t *get_charge_cmd_table(uint32_t *cmd_count); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif diff --git a/code/sdk/zhihui/drivers/charge/service/charge_service.c b/code/sdk/zhihui/drivers/charge/service/charge_service.c new file mode 100644 index 000000000..3f9df3d83 --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/service/charge_service.c @@ -0,0 +1,185 @@ +#include "pinctrl.h" +#include "debug_print.h" +#include "rtc.h" +#include "timer.h" +#include "systick.h" + +static bool g_batter_service_initialled = false; + +#include "tcxo.h" + +#include "cmsis_os2.h" +#include "input_app.h" +#include "charge_service.h" +#include "custom_utils.h" +// #include "custom_runtime.h" +/*** + * 其他cmd在Header里定义,对外开放 +*/ +#define CHARGE_SERVICE_CMD_TIMER_CHECK 0x11 + +osTimerId_t g_charge_service_timer = NULL; + +static bool g_charge_sensor_exist = false; + +static bool g_bat_timer_is_running = false; +#define CHARGE_CHECK_MS 40 +static unsigned long g_app_queue= 0xFFFFFFFF; + +static bool charge_service_running_stat = false; +static void charge_service_check_timer_callback(void* data); + +static void charge_service_timer_start_check(uint32_t rtc_ms) +{ + + if (g_bat_timer_is_running ) + osTimerStop(g_charge_service_timer); + + if (charge_service_running_stat == true) + osTimerStart(g_charge_service_timer, rtc_ms); + + g_bat_timer_is_running = true; + +} +void do_charge_service_check_msg(int cmd); + +static void charge_service_check_timer_callback(void * data) +{ + unused(data); + + g_bat_timer_is_running = false; + + if(charge_service_running_stat == true){ + // mmc5603_check(); //此处只能直接加到timer callback中,采用queue的话,新能跟不上,系统资源会挂掉。 + do_charge_service_check_msg(CHARGE_SERVICE_CMD_TIMER_CHECK); + // charge_service_timer_start_check(CHARGE_CHECK_MS); + } + + + +} +void uapi_charge_service_deinit(void) +{ + /* Stop the time and clear the pin map */ + osTimerStop(g_charge_service_timer); + osTimerDelete(g_charge_service_timer); + + g_bat_timer_is_running = false; + g_charge_service_timer = NULL; +} + + + +void do_charge_service_check_msg(int cmd) +{ + int ret; + if (g_charge_sensor_exist == false) + return ; + common_notify_mail_t mail = {0}; + mail.comm.app = cmd; + ret = osal_msg_queue_write_copy(g_app_queue, (void *)&mail, + sizeof(common_notify_mail_t), 0); + if (ret != OSAL_SUCCESS) { + MMC_ERROR("Error charge Check MSG 0x%02X send failed! err=0x%x! \r\n",cmd, ret); + } + +} + +static void charge_service_check_task(void const *arg) +{ + unused(arg); + int32_t ret; + common_notify_mail_t mail; + uint32_t msgsize = (uint32_t)sizeof(common_notify_mail_t); + while (1) { + ret = osal_msg_queue_read_copy(g_app_queue, (void *)&mail, &msgsize, + OSAL_MSGQ_WAIT_FOREVER); + if (ret != OSAL_SUCCESS) { + continue; + } + + if (mail.comm.app == CHARGE_SERVICE_CMD_TIMER_CHECK) { + // charge_service_check_and_enable_charge(); + MMC_LOG("CHARGE_SERVICE_CMD_TIMER_CHECK\r\n"); + mmc5603_check(); + }else if (mail.comm.app == CHARGE_SERVICE_CMD_START_CHECK){ + // uapi_dev_runtime_set_mmc_status(1); + // do_custom_fileoperate_service_check_msg(CUSTOM_FILEOPERATE_MSG_TYPE_MMCDATA_READ, NULL, 0); + + mmc5603_start(); + LOS_Mdelay(20); + charge_service_running_stat = true; + // uapi_pm_add_sleep_veto(PM_ID_SCREEN); + charge_service_timer_start_check(CHARGE_CHECK_MS); + }else if (mail.comm.app == CHARGE_SERVICE_CMD_STOP_CHECK){ + // uapi_dev_runtime_set_mmc_status(0); + // SavePara_infile(); + // do_custom_fileoperate_service_check_msg(CUSTOM_FILEOPERATE_MSG_TYPE_MMCDATA_SAVE, NULL, 0); + charge_service_running_stat = false; + osTimerStop(g_charge_service_timer); + mmc5603_stop(); + LOS_Mdelay(20); + + // uapi_pm_remove_sleep_veto(PM_ID_SCREEN); + } + + + } +} +void create_charge_queue(void) +{ + + if (osal_msg_queue_create("charge_service_queue", APP_BOARD_MSG_COUNT, &g_app_queue, + 0, sizeof(common_notify_mail_t)) != ERRCODE_SUCC) { + MMC_ERROR("[charge][service] app create mail fail\n"); + } +} + +#define CHARGE_BOARD_TASK_SIZE 0x1000 +errcode_t uapi_charge_service_init(void) +{ + + + PRINT("uapi_charge_service_init !\r\n"); + + + + // if(CUSTOM_MMC5603_CheckID()!=1) + // { + // //TODO 设置磁力计检测是否存在标识 + // PRINT("MMC5603 not found!\r\n"); + // return ERRCODE_FAIL; + // } + // mmc5603_stop(); + g_charge_sensor_exist = true; + + app_task_definition_t taskcfg={0}; + taskcfg.create_queue_handle = create_charge_queue; + taskcfg.attr.name="charge_service"; + taskcfg.attr.priority = osPriorityBelowNormal4; + taskcfg.attr.stack_size = CHARGE_BOARD_TASK_SIZE; + taskcfg.func = charge_service_check_task; + taskcfg.use_mem = USE_EXTEND_MEM; + + errcode_t ret=uapi_create_osThread_custom(&taskcfg); + if(ret != ERRCODE_SUCC) + { + PRINT("create charge_service failed %d!\r\n",ret); + return ERRCODE_FAIL; + } + + g_charge_service_timer = osTimerNew((osTimerFunc_t)charge_service_check_timer_callback, osTimerPeriodic, NULL, NULL); + + + return ERRCODE_SUCC; +} + +// void charge_service_service_resume(void) +// { +// MMC_LOG("charge_service_service resume!\r\n"); +// charge_service_check_timer_callback(0); +// } +// void charge_service_service_suspend(void) +// { +// MMC_LOG("charge_service_service suspend!\r\n"); +// } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/charge/service/charge_service.h b/code/sdk/zhihui/drivers/charge/service/charge_service.h new file mode 100644 index 000000000..8e0553082 --- /dev/null +++ b/code/sdk/zhihui/drivers/charge/service/charge_service.h @@ -0,0 +1,54 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-23 15:11:01 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-24 17:57:55 + * @FilePath: /sdk615/code/sdk/zhihui/drivers/charge/HP4570/service/charge_service.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Test adc header \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-08-16, Create file. \n + */ + +#ifndef CHARGE_SERVICE_H__ +#define CHARGE_SERVICE_H__ + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" +#include "errcode.h" + + +#define CHARGE_SERVICE_CMD_START_CHECK 0x12 +#define CHARGE_SERVICE_CMD_STOP_CHECK 0x13 + +errcode_t uapi_charge_service_init(void); +void uapi_charge_service_deinit(void); +/** + * 测试指令 参数cmd 选项: CHARGE_SERVICE_CMD_START_CHECK,CHARGE_SERVICE_CMD_STOP_CHECK +*/ +void do_charge_service_check_msg(int cmd); + +float charge_service_get_fAzimuth(void); +float charge_service_get_fPitch(void); +float charge_service_get_fRoll(void); + + +int charge_service_get_iAccuracy(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/mag/mmc5603/MMC5603.c b/code/sdk/zhihui/drivers/mag/mmc5603/MMC5603.c index 185d96aa4..dee38ea98 100644 --- a/code/sdk/zhihui/drivers/mag/mmc5603/MMC5603.c +++ b/code/sdk/zhihui/drivers/mag/mmc5603/MMC5603.c @@ -75,7 +75,8 @@ int CUSTOM_MMC5603_Factory_Test_Mode(void) /* Set Cmm_en bit '0', Disable continuous mode */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL2, 0x00); - MMC5603_Delay_Ms(20); + // MMC5603_Delay_Ms(20); + LOS_Mdelay(20); /* Write reg 0x1B */ /* Set Auto_SR_en bit '0', Disable the function of automatic set/reset */ @@ -89,7 +90,8 @@ int CUSTOM_MMC5603_Factory_Test_Mode(void) /* Write 0x01 to register 0x1B, set Take_meas_M bit '1' */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_TMM); /* Delay 10 ms to finish the TM operation */ - MMC5603_Delay_Ms(10); + // MMC5603_Delay_Ms(10); + LOS_Mdelay(10); /* Read register data */ I2C_MultiRead_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_DATA, 6, data_reg); /* Get high 16bits data */ @@ -102,7 +104,8 @@ int CUSTOM_MMC5603_Factory_Test_Mode(void) /* Write 0x01 to register 0x1B, set Take_meas_M bit '1' */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS,CUSTOM_MMC5603_REG_CTRL0,CUSTOM_MMC5603_CMD_TMM); /* Delay 10 ms to finish the TM operation */ - MMC5603_Delay_Ms(10); + // MMC5603_Delay_Ms(10); + LOS_Mdelay(10); /* Read register data */ I2C_MultiRead_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_DATA, 6, data_reg); /* Get high 16bits data */ @@ -134,7 +137,8 @@ void CUSTOM_MMC5603_SET(void) I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_SET); /* Delay to finish the SET operation */ - MMC5603_Delay_Ms(1); + // MMC5603_Delay_Ms(1); + LOS_Mdelay(1); return; } @@ -148,7 +152,8 @@ void CUSTOM_MMC5603_RESET(void) I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_RESET); /* Delay to finish the RESET operation */ - MMC5603_Delay_Ms(1); + // MMC5603_Delay_Ms(1); + LOS_Mdelay(1); return; } @@ -220,7 +225,8 @@ int CUSTOM_MMC5603_Auto_SelfTest(void) I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_AUTO_ST_EN); /* Delay 15ms to finish the selftest process */ - MMC5603_Delay_Ms(15); + // MMC5603_Delay_Ms(15); + LOS_Mdelay(15); /* Read register 0x18, check Sat_sensor bit */ I2C_Read_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_STATUS1, ®_status); @@ -278,7 +284,8 @@ int CUSTOM_MMC5603_Saturation_Checking(void) /* Do TM_M after selftest operation */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS,CUSTOM_MMC5603_REG_CTRL0,CUSTOM_MMC5603_CMD_TMM); - MMC5603_Delay_Ms(8); + // MMC5603_Delay_Ms(8); + LOS_Mdelay(8); } return ret; @@ -304,15 +311,18 @@ void CUSTOM_MMC5603_Auto_Switch(uint16_t *mag) /* Disable continuous mode */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL2, 0x00); - MMC5603_Delay_Ms(15);//Delay 15ms to finish the last sampling + // MMC5603_Delay_Ms(15);//Delay 15ms to finish the last sampling + LOS_Mdelay(15); /* Do SET operation */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_SET); - MMC5603_Delay_Ms(1);//Delay 1ms to finish the SET operation + // MMC5603_Delay_Ms(1);//Delay 1ms to finish the SET operation + LOS_Mdelay(1); /* Do TM_M before next data reading */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS,CUSTOM_MMC5603_REG_CTRL0,CUSTOM_MMC5603_CMD_TMM); - MMC5603_Delay_Ms(8);//Delay 8ms to finish the TM_M operation + // MMC5603_Delay_Ms(8);//Delay 8ms to finish the TM_M operation + LOS_Mdelay(8); } } else if(sensor_state == 2) @@ -349,7 +359,8 @@ void CUSTOM_MMC5603_Disable(void) /* Set Cmm_en bit '0', Disable continuous mode */ I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL2, 0x00); - MMC5603_Delay_Ms(20); + // MMC5603_Delay_Ms(20); + LOS_Mdelay(20); return; } @@ -378,7 +389,8 @@ void CUSTOM_MMC5603_Enable(void) /* Work mode setting */ CUSTOM_MMC5603_Continuous_Mode_With_Auto_SR(CUSTOM_MMC5603_CMD_BW00, 50); - MMC5603_Delay_Ms(20); + // MMC5603_Delay_Ms(20); + LOS_Mdelay(20); return; } diff --git a/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_at_cmd.c b/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_at_cmd.c index 7f368b42d..d821ed686 100644 --- a/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_at_cmd.c +++ b/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_at_cmd.c @@ -1,3 +1,11 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-16 09:56:44 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-16 20:50:13 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/mag/mmc5603/mmc5603_at_cmd.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ // #include "mmc5603.h" diff --git a/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_hal.h b/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_hal.h index 9f72a3ea4..069caef2a 100644 --- a/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_hal.h +++ b/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_hal.h @@ -28,6 +28,9 @@ int mmc5603_start(void); int mmc5603_savePara_infile(void); int mmc5603_readPara_infile(void); +void mmc5603_poweron(void); +void mmc5603_poweroff(void); + #ifdef __cplusplus #if __cplusplus } diff --git a/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_main.c b/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_main.c index e1fafe86e..4bed63fb1 100644 --- a/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_main.c +++ b/code/sdk/zhihui/drivers/mag/mmc5603/mmc5603_main.c @@ -11,6 +11,13 @@ #include "mmc_customer.h" #include "MMC5603.h" +#ifdef BOARD_U8 +#include "pm_control.h" +#include "platform_core.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" +#endif + #ifdef ACC_LIS2DOC #include "acc_service.h" #endif @@ -24,6 +31,9 @@ float magnetic_field_z; #define A_LAYOUT 7 #define M_LAYOUT 0 +// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚 +#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0 + /* These variables are used to save the magnetic sensor calibrated data. */ float calMagX, calMagY, calMagZ; @@ -71,8 +81,29 @@ static float g_MagPara[4] = {0.0f}; /* This variable is used to save calibrated mag para that need to be saved in system file */ static float saveData[4] = {0.0f}; +void mmc5603_poweron(void) +{ +#ifdef BOARD_U8 + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH); + LOS_Mdelay(100); +#endif +} +void mmc5603_poweroff(void) +{ +#ifdef BOARD_U8 + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW); + LOS_Mdelay(1); +#endif +} int mmc5603_start(void) { + + mmc5603_poweron(); + int i; /* magnetic sensor soft iron calibration matrix, default is unit matrix */ float mag_smm[9] = { 1.0f, 0.0f, 0.0f, \ @@ -443,5 +474,8 @@ int mag_service_get_iAccuracy(void) int mmc5603_stop(void) { CUSTOM_MMC5603_Disable(); + + mmc5603_poweroff(); + return 0; } diff --git a/code/sdk/zhihui/drivers/mag/mmc5603/mmc_customer.h b/code/sdk/zhihui/drivers/mag/mmc5603/mmc_customer.h index a5f8bdedd..a08c83996 100644 --- a/code/sdk/zhihui/drivers/mag/mmc5603/mmc_customer.h +++ b/code/sdk/zhihui/drivers/mag/mmc5603/mmc_customer.h @@ -1,3 +1,11 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-16 09:56:44 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-16 10:33:24 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/mag/mmc5603/mmc_customer.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ #ifndef __MMC5603_PORTING_H__ #define __MMC5603_PORTING_H__ #include @@ -6,7 +14,7 @@ #ifndef XTS_SUPPORT -// #define MMC_DEBUG +#define MMC_DEBUG #endif #ifdef MMC_DEBUG diff --git a/code/sdk/zhihui/drivers/mag/service/mag_service.c b/code/sdk/zhihui/drivers/mag/service/mag_service.c index bab12f639..f0fce98f5 100644 --- a/code/sdk/zhihui/drivers/mag/service/mag_service.c +++ b/code/sdk/zhihui/drivers/mag/service/mag_service.c @@ -71,7 +71,13 @@ static bool g_batter_service_initialled = false; #include "mmc_customer.h" #include "custom_utils.h" -#include "custom_runtime.h" + +#ifdef BOARD_U8 +#include "vc9202_hal.h" +#endif + + +// #include "custom_runtime.h" /*** * 其他cmd在Header里定义,对外开放 */ @@ -162,17 +168,18 @@ static void mag_service_check_task(void const *arg) // MMC_LOG("MAG_SERVICE_CMD_TIMER_CHECK\r\n"); mmc5603_check(); }else if (mail.comm.app == MAG_SERVICE_CMD_START_CHECK){ - uapi_dev_runtime_set_mmc_status(1); - do_custom_fileoperate_service_check_msg(CUSTOM_FILEOPERATE_MSG_TYPE_MMCDATA_READ, NULL, 0); + // uapi_dev_runtime_set_mmc_status(1); + // do_custom_fileoperate_service_check_msg(CUSTOM_FILEOPERATE_MSG_TYPE_MMCDATA_READ, NULL, 0); + mmc5603_start(); LOS_Mdelay(20); mag_service_running_stat = true; // uapi_pm_add_sleep_veto(PM_ID_SCREEN); mag_service_timer_start_check(MAG_CHECK_MS); }else if (mail.comm.app == MAG_SERVICE_CMD_STOP_CHECK){ - uapi_dev_runtime_set_mmc_status(0); + // uapi_dev_runtime_set_mmc_status(0); // SavePara_infile(); - do_custom_fileoperate_service_check_msg(CUSTOM_FILEOPERATE_MSG_TYPE_MMCDATA_SAVE, NULL, 0); + // do_custom_fileoperate_service_check_msg(CUSTOM_FILEOPERATE_MSG_TYPE_MMCDATA_SAVE, NULL, 0); mag_service_running_stat = false; osTimerStop(g_mag_service_timer); mmc5603_stop(); @@ -200,21 +207,28 @@ errcode_t uapi_mag_service_init(void) PRINT("uapi_mag_service_init !\r\n"); - - +#ifdef BOARD_U8 + mmc5603_poweron(); +#endif if(CUSTOM_MMC5603_CheckID()!=1) { //TODO 设置磁力计检测是否存在标识 PRINT("MMC5603 not found!\r\n"); - return ERRCODE_FAIL; +#ifdef BOARD_U8 + mmc5603_poweroff(); +#endif + // return ERRCODE_FAIL; } mmc5603_stop(); +#ifdef BOARD_U8 + mmc5603_poweroff(); +#endif g_mag_sensor_exist = true; app_task_definition_t taskcfg={0}; taskcfg.create_queue_handle = create_mag_queue; taskcfg.attr.name="mag_service"; - taskcfg.attr.priority = TASK_PRIORITY_APP; + taskcfg.attr.priority = osPriorityBelowNormal4; taskcfg.attr.stack_size = MAG_BOARD_TASK_SIZE; taskcfg.func = mag_service_check_task; taskcfg.use_mem = USE_EXTEND_MEM; diff --git a/code/sdk/zhihui/drivers/mag/service/mag_service.h b/code/sdk/zhihui/drivers/mag/service/mag_service.h index 62bbe0e2d..951ffeef9 100644 --- a/code/sdk/zhihui/drivers/mag/service/mag_service.h +++ b/code/sdk/zhihui/drivers/mag/service/mag_service.h @@ -1,3 +1,11 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-16 09:56:44 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-18 17:23:06 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/mag/service/mag_service.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ /** * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n * diff --git a/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt index bed307cc1..8315e769d 100644 --- a/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/ppg/service/CMakeLists.txt @@ -17,6 +17,7 @@ set(PRIVATE_HEADER set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/ppg_at_cmd.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ppg_service.cpp + ) set(COMPONENT_PUBLIC_CCFLAGS diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp b/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp index afb40077b..d86729501 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_at_cmd.cpp @@ -10,6 +10,11 @@ #include #include +#ifdef PPG_VC9202 +#include "vc9202_hal.h" +#include "vc9202_common.h" +#endif + #define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) #define PPG_MAX_ARGC 8 #define PPG_MAX_ARGV_LEN 64 @@ -77,7 +82,10 @@ static uint32_t ppg_do_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) md = PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST; } else if (strcmp(mode, "graycard") == 0) { md = PPG_SERVICE_CMD_TYPE_DO_GRAYCARD_TEST; + } else if (strcmp(mode, "fpc") == 0) { + md = PPG_SERVICE_CMD_TYPE_FPC_TEST; } + if(enabled == 0 ) { if (md == PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST) diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp b/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp index 2c801e8f2..5374055fe 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp @@ -42,18 +42,42 @@ extern "C" { #include "ppg_service.h" #include "los_printf.h" +#include "thread_init.h" +#include "custom_utils.h" + + +#ifdef PPG_VC9202 +#include "vc9202_hal.h" +#include "vc9202_user.h" +#endif +#ifdef PPG_HX3695 #include "hx3695_hal.h" -#include "custom_utils.h" -#include "cywee_hal.h" -#include "cywee_service.h" -#include "custom_runtime.h" -#include "custom_save_runtime.h" +#endif + +#ifdef PPG_VC921X +#include "vc921x_hal.h" +#include "vc921x_user_app.h" +#endif static bool g_ppg_service_initialled = false; uint8_t card_databuf[64] = {0}; uint8_t light_databuf[64] = {0}; + +osTimerId_t g_ppg_service_timer = NULL; + +typedef uint32_t PPG_CMD_TYPE_T ; + +typedef enum{ + HX3695_MSG_TYPE_HRS_UPDATE, + HX3695_MSG_TYPE_HRV_UPDATE, + HX3695_MSG_TYPE_SPO2_UPDATE, + HX3695_MSG_TYPE_LEAKLIGHT_UPDATE, + HX3695_MSG_TYPE_GRAYCARD_UPDATE, + HX3695_MSG_TYPE_WEARSTAT_UPDATE, + HX3695_MSG_TYPE_STATIC_HRS_UPDATE, +} hx3695_msg_type_t; /*** * 其他cmd在Header里定义,对外开放 */ @@ -70,7 +94,7 @@ static bool ppg_service_running_stat = false; static bool ppg_sensor_exist = false; static uint8_t wear_mode_state = 0; -static uint8_t keep_in_wear_det_mod = 1; //持续坚持 佩戴检测模式 +static uint8_t keep_in_wear_det_mod = 0; //持续坚持 佩戴检测模式 void set_keep_in_wear_det_mode(uint8_t mod) @@ -78,6 +102,7 @@ void set_keep_in_wear_det_mode(uint8_t mod) keep_in_wear_det_mod = mod; } +#if 0 //漏光测试 errcode_t update_leaklight_event_notify(uint8_t *data) { @@ -220,6 +245,8 @@ void hx3695_msg_callback(uint8_t msg_type, uint8_t *msg_data, int32_t msg_datale } } +#endif + void uapi_ppg_service_deinit(void) { ppg_service_running_stat = false; @@ -238,8 +265,8 @@ uint32_t ppg_resume(void) void send_ppg_cmd_msg(int cmd) { int ret; - if (ppg_sensor_exist == false) - return ; + // if (ppg_sensor_exist == false) + // return ; PPG_CMD_TYPE_T mail = 0; mail = cmd; @@ -266,21 +293,20 @@ static void ppg_service_check_task(void *arg) } if((wear_mode_state == 1) && (mail > 0x10) && mail != PPG_SERVICE_CMD_TYPE_STOP_WEAR_MODE_TEST) { - uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_STOP); wear_mode_state = 0; - ppg_send_cmd_to_driver("wear",0); + // ppg_send_cmd_to_driver("wear",0); ppg_service_running_stat = false; } char* cmd = "hrs"; int enable = 1; if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_320TIMER_CALLBACK){ - heart_rate_meas_timeout_handler(NULL); + // heart_rate_meas_timeout_handler(NULL); continue; }else if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_40TIMER_CALLBACK){ - agc_timeout_handler(NULL); + // agc_timeout_handler(NULL); continue; }else if(mail == PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_5000TIMER_CALLBACK){ - wear_mode_timeout_handler(NULL); + // wear_mode_timeout_handler(NULL); continue; }else if (mail == PPG_SERVICE_CMD_TYPE_DO_PPG_TEST){ //do_cywee_service_check_msg(CYWEE_SERVICE_CMD_OPEN_GET_ACC,NULL); @@ -291,11 +317,16 @@ static void ppg_service_check_task(void *arg) { uapi_pm_add_sleep_veto(PM_ID_HEART); } - + // osTimerStart(g_ppg_service_timer,400); }else if (mail == PPG_SERVICE_CMD_TYPE_DO_HRV_TEST){ cmd = "hrv"; enable = 1; }else if (mail == PPG_SERVICE_CMD_TYPE_DO_SPO2_TEST){ + uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); + if (cnt == 0) + { + uapi_pm_add_sleep_veto(PM_ID_HEART); + } cmd = "spo2"; enable = 1; }else if (mail == PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST){ @@ -306,7 +337,6 @@ static void ppg_service_check_task(void *arg) enable = 1; }else if (mail == PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_TEST){ if (keep_in_wear_det_mod == 0) continue;; - uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_START); cmd = "wear"; enable = 1; wear_mode_state = 1; @@ -329,50 +359,74 @@ static void ppg_service_check_task(void *arg) { uapi_pm_remove_sleep_veto(PM_ID_HEART); } + // osTimerStop(g_ppg_service_timer); }else if (mail == PPG_SERVICE_CMD_TYPE_STOP_SPO2_TEST){ - + uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART); + if (cnt == 1) + { + uapi_pm_remove_sleep_veto(PM_ID_HEART); + } cmd = "spo2"; enable = 0; } else if (mail == PPG_SERVICE_CMD_TYPE_OPEN_HRS_BLE) { - hx3695_set_hrs_ble_swtich(1); + // hx3695_set_hrs_ble_swtich(1); continue ; } else if (mail == PPG_SERVICE_CMD_TYPE_CLOSE_HRS_BLE) { - hx3695_set_hrs_ble_swtich(0); + // hx3695_set_hrs_ble_swtich(0); continue ; + }else if (mail == PPG_SERVICE_CMD_TYPE_INT_HANDLER){ +#ifdef PPG_VC9202 + vc9202_usr_interrupt_handler(SPORT_TYPE_NORMAL,0); +#elif defined PPG_VC921X + cmd = "int"; + enable = 1; + ppg_send_cmd_to_vc921x_driver(cmd,enable); +#endif + continue; } - if (ppg_service_running_stat == true && enable ==1 ) - { - PRINT_ERR("ppg service already started! \r\n"); - continue ; - }else if ( ppg_service_running_stat == false && enable == 0 ) - { - PRINT_ERR("ppg service already stopped! \r\n"); - continue ; + else if (mail == PPG_SERVICE_CMD_TYPE_FPC_TEST){ +#ifdef PPG_VC9202 + cmd = "fpc"; + enable = 1; +#endif } -#ifdef PPG_HX3695 - ppg_send_cmd_to_driver(cmd,enable); + // if (ppg_service_running_stat == true && enable ==1 ) + // { + // PRINT_ERR("ppg service already started! \r\n"); + // continue ; + // }else if ( ppg_service_running_stat == false && enable == 0 ) + // { + // PRINT_ERR("ppg service already stopped! \r\n"); + // continue ; + // } + +#ifdef PPG_VC9202 + ppg_send_cmd_to_vc9202_driver(cmd,enable); +#elif defined PPG_VC921X + ppg_send_cmd_to_vc921x_driver(cmd,enable); +#endif + if(enable == 1) ppg_service_running_stat = true; else ppg_service_running_stat = false; + if((strcmp(cmd, "wear") != 0) && (enable == 0)) { if (keep_in_wear_det_mod == 1) { - uapi_save_runtime_log(RUNTIME_LOG_WEAR_MIN_START); - ppg_send_cmd_to_driver("wear",1); + //ppg_send_cmd_to_driver("wear",1); wear_mode_state = 1; ppg_service_running_stat = true; } } -#endif - } + } void create_ppg_queue(void) { @@ -387,10 +441,10 @@ errcode_t uapi_ppg_service_init(void) PRINT("uapi_ppg_service_init !\r\n"); - + tyhx_poweron(); #ifdef PPG_HX3695 - tyhx_poweron(); + if ( hx3695_chip_check() == false) { //TODO 没找到3695,退出线程 @@ -398,18 +452,26 @@ errcode_t uapi_ppg_service_init(void) tyhx_poweroff(); return ERRCODE_FAIL; } - tyhx_poweroff(); hx3695_register_msg_callback(hx3695_msg_callback);//注册驱动回调 - // ppg_send_cmd_to_driver("wear",0); - - ppg_sensor_exist = true; + // //ppg_send_cmd_to_driver("wear",0); +#elif defined PPG_VC9202 + if ( vc9202_drv_get_chip_id() != 0x21) + { + //TODO 没找到3695,退出线程 + PRINT("PPG_VC9202 not exist!\r\n"); + tyhx_poweroff(); + return ERRCODE_FAIL; + } #endif + tyhx_poweroff(); + + ppg_sensor_exist = true; app_task_definition_t taskcfg={0}; taskcfg.create_queue_handle = create_ppg_queue; taskcfg.attr.name="ppg_service"; - taskcfg.attr.priority = osPriorityBelowNormal4; + taskcfg.attr.priority = osPriorityHigh; taskcfg.attr.stack_size = PPG_SERVICE_TASK_SIZE; taskcfg.func = ppg_service_check_task; taskcfg.use_mem = USE_EXTEND_MEM; @@ -421,9 +483,20 @@ errcode_t uapi_ppg_service_init(void) return ERRCODE_FAIL; } + + // g_ppg_service_timer = osTimerNew((osTimerFunc_t)ppg_int_callback, osTimerPeriodic, NULL, NULL); + return ERRCODE_SUCC; } +void ppg_int_callback(pin_t pin, uintptr_t param) +{ + uapi_gpio_clear_interrupt(pin); + uint32_t tm; + uapi_get_timestampe_ms(&tm); + PRINT("ppg_int_callback %d 0x%X tm : %d \n",pin,param,tm); + send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_INT_HANDLER); +} // void ppg_service_service_resume(void) // { // DEBUG_PRINTF("ppg_service_service resume!\r\n"); diff --git a/code/sdk/zhihui/drivers/ppg/service/ppg_service.h b/code/sdk/zhihui/drivers/ppg/service/ppg_service.h index 9e2f8ff80..67682fdf8 100644 --- a/code/sdk/zhihui/drivers/ppg/service/ppg_service.h +++ b/code/sdk/zhihui/drivers/ppg/service/ppg_service.h @@ -2,7 +2,7 @@ * @Author: penglei 1624952103@qq.com * @Date: 2024-03-27 09:07:00 * @LastEditors: penglei 1624952103@qq.com - * @LastEditTime: 2024-11-23 22:07:09 + * @LastEditTime: 2024-12-10 17:11:28 * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/service/ppg_service.h * @Description: * @@ -28,6 +28,7 @@ extern "C" { #include "stdint.h" #include "errcode.h" +#include "platform_core.h" #define PPG_SERVICE_CMD_TYPE_DO_WEAR_MODE_5000TIMER_CALLBACK 0x09 #define PPG_SERVICE_CMD_TYPE_DO_PPG_40TIMER_CALLBACK 0x0A @@ -45,6 +46,8 @@ extern "C" { #define PPG_SERVICE_CMD_TYPE_DO_SINGLE_CHECK_MODE_TEST 0x23 #define PPG_SERVICE_CMD_TYPE_OPEN_HRS_BLE 0x24 #define PPG_SERVICE_CMD_TYPE_CLOSE_HRS_BLE 0x25 +#define PPG_SERVICE_CMD_TYPE_INT_HANDLER 0x26 +#define PPG_SERVICE_CMD_TYPE_FPC_TEST 0x27 errcode_t uapi_ppg_service_init(void); void uapi_ppg_service_deinit(void); @@ -89,6 +92,8 @@ typedef struct { //设置佩戴检测模式 void set_keep_in_wear_det_mode(uint8_t mod); +void ppg_int_callback(pin_t pin, uintptr_t param); + #ifdef __cplusplus #if __cplusplus } diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/vc9202/CMakeLists.txt new file mode 100644 index 000000000..0bf14bb6e --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/CMakeLists.txt @@ -0,0 +1,63 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "ppg_sensor_vc9202") + +if("PPG_VC9202" IN_LIST DEFINES) +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc9202_driver_testmode.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc9202_driver.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc9202_user_debug.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc9202_user.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc9202_hal.c +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/inc + +) + +else() +set(SOURCES ${SOURCES} + # ${CMAKE_CURRENT_SOURCE_DIR}/ztw523_touch/ztw523_ctrl.c +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR} +) +endif() + + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES +) + +set(PUBLIC_DEFINES +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +if("PPG_VC9202" IN_LIST DEFINES) + find_library(LIB_PATH_VC9202_1 lib/lib_BIO_v151_int_miniSDK_log_02.a ${CMAKE_CURRENT_SOURCE_DIR}) + find_library(LIB_PATH_VC9202_2 lib/lib_hr_v640ed04_miniSDK_NA_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + find_library(LIB_PATH_VC9202_3 lib/lib_Sp_Int_HaiSi_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + find_library(LIB_PATH_VC9202_4 lib/lib_spo2_9202A4_limit_HaiSi_NA_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + + target_link_libraries(${TARGET_NAME} PRIVATE -Wl,--whole-archive ${LIB_PATH_VC9202_1} ${LIB_PATH_VC9202_2} ${LIB_PATH_VC9202_3} ${LIB_PATH_VC9202_4} PRIVATE -Wl,--whole-archive) +endif() +build_component() + diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/BIODetect_V15_1.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/BIODetect_V15_1.h new file mode 100644 index 000000000..d03b0b1dd --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/BIODetect_V15_1.h @@ -0,0 +1,16 @@ + + +#ifndef BIODETECT +#define BIODETECT + +#include +#include +#include + +void f_BIOInit(int32_t gapDeltaBIO, int32_t gapDeltaPS); + +uint8_t f_BIOdetect(int32_t inputBIO, int32_t inputPS, int32_t PSth); + +char* bioVersion(void); + +#endif /* BIODETECT */ \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/algo.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/algo.h new file mode 100644 index 000000000..a370e99ff --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/algo.h @@ -0,0 +1,70 @@ + +#ifndef APP_ALGO_ALGO_H +#define APP_ALGO_ALGO_H + +#include +#include + +typedef enum +{ + SPORT_TYPE_NORMAL =0x00, // 日常 + SPORT_TYPE_RUNNING =0x01, // 跑步 + SPORT_TYPE_RIDE_BIKE =0X02, // 骑行 + SPORT_TYPE_JUMP_ROPE =0X03, // 跳绳 + SPORT_TYPE_SWIMMING =0X04, // 游泳 + SPORT_TYPE_BADMINTON =0X05, // 羽毛球 + SPORT_TYPE_TABLE_TENNIS=0X06, // 乒乓球 + SPORT_TYPE_TENNIS =0X07, // 网球 + SPORT_TYPE_CLIMBING =0X08, // 爬山 + SPORT_TYPE_WALKING =0X09, // 椭圆机 + SPORT_TYPE_BASKETBALL =0X0A, // 篮球 + SPORT_TYPE_FOOTBALL =0X0B, // 足球 + SPORT_TYPE_BASEBALL =0X0C, // 棒球 + SPORT_TYPE_VOLLEYBALL =0X0D, // 排球 + SPORT_TYPE_CRICKET = 0X0E, // 板球 + SPORT_TYPE_RUGBY = 0X0F, // 橄榄球 + SPORT_TYPE_HOCKEY =0X10, // 曲棍球 + SPORT_TYPE_DANCE = 0X11, // 跳舞 + SPORT_TYPE_SPINNING = 0X12, // 动感单车 + SPORT_TYPE_YOGA = 0X13, // 瑜伽 + SPORT_TYPE_SIT_UP =0X14, // 仰卧起坐 + SPORT_TYPE_TREADMILL =0X15, // 跑步机 + SPORT_TYPE_GYMNASTICS =0X16, // 体操 + SPORT_TYPE_BOATING = 0X17, // 划船 + SPORT_TYPE_JUMPING_JACK = 0X18, // 开合跳 + SPORT_TYPE_FREE_TRAINING = 0X19,// 自由训练 + SPORT_TYPE_PERIODIC_MONITORING = 0X1A,// 定时监测模式 +} AlgoSportMode; +//未出现在上表中的运动形式均先以跑步输入 + + +typedef struct +{ + int32_t x; + int32_t y; + int32_t z; +}AlgoAxesData_t; + +typedef struct +{ + int32_t hrData; + int32_t reliability; +}AlgoOutputData_t; + +typedef struct +{ + AlgoAxesData_t axes; + int32_t ppgSample; + int32_t envSample; +}AlgoInputData_t; + +void Algo_Init(void); +void Algo_Input(AlgoInputData_t *pInputData,int32_t gaptime,AlgoSportMode sportMode,int16_t surfaceRecogMode,int16_t opticalAidMode); +void Algo_Output(AlgoOutputData_t *pOutputData); + + + +#endif /* APP_ALGO_ALGO_H_ */ + + + diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/spo2Algo.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/spo2Algo.h new file mode 100644 index 000000000..351643ae3 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/spo2Algo.h @@ -0,0 +1,14 @@ +#ifndef __SPO2ALGO_H__ +#define __SPO2ALGO_H__ + +#include + +void spo2AlgoInit(void); +int32_t spo2Algo(int32_t r_ppg, int32_t ir_ppg, int32_t mode); + +void spo2_algo_content_init(void); + +char * +version_info_spo2(void); + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc30x91x92x_common.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc30x91x92x_common.h new file mode 100644 index 000000000..36badd54a --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc30x91x92x_common.h @@ -0,0 +1,87 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-07 16:04:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-09 10:32:42 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/ppg/vc9202/vc30x91x92x_common.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc30x91x92x_common.h + * @brief configuration file for vc30x,vc91x,vc92x. + * @details + * @author + * @date + * @version + *********************************************************************************************************/ +#ifndef __VC30x91x92x_COMMON_H__ +#define __VC30x91x92x_COMMON_H__ + +#include "algo.h" +#include "spo2Algo.h" +#include "vcSportMotionIntAlgo.h" + +#ifndef SUB +#define SUB(a, b) ((a) - (b)) +#endif +#ifndef ABS +#define ABS(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) +#endif + +#define FUNC_DISABLE (0) +#define FUNC_ENABLE (!FUNC_DISABLE) +#define WEAR_IS_DROP (0) +#define WEAR_IS_HOLD (1) + +typedef enum +{ + WEAR_STA_NONE = 0, + WEAR_STA_HOLD = 1, + WEAR_STA_DROP = 2, +}WearStatusTypeDef; + +typedef enum +{ + WORK_MODE_NONE = 0, + WORK_MODE_HR = 1, + WORK_MODE_SPO2 = 2, + WORK_MODE_HRV = 3, /* 100hz������ʹ��BIO������Ҫ��֤�ܹ��õ���ʱ��Ӧ��������Ȼ���ܻᵼ�¶��жϣ����������� */ + WORK_MODE_STRESS = 4, + WORK_MODE_WEAR = 5, + WORK_MODE_FACTORY = 6, + WORK_MODE_TEMPERATURE = 7, + WORK_MODE_FPC_TEST = 8, +}WorkModeTypeDef; + +typedef struct +{ + unsigned short sampling_gap_time; + WorkModeTypeDef work_mode; +}InitParamTypeDef; + +typedef struct +{ + unsigned char led_cur[3]; + unsigned char pd_res[3]; + unsigned char env_val[3]; + unsigned char pre_val[2]; + unsigned char ps_val; + unsigned char aenv_val[3]; + unsigned char apdbias_val[4]; + unsigned int pdbias; + unsigned char apre_val[2]; + unsigned char aps_val; + unsigned int ppg_data[128]; + unsigned short int bio_val_i; + unsigned short int bio_val_o; + signed short int temp_val_i; + signed short int temp_val_o; +}SamplingDataTypeDef; + +extern unsigned char usr_iic_write_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size); +extern unsigned char usr_iic_read_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size); +extern unsigned int usr_get_clock_ticks(void); + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_common.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_common.h new file mode 100644 index 000000000..64d5ff998 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_common.h @@ -0,0 +1,77 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-07 16:04:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-10 18:40:24 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/ppg/vc9202/inc/vc9202_common.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc9202_common.h + * @brief configuration file for the hardware driver layer + * @details + * @author + * @date + * @version + *********************************************************************************************************/ +#ifndef __VC9202_COMMON_H__ +#define __VC9202_COMMON_H__ + +#include "vc30x91x92x_common.h" + +#define VC9202_CFG_DRV_BY_TIMER (FUNC_DISABLE) +/* VC_COMMON_VC9202_CFG_SAMPLE_RATE: default 25hz */ +#define VC9202_CFG_SAMPLE_RATE (25) +/*VC_COMMON_CFG_GPIO_TIME: 0-50us, 1-100us, 2-200us, 3-400us */ +#define VC9202_CFG_INTERRUPT_TIME (3) +/* 0:rising edge 1:descending edge */ +#define VC9202_CFG_INTERRUPT_MODE (0) + +#define VC9202_CFG_CLK_CHECK_FREQUENCY (32000) //counter 32K +#define VC9202_CFG_CLK_CHECK_MAX (0xFFFFFF) //24bits counter +#define VC9202_CFG_CLK_CHECK_GAPTIME (10) //seconds +#define VC9202_CFG_CLK_CHECK_DEVIATION (3) + +/**************************************************************************** + * Configuration wear parameters + ***************************************************************************/ +#define VC9202_CFG_WEAR_DETECTION (FUNC_ENABLE) // FUNC_DISABLE FUNC_ENABLE +#define VC9202_CFG_WEAR_DEFAULT_STATUS (WEAR_IS_HOLD) //1 is default wear,0 is default not wear WEAR_IS_HOLD WEAR_IS_DROP +#define VC9202_CFG_WEAR_BIO_EN (FUNC_ENABLE) +#define VC9202_CFG_WEAR_ALG_EN (FUNC_DISABLE) //开启心率摘下功能,必须开启满足(ATC|BIO)为真 +#define VC9202_CFG_WEAR_ACT_EN (FUNC_DISABLE) +#define VC9202_CFG_WEAR_THRESHOLD_EN (FUNC_ENABLE) //绝对阈值宏开关 +#define VC9202_CFG_WEAR_HOLD_CNT (1) +#define VC9202_CFG_WEAR_DROP_CNT (3) + +/* sensor serial default wear param */ +#define VC9202_CFG_WEAR_PARAM_PS (128) +#define VC9202_CFG_WEAR_PARAM_PSIN (100) +#define VC9202_CFG_WEAR_PARAM_ENVMAX (128) //8*16 +#define VC9202_CFG_WEAR_PARAM_ENVMIN (64) //4*16 +#define VC9202_CFG_WEAR_PARAM_BIOIN (40) + +#define VC9202_CFG_PS_SLOT_CUR (0x3A) /* 0x5A */ +#define VC9202_CFG_PS_SLOT_RES (0x47) + +/* board cap halve,电容减半,需要提高一倍采样率的配置 */ +#define VC9202_CFG_IS_HALVE_CAP 0 + +/* VC9202 function */ +extern unsigned char vc9202_drv_reg_init(InitParamTypeDef *pInit_Param); +extern unsigned char vc9202_drv_get_chip_id(void); +extern void vc9202_drv_start_sampling(void); +extern void vc9202_drv_stop_sampling(void); +extern void vc9202_drv_soft_reset(void); +extern unsigned char vc9202_drv_channel_switch(unsigned char num_channel, unsigned char enable_flag); +extern unsigned char vc9202_drv_get_int_reason(void); +extern void vc9202_drv_set_algo_wear_status(WearStatusTypeDef status); +extern void vc9202_drv_set_gsensor_actuating_quantity(unsigned int axis_diff); +extern WearStatusTypeDef vc9202_drv_get_wear_status(void); +extern unsigned char vc9202_drv_get_sampling_data(SamplingDataTypeDef *pSamplingData, unsigned char *psize); +/* electrostatic patch */ +extern void vc9202_drv_electrostatic_death( void ); + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_driver.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_driver.h new file mode 100644 index 000000000..047534aaa --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_driver.h @@ -0,0 +1,184 @@ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************* + * @file vc9202_driver.h + * @brief vc9202 driver layer interface implementation. + * @details + * @author + * @date + * @version + *********************************************************************************************************/ + +#ifndef __VC9202_DRIVER_H__ +#define __VC9202_DRIVER_H__ + +#include "vc9202_common.h" + +#define VC9202_STATUS_CONFLICT (1<<4) +#define VC9202_STATUS_INSAMPLE (1<<3) +#define VC9202_STATUS_OVERLOAD2 (1<<2) +#define VC9202_STATUS_OVERLOAD1 (1<<1) +#define VC9202_STATUS_OVERLOAD0 (1<<0) + +#define VC9202_EVENT_TEMP_MARK (1<<6) //128 +#define VC9202_EVENT_BIO_MARK (1<<5) //64 +#define VC9202_EVENT_PS_MARK (1<<4) //32 +#define VC9202_EVENT_OV_MARK (1<<3) //8 +#define VC9202_EVENT_FIFO_MARK (1<<2) //4 +#define VC9202_EVENT_ENV_MARK (1<<1) //2 +#define VC9202_EVENT_PPG_MARK (1<<0) //1 + +#define VC9202_MAX_RES_LEVEL 17 //21 9202offset只有0-2,3和2一样、所以表中只有17个等效 +#define VC9202_MAX_CUR_LEVEL 0x6F + +#define VC9202_ENV_MAX_TH 8*16 + +/* adjust marco */ +#define VC9202_PPG_TH_CELL 10 // Causes of PPG interruption PPG_TH = 300 +#define VC9202_ADJUST_INCREASE 22 // 1.4 << 4 = 22.4//1.4f +#define VC9202_ADJUST_DECREASE 11 // 0.7 << 4 = 11.2//0.7f +#define VC9202_ADJUST_STEP_MAX 32 +#define VC9202_ADJUST_STEP_MIN 1 +#define VC9202_SLOTCHNU 3 + +/* bio算法运算结果宏定义 */ +#define VC9202_BIO_STA_NONE 0 +#define VC9202_BIO_STA_DROP 1 +#define VC9202_BIO_STA_HOLD 2 + +/**************************************************************************** + * driver ret enum + ***************************************************************************/ +typedef enum +{ + RET_OK = 0, + RET_STATUS_ERR = (1<<0), + RET_OVERLOAD_ERR = (1<<1), + RET_ENV_ERR = (1<<2), + RET_PPG_ERR = (1<<3), + RET_OSC_ERR = (1<<4), + RET_FIFO_ERR = (1<<5), +}VC9202DrvRetTypeDef; + +/**************************************************************************** + * clock calibration_struct + ***************************************************************************/ +typedef struct +{ + unsigned int last_clk_count; + unsigned int osc_gap_cnt; + unsigned char count_index; + unsigned int osc_count[6]; + unsigned int clk_count[6]; + unsigned int last_clk_check; /* 2023.06.05,check running gaptime */ +}VC9202OscClkTypeDef; + +/**************************************************************************** + * WearStatus_struct + ***************************************************************************/ +typedef struct +{ + unsigned char wear_ps; + unsigned char wear_env; + short int wear_bio; + unsigned char wear_hold_cnt; + unsigned char wear_drop_cnt; + WearStatusTypeDef wear_status; + WearStatusTypeDef last_status; +}VC9202WearInfoTypeDef; + +typedef enum +{ + WEAR_NO_CHANGE = 0, + DROP_TO_HOLD = 1, + HOLD_TO_DROP = 2, +}VC9202WearChangeTypeDef; + +/**************************************************************************** + * ADJUST_struct + ***************************************************************************/ +typedef struct +{ + unsigned char res; + unsigned char offset; + unsigned char low; +}VC9202ResTableTypeDef; + +typedef struct +{ + unsigned char res_val; + unsigned char low_res; + unsigned char offset; + unsigned char offset3; +}VC9202ResLevelTypeDef; + +typedef enum +{ + AGC_DIR_NULL = 0, + AGC_DIR_UP = 1, + AGC_DIR_DOWN = 2, +}VC9202AgcDirTypeDef; + +typedef struct +{ + VC9202AgcDirTypeDef dir; + VC9202AgcDirTypeDef last_dir; + unsigned char current_step; +}VC9202AgcInfoTypeDef; + +typedef struct +{ + unsigned char max_current; + unsigned char max_res_level; + unsigned char record_env; + unsigned char slot_env; + unsigned char current; + unsigned char res_level; + VC9202AgcInfoTypeDef info; +}VC9202AdjustSlotTypeDef; + +/**************************************************************************** + * Dev_struct + ***************************************************************************/ +typedef struct +{ + unsigned short fifo_time; + unsigned char work_frequency; + unsigned char enable_bio; + WorkModeTypeDef work_mode; + + unsigned char work_status; + unsigned int int_event; + + WearStatusTypeDef wear_status; + unsigned char osc_clk_status; + unsigned char enfifo_div; + unsigned char enslot[2]; + unsigned char slot_number; + unsigned char read_fifo_address; + +}VC9202DrvInfoTypeDef; + +/**************************************************************************** + * test_struct + ***************************************************************************/ +typedef struct +{ + unsigned char wait_cnt; + unsigned char step1_ret; // step1_ret/step2_ret/step3_ret:0-wait test,1-pass,2-failed + unsigned char icid; + unsigned char reason; + unsigned char leak_pre_value; + unsigned char max_current; + signed short temperature; + unsigned int frequency; + + unsigned char step2_ret; + unsigned char ps_value; + unsigned short biovalue_max; + unsigned short biovalue_now[2]; + unsigned short biovalue_gap[2]; +} VC9202TestInfoTypeDef; + + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_hal.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_hal.h new file mode 100644 index 000000000..44f0a2f8f --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_hal.h @@ -0,0 +1,56 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-06-07 11:18:26 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-21 17:20:43 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.h + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ +#ifndef VC_9202_H__ +#define VC_9202_H__ +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" + +#ifdef PPG_HX3695 + +#include "tyhx_hrs_custom.h" + + +typedef uint32_t PPG_CMD_TYPE_T ; + +typedef enum{ + HX3695_MSG_TYPE_HRS_UPDATE, + HX3695_MSG_TYPE_HRV_UPDATE, + HX3695_MSG_TYPE_SPO2_UPDATE, + HX3695_MSG_TYPE_LEAKLIGHT_UPDATE, + HX3695_MSG_TYPE_GRAYCARD_UPDATE, + HX3695_MSG_TYPE_WEARSTAT_UPDATE, + HX3695_MSG_TYPE_STATIC_HRS_UPDATE, +} hx3695_msg_type_t; + + +typedef void (*hx3695_msg_callback_t)(uint8_t msg_type, uint8_t *msg_data, int32_t msg_datalen); +uint32_t hx3695_register_msg_callback(hx3695_msg_callback_t func); +hx3695_msg_callback_t hx3695_get_send_msg_callback_func(void); + +#endif + +void ppg_send_cmd_to_vc9202_driver(char* mode, uint8_t enable); + +uint32_t tyhx_poweron(void); +uint32_t tyhx_poweroff(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_user.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_user.h new file mode 100644 index 000000000..f2f07eccd --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vc9202_user.h @@ -0,0 +1,58 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-07 16:04:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-21 17:20:35 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/ppg/vc9202/inc/vc9202_user.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc9202_user.h + * @brief functional Module Layer + * @details The functional interface is implemented by calling the driver.contain init_func,irq_handler + * @author + * @date + * @version + *********************************************************************************************************/ + +#ifndef __VC9202_USER_H__ +#define __VC9202_USER_H__ + +#include "vc9202_common.h" + +/* gsensor struct */ +typedef struct +{ + unsigned char sampling_rate; /* 25hz,50hz */ + unsigned char sensing_range; /* ±4G, ±8G, ±16G*/ + unsigned char effective_bits; /* 11(12)bit, 15(16)bit */ + + int gsensor_x_axis[40]; + int gsensor_y_axis[40]; + int gsensor_z_axis[40]; +}GsensorTypeDef; + + +typedef struct +{ + short int hr_rate; + unsigned char spo2_val; + unsigned char hrv_results; + unsigned char stress_results; + signed short int temperature_value; +}AlgoCalcResultsTypeDef; + +void vc9202_usr_init( InitParamTypeDef *pInitParam ); +void vc9202_usr_get_chip_id( unsigned char *pchip_id, unsigned char *pvers_id ); +void vc9202_usr_start_sampling(void); +void vc9202_usr_stop_sampling(void); +void vc9202_usr_soft_reset(void); +unsigned char vc9202_usr_channel_switch(unsigned char num_channel, unsigned char enable_flag); +unsigned char vc9202_usr_get_int_reason(void); +unsigned char vc9202_usr_get_wear_status(void); +void vc9202_usr_interrupt_handler( AlgoSportMode hr_alg_mode, unsigned char spo2_alg_mode ); + +#endif + diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/inc/vcSportMotionIntAlgo.h b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vcSportMotionIntAlgo.h new file mode 100644 index 000000000..b137a7f06 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/inc/vcSportMotionIntAlgo.h @@ -0,0 +1,13 @@ +#ifndef __VCSPORTMOTIONALGOH__ +#define __VCSPORTMOTIONALGOH__ + +#include +#include +#include + + +void vcSportMotionAlgoInit(void); +int32_t vcSportMotionCalculate(int32_t x, int32_t y, int32_t z); +char* version_info_SportMotion(void); + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/.WeDrive b/code/sdk/zhihui/drivers/ppg/vc9202/lib/.WeDrive new file mode 100644 index 000000000..c285ea891 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/lib/.WeDrive @@ -0,0 +1 @@ +C:\Users\zwj\Documents\WXWork\1688852039096625\WeDrive\维客昕微\技术支持组和应用方案开发组公共文件\1.心率IC\1.心率+血氧资料\2.驱动文件\VCHR9202\drv_9202_sensor_v218\algo \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_V151_MiniSdk_NA_01.a b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_V151_MiniSdk_NA_01.a new file mode 100644 index 000000000..cee79a175 Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_V151_MiniSdk_NA_01.a differ diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_v151_int_miniSDK_log_01.a b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_v151_int_miniSDK_log_01.a new file mode 100644 index 000000000..de6f1fb76 Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_v151_int_miniSDK_log_01.a differ diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_v151_int_miniSDK_log_02.a b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_v151_int_miniSDK_log_02.a new file mode 100644 index 000000000..051247082 Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_BIO_v151_int_miniSDK_log_02.a differ diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_Sp_Int_HaiSi_01.a b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_Sp_Int_HaiSi_01.a new file mode 100644 index 000000000..0d572721f Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_Sp_Int_HaiSi_01.a differ diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_hr_v640ed04_miniSDK_NA_01.a b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_hr_v640ed04_miniSDK_NA_01.a new file mode 100644 index 000000000..b19f240ef Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_hr_v640ed04_miniSDK_NA_01.a differ diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_spo2_9202A4_limit_HaiSi_NA_01.a b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_spo2_9202A4_limit_HaiSi_NA_01.a new file mode 100644 index 000000000..c98d6dd3f Binary files /dev/null and b/code/sdk/zhihui/drivers/ppg/vc9202/lib/lib_spo2_9202A4_limit_HaiSi_NA_01.a differ diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_driver.c b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_driver.c new file mode 100644 index 000000000..5164e20fe --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_driver.c @@ -0,0 +1,1621 @@ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc9202_driver.c + * @brief vc9202 driver layer interface implementation. + * @details + * @author + * @date + * @version + *********************************************************************************************************/ +#include "vc9202_common.h" +#include "vc9202_driver.h" +#include "BIODetect_V15_1.h" + +/* static wear status declaration */ +static int bio_result = VC9202_BIO_STA_NONE; +static WearStatusTypeDef alg_wear_status = WEAR_STA_HOLD; +static unsigned int gsnesor_axis_diff = 0; +static VC9202WearInfoTypeDef dev9202_wear = {0}; +/* static adjust data declaration */ +static VC9202AdjustSlotTypeDef dev9202_adjust[3] = {0}; +static unsigned char ppg_mark[128 / 2] = {0}; +/* static device data declaration */ +static VC9202DrvInfoTypeDef dev9202_info = {0}; +/* static oscclk data declaration */ +static VC9202OscClkTypeDef dev9202_clk = {0}; + +static int Bio_Max_Value = 0; +static int Bio_Max_Diff_Value = 0; +static int Bio_Min_Diff_Value = 0; +static int Bio_Old_Value = 0; +static uint8_t Bio_cnt = 0; +static uint8_t Bio_HOLD_cnt = 0; +static uint8_t BIO_HOLD_DROP_FLAG = 2; +/* global test infomation declaration */ +extern VC9202TestInfoTypeDef vc9202_test_info; +extern void vc9202_test_handler(SamplingDataTypeDef *pResult, VC9202TestInfoTypeDef *ptest_info); +extern void vc9202_test_init(VC9202TestInfoTypeDef *ptest_info); +/* res-level tab */ +const static VC9202ResTableTypeDef res_table[22] = { + /* level: 0 */ {0, 0, 1}, + /* level: 1 */ {1, 0, 1}, + /* level: 2 */ {2, 0, 1}, + /* level: 3 */ {3, 0, 1}, + /* level: 4 */ {4, 0, 1}, + /* level: 5 */ {5, 0, 1}, + /* level: 6 */ {0, 0, 0}, + /* level: 7 */ {1, 0, 0}, + /* level: 8 */ {2, 0, 0}, + /* level: 9 */ {3, 0, 0}, + /* level:10 */ {4, 0, 0}, + /* level:11 */ {5, 0, 0}, + /* level:12 */ {6, 0, 0}, + /* level:13 */ {7, 0, 0}, + /* level:14 */ {6, 1, 0}, /* +2 */ + /* level:15 */ {7, 1, 0}, + /* level:16 */ {6, 2, 0}, /* +4 */ + /* level:17 */ {7, 2, 0}, + /* level:18 */ {6, 3, 0}, /* +6 */ + /* level:19 */ {7, 3, 0}, + /* level:20 */ {6, 4, 0}, /* +8 */ + /* level:21 */ {7, 4, 0}, +}; // 21-5 = 16 + +void vc9202_drv_set_gsensor_actuating_quantity(unsigned int axis_diff) +{ + gsnesor_axis_diff = axis_diff; +} + +void vc9202_drv_set_algo_wear_status(WearStatusTypeDef status) +{ + alg_wear_status = status; +} + +/******************************************************************************************************** + * 时钟校准部分 + ********************************************************************************************************/ +static void vc9202_drv_clear_clk(void) +{ + dev9202_clk.osc_gap_cnt = 0; + dev9202_clk.count_index = 0; + dev9202_clk.last_clk_count = 0; + dev9202_info.osc_clk_status = 0; + + dev9202_clk.last_clk_check = 0; +} +/** + * @brief 时钟校验,与原来的VC9201系列一致 + * @param 无 + * @retval + 0 校验正常通过 + 1 vc9202计数当次就溢出 + 2 mcu tick或vc9202后两次中断的时候有计数溢出 + 3 频率计算没有通过 + */ +static unsigned char vc9202_drv_calibration_osc_clk(void) +{ + unsigned char count_vaild = 1; + unsigned char i = 0; + unsigned char osc_buf[4] = {0}; + unsigned int osc_tick[2] = {0}; + unsigned int clock_tick[2] = {0}; + unsigned short int calc_div[2] = {0}; + unsigned short int mean_div = 0; + unsigned char reg_div1[2] = {0}; + /* 判断是否需要校准时钟,如不需则直接返回 */ + unsigned int sec_gap_cnt = VC9202_CFG_CLK_CHECK_GAPTIME * 1000 / dev9202_info.fifo_time; + if (dev9202_info.osc_clk_status && dev9202_clk.osc_gap_cnt++ <= sec_gap_cnt) + { + return 0; + } + /* 获取时钟计数 */ + clock_tick[0] = usr_get_clock_ticks(); + usr_iic_read_bytes(0x07, osc_buf, 4); + clock_tick[1] = usr_get_clock_ticks(); + osc_tick[0] = (osc_buf[0] << 8) + osc_buf[1]; + osc_tick[1] = (osc_buf[2] << 8) + osc_buf[3]; + if ((osc_tick[0] > osc_tick[1]) || (clock_tick[0] > clock_tick[1])) + { + dev9202_clk.count_index = 0; + return 1; + } + /* 存入校准缓存 */ + dev9202_clk.osc_count[dev9202_clk.count_index * 2] = osc_tick[0]; + dev9202_clk.osc_count[dev9202_clk.count_index * 2 + 1] = osc_tick[1]; + dev9202_clk.clk_count[dev9202_clk.count_index * 2] = clock_tick[0]; + dev9202_clk.clk_count[dev9202_clk.count_index * 2 + 1] = clock_tick[1]; + dev9202_clk.count_index++; + if (dev9202_clk.count_index >= 3) + { + dev9202_clk.count_index = 0; + for (i = 0; i < 2; i++) + { + count_vaild = count_vaild && (ABS((dev9202_clk.clk_count[2 * i + 2] - dev9202_clk.clk_count[2 * i]), (dev9202_clk.clk_count[2 * i + 3] - dev9202_clk.clk_count[2 * i + 1])) < VC9202_CFG_CLK_CHECK_DEVIATION); + count_vaild = count_vaild && (ABS((dev9202_clk.osc_count[2 * i + 2] - dev9202_clk.osc_count[2 * i]), (dev9202_clk.osc_count[2 * i + 3] - dev9202_clk.osc_count[2 * i + 1])) < VC9202_CFG_CLK_CHECK_DEVIATION); + count_vaild = count_vaild && (!(dev9202_clk.clk_count[2 * i + 2] == dev9202_clk.clk_count[2 * i])); /* avoid divisor==0, diffCountIsOk set false */ + } + if (count_vaild) + { + for (i = 0; i < 2; i++) + { + calc_div[i] = ((unsigned int)dev9202_clk.osc_count[2 * i + 2] - dev9202_clk.osc_count[2 * i]) * VC9202_CFG_CLK_CHECK_FREQUENCY / dev9202_info.work_frequency / ((unsigned int)dev9202_clk.clk_count[2 * i + 2] - dev9202_clk.clk_count[2 * i]) - 1; + if (calc_div[i] < (20000 / dev9202_info.work_frequency * 0.75f) || calc_div[i] > (20000 / dev9202_info.work_frequency * 1.25f)) + { + return 3; + } + } + /* 比较两次计算偏差是否合理 */ + if ((calc_div[1] - calc_div[0] <= 20) || (calc_div[0] - calc_div[1] <= 20)) + { + mean_div = (calc_div[1] + calc_div[0]) / 2; + reg_div1[0] = mean_div >> 8; + reg_div1[1] = mean_div; + usr_iic_write_bytes(0x14, reg_div1, 2); + dev9202_clk.count_index = 0; + dev9202_clk.osc_gap_cnt = 0; + dev9202_info.osc_clk_status = 1; + return 0; + } + } + } + return 2; +} +/******************************************************************************************************** + * 摘配带判断部分 + ********************************************************************************************************/ +/** + * @brief 佩戴检测,bio检测计算(内部阅读:f_BIOdetect,在BIO+PS均由佩戴产生的边缘时输出2佩戴;摘下时只依赖PS边缘) + * @param + bio_value bio采样值 + ps_value ps采样值 + * @retval bio结果 + */ +static int vc9202_drv_calc_biology_sense(unsigned short int bio_value, unsigned char ps_value, unsigned char env) +{ + static unsigned char calc_ps = 0; + static unsigned short int calc_bio = 0; + static int Bio_Diff_Value = 0; + int ret = 0; + if (bio_value) + { + calc_bio = bio_value; + Bio_Diff_Value = abs(Bio_Old_Value - calc_bio); + Bio_Old_Value = calc_bio; + } + if (ps_value) + { + calc_ps = ps_value; + } + if ((calc_ps < 100) && (env > 4)) + { + if (Bio_Diff_Value < VC9202_CFG_WEAR_PARAM_BIOIN * 0.2) + { + Bio_Max_Value = calc_bio; + Bio_Max_Diff_Value = Bio_Max_Value - (VC9202_CFG_WEAR_PARAM_BIOIN * 0.8); + Bio_Min_Diff_Value = Bio_Max_Value - (VC9202_CFG_WEAR_PARAM_BIOIN * 1.5); + } + } + if (Bio_Max_Diff_Value) + { + if ((calc_bio > Bio_Max_Diff_Value) && (Bio_Diff_Value < VC9202_CFG_WEAR_PARAM_BIOIN * 0.2)) + { + Bio_HOLD_cnt++; + if (Bio_HOLD_cnt > 4) + { + BIO_HOLD_DROP_FLAG = 1; + } + } + else if (calc_bio < Bio_Min_Diff_Value) + { + Bio_cnt++; + if (Bio_cnt > 2) + { + BIO_HOLD_DROP_FLAG = 2; + } + } + else + { + Bio_cnt = 0; + Bio_HOLD_cnt = 0; + BIO_HOLD_DROP_FLAG = 0; + } + } + uint32_t tm; + uapi_get_timestampe_ms(&tm); + printf("before f_BIOdetect bio_value :%d , ps_value : %d , env : %d , tm : %d\n",bio_value,ps_value,env,tm); + printf("before f_BIOdetect calc_bio :%d , calc_ps : %d , VC9202_CFG_WEAR_PARAM_PS : %d ,tm : %d , ret : %d\n",calc_bio,calc_ps,VC9202_CFG_WEAR_PARAM_PS,tm,ret); + ret = f_BIOdetect(calc_bio, calc_ps, VC9202_CFG_WEAR_PARAM_PS); + printf("after f_BIOdetect calc_bio :%d , calc_ps : %d , VC9202_CFG_WEAR_PARAM_PS : %d ,tm : %d , ret : %d\n",calc_bio,calc_ps,VC9202_CFG_WEAR_PARAM_PS,tm,ret); + printf("after f_BIOdetect bio_value :%d , ps_value : %d , env : %d , tm : %d\n",bio_value,ps_value,env,tm); + if (VC9202_BIO_STA_HOLD == ret) + { + vc9202_drv_set_algo_wear_status(WEAR_STA_HOLD); /* bio */ + bio_result = VC9202_BIO_STA_HOLD; + } + else if (VC9202_BIO_STA_DROP == ret) + { + bio_result = VC9202_BIO_STA_DROP; + } + return bio_result; +} +/** + * @brief 佩戴检测过程及状态 + * @param *pwear-佩戴结构体,env-环境光,ps-ps值,bio-活体值 + * @retval 识别改变结果 + */ +static VC9202WearChangeTypeDef vc9202_drv_wear_status_identify(VC9202WearInfoTypeDef *pwear, unsigned char env, unsigned char ps, unsigned short int bio) +{ + printf("vc9202_drv_wear_status_identify bio : %d \n",bio); + VC9202WearChangeTypeDef ret_change = WEAR_NO_CHANGE; + int ret_bio_algo = VC9202_BIO_STA_NONE; + /* bio算法运算 */ + if (dev9202_info.enable_bio) + { + ret_bio_algo = vc9202_drv_calc_biology_sense(bio, ps, env); + } + else + { + ret_bio_algo = VC9202_BIO_STA_HOLD; /* 20230614 因为下面的条件把(ret_bio_algo== )佩戴的条件删了,所以此处必须添加,不然在未开bio的模式下无法佩戴*/ + } +#if (FUNC_DISABLE == VC9202_CFG_WEAR_THRESHOLD_EN) + BIO_HOLD_DROP_FLAG = 2; +#endif +#if (FUNC_DISABLE == VC9202_CFG_WEAR_BIO_EN) + ret_bio_algo = VC9202_BIO_STA_NONE; + BIO_HOLD_DROP_FLAG = 2; +#endif +#if (FUNC_DISABLE == VC9202_CFG_WEAR_ALG_EN) + alg_wear_status = WEAR_STA_HOLD; +#endif +#if (FUNC_DISABLE == VC9202_CFG_WEAR_ACT_EN) + gsnesor_axis_diff = 1; +#endif + switch (pwear->wear_status) + { + case WEAR_STA_DROP: + printf("WEAR_STA_DROP ps : %d , env : %d , ret_bio_algo : %d , alg_wear_status : %d , gsnesor_axis_diff : %d , BIO_HOLD_DROP_FLAG : %d\n",ps,env,ret_bio_algo,alg_wear_status,gsnesor_axis_diff,BIO_HOLD_DROP_FLAG); + if ((ps >= VC9202_CFG_WEAR_PARAM_PS) && (env <= VC9202_CFG_WEAR_PARAM_ENVMIN) && (VC9202_BIO_STA_HOLD == ret_bio_algo) && + (WEAR_STA_HOLD == alg_wear_status) && (1 == gsnesor_axis_diff) && (BIO_HOLD_DROP_FLAG == 2)) + { + if (--pwear->wear_hold_cnt <= 0) + { + pwear->wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT; + pwear->wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT; + ret_change = DROP_TO_HOLD; + } + } + else + { + pwear->wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT; + } + break; + + case WEAR_STA_HOLD: + printf("WEAR_STA_HOLD ps : %d , env : %d , ret_bio_algo : %d , alg_wear_status : %d , BIO_HOLD_DROP_FLAG : %d\n",ps,env,ret_bio_algo,alg_wear_status,BIO_HOLD_DROP_FLAG); + if ((ps < VC9202_CFG_WEAR_PARAM_PS) || (env > VC9202_CFG_WEAR_PARAM_ENVMIN) || (VC9202_BIO_STA_DROP == ret_bio_algo) || (WEAR_STA_DROP == alg_wear_status) || (BIO_HOLD_DROP_FLAG == 1)) + { + if ((WEAR_STA_DROP == alg_wear_status) || (ret_bio_algo == VC9202_BIO_STA_DROP)) + { + pwear->wear_drop_cnt = 1; + } + if (--pwear->wear_drop_cnt <= 0) + { + pwear->wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT; + pwear->wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT; + ret_change = HOLD_TO_DROP; + } + } + else + { + pwear->wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT; + } + break; + default: + break; + } + return ret_change; +} + +/** + * @brief 佩戴检测及通道的开关 + * @param 无 + * @retval 佩戴检测状态 + */ +WearStatusTypeDef vc9202_drv_get_wear_status(void) +{ + WearStatusTypeDef wear_status = dev9202_wear.last_status; /* last status */ + VC9202WearChangeTypeDef calc_status = WEAR_NO_CHANGE; + unsigned char event = 0; + unsigned char en_int = 0; + unsigned char env_value = 0, ps_value = 0; + unsigned char bio_buffer[4] = {0}; + unsigned short int bio_value = 0; + unsigned char wear_interrupt = 0; + unsigned char slot_index = 0; +#if (VC9202_CFG_WEAR_DETECTION != FUNC_ENABLE) + return WEAR_IS_HOLD; +#endif + usr_iic_read_bytes(0x11, &en_int, 1); +#if 0 + usr_iic_read_bytes(0x02, &event, 1); +#else + event = dev9202_info.int_event; +#endif +#if (FUNC_ENABLE == VC9202_CFG_DRV_BY_TIMER) /* 定时触发时,不看中断原因,可能被清掉 */ + wear_interrupt = 1; +#else + /* 使能了PsInt,且使能PS */ + if ((event & VC9202_EVENT_PS_MARK) && (en_int & (1 << 4))) + { + wear_interrupt = 1; + } + /* 未使能PsInt下,ps_ppg同频通过fifo中断去识别摘配带 */ + if (event & VC9202_EVENT_FIFO_MARK) + { + wear_interrupt = 1; + } +#endif + /* 非心率模式,就算使能了运动量,也没有去做处理,直接置1忽略 */ + if (dev9202_info.work_mode != WORK_MODE_HR && dev9202_info.work_mode != WORK_MODE_WEAR) + { + gsnesor_axis_diff = 1; + } + if (wear_interrupt) + { +/* 读取佩戴检测所需的数据 */ +#if 0 + usr_iic_read_bytes(0x43, &env_value, 1); + usr_iic_read_bytes(0x46, &ps_value, 1); + usr_iic_read_bytes(0x4B, bio_buffer, 4); + bio_value = (bio_buffer[2] << 8) + bio_buffer[3]; +#else + env_value = dev9202_wear.wear_env; + ps_value = dev9202_wear.wear_ps; + bio_value = dev9202_wear.wear_bio; +#endif + /* 根据数据得出佩戴状态 */ + calc_status = vc9202_drv_wear_status_identify(&dev9202_wear, env_value, ps_value, bio_value); + if (DROP_TO_HOLD == calc_status) + { + wear_status = WEAR_STA_HOLD; + dev9202_wear.wear_status = wear_status; + dev9202_wear.last_status = wear_status; + InitParamTypeDef init_param = {dev9202_info.fifo_time, dev9202_info.work_mode}; + vc9202_drv_reg_init(&init_param); + } + else if (HOLD_TO_DROP == calc_status) + { + wear_status = WEAR_STA_DROP; + dev9202_wear.wear_status = wear_status; + dev9202_wear.last_status = wear_status; + /* 关灯操作:获取那些ppg通道使能/记录当前使能的通道,然后关闭通道 */ + for (slot_index = 0; slot_index <= 1; slot_index++) + { + if (dev9202_info.enslot[slot_index]) + { + vc9202_drv_channel_switch(slot_index, 0); + } + } + } /* end of(HOLD_TO_DROP == calc_status) */ + } + return wear_status; +} + +/******************************************************************************************************** + * IC状态读取部分,包括IC异常状态处理,常规数据的读取,ENV、PPG调整部分 + ********************************************************************************************************/ +/** + * @brief 等效电阻等级转化为寄存器参数 + * @param level 等效电阻等级 + * @retval 寄存器参数 + */ +static VC9202ResLevelTypeDef vc9202_drv_res_level_to_register(unsigned char level) +{ + VC9202ResLevelTypeDef reg; + reg.res_val = res_table[level].res; + reg.low_res = res_table[level].low; + if (res_table[level].offset >= 4) + { + reg.offset = 0; + reg.offset3 = 1; + } + else + { + reg.offset = res_table[level].offset; + reg.offset3 = 0; + } + return reg; +} + +/** + * @brief 寄存器参数转化为等效电阻等级 + * @param 寄存器参数 + * @retval 等效电阻等级 + */ +static unsigned char vc9202_drv_res_register_to_level(VC9202ResLevelTypeDef *preg) +{ + unsigned char index = 0; + unsigned char level = 0; + VC9202ResTableTypeDef table = {0}; + if (preg->offset3 == 1) + { + table.offset = 4; + } + else + { + table.offset = preg->offset; + } + table.res = preg->res_val; + table.low = preg->low_res; + for (index = 0; index < sizeof(res_table) / sizeof(res_table[0]); index++) + { + if (res_table[index].res == table.res && res_table[index].offset == table.offset && res_table[index].low == table.low) + { + level = index; + break; + } + } + return level; +} + +/** + * @brief 设置通道电流参数 + * @param 无 + * @retval 无 + */ +static void vc9202_drv_set_ppgSlot_current(unsigned char slot_index, unsigned char cur) +{ + unsigned char reg = 0; + unsigned char addr = 0x17 + slot_index; + cur = (cur > 0x7f) ? 0x7f : cur; + usr_iic_read_bytes(addr, ®, 1); + reg &= (1 << 7); + reg |= cur; + usr_iic_write_bytes(addr, ®, 1); +} + +/** + * @brief 设置通道电阻参数 + * @param 设置的通道号,设定的值 + * @retval 无 + */ +static void vc9202_drv_set_ppgSlot_resistance(unsigned char slot_index, unsigned char level) +{ + unsigned char reg_addr = 0x1A + slot_index; + unsigned char res_reg = 0; + unsigned char res_ext[2] = {0}; + VC9202ResLevelTypeDef res = {0}; + level = (level > VC9202_MAX_RES_LEVEL) ? VC9202_MAX_RES_LEVEL : level; + res = vc9202_drv_res_level_to_register(level); + usr_iic_read_bytes(0x22, res_ext, 2); + switch (slot_index) + { + case 0: + res_ext[0] &= ~(3 << 4); /* offset */ + res_ext[0] |= (res.offset << 4); + res_ext[0] &= ~(1 << 0); /* lowres */ + res_ext[0] |= (res.low_res << 0); + res_ext[1] &= ~(1 << 0); + res_ext[1] |= (res.offset3 << 0); + break; + case 1: + res_ext[0] &= ~(3 << 6); /* offset */ + res_ext[0] |= (res.offset << 6); + res_ext[0] &= ~(1 << 1); /* lowres */ + res_ext[0] |= (res.low_res << 1); + res_ext[1] &= ~(1 << 2); + res_ext[1] |= (res.offset3 << 2); + break; + default: + break; + } + usr_iic_read_bytes(reg_addr, &res_reg, 1); + res_reg &= (0x8f); + res_reg |= (res.res_val << 4); + usr_iic_write_bytes(reg_addr, &res_reg, 1); + usr_iic_write_bytes(0x22, res_ext, 2); +} +/** + * @brief 读取PPG饱和中断时的采样值 + * @param enfifo-是否使能fifo,slot_num-通道数,slot_index-通道号, *pdata 数据指针 + * @retval 返回当前读取地址 + */ +static unsigned char vc9202_drv_adjust_ppg_read(unsigned char enfifo, unsigned char slot_num, unsigned char slot_index, unsigned int *pdata) +{ + unsigned char write_index = 0, fifo_addr = 0; + unsigned char fifo_buff[2] = {0}; + /* PPG IRQ addr */ + usr_iic_read_bytes(0x03, &write_index, 1); + fifo_addr = write_index - slot_num * 2 + slot_index * 2; + fifo_addr = (fifo_addr < 0x80) ? (fifo_addr + 0x80) : (fifo_addr); + fifo_addr = enfifo ? fifo_addr : 0x80 + slot_index * 2; + /* read PPG data */ + usr_iic_read_bytes(fifo_addr, fifo_buff, 2); + *pdata = (fifo_buff[0] << 8) + fifo_buff[1]; + return write_index; +} + +/** + * @brief 参数调整时,添加调整标志位 + * @param 无 + * @retval 无 + */ +static void vc9202_drv_adjust_set_fifo_mark(unsigned char slot_index) // SamplingDataTypeDef **pp_result, unsigned char rindex, unsigned char windex, unsigned char slot_num ) +{ + unsigned char mark_ppg_index = 0; + unsigned char mark_offset = 0; + unsigned char rindex = dev9202_info.read_fifo_address; + unsigned char windex = 0; + usr_iic_read_bytes(0x03, &windex, 1); + /* calc PPGOffset */ + if (windex > rindex) + { + mark_offset = (windex - rindex); + } + else + { + mark_offset = windex + 128 - rindex; + } + if ((mark_offset < 2) || (mark_offset > 128)) + { + return; + } + mark_ppg_index = mark_offset / 2 - dev9202_info.slot_number + slot_index; /* 如果是双通道,要判断是那个通道产生的调整 */ + ppg_mark[mark_ppg_index] = 1; +} + +/** + * @brief 检测因电阻过大,电流的最小步长调整都会反复饱和的情况 + * @param dir 调整方向, slot_index 当前通道, res_level 当前电阻等级, cur 当前电流值 + * @retval 1:错误,0:正常 + */ +static unsigned char vc9202_drv_adjust_res_error(VC9202AgcDirTypeDef dir, unsigned char slot_index, uint8_t res_level, uint8_t cur) +{ + static VC9202AgcDirTypeDef lastDir = AGC_DIR_NULL; + static uint8_t last_level = 0; + static uint8_t last_cur[2][3] = {0}; + static uint8_t log_cnt = 0; + if (lastDir != dir && last_level == res_level) + { + last_cur[slot_index][0] = last_cur[slot_index][1]; + last_cur[slot_index][1] = last_cur[slot_index][2]; + last_cur[slot_index][2] = cur; + if (last_cur[slot_index][0] == last_cur[slot_index][2]) + log_cnt++; + } + else + { + log_cnt = 0; + } + lastDir = dir; + last_level = res_level; + if (log_cnt >= 3) + { + log_cnt = 0; + return 1; + } + else + { + return 0; + } +} + +/** + * @brief PPG饱和时,上/下调整电流电阻配置参数 + * @param *padjust-调整结构体,thh_res-电阻限值,thh_cur-电流限值,slot_index-通道编号 + * @retval 执行结果 + */ +static VC9202DrvRetTypeDef vc9202_drv_adjust_ppg_slot_current_res_config(VC9202AdjustSlotTypeDef *padjust, unsigned char thh_res, unsigned char thh_cur, unsigned char slot_index) +{ + unsigned char old_res_lvl = 0; + unsigned char old_current = 0; + unsigned short int old_current_step = 0; + old_res_lvl = padjust->res_level; + old_current = padjust->current; + old_current_step = padjust->info.current_step; + /* 电流已经最大,调电阻 */ + if (padjust->current == thh_cur) + { + if (old_res_lvl == thh_res) + { + return RET_PPG_ERR; + } + else + { + if (padjust->info.dir == AGC_DIR_UP) + { + padjust->res_level = (old_res_lvl >= VC9202_MAX_RES_LEVEL) ? (VC9202_MAX_RES_LEVEL) : (old_res_lvl + 1); + } + else + { + padjust->res_level = (old_res_lvl < 1) ? (0) : (old_res_lvl - 1); + } + vc9202_drv_adjust_set_fifo_mark(slot_index); + } + } + else /* 电流可调 */ + { + /* step calc */ + if (padjust->info.last_dir == AGC_DIR_NULL) + { + old_current_step *= 16; + } + else if (padjust->info.dir == padjust->info.last_dir) + { + if ((old_current_step == 1) || (old_current_step == 2)) + { + old_current_step = (old_current_step + 1) * 16; + } + else + { + old_current_step *= VC9202_ADJUST_INCREASE; + } + } + else + { + old_current_step *= VC9202_ADJUST_DECREASE; + } + padjust->info.current_step = old_current_step >> 4; + padjust->info.current_step = (padjust->info.current_step <= VC9202_ADJUST_STEP_MIN) ? VC9202_ADJUST_STEP_MIN : padjust->info.current_step; + padjust->info.current_step = (padjust->info.current_step >= VC9202_ADJUST_STEP_MAX) ? VC9202_ADJUST_STEP_MAX : padjust->info.current_step; + /* 调整方向 */ + if (padjust->info.dir == AGC_DIR_UP) + { + padjust->current = ((old_current + padjust->info.current_step) > thh_cur) ? thh_cur : (old_current + padjust->info.current_step); + } + else + { + padjust->current = (old_current < padjust->info.current_step) ? thh_cur : old_current - padjust->info.current_step; + } + vc9202_drv_adjust_set_fifo_mark(slot_index); + padjust->info.last_dir = padjust->info.dir; + } + if (vc9202_drv_adjust_res_error(padjust->info.dir, slot_index, padjust->res_level, padjust->current)) + { + if (padjust->res_level >= 13) + { + padjust->res_level--; + } + } + /* 调整后的电流电阻写入寄存器 */ + vc9202_drv_set_ppgSlot_resistance(slot_index, padjust->res_level); + vc9202_drv_set_ppgSlot_current(slot_index, padjust->current); + return RET_OK; +} + +/** + * @brief 环境光饱和中断调整电阻 + * @param *padjust-调整结构体,slot_index-通道编号 + * @retval 执行结果 + */ +static VC9202DrvRetTypeDef vc9202_drv_adjust_env_configure(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index) +{ + if (padjust->slot_env > VC9202_ENV_MAX_TH) + { + padjust->record_env = padjust->slot_env; + if (padjust->res_level != 0) + { + padjust->res_level--; + padjust->max_res_level = padjust->res_level; + vc9202_drv_adjust_set_fifo_mark(slot_index); + vc9202_drv_set_ppgSlot_resistance(slot_index, padjust->res_level); + } + else + { + return RET_ENV_ERR; + } + } + return RET_OK; +} + +/** + * @brief 如果产生overload,降低电流,和电流的最大限制,过载电流-1 + * @param *padjust-调整结构体,slot_index-通道编号,status-状态值 + * @retval 执行结果 + */ +static VC9202DrvRetTypeDef vc9202_drv_adjust_over_load_configure(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index, unsigned char status) +{ + unsigned char overload[3] = {status & VC9202_STATUS_OVERLOAD0, status & VC9202_STATUS_OVERLOAD1, status & VC9202_STATUS_OVERLOAD2}; + if (overload[slot_index]) + { + if (padjust->current != 0) + { + padjust->current--; + padjust->max_current = padjust->current; + vc9202_drv_adjust_set_fifo_mark(slot_index); + vc9202_drv_set_ppgSlot_current(slot_index, padjust->current); + } + else + { + return RET_OVERLOAD_ERR; + } + } + return RET_OK; +} + +/** + * @brief 获取PPG进行电流电阻的调整 + * @param *padjust-调整结构体,slot_index-通道编号,enfifo-是否使能fifo, slot_num-通道数 + * @retval 执行结果 + */ +static VC9202DrvRetTypeDef vc9202_drv_adjust_ppg_configure(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index, unsigned char enfifo, unsigned char slot_num) +{ + static unsigned char last_index = 0, cnt = 0; + VC9202DrvRetTypeDef vc_ret = RET_OK; + unsigned char windex = 0; + unsigned char index_gap = 0; + unsigned int data = 0; + // 根据通道号和是否enfifo获取产生ppg中断的ppg值。 + windex = vc9202_drv_adjust_ppg_read(enfifo, slot_num, slot_index, &data); + /* 修改last dir */ + if (enfifo) + { + index_gap = (windex > last_index) ? (windex - last_index) : (windex - last_index + 0x80); + if (index_gap != slot_num * 2) + { + padjust->info.last_dir = AGC_DIR_NULL; + } + cnt++; + if (cnt >= slot_num) + { + cnt = 0; + last_index = windex; + } + } + /* 根据ppg值进行电流、等效电阻上下调节 */ + if (data >= 3770) + { + padjust->info.dir = AGC_DIR_UP; + vc_ret |= vc9202_drv_adjust_ppg_slot_current_res_config(padjust, padjust->max_res_level, padjust->max_current, slot_index); + } + else if (data < 320) + { + padjust->info.dir = AGC_DIR_DOWN; + vc_ret |= vc9202_drv_adjust_ppg_slot_current_res_config(padjust, 0, 0, slot_index); + } + return vc_ret; +} + +/** + * @brief 最大电阻的调整,通过判断环境光,来恢复电阻的最大限制 + * @param *padjust-调整结构体,slot_index-通道编号 + * @retval 无 + */ +static void vc9202_drv_res_max_resize(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index) +{ + static unsigned short int count_qares[2] = {0}; + static unsigned short int count_pdres[2] = {0}; + unsigned char min_env = 0; + // 该通道得最大电阻已经是最大的等级了,无需恢复退出 + if (padjust->max_res_level >= VC9202_MAX_RES_LEVEL) + { + return; + } + /* 获取一个环境光比较值,取上一次环境光调整时的一半或者环境光中断阈值 */ + min_env = (padjust->record_env / 2 < VC9202_ENV_MAX_TH) ? (padjust->record_env / 2) : VC9202_ENV_MAX_TH; + if (padjust->slot_env < min_env) + { + /* 环境光一直小于1,持续超过30次,那么直接将电阻限制设置为最大 */ + if (padjust->slot_env <= 1) + { + count_pdres[slot_index] = 0; + count_qares[slot_index] = (count_qares[slot_index] == 30) ? 0 : count_qares[slot_index] + 1; + padjust->max_res_level = (count_qares[slot_index] == 30) ? VC9202_MAX_RES_LEVEL : padjust->max_res_level; + } + else + { + /* 环境光一直小于比较值,持续超过120次,那么直接将电阻限制+1 */ + count_qares[slot_index] = 0; + count_pdres[slot_index] = count_pdres[slot_index] + 1; + padjust->max_res_level = (count_pdres[slot_index] == 120) ? padjust->max_res_level + 1 : padjust->max_res_level; + } + } + else + { + count_pdres[slot_index] = 0; + count_qares[slot_index] = 0; + } +} + +/* 判断PS通道的过载和环境光是否异常 */ +VC9202DrvRetTypeDef vc9202_drv_ps_slot_status(VC9202AdjustSlotTypeDef *p_slot_ps, unsigned char event, unsigned char status) +{ + VC9202DrvRetTypeDef vc_ret = RET_OK; +#if (FUNC_ENABLE == VC9202_CFG_DRV_BY_TIMER) /* 定时触发时,不看中断原因,因为可能被清掉 */ + if (status & VC9202_STATUS_OVERLOAD2) + { + vc_ret |= RET_OVERLOAD_ERR; + } + if (p_slot_ps->slot_env > VC9202_ENV_MAX_TH) + { + vc_ret |= RET_ENV_ERR; + } +#else + if ((event & VC9202_EVENT_OV_MARK) && (status & VC9202_STATUS_OVERLOAD2)) + { + vc_ret |= RET_OVERLOAD_ERR; + } + if ((event & VC9202_EVENT_ENV_MARK) && (p_slot_ps->slot_env > VC9202_ENV_MAX_TH)) + { + vc_ret |= RET_ENV_ERR; + } +#endif + return vc_ret; +} +/** + * @brief 识别IC的中断状态及中断事件,并对不同的情况进行调整处理等 + * @param status-工作状态, event-中断事件 + * @retval 执行结果 + */ +static VC9202DrvRetTypeDef vc9202_drv_status_event_verify(unsigned char status, unsigned char event) +{ + VC9202DrvRetTypeDef vc_ret = RET_OK; + unsigned char index = 0; + unsigned char index_slot = 0; + if (status & (VC9202_STATUS_CONFLICT | VC9202_STATUS_INSAMPLE)) + { + return RET_STATUS_ERR; + } + /* PS通道异常判断 */ + vc_ret |= vc9202_drv_ps_slot_status(&dev9202_adjust[2], event, status); + /* PPG通道的环境光读取,异常中断处理 */ + for (index = 0; index < dev9202_info.slot_number; index++) + { + index_slot = (dev9202_info.slot_number == 2) ? index : (dev9202_info.enslot[0] ? 0 : 1); + /* 恢复最大电阻的限制,根据当前 */ + vc9202_drv_res_max_resize(&dev9202_adjust[index_slot], index_slot); + /* over load, max current */ + if (event & VC9202_EVENT_OV_MARK) + { + printf("event & VC9202_EVENT_OV_MARK \n"); + vc_ret |= vc9202_drv_adjust_over_load_configure(&dev9202_adjust[index_slot], index_slot, status); + } + /* env, max res */ + if (event & VC9202_EVENT_ENV_MARK) + { + printf("event & VC9202_EVENT_ENV_MARK \n"); + vc_ret |= vc9202_drv_adjust_env_configure(&dev9202_adjust[index_slot], index_slot); + } + /* ppg interruput */ + if (event & VC9202_EVENT_PPG_MARK) + { + vc_ret |= vc9202_drv_adjust_ppg_configure(&dev9202_adjust[index_slot], index_slot, dev9202_info.enfifo_div, dev9202_info.slot_number); + printf("event & VC9202_EVENT_PPG_MARK vc_ret : 0x%x\n",vc_ret); + } + else + { + printf("event : 0x%x \n",event); + dev9202_adjust[index].info.dir = AGC_DIR_NULL; + dev9202_adjust[index].info.last_dir = AGC_DIR_NULL; + } + } + return vc_ret; +} + +/******************************************************************************************************** + * fifo 读取部分 + ********************************************************************************************************/ +/** + * @brief 校验fifo读写的偏移的可用性,及fifo是否翻转等错误。 + * @param rindex-读地址,windex-写地址,slot_num-通道数量,fifo_div-fifo深度 + * @retval 无 + */ +static VC9202DrvRetTypeDef vc9202_drv_fifo_infomation_check(unsigned char *rindex, unsigned char *windex, unsigned char slot_num, unsigned char fifo_div) +{ + unsigned int clk_diffs = 0; + unsigned int clk_count = usr_get_clock_ticks(); + /* 间隔时间的校验,后续看是否需要补充 */ + clk_diffs = (dev9202_clk.last_clk_count < clk_count) ? (clk_count - dev9202_clk.last_clk_count) : (clk_count - dev9202_clk.last_clk_count + VC9202_CFG_CLK_CHECK_MAX); + if (clk_diffs > (unsigned int)((64.0f / dev9202_info.work_frequency) * 0.8f * VC9202_CFG_CLK_CHECK_FREQUENCY / dev9202_info.slot_number)) + { + *windex = 0; + *rindex = 0x80; + dev9202_clk.last_clk_count = clk_count; + return RET_FIFO_ERR; + } + /* 读写地址的校验 */ + if (*windex < 0x80) + { + *rindex = *rindex + (fifo_div + 1) * 2; + if (*rindex < 0x80) + { + *rindex += 0x80; + } + dev9202_clk.last_clk_count = clk_count; + return RET_FIFO_ERR; + } + if (*rindex < 0x80) + { + *rindex = *windex; + dev9202_clk.last_clk_count = clk_count; + return RET_FIFO_ERR; + } + if (*windex == *rindex) + { + dev9202_clk.last_clk_count = clk_count; + return RET_FIFO_ERR; + } + dev9202_clk.last_clk_count = clk_count; + return RET_OK; +} + +/** + * @brief 获取fifos数据 + * @param enfifo-是否使能fifo,p_result-数据地址,psize-数据大小,rindex-读地址,windex-写地址,slot_num-通道数量 + * @retval 无 + */ +static void vc9202_drv_read_fifo_data(unsigned char enfifo, SamplingDataTypeDef *p_result, unsigned char *psize, unsigned char *rindex, unsigned char *windex, unsigned char slot_num) +{ + unsigned char i = 0; + unsigned char fifo_length = 0; + unsigned char fifoData[128] = {0}; + unsigned char fifo_index_offset = 0; /*正常情况下:r=w, 异常情况下,r=w-fifo_index_offset */ + /*------------- disable fifo -------------*/ + if (!enfifo) + { + *psize = slot_num; + usr_iic_read_bytes(0x80, fifoData, slot_num * 2); + for (i = 0; i < *psize; i++) + { + p_result->ppg_data[i] = (fifoData[i * 2] << 8) + fifoData[i * 2 + 1]; + if (ppg_mark[i]) + { + ppg_mark[i] = 0; + p_result->ppg_data[i] |= 0x1000; // 0x01000000; + } + } + return; + } + /*------------- enable fifo -------------*/ + /* 读取解析fifo数据 */ + if (*windex > *rindex) + { + fifo_length = *windex - *rindex; + if ((fifo_length % (dev9202_info.slot_number * 2)) && (dev9202_info.slot_number >= 2)) /* 当是多通道,但是通道数与字节数对应不上的异常处理 */ + { + fifo_index_offset = fifo_length % (dev9202_info.slot_number * 2); + fifo_length = fifo_length - fifo_index_offset; /* 只读取满足通道数的fifo数量,如果未出现异常,fifo_index_offset=0,跟之前处理一样 */ + } + usr_iic_read_bytes(*rindex, fifoData, fifo_length); + *rindex = *windex - fifo_index_offset; + } + else + { + fifo_length = *windex + 0x80 - *rindex; + if ((fifo_length % (dev9202_info.slot_number * 2)) && (dev9202_info.slot_number >= 2)) /* 当是多通道,但是通道数与字节数对应不上的异常处理 */ + { + fifo_index_offset = fifo_length % (dev9202_info.slot_number * 2); + fifo_length = fifo_length - fifo_index_offset; /* 只读取满足通道数的fifo数量 */ + } + if (*windex == 0x80) /* 数据刚好在0xfe-0xff截至 */ + { + usr_iic_read_bytes(*rindex, fifoData, fifo_length); + if (fifo_index_offset) + { + *rindex = *windex + 0x80 - fifo_index_offset; + } + else + { + *rindex = *windex - fifo_index_offset; /* fifo_index_offset=0 */ + } + } + else /* (*windex != 0x80): 0x80及以后还有数据 */ + { + usr_iic_read_bytes(*rindex, fifoData, (256 - *rindex)); /* 获取rindex-0xff的数据 */ + usr_iic_read_bytes(0x80, &fifoData[256 - *rindex], (*windex - 0x80) - fifo_index_offset); /* 剩下的数据部分如果存在 */ + *rindex = *windex - fifo_index_offset; + } + } + + *psize = fifo_length / 2; + for (i = 0; i < *psize; i++) + { + p_result->ppg_data[i] = (fifoData[i * 2] << 8) + fifoData[i * 2 + 1]; + if (ppg_mark[i]) + { + ppg_mark[i] = 0; + p_result->ppg_data[i] |= 0x1000; // 0x01000000; + } + } +} + +/** + * @brief 校验fifo并获取结果 + * @param p_result-数据地址,psize-数据大小 + * @retval 执行结果 + */ +static VC9202DrvRetTypeDef vc9202_drv_read_fifo_result(SamplingDataTypeDef *p_result, unsigned char *psize) +{ + VC9202DrvRetTypeDef vc_ret = RET_OK; + unsigned char write_index = 0; + unsigned char event = 0; + event = dev9202_info.int_event; +#if (VC9202_CFG_DRV_BY_TIMER == FUNC_ENABLE) + event = VC9202_EVENT_FIFO_MARK; +#endif + if (event & VC9202_EVENT_FIFO_MARK) + { + usr_iic_read_bytes(0x03, &write_index, 1); + vc_ret |= vc9202_drv_fifo_infomation_check(&dev9202_info.read_fifo_address, &write_index, dev9202_info.slot_number, dev9202_info.enfifo_div); + if (RET_OK == vc_ret && dev9202_info.osc_clk_status) + { + vc9202_drv_read_fifo_data(dev9202_info.enfifo_div, p_result, psize, &dev9202_info.read_fifo_address, &write_index, dev9202_info.slot_number); + } + } + return vc_ret; +} + +/*********************************************************************************************************/ +/** + * @brief 读取相关采样值和寄存器值 + * @param 无 + * @retval 无 + */ +static unsigned char vc9202_drv_read_reg(SamplingDataTypeDef *read_reg) +{ + unsigned char reg_val[6] = {0}; + unsigned char res_ext[2] = {0}; + VC9202ResLevelTypeDef res = {0}; + + /* 4bit数据读取 */ + usr_iic_read_bytes(0x04, reg_val, 3); + read_reg->pre_val[0] = reg_val[0] & 0x0F; + read_reg->pre_val[1] = reg_val[1] & 0x0F; + read_reg->env_val[0] = (reg_val[0] >> 4) & 0x0F; + read_reg->env_val[1] = (reg_val[1] >> 4) & 0x0F; + read_reg->env_val[2] = (reg_val[2] >> 4) & 0x0F; + read_reg->ps_val = reg_val[2] & 0x0F; + + /* old param */ + usr_iic_read_bytes(0x17, reg_val, 6); + read_reg->led_cur[0] = reg_val[0] & 0x7F; + read_reg->led_cur[1] = reg_val[1] & 0x7F; + read_reg->led_cur[2] = reg_val[2] & 0x7F; + read_reg->pd_res[0] = (reg_val[3] >> 4) & 0x07; + read_reg->pd_res[1] = (reg_val[4] >> 4) & 0x07; + read_reg->pd_res[2] = (reg_val[5] >> 4) & 0x07; + /* 8bit数据读取 */ + usr_iic_read_bytes(0x41, reg_val, 6); + read_reg->aenv_val[0] = reg_val[0]; + read_reg->aenv_val[1] = reg_val[1]; + read_reg->aenv_val[2] = reg_val[2]; + read_reg->apre_val[0] = reg_val[3]; + read_reg->apre_val[1] = reg_val[4]; + read_reg->aps_val = reg_val[5]; + /* new param */ + usr_iic_read_bytes(0x22, res_ext, 2); + /* slot0 */ + dev9202_adjust[0].slot_env = read_reg->aenv_val[0]; + dev9202_adjust[0].current = read_reg->led_cur[0]; + res.res_val = read_reg->pd_res[0]; + res.low_res = (res_ext[0] >> 0) & 0x01; + res.offset = (res_ext[0] >> 4) & 0x03; + res.offset3 = 0; + dev9202_adjust[0].res_level = vc9202_drv_res_register_to_level(&res); + /* slot1 */ + dev9202_adjust[1].slot_env = read_reg->aenv_val[1]; + dev9202_adjust[1].current = read_reg->led_cur[1]; + res.res_val = read_reg->pd_res[1]; + res.low_res = (res_ext[0] >> 1) & 0x01; + res.offset = (res_ext[0] >> 6) & 0x03; + res.offset3 = 0; + dev9202_adjust[1].res_level = vc9202_drv_res_register_to_level(&res); + /* slot2 */ + dev9202_adjust[2].slot_env = read_reg->aenv_val[2]; + dev9202_adjust[2].current = read_reg->led_cur[2]; + dev9202_adjust[2].res_level = read_reg->pd_res[2]; + /* 如果有等效电阻的等级,那么传出等效等级 */ + read_reg->pd_res[0] = dev9202_adjust[0].res_level; + read_reg->pd_res[1] = dev9202_adjust[1].res_level; + read_reg->pd_res[2] = dev9202_adjust[2].res_level; + /* pdbias */ + usr_iic_read_bytes(0x47, reg_val, 4); + read_reg->apdbias_val[0] = reg_val[0]; + read_reg->apdbias_val[1] = reg_val[1]; + read_reg->apdbias_val[2] = reg_val[2]; + read_reg->apdbias_val[3] = reg_val[3] & 0xf; + read_reg->pdbias = read_reg->apdbias_val[2] * 16 + read_reg->apdbias_val[3]; + + usr_iic_read_bytes(0x4B, reg_val, 4); + read_reg->bio_val_i = (reg_val[0] << 8) + reg_val[1]; + read_reg->bio_val_o = (reg_val[2] << 8) + reg_val[3]; + + if ((read_reg->aps_val >> 4) == read_reg->ps_val) /* 防止数据错误,4bit与8bit不匹配,则不对佩戴数据进行更新,防止因为异常摘下 */ + { + dev9202_wear.wear_ps = read_reg->aps_val; + dev9202_wear.wear_env = read_reg->pdbias; + dev9202_wear.wear_bio = read_reg->bio_val_o; + } + return 0; +} + +// 注意,该部分需要分为两部分,一部分为中断调用,一部分为定时调用,保证低端客户的可用性较高 +/** + * @brief 通过宏定义#if (FUNC_ENABLE==VC9202_CFG_DRV_BY_TIMER) 已经对定时器调用方式做了对应的处理,现在通用一个函数接口即可 + * @param 无 + * @retval 无 + */ +static VC9202DrvRetTypeDef vc9202_drv_gpio_event_handler(SamplingDataTypeDef *pResult, unsigned char *psize) +{ + VC9202DrvRetTypeDef vc_ret = RET_OK; + switch (dev9202_info.work_mode) + { + case WORK_MODE_HR: + vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event); + vc9202_drv_calibration_osc_clk(); + vc_ret |= vc9202_drv_read_fifo_result(pResult, psize); + break; + case WORK_MODE_SPO2: + vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event); + vc9202_drv_calibration_osc_clk(); + vc_ret |= vc9202_drv_read_fifo_result(pResult, psize); + break; + case WORK_MODE_HRV: + vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event); + vc9202_drv_calibration_osc_clk(); + vc_ret |= vc9202_drv_read_fifo_result(pResult, psize); + break; + case WORK_MODE_STRESS: + vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event); + vc9202_drv_calibration_osc_clk(); + vc_ret |= vc9202_drv_read_fifo_result(pResult, psize); + break; + case WORK_MODE_WEAR: + vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event); + vc9202_drv_calibration_osc_clk(); + break; + case WORK_MODE_FACTORY: + if (dev9202_info.int_event & VC9202_EVENT_OV_MARK) + { + vc_ret |= vc9202_drv_adjust_over_load_configure(&dev9202_adjust[0], 0, dev9202_info.work_status); + } + pResult->led_cur[0] = dev9202_adjust[0].max_current; + break; + case WORK_MODE_FPC_TEST: + vc9202_test_handler(pResult, &vc9202_test_info); + break; + default: + break; + } + return vc_ret; +} + +/** + * @brief 初始化驱动参数 + * @param + @pInit fifo_div fifo分频深度 + @pInit enslot 通道使能配置 + * @retval 无 + */ +void vc9202_drv_system_param_init(unsigned char fifo_div, unsigned char enslot) +{ + unsigned char i = 0; + /* dev info param init */ + dev9202_info.enfifo_div = fifo_div; + dev9202_info.enslot[0] = (enslot & 0x01); + dev9202_info.enslot[1] = (enslot & 0x02) >> 1; + dev9202_info.slot_number = dev9202_info.enslot[0] + dev9202_info.enslot[1]; + + dev9202_info.osc_clk_status = 0; + dev9202_info.read_fifo_address = 0x80; + /* dev9202_adjust info param init */ + for (i = 0; i < 2; i++) + { + dev9202_adjust[i].max_current = VC9202_MAX_CUR_LEVEL; + dev9202_adjust[i].max_res_level = VC9202_MAX_RES_LEVEL; + dev9202_adjust[i].record_env = 0; + dev9202_adjust[i].info.dir = AGC_DIR_NULL; + dev9202_adjust[i].info.last_dir = AGC_DIR_NULL; + dev9202_adjust[i].info.current_step = 4; + } + dev9202_adjust[2].max_res_level = VC9202_MAX_RES_LEVEL; + /* dev9202_wear param init */ +#if (VC9202_CFG_WEAR_DEFAULT_STATUS == WEAR_IS_HOLD) + dev9202_info.wear_status = WEAR_STA_HOLD; + dev9202_wear.wear_status = WEAR_STA_HOLD; + dev9202_wear.last_status = (WEAR_STA_NONE == dev9202_wear.last_status) ? WEAR_STA_HOLD : dev9202_wear.last_status; +#else + dev9202_wear.wear_status = WEAR_STA_DROP; + dev9202_wear.last_status = (WEAR_STA_NONE == dev9202_wear.last_status) ? WEAR_STA_DROP : dev9202_wear.last_status; +#endif +#if (VC9202_CFG_WEAR_DETECTION != FUNC_ENABLE) + dev9202_info.wear_status = WEAR_STA_HOLD; + dev9202_wear.wear_status = WEAR_STA_HOLD; + dev9202_wear.last_status = WEAR_STA_HOLD; +#endif + if (dev9202_wear.last_status == WEAR_STA_DROP && dev9202_info.work_mode != WORK_MODE_FACTORY && dev9202_info.work_mode != WORK_MODE_FPC_TEST) + { + if (dev9202_info.enslot[0]) + { + vc9202_drv_channel_switch(0, 0); + } + if (dev9202_info.enslot[1]) + { + vc9202_drv_channel_switch(1, 0); + } + } + dev9202_wear.wear_status = dev9202_wear.last_status; + dev9202_info.wear_status = dev9202_wear.wear_status; + alg_wear_status = WEAR_STA_HOLD; + dev9202_wear.wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT; + dev9202_wear.wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT; + vc9202_drv_clear_clk(); +#if 0 + f_BIOInit(VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN); + bio_result = VC9202_BIO_STA_NONE; + if( dev9202_wear.last_status==WEAR_STA_HOLD ) + { + bio_result = VC9202_BIO_STA_HOLD; + } + else + { + bio_result = VC9202_BIO_STA_NONE; + } +#else + printf("fifo_div : %d, enslot : %d \n", fifo_div, enslot ); + printf("f_BIOedgeinit(%d, %d) \n", VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN ); + if (VC9202_BIO_STA_NONE == bio_result) + { + uint32_t irq_sts = osal_irq_lock(); + f_BIOInit(VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN); + osal_irq_restore(irq_sts); + printf(" VC9202_BIO_STA_DROP == bio_result f_BIOedgeinit(%d, %d) \n", VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN ); + } +#endif +} + +/********************************************************************************************************* + * 对外功能函数 + ********************************************************************************************************/ + +/** + * @brief 获取chip_id + * @param 无 + * @retval chip_id值 + */ +unsigned char vc9202_drv_get_chip_id(void) +{ + unsigned char chip_id = 0; + usr_iic_read_bytes(0x00, &chip_id, 1); + printf("vc9202 chip id : 0x%x\n",chip_id); + return chip_id; +} + +/** + * @brief 开始采样 + * @param 无 + * @retval 无 + */ +void vc9202_drv_start_sampling(void) +{ + unsigned char temp = 0x00; + usr_iic_read_bytes(0x10, &temp, 1); + temp |= (1 << 7); + usr_iic_write_bytes(0x10, &temp, 1); +} + +/** + * @brief 停止采样 + * @param 无 + * @retval 无 + */ +void vc9202_drv_stop_sampling(void) +{ + unsigned char temp = 0x00; + usr_iic_read_bytes(0x10, &temp, 1); + temp &= ~(1 << 7); + usr_iic_write_bytes(0x10, &temp, 1); + bio_result = VC9202_BIO_STA_NONE; +} + +/** + * @brief 软复位 + * @param 无 + * @retval 无 + */ +void vc9202_drv_soft_reset(void) +{ + unsigned char reset_reg_cfg = 0x5A; + usr_iic_write_bytes(0x3B, &reset_reg_cfg, 1); +} + +/** + * @brief 独立使/失能某一物理通道 + * @param + @num_channel 通道编号(0,1,2) + @enable_flag 使能或失能标志位 + * @retval 0执行成功 + */ +unsigned char vc9202_drv_channel_switch(unsigned char num_channel, unsigned char enable_flag) +{ + unsigned char temp = 0x00; + usr_iic_read_bytes(0x10, &temp, 1); + if (num_channel > 2) + { + return 1; + } + if (enable_flag == 1) + { + temp |= (1 << num_channel); + usr_iic_write_bytes(0x10, &temp, 1); + /* 同频处理 */ + if (WORK_MODE_SPO2 == dev9202_info.work_mode) + { + usr_iic_read_bytes(0x11, &temp, 1); + temp &= ~(1 << 4); + usr_iic_write_bytes(0x11, &temp, 1); + temp = 0; + usr_iic_write_bytes(0x16, &temp, 1); + } + } + else if (enable_flag == 0) + { + temp &= ~(1 << num_channel); + usr_iic_write_bytes(0x10, &temp, 1); + /* 同频处理 */ + usr_iic_read_bytes(0x11, &temp, 1); + temp |= (1 << 4); + usr_iic_write_bytes(0x11, &temp, 1); + temp = dev9202_info.enfifo_div; + usr_iic_write_bytes(0x16, &temp, 1); + } + else + { + return 2; + } + return 0; +} + +/** + * @brief 获取中断原因 + * @param 无 + * @retval 中断原因 + */ +unsigned char vc9202_drv_get_int_reason(void) +{ + unsigned char int_reason = 0; + unsigned char int_enable = 0; + usr_iic_read_bytes(0x02, &int_reason, 1); + usr_iic_read_bytes(0x11, &int_enable, 1); + /* 在同频时,获取到的ps中断,并非ps所需要的中断 */ + if (!(int_enable & (1 << 4))) + { + int_reason &= ~(1 << 4); + } +#if (VC9202_CFG_DRV_BY_TIMER == FUNC_ENABLE) + int_reason = (VC9202_EVENT_PS_MARK | VC9202_EVENT_FIFO_MARK); +#endif + return int_reason; +} + +/** + * @brief 防止静电打死,自动恢复,定时去调用检查即可 + * @param 无 + * @retval + */ +void vc9202_drv_electrostatic_death(void) +{ + unsigned char work_reg = 1; + unsigned char bio_reg[2] = {1, 1}; + unsigned short bio_val = 0; + usr_iic_read_bytes(0x10, &work_reg, 1); + if(dev9202_info.enable_bio) + { + usr_iic_read_bytes(0x4D, bio_reg, 2); + } + bio_val = (bio_reg[1] << 8) + bio_reg[0]; + /* dev9202 death */ + if (0 == work_reg || 0 == bio_val) + { + InitParamTypeDef init_param = {dev9202_info.fifo_time, dev9202_info.work_mode}; + vc9202_drv_soft_reset(); + vc9202_drv_reg_init(&init_param); + } +} + +/** + * @brief 防止任务队列堆积处理,导致短时间连续执行 + * @param 无 + * @retval 0-pass,-1-fail + */ +#define CHECK_GAPTIME_RATIO 3/4 /* 最短中断时间的3/4,30ms,算上频率在[16K,24K]波动,限制的时间为[25~37]ms以内会被过滤掉 */ +static int vc9202_drv_check_running_gaptime(void) +{ + unsigned int last_count = dev9202_clk.last_clk_check; + unsigned int now_count = 0; + + unsigned int count1 = 0, count2 = 0; + unsigned int count_diff = 0; + unsigned char cnt_reg[4] = {0}; + int ret = 0; + unsigned char check_gap_time = (1000/dev9202_info.work_frequency)*CHECK_GAPTIME_RATIO; + usr_iic_read_bytes(0x07, cnt_reg, 4); + count1 = (cnt_reg[0] << 8) + cnt_reg[1]; + count2 = (cnt_reg[2] << 8) + cnt_reg[3]; + count_diff = (count1 <= count2) ? (count2 - count1) : (count2 - count1 + 0xffff); + /* count值获取正确有效 */ + if (count_diff <= 5) + { + now_count = count1; + } + count_diff = 8000; + if ((0 != now_count) && (0 != last_count)) + { + count_diff = (last_count <= now_count) ? (now_count - last_count) : (now_count - last_count + 0xffff); + } + /* 间隔时间过小,算上频率在[16K,24K]波动,限制的时间为[25~37]ms以内会被过滤掉 */ + if (count_diff <= 20 * check_gap_time) + { + ret = -1; + } + dev9202_clk.last_clk_check = now_count; + return ret; +} + +/** + * @brief 寄存器配置 + * @param + @pInit_Param->work_mode 工作模式 + @pInit_Param->sampling_gap_time FIFO中断间隔时间,FIFO深度 + * @retval 无 + */ +unsigned char vc9202_drv_reg_init(InitParamTypeDef *pInit_Param) +{ + unsigned short int clk_div = 0x0000; + unsigned char fifo_div = 0; + unsigned char reg_cfg[17] = {0x00, 0x1F, 0x8A, 0x00, 0x03, 0x1F, 0x00, 0x00, 0x80, 0x00, 0x57, 0x57, 0x07, 0x16, 0x56, 0x16, 0x00}; + unsigned char reg_new = (1 << 3); + unsigned char reg_bio_cfg[2] = {0x00, 0xA2}; +/* 设置中断触发方式 0上升沿 1下降沿 */ +#if VC9202_CFG_INTERRUPT_MODE + reg_cfg[1] |= (1 << 7); +#endif + +/* 设置中断电平保持时间 */ +#ifdef VC9202_CFG_INTERRUPT_TIME + reg_cfg[1] |= (VC9202_CFG_INTERRUPT_TIME << 5); +#endif + + /* 设置FIFO深度,FIFO/PS中断间隔时间,同时设置采样分频 */ + dev9202_info.work_frequency = VC9202_CFG_SAMPLE_RATE; + dev9202_info.work_mode = (WorkModeTypeDef)pInit_Param->work_mode; + dev9202_info.fifo_time = pInit_Param->sampling_gap_time; + if (WORK_MODE_HRV == dev9202_info.work_mode) + { + dev9202_info.work_frequency = 100; + dev9202_info.fifo_time = 200; + } + fifo_div = dev9202_info.fifo_time / (1000 / dev9202_info.work_frequency) - 1; + clk_div = (20000 / dev9202_info.work_frequency) - 1; + reg_cfg[3] = fifo_div; + reg_cfg[4] = (clk_div >> 8) & 0xFF; + reg_cfg[5] = (clk_div & 0xFF); + reg_cfg[6] = fifo_div; + + /* 设置PS通道PD电阻,LED电流 */ + reg_cfg[9] = VC9202_CFG_PS_SLOT_CUR; + reg_cfg[12] = VC9202_CFG_PS_SLOT_RES; + + switch (dev9202_info.work_mode) + { + case WORK_MODE_HR: + reg_cfg[0] = 0x45; +#if VC9202_CFG_IS_HALVE_CAP + reg_cfg[10] = 0x54; /* 根据发光时间设置滤波电阻 */ + reg_cfg[13] = 0x03; // 0x03; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */ + reg_cfg[16] = 0x01; /* 发光时间减半,开1倍过采 */ +#else + reg_cfg[10] = 0x57; /* 根据发光时间设置滤波电阻 0x57 */ + reg_cfg[13] = 0x16; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */ + reg_cfg[16] = 0x00; /* 发光时间减半,开1倍过采 */ +#endif + break; + + case WORK_MODE_SPO2: + reg_cfg[0] = 0x47; + reg_cfg[1] &= ~(1 << 4); /* 关闭PS中断 */ + reg_cfg[6] = 0x00; /* PS开同频,避免引入同频干扰 */ + reg_cfg[7] = 0x80; /* slot0(红光)开32倍增益 */ + reg_cfg[13] = 0xB6; /*B6-3 红外(物理通道2)映射到逻辑通道0,并设置采样时长为200us */ + reg_cfg[14] = 0x76; /*76-3 红光(物理通道1)映射到逻辑通道0,并设置采样时长为200us */ + reg_cfg[16] = 0x04; /* 开16倍过采 */ + break; + + case WORK_MODE_HRV: + reg_cfg[0] = 0x45; +#if VC9202_CFG_IS_HALVE_CAP + reg_cfg[10] = 0x54; /* 根据发光时间设置滤波电阻 */ + reg_cfg[13] = 0x03; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */ + reg_cfg[16] = 0x01; /* 发光时间减半,开1倍过采 */ +#else + reg_cfg[10] = 0x57; /* 根据发光时间设置滤波电阻 */ + reg_cfg[13] = 0x16; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */ + reg_cfg[16] = 0x00; /* 发光时间减半,开1倍过采 */ +#endif + reg_bio_cfg[1] = 0x00; + break; + + case WORK_MODE_STRESS: + reg_cfg[0] = 0x45; +#if VC9202_CFG_IS_HALVE_CAP + reg_cfg[10] = 0x54; /* 根据发光时间设置滤波电阻 */ + reg_cfg[13] = 0x03; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */ + reg_cfg[16] = 0x01; /* 发光时间减半,开1倍过采 */ +#else + reg_cfg[10] = 0x57; /* 根据发光时间设置滤波电阻 */ + reg_cfg[13] = 0x16; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */ + reg_cfg[16] = 0x00; /* 发光时间减半,开1倍过采 */ +#endif + break; + + case WORK_MODE_WEAR: + reg_cfg[0] = 0x44; + reg_cfg[1] = (reg_cfg[1] | (1 << 4)) & 0xF0; + break; + + case WORK_MODE_FACTORY: + reg_cfg[0] = 0x47; + reg_cfg[7] = 0xEF; + reg_cfg[8] = 0xEF; + reg_cfg[10] = 0x77; + reg_cfg[11] = 0x77; + break; + case WORK_MODE_FPC_TEST: + reg_cfg[0] = 0x47; + reg_cfg[7] = 0xEF; + reg_cfg[8] = 0xEF; + reg_cfg[10] = 0x77; + reg_cfg[11] = 0x77; + vc9202_test_init(&vc9202_test_info); + break; + default: + break; + } + usr_iic_write_bytes(0x10, reg_cfg, 17); /* 心率血氧相关寄存器配置 */ + usr_iic_write_bytes(0x22, ®_new, 1); + usr_iic_write_bytes(0x23, reg_bio_cfg, 2); /*BIO相关寄存器配置 */ + if (reg_bio_cfg[1] & 0x80) + { + dev9202_info.enable_bio = 1; + } + else + { + dev9202_info.enable_bio = 0; + } + vc9202_drv_system_param_init(fifo_div, reg_cfg[0]); + /* mode位置1,芯片开始工作 */ + vc9202_drv_start_sampling(); + return 0; +} + +/** + * @brief 传递采样数据 + * @param 采样数据保存地址,ppg数量 + * @retval 执行结果 + */ +unsigned char vc9202_drv_get_sampling_data(SamplingDataTypeDef *pSamplingData, unsigned char *psize) +{ + unsigned char ret = 0; + /* 读取状态及中断事件 */ + usr_iic_read_bytes(0x01, &dev9202_info.work_status, 1); + usr_iic_read_bytes(0x02, (unsigned char *)&dev9202_info.int_event, 1); + + printf("dev9202_info.work_status : 0x%x ,dev9202_info.int_event : 0x%x\n",dev9202_info.work_status,dev9202_info.int_event); + + if (dev9202_info.work_status & 0xf8) /* 防止insample和conflict时数据错误,则不对设备进行处理 */ + { + printf("dev9202_info.work_status & 0xf8 \n"); + dev9202_info.int_event = 0; /* 异常时,避免执行佩戴检测 */ + return 1; + } + if (-1 == vc9202_drv_check_running_gaptime()) + { + printf("-1 == vc9202_drv_check_running_gaptime() \n"); + dev9202_info.int_event = 0; /* 异常时,避免执行佩戴检测 */ + return 1; + } + ret = vc9202_drv_read_reg(pSamplingData); + ret = (unsigned char)vc9202_drv_gpio_event_handler(pSamplingData, psize); + return ret; +} diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_driver_testmode.c b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_driver_testmode.c new file mode 100644 index 000000000..763c08e75 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_driver_testmode.c @@ -0,0 +1,176 @@ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc9202_driver_testmode.c + * @brief + * @details + * @author + * @date + * @version + *********************************************************************************************************/ +//!!!注意:本文文件包含step1(id,频率,温度的读取判断),step2(bio是否满足变化/ps是否能够达到阈值)两步进行FPC测试,用于那些不使用测试板的测试的用户,排查基础问题 +//!!!注意:本文文件包含step1(id,频率,温度的读取判断),step2(bio是否满足变化/ps是否能够达到阈值)两步进行FPC测试,用于那些不使用测试板的测试的用户,排查基础问题 +//如果不需要,删除本文件和其他报错的地方即可 +#include "vc9202_common.h" +#include "vc9202_driver.h" + +VC9202TestInfoTypeDef vc9202_test_info = {0}; + +const static unsigned char disp_green[17] = {0xC5, 0x30, 0x8A, 0x40, 0x03, 0x1F, 0x00, + 0x30, 0x40, 0x5A, + 0x57, 0x37, 0x47, + 0x16, 0x56, 0x16, 0x00}; +const static unsigned char disp_red[17] = {0xC6, 0x30, 0x8A, 0x40, 0x03, 0x1F, 0x00, + 0x30, 0x40, 0x5A, + 0x57, 0x37, 0x47, + 0x16, 0x56, 0x16, 0x00}; +static unsigned int mcu_cnt[2] = {0}, chip_cnt[2] = {0}; +void vc9202_test_init(VC9202TestInfoTypeDef *ptest_info) +{ + mcu_cnt[0] = 0; + mcu_cnt[1] = 0; + chip_cnt[0] = 0; + chip_cnt[1] = 0; + memset(ptest_info, 0, sizeof(VC9202TestInfoTypeDef)); +} + +static unsigned int vc9202_test_real_frequency(void) +{ + unsigned char cnt_reg[4] = {0}; + unsigned int mcu_cnt_dif = 0; + unsigned int chp_cnt_dif = 0; + unsigned int calc_freq = 0; + + mcu_cnt[1] = mcu_cnt[0]; + chip_cnt[1] = chip_cnt[0]; + mcu_cnt[0] = usr_get_clock_ticks(); + usr_iic_read_bytes(0x07, cnt_reg, 4); + chip_cnt[0] = (cnt_reg[0] << 8) + cnt_reg[1]; + unsigned short cnt1 = (cnt_reg[0] << 8) + cnt_reg[1]; + unsigned short cnt2 = (cnt_reg[2] << 8) + cnt_reg[3]; + if (abs(cnt1 - cnt2) >= 10) + { + return 0xffff; + } + if ((0 == mcu_cnt[1]) || (0 == mcu_cnt[0])) + return 20 * 1000; + if ((0 == chip_cnt[1]) || (0 == chip_cnt[0])) + return 20 * 1000; + mcu_cnt_dif = (mcu_cnt[0] > mcu_cnt[1]) ? (mcu_cnt[0] - mcu_cnt[1]) : (VC9202_CFG_CLK_CHECK_MAX - mcu_cnt[1] + mcu_cnt[0]); + chp_cnt_dif = (chip_cnt[0] > chip_cnt[1]) ? (chip_cnt[0] - chip_cnt[1]) : (0xffff - chip_cnt[1] + chip_cnt[0]); + float timeDiff = (float)mcu_cnt_dif / (float)VC9202_CFG_CLK_CHECK_FREQUENCY; + calc_freq = (float)chp_cnt_dif / timeDiff; + if (calc_freq >= 0xffff) + calc_freq = 0xffff; + if (calc_freq <= 0) + calc_freq = 0; + return calc_freq; +} + +static int vc9202_test_led_glint(VC9202TestInfoTypeDef *ptest_info) +{ + static unsigned char glint_count = 0; + if (ptest_info->step1_ret && ptest_info->step2_ret) + { + glint_count++; + if (glint_count == 25) + { + usr_iic_write_bytes(0x10, (unsigned char *)disp_green, 17); + } + else if (glint_count == 50) + { + glint_count = 0; + usr_iic_write_bytes(0x10, (unsigned char *)disp_red, 17); + } + return 1; + } + return 0; +} +/*记录bio变化值的最大的差值,用于判断bio变化是否满足阈值判断*/ +static void vc9202_test_bio_variation(VC9202TestInfoTypeDef *ptest_info, unsigned short bio) +{ + unsigned short now_gap = 0; + ptest_info->biovalue_now[1] = ptest_info->biovalue_now[0]; + ptest_info->biovalue_now[0] = bio; + if (0 == ptest_info->biovalue_now[1] || 0 == ptest_info->biovalue_now[0]) + { + return; + } + now_gap = (ptest_info->biovalue_now[0] > ptest_info->biovalue_now[1]) ? (ptest_info->biovalue_now[0] - ptest_info->biovalue_now[1]) : (ptest_info->biovalue_now[1] - ptest_info->biovalue_now[0]); + if (now_gap > ptest_info->biovalue_max) + { + ptest_info->biovalue_max = now_gap; + ptest_info->biovalue_gap[0] = ptest_info->biovalue_now[0]; + ptest_info->biovalue_gap[1] = ptest_info->biovalue_now[1]; + } + return; +} +void vc9202_test_handler(SamplingDataTypeDef *pResult, VC9202TestInfoTypeDef *ptest_info) +{ + // 判断是否测试完成,只执行交替闪 + if (vc9202_test_led_glint(ptest_info)) + { + return; + } + // step1 计算频率 + 读取ID及中断原因 + if (0 == ptest_info->step1_ret) + { + ptest_info->max_current = pResult->led_cur[0]; + ptest_info->leak_pre_value = pResult->apre_val[0]; + ptest_info->frequency = vc9202_test_real_frequency(); + usr_iic_read_bytes(0x00, &ptest_info->icid, 1); + usr_iic_read_bytes(0x02, &ptest_info->reason, 1); + return; + } + // step2 bio.ps + if (0 != ptest_info->step1_ret && 0 == ptest_info->step2_ret) + { + ptest_info->ps_value = pResult->aps_val; + vc9202_test_bio_variation(ptest_info, pResult->bio_val_o); + } + return; +} + +// 在xx_user.c中调用 case WORK_MODE_FACTORY: factory_test_function( &data ); break; +#if 0 +static void fpc_test_function(SamplingDataTypeDef *pdata) +{ + extern VC9202TestInfoTypeDef vc9202_test_info; + /* 等待5次中断工作稳定 */ + if (vc9202_test_info.wait_cnt <= 5) + { + vc9202_test_info.wait_cnt++; + return; + } + /* 步骤一:常规数据读取判断是否在范围内,此处得数据请根据实际设计对参数进行调整 */ + if (0 == vc9202_test_info.step1_ret) + { + if (vc9202_test_info.icid == 0x21 && vc9202_test_info.reason & 0x3f && + vc9202_test_info.frequency >= 16000 && vc9202_test_info.frequency <= 24000) + { + vc9202_test_info.step1_ret = 1; + } + else + { + vc9202_test_info.step1_ret = 2; + } + } + /* 步骤二:bio/ps数据读取判断是否在范围内 */ + else if (0 == vc9202_test_info.step2_ret) + { + if (vc9202_test_info.biovalue_max >= 400 && vc9202_test_info.ps_value >= 200) + { + vc9202_test_info.step2_ret = 1; + } + } + /*注意:上述方式会一直等待,直到检测通过,也可以使用人为触发记录,进行比较两次触发时的记录值差距是否满足。 + 记录两次不同状态(模拟佩戴和摘下)下时的pdata->bio_val_o,比较差值 + 记录模拟佩戴下的pdata->ps_val,判断是否满足PS范围 + */ + /* 其中step1_ret和step2_ret,分别表示测试是否通过,由于step2_ret需要检测变化量,所以需要一直等待操作,如果测试通过后,驱动会控制红绿灯交替闪烁 */ + DEBUG("[FAT]icid=%#x,reason=%#x,frequency=%d,temperature=%d", vc9202_test_info.icid, vc9202_test_info.reason, vc9202_test_info.frequency, vc9202_test_info.temperature); + printf("[FAT]biovalue_max=%d,ps=%d,gap[%d,%d]", vc9202_test_info.biovalue_max, vc9202_test_info.ps_value, vc9202_test_info.biovalue_gap[0], vc9202_test_info.biovalue_gap[1]); + printf("[FAT]-ret(%d,%d)", vc9202_test_info.step1_ret, vc9202_test_info.step2_ret); +} + +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c new file mode 100644 index 000000000..907333c35 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_hal.c @@ -0,0 +1,211 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-03-13 15:08:38 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-24 10:25:14 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ + +#include +#include +#include +#include +#include + +#include "pm_control.h" +#include "platform_core.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" + +#ifdef PPG_VC9202 +#include "vc30x91x92x_common.h" +#include "vc9202_user.h" +#endif + +#ifdef PPG_HX3695 +#include "tyhx_hrs_custom.h" +#include "hx3695.h" +#include "hx3695_hal.h" +#include "hx3695.h" + + +hx3695_msg_callback_t g_send_msg_toUI = NULL; + +// typedef void (*hx3695_msg_callback_t)(uint8_t msg_type, uint8_t *msg_data, int32_t msg_datalen); +uint32_t hx3695_register_msg_callback(hx3695_msg_callback_t func) +{ + g_send_msg_toUI = func; + return 0; +} + +hx3695_msg_callback_t hx3695_get_send_msg_callback_func(void) +{ + return g_send_msg_toUI; +} + + +#include "hx3695.h" +#include "tyhx_hrs_custom.h" + +#endif + + +// S_AGPIO_L26 心率复位 PPG reset +#define GPIO_PIN_PRG_RESET S_AGPIO_L26 +// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚 +#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0 + +uint32_t tyhx_poweron(void) +{ + uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_HIGH); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH); + LOS_Udelay(30); + return 0; +} +uint32_t tyhx_poweroff(void) +{ + uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_LOW); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW); + LOS_Mdelay(1); + return 0; +} + + +void ppg_send_cmd_to_vc9202_driver(char* mode, uint8_t enable) +{ +#ifdef PPG_VC9202 + WorkModeTypeDef md = WORK_MODE_NONE; +#elif defined PPG_HX3695 + WORK_MODE_T md = NULL_MODE; +#endif + if (strcmp(mode, "hrs") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_HR; +#elif defined PPG_HX3695 + md = HRS_MODE; +#endif + } else if (strcmp(mode, "hrv") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_HRV; +#elif defined PPG_HX3695 + md = HRV_MODE; +#endif + } else if (strcmp(mode, "spo2") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_SPO2; +#elif defined PPG_HX3695 + md = SPO2_MODE; +#endif + } else if (strcmp(mode, "leaklight") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_NONE; +#elif defined PPG_HX3695 + md = FT_LEAK_LIGHT_MODE; +#endif + } else if (strcmp(mode, "graycard") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_NONE; +#elif defined PPG_HX3695 + md = FT_GRAY_CARD_MODE; +#endif + } else if (strcmp(mode, "ledoff") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_NONE; +#elif defined PPG_HX3695 + md = FT_LED_OFF_MODE; +#endif + } else if (strcmp(mode, "wear") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_WEAR; +#elif defined PPG_HX3695 + md = WEAR_MODE; +#endif + } else if (strcmp(mode, "single") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_NONE; +#elif defined PPG_HX3695 + md = FT_SINGLE_CHECK_MODE; +#endif + }else if (strcmp(mode, "factory") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_FACTORY; +#endif + }else if (strcmp(mode, "fpc") == 0) { +#ifdef PPG_VC9202 + md = WORK_MODE_FPC_TEST; +#endif + } + +#ifdef PPG_HX3695 + if (enable == 1 || md == FT_LED_OFF_MODE) +#elif defined PPG_VC9202 + if (enable == 1) +#endif + { + // ppg_service_running_stat = true; + uapi_pm_control(PM_APP_WAKE_NEEDED); + tyhx_poweron(); +#ifdef PPG_HX3695 + hx3695_init(md); +#endif +#ifdef PPG_VC9202 + InitParamTypeDef pInit_Param = {0}; + pInit_Param.sampling_gap_time = 400; + pInit_Param.work_mode = md; + vc9202_usr_init(&pInit_Param); +#endif + } else { + +#ifdef PPG_HX3695 + // ppg_service_running_stat = false; + if(md == HRS_MODE|| md == FT_LEAK_LIGHT_MODE || md == FT_GRAY_CARD_MODE || md == WEAR_MODE || md == FT_SINGLE_CHECK_MODE) + { +#ifdef HRS_ALG_LIB + hx3695_hrs_disable(); + // PRINT("uapi_dev_runtime_get_sleep_monitoring_status : %d \n",uapi_dev_runtime_get_sleep_monitoring_status()); + // PRINT("uapi_dev_runtime_get_hrs_passivity_flag : %d \n",uapi_dev_runtime_get_hrs_passivity_flag()); + if(uapi_dev_runtime_get_sleep_monitoring_status() && uapi_dev_runtime_get_hrs_passivity_flag())//处于睡眠监测 且在心率周期检测期间 上报活体佩戴 + { + hx3695_wearstatus_update(); + uapi_dev_runtime_set_hrs_passivity(0);//清除被动检测runtime + } +#endif + }else if(md == HRV_MODE) + { +#ifdef HRV_ALG_LIB + hx3695_hrv_disable(); +#endif + }else if(md == SPO2_MODE) + { +#ifdef SPO2_ALG_LIB + hx3695_spo2_disable(); +#endif + } + else{ +#ifdef HRS_ALG_LIB + hx3695_hrs_disable(); +#endif + } + +#elif defined PPG_VC9202 + vc9202_usr_stop_sampling(); +#endif + + + uapi_pm_control(PM_APP_WAKE_NONEED); + tyhx_poweroff(); + } +} \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_user.c b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_user.c new file mode 100644 index 000000000..5d5fbbc10 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_user.c @@ -0,0 +1,569 @@ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc9202_user.c + * @brief functional Module Layer + * @details The functional interface is implemented by calling the driver.contain init_func,irq_handler + * @author + * @date + * @version + *********************************************************************************************************/ +#include "algo.h" +#include "spo2Algo.h" +#include "vcSportMotionIntAlgo.h" +#include "vc9202_common.h" +#include "vc9202_user.h" +#include "vc9202_driver.h" +#include "custom_utils.h" +#include "platform_core.h" +#include "systick.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" +#include "los_tick.h" + +static WorkModeTypeDef work_mode = WORK_MODE_NONE; +AlgoCalcResultsTypeDef vc9202_alg_results = {0}; + +/* 蓝牙发送原始数据接口 */ +extern void vc9202_debug_send_heart_rate_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char heart_rate, unsigned char algo_mode, unsigned char ppgsize ); +extern void vc9202_debug_send_spo2_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char spo2_val, unsigned char ppgsize ); + +/********************************************************************************************************* + * PERIPHERAL FUNCTIONS + ********************************************************************************************************/ +#define CHIP_I2C_ADDRESS 0x33 +#define VC9202_I2C_BUS I2C_BUS_2 + +/** + * @brief iic多字节写 + * @param + * @arg reg_addr:寄存器地址 + * @arg pBuffer:缓冲区指针 + * @arg num_bytes:写的字节数 + * @retval 无 + */ +unsigned char usr_iic_write_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size) +{ + custom_i2c_write_reg(CHIP_I2C_ADDRESS, reg_addr, 1, pBuffer, buf_size, VC9202_I2C_BUS); + return 0; +} + + +/** + * @brief iic多字节读 + * @param + * @arg reg_addr:寄存器地址 + * @arg pBuffer:缓冲区指针 + * @arg num_bytes:读的字节数 + * @retval 无 + */ +unsigned char usr_iic_read_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size) +{ + custom_i2c_read_regs(CHIP_I2C_ADDRESS, reg_addr, 1 , pBuffer, buf_size, VC9202_I2C_BUS); + return 0; +} + + +/** + * @brief 校验用时钟tick获取 + * @param 无 + * @retval 时钟tick + */ +unsigned int usr_get_clock_ticks(void) +{ + return uapi_systick_get_count(); +} + +/********************************************************************************************************* + * API FUNCTIONS + ********************************************************************************************************/ +/** + * @brief 获取chip_id + * @param 无 + * @retval chip_id值 + */ +void vc9202_usr_get_chip_id( unsigned char *pchip_id, unsigned char *pvers_id ) +{ + usr_iic_read_bytes( 0x00, pchip_id, 1 ); + usr_iic_read_bytes( 0x40, pvers_id, 1 ); +} + +/** + * @brief 初始化 + * @param 无 + * @retval 无 + */ +void vc9202_usr_init( InitParamTypeDef *pInitParam ) +{ + memset( &vc9202_alg_results, 0 ,sizeof(vc9202_alg_results) ); + // vcSpo2AlgoInit(); + spo2AlgoInit(); + Algo_Init(); + vcSportMotionAlgoInit(); + work_mode = (WorkModeTypeDef)pInitParam->work_mode; + vc9202_drv_soft_reset(); + vc9202_drv_reg_init( pInitParam ); +} + +/** + * @brief 开始采样 + * @param 无 + * @retval 无 + */ +void vc9202_usr_start_sampling(void) +{ + vc9202_drv_start_sampling(); +} + + +/** + * @brief 停止采样 + * @param 无 + * @retval 无 + */ +void vc9202_usr_stop_sampling(void) +{ + vc9202_drv_stop_sampling(); +} + + +/** + * @brief 软复位 + * @param 无 + * @retval 无 + */ +void vc9202_usr_soft_reset(void) +{ + vc9202_drv_soft_reset(); +} + +/** + * @brief 独立使/失能某一物理通道 + * @param + @num_channel 通道编号(1,2,3) + @enable_flag 使能或失能标志位 + * @retval 0-成功,其他-失败 + */ +unsigned char vc9202_usr_channel_switch(unsigned char num_channel, unsigned char enable_flag) +{ + return vc9202_drv_channel_switch(num_channel, enable_flag); +} + +/** + * @brief 获取中断原因 + * @param @无 + @ int_reason 中断原因 + * @retval 中断原因 + */ +unsigned char vc9202_usr_get_int_reason(void) +{ + /* bit2:fifo,bit4:ps */ + return vc9202_drv_get_int_reason(); +} +/** + * @brief 获取佩戴检测结果 + * @param @无 + @ 无 + * @retval 佩戴检测结果 + */ +unsigned char vc9202_usr_get_wear_status(void) +{ + unsigned char sta = 0; + WearStatusTypeDef retSta = vc9202_drv_get_wear_status(); + if( WEAR_STA_DROP == retSta ) + { + sta = 0; + } + else + { + sta = 1; + } + return sta; +} + +/**********************************************************************/ + +#define ENABLE_GSENSOR 0 +/* gsensor 相关的示例代码 */ +#if ENABLE_GSENSOR +typedef struct +{ + int16_t AXIS_X; + int16_t AXIS_Y; + int16_t AXIS_Z; +} AxesRaw_t; +static void gsensor_data_match(AxesRaw_t *org_data, GsensorTypeDef *pGsensorParam, unsigned char ppg_size) +{ + const unsigned char arry10[] = {0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12}; + const unsigned char arry20[] = {0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30}; + /* ppglen = 10 抽样 */ + if( 10<=ppg_size ) + { + for (uint8_t i = 0; i < ppg_size; i++) + { + pGsensorParam->gsensor_x_axis[i] = org_data[arry10[i]].AXIS_X; + pGsensorParam->gsensor_y_axis[i] = org_data[arry10[i]].AXIS_Y; + pGsensorParam->gsensor_z_axis[i] = org_data[arry10[i]].AXIS_Z; + } + } + else /* ppglen = 20 、25抽样 */ + { + for (uint8_t i = 0; i < ppg_size; i++) + { + pGsensorParam->gsensor_x_axis[i] = org_data[arry20[i]].AXIS_X; + pGsensorParam->gsensor_y_axis[i] = org_data[arry20[i]].AXIS_Y; + pGsensorParam->gsensor_z_axis[i] = org_data[arry20[i]].AXIS_Z; + } + } +} +#endif + +static void get_gsensor_data( GsensorTypeDef *pGsensorParam, unsigned char *pgsensor_len, unsigned char ppg_size ) +{ + /* + Gsensor精度要求 ReadGsensorFIFO(+-4G11bit or +-8G12bit 256/g) + 一个fifo周期为800ms,20组ppg数据,需要获取800ms内至少获取ppgCount组gsensor数据(40ms*20),用于匹配20组ppg信号,此函数需要根据用户实际的gsensor进行匹配处理。 + */ +#if ENABLE_GSENSOR + unsigned char i = 0; + unsigned char gsensor_len = 0; + AxesRaw_t gsensor_buff[40] = {0}; + pGsensorParam->sampling_rate = 25; + pGsensorParam->sensing_range = 4; + pGsensorParam->effective_bits = 12; + // stk8321_get_fifo_data(&gsensor_len, gsensor_buff); + if (ppg_size == 0) + { + *pgsensor_len = gsensor_len; + /* 不抽样 */ + for (i = 0; i < *pgsensor_len; i++) + { + pGsensorParam->gsensor_x_axis[i] = gsensor_buff[i].AXIS_X; + pGsensorParam->gsensor_y_axis[i] = gsensor_buff[i].AXIS_Y; + pGsensorParam->gsensor_z_axis[i] = gsensor_buff[i].AXIS_Z; + } + } + /* æ­¤demo中gsensor的采样频率高于ppg采样,所以正常情况下,gsensor的数量一定是大于ppg的数据。特殊情况需要考虑ppg数量大于gsensor数量。需要对gsensor数据进行补长 */ + if( (gsensor_len>=ppg_size)&&(ppg_size!=0) ) + { + *pgsensor_len = ppg_size; + // gsensor_data_match( gsensor_buff,pGsensorParam, ppg_size ); + } + else if( (gsensor_lengsensor_x_axis[i] = gsensor_buff[i].AXIS_X; + pGsensorParam->gsensor_y_axis[i] = gsensor_buff[i].AXIS_Y; + pGsensorParam->gsensor_z_axis[i] = gsensor_buff[i].AXIS_Z; + } + for( i=gsensor_len; igsensor_x_axis[i] = gsensor_buff[gsensor_len-1].AXIS_X; + pGsensorParam->gsensor_y_axis[i] = gsensor_buff[gsensor_len-1].AXIS_Y; + pGsensorParam->gsensor_z_axis[i] = gsensor_buff[gsensor_len-1].AXIS_Z; + } + } +#endif +} + +static unsigned int vc9202_usr_gsensor_actuating_quantity(int x_axis, int y_axis, int z_axis) +{ + unsigned int ret_atc = 0; + unsigned int abs_sum_current = 0; + static unsigned int abs_sum_last = 0; + if(x_axis < 0) + { + x_axis = -x_axis; + } + if(y_axis < 0) + { + y_axis = -y_axis; + } + if(z_axis < 0) + { + z_axis = -z_axis; + } + abs_sum_current = x_axis + y_axis + z_axis; + if(abs_sum_last&&abs_sum_current) + { + if( ABS(abs_sum_last,abs_sum_current)>=40 ) + { + ret_atc = 1; + } + } + abs_sum_last = abs_sum_current; + /* 存在运动量时处理,释放掉心率算法摘下的状态 */ + if( ret_atc ) + { + vc9202_drv_set_algo_wear_status( WEAR_STA_HOLD ); + } + vc9202_drv_set_gsensor_actuating_quantity( ret_atc ); + return ret_atc; +} + +static short int alg_calculate_hr_handler( short int last_hr_val, SamplingDataTypeDef *pdata, unsigned char ppg_size, GsensorTypeDef *pgsensor, AlgoSportMode hr_alg_mode ) +{ + unsigned char i=0; + short int heart_rate_value = last_hr_val; + AlgoInputData_t alg_i_data={0}; + AlgoOutputData_t alg_o_data={0}; + /* 如果没有fifo则直接推出,此处return需要返回上一次的值 */ + if( ppg_size <= 0 ) + { + return heart_rate_value; + } + if(ppg_size>=40) + { + ppg_size = 40; + } + // printf("ppg_size : %d \n",ppg_size); + alg_i_data.envSample = pdata->env_val[0]; + for( i=0; igsensor_x_axis[i]; + alg_i_data.axes.y = pgsensor->gsensor_y_axis[i]; + alg_i_data.axes.z = pgsensor->gsensor_z_axis[i]; + alg_i_data.ppgSample = pdata->ppg_data[i]; + printf("pdata->ppg_data[%d] : %d \n",i,pdata->ppg_data[i]); + // printf(" i : alg_i_data.axes.x : %d ,alg_i_data.axes.y : %d , alg_i_data.axes.z : %d \n",i,alg_i_data.axes.x,alg_i_data.axes.y,alg_i_data.axes.z); + Algo_Input( &alg_i_data, 1000/25, hr_alg_mode, 1, 1 ); + } + Algo_Output( &alg_o_data ); + // printf("alg_o_data.hrData : %d \n",alg_o_data.hrData); + if( -1 == alg_o_data.hrData ) + { + vc9202_drv_set_algo_wear_status( WEAR_STA_DROP ); + } + else if( alg_o_data.hrData > 0 ) + { + heart_rate_value = alg_o_data.hrData; + } + return heart_rate_value; +} + +static unsigned char alg_calculate_spo2_handler( unsigned char last_spo2_val , SamplingDataTypeDef *pdata, unsigned char ppg_size, GsensorTypeDef *pgsensor, unsigned char spo2_alg_mode ) +{ + unsigned char i=0; + unsigned char spo2_value = last_spo2_val; + float ret_spo2 = 0.0f; + float ir_PPG = 0.0f; + float red_PPG = 0.0f; + float sport_flag = 0.0f; + /* 如果没有fifo则直接推出,此处return需要返回上一次的值 */ + if( ppg_size<=0 ) + { + return spo2_value; + } + for( i=0; ippg_data[i*2]; + red_PPG = (float)pdata->ppg_data[i*2+1]; + // ret_spo2 = vcSpo2Calculate( red_PPG, ir_PPG ); + ret_spo2 = spo2Algo(red_PPG,ir_PPG,1); + sport_flag = vcSportMotionCalculate( pgsensor->gsensor_x_axis[i], pgsensor->gsensor_y_axis[i], pgsensor->gsensor_z_axis[i] ); + if ( (-1!=ret_spo2)&&(!sport_flag)) + { + spo2_value = (unsigned char)ret_spo2; + } + } + return spo2_value; +} + +static void factory_test_function( SamplingDataTypeDef *pdata ) +{ + // /* 最大电流 */ + // unsigned char ledMaxCur = pdata->led_cur[0]; //最大电流,黑箱通道2 + // /* 获取测试数据 */ + // unsigned int pre0 = pdata->apre_val[0];//绿灯强度,漏光模式通道1 + // unsigned int ps = pdata->aps_val;//红外强度,灰卡模式通道3 + // /* 温度 */ + // signed short int temp0 = pdata->temp_val_i; + // signed short int temp1 = pdata->temp_val_o; + // /* compare abs(bio0,bio1) */ + // unsigned short int bio0 = pdata->bio_val_o; + // unsigned short int bio1 = pdata->bio_val_o; +} +static void fpc_test_function(SamplingDataTypeDef *pdata) +{ + extern VC9202TestInfoTypeDef vc9202_test_info; + /* 等待5次中断工作稳定 */ + if (vc9202_test_info.wait_cnt <= 5) + { + vc9202_test_info.wait_cnt++; + return; + } + /* 步骤一:常规数据读取判断是否在范围内,此处得数据请根据实际设计对参数进行调整 */ + if (0 == vc9202_test_info.step1_ret) + { + if (vc9202_test_info.icid == 0x21 && vc9202_test_info.reason & 0x3f && + vc9202_test_info.frequency >= 16000 && vc9202_test_info.frequency <= 24000 ) + { + vc9202_test_info.step1_ret = 1; + } + else + { + vc9202_test_info.step1_ret = 2; + } + } + /* 步骤二:bio/ps数据读取判断是否在范围内 */ + else if (0 == vc9202_test_info.step2_ret) + { + if (vc9202_test_info.biovalue_max >= 60 && vc9202_test_info.ps_value >= 200) + { + vc9202_test_info.step2_ret = 1; + } + } + /*注意:上述方式会一直等待,直到检测通过,也可以使用人为触发记录,进行比较两次触发时的记录值差距是否满足。 + 记录两次不同状态(模拟佩戴和摘下)下时的pdata->bio_val_o,比较差值 + 记录模拟佩戴下的pdata->ps_val,判断是否满足PS范围 + */ + /* 其中step1_ret和step2_ret,分别表示测试是否通过,由于step2_ret需要检测变化量,所以需要一直等待操作,如果测试通过后,驱动会控制红绿灯交替闪烁 */ + printf("[FAT]icid=%#x,reason=%#x,frequency=%d,temperature=%d \n", vc9202_test_info.icid, vc9202_test_info.reason, vc9202_test_info.frequency, vc9202_test_info.temperature); + printf("[FAT]biovalue_max=%d,ps=%d,gap[%d,%d] \n", vc9202_test_info.biovalue_max, vc9202_test_info.ps_value, vc9202_test_info.biovalue_gap[0], vc9202_test_info.biovalue_gap[1]); + printf("[FAT]-ret(%d,%d) \n", vc9202_test_info.step1_ret, vc9202_test_info.step2_ret); +} + +void vc9202_usr_interrupt_handler( AlgoSportMode hr_alg_mode, unsigned char spo2_alg_mode ) +{ + unsigned char wear_status = WEAR_STA_NONE; + SamplingDataTypeDef data = {0}; + GsensorTypeDef gsensor_data = {0}; + unsigned char gsensor_size = 0; + unsigned char ppg_size = 0; + VC9202DrvRetTypeDef ret = vc9202_drv_get_sampling_data( &data, &ppg_size ); + printf("ppg_size : %d work_mode : %d ret : %d\n",ppg_size,work_mode,ret); + switch ( work_mode ) + { + case WORK_MODE_HR: + printf("11111 vc9202_usr_get_int_reason : 0x%x \n",vc9202_usr_get_int_reason()); + if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) ) + { + wear_status = vc9202_usr_get_wear_status(); + printf("11111 wear_status : %d \n",wear_status); + get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size); + if( gsensor_size>0 ) + { + vc9202_usr_gsensor_actuating_quantity( gsensor_data.gsensor_x_axis[0], gsensor_data.gsensor_y_axis[0], gsensor_data.gsensor_z_axis[0] ); + } + if(wear_status) + { + vc9202_alg_results.hr_rate = alg_calculate_hr_handler( vc9202_alg_results.hr_rate, &data, ppg_size, &gsensor_data, hr_alg_mode ); + printf("vc9202_alg_results.hr_rate : %d \n",vc9202_alg_results.hr_rate); + vc9202_debug_send_heart_rate_data( &data, &gsensor_data, vc9202_alg_results.hr_rate, hr_alg_mode, ppg_size ); + } + else + { + vc9202_alg_results.hr_rate = 0; + Algo_Init(); + } + } + break; + + case WORK_MODE_SPO2: + if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) ) + { + wear_status = vc9202_usr_get_wear_status(); + get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size); + if(wear_status) + { + vc9202_alg_results.spo2_val = alg_calculate_spo2_handler( vc9202_alg_results.spo2_val, &data, ppg_size/2, &gsensor_data, spo2_alg_mode ); + printf("vc9202_alg_results.spo2_val : %d \n",vc9202_alg_results.spo2_val); + vc9202_debug_send_spo2_data( &data, &gsensor_data, vc9202_alg_results.spo2_val, ppg_size/2 ); + } + else + { + vc9202_alg_results.spo2_val = 0; + // vcSpo2AlgoInit(); + spo2AlgoInit(); + vcSportMotionAlgoInit(); + } + } + break; + + case WORK_MODE_HRV: + if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) ) + { + wear_status = vc9202_usr_get_wear_status(); + get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size); + if(wear_status) + { + vc9202_alg_results.hr_rate = alg_calculate_hr_handler( vc9202_alg_results.hr_rate, &data, ppg_size, &gsensor_data, hr_alg_mode ); + /* 校验+算法HRV */ + } + else + { + vc9202_alg_results.hr_rate = 0; + Algo_Init(); + /* 清空数据+初始化算法 */ + } + } + break; + + case WORK_MODE_STRESS: + if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) ) + { + wear_status = vc9202_usr_get_wear_status(); + get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size); + if(wear_status) + { + /* 校验+算法STRESS */ + } + else + { + /* 清空数据+初始化算法 */ + } + } + break; + + case WORK_MODE_WEAR: + if( vc9202_usr_get_int_reason() & VC9202_EVENT_PS_MARK ) + { + wear_status = vc9202_usr_get_wear_status(); + get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size); + if( gsensor_size>0 ) + { + vc9202_usr_gsensor_actuating_quantity( gsensor_data.gsensor_x_axis[0], gsensor_data.gsensor_y_axis[0], gsensor_data.gsensor_z_axis[0] ); + } + /* 根据佩戴状态添加对应的处理代码 */ + if(wear_status) + { + printf("111 wear \n"); + } + else + { + printf("222 nowear \n"); + } + } + break; + case WORK_MODE_FACTORY: + factory_test_function( &data ); + break; + case WORK_MODE_FPC_TEST: + fpc_test_function(&data); + break; + + default: + break; + } +} + +#if 0 +int main(int argc, char *argv[]) +{ + board_driver_init(); //MCU外设初始化 + InitParamTypeDef config={400,WORK_MODE_HR}; //修改fifo间隔时间(关系到fifolength), 设定工作模式 + vc9102_usr_init( &config ); + while(1) + { + if( irq_msg ) + { + //调用时传入心率算法模式(日常、运动...)和血氧算法参数。 + vc9102_usr_interrupt_handler( algo_mode, 1 ); + } + } + return 0 +} +#endif + diff --git a/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_user_debug.c b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_user_debug.c new file mode 100644 index 000000000..c40192b8c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc9202/src/vc9202_user_debug.c @@ -0,0 +1,188 @@ +/********************************************************************************************************* + * Copyright(c) 2022, vcare Corporation. All rights reserved. + ********************************************************************************************************** + * @file vc9202_user_debug.c + * @brief example,debug send original data + * @details + * @author + * @date + * @version + *********************************************************************************************************/ + +#include "vc9202_common.h" +#include "vc9202_user.h" + +// #include "os_timer.h" +// #include +// #include "wristband_global_data.h" +// extern RtkWristBandSysType_t RtkWristbandSys; + +static unsigned char ble_buf[1024]={0}; +static unsigned short int buf_size = 0; +static unsigned short int buf_index = 0; +#define BLE_PACK_SIZE 160 +#define TIMER_BLE_GAP 100 + +/********************************************************************************************************** + * 对苹果手机APP不能连续接收长段数据,利用软件定时器,进行分包发送 + * 创建软件定时器及数据分包处理 + */ +static void send_data_by_ble( unsigned char *pbuf, unsigned short int size ) +{ + // if (RtkWristbandSys.gap_conn_state == GAP_CONN_STATE_CONNECTED) + // { + // hr_ble_service_send_v3_notify(RtkWristbandSys.wristband_conn_id, hr_ser_id, pbuf, size); + // DBG_DIRECT("ble_send_buffer_size=%d",size); + // } +} + +static int timer_send_data_function(void) +{ + unsigned short int residue_size = 0; + //数据发送已经完成 + if( buf_index >= buf_size ) + { + return 0; + } + //判断剩余数据长度是否还需要分包 + residue_size = buf_size-buf_index; + if( residue_size <= BLE_PACK_SIZE ) + { + send_data_by_ble( &ble_buf[buf_index], residue_size ); + return 0; + } + else + { + send_data_by_ble( &ble_buf[buf_index], BLE_PACK_SIZE ); + buf_index +=BLE_PACK_SIZE; + return 1; + } +} + + +/* 创建软件定时器,如果数据太长通过软件定时器发送 */ +#define TIMER_ID 0xf0 +static void *debug_send_timer = NULL; +static void debug_send_timer_start(void) +{ + if( debug_send_timer ) + { + // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP); + } +} +static void debug_send_timer_stop(void) +{ + if( debug_send_timer ) + { + os_timer_stop(&debug_send_timer); + } +} + +static void debug_send_timer_callback( void *p_handle ) +{ + if( timer_send_data_function() ) + { + /* 定时器继续循环 */ + // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP); + } + else + { + /* 关闭定时器 */ + debug_send_timer_stop(); + } +} + +void vc9202_debug_send_timer_init( void ) +{ + if(debug_send_timer == NULL) + { + os_timer_create(&debug_send_timer, "debug_send_timer", TIMER_ID, TIMER_BLE_GAP, false, debug_send_timer_callback); + } + // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP); + os_timer_stop(&debug_send_timer); +} + +static void debug_orginal_data_send( unsigned short int size ) +{ + buf_index = 0; + buf_size = size; + if( buf_size <= BLE_PACK_SIZE ) + { + send_data_by_ble( ble_buf, size ); + } + else + { + send_data_by_ble( ble_buf, BLE_PACK_SIZE ); + buf_index += BLE_PACK_SIZE; + debug_send_timer_start(); + } +} + +/**********************************************************************************************************/ +#define ORIGINAL_DATA_DEBUG_ENABLE (1) + +#if ORIGINAL_DATA_DEBUG_ENABLE + +void vc9202_debug_send_heart_rate_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char heart_rate, unsigned char algo_mode, unsigned char ppgsize ) +{ + unsigned short int i = 0; + for( i=0; ippg_data[i] >> 8; + ble_buf[i*16 + 1 ] = presult->ppg_data[i] & 0xff; + ble_buf[i*16 + 2 ] = paxis->gsensor_x_axis[i] >> 8; + ble_buf[i*16 + 3 ] = paxis->gsensor_x_axis[i] & 0xff; + ble_buf[i*16 + 4 ] = paxis->gsensor_y_axis[i] >> 8; + ble_buf[i*16 + 5 ] = paxis->gsensor_y_axis[i] & 0xff; + ble_buf[i*16 + 6 ] = paxis->gsensor_z_axis[i] >> 8; + ble_buf[i*16 + 7 ] = paxis->gsensor_z_axis[i] & 0xff; + ble_buf[i*16 + 8 ] = heart_rate; + ble_buf[i*16 + 9 ] = presult->pd_res[0]; + ble_buf[i*16 + 10] = presult->led_cur[0]; + ble_buf[i*16 + 11] = presult->env_val[2]; + ble_buf[i*16 + 12] = presult->pre_val[0]; + ble_buf[i*16 + 13] = presult->bio_val_o>>8; + ble_buf[i*16 + 14] = presult->bio_val_o&0xff; + ble_buf[i*16 + 15] = presult->aps_val; + } + if( ppgsize > 0 ) + { + debug_orginal_data_send( ppgsize*16 ); + } +} + +/**************************************************************************************** + * + */ +void vc9202_debug_send_spo2_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char spo2_val, unsigned char ppgsize ) +{ + unsigned short int i = 0; + for( i=0; ippg_data[i*2] >> 8; + ble_buf[i*16 + 1 ] = presult->ppg_data[i*2] & 0xff; + ble_buf[i*16 + 2 ] = paxis->gsensor_x_axis[i] >> 8; + ble_buf[i*16 + 3 ] = paxis->gsensor_x_axis[i] & 0xff; + ble_buf[i*16 + 4 ] = paxis->gsensor_y_axis[i] >> 8; + ble_buf[i*16 + 5 ] = paxis->gsensor_y_axis[i] & 0xff; + ble_buf[i*16 + 6 ] = presult->pre_val[0]; + ble_buf[i*16 + 7 ] = presult->pre_val[1]; + ble_buf[i*16 + 8 ] = presult->ppg_data[i*2+1] >> 8; + ble_buf[i*16 + 9 ] = presult->ppg_data[i*2+1] & 0xff; + ble_buf[i*16 + 10] = spo2_val; + ble_buf[i*16 + 11] = presult->env_val[2]; + ble_buf[i*16 + 12] = presult->pd_res[0]; + ble_buf[i*16 + 13] = presult->led_cur[0]; + ble_buf[i*16 + 14] = presult->pd_res[1]; + ble_buf[i*16 + 15] = presult->led_cur[1]; + } + if( ppgsize > 0 ) + { + debug_orginal_data_send( ppgsize*16 ); + } +} + +#endif + + + diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/vc921x/CMakeLists.txt new file mode 100644 index 000000000..d91011b88 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/CMakeLists.txt @@ -0,0 +1,62 @@ +#=============================================================================== +# @brief cmake file +# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved. +#=============================================================================== +set(COMPONENT_NAME "ppg_sensor_vc921x") + +if("PPG_VC921X" IN_LIST DEFINES) +set(SOURCES ${SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc921x_core.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc921x_driver.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc921x_original_data_send.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc921x_user_app.c + ${CMAKE_CURRENT_SOURCE_DIR}/src/vc921x_hal.c +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR}/inc + +) + +else() +set(SOURCES ${SOURCES} +) +set(PUBLIC_HEADER + ${CMAKE_CURRENT_SOURCE_DIR} +) +endif() + + +set(PRIVATE_HEADER +) + +set(PRIVATE_DEFINES +) + +set(PUBLIC_DEFINES +) + +# use this when you want to add ccflags like -include xxx +set(COMPONENT_PUBLIC_CCFLAGS +) + +set(COMPONENT_CCFLAGS +) + +set(WHOLE_LINK + true +) + +set(MAIN_COMPONENT + false +) + +if("PPG_VC921X" IN_LIST DEFINES) + find_library(LIB_PATH_VC921X_1 lib/lib_BIO_v141_int_miniSDK_NA_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + find_library(LIB_PATH_VC921X_2 lib/lib_hr_vH102_int_miniSDK_NA_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + find_library(LIB_PATH_VC921X_3 lib/lib_spo2_vc30FS_float_V07_miniSDK_NA_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + find_library(LIB_PATH_VC921X_4 lib/lib_sportMotion_std_int_miniSDK_NA_01.a ${CMAKE_CURRENT_SOURCE_DIR}) + + target_link_libraries(${TARGET_NAME} PRIVATE -Wl,--whole-archive ${LIB_PATH_VC921X_1} ${LIB_PATH_VC921X_2} ${LIB_PATH_VC921X_3} ${LIB_PATH_VC921X_4} PRIVATE -Wl,--whole-archive) +endif() +build_component() + diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/BIODetect_V14_1.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/BIODetect_V14_1.h new file mode 100644 index 000000000..9b14b9d68 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/BIODetect_V14_1.h @@ -0,0 +1,19 @@ +/* + * + * Created on: 2023-6-04 + * Author: runningHorse + */ + +#ifndef BIODETECT +#define BIODETECT + +#include +#include + +void f_BIOInit(int32_t gapDeltaBIO, int32_t gapDeltaPS); + +uint8_t f_BIOdetect(int32_t inputBIO, int32_t inputPS, int32_t PSth); + +char* bioVersion(void); + +#endif /* BIODETECT */ \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/algo.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/algo.h new file mode 100644 index 000000000..3e9531379 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/algo.h @@ -0,0 +1,70 @@ + +#ifndef APP_ALGO_ALGO_H +#define APP_ALGO_ALGO_H + +#include +#include + +typedef enum +{ + SPORT_TYPE_NORMAL =0x00, // 日常 + SPORT_TYPE_RUNNING =0x01, // 跑步 + SPORT_TYPE_RIDE_BIKE =0X02, // 骑行 + SPORT_TYPE_JUMP_ROPE =0X03, // 跳绳 + SPORT_TYPE_SWIMMING =0X04, // 游泳 + SPORT_TYPE_BADMINTON =0X05, // 羽毛球 + SPORT_TYPE_TABLE_TENNIS=0X06, // 乒乓球 + SPORT_TYPE_TENNIS =0X07, // 网球 + SPORT_TYPE_CLIMBING =0X08, // 爬山 + SPORT_TYPE_WALKING =0X09, // 徒步 + SPORT_TYPE_BASKETBALL =0X0A, // 篮球 + SPORT_TYPE_FOOTBALL =0X0B, // 足球 + SPORT_TYPE_BASEBALL =0X0C, // 棒球 + SPORT_TYPE_VOLLEYBALL =0X0D, // 排球 + SPORT_TYPE_CRICKET = 0X0E, // 板球 + SPORT_TYPE_RUGBY = 0X0F, // 橄榄球 + SPORT_TYPE_HOCKEY =0X10, // 曲棍球 + SPORT_TYPE_DANCE = 0X11, // 跳舞 + SPORT_TYPE_SPINNING = 0X12, // 动感单车 + SPORT_TYPE_YOGA = 0X13, // 瑜伽 + SPORT_TYPE_SIT_UP =0X14, // 仰卧起坐 + SPORT_TYPE_TREADMILL =0X15, // 跑步机 + SPORT_TYPE_GYMNASTICS =0X16, // 体操 + SPORT_TYPE_BOATING = 0X17, // 划船 + SPORT_TYPE_JUMPING_JACK = 0X18, // 开合跳 + SPORT_TYPE_FREE_TRAINING = 0X19,// 自由训练 + SPORT_TYPE_PERIODIC_MONITORING = 0X1A,// 定时监测模式 +} AlgoSportMode; +//未出现在上表中的运动形式均先以跑步输入 + + +typedef struct +{ + int32_t x; + int32_t y; + int32_t z; +}AlgoAxesData_t; + +typedef struct +{ + int32_t hrData; + int32_t reliability; +}AlgoOutputData_t; + +typedef struct +{ + AlgoAxesData_t axes; + int32_t ppgSample; + int32_t envSample; +}AlgoInputData_t; + +void Algo_Init(void); +void Algo_Input(AlgoInputData_t *pInputData,int32_t gaptime,AlgoSportMode sportMode,int16_t surfaceRecogMode,int16_t opticalAidMode); +void Algo_Output(AlgoOutputData_t *pOutputData); + + + +#endif /* APP_ALGO_ALGO_H_ */ + + + diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/spo2Algo_16bit.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/spo2Algo_16bit.h new file mode 100644 index 000000000..a838c5ede --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/spo2Algo_16bit.h @@ -0,0 +1,57 @@ +/* + * File: main.h + * + * MATLAB Coder version : 3.3 + * C/C++ source code generated on : 09-Sep-2020 19:11:59 + */ + +/*************************************************************************/ +/* This automatically generated example C main file shows how to call */ +/* entry-point functions that MATLAB Coder generated. You must customize */ +/* this file for your application. Do not modify this file directly. */ +/* Instead, make a copy of this file, modify it, and integrate it into */ +/* your development environment. */ +/* */ +/* This file initializes entry-point function arguments to a default */ +/* size and value before calling the entry-point functions. It does */ +/* not store or use any values returned from the entry-point functions. */ +/* If necessary, it does pre-allocate memory for returned values. */ +/* You can use this file as a starting point for a main function that */ +/* you can deploy in your application. */ +/* */ +/* After you copy the file, and before you deploy it, you must make the */ +/* following changes: */ +/* * For variable-size function arguments, change the example sizes to */ +/* the sizes that your application requires. */ +/* * Change the example values of function arguments to the values that */ +/* your application requires. */ +/* * If the entry-point functions return values, store these values or */ +/* otherwise use them as required by your application. */ +/* */ +/*************************************************************************/ +#ifndef SPO2ALGO_16bit_H +#define SPO2ALGO_16bit_H + +/* Include Files */ +#include +#include +#include +#include +#include +//#include "rt_nonfinite.h" +//#include "rtwtypes.h" +//#include "spo2_algo_interface_types.h" + +/* Function Declarations */ +extern float vcSpo2Calculate_16bit(float r_ppg, float ir_ppg, float model); +extern int vcSpo2AlgoInit_16bit(void); +extern void vcSpo2AlgoTerminate_16bit(void); +extern char * +version_info_16bit(void); +#endif + +/* + * File trailer for main.h + * + * [EOF] + */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_core.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_core.h new file mode 100644 index 000000000..27f915d00 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_core.h @@ -0,0 +1,325 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2024-03-21 15:58:48 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ + +#ifndef __VC921x_CORE_H__ +#define __VC921x_CORE_H__ + +#ifndef VC_PACKED +#define VC921x_PACKED //__attribute__((packed)) +#endif + +/*=============================================================== +regist_list_map start... +================================================================*/ +#define CORE921x_DEV_VER_ID_H_ADDR (0x00) +#define CORE921x_FDY_EXT_ID_L_ADDR (0x01) +#define CORE921x_WORK_STATUS1_ADDR (0x02) +#define CORE921x_WORK_STATUS2_ADDR (0x03) +#define CORE921x_FIFO_W_INDEX_ADDR (0x04) +#define CORE921x_OSC_CNT0_H_ADDR (0x05) +#define CORE921x_OSC_CNT0_L_ADDR (0x06) +#define CORE921x_OSC_CNT1_H_ADDR (0x07) +#define CORE921x_OSC_CNT1_L_ADDR (0x08) + +/**************************************************************** + * ic sample param structure, 0x09 - 0x23 = 28byte + ***************************************************************/ +#define CORE921x_SAMPLE_DATA_ADDR_BASE (0x09) +typedef struct +{ + /* env data, 6byte_12bit[12,0] */ + unsigned char slot0_envh6; + unsigned char slot0_envl6; + unsigned char slot1_envh6; + unsigned char slot1_envl6; + unsigned char slot2_envh6; + unsigned char slot2_envl6; + /* ps data 3byte */ + unsigned char slot0_ps; + unsigned char slot1_ps; + unsigned char slot2_ps; + /* bio data 4byte */ + unsigned char bioinn_valh; + unsigned char bioinn_vall; + unsigned char bioext_valh; + unsigned char bioext_vall; + /* temp data 6byte */ + unsigned char tempslot0_valh; /* temp0-inside */ + unsigned char tempslot0_vall; + unsigned char tempslot1_valh; /* temp1-external */ + unsigned char tempslot1_vall; + unsigned char tempref_valh; /* temp_ext_ref */ + unsigned char tempref_vall; +} VC921x_PACKED core921x_reg_result_t; + +/**************************************************************** + * ic config param structure.[SLOT_CONFIG] + ***************************************************************/ +#define CORE921x_CONFIG_SLOT_ADDR_BASE (0x40) +typedef struct +{ + unsigned char oversample : 3; + unsigned char freq_isps : 1; + unsigned char rxgain : 3; + unsigned char enable : 1; +} VC921x_PACKED core921x_slot_ppg_cfg0bit; +typedef struct +{ + unsigned char env_time : 4; + unsigned char sample_time : 2; + unsigned char txch : 2; +} VC921x_PACKED core921x_slot_ppg_cfg1bit; +typedef struct +{ + unsigned char current : 7; + unsigned char storefifo : 1; +} VC921x_PACKED core921x_slot_cfg2bit; +typedef struct +{ + unsigned char sc : 4; + unsigned char resistance : 4; +} VC921x_PACKED core921x_slot_cfg3bit; +/*---[slot regist map]---*/ +typedef struct +{ + union /* 1_byte */ + { + unsigned char byte; + core921x_slot_ppg_cfg0bit bits; + } slot_cfg0; + union /* 2_byte */ + { + unsigned char byte; + core921x_slot_ppg_cfg1bit bits; + } slot_cfg1; + union /* 3_byte */ + { + unsigned char byte; + core921x_slot_cfg2bit bits; + } slot_cfg2; + union /* 4_byte */ + { + unsigned char byte; + core921x_slot_cfg3bit bits; + } slot_cfg3; +} VC921x_PACKED core921x_slot_config_t; + +/**************************************************************** + * ic config param structure.[PD_CONFIG + IRQ_RATE_CONFIG + IRQ_CONFIG] + ***************************************************************/ +#define CORE921x_INT_RATE_IRQ_CONFIG_ADDR_BASE (0x4C) + +typedef struct +{ + unsigned char slot0_pdch : 2; + unsigned char slot1_pdch : 2; + unsigned char slot2_pdch : 2; + unsigned char reserved : 2; +} VC921x_PACKED core921x_pd_cfgbit; + +typedef struct +{ + unsigned char anti_current : 3; + unsigned char reserved1 : 1; + unsigned char deslot0 : 1; + unsigned char deslot1 : 1; + unsigned char deslot2 : 1; + unsigned char reserved2 : 1; +} VC921x_PACKED core921x_anti_cfgbit_1120mpw; + +typedef struct +{ + unsigned char anti_current : 3; + unsigned char deslot0 : 1; + unsigned char deslot1 : 1; + unsigned char deslot2 : 1; + unsigned char antiTxch : 2; +} VC921x_PACKED core921x_anti_cfgbit; + +typedef struct +{ + unsigned char cpd : 3; + unsigned char fifo_en : 1; + unsigned char fifoformat : 1; + unsigned char bio_disfreqHop : 1; /* del function */ + unsigned char i2crelease_en : 1; + unsigned char deenv_en : 1; +} VC921x_PACKED core921x_com_cfgbit; +typedef struct +{ + unsigned char ppgthl : 4; + unsigned char ppgthh : 4; +} VC921x_PACKED core921x_ppgth_cfgbit; + +typedef struct +{ + unsigned char intppg_en : 1; + unsigned char intov_en : 1; + unsigned char intfifo_en : 1; + unsigned char intfreq2_en : 1; + unsigned char intlen : 2; + unsigned char intdir : 1; + unsigned char intmode : 1; +} VC921x_PACKED core921x_int_cfgbit; + +typedef struct +{ + /* 1byte pdch_config */ + union + { + unsigned char byte; + core921x_pd_cfgbit bits; + } pd_cfg; + /* 2_byte:anti_slot */ + union + { + unsigned char byte; + core921x_anti_cfgbit bits; + }; + /* 3_byte:com&pdcfg */ + union + { + unsigned char byte; + core921x_com_cfgbit bits; + } com_cfg; + /* 4~7_byte */ + unsigned char freq1_divH; + unsigned char freq1_divL; /* ppg_freq1_div = 20K / rete1 */ + unsigned char freq2_div; /* ps_freq2_div = ppg_freq / rate2 */ + unsigned char freq3_div; /* fifo_freq3_div = ps_freq / rate3 */ + /* 8_byte */ + union + { + unsigned char byte; + core921x_ppgth_cfgbit bits; + } ppgth_cfg; + /* 9_byte */ + union + { + unsigned char byte; + core921x_int_cfgbit bits; + } int_cfg; +} VC921x_PACKED core921x_common_config_t; + +/**************************************************************** + * ic config param structure.[EXTRA_CONFIG] + ***************************************************************/ +#define CORE921x_EXTRA_CONFIG_ADDR_BASE (0x54) + +typedef struct +{ + /* byte1 */ + unsigned char bio_freq : 2; + unsigned char bio_pdch : 2; + unsigned char bio_mode : 2; /* 00/01 work in freq2,noFIFO/inFIFO, single sample data + 10/11 work in freq1,inFIFO, single sample data / the sum data on freq2 */ + unsigned char bio_inn_en : 1; + unsigned char bio_ext_en : 1; +} VC921x_PACKED core921x_bio_cfg0bit; +typedef struct +{ + unsigned char bio_time : 3; + unsigned char bio_capadd : 5; +} VC921x_PACKED core921x_bio_cfg1bit; + +typedef struct +{ + unsigned char temp_currset : 3; + unsigned char temp_reserved_1 : 1; + unsigned char temp_slotch : 2; + unsigned char temp_reserved_2 : 1; + unsigned char temp_enable : 1; +} VC921x_PACKED core921x_temp_cfgbit; +typedef struct +{ + union /* 1_byte */ + { + unsigned char byte; + core921x_bio_cfg0bit bits; + } bio_cfg0; + union /* 2_byte */ + { + unsigned char byte; + core921x_bio_cfg1bit bits; + } bio_cfg1; + union /* 3_byte */ + { + unsigned char byte; + core921x_temp_cfgbit bits; + } temp0_cfg; + union /* 4_byte */ + { + unsigned char byte; + core921x_temp_cfgbit bits; + } temp1_cfg; +} VC921x_PACKED core921x_extra_config_t; // core921x_extra_config_t + +typedef struct +{ + unsigned char ovtype : 1; + unsigned char cmpset : 2; + unsigned char reserved : 1; + unsigned char ppg_resulution : 2; + unsigned char adc_speed : 1; /* reserved */ + unsigned char env_clkdiv : 1; /* reserved */ +} VC921x_PACKED core921x_adc_config_t; + +typedef struct +{ + unsigned char ovtype : 1; + unsigned char reserved : 3; + unsigned char ppg_resulution : 2; + unsigned char adc_speed : 1; /* reserved */ + unsigned char env_clkdiv : 1; /* reserved */ +} VC921x_PACKED core921x_adc_config_t_1120mpw; + +/**************************************************************** + * work_cmd & fifo_data structure + ***************************************************************/ +#define CORE921x_WORK_CMD_ADDR_BASE (0X7B) +#define CORE921x_WORK_CMD_SIZE (1) +/* fifo addr */ +#define CORE921x_FIFO_READADDR_INDEX (0xFE) +#define CORE921x_FIFO_DATA_ADDR (0xff) + +/**************************************************************** + * inline func: vc921x_core_memset,vc921x_core_memcpy + ***************************************************************/ +#ifndef NULL +#define NULL (void *)0 +#endif +static inline void *vc921x_core_memset(void *dest, int set, unsigned int n) +{ + if (dest == NULL || n <= 0) + { + return NULL; + } + char *pdest = (char *)dest; + while (n-- > 0) + { + *pdest++ = set; + } + return dest; +} +static inline void *vc921x_core_memcpy(void *dest, void *src, unsigned int n) +{ + if (dest == NULL || src == NULL) + { + return NULL; + } + char *pdest = (char *)dest; + char *psrc = (char *)src; + while (n--) + { + *pdest++ = *psrc++; + } + return dest; +} + +#endif /* __VC921x_CORE_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_core_com.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_core_com.h new file mode 100644 index 000000000..47c170662 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_core_com.h @@ -0,0 +1,458 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2024-04-09 15:26:54 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +//!!!!!!注意:本头文件不允许用户自己包含及调用相关的API,仅允许vc921x_driver.c包含,避免出错或者是产生的ROM占用 +//!!!!!!注意:本头文件不允许用户自己包含及调用相关的API,仅允许vc921x_driver.c包含,避免出错或者是产生的ROM占用 +#ifndef __VC921x_CORE_COM_H__ +#define __VC921x_CORE_COM_H__ + +#include "vc921x_sample_result.h" +#include "vc921x_driver_config.h" + +/* 如果需要指定变量到对应的字段在次定义,且重新编译 */ +#define CORE921x_DATA_RAM_SECTION //__attribute__((section(".core921xdata"))) +#define CORE921x_FUNC_RAM_SECTION //__attribute__((section(".core921xfunc"))) +/*============================================================================ + * CORE921x_DEBUG :debug interface + ===========================================================================*/ +// #define CORE921x_DEBUG_VERSION +/* 在编译库的时候,-D CORE921x_DEBUG_VERSION 对代码进行分版本生成库(debug/release) */ +#ifdef CORE921x_DEBUG_VERSION +extern void log_direct(unsigned int info, const char *fmt, ...); +#define CORE921x_DEBUG_LOG(fmt, ...) \ + do \ + { \ + log_direct((33 << 24), "[CORE921x_LOG]line(%d)" fmt, __LINE__, ##__VA_ARGS__); \ + } while (0) +#define CORE921x_DEBUG_ERR(fmt, ...) \ + do \ + { \ + log_direct((33 << 24), "[CORE921x_ERR]line(%d)" fmt, __LINE__, ##__VA_ARGS__); \ + } while (0) +#else +#define CORE921x_DEBUG_LOG(fmt, ...) +#define CORE921x_DEBUG_ERR(fmt, ...) +#endif + +#if 0 // CORE921x_DEBUG_LOG example +extern int (*vc921x_dbglog_user)(const char *, ...); +#define CORE921x_DEBUG_LOG(fmt, ...) \ + do \ + { \ + if (vc921x_dbglog_user) \ + vc921x_dbglog_user("[CORE921x_LOG]%s(%d)" fmt, __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) +#define CORE921x_DEBUG_ERR(fmt, ...) \ + do \ + { \ + if (vc921x_dbglog_user) \ + vc921x_dbglog_user("[CORE921x_ERR]%s(%d)" fmt, __func__, __LINE__, ##__VA_ARGS__); \ + } while (0) +//#else +#define CORE921x_DEBUG_LOG(fmt, ...) +#define CORE921x_DEBUG_ERR(fmt, ...) +#endif + +/*============================================================================ + * IC resources marco + ===========================================================================*/ + /* VC921x IC type ID */ +#define VC921x_DEV_REV_ID 0x24 +#define VC921x_FDY_VER_ID0 0x10 + +#define VC921x_FDY_VER_ID1 0x30 + +#define VC921x_DEFAULT_FREQ (20000) /* 20K */ +/* work event */ +#define VC921x_EVENT_BIO_FLOW (1 << 6) +#define VC921x_EVENT_INSAMPLE (1 << 5) +#define VC921x_EVENT_CONFLICT (1 << 4) +#define VC921x_EVENT_INTPS_RDY (1 << 3) +#define VC921x_EVENT_INTFIFO_RDY (1 << 2) +#define VC921x_EVENT_INTOVLOAD (1 << 1) +#define VC921x_EVENT_INTPPG_STA (1 << 0) +/* work status */ +#define VC921x_STATUS_CH2_OVERLOAD (1 << 2) +#define VC921x_STATUS_CH1_OVERLOAD (1 << 1) +#define VC921x_STATUS_CH0_OVERLOAD (1 << 0) +/* enable event */ +#define VC921x_EN_EVT_FREQ2 (1 << 3) +#define VC921x_EN_EVT_FIFO (1 << 2) +#define VC921x_EN_EVT_OVLD (1 << 1) +#define VC921x_EN_EVT_PPG (1 << 0) + +typedef enum +{ + VC921x_CFG_DISABLE = 0, + VC921x_CFG_ENABLE = 1, +} VC921x_CFG_FUNC; + +typedef enum +{ + VC921x_PPG_SLOT_0 = 0, + VC921x_PPG_SLOT_1 = 1, + VC921x_PPG_SLOT_2 = 2, /* fix=ps */ +} VC921x_PPG_SLOT_I; /* 逻辑工作通道 */ + +typedef enum +{ + VC921x_PPG_TXCH_0 = 0, /* default:green */ + VC921x_PPG_TXCH_1 = 1, /* default: red */ + VC921x_PPG_TXCH_2 = 2, /* fix=ps,or irled */ +} VC921x_PPG_TXCH_I; /* 物理发光通道 */ + +typedef enum +{ + VC921x_FREQ_PPG = 0, /* high */ + VC921x_FREQ_PS = 1, /* low */ +} VC921x_FREQ_SEL; + +typedef enum +{ + VC921x_NO_STORE = 0, + VC921x_IN_STORE = 1, +} VC921x_STORE_FIFO; + +typedef enum +{ + VC921x_IO_PUSH_PULL = 0, + VC921x_IO_OPEN_DRAIN = 1, +} VC921x_IO_MODE; +typedef enum +{ + VC921x_IO_DIR_UP_EDGE = 0, + VC921x_IO_DIR_DOWN_EDGE = 1, +} VC921x_IO_DIR; + +typedef enum +{ + VC921x_IO_PULSE_TIM_100US = 0, + VC921x_IO_PULSE_TIM_200US = 1, + VC921x_IO_PULSE_TIM_400US = 2, + VC921x_IO_PULSE_TIM_800US = 3, +} VC921x_IO_PULSE_TIM; + +typedef enum +{ + VC921x_SAMPLE_TIM_50US = 0, + VC921x_SAMPLE_TIM_100US = 1, + VC921x_SAMPLE_TIM_150US = 2, + VC921x_SAMPLE_TIM_200US = 3, +} VC921x_SAMPLE_TIM; + +typedef enum +{ + VC921x_SLOT_CHSEL_NONE= 0, + VC921x_SLOT_CHSEL_PD01= 1, + VC921x_SLOT_CHSEL_PD10= 2, + VC921x_SLOT_CHSEL_PD11= 3, +}VC921x_SLOT_CHSEL; + +typedef enum +{ + VC921x_BIO_NOFIFO_PS_SGL= 0, + VC921x_BIO_INFIFO_PS_SGL= 1, + VC921x_BIO_INFIFO_PPG_SGL= 2, + VC921x_BIO_INFIFO_PPG_SUM= 3, +}VC921x_BIO_MODE; + +typedef enum +{ + VC921x_BIO_CHSEL_NONE= 0, + VC921x_BIO_CHSEL_ETP0= 1, + VC921x_BIO_CHSEL_ETP1= 2, + VC921x_BIO_CHSEL_PD11= 3, +}VC921x_BIO_CHSEL; + +typedef enum +{ + VC921x_TEMP_SLOT_INN = 0, + VC921x_TEMP_SLOT_EXT0 = 1, + VC921x_TEMP_SLOT_EXT1 = 2, +}VC921x_TEMP_SLOT; + +typedef enum +{ + VC921x_ADC_RESOLUTION_16BIT = 0, + VC921x_ADC_RESOLUTION_18BIT = 1, + VC921x_ADC_RESOLUTION_20BIT = 2, + VC921x_ADC_RESOLUTION_22BIT = 3, +}VC921x_ADC_RESOLUTION; + +typedef enum +{ + VC921x_STOP_WORK_CMD = 0, + VC921x_START_WORK_CMD, + VC921x_RESET_SOFT_CMD, + VC921x_WORK_CMD_NUM, +} VC921x_WORK_CMD; +/*============================================================================ + * VC921x_CORE_API + ===========================================================================*/ +/**************************************************************************** + * @description: 获取内核驱动版本信息 + * @param {char} **ppver + * @return {int} 0(success),-1(read/write/ticks func_pointer error) + ****************************************************************************/ +static inline int core921x_read_software_version(char **ppver) +{ + extern int __core921x_read_software_version(char **ppver); + return __core921x_read_software_version(ppver); +} + +/**************************************************************************** + * @description: 读取ic的ID参数 + * @param {unsigned char} *pid1 版本ID + * @param {unsigned char} *pid2 扩展ID + * @return {int} 0(success),-1(read/write error),1(parameter error),2(ic_id error) + ****************************************************************************/ +static inline int core921x_read_id(unsigned char *pid1, unsigned char *pid2) +{ + extern int __core921x_read_id(unsigned char *pid1, unsigned char *pid2); + return __core921x_read_id(pid1, pid2); +} + +/**************************************************** + * @description: 读取中断事件和过载状态 + * @param {int} *pevt 事件状态 + * @param {unsigned char} *povsta 过载状态 + * @return {int} 0(success),-1(read/write error) + ****************************************************/ +static inline int core921x_read_event_status(unsigned char *pevt, unsigned char *povsta, unsigned char *pwindex_bak, unsigned char *pwindex_rel ) +{ + extern int __core921x_read_event_status(unsigned char *pevt, unsigned char *povsta, unsigned char *pwindex_bak, unsigned char *pwindex_rel); + return __core921x_read_event_status(pevt, povsta, pwindex_bak, pwindex_rel ); +} + +/*************************************************************************** + * @description: 读取时钟tick + * @param {unsigned int} *ptick0 + * @param {unsigned int} *ptick1 + * @return {int} 0(success),-1(read/write error) + ****************************************************************************/ +static inline int core921x_read_rcosc_tick(unsigned short int *ptick0, unsigned short int *ptick1) +{ + extern int __core921x_read_rcosc_tick(unsigned short int *ptick0, unsigned short int *ptick1); + return __core921x_read_rcosc_tick(ptick0, ptick1); +} + +/**************************************************************************** + * @description: 读取基础采样数据 + * @param {result_t} *psample_ret + * @return {int} 0(success),-1(read/write error) + ****************************************************************************/ +static inline int core921x_read_output(vc921x_sample_info_t *psample_ret) +{ + extern int __core921x_read_output(vc921x_sample_info_t * psample_ret); + return __core921x_read_output(psample_ret); +} + +/**************************************************************************** + * @description: 读取fifo_PPG数据 + * @param {result_t} *psample_ret + * @param {unsigned char} *pread_fifoaddr + * @return {int} 0(success),-1(read/write error),1(analysis err) + ****************************************************************************/ +static inline int core921x_read_fifo_data(vc921x_sample_info_t *psample_ret, unsigned char *pread_fifoaddr, unsigned char read_windex) +{ + extern int __core921x_read_fifo_data(vc921x_sample_info_t * psample_ret, unsigned char *pread_fifoaddr, unsigned char read_windex); + return __core921x_read_fifo_data(psample_ret, pread_fifoaddr, read_windex); +} + +/* 通道相关配置 */ +static inline int core921x_set_enable_config(VC921x_PPG_SLOT_I slot_index, VC921x_CFG_FUNC config_enable) +{ + extern int __core921x_set_slot_enable_config(VC921x_PPG_SLOT_I slot_index, VC921x_CFG_FUNC config_enable); + return __core921x_set_slot_enable_config(slot_index, config_enable); +} + +static inline int core921x_set_slot_fix_param_config(VC921x_PPG_SLOT_I slot_index, unsigned char rxgain, VC921x_CFG_FUNC freq_isps, unsigned char oversample, VC921x_PPG_TXCH_I txslot, VC921x_SAMPLE_TIM sample_tim, VC921x_CFG_FUNC slot_infifo ) +{ + extern int __core921x_set_slot_fix_param_config(VC921x_PPG_SLOT_I slot_index, unsigned char rxgain, VC921x_CFG_FUNC freq_isps, unsigned char oversample, VC921x_PPG_TXCH_I txchsel, VC921x_SAMPLE_TIM sample_tim, VC921x_CFG_FUNC slot_infifo ); + return __core921x_set_slot_fix_param_config(slot_index, rxgain, freq_isps, oversample, txslot, sample_tim, slot_infifo ); +} + +static inline int core921x_read_slot_adjust_param(unsigned char *pmax_res, unsigned char *pmin_res, unsigned char *pmax_curr, unsigned char *pmin_curr) +{ + extern int __core921x_read_slot_adjust_param(unsigned char *pmax_res, unsigned char *pmin_res, unsigned char *pmax_curr, unsigned char *pmin_curr); + return __core921x_read_slot_adjust_param(pmax_res, pmin_res, pmax_curr, pmin_curr); +} +static inline int core921x_read_slot_current_res(VC921x_PPG_SLOT_I slot_index, unsigned char *pslot_curr, unsigned char *pslot_reslvl) +{ + extern int __core921x_read_slot_current_res(VC921x_PPG_SLOT_I slot_index, unsigned char *pslot_curr, unsigned char *pslot_reslvl); + return __core921x_read_slot_current_res(slot_index, pslot_curr, pslot_reslvl); +} + +static inline int core921x_set_ppgslot_current(VC921x_PPG_SLOT_I slot_index, unsigned char current) +{ + extern int __core921x_set_ppgslot_current(VC921x_PPG_SLOT_I slot_index, unsigned char current); + return __core921x_set_ppgslot_current(slot_index, current); +} + +static inline int core921x_set_ppgslot_resistance(VC921x_PPG_SLOT_I slot_index, unsigned char res_level, unsigned char allow_oversample ) +{ + extern int __core921x_set_ppgslot_resistance(VC921x_PPG_SLOT_I slot_index, unsigned char res_level, unsigned char allow_oversample ); + return __core921x_set_ppgslot_resistance(slot_index, res_level, allow_oversample ); +} +/*--------------------------------------------------------------*/ +extern int __core921x_set_slotx_pd_config( VC921x_SLOT_CHSEL slot0_pd, VC921x_SLOT_CHSEL slot1_pd, VC921x_SLOT_CHSEL slot2_pd ); +extern int __core921x_set_anti_slot_config( unsigned char anti_current, VC921x_CFG_FUNC deslot0, VC921x_CFG_FUNC deslot1, VC921x_CFG_FUNC deslot2, VC921x_PPG_TXCH_I antich ); +extern int __core921x_set_adc_config( VC921x_ADC_RESOLUTION adc_resulution, VC921x_CFG_FUNC ovdata_sum_enable ); +extern int __core921x_set_common_config(VC921x_CFG_FUNC deenv_en, VC921x_CFG_FUNC i2crelease_en, VC921x_CFG_FUNC bio_disfreqHop, VC921x_CFG_FUNC fifo_format, VC921x_CFG_FUNC fifo_en, unsigned char cpd); +static inline int core921x_set_common_config(unsigned char fifo_enable, unsigned fifo_format, unsigned char adc_resolution, VC921x_SLOT_CHSEL slot0_pd, VC921x_SLOT_CHSEL slot1_pd, VC921x_SLOT_CHSEL slot2_pd ) +{ + VC921x_CFG_FUNC fifo_enable_cfg = (fifo_enable) ? VC921x_CFG_ENABLE : VC921x_CFG_DISABLE; + VC921x_CFG_FUNC fifo_format_cfg = (fifo_format) ? VC921x_CFG_ENABLE : VC921x_CFG_DISABLE; + VC921x_ADC_RESOLUTION adc_resolution_cfg = VC921x_ADC_RESOLUTION_16BIT; + switch ( adc_resolution ) + { + case 16:adc_resolution_cfg=VC921x_ADC_RESOLUTION_16BIT; break; + case 18:adc_resolution_cfg=VC921x_ADC_RESOLUTION_18BIT; break; + case 20:adc_resolution_cfg=VC921x_ADC_RESOLUTION_20BIT; break; + case 22:adc_resolution_cfg=VC921x_ADC_RESOLUTION_22BIT; break; + default:adc_resolution_cfg=VC921x_ADC_RESOLUTION_16BIT; break; + } + __core921x_set_slotx_pd_config( slot0_pd, slot1_pd, slot2_pd ); + __core921x_set_anti_slot_config( 0/*0-7*/, VC921x_CFG_DISABLE,VC921x_CFG_DISABLE,VC921x_CFG_DISABLE, VC921x_PPG_TXCH_2 ); + __core921x_set_adc_config( adc_resolution_cfg, VC921x_CFG_DISABLE /* ov_type */ ); + return __core921x_set_common_config(VC921x_CFG_ENABLE, VC921x_CFG_ENABLE, VC921x_CFG_ENABLE/*dis_biofreq_hop*/, fifo_format_cfg, fifo_enable_cfg, 0); +} +/* 频率设置相关API */ +/**************************************************************************** + * @description: (ppg=20K/div1,ps=ppg/div2,fifo=ps/div3) + * @param {unsigned short int} div1 + * @param {unsigned char} div2 + * @param {unsigned char} div3 + * @return {int} 0(success),-1(read/write error) + ****************************************************************************/ +static inline int core921x_set_sample_frequency(unsigned short int div1, unsigned char div2, unsigned char div3) +{ + extern int __core921x_set_sample_frequency(unsigned short int div1, unsigned char div2, unsigned char div3); + return __core921x_set_sample_frequency(div1 - 1, div2 - 1, div3 - 1); +} + +static inline int core921x_set_threshold_config(unsigned char ppgth_h, unsigned char ppgth_l) +{ + extern int __core921x_set_threshold_config(unsigned char ppgth_h, unsigned char ppgth_l); + return __core921x_set_threshold_config(ppgth_h, ppgth_l); +} +static inline int core921x_set_interrupt_config(unsigned char evt_en) +{ + extern int __core921x_set_interrupt_config(VC921x_IO_MODE int_mode, VC921x_IO_DIR int_dir, VC921x_IO_PULSE_TIM int_len, unsigned char evt_en); + return __core921x_set_interrupt_config(VC921x_IO_PUSH_PULL, VC921x_IO_DIR_UP_EDGE, VC921x_IO_PULSE_TIM_100US, evt_en); +} + +static inline int core921x_set_bioslot_config(vc921x_sample_info_t *psample_info, unsigned char addcap) +{ + unsigned char bio_time = 6; + if( VC921x_BIO_INFIFO_PPG_SGL==psample_info->extra_result.biofifo_mode || VC921x_BIO_INFIFO_PPG_SUM==psample_info->extra_result.biofifo_mode ) + { +#if (VC921x_PS_WORK_FREQUENCY_CONFIG==1) + bio_time = 3; /* (ps=(25/13)hz~520ms,ps_div=13,fifo_div=1) 5200us */ +#elif (VC921x_PS_WORK_FREQUENCY_CONFIG==0) + switch (psample_info->ps_div) /* time = 2^n * 50 * ps_div */ + { + case 5: /* ppg=25,ps=5 */ + bio_time = 5; /* default 8ms:5-4-3-2-1 , 4ms:4-3-2-1-0 */ + break; + case 10: + bio_time = 4; + break; + case 20: + bio_time = 3; + break; + case 40: + bio_time = 2; + break; + case 80: + bio_time = 1; + break; + default: + CORE921x_DEBUG_ERR("fifo time error when underclocking"); + break; + } +#endif + } + extern int __core921x_set_bioslot_config(VC921x_CFG_FUNC bioinn_en, VC921x_CFG_FUNC bioext_en, VC921x_BIO_MODE biofifo_mode, VC921x_BIO_CHSEL bio_chsel, unsigned char biofreq, unsigned char biocap, unsigned char biotime) ; + return __core921x_set_bioslot_config((VC921x_CFG_FUNC)psample_info->extra_result.bioinn_enwork, + (VC921x_CFG_FUNC)psample_info->extra_result.bioext_enwork, + (VC921x_BIO_MODE)psample_info->extra_result.biofifo_mode, + VC921x_CFG_BIO_CHANNL_SELECT, + 2, addcap, bio_time); +} +static inline int core921x_set_bioinn_addcap(vc921x_sample_info_t *psample_info,unsigned char biocap) +{ + extern int __core921x_set_bioinn_addcap(unsigned char biocap); + return __core921x_set_bioinn_addcap(biocap); +} + +static inline int core921x_set_temperature_config(vc921x_sample_info_t *psample_info) +{ + extern int __core921x_set_temperature_config(VC921x_CFG_FUNC tempslot0_en, VC921x_TEMP_SLOT tempslot0_chsel, unsigned char tempslot0_current, + VC921x_CFG_FUNC tempslot1_en, VC921x_TEMP_SLOT tempslot1_chsel, unsigned char tempslot1_current ); + return __core921x_set_temperature_config((VC921x_CFG_FUNC)psample_info->extra_result.tempslot0_enwork, VC921x_TEMP_SLOT_INN, psample_info->extra_result.tempslot0_setcur, + (VC921x_CFG_FUNC)psample_info->extra_result.tempslot1_enwork, VC921x_TEMP_SLOT_EXT1, psample_info->extra_result.tempslot1_setcur ); +} + +/**************************************************************************** + * @description: 设置RCOSC校准值 + * @param {unsigned char} oscfreq + * @return {int} 0(success),-1(read/write error) + ****************************************************************************/ +static inline int core921x_set_rcosc_frequency(unsigned char oscfreq) +{ + extern int __core921x_set_rcosc_frequency(unsigned char oscset); + return __core921x_set_rcosc_frequency(oscfreq); +} + +/**************************************************************************** + * @description: + * @param {VC921x_WORK_CMD} cmd + * @return {int} 0(success),-1(read/write error),1(parameter error) + ****************************************************************************/ +static inline int core921x_write_work_cmd(VC921x_WORK_CMD cmd) +{ + extern int __core921x_write_work_cmd(VC921x_WORK_CMD cmd); + return __core921x_write_work_cmd(cmd); +} + +/*============================================================================ + * IC config ppg/ps slot function + ===========================================================================*/ +static inline int core921x_sample_slotx_config(VC921x_PPG_SLOT_I slot_index ,vc921x_sample_info_t *psample_info, VC921x_PPG_TXCH_I ppg_tx, unsigned char rxgain, unsigned char oversample, VC921x_SAMPLE_TIM sampletime) +{ + /* ppg slot0 config */ + VC921x_CFG_FUNC freq_isps = (1==psample_info->slot_result[slot_index].slot_freq_sel)?VC921x_CFG_ENABLE:VC921x_CFG_DISABLE; + if (psample_info->slot_result[slot_index].slot_enwork) + { + core921x_set_ppgslot_current(slot_index, psample_info->slot_result[slot_index].slot_current); + core921x_set_ppgslot_resistance(slot_index, psample_info->slot_result[slot_index].slot_resistance, 0 ); + core921x_set_slot_fix_param_config(slot_index, rxgain, freq_isps, oversample, ppg_tx, sampletime, psample_info->slot_result[slot_index].slot_storefifo ); + core921x_set_enable_config(slot_index, VC921x_CFG_ENABLE); + } + return 0; +} +/*=====================================================================================================================================*/ +extern int core921x_check_nto_version_init(void); +/**************************************************************** + * CORE_API.write()/set() + * common interface to write/read configuration + * write or set config registers, debug or other function. + ***************************************************************/ + +extern int vc921x_param_write_flash(unsigned char *pdata, unsigned int size); +extern int vc921x_param_read_flash(unsigned char *pdata, unsigned int size); + +extern void *vc921x_malloc(unsigned int size); +extern void vc921x_free(void *ptr); + +extern int vc921x_read_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size); +extern int vc921x_write_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size); +extern unsigned int vc921x_get_cputimer_tick(void); + +#endif /* __VC921x_CORE_COM_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver.h new file mode 100644 index 000000000..36f5bc36e --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver.h @@ -0,0 +1,127 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2023-12-21 15:37:20 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ + +#ifndef __VC921x_DRIVER_H__ +#define __VC921x_DRIVER_H__ + +#include "vcare_device_com.h" +/**************************************************************************** + * WearStatus_t + ***************************************************************************/ +#define VC921x_BIO_STA_NONE 0 +#define VC921x_BIO_STA_DROP 1 +#define VC921x_BIO_STA_HOLD 2 + +typedef enum +{ + VC921x_WEAR_NO_CHANGE = 0, + VC921x_HOLD_TO_DROP, + VC921x_DROP_TO_HOLD, +} vc921x_wear_change; + +typedef struct +{ + unsigned char hold_cnt; + unsigned char drop_cnt; + wear_status wear_status; + wear_status last_status; + wear_status algo_wear_status; + wear_status acce_wear_status; + int bio_wear_result; + unsigned short int last_ps_data[2]; + +} vc921x_wear_info; + +/**************************************************************************** + * oscclk_t + ***************************************************************************/ +typedef struct +{ + /* calc real frequency */ + unsigned int osc_count[6]; + unsigned int clk_count[6]; + unsigned char count_index; + unsigned char osc_gap_cnt; + unsigned short int rcosc_frequency; + /* check interrupt gaptime */ + unsigned short int last_check_ticks; + /* startup need get calc value */ + unsigned char rcosc_calibration; + unsigned char clk_calc_freq_status; /* calculate frequency finished */ + unsigned char clk_calc_status; /* calculate rcsoc status finished */ + +} vc921x_clk_info; + +/**************************************************************************** + * adjust_t + ***************************************************************************/ +#define VC921x_ADJUST_DIR_NONE 0 +#define VC921x_ADJUST_DIR_UP 1 +#define VC921x_ADJUST_DIR_DOWN 2 + +typedef struct +{ + unsigned char direction; + unsigned char direction_last; + unsigned short int current_step; +} vc921x_adjust_param; + +typedef struct +{ + unsigned char const_max_current; /* ic参数确定的最大电流电阻,固定 */ + unsigned char const_min_current; + unsigned char const_max_res_level; + unsigned char const_min_res_level; + unsigned char max_current; /* ic工作环境的最大电流电阻,可变 */ + unsigned char max_res_level; + unsigned char current; /* ic当前工作的最大电流电阻,可变 */ + unsigned char res_level; + + vc921x_adjust_param adj_param; + +} vc921x_adjust_info; +typedef struct +{ + int work_mode; + unsigned short ppg_div; + unsigned char ps_div; + unsigned char fifo_div; + unsigned char drop_div; + unsigned char hr_algo_mode; + + unsigned char int_event; + unsigned char ov_status; + unsigned char read_fifo_address; + unsigned char write_fifo_address_bak; /* write_addr when fifo event */ + unsigned char write_fifo_address_rel; /* write_addr at present */ + + int optimal_bio_gap; + int optimal_bio_temp; + unsigned char optimal_cap; + unsigned char optimal_bio_valid; + unsigned char ppg_max_thval; + unsigned char ppg_min_thval; + + unsigned char ppg_convert_ps; /* 如果不使用PS频率采集PS,使用PPGir来对佩戴检测进行识别,需要设置为1 */ + + unsigned char param_read_finished_sync; + unsigned char fifo_read_finished_sync; + unsigned char fifo_read_data_valid; /* 0-havn't fifo data, 1-normal fifo data, 2-read fifo data when fifo_windex offset */ + unsigned char event_read_finished_sync; + +} vc921x_drv_info; + +typedef struct +{ + work_mode mode; + int (*mode_init)(void); + int (*mode_handler)(const void *ops_self, vcare_ppg_device_t *pdev); +} vc921x_mode_ops; + +#endif /* __VC9211x_DRIVER_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver_com.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver_com.h new file mode 100644 index 000000000..55b1142a5 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver_com.h @@ -0,0 +1,148 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2023-09-26 15:22:19 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ + +#ifndef __VC921x_DRIVER_COM_H__ +#define __VC921x_DRIVER_COM_H__ + +#include "vcare_device_com.h" +/********************************************************************************************************* + * DRV_API + ********************************************************************************************************/ +/* 注意: +VC921x - fifo长度最长只有192字节,在多通道时,一次fifo的缓存不能超过192字节 + +typical: +ppg_div=800, ps_div=5, fifo_div=5 (ppg-25hz, psbio-5hz, fifo-1hz) 1000ms (921x_max=20*4+4*6=104) +ppg_div=800, ps_div=5, fifo_div=4 (ppg-25hz, psbio-5hz, fifo-1.25hz) 800ms (921x_max=20*4+4*6=104) +ppg_div=400, ps_div=10, fifo_div=2 (ppg-50hz, psbio-5hz, fifo-2.5hz) 400ms (921x_max=20*4+2*6=92) +ppg_div=200, ps_div=20, fifo_div=1 (ppg-100hz,psbio-5hz, fifo-5hz) 200ms (921x_max=20*4+1*6=88) +*/ +/**************************************************************************** + * @description: 初始化并且开始进行采样 + * @param {void} *pdevice + * @param {int} workmode + * @param {unsigned short int} ppgdiv + * @param {unsigned char} psdiv + * @param {unsigned char} fifodiv + * @return {*} + ****************************************************************************/ +int vc921x_drv_init_start_work(void *pdevice, int workmode, unsigned short int ppgdiv, unsigned char psdiv, unsigned char fifodiv, unsigned char dropdiv); +/**************************************************************************** + * @description: 获取驱动版本,IC的主ID,次ID + * @param {char} * + * @param {unsigned char} *pid1 + * @param {unsigned char} *pid2 + * @return {*} + ****************************************************************************/ +int vc921x_drv_get_hwsw_infomation(char **str_drv_ver, unsigned char *pid1, unsigned char *pid2); +/**************************************************************************** + * @description: 软复位IC并且退出工作(如需重新工作需要重新调用初始化) + * @param {void} *device + * @return {*} + ****************************************************************************/ +int vc921x_drv_exit_stop_work(void *device); +/**************************************************************************** + * @description: 软复位IC(如需重新工作需要重新调用初始化) + * @param {void} *device + * @return {*} + ****************************************************************************/ +int vc921x_drv_software_reset(void *device); +/**************************************************************************** + * @description: 唤醒工作(可以唤醒调用sleep停止工作) + * @param {void} *device + * @return {*} + ****************************************************************************/ +int vc921x_drv_wakeup_work(void *device); +/**************************************************************************** + * @description: 休眠工作(休眠后可以用wakeup唤醒工作) + * @param {void} *device + * @return {*} + ****************************************************************************/ +int vc921x_drv_sleep_work(void *device); +/**************************************************************************** + * @description: 心率算法扩展的摘下状态设置 + * @param {void} *device + * @param {int} status + * @return {*} + ****************************************************************************/ +int vc921x_drv_set_algo_wear_status(void *device, int status); +/**************************************************************************** + * @description: 运动量判断佩戴的状态设置 + * @param {void} *device + * @param {int} status + * @return {*} + ****************************************************************************/ +int vc921x_drv_set_acce_wear_status(void *device, int status); +/**************************************************************************** + * @description: 获取参数并且进行佩戴状态判断 + * @param {void} *device + * @return {*} + ****************************************************************************/ +wear_status vc921x_drv_get_wear_status(void *device); +/**************************************************************************** + * @description: 获取具体的佩戴状态各子状态 + * @param {unsigned char} *bio_ret + * @param {unsigned char} *algo_ret + * @param {unsigned char} *acce_ret + * @return {*} + ****************************************************************************/ +void vc921x_drv_get_wear_detail_result( unsigned char *bio_ret, unsigned char *algo_ret, unsigned char *acce_ret ); +/**************************************************************************** + * @description: 获取采样数据,包含PPG,PS,BIO,TMEP + * @param {void} *device + * @return {*} + ****************************************************************************/ +int vc921x_drv_get_result_handler(void *device); +/**************************************************************************** + * @description: 是否为fifo中断事件 + * @param {void} *pdevice + * @return {*} + ****************************************************************************/ +int vc921x_drv_is_fifo_event(void *pdevice); +/**************************************************************************** + * @description: 是否为PS中断事件 + * @param {void} *pdevice + * @return {*} + ****************************************************************************/ +int vc921x_drv_is_ps_event(void *pdevice); +/**************************************************************************** + * @description: 是否为PPG中断事件 + * @param {void} *pdevice + * @return {*} + ****************************************************************************/ +int vc921x_drv_is_ppg_event(void *pdevice); +/**************************************************************************** + * @description: 配平校准活体 + * @param {void} *pdevice + * @return {*} + ****************************************************************************/ +int vc921x_drv_clear_reset_bio_param(void *pdevice); +/**************************************************************************** + * @description: 同步驱动状态,清理状态数据 + * @param {void} *pdevice + * @return {*} + ****************************************************************************/ +int vc921x_drv_finished_sync(void *pdevice); +/**************************************************************************** + * @description: 提前读取中断信息,避免任务延时响应导致信息被刷掉 + * @param {*} + * @return {*} + ****************************************************************************/ +void vc921x_drv_read_event_infomation_byIRQ(void); +/**************************************************************************** + * @description: 软件定时器读取RO信息,用于定时温度检测 + * @param {*} + * @return {*} + ****************************************************************************/ +int vc921x_drv_read_check_temperature_abnormal( void *pdevice, unsigned char *p_freq_ret, unsigned char *p_temp_ret, unsigned short *pdev_cnt1, unsigned short *pdev_cnt2 ); + +int vc921x_drv_memroy_alloc(void); +int vc921x_drv_memroy_free(void); + +#endif /* __DRV_DEV_MANAGER_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver_config.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver_config.h new file mode 100644 index 000000000..15acae30e --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_driver_config.h @@ -0,0 +1,115 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2024-03-21 11:16:25 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +#ifndef __VC921x_DRIVER_CONFIG_H__ +#define __VC921x_DRIVER_CONFIG_H__ + +/* wear default status select */ +#define VC921x_WEAR_DFT_NONE (0) +#define VC921x_WEAR_DFT_DROP (1) +#define VC921x_WEAR_DFT_HOLD (2) +/* function enable select */ +#define VC921x_FUNC_DISABLE (0) +#define VC921x_FUNC_ENABLE (1) + +#define VC921x_FREQUENCY_MAX 20000 +#define VC921x_FREQUENCY_MIN 19900 +//#define VC921x_CFG_MCU_TICK_FREQUENCY 32000 // counter 32K +extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; /* extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; */ +#define VC921x_CFG_MCU_TICK_MAX 0xffffff // 24-bit counters +#define VC921x_CFG_CLK_CALC_DEVIATION 3 +#define VC921x_CFG_CLK_CALC_GAPTIME 10 // interrupt gap times( 25hz_fifo_irq:20*40~0.4sec; 5hz_fifo_irq: 20*200 ~ 2sec; 1.25hz_fifo_irq: 10*800 ~ 8sec ) + +#define VC921x_CFG_CLK_CLAC_IRQGAP_EN (VC921x_FUNC_DISABLE) +/* interrupt run check timegap,dont write "(3/4)" !!! */ +/* 25hz(40ms~30ms), 50hz(20ms~15ms), 100hz(10ms~7ms) */ +#define VC921x_IRQ_GAP_RATIO 3/4 + +#define VC921x_CFG_IRQ_BY_TIMER_EN (VC921x_FUNC_DISABLE) +/* notice:ps_freq = ppg_freq/drop_div, and VC921x_PS_WORK_FREQUENCY_CONFIG(0). */ +#define VC921x_CFG_DROP_REDUCE_FREQ (VC921x_FUNC_ENABLE) + +#define VC921x_CFG_DEFAULT_PPGGAIN_EN (1) /* 1-最小使用2倍增益, 0-最小使用单倍增益 */ + +/**************************************************************************** + * Configuration hardware:PD/BIO channl; sport heartrate param; + ***************************************************************************/ +/* (VC921x_SLOT_CHSEL_PD11):setting ppgchx pd0+pd1, (VC921x_SLOT_CHSEL_PD01),setting pd0, (VC921x_SLOT_CHSEL_PD10),setting pd1 vc921x_core_com.h@VC921x_SLOT_CHSEL*/ +#define VC921x_CFG_PPG_CHANNL_SELECT (VC921x_SLOT_CHSEL_PD11) +/* (VC921x_BIO_CHSEL_PD11),setting biochx pd0+pd1, (VC921x_BIO_CHSEL_ETP1),setting extern touch vc921x_core_com.h@VC921x_BIO_CHSEL*/ +#define VC921x_CFG_BIO_CHANNL_SELECT (VC921x_BIO_CHSEL_PD11) +#define VC921x_CFG_SPORT_HR_OVERSAMPLE (3) /* oversample = 2^N */ +#define VC921x_CFG_SPORT_HR_SAMPLETIME (VC921x_SAMPLE_TIM_200US) + +/**************************************************************************** + * Configuration wear parameters + ***************************************************************************/ +#define VC921x_CFG_WEAR_DETECTION (VC921x_FUNC_ENABLE) +#define VC921x_CFG_WEAR_DEFAULT_STA (VC921x_WEAR_DFT_HOLD) +#define VC921x_CFG_WEAR_BIO_EN (VC921x_FUNC_ENABLE) +#define VC921x_CFG_WEAR_ALG_EN (VC921x_FUNC_DISABLE) +#define VC921x_CFG_WEAR_ACC_EN (VC921x_FUNC_DISABLE) +#define VC921x_CFG_WEAR_HOLD_CNT (1) +#define VC921x_CFG_WEAR_DROP_CNT (3) +/* sensor serial default wear param */ +#define VC921x_CFG_WEAR_BIO_OLD_EN (VC921x_FUNC_DISABLE) /* 使用算法相对的方式计算活体的佩戴状态 */ +#define VC921x_WEAR_PARAM_ENVMIN 100 /* 80nA/D */ +#define VC921x_WEAR_PARAM_ENVMAX 400 +#define VC921x_WEAR_PARAM_PSTH 0xA000 /* 16bit:0xA400~40960 , 8bit:0xA0~160 */ +#define VC921x_WEAR_PARAM_PS_DELTA 0x3000 /* 16bit:0x3000~12288 , 8bit:0x30~48 */ +#define VC921x_WEAR_PARAM_BIO_DELTA 100 /* bio0/1,建议取测试变化量的45%作为参数设置 */ + +//#define VC921x_WEAR_PARAM_BIO_ABS_HOLD 200 /* 80% */ +//#define VC921x_WEAR_PARAM_BIO_ABS_DROP 160 /* 50% */ +extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; */ +extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP; */ + +/* 约定最后的一个slot一定作为红外采样 */ +#define VC921x_WEAR_PARAM_PS_CURRENT 0x25 /*range:0-0x7F */ +#define VC921x_WEAR_PARAM_PS_RESISTANCE 6 /*range:0-13 */ +#define VC921x_WEAR_PARAM_PS_GAIN 1 /* 2^n */ + +#if VC921x_CFG_DEFAULT_PPGGAIN_EN +#define VC921x_PPG_CURT 0x40 +#define VC921x_PPG_RESISTANCE 9 /* 9-1 ~ 4.48M */ +#define VC921x_PPG_GAIN 1 +/* Set the maximum current parameter in FAT1/FAT2 work_mode */ +#define VC921x_FAT_GREEN_MAX_CURT 0x60 /* 0-0x7F */ +#define VC921x_FAT_RED_MAX_CURT 0x60 /* 0-0x7F */ +#define VC921x_FAT_IR_MAX_CURT 0x60 /* 0-0x7F */ +#define VC921x_FAT_RESISTANCE 9 /* 9~4.48M, 11~8.96M */ +#define VC921x_FAT_GAIN 1 +#else +#define VC921x_PPG_CURT 0x40 +#define VC921x_PPG_RESISTANCE 11 /* 9-1 ~ 4.48M */ +#define VC921x_PPG_GAIN 0 +/* Set the maximum current parameter in FAT1/FAT2 work_mode */ +#define VC921x_FAT_GREEN_MAX_CURT 0x60 /* 0-0x7F */ +#define VC921x_FAT_RED_MAX_CURT 0x60 /* 0-0x7F */ +#define VC921x_FAT_IR_MAX_CURT 0x60 /* 0-0x7F */ +#define VC921x_FAT_RESISTANCE 11 /* 9~4.48M, 11~8.96M */ +#define VC921x_FAT_GAIN 0 +#endif + +/**************************************************************************** + * PPG AUTO ADJUST PARAMETERS + ***************************************************************************/ +#define VC921x_PPG_MIN_DEFT_THVAL (0x6) +#define VC921x_PPG_MAX_DEFT_THVAL (0xA) /*0xA~0xB*/ +#define VC921x_PPG_SPO2_MIN_DEFT_THVAL (0x09) +#define VC921x_PPG_SPO2_MAX_DEFT_THVAL (0x0A) /* 0x0A~0x0B */ +#define VC921x_ADJ_I_INCREASE 22 // 1.4 << 4 = 22.4//1.4f +#define VC921x_ADJ_I_DECREASE 11 // 0.7 << 4 = 11.2//0.7f +#define VC921x_ADJ_I_STEP_MAX 8 +#define VC921x_ADJ_I_STEP_MIN 1 +#define VC921x_ADJ_I_STEP_DFT 4 // default step + +/* fix 16bit ppg */ +#define VC921x_PPG_CONV_BIT4(data) ((data)>>4) + +#endif /* __VC921x_DRIVER_CONFIG_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_hal.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_hal.h new file mode 100644 index 000000000..735e6662c --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_hal.h @@ -0,0 +1,53 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-06-07 11:18:26 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-12 18:03:51 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.h + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ +#ifndef VC_921X_H__ +#define VC_921X_H__ +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#include "stdint.h" + +#ifdef PPG_HX3695 + +#include "tyhx_hrs_custom.h" + + +typedef uint32_t PPG_CMD_TYPE_T ; + +typedef enum{ + HX3695_MSG_TYPE_HRS_UPDATE, + HX3695_MSG_TYPE_HRV_UPDATE, + HX3695_MSG_TYPE_SPO2_UPDATE, + HX3695_MSG_TYPE_LEAKLIGHT_UPDATE, + HX3695_MSG_TYPE_GRAYCARD_UPDATE, + HX3695_MSG_TYPE_WEARSTAT_UPDATE, + HX3695_MSG_TYPE_STATIC_HRS_UPDATE, +} hx3695_msg_type_t; + + +typedef void (*hx3695_msg_callback_t)(uint8_t msg_type, uint8_t *msg_data, int32_t msg_datalen); +uint32_t hx3695_register_msg_callback(hx3695_msg_callback_t func); +hx3695_msg_callback_t hx3695_get_send_msg_callback_func(void); + +#endif + +void ppg_send_cmd_to_vc921x_driver(char* mode, uint8_t enable); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_sample_result.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_sample_result.h new file mode 100644 index 000000000..9b164f4dc --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_sample_result.h @@ -0,0 +1,158 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2024-03-21 10:49:02 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +#ifndef __VC921x_SAMPLE_RESULT_H__ +#define __VC921x_SAMPLE_RESULT_H__ + +/**************************************************************************** +drviver vc921x RAM: +core+driver: 400bytes + fifo_data_memory <= 1kb +fifo_data_memory static: 128*2 + 64*(2*2+2*1) = 448 bytes +fifo_data_memory dynamic: 128*x + 64*(2*y+2*z) = 0~448 bytes +fifo_data_memory fixdync: +*/ +#define VC921x_USE_STATIC_MEMORY (0) +#define VC921x_USE_FIXDYNC_MEMORY (1) /* memory is allocated when the device is registered and freed when the device is deregistered */ +#define VC921x_USE_MEMORY_SELECT (VC921x_USE_STATIC_MEMORY) +#define VC921x_PPGSLOT_BUFFER_NUM (64) /* memory_buffer(40~64) = enable_ppgslot_num * ( VC921x_PPGSLOT_BUFFER_NUM * sizeof(unsigned short int) ) */ +#define VC921x_PS2SLOT_BUFFER_NUM (32) /* memory_buffer(20~32) = enable_bioslot_num * ( VC921x_PS2SLOT_BUFFER_NUM * sizeof(unsigned short int) ) + 1*( VC921x_PS2SLOT_BUFFER_NUM * sizeof(unsigned short int) ) */ + +/* ps sample frequency config, if work_fast,the frequency=12.5hz, otherwise is 5hz +[0] ps= 5hz~200ms, fifo_time=1000ms, 800ms, 600ms, 400ms, 200ms +[1] ps=(1000/520)hz~520ms, fifo_time=520ms(25hz), 260ms(50hz), 130ms(100hz), user defined time, ps-fifo working on the same frequency (~9201,VC30F). + !!!notice: need config bio_param_time @ vc30fx_core_com.h @ core30fx_set_bioslot_config +[2]........ +*/ +#define VC921x_PS_WORK_FREQUENCY_CONFIG (0) + +/* ppg/ps slot parameter description: +slot_config: structure handle. +enwork: slot configuration enable work, 0-disbale, 1-work_ppg, 2-work_ps. +freqsel: frequency selection, 0-ppg_frequency, 1-ps_frequency. vc921x_core_com.h:enum@VC921x_FREQ_SEL. +storefifo: fifo configuration, 0-nofifo,1-infifo, available when slot_freq_sel is ps_frequency. @VC921x_STORE_FIFO. +current: ppg_slot work current set(0x00~0x7f). +resistance: ppg_slot work resistance set(0~13). +*/ +#define VC921x_SLOT_PARAM_CONFIG(slot_config, enwork, freqsel, storefifo, current, resistance) \ + { \ + slot_config.slot_enwork = enwork; \ + slot_config.slot_freq_sel = freqsel; \ + slot_config.slot_storefifo = storefifo; \ + slot_config.slot_current = current; \ + slot_config.slot_resistance = resistance; \ + } +#define VC921x_PPG_SLOT_PARAM_CONFIG(slot_config, current, resistance) VC921x_SLOT_PARAM_CONFIG(slot_config, 1, VC921x_FREQ_PPG, VC921x_IN_STORE, current, resistance) +/*------PS slot default use slot2------*/ +#define VC921x_PS_SLOT_PARAM_CONFIG(slot_config, storefifo, current, resistance) VC921x_SLOT_PARAM_CONFIG(slot_config, 2, VC921x_FREQ_PS, storefifo, current, resistance) +/* bio slot parameter description: +bio_config: structure handle. +inn_enable: inside slot configuration enable work, @VC921x_CFG_FUNC. +ext_enable: external slot configuration enable work, @VC921x_CFG_FUNC. +fifo_mode: fifo and ppgmode configuration, @VC921x_BIO_MODE. +*/ +#define VC921x_BIO_SLOT_PARAM_CONFIG(bio_config, inn_enable, ext_enable, fifo_mode ) \ + { \ + bio_config.bioinn_enwork = inn_enable; \ + bio_config.bioext_enwork = ext_enable; \ + bio_config.biofifo_mode = fifo_mode; \ + } +/* tmp slot parameter description: +tmp_config: structure handle. +inn_enable: inside slot configuration enable work, @VC921x_CFG_FUNC. +ext_enable: external slot configuration enable work, @VC921x_CFG_FUNC. +setcur: external slot config work current(0~7). +*/ +#define VC921x_TMP_SLOT_PARAM_CONFIG(tmp_config, slot0_enable, slot1_enable, setcur) \ + { \ + tmp_config.tempslot0_enwork = slot0_enable; \ + tmp_config.tempslot1_enwork = slot1_enable; \ + tmp_config.tempslot0_setcur = setcur; \ + tmp_config.tempslot1_setcur = setcur; \ + } + +/**************************************************************** + * structures:vc921x_sample_info_t + ***************************************************************/ +typedef struct +{ + /* slot_config */ + unsigned char slot_enwork; /* slot_enwork, 0-disbale, 1-work_ppg, 2-work_ps. */ + unsigned char slot_freq_sel; /* 0-ppg_frequency, 1-ps_frequency. vc921x_core_com.h, @VC921x_FREQ_SEL. */ + unsigned char slot_storefifo; /* 0-nofifo,1-infifo, available when slot_freq_sel is ps_frequency. */ + unsigned char slot_led_sel; /* 0-green led, 1-red led, 2-infrared led */ + /* slot_variable_config */ + unsigned char slot_current; /* 0~0x7F */ + unsigned char slot_resistance; /* 0~13/0~23 */ + /* slot_result */ + unsigned short int env_data; + union + { + unsigned short int ps_data; + unsigned short int pre_data; + } u; + unsigned char ppg_num; + unsigned char ppg_buffer[VC921x_PPGSLOT_BUFFER_NUM*3]; /* 按字节存储,可以节省最大RAM */ +} vc921x_sample_slot_t; + +typedef struct +{ + /* bio_slot config */ + unsigned char bioinn_enwork; + unsigned char bioext_enwork; + unsigned char biofifo_mode; /* @VC921x_BIO_MODE */ + /* temp_slot config */ + unsigned char tempslot0_enwork; + unsigned char tempslot0_setcur; + unsigned char tempslot1_enwork; + unsigned char tempslot1_setcur; + /* extern result */ + unsigned char bio_fifo_num; + unsigned short int bioinn_data; + unsigned short int bioext_data; + unsigned short int bioabs_calc; /* abs(base-ext_now)?thh */ + unsigned short int temp0_data; + unsigned short int temp1_data; + unsigned short int tempref_data; + unsigned short int bioinn_buffer[VC921x_PS2SLOT_BUFFER_NUM]; + unsigned short int bioext_buffer[VC921x_PS2SLOT_BUFFER_NUM]; +} vc921x_sample_extra_t; + +typedef struct +{ + unsigned char ic_type_id; + unsigned char ic_ficv_id; + unsigned short int ppg_div; /* ppg_frequency = 20K / ppg_div */ + unsigned char ps_div; /* ps_frequency = ppg_frequency / ps_div */ + unsigned char fifo_div; /* fifo_frequency = ps_frequency / fifo_div */ + unsigned char hold_div; /* ps/fifo_frequency = ppg_frequency / hold_div */ + unsigned char drop_div; /* ps/fifo_frequency = ppg_frequency / drop_div */ + unsigned char fifo_enable; /* fifo_enable = 1*/ + unsigned char fifo_format; /* fifo_format,0:16bit, 1:24bit */ + unsigned char adc_resolution; /* */ + unsigned char wear_drop_flag; /* send original data flag as drop event happens */ + vc921x_sample_extra_t extra_result; + vc921x_sample_slot_t slot_result[3]; +} vc921x_sample_info_t; + +static inline unsigned int VC921x_GET_SLOT_SAMPLE_DATA( vc921x_sample_info_t* psample_info, unsigned char slot_index, unsigned char ppg_index ) +{ + if( psample_info->fifo_format == 0 ) + { + return (psample_info->slot_result[slot_index].ppg_buffer[ppg_index*2]<<8) + (psample_info->slot_result[slot_index].ppg_buffer[ppg_index*2+1] ); + } + else + { + return (psample_info->slot_result[slot_index].ppg_buffer[ppg_index*3]<<16) + (psample_info->slot_result[slot_index].ppg_buffer[ppg_index*3+1]<<8) + (psample_info->slot_result[slot_index].ppg_buffer[ppg_index*3+2] ); + } +} +static inline unsigned int VC921x_GET_SLOT_PS_DATA( vc921x_sample_info_t* psample_info, unsigned char ppg_index ) +{ + return (psample_info->slot_result[2].ppg_buffer[ppg_index*2]<<8) + (psample_info->slot_result[2].ppg_buffer[ppg_index*2+1] ); +} + +#endif /* __VC921x_SAMPLE_RESULT_H__ */ diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_user_app.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_user_app.h new file mode 100644 index 000000000..e4c85209b --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vc921x_user_app.h @@ -0,0 +1,47 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2023-10-17 09:50:21 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +#ifndef __VC921x_USER_APP_H__ +#define __VC921x_USER_APP_H__ + +#include "vcare_device_com.h" + +/* vc921x设备函数接口 */ +void vc921x_usr_device_init( InitParamTypeDef *pinitconfig ); +void vc921x_usr_get_dev_info(unsigned char *pchip_id, unsigned char *pvers_id, char **drv_name, char **dev_name); +void vc921x_usr_start_work(void); +void vc921x_usr_stop_work(void); +void vc921x_usr_soft_reset(void); +void vc921x_usr_reset_bio_param(void); +int vc921x_usr_get_wear_status(void); +void vc921x_usr_get_event_status_byIRQ(void); +void vc921x_usr_device_handler( unsigned char heart_algo_mode, unsigned char spo2_algo_mode ); +void vc921x_usr_check_temperature_abnormal(void); + + +void tyhx_poweron(void); +void tyhx_poweroff(void); + + +/* 获取vc921x设备/如果动态内存则会申请驱动内存,以下为获取的设备API,设备对象中会记录一部分计算参数和结果,用户需要直接使用即可,具体参考头文件"vcare_device_com.h": +{ + .dev_init = vc921x_usr_device_init, + .get_dev_info = vc921x_usr_get_dev_info, + .start_work = vc921x_usr_start_work, + .stop_work = vc921x_usr_stop_work, + .soft_reset = vc921x_usr_soft_reset, + .get_events = NULL, + .set_slot_enable = NULL, + .reset_bio_param = vc921x_usr_reset_bio_param, + .get_wear_status = vc921x_usr_get_wear_status, + .dev_irq_handler = vc921x_usr_device_handler, +}; +*/ +vcare_ppg_device_t *get_vc921x_device(void); + +#endif // ! diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vcSportMotionIntAlgo.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vcSportMotionIntAlgo.h new file mode 100644 index 000000000..9b4e7f307 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vcSportMotionIntAlgo.h @@ -0,0 +1,12 @@ +#ifndef VC_SPORT_MOTION_ALGO_H +#define VC_SPORT_MOTION_ALGO_H + +#include +#include +#include + + +void vcSportMotionAlgoInit(void); +int32_t vcSportMotionCalculate(int32_t x, int32_t y, int32_t z); +char *sportMotionVersion(void); +#endif diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/inc/vcare_device_com.h b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vcare_device_com.h new file mode 100644 index 000000000..a73436433 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/inc/vcare_device_com.h @@ -0,0 +1,200 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-02-23 17:47:18 + * @LastEditTime: 2023-11-14 17:38:46 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ + +#ifndef __VCARE_DEVICE_COM_H__ +#define __VCARE_DEVICE_COM_H__ + +/* parameter type sleep and retain */ +#ifndef PARAM_RETAIN +#define PARAM_RETAIN +#endif +/* define NULL 0 */ +#ifndef NULL +#define NULL ((void *)0) +#endif + +/* gsensor struct,user peripheral data */ +typedef struct +{ + short int xData[40]; + short int yData[40]; + short int zData[40]; +} gsensor_axes; + +typedef enum +{ + WEAR_STA_NONE = 0, + WEAR_STA_DROP, + WEAR_STA_HOLD, +} wear_status; + +typedef enum +{ + WORK_MODE_HR = 0, + WORK_MODE_SPO2, + WORK_MODE_HRV, + WORK_MODE_STRESS, + WORK_MODE_BLOODPRESSURE, + WORK_MODE_WEAR, + WORK_MODE_TEMPERATURE, + WORK_MODE_FACTORY0, + WORK_MODE_FACTORY1, + WORK_MODE_HRSPO2, + + WORK_MODE_UNDEFINED, + WORK_MODE_NUMBER, +} work_mode; + +typedef struct +{ + unsigned short sampling_gap_time; /* reserved. */ + unsigned char work_mode; /* work_mode,WorkModeTypeDef/unsigned char */ + unsigned char hr_algo_mode; +}InitParamTypeDef; + + +typedef void (*FUNC_DEV_INIT)( InitParamTypeDef *pInitconfig ); +typedef void (*FUNC_GET_DEV_INFO)(unsigned char *pchip_id, unsigned char *pvers_id, char **drv_name, char **dev_name); +typedef void (*FUNC_START_WORK)(void); +typedef void (*FUNC_STOP_WORK)(void); +typedef void (*FUNC_SOFT_RESET)(void); +typedef int (*FUNC_GET_EVENTS)(void); +typedef int (*FUNC_GET_WEAR_STATUS)(void); +typedef void (*FUNC_SET_SLOT_ENABLE)(unsigned char slot_index, unsigned char slot_enable); +typedef void (*FUNC_BIO_RESET_PARAM)(void); +typedef void (*FUNC_DEV_IRQ_HANDLER)(unsigned char heart_algo_mode, unsigned char spo2_algo_mode); +typedef void (*FUNC_DEV_CHK_TEMP_ERR)(void); + +typedef struct +{ + FUNC_DEV_INIT dev_init; + FUNC_GET_DEV_INFO get_dev_info; /* reserved */ + FUNC_START_WORK start_work; + FUNC_STOP_WORK stop_work; + FUNC_SOFT_RESET soft_reset; + FUNC_GET_EVENTS get_events; /* reserved */ + FUNC_GET_WEAR_STATUS get_wear_status; + FUNC_SET_SLOT_ENABLE set_slot_enable; /* reserved */ + FUNC_BIO_RESET_PARAM reset_bio_param; + FUNC_DEV_IRQ_HANDLER dev_irq_handler; + FUNC_DEV_CHK_TEMP_ERR dev_check_temp_error; +} dev_ops; + +typedef struct +{ + char *dev_name; + unsigned char id1; + unsigned char id2; + unsigned char dev_work_status; /* 0-don't work, 1-working */ + + unsigned char heart_algo_mode; + unsigned char spo2_algo_mode; + work_mode workmode; + wear_status wear; + /* raw result */ + void *result; + /* device ops */ + const dev_ops *ops; + /* calc result */ + int heart_rate; + int spo2; + int hrv; + int stress; + int ecg; + int temperature0; + int temperature1; + int blood_pressure; +} vcare_ppg_device_t; + +/**-------------------- defined functions --------------------**/ +#define ENABLE_MY_MEMFUNC 1 +#if ENABLE_MY_MEMFUNC +static inline void *vcare_memset(void *dest, int set, unsigned int n) +{ + if (dest == NULL || n <= 0) + { + return NULL; + } + char *pdest = (char *)dest; + while (n-- > 0) + { + *pdest++ = set; + } + return dest; +} + +static inline void *vcare_memcpy(void *dest, void *src, unsigned int n) +{ + if (dest == NULL || src == NULL) + { + return NULL; + } + char *pdest = (char *)dest; + char *psrc = (char *)src; + while (n--) + { + *pdest++ = *psrc++; + } + return dest; +} + +/* 2^(n/16) */ +static const float exponent_tab[]={1.000000,1.044274,1.090508,1.138789,1.189207,1.241858,1.296840,1.354256,1.414214, + 1.476826,1.542211,1.610490,1.681793,1.756252,1.834008,1.915207,2.000000}; +static inline float vcare_I_exponent_func( float base_i, unsigned char data_i ) +{ + unsigned char data_h = (data_i>>4)&0xf; + unsigned char data_l = (data_i>>0)&0xf; + return (base_i*(1<(bit_n))?((format_n)-(bit_n)):0) +#define CORE921x_DATA_FORMAT_COVNVERT(format_n,bit_n,data) ( (data)>>( CORE921x_FORMAT_ADCBIT_COMPARE( format_n, bit_n ) ) ) + +static const char CORE921x_VERSION[] = "core921x_v0.22"; + +/* rxgain+pdres ~ level */ +struct vc921x_core_res_table +{ + unsigned char level; + unsigned char pdres; + unsigned char rxgain; +}; +#if VC921x_CFG_DEFAULT_PPGGAIN_EN +#define MAX_RES_LEVEL 21 +#define MIN_RES_LEVEL 0 +#define MAX_CURRENT 0x7f +#define MIN_CURRENT 0 +const struct vc921x_core_res_table vc921x_res_table[] = + { + /* level, pdres, rxgain */ + {0, 0, 1}, /* 200K */ + {1, 1, 1}, + {2, 2, 1}, /* 400K */ + {3, 3, 1}, + {4, 4, 1}, /* 800K */ + {5, 5, 1}, + {6, 6, 1}, /* 1.6M */ + {7, 7, 1}, + {8, 8, 1},/* 3.2M */ + {9, 9, 1}, + {10, 10, 1}, /* 6.4M */ + {11, 11, 1}, /*8.96M*/ + {12, 12, 1}, + {13, 13, 1}, /*17.92*/ + {14, 12, 2}, + {15, 13, 2},/*35.84*/ + {16, 12, 3}, + {17, 13, 3},/*71.68*/ + {18, 12, 4}, + {19, 13, 4}, /* 143.36 */ + {20, 12, 5}, + {21, 13, 5}, /* 286.72 */ +}; +#else +#define MAX_RES_LEVEL 23 +#define MIN_RES_LEVEL 0 +#define MAX_CURRENT 0x7f +#define MIN_CURRENT 0 +const struct vc921x_core_res_table vc921x_res_table[] = + { + /* level, pdres, rxgain */ + {0, 0, 0}, /* 100K */ + {1, 1, 0}, + {2, 2, 0}, /* 200K */ + {3, 3, 0}, + {4, 4, 0}, /* 400K */ + {5, 5, 0}, + {6, 6, 0}, /* 800K */ + {7, 7, 0}, + {8, 8, 0}, /* 1.6M */ + {9, 9, 0}, + {10, 10, 0},/* 3.2M */ + {11, 11, 0}, + {12, 12, 0}, /* 6.4M */ + {13, 13, 0}, /*8.96M*/ + {14, 12, 1}, + {15, 13, 1}, /*17.92*/ + {16, 12, 2}, + {17, 13, 2},/*35.84*/ + {18, 12, 3}, + {19, 13, 3},/*71.68*/ + {20, 12, 4}, + {21, 13, 4}, /* 143.36 */ + {22, 12, 5}, + {23, 13, 5}, /* 286.72 */ +}; +#endif + +static unsigned char core921x_nto_version=0; /* 0127nto or(0808-1120mpw) */ +static unsigned char core921x_0808mpw=0; /* 0808mpw ~ 1120mpw */ +/* 需要在刚刚初始化完成之后去调用判断 */ +CORE921x_FUNC_RAM_SECTION int core921x_check_nto_version_init(void) +{ + unsigned char mpw0808_test=0xA0; + unsigned char read_buffer[4]={0}; + unsigned short count1=0, count2=0; + unsigned int delay_tick=1000; + vc921x_write_register(0x5C, &mpw0808_test, 1); + mpw0808_test=0; + vc921x_read_register(0x5C, &mpw0808_test, 1); + if( mpw0808_test==0xA0 ) + { + core921x_0808mpw=0; + mpw0808_test=0; + vc921x_write_register(0x5C, &mpw0808_test, 1); /* write 0, clear DEBUG register. */ + } + else + { + core921x_0808mpw=1; + } + /* 0127nto ~ 0808_1120mpw */ + vc921x_read_register( 0x05, &read_buffer[0], 2 ); + while(delay_tick--); + vc921x_read_register( 0x07, &read_buffer[2], 2 ); + count1 = (read_buffer[0]<<8)+read_buffer[1]; + count2 = (read_buffer[2]<<8)+read_buffer[3]; + if( count2-count1>=1 && count2-count1<=255 ) + { + core921x_nto_version=0; + } + else + { + core921x_nto_version=1; + } + CORE921x_DEBUG_LOG("0127nto=%d~0808mpw=%d", core921x_nto_version,core921x_0808mpw); + return core921x_nto_version; +} + +CORE921x_FUNC_RAM_SECTION static unsigned char get_level_by_res_rxgain(unsigned char pdres, unsigned char rxgain) +{ + unsigned char index = 0; + for (index = 0; index < sizeof(vc921x_res_table) / sizeof(vc921x_res_table[0]); index++) + { + if ((vc921x_res_table[index].pdres == pdres) && (vc921x_res_table[index].rxgain == rxgain)) + { + return vc921x_res_table[index].level; + } + } + return 0; +} +CORE921x_FUNC_RAM_SECTION static int get_res_rxgain_by_level(unsigned char level, unsigned char *ppdres, unsigned char *prxgain) +{ + *ppdres = vc921x_res_table[level].pdres; + *prxgain = vc921x_res_table[level].rxgain; + return 0; +} + +/**************************************************************** + * CORE_API.read() + * read IC event or sample data + ***************************************************************/ +CORE921x_FUNC_RAM_SECTION int __core921x_read_software_version(char **ppver) // +{ + if (ppver) + { + *ppver = (char *)CORE921x_VERSION; + return 0; + } + return -1; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_read_id(unsigned char *pid1, unsigned char *pid2) // +{ + int ret = 0; + if ((NULL == pid1) || (NULL == pid2)) + { + return 1; + } + ret = vc921x_read_register(CORE921x_DEV_VER_ID_H_ADDR, pid1, 1); + ret = vc921x_read_register(CORE921x_FDY_EXT_ID_L_ADDR, pid2, 1); + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_read_event_status(unsigned char *pevt, unsigned char *povsta, unsigned char *pwindex_bak, unsigned char *pwindex_rel ) // +{ + int ret = 0; + unsigned char reg[4] = {0}; + ret = vc921x_read_register(CORE921x_WORK_STATUS1_ADDR, reg, 4); + if (pevt) + { + *pevt = reg[0]; + } + if (povsta) + { + *povsta = reg[1]; + } + if( core921x_nto_version ) + { + if (pwindex_bak) + { + *pwindex_bak = reg[2]; + } + if (pwindex_rel) + { + *pwindex_rel = reg[3]; + } + } + else + { + if (pwindex_bak) + { + *pwindex_bak = reg[2]; + } + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_read_rcosc_tick(unsigned short int *ptick0, unsigned short int *ptick1) // +{ + int ret = 0; + unsigned char reg[4] = {0}; + if( core921x_nto_version==1 ) + { + ret = vc921x_read_register(CORE921x_OSC_CNT0_H_ADDR+1, reg, 4); + } + else + { + ret = vc921x_read_register(CORE921x_OSC_CNT0_H_ADDR, reg, 4); + } + if (ptick0) + { + *ptick0 = (reg[0] << 8) + reg[1]; + } + if (ptick1) + { + *ptick1 = (reg[2] << 8) + reg[3]; + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_read_output(vc921x_sample_info_t *psample_ret) +{ + int ret = 0; + core921x_reg_result_t reg_result = {0}; + if( core921x_nto_version==1 ) + { + ret = vc921x_read_register(CORE921x_SAMPLE_DATA_ADDR_BASE+1, (unsigned char *)®_result, sizeof(core921x_reg_result_t)); + } + else + { + ret = vc921x_read_register(CORE921x_SAMPLE_DATA_ADDR_BASE, (unsigned char *)®_result, sizeof(core921x_reg_result_t)); + } + + if (psample_ret) + { + psample_ret->slot_result[0].env_data = (reg_result.slot0_envh6 << 8) | reg_result.slot0_envl6; + psample_ret->slot_result[1].env_data = (reg_result.slot1_envh6 << 8) | reg_result.slot1_envl6; + psample_ret->slot_result[2].env_data = (reg_result.slot2_envh6 << 8) | reg_result.slot2_envl6; + + psample_ret->slot_result[0].u.ps_data = reg_result.slot0_ps; + psample_ret->slot_result[1].u.ps_data = reg_result.slot1_ps; + psample_ret->slot_result[2].u.ps_data = reg_result.slot2_ps; + + psample_ret->extra_result.bioinn_data = (reg_result.bioinn_valh << 8) | reg_result.bioinn_vall; + psample_ret->extra_result.bioext_data = (reg_result.bioext_valh << 8) | reg_result.bioext_vall; + psample_ret->extra_result.temp0_data = (reg_result.tempslot0_valh << 8) | reg_result.tempslot0_vall; + psample_ret->extra_result.temp1_data = (reg_result.tempslot1_valh << 8) | reg_result.tempslot1_vall; + psample_ret->extra_result.tempref_data = (reg_result.tempref_valh << 8) | reg_result.tempref_vall; + } + return ret; +} + +/*------------------------------------------------------------------------------------------------------------------------------------- +fifo 解析数据相关的函数功能模块 +-------------------------------------------------------------------------------------------------------------------------------------*/ +CORE921x_FUNC_RAM_SECTION static inline int fifo_calc_sample_slot_nums(vc921x_sample_info_t *psample_ret, unsigned char *p_ppgfreq_slotnum, unsigned char *p_psfreq_slotnum, unsigned char *p_bioppgfreq_slotnum) +{ + /* 1 ppg slot infomation */ + for( unsigned char i=0; i<3; i++ ) + { + if( psample_ret->slot_result[i].slot_enwork==1 && psample_ret->slot_result[i].slot_freq_sel==VC921x_FREQ_PPG ) + { + (*p_ppgfreq_slotnum)++; + } + else if( psample_ret->slot_result[i].slot_enwork==2 && psample_ret->slot_result[i].slot_freq_sel==VC921x_FREQ_PS && psample_ret->slot_result[i].slot_storefifo==VC921x_IN_STORE ) + { + (*p_psfreq_slotnum)++; + } + } + + /* 3 bio slot infomation */ + if ((psample_ret->extra_result.bioext_enwork==1||psample_ret->extra_result.bioinn_enwork==1)&&(psample_ret->extra_result.biofifo_mode==VC921x_BIO_INFIFO_PS_SGL||psample_ret->extra_result.biofifo_mode==VC921x_BIO_INFIFO_PPG_SUM)) + { + if (psample_ret->extra_result.bioext_enwork == 1) + { + (*p_psfreq_slotnum)++; + } + if (psample_ret->extra_result.bioinn_enwork == 1) + { + (*p_psfreq_slotnum)++; + } + } + else if ((psample_ret->extra_result.bioext_enwork==1||psample_ret->extra_result.bioinn_enwork==1)&&(psample_ret->extra_result.biofifo_mode==VC921x_BIO_INFIFO_PPG_SGL)) + { + if (psample_ret->extra_result.bioext_enwork == 1) + { + (*p_bioppgfreq_slotnum)++; + } + if (psample_ret->extra_result.bioinn_enwork == 1) + { + (*p_bioppgfreq_slotnum)++; + } + } + CORE921x_DEBUG_LOG("slotnum_ppgfreq[%d],slotnum_psfreq[%d], slotnum_bioppg[%d]", *p_ppgfreq_slotnum, *p_psfreq_slotnum, *p_bioppgfreq_slotnum); + return 0; +} + +CORE921x_FUNC_RAM_SECTION static inline int read_data_from_fifo_buffer(const unsigned char *pbuffer, unsigned char *poffset, unsigned char fifo_format_is24bit, unsigned char adc_resolution ) +{ + int data = 0; + if( fifo_format_is24bit ) + { + if( (*poffset)+2 >=192 ) return 0; + data = (pbuffer[(*poffset)]<<16) + (pbuffer[(*poffset)+1]<<8) + pbuffer[(*poffset)+2]; + data = CORE921x_DATA_FORMAT_COVNVERT( 24, adc_resolution, data ); + *poffset += 3; + } + else + { + if( (*poffset)+1 >=192 ) return 0; + data = (pbuffer[(*poffset)] << 8) + pbuffer[(*poffset) + 1]; + data = CORE921x_DATA_FORMAT_COVNVERT( 16, adc_resolution, data ); + *poffset += 2; + } + return data; +} + +CORE921x_FUNC_RAM_SECTION static inline int write_data_to_fifo_buffer( unsigned char *pbuffer, unsigned char offset, unsigned int ppg_data, unsigned char fifo_format_is24bit ) +{ + if( fifo_format_is24bit ) + { + if( offset*3+2>=VC921x_PPGSLOT_BUFFER_NUM*3 ) return -1; + pbuffer[offset*3+0]=(ppg_data>>16)&0xff; + pbuffer[offset*3+1]=(ppg_data>>8) &0xff; + pbuffer[offset*3+2]=(ppg_data>>0) &0xff; + } + else + { + if( offset*2+1>=VC921x_PPGSLOT_BUFFER_NUM*3 ) return -1; + pbuffer[offset*2+0]=(ppg_data>>8) &0xff; + pbuffer[offset*2+1]=(ppg_data>>0) &0xff; + } + return 0; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_read_fifo_data(vc921x_sample_info_t *psample_ret, unsigned char *pread_fifoaddr, unsigned char read_windex) // +{ + int ret = 0; + unsigned char i = 0, j = 0; + unsigned char rindex = *pread_fifoaddr; + unsigned char read_size = 0, wait_size = 0;; + unsigned char fifo_data[192] = {0}; + /* fifo有效通道数量 */ + unsigned char ppg_freq_slot_num = 0; /* ppg频率下ppg_slot的数量*/ + unsigned char ps_freq_slot_num = 0; /* ps频率下psbio_slot的数量*/ + unsigned char bio_ppgfreq_slot_num = 0; /* ppg频率下bio_slot的数量 */ + unsigned char ppg_ps_fifo_ratio = 0; /* ppg频率与ps频率的占比,用于计算有效ps频率的fifo数据位置 */ + + unsigned char fifo_bytes= 0; /* fifo_bytes= group_len*fifo_div */ + unsigned char group_len = 0; /* ppg0(slot1,2) ppg1(slot1,2) ps(1,2) */ + unsigned char group_num = 0; /* group_len * group_num = fifosize */ + /* array(ppg_freq+ps_freq) */ + unsigned char ppg_freq_array_len = 0; + unsigned char ps_freq_array_len = 0; + unsigned char array_offset = 0; /* group 组内偏移 */ + unsigned char slot_index = 0; + /* 当bio模式为VC921x_BIO_INFIFO_PPG_SGL,需要驱动进行加算 */ + unsigned short int bioext_ppgsgl_sum=0,bioinn_ppgsgl_sum=0; + /* 解析临时缓存ppg数据 */ + unsigned int analysis_ppg_data=0; + /************* 1.获取配置参数 *************/ + if (!psample_ret) + return 1; + ppg_ps_fifo_ratio = psample_ret->ps_div; /* 假设25/10=2.5hz,ppg频率中间隔10个,插入一个ps */ + fifo_calc_sample_slot_nums(psample_ret, &ppg_freq_slot_num, &ps_freq_slot_num, &bio_ppgfreq_slot_num); /* 获取各个fifo信息 */ + /* calc ppgfreq_fifodata/psfreq_fifodata array length, group length=ppg*ratio+ps */ + if( 1==psample_ret->fifo_format ) + { + ppg_freq_array_len += (ppg_freq_slot_num*3); + } + else + { + ppg_freq_array_len += (ppg_freq_slot_num*2); + } + ppg_freq_array_len+= (bio_ppgfreq_slot_num*2); + ps_freq_array_len += (ps_freq_slot_num * 2); + group_len = ppg_freq_array_len * ppg_ps_fifo_ratio + ps_freq_array_len; + fifo_bytes= group_len*psample_ret->fifo_div; + CORE921x_DEBUG_LOG("group_len(%d)=(%d*%d)+%d", group_len, ppg_freq_array_len, ppg_ps_fifo_ratio, ps_freq_array_len); + if(group_len==0||fifo_bytes==0) + { + return -1; + } + /************** 2.校验参数读取 *************/ + /* group=[ ppg0(slot0,slot1)+ppg1(slot0,slot1)+...ppgN(slot0,slot1)+ps(ps,bioinn,bioext) ] + fifo =[ group0,group1... ]n */ + if (0 == psample_ret->fifo_enable) + { + CORE921x_DEBUG_LOG("psample_ret->fifo_enable=%d", psample_ret->fifo_enable); + rindex = 0x00; /*disable fifo:fifo=ps频率,数据始于,0x00 */ + } + if (read_windex == rindex) /* 数据溢出或则无数据 */ + { + return -2; + } + if (read_windex > rindex) /* rindex-windex */ + { + wait_size = (read_windex - rindex); + } + else /* [rindex-192]+[0-windex] */ + { + wait_size = 192 - rindex + read_windex; + } + if( wait_size < fifo_bytes ) + { + CORE921x_DEBUG_ERR("[%x~%x]waite_size=%d, fifo_bytes=%d", rindex, read_windex, wait_size, fifo_bytes ); + return -3; + } + /* windex error process, the windex cover all fifo area and more than the rindex. */ + if (wait_size % fifo_bytes) + { + read_size = (wait_size/fifo_bytes)*fifo_bytes; + CORE921x_DEBUG_ERR("read_fifo_bytes(%d)/group_len(%d) != 0 read_size[%d]", wait_size, fifo_bytes, read_size ); + ret=1; + if( core921x_nto_version ) + { + return ret; + } + } + else + { + read_size=wait_size; + } + *pread_fifoaddr = ((rindex + read_size) >= 192) ? (rindex + read_size - 192) : (rindex + read_size); + ret = vc921x_write_register(CORE921x_FIFO_READADDR_INDEX, &rindex, 1); + ret = vc921x_read_register(CORE921x_FIFO_DATA_ADDR, &fifo_data[0], read_size); + + CORE921x_DEBUG_LOG("[%#x]-[%#x],fifo_bytes=%d,", rindex, read_windex, read_size); + CORE921x_DEBUG_LOG("PPG_data[0- 8]:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x", fifo_data[0], fifo_data[1], fifo_data[2], fifo_data[3], fifo_data[4], fifo_data[5], fifo_data[6], fifo_data[7]); + CORE921x_DEBUG_LOG("PPG_data[9-16]:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x", fifo_data[8], fifo_data[9], fifo_data[10], fifo_data[11], fifo_data[12], fifo_data[13], fifo_data[14], fifo_data[15]); + CORE921x_DEBUG_LOG("..............:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x", fifo_data[read_size - 8], fifo_data[read_size - 7], fifo_data[read_size - 6], fifo_data[read_size - 5], fifo_data[read_size - 4], fifo_data[read_size - 3], fifo_data[read_size - 2], fifo_data[read_size - 1]); + /******** 3.group,array,cell analysis ********/ + if(group_len==0) + { + return 3; + } + group_num = read_size / group_len; + for (i = 0; i < group_num; i++) /* i=0~N,每次所有通道的采样PPG群数,每个群的处理 */ + { + array_offset = i * group_len; + bioinn_ppgsgl_sum=0,bioext_ppgsgl_sum=0; + /* ppg_freq array analysis*/ + for (j = 0; j < ppg_ps_fifo_ratio; j++) /* j=0-n,每个群里面拥有的ppg_freq的组数轮询 */ + { + for (slot_index = 0; slot_index < 3; slot_index++) + { + if (1 == psample_ret->slot_result[slot_index].slot_enwork && VC921x_FREQ_PPG == psample_ret->slot_result[slot_index].slot_freq_sel) + { + psample_ret->slot_result[slot_index].ppg_num += 1; + analysis_ppg_data = read_data_from_fifo_buffer(fifo_data, &array_offset, psample_ret->fifo_format, psample_ret->adc_resolution ); + write_data_to_fifo_buffer( psample_ret->slot_result[slot_index].ppg_buffer, psample_ret->slot_result[slot_index].ppg_num-1, analysis_ppg_data, psample_ret->fifo_format ); + CORE921x_DEBUG_LOG("slot_result[%d].ppg_data[%d]=%d", slot_index, i*ppg_ps_fifo_ratio+j, analysis_ppg_data ); + } + } + if( bio_ppgfreq_slot_num && VC921x_BIO_INFIFO_PPG_SGL==psample_ret->extra_result.biofifo_mode ) /* VC921x_BIO_INFIFO_PPG_SGL */ + { + if (1 == psample_ret->extra_result.bioinn_enwork) bioinn_ppgsgl_sum+=read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + if (1 == psample_ret->extra_result.bioext_enwork) bioext_ppgsgl_sum+=read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + } + } + if( bio_ppgfreq_slot_num && VC921x_BIO_INFIFO_PPG_SGL==psample_ret->extra_result.biofifo_mode ) + { + psample_ret->extra_result.bio_fifo_num += 1; + if (1 == psample_ret->extra_result.bioinn_enwork) + { + psample_ret->extra_result.bioinn_buffer[i] = bioinn_ppgsgl_sum; + CORE921x_DEBUG_LOG("result.bioinn_buffer[%d]=%d", i, psample_ret->extra_result.bioinn_buffer[i]); + } + if (1 == psample_ret->extra_result.bioext_enwork) + { + psample_ret->extra_result.bioext_buffer[i] = bioext_ppgsgl_sum; + CORE921x_DEBUG_LOG("result.bioext_buffer[%d]=%d", i, psample_ret->extra_result.bioext_buffer[i]); + } + } + /* ps_freq array analysis */ + // CORE921x_DEBUG_LOG("PS_ARRAY_OFFSET=(%d)?(%d)", ppg_freq_array_len * ppg_ps_fifo_ratio, array_offset); + /* 数据交换处理 */ + if ( VC921x_BIO_INFIFO_PS_SGL==psample_ret->extra_result.biofifo_mode ) + { + if (2 == psample_ret->slot_result[2].slot_enwork && VC921x_IN_STORE == psample_ret->slot_result[2].slot_storefifo) + { + psample_ret->slot_result[2].ppg_num += 1; + analysis_ppg_data = read_data_from_fifo_buffer( fifo_data, &array_offset, 0, 16 ); + write_data_to_fifo_buffer( psample_ret->slot_result[2].ppg_buffer, psample_ret->slot_result[2].ppg_num-1, analysis_ppg_data, 0 ); + CORE921x_DEBUG_LOG("slot_result[2].ps_data[%d]=%d", i, analysis_ppg_data); + } + if ( 1 == psample_ret->extra_result.bioinn_enwork || 1 == psample_ret->extra_result.bioext_enwork) + { + psample_ret->extra_result.bio_fifo_num += 1; + if (1 == psample_ret->extra_result.bioinn_enwork) + { + psample_ret->extra_result.bioinn_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + CORE921x_DEBUG_LOG("result.bioinn_buffer[%d]=%d", i, psample_ret->extra_result.bioinn_buffer[i]); + } + if (1 == psample_ret->extra_result.bioext_enwork) + { + psample_ret->extra_result.bioext_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + CORE921x_DEBUG_LOG("result.bioext_buffer[%d]=%d", i, psample_ret->extra_result.bioext_buffer[i]); + } + } + } + else if(VC921x_BIO_INFIFO_PPG_SUM == psample_ret->extra_result.biofifo_mode) + { + if ( 1==psample_ret->extra_result.bioinn_enwork||1==psample_ret->extra_result.bioext_enwork ) + { + psample_ret->extra_result.bio_fifo_num += 1; + if (1 == psample_ret->extra_result.bioinn_enwork) + { + psample_ret->extra_result.bioinn_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + CORE921x_DEBUG_LOG("result.bioinn_buffer[%d]=%d", i, psample_ret->extra_result.bioinn_buffer[i]); + } + if (1 == psample_ret->extra_result.bioext_enwork) + { + psample_ret->extra_result.bioext_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + CORE921x_DEBUG_LOG("result.bioext_buffer[%d]=%d", i, psample_ret->extra_result.bioext_buffer[i]); + } + } + if (2 == psample_ret->slot_result[2].slot_enwork && VC921x_IN_STORE == psample_ret->slot_result[2].slot_storefifo) + { + psample_ret->slot_result[2].ppg_num += 1; + analysis_ppg_data = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + write_data_to_fifo_buffer( psample_ret->slot_result[2].ppg_buffer, psample_ret->slot_result[2].ppg_num-1, analysis_ppg_data, 0 ); + CORE921x_DEBUG_LOG("slot_result[2].ps_data[%d]=%d", i, analysis_ppg_data); + } + } + else /* VC921x_BIO_NOFIFO_PS_SGL VC921x_BIO_INFIFO_PPG_SGL */ + { + if (2 == psample_ret->slot_result[2].slot_enwork && VC921x_IN_STORE == psample_ret->slot_result[2].slot_storefifo) + { + psample_ret->slot_result[2].ppg_num += 1; + analysis_ppg_data = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 ); + write_data_to_fifo_buffer( psample_ret->slot_result[2].ppg_buffer, psample_ret->slot_result[2].ppg_num-1, analysis_ppg_data, 0 ); + CORE921x_DEBUG_LOG("slot_result[2].ps_data[%d]=%d", i, analysis_ppg_data); + } + } + } /* end of for(i 7) ? 7 : oversample; + slotcfg.slot_cfg1.bits.txch = txchsel; + slotcfg.slot_cfg2.bits.storefifo = slot_infifo; + + switch (sample_tim) + { + case VC921x_SAMPLE_TIM_50US: + slotcfg.slot_cfg1.bits.env_time = 2; + slotcfg.slot_cfg1.bits.sample_time = 0; + slotcfg.slot_cfg3.bits.sc = 3; /* env_time_config+1 */ + break; + case VC921x_SAMPLE_TIM_100US: + slotcfg.slot_cfg1.bits.env_time = 5; + slotcfg.slot_cfg1.bits.sample_time = 1; + slotcfg.slot_cfg3.bits.sc = 6; + break; + case VC921x_SAMPLE_TIM_150US: + slotcfg.slot_cfg1.bits.env_time = 8; + slotcfg.slot_cfg1.bits.sample_time = 2; + slotcfg.slot_cfg3.bits.sc = 9; + break; + case VC921x_SAMPLE_TIM_200US: + slotcfg.slot_cfg1.bits.env_time = 11; + slotcfg.slot_cfg1.bits.sample_time = 3; + slotcfg.slot_cfg3.bits.sc = 12; + break; + default: + slotcfg.slot_cfg1.bits.env_time = 5; + slotcfg.slot_cfg1.bits.sample_time = 1; + slotcfg.slot_cfg3.bits.sc = 6; + break; + } + ret = vc921x_write_register(slot_base_addr, (unsigned char *)&slotcfg, sizeof(core921x_slot_config_t)); + return ret; +} + +/* PPG通道及调整的函数接口 */ +CORE921x_FUNC_RAM_SECTION int __core921x_read_slot_adjust_param(unsigned char *pmax_res, unsigned char *pmin_res, unsigned char *pmax_curr, unsigned char *pmin_curr) +{ + *pmax_res = MAX_RES_LEVEL; + *pmin_res = MIN_RES_LEVEL; + *pmax_curr = MAX_CURRENT; + *pmin_curr = MIN_CURRENT; + return 0; +} + +/* 电流+电阻等级的读写,这部分是在使用过程中会反复调用的 */ +CORE921x_FUNC_RAM_SECTION int __core921x_read_slot_current_res(VC921x_PPG_SLOT_I slot_index, unsigned char *pslot_curr, unsigned char *pslot_reslvl) +{ + int ret = 0; + core921x_slot_config_t slotcfg = {0}; + /* read current */ + unsigned char cfg2_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 2; + ret = vc921x_read_register(cfg2_addr, (unsigned char *)&slotcfg.slot_cfg2, 1); + if (pslot_curr) + { + *pslot_curr = slotcfg.slot_cfg2.bits.current; + } + /* read reslvl */ + unsigned char cfg0_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4); + unsigned char cfg3_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 3; + vc921x_read_register(cfg0_addr, (unsigned char *)&slotcfg.slot_cfg0, 1); + vc921x_read_register(cfg3_addr, (unsigned char *)&slotcfg.slot_cfg3, 1); + if (pslot_reslvl) + { + //*pslot_reslvl = slotcfg.slot_cfg3.bits.resistance; + *pslot_reslvl = get_level_by_res_rxgain(slotcfg.slot_cfg3.bits.resistance, slotcfg.slot_cfg0.bits.rxgain); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_ppgslot_current(VC921x_PPG_SLOT_I slot_index, unsigned char current) +{ + int ret = 0; + core921x_slot_cfg2bit slotcfg2 = {0}; + unsigned char cfg2_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 2; + ret = vc921x_read_register(cfg2_addr, (unsigned char *)&slotcfg2, 1); + slotcfg2.current = (current >= MAX_CURRENT) ? MAX_CURRENT : current; + ret = vc921x_write_register(cfg2_addr, (unsigned char *)&slotcfg2, 1); + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_ppgslot_resistance(VC921x_PPG_SLOT_I slot_index, unsigned char res_level, unsigned char allow_oversample ) +{ + int ret = 0; + unsigned char res = 0, rxgain = 0; + core921x_slot_ppg_cfg0bit slotcfg0 = {0}; + core921x_slot_cfg3bit slotcfg3 = {0}; + unsigned char cfg0_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4); + unsigned char cfg3_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 3; + ret = vc921x_read_register(cfg0_addr, (unsigned char *)&slotcfg0, 1); + ret = vc921x_read_register(cfg3_addr, (unsigned char *)&slotcfg3, 1); + res_level = (res_level >= MAX_RES_LEVEL) ? MAX_RES_LEVEL : res_level; + get_res_rxgain_by_level(res_level, &res, &rxgain); + slotcfg3.resistance = res; + slotcfg0.rxgain=rxgain; +#if 1 + if (slot_index <= 1 && allow_oversample) + { + slotcfg0.oversample = 1 * rxgain; + } +#endif + ret = vc921x_write_register(cfg0_addr, (unsigned char *)&slotcfg0, 1); + ret = vc921x_write_register(cfg3_addr, (unsigned char *)&slotcfg3, 1); + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_slotx_pd_config( VC921x_SLOT_CHSEL slot0_pd, VC921x_SLOT_CHSEL slot1_pd, VC921x_SLOT_CHSEL slot2_pd ) +{ + int ret = 0; + core921x_pd_cfgbit pd_config = {0}; + pd_config.slot0_pdch = slot0_pd; + pd_config.slot1_pdch = slot1_pd; + pd_config.slot2_pdch = slot2_pd; + ret = vc921x_write_register(0x4C, (unsigned char *)&pd_config, sizeof(pd_config)); + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_anti_slot_config( unsigned char anti_current, VC921x_CFG_FUNC deslot0, VC921x_CFG_FUNC deslot1, VC921x_CFG_FUNC deslot2, VC921x_PPG_TXCH_I antich ) +{ + int ret = 0; + core921x_anti_cfgbit anti_config = {0}; + core921x_anti_cfgbit_1120mpw anti_config_1120mpw={0}; + if( core921x_nto_version ) + { + anti_config.anti_current = anti_current>=7?7:anti_current; + anti_config.deslot0 = deslot0; + anti_config.deslot1 = deslot1; + anti_config.deslot2 = deslot2; + anti_config.antiTxch=antich; + ret = vc921x_write_register(0x4D, (unsigned char *)&anti_config, sizeof(core921x_anti_cfgbit)); + } + else + { + if( core921x_0808mpw ) return ret; + anti_config_1120mpw.anti_current = anti_current>=7?7:anti_current; + anti_config_1120mpw.deslot0 = deslot0; + anti_config_1120mpw.deslot1 = deslot1; + anti_config_1120mpw.deslot2 = deslot2; + ret = vc921x_write_register(0x4D, (unsigned char *)&anti_config_1120mpw, sizeof(core921x_anti_cfgbit_1120mpw)); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_common_config(VC921x_CFG_FUNC deenv_en, VC921x_CFG_FUNC i2crelease_en, VC921x_CFG_FUNC bio_disfreqHop, VC921x_CFG_FUNC fifo_format, VC921x_CFG_FUNC fifo_en, unsigned char cpd) +{ + int ret = 0; + core921x_com_cfgbit com_config = {0}; + com_config.deenv_en = deenv_en; + com_config.i2crelease_en = i2crelease_en; + com_config.bio_disfreqHop = bio_disfreqHop; + com_config.fifoformat = fifo_format; + com_config.fifo_en = fifo_en; + com_config.cpd = cpd; + if( core921x_0808mpw ) + { + com_config.bio_disfreqHop = 0; /* deFlick */ + ret = vc921x_write_register(0x4D, (unsigned char *)&com_config, sizeof(com_config)); + } + else + { + ret = vc921x_write_register(0x4E, (unsigned char *)&com_config, sizeof(com_config)); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_sample_frequency(unsigned short int div1, unsigned char div2, unsigned char div3) +{ + int ret = 0; + unsigned char freq_config[4] = {0}; + freq_config[0] = (div1 >> 8); + freq_config[1] = (div1 & 0xFF); + freq_config[2] = div2; + freq_config[3] = div3; + if( core921x_0808mpw ) + { + ret = vc921x_write_register(0x4E, freq_config, sizeof(freq_config)); + } + else + { + ret = vc921x_write_register(0x4F, freq_config, sizeof(freq_config)); + } + return ret; +} + +/**************************************************************** + * CORE_API.write()/set() + * txchx_comconfig & ppg threshold configuration + * write or set config registers + ***************************************************************/ +CORE921x_FUNC_RAM_SECTION int __core921x_set_threshold_config(unsigned char ppgth_h, unsigned char ppgth_l) +{ + int ret = 0; + core921x_ppgth_cfgbit ppgth_config = {0}; + ppgth_config.ppgthh = (ppgth_h >= 0xf) ? 0xf : ppgth_h; + ppgth_config.ppgthl = (ppgth_l >= 0xf) ? 0xf : ppgth_l; + if( core921x_0808mpw ) + { + ret = vc921x_write_register(0x52, (unsigned char *)&ppgth_config, 1); + } + else + { + ret = vc921x_write_register(0x53, (unsigned char *)&ppgth_config, 1); + } + return ret; +} +/**************************************************************** + * CORE_API.write()/set() + * extra(ADC,BIO,temperature,AT/DT) configuration + * write or set config registers + ***************************************************************/ +CORE921x_FUNC_RAM_SECTION int __core921x_set_interrupt_config(VC921x_IO_MODE int_mode, VC921x_IO_DIR int_dir, VC921x_IO_PULSE_TIM int_len, unsigned char evt_en) +{ + int ret = 0; + core921x_int_cfgbit int_config = {0}; + int_config.intmode = (unsigned char)int_mode; + int_config.intdir = (unsigned char)int_dir; + int_config.intlen = (unsigned char)int_len; + if (evt_en & VC921x_EN_EVT_FREQ2) + { + int_config.intfreq2_en = 1; + } + if (evt_en & VC921x_EN_EVT_FIFO) + { + int_config.intfifo_en = 1; + } + if (evt_en & VC921x_EN_EVT_OVLD) + { + int_config.intov_en = 1; + } + if (evt_en & VC921x_EN_EVT_PPG) + { + int_config.intppg_en = 1; + } + if( core921x_0808mpw ) + { + ret = vc921x_write_register(0x53, (unsigned char *)&int_config, sizeof(int_config)); + } + else + { + ret = vc921x_write_register(0x54, (unsigned char *)&int_config, sizeof(int_config)); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_bioslot_config(VC921x_CFG_FUNC bioinn_en, VC921x_CFG_FUNC bioext_en, VC921x_BIO_MODE biofifo_mode, VC921x_BIO_CHSEL bio_chsel, unsigned char biofreq, unsigned char biocap, unsigned char biotime) +{ + int ret = 0; + core921x_bio_cfg0bit bio_config0 = {0}; + core921x_bio_cfg1bit bio_config1 = {0}; + bio_config0.bio_inn_en = bioinn_en; + bio_config0.bio_ext_en = bioext_en; + bio_config0.bio_mode = biofifo_mode; + bio_config0.bio_pdch = bio_chsel; + bio_config0.bio_freq = (biofreq > 3) ? 3 : biofreq; + + bio_config1.bio_capadd = (biocap > 0x1f) ? (0x1f) : biocap; + bio_config1.bio_time = (biotime > 0x7) ? (0xf) : biotime; + if( core921x_0808mpw ) + { + ret = vc921x_write_register(0x54, (unsigned char *)&bio_config0, 1); + ret = vc921x_write_register(0x55, (unsigned char *)&bio_config1, 1); + } + else + { + ret = vc921x_write_register(0x55, (unsigned char *)&bio_config0, 1); + ret = vc921x_write_register(0x56, (unsigned char *)&bio_config1, 1); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_bioinn_addcap(unsigned char biocap) +{ + int ret = 0; + core921x_bio_cfg1bit bio_config1 = {0}; + if( core921x_0808mpw ) + { + vc921x_read_register(0x55, (unsigned char *)&bio_config1, 1); + bio_config1.bio_capadd = (biocap > 0x1f) ? (0x1f) : biocap; + ret = vc921x_write_register(0x55, (unsigned char *)&bio_config1, 1); + } + else + { + vc921x_read_register(0x56, (unsigned char *)&bio_config1, 1); + bio_config1.bio_capadd = (biocap > 0x1f) ? (0x1f) : biocap; + ret = vc921x_write_register(0x56, (unsigned char *)&bio_config1, 1); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_temperature_config(VC921x_CFG_FUNC tempslot0_en, VC921x_TEMP_SLOT tempslot0_chsel, unsigned char tempslot0_current, +VC921x_CFG_FUNC tempslot1_en, VC921x_TEMP_SLOT tempslot1_chsel, unsigned char tempslot1_current ) +{ + int ret = 0; + core921x_temp_cfgbit temp_config[2] = {0}; + temp_config[0].temp_enable = tempslot0_en; + temp_config[0].temp_slotch = tempslot0_chsel; + temp_config[0].temp_currset = (tempslot0_current >= 7) ? 7 : tempslot0_current; + temp_config[1].temp_enable = tempslot1_en; + temp_config[1].temp_slotch = tempslot1_chsel; + temp_config[1].temp_currset = (tempslot1_current >= 7) ? 7 : tempslot1_current; + if(core921x_0808mpw) + { + ret = vc921x_write_register(0x56, (unsigned char *)&temp_config, sizeof(temp_config)); + } + else + { + ret = vc921x_write_register(0x57, (unsigned char *)&temp_config, sizeof(temp_config)); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_adc_config( VC921x_ADC_RESOLUTION adc_resulution, VC921x_CFG_FUNC ovdata_sum_enable ) +{ + int ret=0; + core921x_adc_config_t adc_config={0}; + core921x_adc_config_t_1120mpw adc_config_1120mpw={0}; + if( core921x_nto_version ) + { + adc_config.ppg_resulution=adc_resulution; + adc_config.ovtype = ovdata_sum_enable; + adc_config.cmpset = 3; + adc_config.env_clkdiv=0; + adc_config.adc_speed=0; + ret = vc921x_write_register(0x59, (unsigned char *)&adc_config, sizeof(adc_config)); + } + else + { + adc_config_1120mpw.ppg_resulution=adc_resulution; + adc_config_1120mpw.ovtype = ovdata_sum_enable; + adc_config_1120mpw.reserved = 0; + adc_config_1120mpw.env_clkdiv=0; + adc_config_1120mpw.adc_speed=0; + if( core921x_0808mpw ) + { + ret = vc921x_write_register(0x58, (unsigned char *)&adc_config_1120mpw, sizeof(adc_config_1120mpw)); + } + else + { + ret = vc921x_write_register(0x59, (unsigned char *)&adc_config_1120mpw, sizeof(adc_config_1120mpw)); + } + } + //CORE921x_DEBUG_LOG("write register adc_resulution=[%d],ovdata_sum_enable=[%d]", adc_resulution, ovdata_sum_enable); + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_set_rcosc_frequency(unsigned char oscset) +{ + int ret = 0; + if( core921x_0808mpw ) + { + ret = vc921x_write_register(0x59, &oscset, 1); + } + else + { + ret = vc921x_write_register(0x5A, &oscset, 1); + } + return ret; +} + +CORE921x_FUNC_RAM_SECTION int __core921x_write_work_cmd(VC921x_WORK_CMD cmd) // +{ + int ret = 0; + unsigned char wcmd = 0; + switch (cmd) + { + case VC921x_STOP_WORK_CMD: + wcmd = 0x00; + break; + case VC921x_START_WORK_CMD: + wcmd = 0x5A; + break; + case VC921x_RESET_SOFT_CMD: + wcmd = 0xA5; + break; + default: + return 1; + } + ret = vc921x_write_register(CORE921x_WORK_CMD_ADDR_BASE, &wcmd, 1); + return ret; +} diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_driver.c b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_driver.c new file mode 100644 index 000000000..1f6b548fd --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_driver.c @@ -0,0 +1,1907 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-11-03 01:20:20 + * @LastEditTime: 2024-04-11 20:37:31 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +#include "vc921x_core_com.h" +#include "vc921x_driver_config.h" +#include "vc921x_driver.h" + +#if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE) +#include "BIODetect_V14_1.h" +#endif + +#ifndef VC_ABS_MAX +#define VC_ABS_MAX(a, b, max) (((a) > (b)) ? ((a) - (b)) : (max + (a) - (b))) +#endif +#ifndef VC_ABS +#define VC_ABS(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a))) +#endif + +#ifndef VC921x_ENV_CONVERT +#define VC921x_ENV_CONVERT( hex_env ) (((hex_env)>>8)*50+((hex_env)&0xff)) +#endif + +unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY=32000; /* extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; */ +unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD=100; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; */ +unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP=100; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; */ + +unsigned int vc921x_calc_ps_reflect_thh( unsigned char psI, unsigned char psR, unsigned char ps_adcbit ) +{ + unsigned int calc_psthh = 0; + float fix_I = vcare_I_exponent_func( 0.8f, VC921x_WEAR_PARAM_PS_CURRENT ); + float fix_R = vcare_R_exponent_func( 100.0f, VC921x_WEAR_PARAM_PS_RESISTANCE ); + float real_I= vcare_I_exponent_func( 0.8f, psI ); +#if VC921x_CFG_DEFAULT_PPGGAIN_EN + float real_R= vcare_R_exponent_func( 200.0f, psR ); /* !!notice:gain_min=1 */ +#else + float real_R= vcare_R_exponent_func( 100.0f, psR ); /* !!notice:gain_min=0 */ +#endif + unsigned int adc_gain=1<<(ps_adcbit-16); + float k = (real_I*real_R)/(fix_I*fix_R*(1<wear_drop_flag = 0; + if (drv_info_handle->fifo_read_data_valid) + { + /* ppg ps slot */ + for (i = 0; i < 3; i++) + { + presult_info->slot_result[i].ppg_num = 0; + vcare_memset(presult_info->slot_result[i].ppg_buffer, 0, sizeof(presult_info->slot_result[i].ppg_buffer)); + } + /* bioinn bioext */ + presult_info->extra_result.bio_fifo_num = 0; + vcare_memset(presult_info->extra_result.bioinn_buffer, 0, sizeof(presult_info->extra_result.bioinn_buffer)); + vcare_memset(presult_info->extra_result.bioext_buffer, 0, sizeof(presult_info->extra_result.bioext_buffer)); + } +} + +/******************************************************************************************************** + * 驱动参数保存部分 + ********************************************************************************************************/ +static int drv_infomation_param_save(void) +{ + int ret = 0; + unsigned char save_buf[12] = {0}; + save_buf[0] = 0xAA; + save_buf[1] = drv_info_handle->optimal_bio_valid = 1; + save_buf[2] = drv_info_handle->optimal_cap; + + save_buf[3] = (drv_info_handle->optimal_bio_gap >> 24) & 0xff; /* calibration deviation */ + save_buf[4] = (drv_info_handle->optimal_bio_gap >> 16) & 0xff; + save_buf[5] = (drv_info_handle->optimal_bio_gap >> 8) & 0xff; + save_buf[6] = (drv_info_handle->optimal_bio_gap >> 0) & 0xff; + save_buf[7] = (drv_info_handle->optimal_bio_temp >> 24) & 0xff; /* temperature deviation */ + save_buf[8] = (drv_info_handle->optimal_bio_temp >> 16) & 0xff; + save_buf[9] = (drv_info_handle->optimal_bio_temp >> 8) & 0xff; + save_buf[10] = (drv_info_handle->optimal_bio_temp >> 0) & 0xff; + ret = vc921x_param_write_flash(save_buf, sizeof(save_buf)); + VCARE_DBG_LOG("save bio param: %d,%d,%d,%d(temp)", drv_info_handle->optimal_bio_valid, drv_info_handle->optimal_cap, drv_info_handle->optimal_bio_gap, drv_info_handle->optimal_bio_temp); + return ret; /* successed return 0 */ +} +static int drv_infomation_param_load(void) +{ + int ret = 0; + unsigned char load_buf[12] = {0}; + ret = vc921x_param_read_flash(load_buf, sizeof(load_buf)); + if (load_buf[0] == 0xAA) + { + drv_info_handle->optimal_bio_valid = load_buf[1]; + drv_info_handle->optimal_cap = load_buf[2]; + drv_info_handle->optimal_bio_gap = (int)((load_buf[3] << 24) + (load_buf[4] << 16) + (load_buf[5] << 8) + (load_buf[6])); + drv_info_handle->optimal_bio_temp= (int)((load_buf[7] << 24) + (load_buf[8] << 16) + (load_buf[9] << 8) + (load_buf[10])); + } + else + { + drv_info_handle->optimal_bio_valid = 0; + drv_info_handle->optimal_cap = 0; + drv_info_handle->optimal_bio_gap = 0; + drv_info_handle->optimal_bio_temp=0; + ret=0; + } + VCARE_DBG_LOG("load bio param: %d,%d,%d,%d(temp)", drv_info_handle->optimal_bio_valid, drv_info_handle->optimal_cap, drv_info_handle->optimal_bio_gap, drv_info_handle->optimal_bio_temp); + return ret; /* successed return 0 */ +} +/* clear param,and */ +static int drv_infomation_param_reset(void) +{ + drv_info_handle->optimal_bio_valid = 0; + drv_info_handle->optimal_cap = 0; + drv_info_handle->optimal_bio_gap = 0; + drv_info_handle->optimal_bio_temp=0; + /* init [dichotomy]param */ + last_ext_bio=0; + remember_biomax_mark=0; + remember_biomin_mark=0; + remember_biomax_value = 0; + remember_biomin_value = 0; + /* 二分中值及采样标志 */ + last_inn_bio_mid=0; + set_flg_mid=0; + /* 二分初始数据 */ + set_cap_max=31; + set_cap_mid=16; + set_cap_min=1; + return 0; +} +/***************************************************************************** + * driver_work_mode table: + * {WORK_MODE, MODE_INIT_FUNC, MODE_HANDLER_FUNC } + *****************************************************************************/ +static const vc921x_mode_ops *sel_mode_ops = NULL; +static int drv_heartrate_mode_init(void); +static int drv_spo2_mode_init(void); +static int drv_bloodpressure_mode_init(void); +static int drv_wear_mode_init(void); +static int drv_temperature_mode_init(void); +static int drv_factory_green_ps_mode_init(void); +static int drv_factory_ir_red_mode_init(void); +static int drv_hrspo2_mode_init(void); +/*handler*/ +static int drv_ppg_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev); +static int drv_factory_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev); + +static const vc921x_mode_ops mode_ops[] = + { + /* work_mode, work_mode_init, work_mode_handler */ + {WORK_MODE_HR, drv_heartrate_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_SPO2, drv_spo2_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_HRV, drv_heartrate_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_STRESS, drv_heartrate_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_BLOODPRESSURE, drv_bloodpressure_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_WEAR, drv_wear_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_TEMPERATURE, drv_temperature_mode_init, drv_ppg_mode_handler}, + {WORK_MODE_FACTORY0, drv_factory_green_ps_mode_init, drv_factory_mode_handler}, + {WORK_MODE_FACTORY1, drv_factory_ir_red_mode_init, drv_factory_mode_handler}, + {WORK_MODE_HRSPO2, drv_hrspo2_mode_init, drv_ppg_mode_handler}, +}; + +/****************************************************************************** + * 初始化部分 + ******************************************************************************/ +static void drv_infomation_param_init(vcare_ppg_device_t *pdev) +{ + int i; + unsigned char max_cur = 0, min_cur = 0, max_res_lvl = 0, min_res_lvl = 0; + /* slot_adjust param */ + core921x_read_slot_adjust_param(&max_res_lvl, &min_res_lvl, &max_cur, &min_cur); + for (i = 0; i < 3; i++) + { + adjust_info_handle[i]->const_max_current = max_cur; + adjust_info_handle[i]->const_min_current = min_cur; + adjust_info_handle[i]->max_current = max_cur; + adjust_info_handle[i]->const_max_res_level = max_res_lvl; + adjust_info_handle[i]->const_min_res_level = min_res_lvl; + adjust_info_handle[i]->max_res_level = max_res_lvl; + adjust_info_handle[i]->adj_param.current_step = VC921x_ADJ_I_STEP_DFT; + adjust_info_handle[i]->adj_param.direction = VC921x_ADJUST_DIR_NONE; + adjust_info_handle[i]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE; + } + /* dev_wear param */ + drv_info_handle->optimal_bio_valid =1; /* 先置1,等待在factory模式下主动清除后进行配平 */ +#if (VC921x_WEAR_DFT_HOLD == VC921x_CFG_WEAR_DEFAULT_STA) + wear_info_handle->last_status = (WEAR_STA_NONE == wear_info_handle->last_status) ? WEAR_STA_HOLD : wear_info_handle->last_status; +#else + #if (VC921x_CFG_WEAR_BIO_OLD_EN!=VC921x_FUNC_ENABLE) + /* 注意:只能非边沿活体的条件下,第一次或者停止工作后,重置活体状态为DROP。边沿的方式调用stop因为机制问题,无论如何都不能完美处理stop之后的状态 */ + wear_info_handle->bio_wear_result = (WEAR_STA_NONE == wear_info_handle->last_status) ? VC921x_BIO_STA_DROP : wear_info_handle->bio_wear_result; + #endif + wear_info_handle->last_status = (WEAR_STA_NONE == wear_info_handle->last_status) ? WEAR_STA_DROP : wear_info_handle->last_status; +#endif +#if (VC921x_FUNC_ENABLE != VC921x_CFG_WEAR_DETECTION) + wear_info_handle->last_status = WEAR_STA_HOLD; +#endif + /* 切换模式如果为摘下时,需要关灯 */ + if (wear_info_handle->last_status == WEAR_STA_DROP && (drv_info_handle->work_mode != WORK_MODE_FACTORY0 && drv_info_handle->work_mode != WORK_MODE_FACTORY1)) + { + for (i = 0; i < 3; i++) + { + if (sample_info_handle->slot_result[i].slot_enwork == 1) + { + core921x_set_enable_config((VC921x_PPG_SLOT_I)i, VC921x_CFG_DISABLE); + sample_info_handle->slot_result[i].slot_enwork = 0; + } + if( drv_info_handle->ppg_convert_ps ) + { + drv_info_handle->ppg_convert_ps=0; + VC921x_PS_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[2] /*slot2_ps*/, VC921x_IN_STORE /*storefifo*/, VC921x_WEAR_PARAM_PS_CURRENT /*current*/, VC921x_WEAR_PARAM_PS_RESISTANCE /*resistance*/); + core921x_sample_slotx_config( VC921x_PPG_SLOT_2, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_WEAR_PARAM_PS_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + } + } + } + wear_info_handle->wear_status = wear_info_handle->last_status; + pdev->wear = wear_info_handle->last_status; + + wear_info_handle->drop_cnt = VC921x_CFG_WEAR_DROP_CNT; + wear_info_handle->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT; + wear_info_handle->acce_wear_status = WEAR_STA_HOLD; + wear_info_handle->algo_wear_status = WEAR_STA_HOLD; + /* dev_clk param */ + drv_calibration_clk_clear(); + /* read_fifo_address */ + drv_info_handle->read_fifo_address = 0; + if( drv_info_handle->work_mode==WORK_MODE_SPO2 || drv_info_handle->work_mode==WORK_MODE_HRSPO2 ) + { + drv_info_handle->ppg_max_thval = VC921x_PPG_SPO2_MAX_DEFT_THVAL; + drv_info_handle->ppg_min_thval = VC921x_PPG_SPO2_MIN_DEFT_THVAL; + } + else + { + drv_info_handle->ppg_max_thval = VC921x_PPG_MAX_DEFT_THVAL; + drv_info_handle->ppg_min_thval = VC921x_PPG_MIN_DEFT_THVAL; + } + if (wear_info_handle->bio_wear_result == VC921x_BIO_STA_NONE) + { +#if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE) + f_BIOInit( VC921x_WEAR_PARAM_BIO_DELTA, VC921x_WEAR_PARAM_PS_DELTA ); + VCARE_DBG_LOG("f_BIOedgeinit(%d, %d, %d)", VC921x_WEAR_PARAM_BIO_DELTA, VC921x_WEAR_PARAM_PS_DELTA ); +#endif + } +} + +static int drv_calc_bioinn_auto_addcap(unsigned char status, vc921x_sample_info_t *psample_info) +{ + unsigned char finished_set=0; + unsigned char finished_mark=0; + if (status & VC921x_EVENT_INTPS_RDY) + { + if (drv_info_handle->optimal_bio_valid) + { + return 0; + } + /* 判断是否bioext发生变化,如果变化太大,那么直接校准失败 */ + if( last_ext_bio!=0 && VC_ABS(last_ext_bio,psample_info->extra_result.bioext_data)>=20 ) + { + VCARE_DBG_ERR("calc bioinn error, bioext running..."); + } + last_ext_bio = psample_info->extra_result.bioext_data; + /* 二分法校准,循环赋值,设置参数与采样值呈负相关 */ + if( set_flg_mid==1 ) + { + set_flg_mid=0; + last_inn_bio_mid=psample_info->extra_result.bioinn_data; + } + if( last_inn_bio_mid==0 ) + { + core921x_set_bioinn_addcap(psample_info,set_cap_mid); + set_flg_mid=1; + return 0; + } + /* 在合理范围内快速退出 */ + if( (psample_info->extra_result.bioext_data-VC921x_CALC_BIOINN_OFFSET)<=last_inn_bio_mid && (psample_info->extra_result.bioext_data+VC921x_CALC_BIOINN_OFFSET)>=last_inn_bio_mid ) + { + finished_set=set_cap_mid; + finished_mark=1; + VCARE_DBG_LOG("(+-100)now set cap[%d,%d,%d],now_bio_val[%d](%d) ->set[%d]", set_cap_min,set_cap_mid, set_cap_max, + last_inn_bio_mid, psample_info->extra_result.bioext_data, last_inn_bio_mid ); + } + else /* 不在范围,范围比较大,继续二分 */ + { + /* 检索完成,需要再min和max中取一个值 */ + if( (set_cap_max-set_cap_min)<=1 ) + { + if(remember_biomax_mark==1) + { + remember_biomax_mark=0; + remember_biomax_value = psample_info->extra_result.bioinn_data; + } + if( remember_biomin_mark==1 ) + { + remember_biomin_mark=0; + remember_biomin_value = psample_info->extra_result.bioinn_data; + } + if( remember_biomax_value==0 ) + { + remember_biomax_mark=1; + core921x_set_bioinn_addcap(psample_info,set_cap_max); + return 0; + } + if( remember_biomin_value==0 ) + { + remember_biomin_mark=1; + core921x_set_bioinn_addcap(psample_info,set_cap_min); + return 0; + } + if( VC_ABS(remember_biomin_value,psample_info->extra_result.bioext_data) <= VC_ABS(remember_biomax_value,psample_info->extra_result.bioext_data) ) + { + finished_set=set_cap_min;/* 取min,结束 */ + last_inn_bio_mid = remember_biomin_value; + } + else + { + finished_set=set_cap_max;/* 取max,结束 */ + last_inn_bio_mid = remember_biomax_value; + } + finished_mark=1; + VCARE_DBG_LOG("mingap(%d)[%d],maxgap(%d)[%d]->(%d)",set_cap_min,VC_ABS(remember_biomin_value,psample_info->extra_result.bioext_data), + set_cap_max,VC_ABS(remember_biomax_value,psample_info->extra_result.bioext_data), finished_set); + } + /* 继续执行二分逼近 */ + if( last_inn_bio_midextra_result.bioext_data ) + { + VCARE_DBG_LOG("(midset[%d]", set_cap_min,set_cap_mid, set_cap_max, + last_inn_bio_mid, psample_info->extra_result.bioext_data, (set_cap_min+set_cap_mid)/2 ); + set_cap_max = set_cap_mid; + set_cap_mid = (set_cap_min+set_cap_mid)/2; + set_flg_mid = 1; + core921x_set_bioinn_addcap(psample_info,set_cap_mid); + } + else if( last_inn_bio_mid>psample_info->extra_result.bioext_data ) + { + VCARE_DBG_LOG("(mid>bioext)now set cap[%d,%d,%d],now_bio_val[%d](%d) ->set[%d]", set_cap_min,set_cap_mid, set_cap_max, + last_inn_bio_mid, psample_info->extra_result.bioext_data, (set_cap_max+set_cap_mid)/2 ); + set_cap_min = set_cap_mid; + set_cap_mid = (set_cap_max+set_cap_mid)/2; + set_flg_mid = 1; + core921x_set_bioinn_addcap(psample_info,set_cap_mid); + } + else if( last_inn_bio_mid==psample_info->extra_result.bioext_data ) /* 完全相等,直接结束 */ + { + VCARE_DBG_LOG("(mid=bioext)now set cap[%d,%d,%d],now_bio_val[%d](%d) ->set[%d]", set_cap_min,set_cap_mid, set_cap_max, + last_inn_bio_mid, psample_info->extra_result.bioext_data, set_cap_mid); + finished_set=set_cap_mid; + finished_mark=1; + } + } + if( finished_mark ) /* 查找结束处理 */ + { + drv_info_handle->optimal_cap = finished_set; + drv_info_handle->optimal_bio_gap = last_inn_bio_mid - psample_info->extra_result.bioext_data; + drv_info_handle->optimal_bio_temp= psample_info->extra_result.temp0_data; /* inn_temp */ + /* set optimal_cap */ + core921x_set_bioinn_addcap(psample_info,drv_info_handle->optimal_cap); + VCARE_DBG_LOG("optimal_cap=%d, optimal_bio_gap=%d", drv_info_handle->optimal_cap, drv_info_handle->optimal_bio_gap ); + /* save flash_ok */ + drv_infomation_param_save(); + } + } + return -1; +} + +static void drv_calibration_entry_fast_irq( void ) +{ + core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2|VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD | VC921x_EN_EVT_PPG ); +} +static void drv_calibration_exit_fast_irq( void ) +{ + if( drv_info_handle->work_mode==WORK_MODE_FACTORY0 || drv_info_handle->work_mode==WORK_MODE_FACTORY1 ) + { + core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2 | VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD ); + } + else + { + core921x_set_interrupt_config( VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD | VC921x_EN_EVT_PPG ); + } +} + +static void drv_common_register_config( vc921x_drv_info *pdrv_info ) +{ + sample_info_handle->ppg_div = pdrv_info->ppg_div; + sample_info_handle->ps_div = pdrv_info->ps_div; + sample_info_handle->fifo_div = pdrv_info->fifo_div; + sample_info_handle->hold_div = pdrv_info->ps_div; + sample_info_handle->drop_div = pdrv_info->drop_div; +#if (VC921x_CFG_DROP_REDUCE_FREQ==VC921x_FUNC_ENABLE && 0==VC921x_PS_WORK_FREQUENCY_CONFIG) + if( WEAR_STA_DROP==wear_info_handle->wear_status ) + { + sample_info_handle->ps_div= pdrv_info->drop_div; + sample_info_handle->fifo_div=1; + } +#endif + sample_info_handle->fifo_enable = 1; + sample_info_handle->adc_resolution = 16; /* adc位数设置=16,18,20,22,注意初版0808mp的22bitADC不可用 */ + sample_info_handle->fifo_format = ( sample_info_handle->adc_resolution>=18 )?1:0; + core921x_set_common_config(sample_info_handle->fifo_enable, sample_info_handle->fifo_format, sample_info_handle->adc_resolution, + VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT); + /* set frequency and enable IRQ */ + core921x_set_sample_frequency(sample_info_handle->ppg_div, sample_info_handle->ps_div, sample_info_handle->fifo_div); + core921x_set_interrupt_config( VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD | VC921x_EN_EVT_PPG ); + /* ps2 */ + VC921x_PS_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[2] /*slot2_ps*/, VC921x_IN_STORE /*storefifo*/, VC921x_WEAR_PARAM_PS_CURRENT /*current*/, VC921x_WEAR_PARAM_PS_RESISTANCE /*resistance*/); + core921x_sample_slotx_config( VC921x_PPG_SLOT_2, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_WEAR_PARAM_PS_GAIN/*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* bio */ +#if (VC921x_FUNC_ENABLE == VC921x_CFG_WEAR_BIO_EN) + VC921x_BIO_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*bio_innenable*/, VC921x_CFG_ENABLE /*bio_extenable*/, VC921x_BIO_INFIFO_PPG_SUM /*biofifo_mode*/); + core921x_set_bioslot_config(sample_info_handle, drv_info_handle->optimal_cap); +#endif + /* inn-slot0,用于修正活体问题偏差及检验IC异常状态 */ + VC921x_TMP_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*tmpslot0_enable*/, VC921x_CFG_ENABLE /*tmpslot1_enable*/, 6 /*tmp_setcur*/); + core921x_set_temperature_config(sample_info_handle); +} + +static int drv_heartrate_mode_init(void) +{ + unsigned char hr_over_sample_config=0; + VC921x_SAMPLE_TIM sample_time_config = VC921x_SAMPLE_TIM_100US; + if( WORK_MODE_HR==sel_mode_ops->mode ) + { + hr_over_sample_config = 0; + sample_info_handle->adc_resolution = 16; /* adc位数设置=16,18,20 */ + if( drv_info_handle->hr_algo_mode != 0 ) /* 20240531.心率普通模式特殊配置,开启16倍过采,200us发光@algo.h */ + { + hr_over_sample_config = VC921x_CFG_SPORT_HR_OVERSAMPLE; + sample_time_config = VC921x_CFG_SPORT_HR_SAMPLETIME; + } + sample_info_handle->fifo_format = ( sample_info_handle->adc_resolution>=18 )?1:0; + core921x_set_common_config(sample_info_handle->fifo_enable, sample_info_handle->fifo_format, sample_info_handle->adc_resolution, + VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT); + } + /* ppg0 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config( VC921x_PPG_SLOT_0, sample_info_handle, VC921x_PPG_TXCH_0, VC921x_PPG_GAIN /*rxgain*/, hr_over_sample_config /*oversample,2^N*/, sample_time_config); + return 0; +} + +static int drv_spo2_mode_init(void) +{ + sample_info_handle->adc_resolution = 16; /* adc位数设置=16,18,20,22 */ + sample_info_handle->fifo_format = ( sample_info_handle->adc_resolution>=18 )?1:0; + core921x_set_common_config(sample_info_handle->fifo_enable, sample_info_handle->fifo_format, sample_info_handle->adc_resolution, + VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT); + /* ppg0 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_0, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_PPG_GAIN /*rxgain*/, 3 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ppg1 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_1, sample_info_handle, VC921x_PPG_TXCH_1, VC921x_PPG_GAIN /*rxgain*/, 3 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + return 0; +} +static int drv_bloodpressure_mode_init(void) +{ + /* ppg0 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_0, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_PPG_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + return 0; +} +static int drv_wear_mode_init(void) +{ + return 0; +} +static int drv_factory_green_ps_mode_init(void) +{ + /* ppg0 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_FAT_GREEN_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_0, sample_info_handle, VC921x_PPG_TXCH_0, VC921x_FAT_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ppg1 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_FAT_RED_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_1, sample_info_handle, VC921x_PPG_TXCH_1, VC921x_FAT_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ps2 */ + VC921x_PS_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[2] /*slot2_ps*/, VC921x_IN_STORE /*storefifo*/, VC921x_WEAR_PARAM_PS_CURRENT /*current*/, VC921x_WEAR_PARAM_PS_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_2, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_WEAR_PARAM_PS_GAIN/*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* bio/temp */ +#if (VC921x_FUNC_ENABLE == VC921x_CFG_WEAR_BIO_EN) + VC921x_BIO_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*bio_innenable*/, VC921x_CFG_ENABLE /*bio_extenable*/, VC921x_BIO_INFIFO_PPG_SUM /*biofifo_mode*/ ); + core921x_set_bioslot_config(sample_info_handle, drv_info_handle->optimal_cap); +#endif + /* += enable freq2ps irq */ + core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2 | VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD ); + return 0; +} +static int drv_factory_ir_red_mode_init(void) +{ + /* ppg0 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_FAT_IR_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_0, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_FAT_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ppg1 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_FAT_RED_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_1, sample_info_handle, VC921x_PPG_TXCH_1, VC921x_FAT_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ps2 */ + VC921x_PS_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[2] /*slot2_ps*/, VC921x_IN_STORE /*storefifo*/, VC921x_WEAR_PARAM_PS_CURRENT /*current*/, VC921x_WEAR_PARAM_PS_RESISTANCE /*resistance*/); + core921x_sample_slotx_config(VC921x_PPG_SLOT_2, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_WEAR_PARAM_PS_GAIN/*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* bio/temp */ +#if (VC921x_FUNC_ENABLE == VC921x_CFG_WEAR_BIO_EN) + VC921x_BIO_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*bio_innenable*/, VC921x_CFG_ENABLE /*bio_extenable*/, VC921x_BIO_INFIFO_PPG_SUM /*biofifo_mode*/ ); + core921x_set_bioslot_config(sample_info_handle, drv_info_handle->optimal_cap); +#endif + VC921x_TMP_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*tmpslot0_enable*/, VC921x_CFG_ENABLE /*tmpslot1_enable*/, 6 /*tmp_setcur*/); + core921x_set_temperature_config(sample_info_handle); + /* += enable freq2ps irq */ + core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2 | VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD ); + return 0; +} +static int drv_temperature_mode_init(void) +{ + return 0; +} + +static int drv_hrspo2_mode_init(void) +{ + drv_info_handle->ppg_convert_ps=1; + /* ppg0 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config( VC921x_PPG_SLOT_0, sample_info_handle, VC921x_PPG_TXCH_0, VC921x_PPG_GAIN /*rxgain*/, 0 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ppg1 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config( VC921x_PPG_SLOT_1, sample_info_handle, VC921x_PPG_TXCH_1, VC921x_PPG_GAIN /*rxgain*/, 3 /*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + /* ppg-ps2 */ + VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[2] /*slot2_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/); + core921x_sample_slotx_config( VC921x_PPG_SLOT_2, sample_info_handle, VC921x_PPG_TXCH_2, VC921x_PPG_GAIN /*rxgain*/, 3/*oversample,2^N*/, VC921x_SAMPLE_TIM_100US); + return 0; +} + +static void drv_work_init(vcare_ppg_device_t *pdev, int mode, unsigned short int ppg_div, unsigned char ps_div, unsigned char fifo_div, unsigned char drop_div, unsigned char algo_mode) +{ + if( VC921x_DEV_REV_ID==pdev->id1 && VC921x_FDY_VER_ID0==pdev->id2 ) + { + sample_info_handle->ic_type_id = VC921x_DEV_REV_ID; + sample_info_handle->ic_ficv_id = VC921x_FDY_VER_ID0; + } + else + { + VCARE_DBG_ERR("vc921x id error"); + return ; + } + /* set & init param */ + drv_info_handle->work_mode = mode; + drv_info_handle->ppg_div = ppg_div; + drv_info_handle->ps_div = ps_div; + drv_info_handle->fifo_div = fifo_div; + drv_info_handle->drop_div = drop_div; + drv_info_handle->hr_algo_mode = algo_mode; /* 新增传入算法模式,配置不同心率配置 */ + drv_info_handle->ppg_convert_ps=0; + drv_infomation_param_load(); + core921x_write_work_cmd(VC921x_RESET_SOFT_CMD); + core921x_write_work_cmd(VC921x_STOP_WORK_CMD); + core921x_write_work_cmd(VC921x_START_WORK_CMD); + drv921x_nto_version = core921x_check_nto_version_init(); /* 初始化判断1120mpw和0127nto */ + core921x_write_work_cmd(VC921x_RESET_SOFT_CMD); + core921x_write_work_cmd(VC921x_STOP_WORK_CMD); + /* 公共配置初始化 */ + drv_common_register_config( drv_info_handle ); + /* 模式配置初始化 */ + if (sel_mode_ops) + { + if (sel_mode_ops->mode_init) sel_mode_ops->mode_init(); + } + else + { + return; + } + /* 驱动参数初始化*/ + drv_infomation_param_init(pdev); + /* 血样模式配置不同的阈值 */ + core921x_set_threshold_config(drv_info_handle->ppg_max_thval, drv_info_handle->ppg_min_thval); +#if 1 + unsigned char config_debug_reg[32] = {0}; + unsigned char debug_index = 0; + vc921x_read_register(0x40, config_debug_reg, 26); + VCARE_DBG_LOG("[0x40]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x48]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x50]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x58]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); +#endif + core921x_write_work_cmd(VC921x_START_WORK_CMD); +} + +/******************************************************************************************************** + *佩戴检测部分代码 + ********************************************************************************************************/ +#if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE) +static int drv_calc_biology_sense( vc921x_wear_info *pwear_info, vc921x_sample_info_t *presult, unsigned short int bioinn_data, unsigned short int bioext_data, unsigned short int ps_data ) +{ + static unsigned int calc_ps = 0; + static int calc_bio_ext=0; + int ret = 0; + /* bio ps 有效判断 */ + if( bioext_data && ps_data ) + { + calc_bio_ext = bioext_data; + calc_ps = ps_data; + } + ret = f_BIOdetect(calc_bio_ext, calc_ps, VC921x_WEAR_PARAM_PSTH); + VCARE_DBG_LOG("__f_TPedge(%d,%d,%d)=%d =>[%d]", calc_bio_ext, calc_ps, VC921x_WEAR_PARAM_PSTH, ret, pwear_info->bio_wear_result); + if ( VC921x_BIO_STA_HOLD == ret) + { + pwear_info->bio_wear_result = VC921x_BIO_STA_HOLD; + pwear_info->algo_wear_status = WEAR_STA_HOLD; /* bio重新佩戴重置心率算法佩戴状态 */ + } + else if ( VC921x_BIO_STA_DROP == ret) + { + pwear_info->bio_wear_result = VC921x_BIO_STA_DROP; + } + return pwear_info->bio_wear_result; +} +#else +static int drv_calc_biology_sense_absolute(vc921x_wear_info *pwear_info, vc921x_sample_info_t *presult, unsigned short int bioinn_data, unsigned short int bioext_data, unsigned short int ps_data) +{ + unsigned short int bio_refence_base = 0; + unsigned char bio_ps_decline = 0; /* 1-单次下降满足,2-连续下降满足 */ + if (presult->extra_result.bioinn_enwork == 0 && presult->extra_result.bioext_enwork ==0 ) + { + return VC921x_BIO_STA_NONE; + } + if( !drv_info_handle->optimal_bio_valid ) + { + return VC921x_BIO_STA_NONE; + } + /* ps 有效判断 */ + if (ps_data) + { + /* 单次下降达到阈值 */ + if (pwear_info->last_ps_data[0] > ps_data && (pwear_info->last_ps_data[0] - ps_data) >= VC921x_WEAR_PARAM_PS_DELTA) + { + bio_ps_decline = 1; + } + /*连续两次供下降达到了阈值的1.5倍,避免刚好遇到两次采样缓慢下降的情况*/ + if ((pwear_info->last_ps_data[1] > pwear_info->last_ps_data[0]) && (pwear_info->last_ps_data[0] > ps_data) && (pwear_info->last_ps_data[1] - ps_data) >= (VC921x_WEAR_PARAM_PS_DELTA * 15 / 10)) + { + bio_ps_decline = 2; + } + /* buffer move */ + pwear_info->last_ps_data[1] = pwear_info->last_ps_data[0]; + pwear_info->last_ps_data[0] = ps_data; + } + /* bio 有效判断 */ + if (bioinn_data && bioext_data) + { + int real_bio_gap = drv_info_handle->optimal_bio_gap+(drv_info_handle->optimal_bio_temp-presult->extra_result.temp0_data)/36.0f*1.735f; + VCARE_DBG_LOG("calc_temp=%f", (drv_info_handle->optimal_bio_temp-presult->extra_result.temp0_data)/36.0f*1.735f ); + bio_refence_base = bioinn_data - real_bio_gap; + VCARE_DBG_LOG("bio_gap=%d(real=%d), bio_base=%d, bio_ext=%d, abs_gap(%d?[%d,%d])", + drv_info_handle->optimal_bio_gap, real_bio_gap, bio_refence_base, + bioext_data, VC_ABS(bioext_data, bio_refence_base), VC921x_WEAR_PARAM_BIO_ABS_DROP, VC921x_WEAR_PARAM_BIO_ABS_HOLD); + presult->extra_result.bioabs_calc = VC_ABS(bioext_data, bio_refence_base); + if (VC_ABS(bioext_data, bio_refence_base) >= VC921x_WEAR_PARAM_BIO_ABS_HOLD) + { + pwear_info->bio_wear_result = VC921x_BIO_STA_HOLD; + pwear_info->algo_wear_status = WEAR_STA_HOLD; /* bio重新佩戴重置心率算法佩戴状态 */ + } + else if ((VC_ABS(bioext_data, bio_refence_base) <= VC921x_WEAR_PARAM_BIO_ABS_DROP) && bio_ps_decline) + { + pwear_info->bio_wear_result = VC921x_BIO_STA_DROP; + } + } + return pwear_info->bio_wear_result; +} +#endif + +static vc921x_wear_change drv_wear_status_identify(vc921x_wear_info *pwear_info, vc921x_sample_info_t *presult) +{ + vc921x_wear_change ret_change = VC921x_WEAR_NO_CHANGE; + int ret_bio_algo = VC921x_BIO_STA_NONE; + /* 根据是否存入fifo对参数进行取值 和 采样次数进行判断 */ + unsigned char data_index = 0; + unsigned char sample_num = 1; + unsigned int ps = 0; + unsigned short int env = 0; + unsigned short int bioinn = 0; + unsigned short int bioext = 0; + unsigned int calc_psthh=VC921x_WEAR_PARAM_PSTH; + + if (presult->slot_result[2].slot_storefifo == 1) + { + sample_num = presult->slot_result[2].ppg_num; + } + if( drv_info_handle->ppg_convert_ps ) + { + sample_num=1; + } + for (data_index = 0; data_index < sample_num; data_index++) + { + if (presult->slot_result[2].slot_storefifo == 1) + { + ps = VC921x_GET_SLOT_PS_DATA(presult, data_index ); + } + else + { + ps = presult->slot_result[2].u.ps_data << 8; + } + if (presult->extra_result.biofifo_mode == VC921x_BIO_NOFIFO_PS_SGL) + { + bioinn = presult->extra_result.bioinn_data; + bioext = presult->extra_result.bioext_data; + } + else + { + bioinn = presult->extra_result.bioinn_buffer[data_index]; + bioext = presult->extra_result.bioext_buffer[data_index]; + } + env = presult->slot_result[2].env_data; +#if (VC921x_FUNC_DISABLE == VC921x_CFG_WEAR_BIO_EN) + ret_bio_algo = VC921x_BIO_STA_NONE; +#else + if( drv_info_handle->ppg_convert_ps ) + { + ret_bio_algo = VC921x_BIO_STA_NONE; + } + else + { + #if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE) + ret_bio_algo = drv_calc_biology_sense( pwear_info, presult, bioinn, bioext, ps ); + #else + ret_bio_algo = drv_calc_biology_sense_absolute(pwear_info, presult, bioinn, bioext, ps); + #endif + } +#endif + VCARE_DBG_LOG("status[%d] ps=%d,env=%d,bio_inn ext=(%d,%d)>bioret=%d", pwear_info->wear_status, ps, env, bioinn, bioext, ret_bio_algo); + VCARE_DBG_LOG("extern heart_algo_ret=%d,gsnesor_axis_ret=%d", pwear_info->algo_wear_status, pwear_info->acce_wear_status); +#if (VC921x_FUNC_DISABLE == VC921x_CFG_WEAR_ALG_EN) + pwear_info->algo_wear_status = WEAR_STA_HOLD; +#endif +#if (VC921x_FUNC_DISABLE == VC921x_CFG_WEAR_ACC_EN) + pwear_info->acce_wear_status = WEAR_STA_HOLD; +#endif + if( drv_info_handle->ppg_convert_ps ) + { + calc_psthh=vc921x_calc_ps_reflect_thh( presult->slot_result[2].slot_current, presult->slot_result[2].slot_resistance, presult->adc_resolution ); + VCARE_DBG_LOG("PS,fix(%d-%d),dyn(%d-%d)", ps, VC921x_WEAR_PARAM_PSTH, \ + VC921x_GET_SLOT_SAMPLE_DATA(presult, 2, presult->slot_result[2].ppg_num-1 ) ,calc_psthh ); + ps=VC921x_GET_SLOT_SAMPLE_DATA(presult, 2, presult->slot_result[2].ppg_num-1 ); + } + switch (pwear_info->wear_status) + { + case WEAR_STA_DROP: + if ((ps >= calc_psthh) && (env <= VC921x_WEAR_PARAM_ENVMIN) && (VC921x_BIO_STA_NONE == ret_bio_algo || VC921x_BIO_STA_HOLD == ret_bio_algo) && + (WEAR_STA_HOLD == pwear_info->algo_wear_status) && (WEAR_STA_HOLD == pwear_info->acce_wear_status)) + { + VCARE_DBG_LOG("drop->hold_cnt=%d", pwear_info->hold_cnt); + if (--pwear_info->hold_cnt <= 0) + { + pwear_info->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT; + pwear_info->drop_cnt = VC921x_CFG_WEAR_DROP_CNT; + pwear_info->wear_status = WEAR_STA_HOLD; + ret_change = VC921x_DROP_TO_HOLD; + goto CHANGE_RETURN; + } + } + else + { + pwear_info->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT; + } + break; + case WEAR_STA_HOLD: + if ((ps < calc_psthh) || (env > VC921x_WEAR_PARAM_ENVMAX) || (VC921x_BIO_STA_DROP == ret_bio_algo) || (WEAR_STA_DROP == pwear_info->algo_wear_status)) + { + if ((WEAR_STA_DROP == pwear_info->algo_wear_status) || (VC921x_BIO_STA_DROP == ret_bio_algo)) + { + pwear_info->drop_cnt = 1; + } + VCARE_DBG_LOG("hold->drop_cnt=%d", pwear_info->drop_cnt); + if (--pwear_info->drop_cnt <= 0) + { + pwear_info->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT; + pwear_info->drop_cnt = VC921x_CFG_WEAR_DROP_CNT; + pwear_info->wear_status = WEAR_STA_DROP; + ret_change = VC921x_HOLD_TO_DROP; + goto CHANGE_RETURN; + } + } + else + { + pwear_info->drop_cnt = VC921x_CFG_WEAR_DROP_CNT; + } + break; + default: + break; + } + } +CHANGE_RETURN: + return ret_change; +} + +static int drv_read_wear_sample_data(vc921x_sample_info_t *pwear_result_info) +{ + drv_read_sample_param(pwear_result_info); + drv_read_fifo_data(pwear_result_info); + if( !clk_info_handle->clk_calc_status ) + { + pwear_result_info->slot_result[0].ppg_num=0;/* clear ppg_data number, the clock_frequency wait calibration */ + pwear_result_info->slot_result[1].ppg_num=0; + } + return 0; +} + +static wear_status drv_get_wear_status(vcare_ppg_device_t *pdev) +{ + wear_status calc_status = wear_info_handle->last_status; + vc921x_wear_change wear_change = VC921x_WEAR_NO_CHANGE; + vc921x_sample_info_t *result_info_ptr = pdev->result; +#if (VC921x_CFG_WEAR_DETECTION == VC921x_FUNC_DISABLE) + return WEAR_STA_HOLD; +#endif + drv_read_event_status(drv_info_handle); + drv_read_wear_sample_data(result_info_ptr); + VCARE_DBG_LOG("fifo_read_data_valid=%d", drv_info_handle->fifo_read_data_valid); + /* 数据读取及处理 */ + if ( drv_info_handle->fifo_read_data_valid ) + { + wear_change = drv_wear_status_identify(wear_info_handle, result_info_ptr); + if (VC921x_DROP_TO_HOLD == wear_change) + { + calc_status = WEAR_STA_HOLD; + wear_info_handle->wear_status = calc_status; + wear_info_handle->last_status = calc_status; + pdev->wear = calc_status; + drv_calibration_clk_clear(); + drv_work_init(pdev, drv_info_handle->work_mode, drv_info_handle->ppg_div, drv_info_handle->ps_div, drv_info_handle->fifo_div, drv_info_handle->drop_div, drv_info_handle->hr_algo_mode ); + } + else if (VC921x_HOLD_TO_DROP == wear_change) + { + calc_status = WEAR_STA_DROP; + wear_info_handle->wear_status = calc_status; + wear_info_handle->last_status = calc_status; + pdev->wear = calc_status; + /* 必须重新初始化,重置windex,否则摘下的瞬间,会出现windex错误偏移,导致数据解析出错 */ + drv_work_init(pdev, drv_info_handle->work_mode, drv_info_handle->ppg_div, drv_info_handle->ps_div, drv_info_handle->fifo_div, drv_info_handle->drop_div, drv_info_handle->hr_algo_mode); + result_info_ptr->wear_drop_flag = 1; /* 用于发送摘下时原始数据标志 */ + } + } + return calc_status; +} + +/******************************************************************************************************** + * 自动化调整部分代码 + ********************************************************************************************************/ +static int drv_adjust_overload_max_current(vc921x_sample_info_t *psample_result_info, unsigned char overload, int event) +{ + int ret = 0; + unsigned char slot_i = 0; + vc921x_adjust_info *padjust_info = NULL; + unsigned char ovload_mark[3] = {overload & VC921x_STATUS_CH0_OVERLOAD, overload & VC921x_STATUS_CH1_OVERLOAD, overload & VC921x_STATUS_CH2_OVERLOAD}; + for (slot_i = 0; slot_i < 3; slot_i++) + { + padjust_info = adjust_info_handle[slot_i]; + if (ovload_mark[slot_i]) + { + VCARE_DBG_LOG("ovload_mark[%d] now_cur=%d", slot_i, padjust_info->current); + if (padjust_info->current != 0) + { + padjust_info->current--; + padjust_info->max_current = padjust_info->current; + padjust_info->const_max_current = padjust_info->max_current; + /* set adjust mark & adjust param */ + core921x_set_ppgslot_current((VC921x_PPG_SLOT_I)slot_i, padjust_info->current); + } + else + { + ret = -1; + } + } + } + return ret; +} +static int drv_adjust_slot_current_res(vc921x_adjust_info *padjust_info, unsigned char slot_index, unsigned char thh_res_level, unsigned char thh_current) +{ + unsigned char allow_oversample = 0; + unsigned char old_res_level = padjust_info->res_level; + unsigned char old_current = padjust_info->current; + unsigned short int old_current_step = padjust_info->adj_param.current_step; + VCARE_DBG_LOG("ADF_SLOT[%d]-dir(%d)-I_R thh[%d,%d] I_R now(%d,%d)", slot_index, padjust_info->adj_param.direction, thh_res_level, thh_current, old_res_level, old_current); + if (padjust_info->current == thh_current) + { + if (padjust_info->res_level == thh_res_level) + { + VCARE_DBG_ERR("RESLVL-OFFSET-LOW IS MAX/MIN--[%d]>=[%d]", old_res_level, thh_res_level); + return -1; + } + else + { + if (padjust_info->adj_param.direction == VC921x_ADJUST_DIR_UP) + { + padjust_info->res_level = (old_res_level >= thh_res_level) ? (thh_res_level) : (old_res_level + 1); + } + else + { + padjust_info->res_level = (old_res_level <= thh_res_level) ? (thh_res_level) : (old_res_level - 1); + } + /* 20241030.电阻降到默认+4以下时,限制最大电流到约0x65,下调故当前电流置为最小 */ + if( drv_info_handle->work_mode!=WORK_MODE_FACTORY0 && drv_info_handle->work_mode!=WORK_MODE_FACTORY1 && padjust_info->res_level < VC921x_PPG_RESISTANCE+4 ) + { + padjust_info->max_current = 0x65; + padjust_info->current = (padjust_info->adj_param.direction == VC921x_ADJUST_DIR_UP)? padjust_info->max_current: padjust_info->const_min_current; + } + else if( drv_info_handle->work_mode!=WORK_MODE_FACTORY0 && drv_info_handle->work_mode!=WORK_MODE_FACTORY1 && padjust_info->res_level >= VC921x_PPG_RESISTANCE+4 ) + { + padjust_info->max_current = padjust_info->const_max_current; + padjust_info->current = (padjust_info->adj_param.direction == VC921x_ADJUST_DIR_UP)? padjust_info->max_current: padjust_info->const_min_current; + } + } + } + else + { + /* calc step */ + if (padjust_info->adj_param.direction_last == VC921x_ADJUST_DIR_NONE) + { + old_current_step *= 16; + } + else if (padjust_info->adj_param.direction_last == padjust_info->adj_param.direction) + { + old_current_step = (old_current_step == 1 || old_current_step == 2) ? ((old_current_step + 1) * 16) : (old_current_step * VC921x_ADJ_I_INCREASE); /* 同向加大步长,但是在1和2的时候,1.4倍无法使整型增长,就直接+1 */ + } + else + { + old_current_step = old_current_step * VC921x_ADJ_I_DECREASE; + } + padjust_info->adj_param.current_step = old_current_step >> 4; + padjust_info->adj_param.current_step = (padjust_info->adj_param.current_step <= VC921x_ADJ_I_STEP_MIN) ? VC921x_ADJ_I_STEP_MIN : padjust_info->adj_param.current_step; + padjust_info->adj_param.current_step = (padjust_info->adj_param.current_step >= VC921x_ADJ_I_STEP_MAX) ? VC921x_ADJ_I_STEP_MAX : padjust_info->adj_param.current_step; + /* adjust current */ + if (VC921x_ADJUST_DIR_UP == padjust_info->adj_param.direction) + { + padjust_info->current = ((old_current + padjust_info->adj_param.current_step) > thh_current) ? thh_current : (old_current + padjust_info->adj_param.current_step); + } + else if (VC921x_ADJUST_DIR_DOWN == padjust_info->adj_param.direction) + { + padjust_info->current = (old_current < padjust_info->adj_param.current_step) ? thh_current : old_current - padjust_info->adj_param.current_step; + } + padjust_info->adj_param.direction_last = padjust_info->adj_param.direction; + } + VCARE_DBG_LOG("index=%d,res_level=%d,current=%d,step=%d", slot_index, padjust_info->res_level, padjust_info->current, padjust_info->adj_param.current_step); + if (WORK_MODE_HR == drv_info_handle->work_mode) /* 暂定得是只有心率模式下支持修改过采配置 */ + { + allow_oversample = 0; + } + core921x_set_ppgslot_resistance((VC921x_PPG_SLOT_I)slot_index, padjust_info->res_level, allow_oversample ); + core921x_set_ppgslot_current((VC921x_PPG_SLOT_I)slot_index, padjust_info->current); + return 0; +} + +static int drv_adjust_slot_ppg_overflow(vc921x_sample_info_t *psample_result_info, int event) +{ + unsigned char slot_i = 0; + unsigned int over_ppgdata = 0; + vc921x_adjust_info *padjust_info = NULL; + vc921x_sample_slot_t *pslot_ret = NULL; + for (slot_i = 0; slot_i < 3; slot_i++) + { + padjust_info = adjust_info_handle[slot_i]; + pslot_ret = &psample_result_info->slot_result[slot_i]; + over_ppgdata = pslot_ret->u.pre_data; + if (1 == pslot_ret->slot_enwork) + { + VCARE_DBG_LOG("ppg_overflow(%d)=4bit[%d]", over_ppgdata, VC921x_PPG_CONV_BIT4(over_ppgdata) ); + if (VC921x_PPG_CONV_BIT4(over_ppgdata) > drv_info_handle->ppg_max_thval) + { + padjust_info->adj_param.direction = VC921x_ADJUST_DIR_DOWN; + drv_adjust_slot_current_res(padjust_info, slot_i, padjust_info->const_min_res_level, padjust_info->const_min_current); + } + else if (VC921x_PPG_CONV_BIT4(over_ppgdata) < drv_info_handle->ppg_min_thval) + { + padjust_info->adj_param.direction = VC921x_ADJUST_DIR_UP; + drv_adjust_slot_current_res(padjust_info, slot_i, padjust_info->max_res_level, padjust_info->max_current); + } + else + { + padjust_info->adj_param.direction = VC921x_ADJUST_DIR_NONE; + padjust_info->adj_param.direction_last = VC921x_ADJUST_DIR_NONE; + VCARE_DBG_LOG("slot[%d] in the range,clear slot adjustment direction", slot_i); + } + } + } + return 0; +} + +static int drv_auto_adjust_slot_config(int event, unsigned char ov_status) +{ + if( wear_info_handle->wear_status==WEAR_STA_DROP ) + { + return -1; + } + if ((event&VC921x_EVENT_INTOVLOAD)||VC921x_CFG_IRQ_BY_TIMER_EN) + { + drv_adjust_overload_max_current(sample_info_handle, ov_status, event); + } + if((event&VC921x_EVENT_INTPPG_STA)||VC921x_CFG_IRQ_BY_TIMER_EN) + { + drv_adjust_slot_ppg_overflow(sample_info_handle, event); + } + else + { + /* clear adjust_param */ + adjust_info_handle[0]->adj_param.direction = VC921x_ADJUST_DIR_NONE; + adjust_info_handle[0]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE; + adjust_info_handle[1]->adj_param.direction = VC921x_ADJUST_DIR_NONE; + adjust_info_handle[1]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE; + adjust_info_handle[2]->adj_param.direction = VC921x_ADJUST_DIR_NONE; + adjust_info_handle[2]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE; + } + return 0; +} + +/******************************************************************************************************** + * 时钟校准部分 + *******************************************************************************************************/ +static int drv_calibration_oscclk_frequency(vc921x_clk_info *pclk_info) +{ + unsigned char count_vaild = 1; + unsigned char i = 0; + unsigned int clock_tick[2] = {0}; + unsigned short int osc_tick[2] = {0}; + unsigned short osc_frequency[2]; + + clock_tick[0] = vc921x_get_cputimer_tick(); + core921x_read_rcosc_tick(&osc_tick[0], &osc_tick[1]); + clock_tick[1] = vc921x_get_cputimer_tick(); + if ((osc_tick[0] > osc_tick[1]) || (clock_tick[0] > clock_tick[1])) + { + pclk_info->count_index = 0; + VCARE_DBG_ERR("osc/clk ticks is error\n"); + return 1; + } + pclk_info->osc_count[pclk_info->count_index * 2] = osc_tick[0]; + pclk_info->osc_count[pclk_info->count_index * 2 + 1] = osc_tick[1]; + pclk_info->clk_count[pclk_info->count_index * 2] = clock_tick[0]; + pclk_info->clk_count[pclk_info->count_index * 2 + 1] = clock_tick[1]; + pclk_info->count_index++; + if (pclk_info->count_index >= 3) + { + pclk_info->count_index = 0; + for (i = 0; i < 2; i++) + { + count_vaild = count_vaild && (VC_ABS(VC_ABS_MAX(pclk_info->clk_count[2 * i + 2], pclk_info->clk_count[2 * i], VC921x_CFG_MCU_TICK_MAX), VC_ABS_MAX(pclk_info->clk_count[2 * i + 3], pclk_info->clk_count[2 * i + 1], VC921x_CFG_MCU_TICK_MAX)) < VC921x_CFG_CLK_CALC_DEVIATION); + count_vaild = count_vaild && (VC_ABS(VC_ABS_MAX(pclk_info->osc_count[2 * i + 2], pclk_info->osc_count[2 * i], 0xffff), VC_ABS_MAX(pclk_info->osc_count[2 * i + 3], pclk_info->osc_count[2 * i + 1], 0xffff)) < VC921x_CFG_CLK_CALC_DEVIATION); + count_vaild = count_vaild && (!(pclk_info->clk_count[2 * i + 2] == pclk_info->clk_count[2 * i])); /* avoid divisor==0, diffCountIsOk set false */ + count_vaild = count_vaild && (!(pclk_info->osc_count[2 * i + 2] == pclk_info->osc_count[2 * i])); /* avoid divisor==0, diffCountIsOk set false */ + } + if (count_vaild) + { + for (i = 0; i < 2; i++) + { + osc_frequency[i] = VC_ABS_MAX((unsigned int)pclk_info->osc_count[2 * i + 2], pclk_info->osc_count[2 * i], 0xffff) * VC921x_CFG_MCU_TICK_FREQUENCY / VC_ABS_MAX((unsigned int)pclk_info->clk_count[2 * i + 2], pclk_info->clk_count[2 * i], VC921x_CFG_MCU_TICK_MAX); + VCARE_DBG_LOG("f20kOsc[20K_%d]=(%d)", i, osc_frequency[i]); + } + if (VC_ABS(osc_frequency[0], osc_frequency[1]) <= 20) + { + pclk_info->rcosc_frequency = (osc_frequency[0] + osc_frequency[1]) / 2; + pclk_info->clk_calc_freq_status = 1; + } + return 0; + } + } + return 2; +} + +static int drv_auto_calibration_oscclk(vc921x_clk_info *pclk_info) +{ + /* calibration the osc frequency by method of bisection */ + if (pclk_info->clk_calc_freq_status && pclk_info->rcosc_frequency) + { + pclk_info->clk_calc_freq_status = 0; + if (pclk_info->rcosc_frequency >= VC921x_FREQUENCY_MAX) + { + if( drv921x_nto_version ) + { + rcosc_min = (rcosc_mid <= 0xfe) ? rcosc_mid + 1 : 0xff; + } + else + { + rcosc_min = (rcosc_mid <= 0x7e) ? rcosc_mid + 1 : 0x7f; + } + } + else if (pclk_info->rcosc_frequency <= VC921x_FREQUENCY_MIN) + { + rcosc_max = (rcosc_mid >= 1) ? (rcosc_mid - 1) : 0; + } + else + { + pclk_info->clk_calc_status = 1; /* calibration finished mark */ + pclk_info->osc_gap_cnt = 0; + rcosc_max = rcosc_mid + 2; /* 修正成功后,扩张一个调整点的范围,以便温漂时调整余量 */ + rcosc_min = rcosc_mid - 2; + } + rcosc_mid = (rcosc_max + rcosc_min) / 2; + VCARE_DBG_LOG("min,max[%d,%d]~min(%d)", rcosc_min, rcosc_max, rcosc_mid); + core921x_set_rcosc_frequency(rcosc_mid); + pclk_info->rcosc_calibration = rcosc_mid; + /* 如果发生温漂,修改收缩的上下限,进行缓慢修正时钟 */ + if ((pclk_info->rcosc_frequency <= VC921x_FREQUENCY_MIN) && VC_ABS(rcosc_max, rcosc_min) <= 2) + { + rcosc_min -= 2; + VCARE_DBG_LOG("!!!temp->min,max[%d,%d]~min(%d)", rcosc_min, rcosc_max, rcosc_mid); + } + if ((pclk_info->rcosc_frequency >= VC921x_FREQUENCY_MAX) && VC_ABS(rcosc_max, rcosc_min) <= 2) + { + rcosc_max += 2; + VCARE_DBG_LOG("!!!temp->min,max[%d,%d]~min(%d)", rcosc_min, rcosc_max, rcosc_mid); + } + } + return 0; +} + +static int drv_calibration_oscclk_config(vcare_ppg_device_t *pdev) +{ + vc921x_clk_info *pclk_info = clk_info_handle; +#if 1 + if (pclk_info->clk_calc_status) +#else + if (pclk_info->clk_calc_status && pclk_info->osc_gap_cnt <= VC921x_CFG_CLK_CALC_GAPTIME) +#endif + { + pclk_info->osc_gap_cnt++; + return 0; + } + /* calibration clk running, enter fast irq config */ + drv_calibration_entry_fast_irq( ); + drv_calibration_oscclk_frequency(pclk_info); + drv_auto_calibration_oscclk(pclk_info); + if( pclk_info->clk_calc_status ) /* calibration clk finished, exit fast irq config */ + { + startup_inntemperature = sample_info_handle->extra_result.temp0_data; + drv_calibration_exit_fast_irq( ); + } + return 1; +} +static void drv_calibration_clk_clear(void) +{ + static unsigned char is_first_run = 1; + vc921x_clk_info *pclk_info = clk_info_handle; + pclk_info->last_check_ticks = 0; + pclk_info->osc_gap_cnt = 0; + pclk_info->count_index = 0; + pclk_info->clk_calc_freq_status = 0; + /* 校验频率温度清空 */ + check_cpu_tick[0]=0,check_cpu_tick[1]=0; + check_dev_tick[0]=0,check_dev_tick[1]=0; + if (is_first_run == 1) + { + is_first_run = 0; + if( drv921x_nto_version ) + { + rcosc_max = 255,rcosc_min = 0,rcosc_mid = 127; + } + else + { + rcosc_max = 127,rcosc_min = 0,rcosc_mid = 63; + } + pclk_info->clk_calc_status = 0; + core921x_set_rcosc_frequency(rcosc_mid); + } + else + { + if( pclk_info->rcosc_calibration==0 ) + { + if( drv921x_nto_version ) + { + rcosc_max = 255,rcosc_min = 0,rcosc_mid = 127; + } + else + { + rcosc_max = 127,rcosc_min = 0,rcosc_mid = 63; + } + pclk_info->clk_calc_status = 0; + pclk_info->rcosc_calibration=rcosc_mid; + } + core921x_set_rcosc_frequency(pclk_info->rcosc_calibration); + } +} + +static int drv_check_running_gaptime(void) +{ +#if VC921x_CFG_CLK_CLAC_IRQGAP_EN + int ret = 0; + unsigned short int curr_ticks = 0; + unsigned short int ticks_chk, ticks_gap = 0; + unsigned short int ticks1 = 0, ticks2 = 0; + unsigned char times_gap = 0; + core921x_read_rcosc_tick(&ticks1, &ticks2); + times_gap = (1000 * drv_info_handle->ppg_div / VC921x_DEFAULT_FREQ) * VC921x_IRQ_GAP_RATIO; + ticks_chk = (ticks2 >= ticks1) ? (ticks2 - ticks1) : (0xffff + ticks2 - ticks1); + if (ticks_chk <= 10) + { + curr_ticks = ticks1; + } + else + { /* IC问题,可能出现其中一个tick低位出现异常,如果出现异常则取另外一共tick作为运算准 */ + curr_ticks = (ticks2&0xff)?(ticks2):(ticks1); + VCARE_DBG_ERR("read check tick failed(%d,%d)", ticks1, ticks2); + } + // ticks_gap = 2000; + if (0 != curr_ticks && 0 != clk_info_handle->last_check_ticks) + { + ticks_gap = (curr_ticks >= clk_info_handle->last_check_ticks) ? (curr_ticks - clk_info_handle->last_check_ticks) : (0xffff + curr_ticks - clk_info_handle->last_check_ticks); + } + if (ticks_gap <= 20 * times_gap) /* 20k,1ms~20ticks */ + { + VCARE_DBG_ERR("last(%d)now(%d)gap[%d<%d]", clk_info_handle->last_check_ticks, curr_ticks, ticks_gap, 20 * times_gap); + ret = -1; + } + clk_info_handle->last_check_ticks = curr_ticks; + return ret; +#else + return 0; +#endif +} + +static void drv_fifo_error_softreset( void ) +{ + static unsigned char last_add_mark=0; + unsigned char save_config[32]={0}; + /* 软复位,清空所有数据,避免传入算法或者引起其他异常 */ + drv_sample_result_memroy_finished( sample_info_handle ); + vc921x_read_register( 0x40, save_config, sizeof(save_config) ); + core921x_write_work_cmd( VC921x_STOP_WORK_CMD ); + core921x_write_work_cmd( VC921x_RESET_SOFT_CMD ); + drv_info_handle->read_fifo_address = 0; + vc921x_write_register( 0x40, save_config, sizeof(save_config) ); + core921x_write_work_cmd( VC921x_START_WORK_CMD ); + if( last_add_mark==0 ) + { + last_add_mark=1; + core921x_set_rcosc_frequency( clk_info_handle->rcosc_calibration-1 ); + } + else + { + last_add_mark=0; + core921x_set_rcosc_frequency( clk_info_handle->rcosc_calibration+1 ); + } + #if 1 + unsigned char config_debug_reg[32] = {0}; + unsigned char debug_index = 0; + vc921x_read_register(0x40, config_debug_reg, 32); + VCARE_DBG_LOG("[0x40]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x48]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x50]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x58]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + #endif +} +/******************************************************************************************************** + *数据读取部分 + ********************************************************************************************************/ +static int drv_read_fifo_data(vc921x_sample_info_t *psample_result) +{ + int read_fifo_ret = 0; + vc921x_sample_info_t *sample_result_ptr = psample_result; + unsigned char bio_fifo_error_cnt=0; + unsigned char bio_fifo_error_flg=0; + unsigned char ps_fifo_error_flg=0; + if (!sample_result_ptr) + { + return -1; + } + /* fifo中断 */ + if (0 != drv_info_handle->fifo_read_finished_sync) + { + return 0; + } + drv_info_handle->fifo_read_finished_sync = 1; + read_fifo_ret = core921x_read_fifo_data(sample_result_ptr, &drv_info_handle->read_fifo_address, drv_info_handle->write_fifo_address_bak); + VCARE_DBG_LOG("read_fifo updata read address: %d, write_address:%d, write_address_rel:%d",drv_info_handle->read_fifo_address, drv_info_handle->write_fifo_address_bak, drv_info_handle->write_fifo_address_rel ); + if (read_fifo_ret>=0) + { + drv_info_handle->fifo_read_data_valid = 1; + /* nto版本直接更新read_addr */ + if( drv921x_nto_version ) + { + if( read_fifo_ret==1 ) + { + drv_info_handle->read_fifo_address = drv_info_handle->write_fifo_address_bak; + /* fifo错误,清空fifo数据 */ + VCARE_DBG_LOG("===PS_FIFO_ERROR===") ; + drv_sample_result_memroy_finished( sample_info_handle ); + return read_fifo_ret; + } + } + else + { + if( read_fifo_ret==1 && (drv_info_handle->int_event&VC921x_EN_EVT_FIFO) && !(drv_info_handle->int_event&VC921x_EVENT_INSAMPLE) ) /* 当出现了fifo中断,且并不是fifo数量的倍数时,可以认定为错位,进行纠错处理 */ + { + drv_info_handle->read_fifo_address = drv_info_handle->write_fifo_address_bak; + drv_info_handle->fifo_read_data_valid = 2; + VCARE_DBG_LOG("delay response read_addr updata:%d=write_addr:%d", drv_info_handle->read_fifo_address, drv_info_handle->write_fifo_address_bak); + } + /* 20240119.校验RO_PS与fifo_PS是否异常(如果异常则可以判断为fifo异常错位:1.过度延后导致的fifo覆盖反转,2.ICfifo数据异常丢失) + * 20240229.添加bio的全部出现0xff的情况,判断为fifo异常错位 + */ + if( sample_result_ptr->extra_result.bioext_enwork && sample_result_ptr->extra_result.bio_fifo_num!=0 ) + { + for( bio_fifo_error_cnt=0; bio_fifo_error_cntextra_result.bio_fifo_num; bio_fifo_error_cnt++ ) + { + VCARE_DBG_LOG("bio=%x ~ 0xff",sample_result_ptr->extra_result.bioext_buffer[bio_fifo_error_cnt] ); + if( (sample_result_ptr->extra_result.bioext_buffer[bio_fifo_error_cnt]&0xff) != 0xff ) + { + bio_fifo_error_cnt=0; + break; + } + } + VCARE_DBG_LOG("bio_num=%d,%d",sample_result_ptr->extra_result.bio_fifo_num, bio_fifo_error_cnt); + if( sample_result_ptr->extra_result.bio_fifo_num==bio_fifo_error_cnt ) + { + bio_fifo_error_flg=1; + } + } + if( sample_result_ptr->slot_result[2].slot_enwork==2 && sample_result_ptr->slot_result[2].ppg_num!=0 ) + { + VCARE_DBG_LOG("last_ps=%x ~ %x",VC921x_GET_SLOT_PS_DATA(sample_result_ptr, sample_result_ptr->slot_result[2].ppg_num-1), sample_result_ptr->slot_result[2].u.ps_data ); + if( VC921x_GET_SLOT_PS_DATA(sample_result_ptr, sample_result_ptr->slot_result[2].ppg_num-1)>>8 != sample_result_ptr->slot_result[2].u.ps_data ) + { + ps_fifo_error_flg=1; + } + } + /* bio_fifo_error || ps_fifo_error */ + if( bio_fifo_error_flg || ps_fifo_error_flg ) + { + VCARE_DBG_LOG("===PS_FIFO_ERROR===") ; + drv_fifo_error_softreset(); + return read_fifo_ret; + } + } + /* 20241018.在insample的时候,如果出现中断延时处理/定时器,获取到的RO_bio的值可能还未完全采样计算完成,需要从fifo中更新数据 */ + if( (VC921x_CFG_IRQ_BY_TIMER_EN||drv_info_handle->int_event&VC921x_EVENT_INSAMPLE||0==drv_info_handle->int_event) && (VC921x_BIO_NOFIFO_PS_SGL!=sample_result_ptr->extra_result.biofifo_mode) ) + { + if( sample_result_ptr->extra_result.bioext_enwork && + sample_result_ptr->extra_result.bioext_data != sample_result_ptr->extra_result.bioext_buffer[sample_result_ptr->extra_result.bio_fifo_num-1] ) + { + sample_result_ptr->extra_result.bioext_data = sample_result_ptr->extra_result.bioext_buffer[sample_result_ptr->extra_result.bio_fifo_num-1]; + VCARE_DBG_ERR("INSAMPLE_ERR_EXTBIO-modify=%d",sample_result_ptr->extra_result.bioext_data); + } + if( sample_result_ptr->extra_result.bioinn_enwork && + sample_result_ptr->extra_result.bioinn_data != sample_result_ptr->extra_result.bioinn_buffer[sample_result_ptr->extra_result.bio_fifo_num-1]) + { + sample_result_ptr->extra_result.bioinn_data = sample_result_ptr->extra_result.bioinn_buffer[sample_result_ptr->extra_result.bio_fifo_num-1]; + VCARE_DBG_ERR("INSAMPLE_ERR_INNBIO-modify=%d",sample_result_ptr->extra_result.bioinn_data); + } + } + } + else + { + VCARE_DBG_ERR("read_fifo_ret error(%d)", read_fifo_ret); + return read_fifo_ret; + } + return 0; +} + +static int drv_read_sample_param(vc921x_sample_info_t *psample_ret) +{ + unsigned char slot_i = 0; + unsigned char slot_current = 0, slot_res_lvl = 0; + if (0 == drv_info_handle->param_read_finished_sync) + { + core921x_read_output(psample_ret); + VCARE_DBG_LOG("env(0x)=%x-%x-%x(%d,%d,%d)", psample_ret->slot_result[0].env_data, + psample_ret->slot_result[1].env_data, + psample_ret->slot_result[2].env_data, + VC921x_ENV_CONVERT(psample_ret->slot_result[0].env_data), + VC921x_ENV_CONVERT(psample_ret->slot_result[1].env_data), + VC921x_ENV_CONVERT(psample_ret->slot_result[2].env_data)); + VCARE_DBG_LOG("ppg/ps_data=%d-%d-%d", psample_ret->slot_result[0].u.ps_data, psample_ret->slot_result[1].u.ps_data, psample_ret->slot_result[2].u.ps_data); + VCARE_DBG_LOG("bio01_data=%d-%d", psample_ret->extra_result.bioinn_data, psample_ret->extra_result.bioext_data); + VCARE_DBG_LOG("temp01_data=%d-%d-ref(%d)", psample_ret->extra_result.temp0_data, psample_ret->extra_result.temp1_data, psample_ret->extra_result.tempref_data); + + psample_ret->slot_result[0].env_data = VC921x_ENV_CONVERT(psample_ret->slot_result[0].env_data); + psample_ret->slot_result[1].env_data = VC921x_ENV_CONVERT(psample_ret->slot_result[1].env_data); + psample_ret->slot_result[2].env_data = VC921x_ENV_CONVERT(psample_ret->slot_result[2].env_data); + for (slot_i = 0; slot_i < 3; slot_i++) + { + core921x_read_slot_current_res((VC921x_PPG_SLOT_I)slot_i, &slot_current, &slot_res_lvl); + psample_ret->slot_result[slot_i].slot_current = slot_current; + psample_ret->slot_result[slot_i].slot_resistance = slot_res_lvl; + adjust_info_handle[slot_i]->current = slot_current; + adjust_info_handle[slot_i]->res_level = slot_res_lvl; + } + drv_info_handle->param_read_finished_sync = 1; + VCARE_DBG_LOG("slot[0]cur%d,res%d ^ slot[1]cur%d,res%d ^ slot[2]cur%d,res%d", + psample_ret->slot_result[0].slot_current, psample_ret->slot_result[0].slot_resistance, + psample_ret->slot_result[1].slot_current, psample_ret->slot_result[1].slot_resistance, + psample_ret->slot_result[2].slot_current, psample_ret->slot_result[2].slot_resistance); + } + return 0; +} + +static int drv_read_event_status(vc921x_drv_info *pdrv_info) +{ + if (0 == pdrv_info->event_read_finished_sync) + { + core921x_read_event_status(&pdrv_info->int_event, &pdrv_info->ov_status, &pdrv_info->write_fifo_address_bak, &pdrv_info->write_fifo_address_rel); + pdrv_info->event_read_finished_sync = 1; + VCARE_DBG_LOG("read_event=[%x], read_status=[%x], read_Windex=[%x]~rel[%x]", pdrv_info->int_event, pdrv_info->ov_status, pdrv_info->write_fifo_address_bak, pdrv_info->write_fifo_address_rel ); + } + return 0; +} + +/******************************************************************************************************** + * 中断事件处理部分调用逻辑 + ********************************************************************************************************/ +static int drv_ppg_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev) +{ + int ret = 0; + vc921x_sample_info_t *sample_result_ptr = pdev->result; + vc921x_mode_ops *self_ptr = (vc921x_mode_ops *)ops_self; + drv_calibration_oscclk_config( pdev ); + if( 1 == clk_info_handle->clk_calc_status ) + { + ret = drv_auto_adjust_slot_config(drv_info_handle->int_event, drv_info_handle->ov_status); + } + if (ret >= 0 && 1 == clk_info_handle->clk_calc_status) + { + drv_read_fifo_data(sample_result_ptr); + } + else + { + VCARE_DBG_ERR("WORK_MODE_[%d] clk_status[%d]", self_ptr->mode, clk_info_handle->clk_calc_status); + } + return ret; +} +static int drv_factory_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev) +{ + int ret = 0; + unsigned short int base =0; + vc921x_sample_info_t *sample_result_ptr = pdev->result; + drv_calibration_oscclk_config( pdev ); + if (drv_info_handle->int_event & VC921x_EVENT_INTOVLOAD) + { + ret = drv_adjust_overload_max_current(sample_result_ptr, drv_info_handle->ov_status, drv_info_handle->int_event); + } + drv_read_fifo_data(sample_result_ptr); + if( 1==clk_info_handle->clk_calc_status ) + { + drv_calc_bioinn_auto_addcap(drv_info_handle->int_event, sample_result_ptr); + } + base = sample_result_ptr->extra_result.bioinn_data - drv_info_handle->optimal_bio_gap; + sample_result_ptr->extra_result.bioabs_calc = VC_ABS( sample_result_ptr->extra_result.bioext_data, base ); + return ret; +} + +/********************************************************************************************************* + * DRV_API 对外功能模块部分 + ********************************************************************************************************/ +int vc921x_drv_init_start_work(void *pdevice, int workmode, unsigned short int ppgdiv, unsigned char psdiv, unsigned char fifodiv, unsigned char dropdiv) +{ + vcare_ppg_device_t *pdev = (vcare_ppg_device_t *)pdevice; + char *drv_ver = NULL; + unsigned char mode_count = 0; + unsigned char mode_index = 0; + vcare_memset(sample_info_handle, 0, sizeof(vc921x_sample_info_t)); + pdev->result = sample_info_handle; /* 采样指针传递 */ + core921x_read_software_version(&drv_ver); + core921x_read_id(&pdev->id1, &pdev->id2); /* 0x24, 0x10 */ + VCARE_DBG_LOG("[%s]devID0-2=0x%02x 0x%02x", drv_ver, pdev->id1, pdev->id2); + mode_count = sizeof(mode_ops) / sizeof(mode_ops[0]); + sel_mode_ops = NULL; + for (mode_index = 0; mode_index < mode_count; mode_index++) + { + if (workmode == mode_ops[mode_index].mode) + { + sel_mode_ops = &mode_ops[mode_index]; + break; + } + } + if (!sel_mode_ops) + { + VCARE_DBG_ERR("work_mode is error(NULL),please code mode"); + return -1; + } + drv_work_init(pdev, workmode, ppgdiv, psdiv, fifodiv, dropdiv, pdev->heart_algo_mode); + return 0; +} +int vc921x_drv_get_hwsw_infomation(char **str_drv_ver, unsigned char *pid1, unsigned char *pid2) +{ + core921x_read_software_version(str_drv_ver); + core921x_read_id(pid1, pid2); + return 0; +} +int vc921x_drv_exit_stop_work(void *pdevice) +{ + wear_info_handle->last_status = WEAR_STA_NONE; + core921x_write_work_cmd(VC921x_RESET_SOFT_CMD); + core921x_write_work_cmd(VC921x_STOP_WORK_CMD); + return 0; +} +int vc921x_drv_software_reset(void *pdevice) +{ + wear_info_handle->last_status = WEAR_STA_NONE; + return core921x_write_work_cmd(VC921x_RESET_SOFT_CMD); +} +int vc921x_drv_wakeup_work(void *pdevice) +{ + return core921x_write_work_cmd(VC921x_START_WORK_CMD); +} +int vc921x_drv_sleep_work(void *pdevice) +{ + wear_info_handle->last_status = WEAR_STA_NONE; + return core921x_write_work_cmd(VC921x_STOP_WORK_CMD); +} +int vc921x_drv_set_algo_wear_status(void *pdevice, int status) +{ + wear_info_handle->algo_wear_status = (status == -1) ? (WEAR_STA_DROP) : (WEAR_STA_HOLD); + return 0; +} +int vc921x_drv_set_acce_wear_status(void *pdevice, int status) +{ + /* 产生运动量,清除心率摘下标志 */ + if (0 == status) + { + wear_info_handle->acce_wear_status = WEAR_STA_DROP; + } + else + { + wear_info_handle->acce_wear_status = WEAR_STA_HOLD; + wear_info_handle->algo_wear_status = WEAR_STA_HOLD; + } + return 0; +} +wear_status vc921x_drv_get_wear_status(void *pdevice) +{ + vcare_ppg_device_t *pdev = (vcare_ppg_device_t *)pdevice; + if (!sel_mode_ops) + { + return WEAR_STA_HOLD; + } + if (pdev->workmode == WORK_MODE_FACTORY0 || pdev->workmode == WORK_MODE_FACTORY1) + { + return WEAR_STA_HOLD; + } + return drv_get_wear_status(pdevice); +} + +void vc921x_drv_get_wear_detail_result( unsigned char *bio_ret, unsigned char *algo_ret, unsigned char *acce_ret ) +{ + *bio_ret = (VC921x_BIO_STA_HOLD==wear_info_handle->bio_wear_result)?1:0; + *algo_ret = (WEAR_STA_HOLD==wear_info_handle->algo_wear_status)?1:0; + *acce_ret = (WEAR_STA_HOLD==wear_info_handle->acce_wear_status)?1:0; +} + +/* irq/timer callback interface. */ +int vc921x_drv_get_result_handler(void *pdevice) +{ + vcare_ppg_device_t *pdev = (vcare_ppg_device_t *)pdevice; + pdev->result = sample_info_handle; + vc921x_sample_info_t *sample_result_ptr = pdev->result; + if (!sample_result_ptr || !sel_mode_ops ) + { + return -2; + } + /* 读取基础采样数据 */ + drv_read_event_status(drv_info_handle); + if( drv_info_handle->int_event==0 ) + { + return -1; + } + if (drv_info_handle->int_event & VC921x_EVENT_CONFLICT) + { + VCARE_DBG_ERR("work_status=%x", drv_info_handle->int_event); + return -1; + } + /* check gap time */ + if (0 != drv_check_running_gaptime()) + { + VCARE_DBG_ERR("running gaptime"); + return -1; + } + drv_read_sample_param(sample_result_ptr); + /* 模式数据处理 */ + if (sel_mode_ops->mode_handler) + { + sel_mode_ops->mode_handler(sel_mode_ops, pdev); + } + return 0; +} + +void vc921x_drv_read_event_infomation_byIRQ(void) +{ + drv_read_event_status(drv_info_handle); +} + +int vc921x_drv_is_fifo_event(void *pdevice) +{ + if( drv_info_handle->fifo_read_data_valid ) + { + return 1; + } + return 0; +} +int vc921x_drv_is_ps_event(void *pdevice) +{ + if (drv_info_handle->int_event & (VC921x_EVENT_INTPS_RDY)) + { + return 1; + } + return 0; +} +int vc921x_drv_is_ppg_event(void *pdevice) +{ + if (drv_info_handle->int_event & (VC921x_EVENT_INTPPG_STA)) + { + return 1; + } + return 0; +} +int vc921x_drv_clear_reset_bio_param(void *pdevice) +{ + drv_infomation_param_reset(); + core921x_set_bioinn_addcap( sample_info_handle, set_cap_mid ); + return 0; +} + +unsigned char vc921x_drv_check_frequency_abnormal( unsigned short dev_tick1, unsigned short dev_tick2, unsigned int cpu_tick1, unsigned int cpu_tick2 ) +{ + static unsigned short calc_freq[2]={0}; + unsigned int cpu_tick_diff=0,dev_tick_diff=0; + float gap_time_diff=0.0f; + if( !clk_info_handle->clk_calc_status ) return 0; + check_cpu_tick[1] = check_cpu_tick[0]; + check_dev_tick[1] = check_dev_tick[0]; + check_cpu_tick[0] = cpu_tick1; + check_dev_tick[0] = dev_tick1; + if( VC_ABS_MAX(dev_tick2,dev_tick1,0xffff)>=20 || VC_ABS_MAX(cpu_tick2, cpu_tick1, VC921x_CFG_MCU_TICK_MAX)>=32 ) + { + check_cpu_tick[0]=0,check_cpu_tick[1]=0; + check_dev_tick[0]=0,check_dev_tick[1]=0; + return 0; + } + if (0 == check_cpu_tick[1]||0 == check_cpu_tick[0]) + { + return 0; + } + if (0 == check_dev_tick[1]||0==check_dev_tick[0]) + { + return 0; + } + cpu_tick_diff = VC_ABS_MAX( check_cpu_tick[0], check_cpu_tick[1], VC921x_CFG_MCU_TICK_MAX ); + dev_tick_diff = VC_ABS_MAX( check_dev_tick[0], check_dev_tick[1], 0xFFFF ); + gap_time_diff = (float)cpu_tick_diff/(float)VC921x_CFG_MCU_TICK_FREQUENCY; + calc_freq[1] = calc_freq[0]; + calc_freq[0] = (float)dev_tick_diff/gap_time_diff; + if( calc_freq[0]&& calc_freq[1] && VC_ABS( calc_freq[0], calc_freq[1] )<=100 ) + { + VCARE_DBG_LOG("check temp freq=[%d][%d](%d,%d)", calc_freq[0],calc_freq[1], cpu_tick_diff, dev_tick_diff ); + if( 20000>=calc_freq[0] && (20000-calc_freq[0])/40 >= 60 ) /* 相较于上电时的频率温升60即返回出错 */ + { + check_cpu_tick[0]=0,check_cpu_tick[1]=0; + check_dev_tick[0]=0,check_dev_tick[1]=0; + return 1; + } + } + return 0; +} +#define CHECK_BUFF_SIZE 20 +int vc921x_drv_read_check_temperature_abnormal( void *pdevice, unsigned char *p_freq_ret, unsigned char *p_temp_ret, unsigned short *pdev_cnt1, unsigned short *pdev_cnt2 ) +{ + static unsigned char fiil_mark=0; + static unsigned char fill_index=0; + static unsigned short check_innbio_buff[CHECK_BUFF_SIZE]={0}; + static unsigned short check_extbio_buff[CHECK_BUFF_SIZE]={0}; + static unsigned short check_tick1_buff[CHECK_BUFF_SIZE]={0}; + static unsigned short check_tick2_buff[CHECK_BUFF_SIZE]={0}; + unsigned int check_clk_tick[2]={0}; + unsigned char i=0; + int check_ret=0; + *p_freq_ret = 0; + *p_temp_ret = 0; + + drv_read_sample_param( sample_info_handle ); + drv_info_handle->param_read_finished_sync = 0; /* 读取完成之后不置同步标志,该数据仅做异常检测 */ + /****** 进入临界区 ******/ + check_clk_tick[0] = vc921x_get_cputimer_tick(); + core921x_read_rcosc_tick( pdev_cnt1, pdev_cnt2 ); + check_clk_tick[1] = vc921x_get_cputimer_tick(); + /****** 退出临界区 ******/ + check_innbio_buff[fill_index]=sample_info_handle->extra_result.bioinn_data; + check_extbio_buff[fill_index]=sample_info_handle->extra_result.bioext_data; + check_tick1_buff[fill_index]=*pdev_cnt1; + check_tick2_buff[fill_index]=*pdev_cnt2; + /* 检验频率温度是否正常 */ + *p_freq_ret = vc921x_drv_check_frequency_abnormal( *pdev_cnt1, *pdev_cnt2, check_clk_tick[0], check_clk_tick[1] ); + /* 检验内部温度是否正常 */ +#if 0 /* 使用上电时的内部温度和当前的相对温度进行比较 或者是 内部一致就使用绝对比较 */ + if( sample_info_handle->extra_result.temp0_data>0 && startup_inntemperature>sample_info_handle->extra_result.temp0_data && (startup_inntemperature-sample_info_handle->extra_result.temp0_data)>=1000 ) +#else + if( sample_info_handle->extra_result.temp0_data>0 && sample_info_handle->extra_result.temp0_data<=18000 ) /* 如果客户那边内部得温度常温都在19000左右,就可以直接判断绝对值 */ +#endif + { + *p_temp_ret = 1; + } + /* 校验bio/rctick是否卡死且不为0 */ + if( ++fill_index >=CHECK_BUFF_SIZE ) + { + fill_index=0; + fiil_mark=1; + } + if( fiil_mark ) + { + for( i=0; iextra_result.bioext_enwork||0==sample_info_handle->extra_result.bioinn_enwork ) + { + check_ret++;break; /* bio未使能,忽略++ */ + } + if( check_innbio_buff[i]!=check_innbio_buff[i+1]||check_extbio_buff[i]!=check_extbio_buff[i+1] ) + { + check_ret++;break; /* bio未卡死,通过++ */ + } + } + for( i=0; iparam_read_finished_sync = 0; + drv_info_handle->fifo_read_finished_sync = 0; + drv_info_handle->event_read_finished_sync = 0; + drv_info_handle->fifo_read_data_valid = 0; + +#if 1 + unsigned char config_debug_reg[32] = {0}; + unsigned char debug_index = 0; + vc921x_read_register(0x40, config_debug_reg, 32); + VCARE_DBG_LOG("[0x40]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x48]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x50]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); + debug_index += 8; + VCARE_DBG_LOG("[0x58]0x%02x,0x%02x,0x%02x,0x%02x 0x%02x,0x%02x,0x%02x,0x%02x", config_debug_reg[0 + debug_index], config_debug_reg[1 + debug_index], config_debug_reg[2 + debug_index], config_debug_reg[3 + debug_index], + config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]); +#endif + return 0; +} diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c new file mode 100644 index 000000000..477d9eee4 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_hal.c @@ -0,0 +1,75 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-03-13 15:08:38 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-16 16:40:25 + * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.c + * @Description: + * + * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. + */ + +#include +#include +#include +#include +#include +#include "pm_control.h" +#include "vc921x_user_app.h" + +static vcare_ppg_device_t *vc921x_device = NULL; + +void ppg_send_cmd_to_vc921x_driver(char* mode, uint8_t enable) +{ + work_mode md = 1; + if (strcmp(mode, "hrs") == 0) { + md = WORK_MODE_HR; + } else if (strcmp(mode, "hrv") == 0) { + md = WORK_MODE_HRV; + } else if (strcmp(mode, "spo2") == 0) { + md = WORK_MODE_SPO2; + } else if (strcmp(mode, "leaklight") == 0) { + md = WORK_MODE_UNDEFINED; + } else if (strcmp(mode, "graycard") == 0) { + md = WORK_MODE_UNDEFINED; + } else if (strcmp(mode, "ledoff") == 0) { + md = WORK_MODE_UNDEFINED; + } else if (strcmp(mode, "wear") == 0) { + md = WORK_MODE_WEAR; + } else if (strcmp(mode, "single") == 0) { + md = WORK_MODE_UNDEFINED; + }else if (strcmp(mode, "factory") == 0) { + md = WORK_MODE_UNDEFINED; + }else if (strcmp(mode, "fpc") == 0) { + md = WORK_MODE_UNDEFINED; + }else if (strcmp(mode, "int") == 0) { + if(vc921x_device) + vc921x_device->ops->dev_irq_handler(0,0); + return; + } + + if (enable == 1) + { + // ppg_service_running_stat = true; + uapi_pm_control(PM_APP_WAKE_NEEDED); + tyhx_poweron(); + + vc921x_device = get_vc921x_device(); + if(!vc921x_device) + { + printf("get_vc921x_device failed !!!\n"); + tyhx_poweroff(); + return; + } + InitParamTypeDef pInit_Param = {0}; + pInit_Param.sampling_gap_time = 400; + pInit_Param.work_mode = md; + vc921x_device->ops->dev_init(&pInit_Param); + + } else { + + uapi_pm_control(PM_APP_WAKE_NONEED); + vc921x_device->ops->stop_work(); + tyhx_poweroff(); + } +} \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_original_data_send.c b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_original_data_send.c new file mode 100644 index 000000000..30e608675 --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_original_data_send.c @@ -0,0 +1,267 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2024-02-26 09:49:05 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +/* system include */ +// #include "os_timer.h" +// #include +// #include "wristband_global_data.h" +// extern RtkWristBandSysType_t RtkWristbandSys; +/* vcare include */ +#include "vcare_device_com.h" +#include "vc921x_sample_result.h" + +static unsigned char ble_buf[2000] = {0}; +static unsigned short int buf_size = 0; +static unsigned short int buf_index = 0; +#define BLE_PACK_SIZE 200 +#define TIMER_BLE_GAP 10 + +static void debug_orginal_data_send(unsigned short int size); +/********************************************************************************************************* + * 调试蓝牙数据格式: + * [0~7]slot0_8bytes + * { + * .[0~2]ppg_data(h,m,l) + * .[3]ppg_mark + * .[4]resistance + * .[5]current + * .[6~7]env_bit14(h,l) + * } + * [ 8~15]slot1_8bytes{...} + * [16~23]slot2_8bytes{...} + * [24~25]bio0_2bytes(h,l) + * [26~27]bio1_2bytes(h,l) + * [28~29]ps_slot3_2bytes(h,l) + * [30~35]gsensorx/y/z(h,l) or tempRefADC, tempExtADC, temperature + * [36]hr + * [37]spo2 + * [38]algo_mode + * [39]wear_bioret(bit7) | algoret(bit6) | acceret(bit5) | wear_drv(bit3~bit0) + * + * #define FRAME_SIZE 40 + *********************************************************************************************************/ +#define ORIGINAL_DATA_DEBUG_ENABLE (1) +#if ORIGINAL_DATA_DEBUG_ENABLE + +#define HR_PPG_SLOT 0 +#define IR_PPG_SLOT 1 +#define RD_PPG_SLOT 2 +#define PS_PPG_SLOT 3 +/* 单采样帧字节数 */ +#define FRAME_SIZE 40 + +float vc921x_calc_sample_data_coefficient( unsigned int ppg_data, unsigned char ppg_I, unsigned char ppg_R, unsigned char ppg_bits ); +extern void vc921x_drv_get_wear_detail_result( unsigned char *bio_ret, unsigned char *algo_ret, unsigned char *acce_ret ); + +void vc921x_send_orginal_data(vcare_ppg_device_t *pdev, gsensor_axes *pgsensor, unsigned char ppgsize) +{ + unsigned char i = 0; + unsigned char j = 0; + unsigned char slot_k = 0; + unsigned char psfreq_index = 0; + /* wear all result param */ + unsigned char bio_result=0, algo_result=0, acce_result=0; + vc921x_sample_info_t *presult = (vc921x_sample_info_t *)pdev->result; + memset(ble_buf, 0, sizeof(ble_buf)); + vc921x_drv_get_wear_detail_result( &bio_result, &algo_result, &acce_result ); + unsigned char calc_slot=0; + vc921x_calc_sample_data_coefficient( VC921x_GET_SLOT_SAMPLE_DATA(presult, calc_slot, ppgsize-1), presult->slot_result[calc_slot].slot_current, presult->slot_result[calc_slot].slot_resistance, + presult->adc_resolution ); + + for (i = 0; i < ppgsize; i++) + { + j = 0; + /* 0-23,slot_ppg:3*8=24 */ + for (slot_k = 0; slot_k < 3; slot_k++) + { + ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_SAMPLE_DATA(presult, slot_k, i)>>16)&0xff; + ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_SAMPLE_DATA(presult, slot_k, i)>>8) &0xff; + ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_SAMPLE_DATA(presult, slot_k, i)>>0) &0xff; + + ble_buf[i * FRAME_SIZE + j++] = (presult->adc_resolution-16)/2; + ble_buf[i * FRAME_SIZE + j++] = presult->slot_result[slot_k].slot_resistance; + ble_buf[i * FRAME_SIZE + j++] = presult->slot_result[slot_k].slot_current; + ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[slot_k].env_data >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[slot_k].env_data >> 0) & 0xff; + } + /*24-29 bio:2*2 + ps:2 */ + psfreq_index =(presult->wear_drop_flag)?(i/presult->hold_div):(i / presult->ps_div); + if (presult->extra_result.biofifo_mode != 0) //VC921x_BIO_NOFIFO_PS_SGL + { + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_buffer[psfreq_index] >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_buffer[psfreq_index] >> 0) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_buffer[psfreq_index] >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_buffer[psfreq_index] >> 0) & 0xff; + } + else + { + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_data >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_data >> 0) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_data >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_data >> 0) & 0xff; + } + if (presult->slot_result[2].slot_storefifo) + { + ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_PS_DATA(presult, psfreq_index) >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_PS_DATA(presult, psfreq_index) >> 0) & 0xff; + } + else + { + ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[2].u.ps_data >> 8) & 0xff; + ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[2].u.ps_data >> 0) & 0xff; + } +/* 30-35 xyz:2*3=6*/ +#if 1 + ble_buf[i * FRAME_SIZE + j++] = pgsensor->xData[i] >> 8; + ble_buf[i * FRAME_SIZE + j++] = pgsensor->xData[i] & 0xff; + ble_buf[i * FRAME_SIZE + j++] = pgsensor->yData[i] >> 8; + ble_buf[i * FRAME_SIZE + j++] = pgsensor->yData[i] & 0xff; + ble_buf[i * FRAME_SIZE + j++] = pgsensor->zData[i] >> 8; + ble_buf[i * FRAME_SIZE + j++] = pgsensor->zData[i] & 0xff; +#else /* temp result */ + ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.tempref_data >> 8; + ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.tempref_data & 0xff; + ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp0_data >> 8; + ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp0_data & 0xff; + ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp1_data >> 8; + ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp1_data & 0xff; +#endif + /* 36-spo2,37-hr,38-algo_mode */ + ble_buf[i * FRAME_SIZE + j++] = pdev->heart_rate; + ble_buf[i * FRAME_SIZE + j++] = pdev->spo2; + ble_buf[i * FRAME_SIZE + j++] = pdev->heart_algo_mode; + /* [39]wear_bioret(bit7) | algoret(bit6) | acceret(bit5) | wear_drv(bit3~bit0) */ + ble_buf[i * FRAME_SIZE + j++] = (bio_result<<7)|(algo_result<<6)|(acce_result<<5)| (pdev->wear & 0xf); + } + debug_orginal_data_send(ppgsize * FRAME_SIZE); +} + +#endif + +void vc921x_send_orginal_data_debug_mark_data( void ) +{ + for(int i=0; i= buf_size) + { + return 0; + } + // 判断剩余数据长度是否还需要分包 + residue_size = buf_size - buf_index; + if (residue_size <= BLE_PACK_SIZE) + { + send_data_by_ble(&ble_buf[buf_index], residue_size); + return 0; + } + else + { + send_data_by_ble(&ble_buf[buf_index], BLE_PACK_SIZE); + buf_index += BLE_PACK_SIZE; + return 1; + } +} + +/* 创建软件定时器,如果数据太长通过软件定时器发送 */ +#define TIMER_ID 0xf0 +static void *debug_send_timer = NULL; +static void debug_send_timer_start(void) +{ + if (debug_send_timer) + { + os_timer_restart(&debug_send_timer, TIMER_BLE_GAP); + } +} +static void debug_send_timer_stop(void) +{ + if (debug_send_timer) + { + os_timer_stop(&debug_send_timer); + } +} + +static void debug_send_timer_callback(void *p_handle) +{ + if (timer_send_data_function()) + { + /* 定时器继续循环 */ + os_timer_restart(&debug_send_timer, TIMER_BLE_GAP); + } + else + { + /* 关闭定时器 */ + debug_send_timer_stop(); + } +} + +void vc921x_send_orginal_data_timer_init(void) +{ + // if (debug_send_timer == NULL) + // { + // os_timer_create(&debug_send_timer, "debug_send_timer", TIMER_ID, TIMER_BLE_GAP, false, debug_send_timer_callback); + // } + // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP); + // os_timer_stop(&debug_send_timer); +} + +static void debug_orginal_data_send(unsigned short int size) +{ + buf_index = 0; + buf_size = size; + printf("debug_orginal_data_send = %d", size); +#if 1 + if (buf_size <= BLE_PACK_SIZE) + { + send_data_by_ble(ble_buf, size); + } + else + { + send_data_by_ble(ble_buf, BLE_PACK_SIZE); + buf_index += BLE_PACK_SIZE; + debug_send_timer_start(); + } +#else + for (unsigned char i = 0; i * 8 < size; i++) + { + printf("[%d~%d]:%02x %02x %02x %02x , %02x %02x %02x %02x", i * 8, (i + 1) * 8, + ble_buf[i * 8], ble_buf[i * 8 + 1], ble_buf[i * 8 + 2], ble_buf[i * 8 + 3], ble_buf[i * 8 + 4], ble_buf[i * 8 + 5], ble_buf[i * 8 + 6], ble_buf[i * 8 + 7]); + } +#endif +} diff --git a/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_user_app.c b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_user_app.c new file mode 100644 index 000000000..c6b2281cb --- /dev/null +++ b/code/sdk/zhihui/drivers/ppg/vc921x/src/vc921x_user_app.c @@ -0,0 +1,897 @@ +/********************************************************************************************** + * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved. + * @Author: Tse + * @Date: 2023-09-22 17:39:10 + * @LastEditTime: 2024-04-11 20:38:21 + * @LastEditors: Tse + * @Description: + **********************************************************************************************/ +/* 驱动头文件 */ +#include "vc921x_driver_com.h" +#include "vc921x_sample_result.h" +#include "vc921x_user_app.h" +/* 算法头文件 */ +#include "algo.h" +#include "spo2Algo_16bit.h" +#include "vcSportMotionIntAlgo.h" +#include "custom_utils.h" +#include "custom_utils.h" +#include "pinctrl_porting.h" +#include "hal_gpio.h" +#include "vcare_device_com.h" + +#define VC921X_I2C_BUS I2C_BUS_2 +#define CHIP_I2C_ADDRESS 0x33 + +/* vcare_ppg_device */ +static vcare_ppg_device_t vc921x_dev = {"vc921x", 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0}; +/* G-Sensor Data */ +static gsensor_axes vc921x_gsensor_data = {0}; + +static void vc921x_get_board_gsensor_data(unsigned short int *pgsensor_len, unsigned short int ppg_count); +static unsigned int vc921x_gsensor_actuating_quantity(int x_axis, int y_axis, int z_axis); +static int vc921x_heart_rate_calculate(vcare_ppg_device_t *pdev, unsigned char hr_slot ); +static int vc921x_spo2_calculate(vcare_ppg_device_t *pdev, unsigned char ir_slot, unsigned char red_slot); + + +// S_AGPIO_L26 心率复位 PPG reset +#define GPIO_PIN_PRG_RESET S_AGPIO_L26 +// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚 +#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0 + +void tyhx_poweron(void) +{ + // uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + // uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + // uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_HIGH); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH); + LOS_Mdelay(50); +} +void tyhx_poweroff(void) +{ + // uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO); + // uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT); + // uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_LOW); + + uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO); + uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW); + + LOS_Mdelay(1); +} + +/**************************************************************************** + * @description: 驱动参数保存/读取 + * @param {unsigned int} size + * @return {*} + ****************************************************************************/ +int vc921x_param_write_flash(unsigned char *pdata, unsigned int size) +{ + uapi_save_file_data("/user/userdata/vc921x.bin",pdata,size,"wb"); + return 0; +} +int vc921x_param_read_flash(unsigned char *pdata, unsigned int size) +{ + uapi_get_file_data("/user/userdata/vc921x.bin",pdata,&size); + return 0; +} + +/**************************************************************************** + * @description: 内存申请 + * @param {unsigned int} size + * @return {*} + ****************************************************************************/ +void *vc921x_malloc(unsigned int size) +{ + return malloc(size); +} +/**************************************************************************** + * @description: 内存释放 + * @param {void} *ptr + * @return {*} + ****************************************************************************/ +void vc921x_free(void *ptr) +{ + if (ptr) + { + free(ptr); + } +} +/**************************************************************************** + * @description: + * @param {unsigned char} regaddr + * @param {unsigned char*} pbuf + * @param {unsigned short int} size + * @return {*} + ****************************************************************************/ +int vc921x_read_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size) +{ + custom_i2c_read_regs(CHIP_I2C_ADDRESS, regaddr, 1 , pbuf, size, VC921X_I2C_BUS); + return 0; +} +int vc921x_write_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size) +{ + custom_i2c_write_reg(CHIP_I2C_ADDRESS, regaddr, 1, pbuf, size, VC921X_I2C_BUS); + return 0; +} +unsigned int vc921x_get_cputimer_tick(void) +{ + return uapi_systick_get_count(); +} + +/*********************************************************************************************************/ +/* user gsensor code */ +#define ENABLE_GSENSOR 0 +//#include "module_gsensor_stk8321.h" +//#include "hub_gsensor.h" +const unsigned char arry10[] = {0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12}; +const unsigned char arry20[] = {0, 2, 3, 5, 6, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28}; +static void vc921x_get_board_gsensor_data(unsigned short int *pgsensor_len, unsigned short int ppg_count) +{ + int i = 0; + unsigned char gsensor_len = 0; + memset(&vc921x_gsensor_data, 0, sizeof(vc921x_gsensor_data)); +#if ENABLE_GSENSOR + /* Gsensor精度要求 ReadGsensorFIFO(+-4G11bit or +-8G12bit 256/g) 例如一个fifo周期为1sec,25组ppg数据,需要获取1sec内25组gsensor数据(40ms*25),用于匹配25组ppg信号。 + 如果ppg频率高于ppg频率则对进行抽样处理,以下代码仅参考 */ + AxesRaw_t gsensor_buff[40] = {0}; + stk8321_get_fifo_data(&gsensor_len, gsensor_buff); + VCARE_DBG_LOG("gsensor_len[%d]-ppgsize[%d]", gsensor_len, ppg_count); + if (0 == ppg_count) + { + /* 不抽样 */ + *pgsensor_len = gsensor_len; + for (i = 0; i < *pgsensor_len; i++) + { +#if (BOARD_VERSION == BOARD_NEW_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_X; + vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_Y; + vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z; +#elif (BOARD_VERSION == BOARD_OLD_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_Y; + vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_X; + vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z; +#endif + } + } + /* æ­¤demo中gsensor的采样频率高于ppg采样,所以正常情况下,gsensor的数量一定是大于ppg的数据。特殊情况需要考虑ppg数量大于gsensor数量。需要对gsensor数据进行补长 */ + if ((gsensor_len >= ppg_count) && (ppg_count != 0)) + { + *pgsensor_len = ppg_count; + /* ppglen = 10 抽样 */ + if (10 == ppg_count) + { + for (i = 0; i < ppg_count; i++) + { +#if (BOARD_VERSION == BOARD_NEW_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[arry10[i]].AXIS_X; + vc921x_gsensor_data.yData[i] = gsensor_buff[arry10[i]].AXIS_Y; + vc921x_gsensor_data.zData[i] = gsensor_buff[arry10[i]].AXIS_Z; +#elif (BOARD_VERSION == BOARD_OLD_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[arry10[i]].AXIS_Y; + vc921x_gsensor_data.yData[i] = gsensor_buff[arry10[i]].AXIS_X; + vc921x_gsensor_data.zData[i] = gsensor_buff[arry10[i]].AXIS_Z; +#endif + } + } + else /* ppglen = 20 、25抽样 */ + { + for (i = 0; i < ppg_count; i++) + { +#if (BOARD_VERSION == BOARD_NEW_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[arry20[i]].AXIS_X; + vc921x_gsensor_data.yData[i] = gsensor_buff[arry20[i]].AXIS_Y; + vc921x_gsensor_data.zData[i] = gsensor_buff[arry20[i]].AXIS_Z; +#elif (BOARD_VERSION == BOARD_OLD_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[arry20[i]].AXIS_Y; + vc921x_gsensor_data.yData[i] = gsensor_buff[arry20[i]].AXIS_X; + vc921x_gsensor_data.zData[i] = gsensor_buff[arry20[i]].AXIS_Z; +#endif + } + } + } + else if ((gsensor_len < ppg_count) && (gsensor_len != 0)) /* gsensor不足补全 */ + { + *pgsensor_len = ppg_count; + for (i = 0; i < gsensor_len; i++) + { +#if (BOARD_VERSION == BOARD_NEW_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_X; + vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_Y; + vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z; +#elif (BOARD_VERSION == BOARD_OLD_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_Y; + vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_X; + vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z; +#endif + } + for (i = gsensor_len; i < ppg_count; i++) + { +#if (BOARD_VERSION == BOARD_NEW_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[gsensor_len - 1].AXIS_X; + vc921x_gsensor_data.yData[i] = gsensor_buff[gsensor_len - 1].AXIS_Y; + vc921x_gsensor_data.zData[i] = gsensor_buff[gsensor_len - 1].AXIS_Z; +#elif (BOARD_VERSION == BOARD_OLD_BOARD) + vc921x_gsensor_data.xData[i] = gsensor_buff[gsensor_len - 1].AXIS_Y; + vc921x_gsensor_data.yData[i] = gsensor_buff[gsensor_len - 1].AXIS_X; + vc921x_gsensor_data.zData[i] = gsensor_buff[gsensor_len - 1].AXIS_Z; +#endif + } + } +#endif +} + +/**************************************************************************** + * @description: gsensor判断是否存在运动 + * @param {int} x_axis + * @param {int} y_axis + * @param {int} z_axis + * @return {*} + ****************************************************************************/ +static unsigned int vc921x_gsensor_actuating_quantity(int x_axis, int y_axis, int z_axis) +{ + unsigned int ret_atc = 0; + unsigned int abs_sum_current = 0; + static unsigned int abs_sum_last = 0; + if (x_axis < 0) + { + x_axis = -x_axis; + } + if (y_axis < 0) + { + y_axis = -y_axis; + } + if (z_axis < 0) + { + z_axis = -z_axis; + } + abs_sum_current = x_axis + y_axis + z_axis; + if (abs_sum_last && abs_sum_current) + { + if (((abs_sum_last > abs_sum_current) ? (abs_sum_last - abs_sum_current) : (abs_sum_current - abs_sum_last)) >= 40) + { + VCARE_DBG_LOG("ACTIVE..."); + ret_atc = 1; + } + } + abs_sum_last = abs_sum_current; + vc921x_drv_set_acce_wear_status(&vc921x_dev, ret_atc); + return ret_atc; +} + +/**************************************************************************** + * @description: ppg数据加入心率算法 + * @param {vcare_ppg_device_t} *pdev + * @return {*} + ****************************************************************************/ +static int vc921x_heart_rate_calculate(vcare_ppg_device_t *pdev, unsigned char hr_slot ) +{ + int heartRate = 0; + unsigned char reliability = 0; + AlgoInputData_t algoInputData_t = {0}; + AlgoOutputData_t algoOutputData = {0}; + vc921x_sample_info_t *result_info = NULL; + vc921x_sample_slot_t *result = NULL; + unsigned char adc_param = 0; + int i = 0; + if (!pdev) + { + return -1; + } + heartRate = pdev->heart_rate; + result_info = (vc921x_sample_info_t *)pdev->result; + result = &result_info->slot_result[hr_slot]; /* 驱动中初始化slot0为心率绿光ppg */ + adc_param = (result_info->adc_resolution-16)/2; + for (i = 0; i < result->ppg_num; i++) + { + algoInputData_t.axes.x = vc921x_gsensor_data.xData[i]; + algoInputData_t.axes.y = vc921x_gsensor_data.yData[i]; + algoInputData_t.axes.z = vc921x_gsensor_data.zData[i]; + algoInputData_t.envSample = result->env_data; + algoInputData_t.ppgSample = (adc_param<<24)|VC921x_GET_SLOT_SAMPLE_DATA(result_info, hr_slot, i ); /* 驱动中初始化slot0为心率绿光ppg */ + Algo_Input(&algoInputData_t, 1000 / 25, (AlgoSportMode)pdev->heart_algo_mode, 0, 0); + VCARE_DBG_LOG("mode[%d]-[%d] (%d)ppg=%d, x=%d, y=%d, z=%d \n", pdev->heart_algo_mode, i, adc_param, algoInputData_t.ppgSample&0xffffff, \ + algoInputData_t.axes.x, algoInputData_t.axes.y, algoInputData_t.axes.z); + } + Algo_Output(&algoOutputData); + heartRate = algoOutputData.hrData; + reliability = algoOutputData.reliability; + if (-1 == heartRate) + { + Algo_Init(); + /* call heart algo wear status check,[-1] */ + vc921x_drv_set_algo_wear_status(pdev, heartRate); + VCARE_DBG_LOG("ALGO_STA=-1"); + } + VCARE_DBG_LOG("ALGO-HR[%d][%d]", heartRate, reliability); + return heartRate; +} + +/**************************************************************************** + * @description: 血氧PPG数据加入血氧算法 + * @param {vcare_ppg_device_t} *pdev + * @return {*} + ****************************************************************************/ +static int vc921x_spo2_calculate(vcare_ppg_device_t *pdev, unsigned char red_slot, unsigned char ir_slot) +{ + vc921x_sample_info_t *result_info = NULL; + float spo2CalValue = -1.0f; + int spo2Value = 0; + unsigned char sportFlag = 0; + unsigned char adc_param = 0; + unsigned int ir_ppg_data = 0, red_ppg_data = 0; + if (!pdev) + { + return -1; + } + spo2Value = pdev->spo2; + result_info = (vc921x_sample_info_t *)pdev->result; + adc_param = (result_info->adc_resolution-16)/2; + for (int i = 0; i < result_info->slot_result[ir_slot].ppg_num; i++) + { + red_ppg_data= (adc_param<<24)|VC921x_GET_SLOT_SAMPLE_DATA(result_info, red_slot, i ); + ir_ppg_data = (adc_param<<24)|VC921x_GET_SLOT_SAMPLE_DATA(result_info, ir_slot, i ); + spo2CalValue = vcSpo2Calculate_16bit( red_ppg_data, ir_ppg_data, 1); + sportFlag = vcSportMotionCalculate(vc921x_gsensor_data.xData[i], vc921x_gsensor_data.yData[i], vc921x_gsensor_data.zData[i]); + if (-1 != (int)spo2CalValue && spo2CalValue <= 100 && 0 == sportFlag) + { + spo2Value = (int)spo2CalValue; + } + VCARE_DBG_LOG("[%d](%d) ppg_ir=%d, ppg_red=%d, x=%d, y=%d, z=%d", i, adc_param, \ + ir_ppg_data&0xffffff, red_ppg_data&0xffffff, \ + vc921x_gsensor_data.xData[i], vc921x_gsensor_data.yData[i], vc921x_gsensor_data.zData[i]); + } + VCARE_DBG_LOG("ALGO-SPO2[%d][%f]", (unsigned short int)spo2Value, spo2CalValue); + return spo2Value; +} + +/******************************************************************************************************** + * 温度功能部分,需要进行对数运算,必须包含math库 + ********************************************************************************************************/ +#include "math.h" +/* fix Rref = 10K R */ +#define REF_R 10 +/* NTC parameter */ +#define NTC_B 3380 +#define NTC_T (273.15f + 25) /* 25摄氏度下的绝对温度 */ +#define NTC_R 10 /* 10K */ +/* vc921x parameter */ +const unsigned char vc921x_temperature_current[] = {0, 2, 4, 8, 12, 16, 20, 24}; +static signed short int get_ntc_temperature(float ntc_value) +{ + signed short int temperature = 0; + float tmp = 0.0f; + tmp = 1 / (1 / NTC_T + (log(ntc_value / NTC_R) / NTC_B)) - 273.15f; + temperature = (signed short int)(tmp * 10); + VCARE_DBG_LOG("[CALC_TMP]=%d(%4.2f)", temperature, tmp); + return temperature; +} +static void vc921x_temperature_ntc_calculate(vcare_ppg_device_t *pdev) +{ + unsigned char ext_I = 0; + float ext_R = 0.0f; + vc921x_sample_info_t *presult_t = (vc921x_sample_info_t *)pdev->result; + if(presult_t->extra_result.tempslot1_enwork && presult_t->extra_result.temp1_data && presult_t->extra_result.tempref_data ) + { + /* 采样值转换为电阻值 */ + ext_I = vc921x_temperature_current[presult_t->extra_result.tempslot1_setcur]; + if (0 != ext_I) + { + ext_R = (float)(20 * REF_R * presult_t->extra_result.temp1_data) / (float)(presult_t->extra_result.tempref_data * ext_I); + VCARE_DBG_LOG("ext_R=%f", ext_R); + pdev->temperature1 = get_ntc_temperature(ext_R); + } + } +} + +/********************************************************************************************************* + * USER_API + ********************************************************************************************************/ +/* +!!!只针对[心率/摘配带]模式,其他模式均为自适应固定时间fifo时间,注意修改之前需要确认在使用的配置模式下,fifo不会溢出,否则将无法正确获取数据 +if( vc921x_PS_WORK_FAST_FREQUENCY==1 ) (ms) +{ps=12.5hz: fifotime=800,720,640,560...80} +else +{ps=5hz: fifotime=1000,800,600,400,200} +*/ +/**************************************************************************** + * @description: 初始化IC并启动工作 + * @param {InitParamTypeDef} *pinitconfig + * @return {*} + ****************************************************************************/ +void vc921x_usr_device_init( InitParamTypeDef *pinitconfig ) +{ + // tyhx_poweron(); + int algo_confirm_ret=0; + unsigned short int ppgdiv = 0; + unsigned char psdiv = 0; + unsigned char fifodiv = 0; + unsigned char dropdiv =20; /* drop_sta:ps_freq = ppg_hz/drop_div */ + unsigned char frequency=25; /* default frequency=25hz */ + /* ppg_freq=20K/ppgdiv, ps_freq=ppg_freq/psdiv, fifodiv=psfreq/fifodiv + * fifo_max=192byte. The amount of byte by once sampling must not be greater than fifo_max(192bytes). + */ + extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; /* mcu tick frequency parameter */ + extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; /* factory calibration parameter-hold */ + extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP; /* factory calibration parameter-drop */ + VC921x_CFG_MCU_TICK_FREQUENCY=32000; + VC921x_WEAR_PARAM_BIO_ABS_HOLD=150; /* save_diff*8/10 */ + VC921x_WEAR_PARAM_BIO_ABS_DROP=100; /* save_diff*5/10 */ + + vc921x_dev.workmode = (work_mode)pinitconfig->work_mode; + vc921x_dev.heart_algo_mode = pinitconfig->hr_algo_mode; + switch (pinitconfig->work_mode) + { + case WORK_MODE_HR: + case WORK_MODE_SPO2: + case WORK_MODE_WEAR: + case WORK_MODE_FACTORY0: + case WORK_MODE_FACTORY1: + case WORK_MODE_UNDEFINED: + case WORK_MODE_HRSPO2: + frequency=25; + break; + case WORK_MODE_STRESS: + frequency=50; + break; + case WORK_MODE_HRV: + case WORK_MODE_BLOODPRESSURE: + frequency=100; + break; + default: + break; + } + ppgdiv = 20000 / frequency; /* ppg_freq = frequency */ +#if (VC921x_PS_WORK_FREQUENCY_CONFIG==1) + psdiv = pinitconfig->sampling_gap_time*25/1000; /* 520ms ~ ps_div=13, fifo_div=1, 注意设置初始化参数的时间时,要估算一次fifo长度和fifo总长度的关系 */ + fifodiv = 1; + if( WORK_MODE_FACTORY0==pinitconfig->work_mode || WORK_MODE_FACTORY1==pinitconfig->work_mode ) + { + frequency=50; + ppgdiv = 20000 / frequency; + psdiv = pinitconfig->sampling_gap_time*25/1000; /* 注意:别修改psdiv,在有活体的配置里面,会影响活体的时间参数.所以此处通过提高一倍ppg频率,进而加快FAT模式的中断数据更新 */ + fifodiv=1; + } +#elif( VC921x_PS_WORK_FREQUENCY_CONFIG==0 ) /* ps=5hz */ + dropdiv =20; + if (frequency == 25) + { + psdiv = 5; + fifodiv = 4; /* ppg=25hz, psbio=5hz, fifo=1.25hz,fifotime=800ms */ + if( WORK_MODE_SPO2==pinitconfig->work_mode ) + { + fifodiv=2; + } + } + else if (frequency == 50) + { + psdiv = 10; + fifodiv = 2; /* ppg=50hz, psbio=5hz, fifo=2.5hz,fifotime=400ms */ + } + else if (frequency == 100) + { + psdiv = 20; + fifodiv = 1; /* ppg=100hz, psbio=5hz, fifo=5hz, fifotime=200ms */ + } + if( WORK_MODE_HR==pinitconfig->work_mode || WORK_MODE_WEAR==pinitconfig->work_mode ) + { + fifodiv = pinitconfig->sampling_gap_time*50/10000; + } + if( WORK_MODE_HRSPO2==pinitconfig->work_mode ) + { + fifodiv=2; + } + if( WORK_MODE_FACTORY0==pinitconfig->work_mode || WORK_MODE_FACTORY1==pinitconfig->work_mode ) + { + dropdiv = psdiv; + fifodiv=1; + } +#endif + /* 先初始化启动心率芯片 */ + vc921x_drv_init_start_work(&vc921x_dev, pinitconfig->work_mode, ppgdiv, psdiv, fifodiv, dropdiv); + vc921x_dev.dev_work_status = 1; + /* 如果需要保持测试值,比如24h的心率模式,初始化时则不清除记录值心率值,避免初始化后出现一段为0的情况 */ + vc921x_dev.heart_rate = 0; + vc921x_dev.stress=0; + vc921x_dev.hrv = 0; + vc921x_dev.spo2 = 0; + vc921x_dev.blood_pressure=0; + vc921x_dev.ecg=0; + /****** algo_identify_init ******/ + //algo_confirm_ret = Algo_Confirm_init( RtkWristbandSys.SecondCountRTC ); //1704038400 + Algo_Init(); + vcSpo2AlgoInit_16bit(); + vcSportMotionAlgoInit(); + VCARE_DBG_LOG("work_mode=%d,algo_confirm=%d", pinitconfig->work_mode, algo_confirm_ret ); +} + +/**************************************************************************** + * @description: 获取IC及驱动相关参数 + * @param {unsigned char} *pchip_id + * @param {unsigned char} *pvers_id + * @param {char} * + * @param {char} * + * @return {*} + ****************************************************************************/ +void vc921x_usr_get_dev_info(unsigned char *pchip_id, unsigned char *pvers_id, char **drv_name, char **dev_name) +{ + /* pchip_id=0x24, pvers_id=0x10... */ + vc921x_drv_get_hwsw_infomation(drv_name, pchip_id, pvers_id); +} +/**************************************************************************** + * @description: 开始工作 + * @return {*} + ****************************************************************************/ +void vc921x_usr_start_work(void) +{ + vc921x_drv_wakeup_work(&vc921x_dev); + vc921x_dev.dev_work_status = 1; +} +/**************************************************************************** + * @description: 停止工作 + * @return {*} + ****************************************************************************/ +void vc921x_usr_stop_work(void) +{ + vc921x_drv_sleep_work(&vc921x_dev); + vc921x_dev.dev_work_status = 0; +} +/**************************************************************************** + * @description: 软复位 + * @return {*} + ****************************************************************************/ +void vc921x_usr_soft_reset(void) +{ + vc921x_drv_software_reset(&vc921x_dev); + vc921x_dev.dev_work_status = 0; +} +/**************************************************************************** + * @description: 活体IC参数重置校准 + * @return {*} + ****************************************************************************/ +void vc921x_usr_reset_bio_param(void) +{ + vc921x_drv_clear_reset_bio_param(&vc921x_dev); +} +/**************************************************************************** + * @description: 获取佩戴状态 + * @return {*} + ****************************************************************************/ +int vc921x_usr_get_wear_status(void) +{ + if (WEAR_STA_HOLD == vc921x_dev.wear) + { + return 1; + } + return 0; +} +/**************************************************************************** + * @description: 定时器校验当前IC状态,如果发生异常,则重启LDO后初始化 + * @return {*} + ****************************************************************************/ +void vc921x_usr_check_temperature_abnormal(void) +{ + unsigned char check_same_ret = 0, check_freq_ret = 0, check_temp_ret = 0; + unsigned short check_cnt1 = 0, check_cnt2 = 0; + check_same_ret = vc921x_drv_read_check_temperature_abnormal(&vc921x_dev, &check_freq_ret, &check_temp_ret, &check_cnt1, &check_cnt2); + vc921x_temperature_ntc_calculate(&vc921x_dev); + vc921x_sample_info_t *result_info = (vc921x_sample_info_t *)vc921x_dev.result; + VCARE_DBG_LOG("status(%d),psbio_0(%d,%d),cnt=%d,%d,same_ret=%d,freq_ret=%d,temp_ret=%d, temp_ext=%d",vc921x_dev.dev_work_status, + result_info->slot_result[2].u.ps_data, result_info->extra_result.bioext_data, check_cnt1, check_cnt2, + check_same_ret, check_freq_ret, check_temp_ret, vc921x_dev.temperature1); + + if (1 == vc921x_dev.dev_work_status && /* IC处于工作状态 */ + ((result_info->slot_result[2].u.ps_data==0 && (result_info->extra_result.bioext_data==0&&result_info->extra_result.bioext_enwork)) /* ps和bio同时异常,或者RCOSC异常 */ + || (check_cnt1 == 0 && check_cnt2 == 0) + || (1 == check_same_ret) /* bio-cnt其中之一已经不再变化 */ + || (1 == check_freq_ret) /* 频率温度异常 */ + || (1 == check_temp_ret) /* 内部温度异常 */ + || vc921x_dev.temperature1 >= 600)) /* NTC温度异常,如果硬件NC则会固定250 */ + { + /* 1.close ldo, 2.delay(200ms), 3.open ldo, 4.delay(10ms), 5.init_dev */ + //extern void vcare_ldo_power_ctrl(unsigned char onoff); + //vcare_ldo_power_ctrl(0); + //platform_delay_ms(200); + //vcare_ldo_power_ctrl(1); + //platform_delay_ms(10); + vc921x_drv_init_start_work(&vc921x_dev, vc921x_dev.workmode, result_info->ppg_div, result_info->ps_div, result_info->fifo_div, result_info->drop_div); + } +} + +/**************************************************************************** + * @description: 中断事件处理事件 + * @param {unsigned char} heart_algo_mode + * @param {unsigned char} spo2_algo_mode + * @return {*} + ****************************************************************************/ +void vc921x_usr_device_handler( unsigned char heart_algo_mode, unsigned char spo2_algo_mode ) +{ + unsigned short int ppg_num = 0; + unsigned short int gsensor_num = 0; + vc921x_sample_info_t *sample_result_info_ptr = (vc921x_sample_info_t *)vc921x_dev.result; + if( !vc921x_dev.dev_work_status ) return; + VCARE_DBG_LOG("------------------"); + vc921x_dev.heart_algo_mode = heart_algo_mode; + vc921x_dev.spo2_algo_mode = spo2_algo_mode; + vc921x_drv_get_result_handler(&vc921x_dev); + vc921x_dev.wear = vc921x_drv_get_wear_status(&vc921x_dev); + if (vc921x_drv_is_ps_event(&vc921x_dev) || vc921x_drv_is_fifo_event(&vc921x_dev)) + { + //disp_data.wear_sta = vc921x_dev.wear; + //disp_data.disp_bio_val = sample_result_info_ptr->extra_result.bioext_data; + //disp_data.disp_bio_abs = sample_result_info_ptr->extra_result.bioabs_calc; + //VCARE_DBG_LOG("bio_absgap=%d, bioext=%d", disp_data.disp_bio_abs, disp_data.disp_bio_val ); + } + switch (vc921x_dev.workmode) + { + case WORK_MODE_HR: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + ppg_num = sample_result_info_ptr->slot_result[0].ppg_num; + if (ppg_num > 40) + break; + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (gsensor_num) + { + vc921x_gsensor_actuating_quantity(vc921x_gsensor_data.xData[0], vc921x_gsensor_data.yData[0], vc921x_gsensor_data.zData[0]); + } + printf("vc921x_dev.wear : %d \n",vc921x_dev.wear); + if (WEAR_STA_HOLD == vc921x_dev.wear) + { + vc921x_dev.heart_rate = vc921x_heart_rate_calculate(&vc921x_dev, 0); + printf("vc921x_dev.heart_rate : %d \n",vc921x_dev.heart_rate); + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num); + } + else + { + vc921x_dev.heart_rate = 0; + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, (ppg_num?ppg_num:1) ); + Algo_Init(); + } + //disp_data.hr_rate = vc921x_dev.heart_rate; + } + break; + case WORK_MODE_SPO2: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + ppg_num = sample_result_info_ptr->slot_result[1].ppg_num; + if (ppg_num > 40) + break; + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (WEAR_STA_HOLD == vc921x_dev.wear) + { + vc921x_dev.spo2 = vc921x_spo2_calculate(&vc921x_dev, 1, 0); + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num); + } + else + { + vc921x_dev.spo2 = 0; + vcSpo2AlgoInit_16bit(); + vcSportMotionAlgoInit(); + } + printf("vc921x_dev.spo2 : %d \n",vc921x_dev.spo2); + //disp_data.spo2_val = vc921x_dev.spo2; + } + break; + case WORK_MODE_HRV: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + ppg_num = sample_result_info_ptr->slot_result[0].ppg_num; + if (ppg_num > 40) + break; + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (WEAR_STA_HOLD == vc921x_dev.wear) + { /*wear is hold,call_algo_func*/ + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num); + } + else + { /*wear is drop,clear_algo_data*/ + } + } + break; + case WORK_MODE_STRESS: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + ppg_num = sample_result_info_ptr->slot_result[0].ppg_num; + if (ppg_num > 40) + break; + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (WEAR_STA_HOLD == vc921x_dev.wear) + { /*wear is hold,call_algo_func*/ + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num); + } + else + { /*wear is drop,clear_algo_data*/ + } + //disp_data.hr_rate = vc921x_dev.heart_rate; + } + break; + case WORK_MODE_BLOODPRESSURE: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + ppg_num = sample_result_info_ptr->slot_result[0].ppg_num; + if (ppg_num > 40) + break; + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (WEAR_STA_HOLD == vc921x_dev.wear) + { /*wear is hold,call_algo_func*/ + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num); + } + else + { /*wear is drop,clear_algo_data*/ + } + } + break; + case WORK_MODE_WEAR: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (gsensor_num) + { + vc921x_gsensor_actuating_quantity(vc921x_gsensor_data.xData[0], vc921x_gsensor_data.yData[0], vc921x_gsensor_data.zData[0]); + } + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, sample_result_info_ptr->slot_result[2].ppg_num); + } + break; + case WORK_MODE_TEMPERATURE: + vc921x_temperature_ntc_calculate(&vc921x_dev); + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, 1); + //disp_data.temperature_value0 = vc921x_dev.temperature0; + //disp_data.temperature_value1 = vc921x_dev.temperature1; + break; + case WORK_MODE_FACTORY0: + //disp_data.gImx = sample_result_info_ptr->slot_result[0].slot_current; + //disp_data.gPre = sample_result_info_ptr->slot_result[0].u.pre_data; + //disp_data.rImx = sample_result_info_ptr->slot_result[1].slot_current; + //disp_data.rPre = sample_result_info_ptr->slot_result[1].u.pre_data; + //disp_data.ps = sample_result_info_ptr->slot_result[2].u.ps_data; + break; + case WORK_MODE_FACTORY1: + //disp_data.iImx = sample_result_info_ptr->slot_result[0].slot_current; + //disp_data.iPre = sample_result_info_ptr->slot_result[0].u.pre_data; + //disp_data.rImx = sample_result_info_ptr->slot_result[1].slot_current; + //disp_data.rPre = sample_result_info_ptr->slot_result[1].u.pre_data; + break; + case WORK_MODE_HRSPO2: + if (vc921x_drv_is_fifo_event(&vc921x_dev)) + { + ppg_num = sample_result_info_ptr->slot_result[0].ppg_num; + if (ppg_num > 40) + break; + vc921x_get_board_gsensor_data(&gsensor_num, ppg_num); + if (WEAR_STA_HOLD == vc921x_dev.wear) + { + vc921x_dev.heart_rate = vc921x_heart_rate_calculate(&vc921x_dev, 0); + vc921x_dev.spo2 = vc921x_spo2_calculate(&vc921x_dev, 1, 2); + //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num); + } + else + { + vc921x_dev.spo2 = 0; + vcSpo2AlgoInit_16bit(); + vcSportMotionAlgoInit(); + vc921x_dev.heart_rate = 0; + Algo_Init(); + } + //disp_data.spo2_val = vc921x_dev.spo2; + //disp_data.hr_rate = vc921x_dev.heart_rate; + } + break; + case WORK_MODE_UNDEFINED: + break; + default: + break; + } + /* 同步处理数据,清理fifo_buffer内存,为下次采样做准备 */ + vc921x_drv_finished_sync(&vc921x_dev); +} + +static const dev_ops vc921x_ops = + { + .dev_init = vc921x_usr_device_init, + .get_dev_info = vc921x_usr_get_dev_info, + .start_work = vc921x_usr_start_work, + .stop_work = vc921x_usr_stop_work, + .soft_reset = vc921x_usr_soft_reset, + .get_events = NULL, + .set_slot_enable = NULL, + .reset_bio_param = vc921x_usr_reset_bio_param, + .get_wear_status = vc921x_usr_get_wear_status, + .dev_irq_handler = vc921x_usr_device_handler, + .dev_check_temp_error = vc921x_usr_check_temperature_abnormal, +}; + +vcare_ppg_device_t *get_vc921x_device(void) +{ + vc921x_dev.ops = &vc921x_ops; + if (vc921x_drv_memroy_alloc()) + { + return NULL; + } + return &vc921x_dev; +} + +/************************************************************************ + * 以下为MCU外设初始化,任务调用 + * example function task_demo_application + ***********************************************************************/ +#if 0 +/* 系统头文件 */ +#include "os_task.h" +//..... +/* 驱动头文件 */ +#include "task_vcare_demo.h" +#include "vc921x_user_app.h" +/* 心率算法头文件 */ +#include "algo.h" + +#define DEMO_TASK_PRIORITY 2 //!< Task priorities +#define DEMO_TASK_STACK_SIZE 1024 * 3 //!< Task stack size +void *demo_task_handle; //!< APP Task handle +void *demo_queue_handle; +static void board_init(void); +void task_demo_application(void *pvParameters) +{ + T_IO_MSG demo_msg; + AlgoSportMode demo_heart_algo_mode = SPORT_TYPE_NORMAL; + unsigned char demo_spo2_algo_mode = 0; + InitParamTypeDef init_config={ 800, WORK_MODE_HR }; + vcare_ppg_device_t *ppg_dev = NULL; + os_msg_queue_create(&demo_queue_handle, 0x10, sizeof(T_IO_MSG)); + /* 通过芯片固定的id寄存器去获取ID,辨别不同的ppg设备,并且获取对应的设备对象 */ + unsigned char id0=0,id1=0; + i2c_read(0x00,&id0,1); + i2c_read(0x01,&id1,1); + if( id0==0x24) /* id0=0x24 */ + { + ppg_dev = get_vc921x_device(); + } + if( ppg_dev ) + { + board_init(); + init_config.work_mode = WORK_MODE_HR; + //init_config.work_mode = WORK_MODE_SPO2; + //init_config.work_mode = WORK_MODE_HRV; + //init_config.work_mode = WORK_MODE_BLOODPRESSURE; + //init_config.work_mode = WORK_MODE_WEAR; + //init_config.work_mode = WORK_MODE_TEMPERATURE; + //init_config.work_mode = WORK_MODE_FACTORY0; + //init_config.work_mode = WORK_MODE_FACTORY1; + ppg_dev->ops->dev_init( &init_config ); + } + while (1) + { + if (os_msg_recv(demo_queue_handle, &demo_msg, 0xFFFFFFFF) == true) + { + switch (demo_msg.subtype) + { + case DEMO_MSG_VC_IRQ_EVENT: + ppg_dev->ops->dev_irq_handler( demo_heart_algo_mode, demo_spo2_algo_mode ); + break; + case DEMO_MSG_KEY_IRQ_EVENT: + //调用初始化切换工作模式,调用ppg_dev->ops->dev_init(...)进行模式切换 + //demo_work_mode_switch(); + break; + case DEMO_MSG_ERR_IRQ: + ppg_device->ops->dev_check_temp_error(); /* 定时校验IC工作状态,并处理异常 */ + break; + default: + break; + } + } + } /* while(1) */ +} + +void task_demo_creat(void) +{ + //example app creat + if (os_task_create(&demo_task_handle, "demo", task_demo_application, NULL, DEMO_TASK_STACK_SIZE, DEMO_TASK_PRIORITY) != true) + { + VCARE_DBG_LOG(" demo_task creat is failed\r\n "); + } +} + +#endif /* end of example function */ diff --git a/code/sdk/zhihui/drivers/rotary_encoder/CMakeLists.txt b/code/sdk/zhihui/drivers/rotary_encoder/CMakeLists.txt index ff6488d05..4b6e69cd2 100644 --- a/code/sdk/zhihui/drivers/rotary_encoder/CMakeLists.txt +++ b/code/sdk/zhihui/drivers/rotary_encoder/CMakeLists.txt @@ -18,15 +18,16 @@ SUPPORT_AT_HX3507 ) else() set(SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/hx3507/hx3507.c - ${CMAKE_CURRENT_SOURCE_DIR}/hx3507/hx3507_hal.c - ${CMAKE_CURRENT_SOURCE_DIR}/hx3507/hx3507_at_cmd.c + ${CMAKE_CURRENT_SOURCE_DIR}/hx3509/tyhx_OTS_hx3509_custom.c + ${CMAKE_CURRENT_SOURCE_DIR}/hx3509/hx3509_hal.c + ${CMAKE_CURRENT_SOURCE_DIR}/hx3509/hx3509_at_cmd.c ) set(PUBLIC_HEADER - ${CMAKE_CURRENT_SOURCE_DIR}/hx3507 + ${CMAKE_CURRENT_SOURCE_DIR}/hx3509 ) set(PUBLIC_DEFINES -SUPPORT_AT_HX3507 +SUPPORT_AT_HX3509 + ) endif() diff --git a/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_at_cmd.c b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_at_cmd.c new file mode 100644 index 000000000..0d11aca38 --- /dev/null +++ b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_at_cmd.c @@ -0,0 +1,104 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-18 10:23:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-20 18:45:27 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/rotary_encoder/hx3509/hx3509_at_cmd.c + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ + +// #include "hx3509.h" + + +#include "at_cmd_api.h" +#include "pm_control.h" +#include "debug_print.h" +#include "tyhx_OTS_hx3509_custom.h" +#include "custom_utils.h" + +#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0])) +#define HX3509_MAX_ARGC 8 +#define HX3509_MAX_ARGV_LEN 64 + +#define HX3509_SUCCESS 0 +#define HX3509_FAILED (-1) + +static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen, + uint8_t argv[HX3509_MAX_ARGC][HX3509_MAX_ARGV_LEN], uint32_t* argc) +{ + uint32_t pos = 0; + *argc = 0; + + for (uint32_t i = 0; i < paraLen; i++) { + if ((para[i] == ' ' || para[i] == '\n') && pos != 0) { + argv[*argc][pos] = '\0'; + *argc += 1; + pos = 0; + if (*argc >= HX3509_MAX_ARGC) { + return HX3509_FAILED; + } + } else { + argv[*argc][pos] = para[i]; + pos++; + if (pos >= HX3509_MAX_ARGV_LEN) { + return HX3509_FAILED; + } + } + } + if (pos != 0) { + *argc += 1; + } + + return HX3509_SUCCESS; +} + +static uint8_t g_hx3509_test_started = 0; +static uint32_t hx3509_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd) +{ + UNUSED(strCommonCmd); + uint8_t argv[HX3509_MAX_ARGC][HX3509_MAX_ARGV_LEN] = { 0 }; + uint32_t argc = 0; + + int ret = ConvertCmdToParam(para, paraLen, argv, &argc); + if (ret != HX3509_SUCCESS) { + PRINT("HX3509TEST ATCMD Convert Command Failed\n"); + return ERRCODE_FAIL; + } + + if (argc != 1) { + PRINT("HX3509TEST ATCMD Set Parameter Failed argc %d\n",argc); + return ERRCODE_FAIL; + } + uint8_t start = (uint8_t)atoi((char*)argv[0]); + if (start == 1) + { + // if (g_hx3509_test_started == 1) + // { + // PRINT("SKIP hx3509test start, already started\r\n"); + // return 0; + // } + ots_init(); + // ots_start(); + g_hx3509_test_started = 1; + }else if (start == 2){ + if (g_hx3509_test_started == 0) + { + PRINT("SKIP hx3509test stop, already stopped\r\n"); + return 0; + } + ots_stop(); + g_hx3509_test_started = 0 ; + }else{ + custom_exit_lpm(); + } + return ERRCODE_SUCC; +} +static const at_cmd_table_t g_hx3509_cmd[] = { + { (char *)"AT^HX3509TEST", hx3509_test, (char *)"1" }, +}; + +at_cmd_table_t *get_hx3509_cmd_table(uint32_t *cmd_count) +{ + *cmd_count = ARRAY_COUNT(g_hx3509_cmd); + return (at_cmd_table_t *)g_hx3509_cmd; +} diff --git a/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_at_cmd.h b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_at_cmd.h new file mode 100644 index 000000000..20eadf83c --- /dev/null +++ b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_at_cmd.h @@ -0,0 +1,40 @@ +/* + * @Author: penglei 1624952103@qq.com + * @Date: 2024-12-18 10:23:22 + * @LastEditors: penglei 1624952103@qq.com + * @LastEditTime: 2024-12-18 10:32:32 + * @FilePath: /sdk615/code/sdk/drivers/peripheral/rotary_encoder/hx3509/hx3509_at_cmd.h + * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE + */ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Provides at cmd register func \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-07-20, Create file. \n + */ +#ifndef HX3509_AT_PROCESS_H +#define HX3509_AT_PROCESS_H + +#include +#include +#include "errcode.h" +#include "soc_osal.h" +#include "at_cmd_api.h" + +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +at_cmd_table_t *get_hx3509_cmd_table(uint32_t *cmd_count); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif diff --git a/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_hal.c b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_hal.c new file mode 100644 index 000000000..3ed4e00f3 --- /dev/null +++ b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_hal.c @@ -0,0 +1,131 @@ +#include "at_cmd_api.h" +#include "pm_control.h" +#include "tyhx_OTS_hx3509_custom.h" +#include "rotary_encoder_def.h" +#include "i2c.h" +#include "debug_print.h" +#include "hal_i2c.h" + +static uint8_t g_hx3509_test_started = 0; +encoder_callback g_encoder_callback = NULL; +uint32_t hx3509_start(void) +{ + if (g_hx3509_test_started == 1) + { + re_print("SKIP hx3509test start, already started\r\n"); + return 0; + } + crown_init(); + crown_start(); + g_hx3509_test_started = 1; + return ERRCODE_SUCC; +} +uint32_t hx3509_stop(void) +{ + if (g_hx3509_test_started == 0) + { + re_print("SKIP hx3509test stop, already stopped\r\n"); + return 0; + } + crown_stop(); + g_hx3509_test_started = 0 ; + return ERRCODE_SUCC; +} + +static ext_errno hx3509_encoder_init(void *attr) +{ + re_print("hx3509_encoder_init\r\n"); + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_deinit(void) +{ + re_print("hx3509_encoder_deinit\r\n"); + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_get_encoderinfo(uint8_t *data, uint8_t data_len) +{ + + if (data_len != sizeof(re_input_event_info)) + return EXT_ERR_NOT_SUPPORT; + re_input_event_info *encoder_info = (re_input_event_info*)data; + int16_t diff = get_crown_result(); + int16_t stand_still = get_stand_still(); + // re_print("hx3509_encoder_get_encoderinfo diff %d stand_still %d\n",diff,stand_still); + if (stand_still == 1 ) + { + encoder_info->re_event = MC_RE_COVER; + }else { + encoder_info->re_event = MC_RE_MOVE; + } + encoder_info->re_event_info.x_axis[0] = diff; + encoder_info->re_event_info.y_axis[0] = diff; + encoder_info->re_event_info.z_axis[0] = diff; + encoder_info->finger_id = 0 ; + encoder_info->point_num = 0 ; + encoder_info->tv_usec = (uint32_t)uapi_tcxo_get_ms(); + //re_print("hx3509_encoder_get_encoderinfo %s rotate %d\r\n",encoder_info->re_event == MC_RE_SLIDE_UP?"MC_RE_SLIDE_UP":"MC_RE_SLIDE_DOWN",diff); + + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_suspend(void) +{ + re_print("hx3509_encoder_suspend\r\n"); + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_resume(void) +{ + re_print("hx3509_encoder_resume\r\n"); + hx3509_start(); + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_sleep(void) +{ + re_print("hx3509_encoder_sleep\r\n"); + hx3509_stop(); + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_reset(void) +{ + re_print("hx3509_encoder_reset\r\n"); + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_encoder_bus_init(void *private_data) +{ + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_register_callback(void *peri_data, encoder_callback func) +{ + re_print("hx3509_register_callback\r\n"); + g_encoder_callback = func; + return EXT_ERR_SUCCESS; +} +static ext_errno hx3509_unregister_callback(void *peri_data) +{ + re_print("hx3509_unregister_callback\r\n"); + g_encoder_callback = NULL; + return EXT_ERR_SUCCESS; +} + +encoder_peripheral_api g_hx3509_api = { + .encoder_init = hx3509_encoder_init, + .encoder_deinit = hx3509_encoder_deinit, + .encoder_get_encoderinfo = hx3509_encoder_get_encoderinfo, + .encoder_suspend = hx3509_encoder_suspend, + .encoder_resume = hx3509_encoder_resume, + .encoder_sleep = hx3509_encoder_sleep, + .encoder_reset = hx3509_encoder_reset, + .encoder_bus_init = hx3509_encoder_bus_init, + .register_callback = hx3509_register_callback, + .unregister_callback = hx3509_unregister_callback, +}; + + +// void *rotary_encoder_get_api(void) +// { +// return ((void *)&g_hx3509_api); +// } + +// void *rotary_encoder_get_peri_attr(void) +// { +// return ((void *)NULL); +// } \ No newline at end of file diff --git a/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_hal.h b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_hal.h new file mode 100644 index 000000000..9401ff04d --- /dev/null +++ b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/hx3509_hal.h @@ -0,0 +1,32 @@ +/** + * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved. \n + * + * Description: Provides at cmd register func \n + * Author: @CompanyNameTag \n + * History: \n + * 2022-07-20, Create file. \n + */ +#ifndef HX3507_HAL_H +#define HX3507_HAL_H + +#include +#include +#include "errcode.h" +#include "soc_osal.h" +#include "rotary_encoder_def.h" +#ifdef __cplusplus +#if __cplusplus +extern "C" { +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +// void *rotary_encoder_get_api(void); +// void *rotary_encoder_get_peri_attr(void); + +#ifdef __cplusplus +#if __cplusplus +} +#endif /* __cplusplus */ +#endif /* __cplusplus */ + +#endif diff --git a/code/sdk/zhihui/drivers/rotary_encoder/hx3509/tyhx_OTS_hx3509_custom.c b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/tyhx_OTS_hx3509_custom.c new file mode 100644 index 000000000..bfc9a9207 --- /dev/null +++ b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/tyhx_OTS_hx3509_custom.c @@ -0,0 +1,687 @@ +/** + * Copyright (c) 2014 - 2022, 南京天易合芯电子有限公司 + * + * All rights reserved. + * + */ + +/***************************************************************************** + * @file TYHX_OTS_HX3509_CUSTOM.C + * @author TYHX team + * @product saker + * @version V0.1 + * @date 2024-2-19 + * @brief 用户平台处理的接口函数 + * @encode WINDOWS ANSI 编码模式可以看中文注释 + +******************************************************************************/ + +#include +#include +#include +#include +#include +#include "tyhx_OTS_hx3509_custom.h" +#include "cmsis_os2.h" +#include "custom_utils.h" +#include "hal_gpio.h" +#include "pinctrl_porting.h" +// #include "tyhx_hrs_custom.h" +//平台头文件包含定义 +#ifdef NORDIC_SDK +//本示例程序NORDIC_SDK采用的SDK版本基于nrf5_sdk16.0.0_98a08e2 +#include "nordic_common.h" +#include "nrf.h" +#include "ble_err.h" +#include "app_timer.h" +#include "nrf_soc.h" +#include "nrf_delay.h" +#include "app_scheduler.h" +#include "nrf_drv_gpiote.h" +#include "nrf_gpio.h" +#include "tyhx_common.h" +#else //other SDK +//include file add by custom +//custom to do here +#endif //NORDIC_SDK + +#define HAISI_SDK + +#ifdef CHIP_HX3509 +//下面是NORDIC平台用到的所有函数,其他平台由用户自行添加 +#ifdef HAISI_SDK +// APP_TIMER_DEF(g_hx3509_timer); //定义OTS 读写间隔定时器 +void ots_timer_handler(void * p_context); + +#define REPORT_MIN 2 // 这个是最小上报角度, 按照平均值预估的值, 由客户定义, 看多大的数据上报给UI处理一次 +static int16_t ots_result = 0;//ots结果 + +bool ots_timer_running = false; //ots定时器是否运行标志 + +static osTimerId_t g_hx3509_timer = NULL; + +/*--------以下为定时函数相关定义 建立/启动/停止定时器//定时中断处理-----------*/ + +/** + * OTS 定时器创建函数 + * @param NULL + */ +void ots_timer_creat(void) +{ + // app_timer_create(&g_hx3509_timer, APP_TIMER_MODE_REPEATED, ots_timer_handler); + g_hx3509_timer = osTimerNew((osTimerFunc_t)ots_timer_handler, osTimerPeriodic, NULL, NULL); +} + +/** + * 定时器start函数 + * @param NULL + */ +void ots_timer_start(void) +{ + if(ots_timer_running == false) + { + // app_timer_start(g_hx3509_timer, APP_TIMER_TICKS(50), NULL);//定义为50ms定时器间隔 + osTimerStart(g_hx3509_timer,50); + ots_timer_running = true; + } +} + +/** + * 定时器stop函数 + * @param timerid 是对应的定时器; + */ +void ots_timer_stop(void) +{ + // app_timer_stop(g_hx3509_timer); + osTimerStop(g_hx3509_timer); + ots_timer_running = false; +} +/** + * 定时器超时处理函数 + * @param p_context 是对应的定时器; + */ +void ots_timer_handler(void * p_context) +{ + //UNUSED_PARAMETER(p_context); + ots_data_handler(NULL,0); +} +/*----------------------以上为定时函数相关定义 建立/启动/停止定时器//定时中断处理---------- +---------------------*/ + +// 定义一个用于检测ACK信号的函数,返回1表示收到ACK,返回0表示未收到ACK +int crown_check_ack(void) +{ + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + LOS_Udelay(COM_DELAY); + + // 将SCLK引脚拉高,以便从设备在这个时钟周期内返回ACK信号(假设ACK在SCLK高电平期间有效) + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + LOS_Udelay(COM_DELAY); + + // 读取SDIO引脚的电平状态,判断是否为低电平(低电平表示收到ACK) + if (uapi_gpio_get_val(PIN_TYHX_SDIO) == GPIO_LEVEL_LOW) { + return 1; // 收到ACK,返回1 + } + + return 0; // 未收到ACK,返回0 +} + +/*---------------------------以下为OTS 的寄存器读写,初始化/开始/结束------------------------*/ +/** + * 通信读寄存器值函数 + * @param regaddr, hx3507的寄存器地址 + * LOS_Udelay(COM_DELAY), 读写函数的delay 按照实际平台调整, HX3507 通信sclk 最高支持1MHZ频率. + * 在最高频率的范围内, 尽量减小delay, 减少定时器周期读取的时间. + */ +uint8_t crown_read_reg(uint8_t deviceAddr, uint8_t regaddr) +{ + uint8_t readvalue = 0; + // 将传入的7位设备地址左移1位,并设置最低位为1表示读操作 + uint8_t addrWithRwBit = (deviceAddr << 1) | 0x00; + // TYHX_LOG("regaddr 0x%x\r\n",regaddr); + + // regaddr &= 0x7f; + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + uapi_tcxo_delay_us(COM_DELAY); + + // 先发送设备地址(包含读写位) + for(int i = 0; i < 8; i++) + { + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + if(addrWithRwBit & 0x80) + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_HIGH); + } + else + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + } + //uapi_tcxo_delay_us(COM_DELAY); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + + addrWithRwBit <<= 1; + // uapi_tcxo_delay_us(COM_DELAY); + } + + // 发送寄存器地址 + for(int i = 0; i < 8; i++) + { + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + if(regaddr & 0x80) + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_HIGH); + } + else + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + } + //uapi_tcxo_delay_us(COM_DELAY); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + + regaddr <<= 1; + // uapi_tcxo_delay_us(COM_DELAY); + } + + // // addrWithRwBit = (0x0 << 1) | 0x01; + + // addrWithRwBit = 0; + // printf("addrWithRwBit :0x%x \n",addrWithRwBit); + + // // 先发送设备地址(包含读写位) + // for(int i = 0; i < 8; i++) + // { + // uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + // if(addrWithRwBit & 0x80) + // { + // uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_HIGH); + // } + // else + // { + // uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + // } + // // uapi_tcxo_delay_us(COM_DELAY); + // uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + + // addrWithRwBit <<= 1; + // // uapi_tcxo_delay_us(COM_DELAY); + // } + + // 开始读操作,HOST要把SDIO从输出端口改为输入端口. + uapi_gpio_set_dir(PIN_TYHX_SDIO,GPIO_DIRECTION_INPUT); + uapi_pin_set_pull(PIN_TYHX_SDIO, (pin_pull_t)HAL_PIO_PULL_UP); + uapi_pin_set_ie(PIN_TYHX_SDIO,HAL_PIO_IE_ENBALE); + // LOS_Udelay(COM_DELAY); + //nrf_gpio_pin_clear(PIN_TYHX_SCLK); + //uapi_tcxo_delay_us(COM_DELAY); + + for(int i = 0; i < 8; i++) + { + readvalue <<= 1; + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + //uapi_tcxo_delay_us(COM_DELAY); + + //uapi_tcxo_delay_us(COM_DELAY); + + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + + if(uapi_gpio_get_val(PIN_TYHX_SDIO)) + { + readvalue |= 0x1; + } + //uapi_tcxo_delay_us(COM_DELAY); + + } + uapi_gpio_set_dir(PIN_TYHX_SDIO,GPIO_DIRECTION_OUTPUT); + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + // TYHX_LOG("readvalue 0x%x\r\n",readvalue); + return readvalue; +} + + +void crown_write_reg(uint8_t deviceAddr, uint8_t regaddr, uint8_t regvalue) +{ + // TYHX_LOG("regaddr 0x%x regvalue : 0x%x\r\n",regaddr,regvalue); + uint16_t writevalue; + // 将7位设备地址左移1位,并设置最低位为0表示写操作 + uint8_t addrWithRwBit = (deviceAddr << 1) | 0x00; + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + LOS_Udelay(COM_DELAY); + + // 先发送设备地址(包含读写位) + for(int i = 0; i < 8; i++) + { + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + if(addrWithRwBit & 0x80) + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_HIGH); + } + else + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + } + //uapi_tcxo_delay_us(COM_DELAY); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + + addrWithRwBit <<= 1; + } + // if (!crown_check_ack()) { + // printf("write check error \n"); + // return ; + // } + + //写通信协议, 最高位置1, 循环16次依次送出寄存器和值,在SCLK的上升沿前准备好数据 + writevalue= (uint16_t)((regaddr|0x80)<<8) + regvalue; + + for(int i=0; i<16; i++) + { + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + if(writevalue & 0x8000) + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_HIGH); + } + else + { + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + + } + //uapi_tcxo_delay_us(COM_DELAY); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + + writevalue<<=1; + } + uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + return; +} + +uint8_t ots_read_reg(uint8_t regaddr) +{ + uint8_t data_buf = 0; + //add by user, i2c read function + // tyhx_read_regs(I2C_DEV_7ADDR,regaddr,&data_buf,1); + // custom_i2c_read_regs(I2C_DEV_7ADDR,regaddr,1,&data_buf,1,HX3509_I2C_BUS); + data_buf = crown_read_reg(I2C_DEV_7ADDR,regaddr); + return data_buf; //返回读到的寄存器值 +} + + +void ots_write_reg(uint8_t regaddr, uint8_t regvalue) +{ + //add by user, i2c write function + // tyhx_write_reg(I2C_DEV_7ADDR,regaddr,®value); + crown_write_reg(I2C_DEV_7ADDR,regaddr,regvalue); + return; +} + +void ots_data_handler(void *p_event_data, uint16_t event_size) +{ + int16_t deltax = 0; + int16_t deltay = 0; + uint8_t sleepstatus = 0; + int16_t result,report = 0; //djd0305 + //TYHX_LOG("[ots_data_handler]\r\n");// + //nrf_gpio_pin_read(PIN_TYHX_MOT)==false 读取到的MOT 管脚为低电平 + // if((ots_read_reg(RA_MOTION_BIT)&0x80)||(nrf_gpio_pin_read(PIN_TYHX_MOT)==false)) + if((ots_read_reg(RA_MOTION_BIT)&0x80)) + { + //X Y的数据必须全部被读出,但是我们只需要X的结果来判断方向和速度 + deltax = ots_read_reg(RA_ACC_DELTA_X_LOW) |(ots_read_reg(RA_ACC_DELTA_X_HIG)<<8); + deltay = ots_read_reg(RA_ACC_DELTA_Y_LOW) |(ots_read_reg(RA_ACC_DELTA_Y_HIG)<<8); + TYHX_LOG("Deltay = %d \r\n",deltay);//djd0305 + //用户添加程序, deltay 是表冠产生数据, 上报给UI, 如果需要数据变化, + // 积攒到一定值再上报UI, 可以调用 ots_result_deal()函数处理. + } + else + { + //debug的时候, 可能用到, 看一下图像质量 + TYHX_LOG("pic qulity =%d, agc num=%d\r\n",ots_read_reg(RA_DATA_2AGC),ots_read_reg(RA_EXP_NUM_SEL)&0x7F); + } +// 下面是三种模式 处理 +#if (defined(MOT_LOW_LEVEL_MODE))//如果低电平中断模式,要读到芯片MOT变高 + if(nrf_gpio_pin_read(PIN_TYHX_MOT))//低电平模式需要数据读空, MOT才会恢复高电平 + { + TYHX_LOG("PIN_TYHX_MOT is high \r\n");//MOT 变高后关闭读定时器 + ots_timer_stop(); + } +#endif + +#if (defined(MOT_FALLINGTRI_MODE))//脉冲模式中断 + if(nrf_gpio_pin_read(PIN_TYHX_MOT))//读完数据, MOT应该会恢复默认电平 + { + TYHX_LOG("ots mot is cleared\r\n");//HX3509进入sleep后关闭定时器 + } +#endif +//如果是MOT_NO_USE_MODE , 由用户程序处理,在不需要芯片时候关闭读50ms定时器 + + +} + +//MOT 中断处理程序, 这个是根据平台程序处理, 用户可以自行修改 +//这里加中断发生标志位或者把中断处理推送到其他任务队列, +// 不建议在中断处理函数中加入过多的程序处理 +#if (defined(MOT_LOW_LEVEL_MODE) || defined(MOT_FALLINGTRI_MODE)) +/** + * OTS 初始化,包括IO处理,上电时序,定时器定义等; + * @param 无 +*/ +void ots_mot_init(void) +{ +#if (defined(MOT_LOW_LEVEL_MODE) || defined(MOT_FALLINGTRI_MODE)) + nrf_drv_gpiote_in_config_t config_ots = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); + config_ots.pull = NRF_GPIO_PIN_PULLUP; + nrf_drv_gpiote_in_init(PIN_TYHX_MOT, &config_ots, ots_mot_handler); + nrf_drv_gpiote_in_event_enable(PIN_TYHX_MOT, true); + +#endif +} +void ots_mot_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action) +{ + uint32_t err_code; + bool mothitolow = false; + + nrf_drv_gpiote_in_uninit(PIN_TYHX_MOT); + if (action == NRF_GPIOTE_POLARITY_HITOLO) + { + mothitolow = true;// 下降沿中断有效, NORDIC没有低电平中断。 + nrf_drv_gpiote_in_config_t config_ots = GPIOTE_CONFIG_IN_SENSE_LOTOHI(false); + err_code = nrf_drv_gpiote_in_init(PIN_TYHX_MOT, &config_ots, ots_mot_handler); + APP_ERROR_CHECK(err_code); + config_ots.pull = NRF_GPIO_PIN_PULLUP; + nrf_drv_gpiote_in_event_enable(PIN_TYHX_MOT, true); + } + else + { + mothitolow = false; + nrf_drv_gpiote_in_config_t config_ots = GPIOTE_CONFIG_IN_SENSE_HITOLO(false); + err_code = nrf_drv_gpiote_in_init(PIN_TYHX_MOT, &config_ots, ots_mot_handler); + APP_ERROR_CHECK(err_code); + config_ots.pull = NRF_GPIO_PIN_PULLUP; + nrf_drv_gpiote_in_event_enable(PIN_TYHX_MOT, true); + } + nrf_gpio_pin_latch_clear(PIN_TYHX_MOT); + if(mothitolow) + { + TYHX_LOG("mot interrupt! \r\n"); + mothitolow = false; + //调用读取数据处理函数 + app_sched_event_put(NULL, 0, ots_data_handler); +#ifdef MOT_LOW_LEVEL_MODE + ots_timer_start();//低电平中断需要读空数据, 低电平才会恢复 +#endif + } + +} + + +#endif + +/** + * 通信重新同步函数, 作用是防止因为其他干扰而引起的错乱 + * @param NULL; + */ +void crown_com_resync(void) +{ + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + uapi_tcxo_delay_us(5); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + uapi_tcxo_delay_us(5); + uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_HIGH); + uapi_tcxo_delay_us(5); +} + +/** + * OTS 初始化,包括IO处理,上电时序,定时器定义等; + * @param 无 +*/ +void ots_init(void) +{ + //此时要保证芯片已经正常上电 + // uapi_gpio_set_dir(PIN_TYHX_SDIO,GPIO_DIRECTION_OUTPUT); + + // uapi_gpio_set_val(PIN_TYHX_SDIO,GPIO_LEVEL_LOW); + + // uapi_gpio_set_dir(PIN_TYHX_SCLK,GPIO_DIRECTION_OUTPUT); + + // uapi_gpio_set_val(PIN_TYHX_SCLK,GPIO_LEVEL_LOW); + + // uapi_tcxo_delay_us(COM_DELAY); + // crown_com_resync(); + int i; + for(i=0; i<10; i++)//重复读DEVICE ID 是否等于0X35 + { + if(ots_read_reg(RA_DEFINE_PART_ID) == 0x35) + { + TYHX_LOG("read chip id is 0x35\r\n",i); + break; + } + else + { + TYHX_LOG("read chip id is 0x%x\r\n",ots_read_reg(RA_DEFINE_PART_ID)); + } + // if(i<7)//读到ID不对, 复位通信 + // { + // crown_com_resync(); + // } + + } + if(i==10) + { + TYHX_LOG("HX3509 communication err, please check\r\n"); + return; + } + + +#if (defined(MOT_LOW_LEVEL_MODE) || defined(MOT_NO_USE_MODE)) + ots_timer_creat(); +#else + ots_mot_init(); +#endif +} +void hx3509l_calibration(void) +{ + uint8_t cali75,cali74; + LOS_Mdelay(2);//必须有这个delay + ots_write_reg(RA_DEBUG_CAS0,0x41); + cali75 = ots_read_reg(0x75); + cali74 = ots_read_reg(0x74); + + if((cali75!=0x84) || (cali74 < 0x42)) + { + ots_write_reg(RA_DEBUG_CAS0,0x41); + LOS_Mdelay(2); + ots_write_reg(RA_DEBUG_CAS0,0x40); + ots_write_reg(0x78,0x20); + ots_write_reg(0x75,0x84); + ots_write_reg(0x74,0x78); + ots_write_reg(0x73,0x64); + ots_write_reg(0x72,0xBE); + LOS_Mdelay(10); + ots_write_reg(RA_DEBUG_CAS0,0x41); + } +} +/** + * 开启OTS; + * @param NULL +*/ +void ots_start(void) +{ + //bool ret = true; + ots_write_reg(RA_DEBUG_CAS0,0x43); + LOS_Mdelay(2); //delay about 1ms + ots_write_reg(RA_DEBUG_CAS0,0x42); + ots_write_reg(RA_RW_REG_ADDR_60H,0x04); // 通信电压采用1.8V打开这个; + //ots_write_reg(RA_RW_REG_ADDR_60H,0x00); //通信电压采用3.3V打开这个; 也是默认值. + LOS_Mdelay(30); //delay about 30 ms + + ots_write_reg(RA_PRF_NUM_HIG_LOW,0x10); + ots_write_reg(RA_PRF_NUM_HIG_HIG,0x00); + ots_write_reg(RA_NO_MOVE_NUM_HIG_RUN,0x3f); + + ots_write_reg(RA_PRF_NUM_TYP_LOW,0x12);//0x20= 1khz,0x1e = 1.1khz 0x1a = 1.2khz, 0x15 = 1.5khz, + ots_write_reg(RA_PRF_NUM_TYP_HIG,0x00); + + ots_write_reg(RA_PRF_NUM_SLP1_LOW,0x40); + ots_write_reg(RA_PRF_NUM_SLP1_HIG,0x00);//0600 = 46ms,0100 = 8ms,0200 = 16ms 0080 = 4ms + //set slp2 enter time = 0x439*slp1 prf time(0x600*31.25us) + ots_write_reg(RA_NO_MOVE_NUM_SLP1_LOW,0xa8); + ots_write_reg(RA_NO_MOVE_NUM_SLP1_HIG,0x03); + + ots_write_reg(RA_NO_MOVE_NUM_TYP_RUN,0x60); + ots_write_reg(RA_CORR_MAX_EN,0x00); + + //AGC cfg + ots_write_reg(RA_EXP_NUM_SEL,0x90); //agc 0x10=close 0x90=open + ots_write_reg(RA_LED_ISEL_CFG,0x04); //led sel + ots_write_reg(RA_AGC_STEP,0x51); +#if 0// 如果冠轴结构设计摆动角度很大(>5°), 请改成#if 1 + ots_write_reg(RA_Y_HISTORY_CTRL,0xc9); +#endif + ots_write_reg(RA_AGC_EXPECT,0x7a); + ots_write_reg(RA_AGC_THRES_MAX,0x7a+50); + ots_write_reg(RA_AGC_THRES_MIN,0x7a-50); + + ots_write_reg(RA_BUTTON_CTRL,0x0c); + + +#if defined(MOT_LOW_LEVEL_MODE) + ots_write_reg(RA_INT_CTRL,0x17); + //ots_write_reg(RA_RW_REG_ADDR_62H,0x38); +#elif defined(MOT_FALLINGTRI_MODE) + ots_write_reg(RA_INT_CTRL,0x15); + ots_write_reg(RA_INT_WIDTH_POS,0x4e);//设置为50hz 低脉冲为500us的波形 + ots_write_reg(RA_INT_WIDTH_NEG,0x02); + //ots_write_reg(RA_RW_REG_ADDR_62H,0x38); +#elif defined(MOT_NO_USE_MODE) + ots_write_reg(RA_INT_CTRL,0x71); //MOT disable +#endif + ots_write_reg(0x78,0x00); + ots_write_reg(RA_CORR_MAX_15_8,0x03); //02 + ots_write_reg(RA_CORR_MAX_7_0,0x00); //60 + //LOS_Mdelay(10);//delay 10ms + ots_write_reg(RA_OP_MODE,0x1d); + LOS_Mdelay(10); + ots_write_reg(RA_DEBUG_CAS0,0x43); + hx3509l_calibration(); + +#ifdef MOT_NO_USE_MODE // 如果是非中断模式, 初始后, 开启定时器; + ots_timer_start(); +#endif + +} +/** + * 停止OTS 的工作, 并进入power down, 功耗<4uA + * @param NULL +*/ +void ots_stop(void) +{ +#ifdef MOT_NO_USE_MODE + ots_timer_stop(); + ots_result = 0; + ots_timer_stop(); + ots_write_reg(RA_DEBUG_CAS0,0x20); //power down + //LOS_Mdelay(20); + TYHX_LOG("[ots_stop]\r\n"); + +#endif +} +/** + *OTS 进入超低功耗状态, 强行进入SLEEP2模式, 功耗大约<6uA; + * @param NULL +*/ +void ots_ultra_low_power(void) +{ +#ifdef MOT_NO_USE_MODE + ots_result = 0; + ots_timer_stop(); + ots_write_reg(RA_PRF_NUM_SLP2_LOW,0xff); + ots_write_reg(RA_PRF_NUM_SLP2_HIG,0xff); + ots_write_reg(RA_INT_CTRL,0x71); //disable int + + ots_write_reg(RA_OP_MODE,0x5d); + ots_write_reg(RA_DSP_EN,0x01); + ots_write_reg(RA_LED_ISEL_CFG,0x00); + LOS_Mdelay(20); + TYHX_LOG("[ots_ultra_low_power]\r\n"); + +#endif +} + + + + +/** + * OTS 工厂测试函数, 此函数测试chip id, 读efuse, 用于工厂厂测模块调用 + * @param NULL + * 返回值false 检测失败, true检测成功. +*/ +bool ots_factory_test(void) +{ + uint8_t efuse74,efuse75,chip_id,agc_num; + chip_id = ots_read_reg(RA_DEFINE_PART_ID); + efuse75 = ots_read_reg(0x75); + efuse74 = ots_read_reg(0x74); + agc_num = ots_read_reg(RA_EXP_NUM_SEL)&0x7F; + if((chip_id != 0x35)||(efuse75!=0x84) || (efuse74 < 0x42)||(agc_num==0)) + { + TYHX_LOG("chip id = 0x%x, efuse75 = 0x%x,efuse74=0x%x,agc_num=%d \r\n",chip_id, efuse75,efuse74,agc_num);//djd0315 + return false; + } + return true; +} + + +/** + * OTS 的数据结果保存, 结果代表角度 + * @param NULL +*/ +void ots_result_deal(int16_t x) +{ +#if 0// 如果冠轴结构设计摆动角度很大(>5°), 请改成#if 1 + if(abs(x)<=FILTER_MIN ) + return; +#endif + + if(abs(x)>=4 ) + { + ots_result += x/4; //大于等于4的值除以4, 代表角度, 数字4 在匀速转动中大约等于1° + } + else //出值2,3 默认大约为1° + { + if(x>0) + { + ots_result+=1; //2~4 默认一个单位, 1° + } + else + { + ots_result-=1; // + } + } + if(abs(ots_result)>=REPORT_MIN)//最小的值由用户定义, 就是得到值大于一定的值, 再上报UI + { + //OTS结果上报UI, 因为这里是定时读取的函数, 可以把结果上报 + ots_result = 0; + } +} + +#else //其他平台,由用户自行添加上面对应的程序 + +//custom to do here + +#endif + + +/*---------------------------以上为OTS 的寄存器读写,初始化/开始/结束------------------------*/ + +#endif + + diff --git a/code/sdk/zhihui/drivers/rotary_encoder/hx3509/tyhx_OTS_hx3509_custom.h b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/tyhx_OTS_hx3509_custom.h new file mode 100644 index 000000000..a2a464ec4 --- /dev/null +++ b/code/sdk/zhihui/drivers/rotary_encoder/hx3509/tyhx_OTS_hx3509_custom.h @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2014 - 2022, 南京天易合芯电子有限公司 + * + * All rights reserved. + * +*/ + +/*************************************************************************** + * @file TYHX_OTS_hx3509_CUSTOM.h + * @author TYHX team + * @product saker + * @version V0.1 + * @date 2023-11-29; + +****************************************************************************/ +#ifndef _TYHX_OTS_hx3509_CUSTOM_H_ +#define _TYHX_OTS_hx3509_CUSTOM_H_ + +#define CHIP_HX3509 //使用OTS芯片的定义 + +#define I2C_DEV_7ADDR 0x32 //7bit i2c device addr + +#define PIN_TYHX_SDIO S_AGPIO_L12 //custom to do here +#define PIN_TYHX_SCLK S_AGPIO_L13 //custom to do here +/*----------------------以下为用户平台定义区-------------------------------*/ +// #define NORDIC_SDK //NORDIC 52840 +//#define OTHER_SDK // +/*----------------------以上为用户平台定义区-------------------------------*/ + +//MOT管脚使用定义 +//#define MOT_LOW_LEVEL_MODE //MOT使用低电平模式 +//#define MOT_FALLINGTRI_MODE //MOT 使用脉冲模式 +#define MOT_NO_USE_MODE //用户不使用MOT 管脚,推荐模式 + + +#define COM_DELAY 5 // 通信中可能用到的延时 +#define FILTER_MIN 1 // OTS出数, 小于这个的滤掉 + +/*----------------------以下为LOG打印函数, 用户需要改成自己平台的-------------------------------*/ +//log 打印定义 +#define TYHX_LOG_ENABLE +#ifdef TYHX_LOG_ENABLE +#define TYHX_LOG(fmt, ...) \ + do { \ + printf(fmt" ", ##__VA_ARGS__); \ + } while (0) +#else +#define TYHX_LOG(...) +#endif //TYHX_LOG_ENABLE + +/*----------------------以上为LOG打印函数-------------------------------*/ + + +//寄存器定义 +#define RA_DEFINE_PART_ID 0x00 +#define RA_DEFINE_REV_ID 0x01 +#define RA_MOTION_BIT 0x02 +#define RA_OP_MODE 0x03 +#define RA_DSP_EN 0x04 +#define RA_OP_STATUS 0x05 +#define RA_ACC_DELTA_X_LOW 0x06 +#define RA_ACC_DELTA_Y_LOW 0x07 +#define RA_ACC_DELTA_X_HIG 0x08 +#define RA_ACC_DELTA_Y_HIG 0x09 +#define RA_PRF_NUM_HIG_LOW 0x0a +#define RA_PRF_NUM_HIG_HIG 0x0b +#define RA_PRF_NUM_TYP_LOW 0x0c +#define RA_PRF_NUM_TYP_HIG 0x0d +#define RA_PRF_NUM_SLP1_LOW 0x0e +#define RA_PRF_NUM_SLP1_HIG 0x0f +#define RA_PRF_NUM_SLP2_LOW 0x10 +#define RA_PRF_NUM_SLP2_HIG 0x11 +#define RA_NO_MOVE_NUM_HIG_RUN 0x12 +#define RA_NO_MOVE_NUM_TYP_RUN 0x13 +#define RA_NO_MOVE_NUM_SLP1_LOW 0x14 +#define RA_NO_MOVE_NUM_SLP1_HIG 0x15 +#define RA_MOVE_NUM_EXIT_SLP 0x16 +#define RA_EXP_NUM_SEL 0x17 +#define RA_AGC_EXPECT 0x18 +#define RA_AGC_STEP 0x19 +#define RA_AGC_THRES_MAX 0x1a +#define RA_AGC_THRES_MIN 0x1b +#define RA_EXP_NUM_SEL_AGC_MAX 0x1c +#define RA_LED_ISEL_CFG 0x1d +#define RA_CORR_MAX_EN 0x1e +#define RA_CORR_MAX_7_0 0x1f +#define RA_CORR_MAX_15_8 0x20 +#define RA_CORR_DIFF_MIN_7_0 0x21 +#define RA_CORR_DIFF_MIN_9_8 0x22 +#define RA_Y_HISTORY_CTRL 0x23 +#define RA_Y_FRAC_CTRL 0x24 +#define RA_REF_HOLD_CTRL 0x25 +#define RA_MOV_LP_CTRL 0x26 +#define RA_INT_WIDTH_POS 0x27 +#define RA_INT_WIDTH_NEG 0x28 +#define RA_INT_WIDTH_BTN_SLP 0x29 +#define RA_EXIT_SLP_CTRL 0x2a +#define RA_EXIT_SLP_ABS_DELTA_XY_TH 0x2b +#define RA_DELTA_X_OUT_SLP 0x2c +#define RA_DELTA_Y_OUT_SLP 0x2d +#define RA_CORR_DATA_SLP_L 0x2e +#define RA_CORR_DATA_SLP_H 0x2f +#define RA_BUTTON_CTRL 0x30 +#define RA_POLL_NUM 0x31 +#define RA_BTN_HIGH_TH 0x32 +#define RA_BTN_DN_CNT_TH 0x33 +#define RA_BTN_LOW_TH 0x34 +#define RA_BTN_UP_CNT_TH 0x35 +#define RA_BTN_ABS_ACC_Y_THRES 0x36 +#define RA_BTN_PAIR_TIMEOUT 0x37 +#define RA_BTN_UP_DN_CNT 0x38 +#define RA_POLL_ACC_DELTA_X_OUT 0x39 +#define RA_POLL_ACC_DELTA_Y_OUT 0x3a +#define RA_INT_CTRL 0x3b +#define RA_INT_CTRL1 0x3c +#define RA_BURST_TX_DATA 0x40 +#define RA_INDEX_DATA 0x41 +#define RA_COL_DATA_MUX 0x42 +#define RA_DATA_2AGC 0x43 +#define RA_IMG_QA 0x44 +#define RA_SNR 0x45 +#define RA_DELTA_X 0x46 +#define RA_DELTA_Y 0x47 +#define RA_DELTA_Y_FRAC 0x48 +#define RA_DSP_DATA_MUX 0x49 +#define RA_RW_REG_ADDR_60H 0x60 +#define RA_RW_REG_ADDR_61H 0x61 +#define RA_RW_REG_ADDR_62H 0x62 +#define RA_RW_REG_ADDR_63H 0x63 +#define RA_DEBUG_RAM_EN 0x66 +#define RA_DEBUG_RAM_ADDR 0x67 +#define RA_DEBUG_RAM_DATA0 0x68 +#define RA_DEBUG_RAM_DATA1 0x69 +#define RA_DEBUG_RAM_DATA2 0x6a +#define RA_DEBUG_RAM_RDEN 0x6b +#define RA_DEBUG_CAS0 0x6c +#define RA_DEBUG_STATUS0 0x6d +#define RA_DEBUG_STATUS1 0x6e +#define RA_DEBUG_CLK_MISS_CNT 0x6f +#define RA_WRAP_FROM_RDADDR 0x70 +#define RA_WRAP_TO_RDADDR 0x71 +#define RA_DEFINE_MEM_WRDATA_7_0 0x72 +#define RA_DEFINE_MEM_WRDATA_15_8 0x73 +#define RA_DEFINE_MEM_WRDATA_23_16 0x74 +#define RA_DEFINE_MEM_WRDATA_31_24 0x75 +#define RA_MEM_PWE_PULSE_CYCLE_LOW 0x76 +#define RA_MEM_PWE_PULSE_CYCLE_HIG 0x77 +#define RA_MEM_GLOBAL_CTRL 0x78 +#define RA_MEM_MANNUAL_CTRL 0x79 +#define RA_MEM_STATUS 0x7a + + + +//OTS 通信函数 +uint8_t ots_read_reg(uint8_t regaddr); +void ots_write_reg(uint8_t regaddr, uint8_t regvalue); + +//OTS读取数据用的的定时器的 创建/启动/停止/溢出处理函数 +//这个定时器一般定义为50/100ms, 用来定时读取OTS结果数据, 具体见应用文档 +void ots_timer_creat(void);//定时器创建 +void ots_timer_start(void);//定时器启动 +void ots_timer_stop(void);//定时器停止 +void ots_timer_handler(void * p_context);// 定时器中断溢出处理函数 + + +//OTS初始化 +void ots_init(void); +//OTS启动 +void ots_start(void); +//OTS停止 +void ots_stop(void); +//OTS 数据处理 +void ots_data_handler(void *p_event_data, uint16_t event_size); +//OTS MOT 中断初始化 +void ots_mot_init(void); +//OTS MOT 中断响应程序 +#ifdef NORDIC_SDK +void ots_mot_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action); +#endif + + +//把ots读出来的值转换成大概转动的角度,经验值 +void ots_result_deal(int16_t x); + + +//工厂测试模式 +bool ots_factory_test(void); + +#endif //_TYHX__OTS_hx3509_CUSTOM_H diff --git a/code/sdk/zhihui/drivers/rotary_encoder/rotary_encoder_drv.c b/code/sdk/zhihui/drivers/rotary_encoder/rotary_encoder_drv.c index 203298865..4ff5d4159 100644 --- a/code/sdk/zhihui/drivers/rotary_encoder/rotary_encoder_drv.c +++ b/code/sdk/zhihui/drivers/rotary_encoder/rotary_encoder_drv.c @@ -12,6 +12,10 @@ #include "soc_osal.h" #include "rotary_encoder_def.h" #include "input_app.h" + +#ifdef ROTARYENCODER_HX3507 +#include "hx3507_hal.h" +#endif // #if defined(TPTYPE_TMA525B) // #include "tma525b_drv1.h" // #include "tma525b_ctrl.h" @@ -407,8 +411,10 @@ uint32_t re_init(void) struct re_driver_data *redd = NULL; // re_err("re_init ----------1!!!\n"); +#ifdef ROTARYENCODER_HX3507 g_encoder_drv.private_data = rotary_encoder_get_peri_attr(); g_encoder_drv.encoder_api = rotary_encoder_get_api(); +#endif g_encoder_drv.ops = &g_re_status_ops; redd = rotary_encoder_get_driver_data(); redd->queue = re_init_queue(ROTARY_ENCODER_QUEUE_MAX_SIZE); @@ -446,18 +452,21 @@ void rotary_encoder_suspend(void) { /**灭屏,关闭Encoder*/ +#ifdef ROTARYENCODER_HX3507 encoder_peripheral_api *encoder_ptr = rotary_encoder_get_api(); ext_errno ret = encoder_ptr->encoder_sleep(); if (ret != EXT_ERR_SUCCESS) { re_err("encoder sleep ret=0x%x", ret); } - +#endif } void rotary_encoder_resume(void) { +#ifdef ROTARYENCODER_HX3507 /**亮屏,恢复Encoder工作*/ encoder_peripheral_api *encoder_ptr = (encoder_peripheral_api*)rotary_encoder_get_api(); ext_errno ret = encoder_ptr->encoder_resume(); if (ret != EXT_ERR_SUCCESS) { re_err("encoder resume ret=0x%x", ret); } +#endif } void encoder_suspend_for_i2c(void) diff --git a/code/sdk/zhihui/utils/custom_utils.c b/code/sdk/zhihui/utils/custom_utils.c index 4e351c7d7..d2a4dd68e 100644 --- a/code/sdk/zhihui/utils/custom_utils.c +++ b/code/sdk/zhihui/utils/custom_utils.c @@ -2452,7 +2452,9 @@ uint32_t uapi_calendar_recover_date(void) void uapi_ppg_get_id(uint8_t *chip_id) { +#ifdef PPG_HX3695 hx3695_get_id(chip_id); +#endif } #include "hal_i2c.h"