#ifdef CONFIG_OTA_UPDATE_SUPPORT\r
#include "upg.h"\r
#endif\r
+#ifdef SUPPORT_AT_HX3509\r
+#include "hx3509_at_cmd.h"\r
+#endif\r
+#ifdef SUPPORT_AT_LQBP002TA\r
+#include "lqbp_at_cmd.h"\r
+#endif\r
+#ifdef SUPPORT_AT_CHARGE\r
+#include "charge_at_cmd.h"\r
+#endif\r
static void register_at_service(void)\r
{\r
#ifdef SUPPORT_AT_GRAPHIC\r
at_cmd_table_t *rtc_table = get_rtc_cmd_table(&rtc_cmd_count);\r
at_cmd_add_moudle(rtc_table, rtc_cmd_count);\r
#endif\r
+#ifdef SUPPORT_AT_HX3509\r
+ uint32_t hx3509_cmd_count;\r
+ at_cmd_table_t *hx3509_table = get_hx3509_cmd_table(&hx3509_cmd_count);\r
+ at_cmd_add_moudle(hx3509_table, hx3509_cmd_count);\r
+#endif\r
+#ifdef SUPPORT_AT_LQBP002TA\r
+ uint32_t lqbp002ta_cmd_count;\r
+ at_cmd_table_t *lqbp002ta_table = get_lqbp002ta_cmd_table(&lqbp002ta_cmd_count);\r
+ at_cmd_add_moudle(lqbp002ta_table, lqbp002ta_cmd_count);\r
+#endif\r
+#ifdef SUPPORT_AT_CHARGE\r
+ uint32_t charge_cmd_count;\r
+ at_cmd_table_t *charge_table = get_charge_cmd_table(&charge_cmd_count);\r
+ at_cmd_add_moudle(charge_table, charge_cmd_count); \r
+#endif\r
}\r
\r
#ifdef CONFIG_OTA_UPDATE_SUPPORT\r
#include "nv.h"\r
#include "nv_upg.h"\r
\r
+#ifdef ENABLE_LQBP002TA\r
+#include "lqbp_service.h"\r
+#endif\r
+\r
#define EMMC_BASE_ADDR 0x52062000\r
#define TASK_PRIORITY_APP (osPriority_t)(17)\r
#define TICK_TEN_MS (10U)\r
uapi_cywee_service_init();\r
#endif \r
\r
+ #ifdef ENABLE_LQBP002TA\r
+ uapi_lqbp_service_init();\r
+ #endif \r
}\r
#endif\r
\r
'FT_SINGLE_UART',
# 'WEARABLE_LOG_DEBUG',
'SUPPORT_RC_CALIBRATION',
- 'PPG_HX3695',
+ #'PPG_HX3695',
'VIB_USE_PWM',
'CONFIG_PWM_SUPPORT',
# 'ACC_LIS2DOC',
'SUPPORT_AUTO_OTA_SERVER',
'CONFIG_DFX_SUPPORT_DIAG_UP_MACHINE=1',
'TPTYPE_CST86XX',
+ 'PPG_VC9202',
+ 'ROTARYENCODER_HX3507',
'NANDFLASH_DS35X'
],
'ram_component': [
# "hid_service",
"gnss",
"gnss_sample",
- "cywee"
+ "cywee",
+ "lqbp002ta",
+ "ppg_sensor_vc9202",
+ "charge_ic"
],
'image_analysis': False,
'fs_image_path':'evb',
'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',
#自定义配置项,选择硬件及功能参数
'defines': [
'BOARD_W9',
+ 'CFG_FLASH_SIZE=8',
'FT_SINGLE_UART',
'NANDFLASH_F35UQA'
]
'defines': [
'BOARD_W9',
'FT_SINGLE_UART',
+ 'CFG_FLASH_SIZE=8',
'GPIO_POWERON_FLASH',
'NANDFLASH_F35UQA'
]
'FT_SINGLE_UART',
# 'WEARABLE_LOG_DEBUG',
'SUPPORT_RC_CALIBRATION',
- 'PPG_HX3695',
+ #'PPG_HX3695',
'VIB_USE_PWM',
'CONFIG_PWM_SUPPORT',
# 'ACC_LIS2DOC',
'GPS_CAT1_RESET_TEST',
'TPTYPE_CST86XX',
'TEST_4G_UI',
- 'NANDFLASH_F35UQA'
+ 'NANDFLASH_F35UQA',
+ 'PPG_VC921X',
+ 'ROTARYENCODER_HX3509'
],
'ram_component': [
#'baidumapsdk',
# "blemoder",
# "factorytest_service",
# "hid_service",
- "cywee"
+ "cywee",
+ "charge_ic",
+ "ppg_sensor_vc921x",
],
'image_analysis': False,
'fs_image_path':'evb',
#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
{ 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)
{ 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
/**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
};
/**
#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
#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
+
};
/**
* @}
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)
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)
--- /dev/null
+#===============================================================================
+# @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
--- /dev/null
+#include "lqbp002ta.h"\r
+#include "custom_utils.h"\r
+#include "platform_core.h"\r
+\r
+#define LQBP002TA_I2C_BUS I2C_BUS_2\r
+\r
+static struct LQBP002TA_t LQBP002TA = {0};\r
+static struct LQBP002TA_t *p_LQBP002TA = NULL;\r
+\r
+void LQBP002TA_write(uint8_t hwadr, uint8_t regadr, uint8_t val);\r
+uint8_t LQBP002TA_read(uint8_t hwadr, uint8_t regadr);\r
+void LQBP002TA_get_calib_param(void);\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_write\r
+ Description: this function will write data to specofic register through software I2C bus\r
+ Input: uint8_t hwadr hardware I2C address\r
+ uint8_t regadr register address\r
+ uint8_t val write-in value \r
+ Output: \r
+ Return: \r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_write(uint8_t hwadr, uint8_t regadr, uint8_t val)\r
+{\r
+ // SoftI2C_start();\r
+ // SoftI2C_write_byte(hwadr << 1);\r
+ // SoftI2C_write_byte(regadr);\r
+ // SoftI2C_write_byte(val);\r
+ // SoftI2C_stop();\r
+ custom_i2c_write_reg(hwadr, regadr, 1, &val, 1, LQBP002TA_I2C_BUS);\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_read\r
+ Description: this function will read register data through software I2C bus\r
+ Input: uint8_t hwadr hardware I2C address\r
+ uint8_t regadr register address \r
+ Output: \r
+ Return: uint8_t readout value\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+uint8_t LQBP002TA_read(uint8_t hwadr, uint8_t regadr)\r
+{\r
+ uint8_t val = 0;\r
+ // SoftI2C_start();\r
+ // SoftI2C_write_byte(hwadr << 1);\r
+ // SoftI2C_write_byte(regadr);\r
+ // SoftI2C_start();\r
+ // SoftI2C_write_byte((hwadr << 1)|0x01);\r
+ // val = SoftI2C_read_byte(1);\r
+ // SoftI2C_stop();\r
+ custom_i2c_read_regs(hwadr, regadr, 1, &val, 1, LQBP002TA_I2C_BUS);\r
+ return val;\r
+}\r
+\r
+void read_chip_id(void)\r
+{\r
+ p_LQBP002TA->chip_id = LQBP002TA_read(HW_ADR, 0x0D);\r
+ //printf("check chip id =0x%x\n",p_LQBP002TA->chip_id);\r
+}\r
+\r
+uint8_t is_LQBP002TA(void)\r
+{ \r
+ if(p_LQBP002TA->chip_id == 0x11)\r
+ return 1;\r
+ else\r
+ return 0; \r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_init\r
+ Description: initialization\r
+ Input: void \r
+ Output: \r
+ Return: void \r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_init(void)\r
+{\r
+ p_LQBP002TA = &LQBP002TA; /* read Chip Id */\r
+ p_LQBP002TA->i32rawPressure = 0;\r
+ p_LQBP002TA->i32rawTemperature = 0;\r
+ // p_LQBP002TA->chip_id = 0x11;\r
+ read_chip_id();\r
+\r
+ LQBP002TA_get_calib_param();\r
+ // sampling rate = 2Hz; Pressure oversample = 4;\r
+ LQBP002TA_rateset(PRESSURE_SENSOR,2, 4); \r
+ // sampling rate = 2Hz; Temperature oversample = 2; \r
+ LQBP002TA_rateset(TEMPERATURE_SENSOR,2, 2);\r
+ //Start background measurement\r
+ \r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_rateset\r
+ Description: set sample rate and over sample rate per second for specific sensor\r
+ Input: uint8_t u8OverSmpl oversample rate Maximal = 128\r
+ uint8_t u8SmplRate sample rate(Hz) Maximal = 128\r
+ uint8_t iSensor 0: Pressure; 1: Temperature \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_rateset(uint8_t iSensor, uint8_t u8SmplRate, uint8_t u8OverSmpl)\r
+{\r
+ uint8_t reg = 0;\r
+ int32_t i32kPkT = 0;\r
+ switch(u8SmplRate)\r
+ {\r
+ case 2:\r
+ reg |= (1<<4);\r
+ break;\r
+ case 4:\r
+ reg |= (2<<4);\r
+ break;\r
+ case 8:\r
+ reg |= (3<<4);\r
+ break;\r
+ case 16:\r
+ reg |= (4<<4);\r
+ break;\r
+ case 32:\r
+ reg |= (5<<4);\r
+ break;\r
+ case 64:\r
+ reg |= (6<<4);\r
+ break;\r
+ case 128:\r
+ reg |= (7<<4);\r
+ break;\r
+ case 1:\r
+ default:\r
+ break;\r
+ }\r
+ switch(u8OverSmpl)\r
+ {\r
+ case 2:\r
+ reg |= 1;\r
+ i32kPkT = 1572864;\r
+ break;\r
+ case 4:\r
+ reg |= 2;\r
+ i32kPkT = 3670016;\r
+ break;\r
+ case 8:\r
+ reg |= 3;\r
+ i32kPkT = 7864320;\r
+ break;\r
+ case 16:\r
+ i32kPkT = 253952;\r
+ reg |= 4;\r
+ break;\r
+ case 32:\r
+ i32kPkT = 516096;\r
+ reg |= 5;\r
+ break;\r
+ case 64:\r
+ i32kPkT = 1040384;\r
+ reg |= 6;\r
+ break;\r
+ case 128:\r
+ i32kPkT = 2088960;\r
+ reg |= 7;\r
+ break;\r
+ case 1:\r
+ default:\r
+ i32kPkT = 524288;\r
+ break;\r
+ }\r
+\r
+ if(iSensor == PRESSURE_SENSOR)\r
+ {\r
+ p_LQBP002TA->i32kP = i32kPkT;\r
+ //printf("i32kP : %d \n",p_LQBP002TA->i32kP);\r
+ LQBP002TA_write(HW_ADR, 0x06, reg);\r
+ if(u8OverSmpl > 8)\r
+ {\r
+ reg = LQBP002TA_read(HW_ADR, 0x09);\r
+ //printf("0x09 : %x \n",reg);\r
+ LQBP002TA_write(HW_ADR, 0x09, reg | 0x04);\r
+ }\r
+ else\r
+ {\r
+ reg = LQBP002TA_read(HW_ADR, 0x09);\r
+ //printf("0x09 : %x \n",reg);\r
+ LQBP002TA_write(HW_ADR, 0x09, reg & (~0x04));\r
+ }\r
+ }\r
+ if(iSensor == TEMPERATURE_SENSOR)\r
+ {\r
+ p_LQBP002TA->i32kT = i32kPkT;\r
+ //printf("i32kT : %d \n",p_LQBP002TA->i32kT);\r
+ if(is_LQBP002TA())\r
+ LQBP002TA_write(HW_ADR, 0x07, reg); \r
+ else\r
+ LQBP002TA_write(HW_ADR, 0x07, reg|0x80); //Using mems temperature \r
+ if(u8OverSmpl > 8)\r
+ {\r
+ reg = LQBP002TA_read(HW_ADR, 0x09);\r
+ //printf("0x09 : %x \n",reg);\r
+ LQBP002TA_write(HW_ADR, 0x09, reg | 0x08);\r
+ }\r
+ else\r
+ {\r
+ reg = LQBP002TA_read(HW_ADR, 0x09);\r
+ //printf("0x09 : %x \n",reg);\r
+ LQBP002TA_write(HW_ADR, 0x09, reg & (~0x08));\r
+ }\r
+ }\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_get_calib_param\r
+ Description: obtain the calibrated coefficient\r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_get_calib_param(void)\r
+{\r
+ uint8_t h;\r
+ uint8_t m;\r
+ uint8_t l;\r
+ h = LQBP002TA_read(HW_ADR, 0x10);\r
+ l = LQBP002TA_read(HW_ADR, 0x11);\r
+ p_LQBP002TA->calib_param.c0 = (int16_t)h<<4 | l>>4;\r
+ p_LQBP002TA->calib_param.c0 = (p_LQBP002TA->calib_param.c0&0x0800)?(0xF000|p_LQBP002TA->calib_param.c0):p_LQBP002TA->calib_param.c0;\r
+ //printf("0x10 : %x \n",h);\r
+ //printf("0x11 : %x \n",l);\r
+ //printf("c0 : %d \n",p_LQBP002TA->calib_param.c0);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x11);\r
+ l = LQBP002TA_read(HW_ADR, 0x12);\r
+\r
+ p_LQBP002TA->calib_param.c1 = (int16_t)(h&0x0F)<<8 | l;\r
+ p_LQBP002TA->calib_param.c1 = (p_LQBP002TA->calib_param.c1&0x0800)?(0xF000|p_LQBP002TA->calib_param.c1):p_LQBP002TA->calib_param.c1;\r
+ //printf("0x11 : %x \n",h);\r
+ //printf("0x12 : %x \n",l);\r
+ //printf("c1 : %d \n",p_LQBP002TA->calib_param.c1);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x13);\r
+ m = LQBP002TA_read(HW_ADR, 0x14);\r
+ l = LQBP002TA_read(HW_ADR, 0x15);\r
+ p_LQBP002TA->calib_param.c00 = (int32_t)h<<12 | (int32_t)m<<4 | (int32_t)l>>4;\r
+ p_LQBP002TA->calib_param.c00 = (p_LQBP002TA->calib_param.c00&0x080000)?(0xFFF00000|p_LQBP002TA->calib_param.c00):p_LQBP002TA->calib_param.c00;\r
+ //printf("0x13 : %x \n",h);\r
+ //printf("0x14 : %x \n",m);\r
+ //printf("0x15 : %x \n",l);\r
+ //printf("c00 : %d \n",p_LQBP002TA->calib_param.c00);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x15);\r
+ m = LQBP002TA_read(HW_ADR, 0x16);\r
+ l = LQBP002TA_read(HW_ADR, 0x17);\r
+ p_LQBP002TA->calib_param.c10 = (int32_t)(h&0x0F)<<16 | (int32_t)m<<8 | l;\r
+ p_LQBP002TA->calib_param.c10 = (p_LQBP002TA->calib_param.c10&0x080000)?(0xFFF00000|p_LQBP002TA->calib_param.c10):p_LQBP002TA->calib_param.c10;\r
+ //printf("0x15 : %x \n",h);\r
+ //printf("0x16 : %x \n",m);\r
+ //printf("0x17 : %x \n",l);\r
+ //printf("c10 : %d \n",p_LQBP002TA->calib_param.c10);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x18);\r
+ l = LQBP002TA_read(HW_ADR, 0x19);\r
+ p_LQBP002TA->calib_param.c01 = (int16_t)h<<8 | l;\r
+ //printf("0x18 : %x \n",h);\r
+ //printf("0x19 : %x \n",l);\r
+ //printf("c01 : %d \n",p_LQBP002TA->calib_param.c01);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x1A);\r
+ l = LQBP002TA_read(HW_ADR, 0x1B);\r
+ p_LQBP002TA->calib_param.c11 = (int16_t)h<<8 | l;\r
+ //printf("0x1A : %x \n",h);\r
+ //printf("0x1B : %x \n",l);\r
+ //printf("c11 : %d \n",p_LQBP002TA->calib_param.c11);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x1C);\r
+ l = LQBP002TA_read(HW_ADR, 0x1D);\r
+ p_LQBP002TA->calib_param.c20 = (int16_t)h<<8 | l;\r
+ //printf("0x1C : %x \n",h);\r
+ //printf("0x1D : %x \n",l);\r
+ //printf("c20 : %d \n",p_LQBP002TA->calib_param.c20);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x1E);\r
+ l = LQBP002TA_read(HW_ADR, 0x1F);\r
+ p_LQBP002TA->calib_param.c21 = (int16_t)h<<8 | l;\r
+ //printf("0x1E : %x \n",h);\r
+ //printf("0x1F : %x \n",l);\r
+ //printf("c21 : %d \n",p_LQBP002TA->calib_param.c21);\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x20);\r
+ l = LQBP002TA_read(HW_ADR, 0x21);\r
+ p_LQBP002TA->calib_param.c30 = (int16_t)h<<8 | l;\r
+ //printf("0x20 : %x \n",h);\r
+ //printf("0x21 : %x \n",l);\r
+ //printf("c30 : %d \n",p_LQBP002TA->calib_param.c30);\r
+\r
+ if(is_LQBP002TA())\r
+ {\r
+ h = LQBP002TA_read(HW_ADR, 0x22);\r
+ l = LQBP002TA_read(HW_ADR, 0x23);\r
+ p_LQBP002TA->calib_param.c31 = (int16_t)h << 4 | l >> 4;\r
+ p_LQBP002TA->calib_param.c31 = (p_LQBP002TA->calib_param.c31 & 0x0800) ? (0xF000 | p_LQBP002TA->calib_param.c31) : p_LQBP002TA->calib_param.c31;\r
+ //printf("0x22 : %x \n",h);\r
+ //printf("0x23 : %x \n",l);\r
+ //printf("c31 : %d \n",p_LQBP002TA->calib_param.c31);\r
+ h = LQBP002TA_read(HW_ADR, 0x23);\r
+ l = LQBP002TA_read(HW_ADR, 0x24);\r
+ p_LQBP002TA->calib_param.c40 = (int16_t)(h & 0x0F) << 8 | l;\r
+ p_LQBP002TA->calib_param.c40 = (p_LQBP002TA->calib_param.c40 & 0x0800) ? (0xF000 | p_LQBP002TA->calib_param.c40) : p_LQBP002TA->calib_param.c40;\r
+ //printf("0x23 : %x \n",h);\r
+ //printf("0x24 : %x \n",l);\r
+ //printf("c40 : %d \n",p_LQBP002TA->calib_param.c40);\r
+ }\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_start_temperature\r
+ Description: start one measurement for temperature\r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_start_temperature(void)\r
+{\r
+ LQBP002TA_write(HW_ADR, 0x08, 0x02);\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_start_pressure\r
+ Description: start one measurement for pressure\r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+\r
+void LQBP002TA_start_pressure(void)\r
+{\r
+ LQBP002TA_write(HW_ADR, 0x08, 0x01);\r
+}\r
+/*****************************************************************************\r
+ Function: LQBP002TA_start_continuous\r
+ Description: Select mode for the continuously measurement\r
+ Input: uint8_t mode 1: pressure; 2: temperature; 3: pressure and temperature \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_start_continuous(uint8_t mode)\r
+{\r
+ LQBP002TA_write(HW_ADR, 0x08, mode+4);\r
+}\r
+\r
+void LQBP002TA_stop(void)\r
+{\r
+ LQBP002TA_write(HW_ADR, 0x08, 0);\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_get_raw_temp\r
+ Description:obtain the original temperature value and turn them into 32bits-integer \r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_get_raw_temp(void)\r
+{\r
+ uint8_t h,m,l;\r
+\r
+ h = LQBP002TA_read(HW_ADR, 0x03);\r
+ m = LQBP002TA_read(HW_ADR, 0x04);\r
+ l = LQBP002TA_read(HW_ADR, 0x05);\r
+ //printf("0x03 : %x \n",h);\r
+ //printf("0x04 : %x \n",m);\r
+ //printf("0x05 : %x \n",l);\r
+\r
+ p_LQBP002TA->i32rawTemperature = (int32_t)h<<16 | (int32_t)m<<8 | (int32_t)l;\r
+ p_LQBP002TA->i32rawTemperature= (p_LQBP002TA->i32rawTemperature&0x800000) ? (0xFF000000|p_LQBP002TA->i32rawTemperature) : p_LQBP002TA->i32rawTemperature;\r
+ //printf("i32rawTemperature : %d \n",p_LQBP002TA->i32rawTemperature);\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_get_raw_pressure\r
+ Description: obtain the original pressure value and turn them into 32bits-integer\r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+void LQBP002TA_get_raw_pressure(void)\r
+{\r
+ uint8_t h,m,l;\r
+ \r
+ h = LQBP002TA_read(HW_ADR, 0x00);\r
+ m = LQBP002TA_read(HW_ADR, 0x01);\r
+ l = LQBP002TA_read(HW_ADR, 0x02);\r
+ //printf("0x00 : %x \n",h);\r
+ //printf("0x01 : %x \n",m);\r
+ //printf("0x02 : %x \n",l);\r
+ p_LQBP002TA->i32rawPressure = (int32_t)h<<16 | (int32_t)m<<8 | (int32_t)l;\r
+ p_LQBP002TA->i32rawPressure= (p_LQBP002TA->i32rawPressure&0x800000) ? (0xFF000000|p_LQBP002TA->i32rawPressure) : p_LQBP002TA->i32rawPressure;\r
+ //printf("i32rawPressure : %d \n",p_LQBP002TA->i32rawPressure);\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_get_temperature\r
+ Description: return calibrated temperature value base on original value.\r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+float LQBP002TA_get_temperature(void)\r
+{\r
+ float fTCompensate;\r
+ volatile float fTsc = (float)p_LQBP002TA->i32rawTemperature / (float)p_LQBP002TA->i32kT;\r
+ //printf("i32rawTemperature : %d , i32kT : %f ,fTsc : %f\n",p_LQBP002TA->i32rawTemperature,(float)p_LQBP002TA->i32kT,fTsc);\r
+ fTCompensate = (float)p_LQBP002TA->calib_param.c0 * 0.5f + ((float)p_LQBP002TA->calib_param.c1) * (float)fTsc;\r
+ //printf("(float)p_LQBP002TA->calib_param.c0 * 0.5f : %f\n",(float)p_LQBP002TA->calib_param.c0 * 0.5f);\r
+ //printf("((float)p_LQBP002TA->calib_param.c1) * fTsc : %f\n",((float)p_LQBP002TA->calib_param.c1) * fTsc);\r
+ //printf("fTsc : %f\n",fTsc);\r
+ printf("fTCompensate : %f\n",fTCompensate);\r
+ return fTCompensate;\r
+}\r
+\r
+/*****************************************************************************\r
+ Function: LQBP002TA_get_pressure\r
+ Description: return calibrated pressure value base on original value.\r
+ Input: void \r
+ Output: \r
+ Return: void\r
+ Calls: \r
+ Called By: \r
+*****************************************************************************/\r
+\r
+float LQBP002TA_get_pressure(void)\r
+{\r
+ float fTsc, fPsc;\r
+ float qua2, qua3;\r
+ float fPCompensate;\r
+\r
+ fTsc = p_LQBP002TA->i32rawTemperature / (float)p_LQBP002TA->i32kT;\r
+ fPsc = p_LQBP002TA->i32rawPressure / (float)p_LQBP002TA->i32kP;\r
+ qua2 = p_LQBP002TA->calib_param.c10 + fPsc * (p_LQBP002TA->calib_param.c20 + fPsc* (p_LQBP002TA->calib_param.c30+ fPsc * p_LQBP002TA->calib_param.c40));\r
+\r
+ if(is_LQBP002TA())\r
+ qua3 = fTsc * fPsc * (p_LQBP002TA->calib_param.c11 + fPsc * (p_LQBP002TA->calib_param.c21+ fPsc * p_LQBP002TA->calib_param.c31));\r
+ else\r
+ qua3 = fTsc * fPsc * (p_LQBP002TA->calib_param.c11 + fPsc * p_LQBP002TA->calib_param.c21);\r
+ fPCompensate = p_LQBP002TA->calib_param.c00 + fPsc * qua2 + fTsc * p_LQBP002TA->calib_param.c01 + qua3;\r
+ printf("fPCompensate : %f\n",fPCompensate);\r
+ return fPCompensate;\r
+}\r
+\r
+uint8_t lqbp002ta_check_exist(void)\r
+{\r
+ read_chip_id();\r
+ return is_LQBP002TA();\r
+}\r
+\r
+void lqbp002ta_start(void)\r
+{\r
+ LQBP002TA_init();\r
+ LQBP002TA_start_continuous(CONTINUOUS_P_AND_T);\r
+}\r
+\r
+void lqbp002ta_check(void)\r
+{\r
+ float fSplTemp = 0.0f;\r
+ float fSplPressure = 0.0f;\r
+ LQBP002TA_get_raw_temp();\r
+ LQBP002TA_get_raw_pressure();\r
+ fSplTemp = LQBP002TA_get_temperature();\r
+ fSplPressure = LQBP002TA_get_pressure();\r
+}\r
+\r
+\r
+void lqbp002ta_stop(void)\r
+{\r
+ LQBP002TA_stop();\r
+}\r
--- /dev/null
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2024-12-16 20:03:01\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2024-12-17 21:05:56\r
+ * @FilePath: /sdk615/code/sdk/drivers/peripheral/LQBP002TA/driver/lqbp002ta.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE;\r
+ */\r
+#ifndef LQBP002TA_H\r
+#define LQBP002TA_H\r
+\r
+#include "stdint.h"\r
+\r
+#define HW_ADR 0x77\r
+#define CONTINUOUS_PRESSURE 1\r
+#define CONTINUOUS_TEMPERATURE 2\r
+#define CONTINUOUS_P_AND_T 3\r
+#define PRESSURE_SENSOR 0\r
+#define TEMPERATURE_SENSOR 1\r
+\r
+\r
+struct LQBP002TA_calib_param_t { \r
+ int16_t c0;\r
+ int16_t c1;\r
+ int32_t c00;\r
+ int32_t c10;\r
+ int16_t c01;\r
+ int16_t c11;\r
+ int16_t c20;\r
+ int16_t c21;\r
+ int16_t c30;\r
+ int16_t c31;\r
+ int16_t c40;\r
+};\r
+\r
+struct LQBP002TA_t { \r
+ struct LQBP002TA_calib_param_t calib_param;/**<calibration data*/ \r
+ uint8_t chip_id; /**<chip id*/ \r
+ int32_t i32rawPressure;\r
+ int32_t i32rawTemperature;\r
+ int32_t i32kP; \r
+ int32_t i32kT;\r
+};\r
+\r
+void LQBP002TA_init(void);\r
+void LQBP002TA_rateset(uint8_t iSensor, uint8_t u8OverSmpl, uint8_t u8SmplRate);\r
+void LQBP002TA_start_temperature(void);\r
+void LQBP002TA_start_pressure(void);\r
+void LQBP002TA_start_continuous(uint8_t mode);\r
+void LQBP002TA_get_raw_temp(void);\r
+void LQBP002TA_get_raw_pressure(void);\r
+float LQBP002TA_get_temperature(void);\r
+float LQBP002TA_get_pressure(void);\r
+\r
+\r
+void lqbp002ta_start(void);\r
+void lqbp002ta_check(void);\r
+void lqbp002ta_stop(void);\r
+uint8_t lqbp002ta_check_exist(void);\r
+\r
+#endif\r
+\r
--- /dev/null
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-12-16 20:49:09
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2024-12-17 14:26:37
+ * @FilePath: /sdk615/code/sdk/drivers/peripheral/LQBP002TA/service/lqbp_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 "lqbp_service.h"
+
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
+#define LQBP002TA_MAX_ARGC 8
+#define LQBP002TA_MAX_ARGV_LEN 64
+
+#define LQBP002TA_SUCCESS 0
+#define LQBP002TA_FAILED (-1)
+
+static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen,
+ uint8_t argv[LQBP002TA_MAX_ARGC][LQBP002TA_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 >= 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;
+}
--- /dev/null
+/*
+ * @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 <stdint.h>
+#include <stdio.h>
+#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
--- /dev/null
+
+#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
--- /dev/null
+/*
+ * @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
--- /dev/null
+#===============================================================================
+# @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()
--- /dev/null
+#include "hp4570.h"\r
+#include "custom_utils.h"\r
+#include "platform_core.h"\r
+\r
+\r
+#define INPUT_PARA_FAIL_RETURN(value, min, max) \\r
+ do { \\r
+ if (value < min || value > max) \\r
+ return INVALID_INPUT; \\r
+ } while (0)\r
+\r
+#define INVALID_INPUT_RETURN(value, index, array, array_size) \\r
+ do { \\r
+ for(index = 0 ; index < array_size; index++){ \\r
+ if(value == array[index]) \\r
+ break; \\r
+ } \\r
+ if(index == array_size) \\r
+ return INVALID_INPUT; \\r
+ } while (0)\r
+\r
+#define SET_BIT(value, mask, code, shift) \\r
+ do { \\r
+ value &= ~mask; \\r
+ value |= (code << shift); \\r
+ } while (0)\r
+\r
+#define SET_ENABLE(en, value, mask, en_code, shift) \\r
+ do { \\r
+ if (en) \\r
+ SET_BIT(value, mask, en_code, shift); \\r
+ else \\r
+ SET_BIT(value, mask, !en_code, shift); \\r
+ } while (0)\r
+\r
+\r
+struct CHIP_STATE{\r
+ bool vin_fault;\r
+ bool tshut;\r
+ bool vbat_ovp;\r
+ bool safety_mode;\r
+ bool ntc_hot;\r
+ bool ntc_cold;\r
+}hp45xxx_chip_state;\r
+\r
+uint8_t hp45xxx_i2c_addr = 0;\r
+\r
+#define SUCCESS 0\r
+#define FAIL 1\r
+#define I2C_ERROR 1\r
+#define INVALID_INPUT 1\r
+\r
+#ifdef BOARD_L22\r
+#define HP4570_I2C_BUS I2C_BUS_0\r
+#elif defined BOARD_U8\r
+#define HP4570_I2C_BUS I2C_BUS_3\r
+#endif\r
+\r
+bool hp45xxx_write_reg(uint8_t reg, uint8_t value)\r
+{\r
+ return custom_i2c_write_reg(hp45xxx_i2c_addr, reg, 1, &value, 1, HP4570_I2C_BUS);\r
+ \r
+}\r
+\r
+bool hp45xxx_read_reg(uint8_t reg, uint8_t *value)\r
+{\r
+ return custom_i2c_read_regs(hp45xxx_i2c_addr, reg, 1, value, 1, HP4570_I2C_BUS);\r
+}\r
+\r
+// Initialize HP4570 chip\r
+bool hp45xxx_init(uint8_t chip_ver){\r
+ switch (chip_ver){\r
+ case HP4570K:\r
+ hp45xxx_i2c_addr = HP4570K_I2C_ADDR;\r
+ break;\r
+ default:\r
+ hp45xxx_i2c_addr = HP45XXX_I2C_ADDR;\r
+ break;\r
+ }\r
+ if(hp45xxx_identify(chip_ver) != SUCCESS)\r
+ {\r
+ printf("hp45xxx_identify(chip_ver) failed !!!! \n");\r
+ return FAIL;\r
+ }\r
+ printf("hp45xxx_identify(chip_ver) succed !!!! \n");\r
+ // hp45xxx_reg_rst();\r
+ // Add initialization code here, such as configuring registers\r
+ hp45xxx_set_ceb_en(true);\r
+ if( hp45xxx_set_chrg_vbat_mV(4012.5) \r
+ // &&\r
+ // hp45xxx_set_chrg_ipre_mA(34) &&\r
+ // hp45xxx_set_chrg_ichg_mA(200) &&\r
+ // hp45xxx_set_chrg_iterm_mA(34) &&\r
+ // hp45xxx_set_iindpm_mA(1000) &&\r
+ // hp45xxx_set_vin_min_mV(3800)\r
+ )\r
+ return SUCCESS;\r
+ return FAIL;\r
+}\r
+\r
+bool hp45xxx_identify(uint8_t chip_ver){\r
+ uint8_t vid_value[2];\r
+ uint8_t pid_value[2];\r
+ uint8_t chip_ver_value;\r
+ hp45xxx_read_reg(HP45XXX_REG_VID_LSB, &vid_value[0]);\r
+ hp45xxx_read_reg(HP45XXX_REG_VID_MSB, &vid_value[1]);\r
+ hp45xxx_read_reg(HP45XXX_REG_PID_LSB, &pid_value[0]);\r
+ hp45xxx_read_reg(HP45XXX_REG_PID_MSB, &pid_value[1]);\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_VER, &chip_ver_value);\r
+ // 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);\r
+ if((vid_value[0]!=HP45XXX_REG_VID_LSB_DEF)||\r
+ (vid_value[1]!=HP45XXX_REG_VID_MSB_DEF)||\r
+ (pid_value[0]!=HP45XXX_REG_PID_LSB_DEF)||\r
+ (pid_value[1]!=HP45XXX_REG_PID_MSB_DEF)||\r
+ (chip_ver_value != chip_ver))\r
+ return FAIL;\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_entry_shipmode(void){\r
+ hp45xxx_set_batfet_dis(true);\r
+}\r
+\r
+void hp45xxx_reg_rst(void){\r
+ // Write 1 will auto be 0\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1, HP45XXX_REG_RST_RESET << HP45XXX_REG_RST_BIT_SHIFT);\r
+}\r
+\r
+void hp45xxx_wdt_rst(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL1, &value);\r
+ // Write 1 will auto be 0 and timer will reset,after watchdog fault,Only write 1 will restart timer\r
+ SET_BIT(value, HP45XXX_WDT_RST_MASK, HP45XXX_WDT_RST_RESET, HP45XXX_WDT_RST_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1,value);\r
+}\r
+\r
+void hp45xxx_vsys_rst(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL5, &value);\r
+ SET_BIT(value, HP45XXX_VSYS_RST_MASK, HP45XXX_VSYS_RST_RESET, HP45XXX_VSYS_RST_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5,value);\r
+}\r
+\r
+bool hp45xxx_set_vindpm_mV(uint16_t voltage){\r
+ uint8_t value;\r
+ uint8_t vin_min_code;\r
+ INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VIN_MIN_MIN_mV,HP45XXX_VIN_MIN_MAX_mV);\r
+ hp45xxx_read_reg(HP45XXX_REG_DPM_SET, &value);\r
+ vin_min_code = (uint8_t)((voltage - HP45XXX_VIN_MIN_OFFSET_mV)/HP45XXX_VIN_MIN_STEP_mV);\r
+ SET_BIT(value, HP45XXX_VIN_MIN_MASK, vin_min_code, HP45XXX_VIN_MIN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_DPM_SET, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_iindpm_mA(uint16_t current){\r
+ uint8_t value;\r
+ uint8_t iindpm_code;\r
+ INPUT_PARA_FAIL_RETURN(current,HP45XXX_IINDPM_MIN_mA,HP45XXX_IINDPM_MAX_mA);\r
+ hp45xxx_read_reg(HP45XXX_REG_DPM_SET, &value);\r
+ iindpm_code = (uint8_t)((current - HP45XXX_IINDPM_OFFSET_mA)/HP45XXX_IINDPM_STEP_mA);\r
+ SET_BIT(value, HP45XXX_IINDPM_MASK, iindpm_code, HP45XXX_IINDPM_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_DPM_SET, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_trst_dgl_mS(uint32_t time){\r
+ uint8_t value;\r
+ uint8_t trst_dgl_code;\r
+ INVALID_INPUT_RETURN(time, trst_dgl_code, hp45xxx_trst_dgl_time, HP45XXX_NUM_TRST_DGL_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value);\r
+ SET_BIT(value, HP45XXX_TRST_DGL_MASK, trst_dgl_code, HP45XXX_TRST_DGL_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_trst_dur_mS(uint16_t time){\r
+ uint8_t value;\r
+ uint8_t trst_dur_code;\r
+ INVALID_INPUT_RETURN(time, trst_dur_code, hp45xxx_trst_dur_time, HP45XXX_NUM_TRST_DUR_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value);\r
+ SET_BIT(value, HP45XXX_TRST_DUR_MASK, trst_dur_code, HP45XXX_TRST_DUR_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0,value);\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_set_hiz_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_HIZ_MASK, HP45XXX_EN_HIZ_ENABLE, HP45XXX_EN_HIZ_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0,value);\r
+}\r
+\r
+void hp45xxx_set_ceb_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value);\r
+ SET_ENABLE(en, value, HP45XXX_CEB_MASK, HP45XXX_CEB_ENABLE, HP45XXX_CEB_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0, value);\r
+}\r
+\r
+bool hp45xxx_set_vbat_uvlo_mV(uint16_t voltage){\r
+ uint8_t value;\r
+ uint8_t vbat_uvlo_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL0, &value);\r
+ INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VBAT_UVLO_MIN_mV,HP45XXX_VBAT_UVLO_MAX_mV);\r
+ vbat_uvlo_code = (uint8_t)((voltage - HP45XXX_VBAT_UVLO_OFFSET_mV)/HP45XXX_VBAT_UVLO_STEP_mV);\r
+ SET_BIT(value, HP45XXX_VBAT_UVLO_MASK, vbat_uvlo_code, HP45XXX_VBAT_UVLO_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL0, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chrg_ichg_mA(uint16_t current){\r
+ uint8_t value;\r
+ uint8_t ichg_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL1, &value);\r
+ INPUT_PARA_FAIL_RETURN(current,HP45XXX_ICHG_MIN_mA,HP45XXX_ICHG_MAX_mA);\r
+ ichg_code = (uint8_t)((current - HP45XXX_ICHG_OFFSET_mA)/HP45XXX_ICHG_STEP_mA);\r
+ SET_BIT(value, HP45XXX_ICHG_MASK, ichg_code, HP45XXX_ICHG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp4570i_set_chrg_ichg_mA(uint16_t current){\r
+ uint8_t value;\r
+ uint8_t ichg_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL1, &value);\r
+ INPUT_PARA_FAIL_RETURN(current,HP4570I_ICHG_MIN_mA,HP4570I_ICHG_MAX_mA);\r
+ ichg_code = (uint8_t)((current - HP4570I_ICHG_OFFSET_mA)/HP4570I_ICHG_STEP_mA);\r
+ SET_BIT(value, HP45XXX_ICHG_MASK, ichg_code, HP45XXX_ICHG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL1, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_ibatfet_ocp_mA(uint16_t current){\r
+ uint8_t value;\r
+ uint8_t ibatfet_ocp_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_IDSG_ITERM_SET, &value);\r
+ INPUT_PARA_FAIL_RETURN(current,HP45XXX_IBATFET_OCP_MIN_mA,HP45XXX_IBATFET_OCP_MAX_mA);\r
+ ibatfet_ocp_code = (uint8_t)((current - HP45XXX_IBATFET_OCP_OFFSET_mA)/HP45XXX_IBATFET_OCP_STEP_mA);\r
+ SET_BIT(value, HP45XXX_IBATFET_OCP_MASK, ibatfet_ocp_code, HP45XXX_IBATFET_OCP_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_IDSG_ITERM_SET,value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chrg_iterm_mA(uint8_t current){\r
+ uint8_t value;\r
+ uint8_t iterm_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_IDSG_ITERM_SET, &value);\r
+ INPUT_PARA_FAIL_RETURN(current,HP45XXX_ITERM_MIN_mA,HP45XXX_ITERM_MAX_mA);\r
+ iterm_code = (uint8_t)((current - HP45XXX_ITERM_OFFSET_mA)/HP45XXX_ITERM_STEP_mA);\r
+ SET_BIT(value, HP45XXX_ITERM_MASK, iterm_code, HP45XXX_ITERM_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_IDSG_ITERM_SET,value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chrg_vbat_mV(float voltage){\r
+ uint8_t value;\r
+ uint8_t vbatreg_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_BAT_VOL_SET, &value);\r
+ INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VBATREG_MIN_mV,HP45XXX_VBATREG_MAX_mV);\r
+ vbatreg_code = (uint8_t)((voltage - HP45XXX_VBATREG_OFFSET_mV)/HP45XXX_VBATREG_STEP_mV);\r
+ SET_BIT(value, HP45XXX_VBATREG_MASK, vbatreg_code, HP45XXX_VBATREG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_BAT_VOL_SET,value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chrg_vpre_mV(uint8_t voltage){\r
+ uint8_t value0;\r
+ uint8_t value1;\r
+ uint8_t vbat_pre_code;\r
+ INVALID_INPUT_RETURN(voltage, vbat_pre_code, hp45xxx_vbat_pre_voltage, HP45XXX_NUM_VBAT_PRE_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_BAT_VOL_SET, value0);\r
+ hp45xxx_read_reg(HP45XXX_REG_VIPRE, value1);\r
+ SET_BIT(value0, HP45XXX_VBAT_PRE_0_MASK, (vbat_pre_code & 0x1), HP45XXX_VBAT_PRE_0_BIT_SHIFT);\r
+ SET_BIT(value1, HP45XXX_VBAT_PRE_1_MASK, (vbat_pre_code & 0x2)>>1, HP45XXX_VBAT_PRE_1_BIT_SHIFT);\r
+ (hp45xxx_write_reg(HP45XXX_REG_BAT_VOL_SET,value0) & hp45xxx_write_reg(HP45XXX_REG_VIPRE,value1));\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chrg_vre_mV(uint8_t voltage){\r
+ uint8_t value;\r
+ uint8_t vre_chg_code;\r
+ INVALID_INPUT_RETURN(voltage, vre_chg_code, hp45xxx_vre_chg_voltage, HP45XXX_NUM_VRE_CHG_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_BAT_VOL_SET, &value);\r
+ SET_BIT(value, HP45XXX_VRE_CHG_MASK, vre_chg_code, HP45XXX_VRE_CHG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_BAT_VOL_SET,value);\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_set_wdt_dsg_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_WDT_DSG_MASK, HP45XXX_EN_WDT_DSG_ENABLE, HP45XXX_EN_WDT_DSG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value);\r
+}\r
+\r
+void hp45xxx_set_wdt_timer_en(bool en){\r
+ uint8_t value;\r
+ uint32_t wdt_timer_code;\r
+ if(!en)\r
+ hp45xxx_set_wdt_timer_mS(HP45XXX_WDT_TIMER_DIS);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ value &= HP45XXX_WDT_TIMER_MASK;\r
+ if(value >> HP45XXX_WDT_TIMER_BIT_SHIFT == HP45XXX_WDT_TIMER_DIS)\r
+ // do nothing\r
+ return;\r
+ wdt_timer_code = (HP45XXX_REG_SYS_CTRL2_DEF & HP45XXX_WDT_TIMER_MASK) >> HP45XXX_WDT_TIMER_BIT_SHIFT;\r
+ SET_BIT(value, HP45XXX_WDT_TIMER_MASK, wdt_timer_code, HP45XXX_WDT_TIMER_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2,value);\r
+}\r
+\r
+bool hp45xxx_set_wdt_timer_mS(uint32_t time){\r
+ uint8_t value;\r
+ uint8_t wdt_timer_code;\r
+ INVALID_INPUT_RETURN(time, wdt_timer_code, hp45xxx_watchdog_time, HP45XXX_NUM_WDT_TIMER_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ SET_BIT(value, HP45XXX_WDT_TIMER_MASK, wdt_timer_code, HP45XXX_WDT_TIMER_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2,value);\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_set_chrg_term_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_TERM_MASK, HP45XXX_EN_TERM_ENABLE, HP45XXX_EN_TERM_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value);\r
+}\r
+\r
+void hp45xxx_set_chrg_timer_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_TIMER_MASK, HP45XXX_EN_TIMER_ENABLE, HP45XXX_EN_TIMER_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value);\r
+}\r
+\r
+bool hp45xxx_set_chrg_timer_hour(uint8_t time){\r
+ uint8_t value;\r
+ uint8_t chg_timer_code;\r
+ INVALID_INPUT_RETURN(time, chg_timer_code, hp45xxx_fast_chg_time, HP45XXX_NUM_CHG_TIMER_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ SET_BIT(value, HP45XXX_CHG_TIMER_MASK, chg_timer_code, HP45XXX_CHG_TIMER_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2,value);\r
+ return SUCCESS;\r
+}\r
+\r
+// when TERM_TMR is enabled, the IC will not suspend the charge current after the charge termination\r
+void hp45xxx_set_chrg_term_tmr(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL2, &value);\r
+ SET_ENABLE(en, value, HP45XXX_TERM_TMR_MASK, HP45XXX_TERM_TMR_ENABLE, HP45XXX_TERM_TMR_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL2, value);\r
+}\r
+\r
+void hp45xxx_set_ntc_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_NTC_EN_MASK, HP45XXX_NTC_EN_ENABLE, HP45XXX_NTC_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+void hp45xxx_set_chrg_tmr2x_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_TMR2X_EN_MASK, HP45XXX_TMR2X_EN_ENABLE, HP45XXX_TMR2X_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+// when set 1, enter ship mode w/o vbus, the bit will be set to 0 after exiting ship mode\r
+bool hp45xxx_set_batfet_dis(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_BATFET_DIS_MASK, HP45XXX_BATFET_DIS_ENABLE, HP45XXX_BATFET_DIS_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_set_int_pg_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_PG_INT_CONTROL_MASK, HP45XXX_PG_INT_CONTROL_ENABLE, HP45XXX_PG_INT_CONTROL_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+void hp45xxx_set_int_chrg_done_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_CHG_DONE_INT_EN_MASK, HP45XXX_CHG_DONE_INT_EN_ENABLE, HP45XXX_CHG_DONE_INT_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+// Include: not charge to CC, Pre into CC ,CC into CV, not charge into CC(Auto recharge)\r
+void hp45xxx_set_int_chrg_stat_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_CHG_STAT_INT_EN_MASK, HP45XXX_CHG_STAT_INT_EN_ENABLE, HP45XXX_CHG_STAT_INT_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+void hp45xxx_set_int_ntc_transition_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_NTC_TRANSITION_EN_MASK, HP45XXX_NTC_TRANSITION_EN_ENABLE, HP45XXX_NTC_TRANSITION_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+void hp45xxx_set_int_batovp_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL3, &value);\r
+ SET_ENABLE(en, value, HP45XXX_BATOVP_INT_EN_MASK, HP45XXX_BATOVP_INT_EN_ENABLE, HP45XXX_BATOVP_INT_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL3, value);\r
+}\r
+\r
+void hp45xxx_set_pcb_otp_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_PCB_OTP_MASK, HP45XXX_EN_PCB_OTP_ENABLE, HP45XXX_EN_PCB_OTP_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4, value);\r
+}\r
+\r
+void hp45xxx_set_vindpm_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value);\r
+ SET_ENABLE(en, value, HP45XXX_VINDPM_EN_MASK, HP45XXX_VINDPM_EN_ENABLE, HP45XXX_VINDPM_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4, value);\r
+}\r
+\r
+bool hp45xxx_set_thermal_reg_degree(uint8_t degree){\r
+ uint8_t value;\r
+ uint8_t thermal_reg_code;\r
+ INVALID_INPUT_RETURN(degree, thermal_reg_code, hp45xxx_thermal_reg_degree, HP45XXX_NUM_THERMAL_REG_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value);\r
+ SET_BIT(value, HP45XXX_THERMAL_REG_MASK, thermal_reg_code, HP45XXX_THERMAL_REG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_vsys_reg_mV(float voltage){\r
+ uint8_t value;\r
+ uint8_t vsys_reg_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL4, &value);\r
+ INPUT_PARA_FAIL_RETURN(voltage,HP45XXX_VSYS_REG_MIN_mV,HP45XXX_VSYS_REG_MAX_mV);\r
+ vsys_reg_code = (uint8_t)((voltage - HP45XXX_VSYS_REG_OFFSET_mV)/HP45XXX_VSYS_REG_STEP_mV);\r
+ SET_BIT(value, HP45XXX_VSYS_REG_MASK, vsys_reg_code, HP45XXX_VSYS_REG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL4,value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_ship_dgl_mS(uint16_t time){\r
+ uint8_t value;\r
+ uint8_t ship_dgl_code;\r
+ INVALID_INPUT_RETURN(time, ship_dgl_code, hp45xxx_ship_dgl_time, HP45XXX_NUM_SHIP_DGL_VAL);\r
+ SET_BIT(value, HP45XXX_SHIP_DGL_MASK, ship_dgl_code, HP45XXX_SHIP_DGL_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_CHIP_STAT1, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_vin_exit_ship_tset_mS(uint16_t time){\r
+ uint8_t value;\r
+ uint8_t in_exit_ship_tset_code;\r
+ INVALID_INPUT_RETURN(time, in_exit_ship_tset_code, hp45xxx_ship_dgl_time, HP45XXX_NUM_IN_EXIT_SHIP_TSET_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_VIPRE, &value);\r
+ SET_BIT(value, HP45XXX_IN_EXIT_SHIP_TSET_MASK, in_exit_ship_tset_code, HP45XXX_IN_EXIT_SHIP_TSET_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_VIPRE, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chrg_ipre_mA(uint16_t current){\r
+ uint8_t value;\r
+ uint8_t ipre_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_VIPRE, &value);\r
+ INPUT_PARA_FAIL_RETURN(current,HP45XXX_IPRE_MIN_mA,HP45XXX_IPRE_MAX_mA);\r
+ ipre_code = (uint8_t)((current - HP45XXX_IPRE_OFFSET_mA)/HP45XXX_IPRE_STEP_mA);\r
+ SET_BIT(value, HP45XXX_IPRE_MASK, ipre_code, HP45XXX_IPRE_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_VIPRE,value);\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_set_rst_vin_entry_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_EXT_CTRL, &value);\r
+ SET_ENABLE(en, value, HP45XXX_VINDPM_EN_MASK, HP45XXX_VIN_ENTRY_RST_EN_ENABLE, HP45XXX_VIN_ENTRY_RST_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_EXT_CTRL, value);\r
+}\r
+\r
+bool hp45xxx_set_chrg_idead_mA(uint16_t current){\r
+ uint8_t value;\r
+ uint8_t ideadbat_code;\r
+ hp45xxx_read_reg(HP45XXX_REG_EXT_CTRL, &value);\r
+ INPUT_PARA_FAIL_RETURN(current,HP45XXX_IDEADBAT_MIN_mA,HP45XXX_IDEADBAT_MAX_mA);\r
+ ideadbat_code = (uint8_t)((current - HP45XXX_IDEADBAT_OFFSET_mA)/HP45XXX_IDEADBAT_STEP_mA);\r
+ SET_BIT(value, HP45XXX_IDEADBAT_MASK, ideadbat_code, HP45XXX_IDEADBAT_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_EXT_CTRL,value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_en_iindpm_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_EXT_CTRL, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_IINDPM_MASK, HP45XXX_EN_IINDPM_ENABLE, HP45XXX_EN_IINDPM_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_key_wk_time_mS(uint16_t time){\r
+ uint8_t value;\r
+ uint8_t key_wk_set_code;\r
+ INVALID_INPUT_RETURN(time, key_wk_set_code, hp45xxx_key_wk_set_time, HP45XXX_NUM_KEY_WK_SET_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL5, &value);\r
+ SET_BIT(value, HP45XXX_KEY_WK_SET_MASK, key_wk_set_code, HP45XXX_KEY_WK_SET_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_t_hiccup_mS(uint16_t time){\r
+ uint8_t value;\r
+ uint8_t t_hiccup_code;\r
+ INVALID_INPUT_RETURN(time, t_hiccup_code, hp45xxx_key_wk_set_time, HP45XXX_NUM_T_HICCUP_VAL);\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL5, &value);\r
+ SET_BIT(value, HP45XXX_T_HICCUP_MASK, t_hiccup_code, HP45XXX_T_HICCUP_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL5, value);\r
+ return SUCCESS;\r
+}\r
+\r
+void hp45xxx_set_wdt_vsys_rst_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL6, &value);\r
+ SET_ENABLE(en, value, HP45XXX_WDT_VSYS_RST_MASK, HP45XXX_WDT_VSYS_RST_ENABLE, HP45XXX_WDT_VSYS_RST_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL6, value);\r
+}\r
+\r
+void hp45xxx_set_ship_dgl_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL6, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_SHIP_DGL_MASK, HP45XXX_EN_SHIP_DGL_ENABLE, HP45XXX_EN_SHIP_DGL_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL6, value);\r
+}\r
+\r
+void hp45xxx_set_wdt_chg_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_WDT_CHG_MASK, HP45XXX_EN_WDT_CHG_ENABLE, HP45XXX_EN_WDT_CHG_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value);\r
+}\r
+\r
+void hp45xxx_set_rst_pwrkey_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value);\r
+ SET_ENABLE(en, value, HP45XXX_EN_PWRKEY_RST_MASK, HP45XXX_EN_PWRKEY_RST_ENABLE, HP45XXX_EN_PWRKEY_RST_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value);\r
+}\r
+\r
+void hp45xxx_set_rst_vsys_wvbus_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value);\r
+ SET_ENABLE(en, value, HP45XXX_VSYS_RST_WVBUS_MASK, HP45XXX_VSYS_RST_WVBUS_ENABLE, HP45XXX_VSYS_RST_WVBUS_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value);\r
+}\r
+\r
+void hp45xxx_set_pwrkey_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value);\r
+ SET_ENABLE(en, value, HP45XXX_PWRKEY_EN_MASK, HP45XXX_PWRKEY_EN_ENABLE, HP45XXX_PWRKEY_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value);\r
+}\r
+\r
+void hp45xxx_set_vbus_wk_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value);\r
+ SET_ENABLE(en, value, HP45XXX_VBUS_WK_EN_MASK, HP45XXX_VBUS_WK_EN_ENABLE, HP45XXX_VBUS_WK_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value);\r
+}\r
+\r
+void hp45xxx_set_pwrkey_wk_en(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_CTRL7, &value);\r
+ if(en){\r
+ SET_BIT(value, HP45XXX_PWRKEY_WK_EN_MASK, HP45XXX_PWRKEY_WK_EN_ENABLE, HP45XXX_PWRKEY_WK_EN_BIT_SHIFT);\r
+ // Note: bit 2 must be 1\r
+ value |= (HP45XXX_PWRKEY_EN_ENABLE << HP45XXX_PWRKEY_EN_BIT_SHIFT);\r
+ }else\r
+ SET_BIT(value, HP45XXX_PWRKEY_WK_EN_MASK, !HP45XXX_PWRKEY_WK_EN_ENABLE, HP45XXX_PWRKEY_WK_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_CTRL7, value);\r
+}\r
+\r
+bool hp45xxx_set_watchdog_int_enable(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_INT0_ENABLE, &value);\r
+ SET_ENABLE(en, value, HP45XXX_WATCHDOG_INT_EN_MASK, HP45XXX_WATCHDOG_INT_EN_ENABLE, HP45XXX_WATCHDOG_INT_EN_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_INT0_ENABLE, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_set_chg_safety_expired_enable(bool en){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_INT0_ENABLE, &value);\r
+ SET_ENABLE(en, value, HP45XXX_CHG_SAFETY_EXPIRED_MASK, HP45XXX_CHG_SAFETY_EXPIRED_ENABLE, HP45XXX_CHG_SAFETY_EXPIRED_BIT_SHIFT);\r
+ hp45xxx_write_reg(HP45XXX_REG_INT0_ENABLE, value);\r
+ return SUCCESS;\r
+}\r
+\r
+bool hp45xxx_read_status_wdt_fault(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return (value & HP45XXX_WDT_FAULT_MASK) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_chrg_stat_not_chrg(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_NOT_CHRG) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_chrg_stat_dead_chrg(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_DEAD_CHRG) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_chrg_stat_pre_chrg(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_PRE_CHRG) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_chrg_stat_fast_chrg(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_FAST_CHRG) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_chrg_stat_chrg_done(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return ((value & HP45XXX_CHRG_STAT_MASK) == HP45XXX_CHRG_STAT_CHRG_DONE) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_status_vindpm(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return (value & HP45XXX_VIN_DPM_STAT_MASK) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_status_vbus_pg(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return (value & HP45XXX_VBUS_PG_STAT_MASK) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_status_thermal(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT0, &value);\r
+ return (value & HP45XXX_THERM_STAT_MASK) ? true : false;\r
+}\r
+\r
+void hp45xxx_update_status_chip_stat1(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT1, &value);\r
+ if(value & HP45XXX_VIN_FAULT_MASK)\r
+ hp45xxx_chip_state.vin_fault |= true;\r
+ if(value & HP45XXX_TSHUT_MASK)\r
+ hp45xxx_chip_state.tshut |= true;\r
+ if(value & HP45XXX_VBAT_OVP_MASK)\r
+ hp45xxx_chip_state.vbat_ovp |= true;\r
+ if(value & HP45XXX_SAFETY_MODE_MASK)\r
+ hp45xxx_chip_state.safety_mode |= true;\r
+ hp45xxx_chip_state.ntc_hot = (value & HP45XXX_NTC_HOT_MASK) ? true : false;\r
+ hp45xxx_chip_state.ntc_cold = (value & HP45XXX_NTC_COLD_MASK) ? true : false;\r
+}\r
+\r
+void hp45xxx_clear_status_chip_stat1(void){\r
+ hp45xxx_chip_state.vin_fault = false;\r
+ hp45xxx_chip_state.tshut = false;\r
+ hp45xxx_chip_state.vbat_ovp = false;\r
+ hp45xxx_chip_state.safety_mode = false;\r
+}\r
+\r
+bool hp45xxx_read_status_vin_fault(void){\r
+ hp45xxx_update_status_chip_stat1();\r
+ return hp45xxx_chip_state.vin_fault;\r
+}\r
+\r
+bool hp45xxx_read_status_tshut(void){\r
+ hp45xxx_update_status_chip_stat1();\r
+ return hp45xxx_chip_state.tshut;\r
+}\r
+\r
+bool hp45xxx_read_status_vbat_ovp(void){\r
+ hp45xxx_update_status_chip_stat1();\r
+ return hp45xxx_chip_state.vbat_ovp;\r
+}\r
+\r
+bool hp45xxx_read_status_safety_mode(void){\r
+ hp45xxx_update_status_chip_stat1();\r
+ return hp45xxx_chip_state.safety_mode;\r
+}\r
+\r
+bool hp45xxx_read_status_ntc_hot(void){\r
+ hp45xxx_update_status_chip_stat1();\r
+ return hp45xxx_chip_state.ntc_hot;\r
+}\r
+\r
+bool hp45xxx_read_status_ntc_cold(void){\r
+ hp45xxx_update_status_chip_stat1();\r
+ return hp45xxx_chip_state.ntc_cold;\r
+}\r
+\r
+bool hp45xxx_read_status_iindpm(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_CHIP_STAT2, &value);\r
+ return (value & HP45XXX_IIN_DPM_STAT_MASK) ? true : false;\r
+}\r
+\r
+bool hp45xxx_read_status_vin_entry_rst(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value);\r
+ if(value & HP45XXX_ENTRY_RST_STAT_MASK){\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_ENTRY_RST_STAT_MASK);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool hp45xxx_read_status_pwrkey_rst(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value);\r
+ if(value & HP45XXX_PWRKEY_RST_STAT_MASK){\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_PWRKEY_RST_STAT_MASK);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool hp45xxx_read_status_hiccup_latch(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value);\r
+ if(value & HP45XXX_HICCUP_LATCH_STAT_MASK){\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_HICCUP_LATCH_STAT_MASK);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool hp45xxx_read_status_pwrkey_wk(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value);\r
+ if(value & HP45XXX_PWRKEY_WK_MASK){\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_PWRKEY_WK_MASK);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool hp45xxx_read_status_vbus_wk(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_SYS_WAKE_UP_SRC, &value);\r
+ if(value & HP45XXX_VBUS_WK_MASK){\r
+ hp45xxx_write_reg(HP45XXX_REG_SYS_WAKE_UP_SRC,HP45XXX_VBUS_WK_MASK);\r
+ return true;\r
+ }\r
+ return false;\r
+}\r
+\r
+bool hp45xxx_read_status_watchdog_int(void){\r
+ uint8_t value;\r
+ hp45xxx_read_reg(HP45XXX_REG_INT0_STAT, &value);\r
+ return (value & HP45XXX_WATCHDOG_INT_MASK) ? true : false;\r
+}
\ No newline at end of file
--- /dev/null
+/**\r
+ * @file HP4570.h\r
+ * @brief This is the header file containing the HP4570 I2C Settings and Control.\r
+ Includes API for computations related to configuring HP4570 Registers\r
+ and Functions to Control the HP4570 Family IC.\r
+ * @author Hypower Applications\r
+ * @date June 26, 2023\r
+ *\r
+ * Copyright (C) 2023 Hypower Microelectronics (Wuxi) Co., Ltd. All rights reserved.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY HYPOWER MICROELECTRONICS "AS IS" AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+ * IN NO EVENT SHALL HYPOWER MICROELECTRONICS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA,\r
+ * OR PROFITS;OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\r
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*/\r
+\r
+#ifndef HP4570_CHARGER_H\r
+#define HP4570_CHARGER_H\r
+\r
+#include <stdint.h>\r
+#include <stdbool.h>\r
+#include "chip_io.h"\r
+\r
+// for example\r
+// Avoid using "X", x stands for General Condition\r
+enum hp45xxx_chip_ver {\r
+ HP4570A,// all default, package typeA\r
+ HP4570B,// all default, package typeB\r
+ HP4570I = 0x0A,// different ichg range and step\r
+ HP4570J,// different default charge enable\r
+ HP4570K,// different i2c address\r
+ HP4580A = 0x10,// just different name\r
+ HP4570C9 = 0x02,// just different name\r
+};\r
+\r
+\r
+// 7-bit Slave Address\r
+#define HP45XXX_I2C_ADDR 0x07\r
+#define HP4570K_I2C_ADDR 0x3F\r
+\r
+// Register address definitions\r
+#define HP45XXX_REG_DPM_SET 0x00\r
+#define HP45XXX_REG_SYS_CTRL0 0x01\r
+#define HP45XXX_REG_SYS_CTRL1 0x02\r
+#define HP45XXX_REG_IDSG_ITERM_SET 0x03\r
+#define HP45XXX_REG_BAT_VOL_SET 0x04\r
+#define HP45XXX_REG_SYS_CTRL2 0x05\r
+#define HP45XXX_REG_SYS_CTRL3 0x06\r
+#define HP45XXX_REG_SYS_CTRL4 0x07\r
+#define HP45XXX_REG_CHIP_STAT0 0x08\r
+#define HP45XXX_REG_CHIP_STAT1 0x09\r
+#define HP45XXX_REG_CHIP_STAT2 0x0B\r
+#define HP45XXX_REG_VIPRE 0x0C\r
+#define HP45XXX_REG_EXT_CTRL 0x0D\r
+#define HP45XXX_REG_SYS_CTRL5 0x15\r
+#define HP45XXX_REG_SYS_CTRL6 0x19\r
+#define HP45XXX_REG_SYS_CTRL7 0x1B\r
+#define HP45XXX_REG_SYS_WAKE_UP_SRC 0x1E\r
+#define HP45XXX_REG_INT0_ENABLE 0x50\r
+#define HP45XXX_REG_INT0_STAT 0x58\r
+#define HP45XXX_REG_VID_LSB 0x60\r
+#define HP45XXX_REG_VID_MSB 0x61\r
+#define HP45XXX_REG_PID_LSB 0x62\r
+#define HP45XXX_REG_PID_MSB 0x63\r
+#define HP45XXX_REG_CHIP_VER 0x64\r
+\r
+#ifndef GENMASK\r
+#define GENMASK(h, l) (((uint8_t) -1 >> (7 - (h))) & ~((1U << (l)) - 1))\r
+#endif\r
+\r
+#define HP45XXX_VIN_MIN_MASK GENMASK(7, 4)\r
+#define HP45XXX_VIN_MIN_STEP_mV 100\r
+#define HP45XXX_VIN_MIN_OFFSET_mV 3800\r
+#define HP45XXX_VIN_MIN_MIN_mV 3800\r
+#define HP45XXX_VIN_MIN_MAX_mV 4700\r
+#define HP45XXX_VIN_MIN_BIT_SHIFT 4\r
+\r
+#define HP45XXX_IINDPM_MASK GENMASK(2, 0)\r
+#define HP45XXX_IINDPM_STEP_mA 100\r
+#define HP45XXX_IINDPM_OFFSET_mA 100\r
+#define HP45XXX_IINDPM_MIN_mA 100\r
+#define HP45XXX_IINDPM_MAX_mA 900\r
+#define HP45XXX_IINDPM_BIT_SHIFT 0\r
+\r
+#define HP45XXX_NUM_TRST_DGL_VAL 4\r
+#define HP45XXX_TRST_DGL_MASK GENMASK(7, 6)\r
+#define HP45XXX_TRST_DGL_BIT_SHIFT 6\r
+\r
+#define HP45XXX_NUM_TRST_DUR_VAL 2\r
+#define HP45XXX_TRST_DUR_MASK BIT(5)\r
+#define HP45XXX_TRST_DUR_BIT_SHIFT 5\r
+\r
+#define HP45XXX_EN_HIZ_MASK BIT(4)\r
+#define HP45XXX_EN_HIZ_ENABLE 1\r
+#define HP45XXX_EN_HIZ_BIT_SHIFT 4\r
+\r
+#define HP45XXX_CEB_MASK BIT(3)\r
+#define HP45XXX_CEB_ENABLE 0\r
+#define HP45XXX_CEB_BIT_SHIFT 3\r
+\r
+#define HP45XXX_VBAT_UVLO_MASK GENMASK(2, 0)\r
+#define HP45XXX_VBAT_UVLO_STEP_mV 100\r
+#define HP45XXX_VBAT_UVLO_OFFSET_mV 2400\r
+#define HP45XXX_VBAT_UVLO_MIN_mV 2400\r
+#define HP45XXX_VBAT_UVLO_MAX_mV 3100\r
+#define HP45XXX_VBAT_UVLO_DEF_mV 2800\r
+#define HP45XXX_VBAT_UVLO_BIT_SHIFT 0\r
+\r
+#define HP45XXX_REG_RST_MASK BIT(7)\r
+#define HP45XXX_REG_RST_RESET 1\r
+#define HP45XXX_REG_RST_BIT_SHIFT 7\r
+\r
+#define HP45XXX_WDT_RST_MASK BIT(6)\r
+#define HP45XXX_WDT_RST_RESET 1\r
+#define HP45XXX_WDT_RST_BIT_SHIFT 6\r
+\r
+#define HP45XXX_ICHG_MASK GENMASK(5, 0)\r
+#define HP45XXX_ICHG_STEP_mA 8\r
+#define HP45XXX_ICHG_OFFSET_mA 8\r
+#define HP45XXX_ICHG_MIN_mA 8\r
+#define HP45XXX_ICHG_MAX_mA 512\r
+#define HP4570I_ICHG_STEP_mA 8\r
+#define HP4570I_ICHG_OFFSET_mA 8\r
+#define HP4570I_ICHG_MIN_mA 8\r
+#define HP4570I_ICHG_MAX_mA 512\r
+#define HP45XXX_ICHG_BIT_SHIFT 0\r
+\r
+#define HP45XXX_IBATFET_OCP_MASK GENMASK(7, 4)\r
+#define HP45XXX_IBATFET_OCP_STEP_mA 200\r
+#define HP45XXX_IBATFET_OCP_OFFSET_mA 200\r
+#define HP45XXX_IBATFET_OCP_MIN_mA 200\r
+#define HP45XXX_IBATFET_OCP_MAX_mA 3200\r
+#define HP45XXX_IBATFET_OCP_BIT_SHIFT 4\r
+\r
+#define HP45XXX_ITERM_MASK GENMASK(3, 0)\r
+#define HP45XXX_ITERM_STEP_mA 2\r
+#define HP45XXX_ITERM_OFFSET_mA 1\r
+#define HP45XXX_ITERM_MIN_mA 1\r
+#define HP45XXX_ITERM_MAX_mA 31\r
+#define HP45XXX_ITERM_BIT_SHIFT 0\r
+\r
+#define HP45XXX_VBATREG_MASK GENMASK(7, 2)\r
+#define HP45XXX_VBATREG_STEP_mV 12.5\r
+#define HP45XXX_VBATREG_OFFSET_mV 4000\r
+#define HP45XXX_VBATREG_MIN_mV 4000\r
+#define HP45XXX_VBATREG_MAX_mV 4500\r
+#define HP45XXX_VBATREG_BIT_SHIFT 2\r
+\r
+#define HP45XXX_NUM_VBAT_PRE_VAL 4\r
+#define HP45XXX_VBAT_PRE_0_MASK BIT(1)\r
+#define HP45XXX_VBAT_PRE_1_MASK BIT(4)\r
+#define HP45XXX_VBAT_PRE_0_BIT_SHIFT 1\r
+#define HP45XXX_VBAT_PRE_1_BIT_SHIFT 4\r
+\r
+#define HP45XXX_NUM_VRE_CHG_VAL 2\r
+#define HP45XXX_VRE_CHG_MASK BIT(0)\r
+#define HP45XXX_VRE_CHG_BIT_SHIFT 0\r
+\r
+#define HP45XXX_EN_WDT_DSG_MASK BIT(7)\r
+#define HP45XXX_EN_WDT_DSG_ENABLE 1\r
+#define HP45XXX_EN_WDT_DSG_BIT_SHIFT 7\r
+\r
+#define HP45XXX_NUM_WDT_TIMER_VAL 4\r
+#define HP45XXX_WDT_TIMER_MASK GENMASK(6, 5)\r
+#define HP45XXX_WDT_TIMER_DIS 0\r
+#define HP45XXX_WDT_TIMER_BIT_SHIFT 5\r
+\r
+#define HP45XXX_EN_TERM_MASK BIT(4)\r
+#define HP45XXX_EN_TERM_ENABLE 1\r
+#define HP45XXX_EN_TERM_BIT_SHIFT 4\r
+\r
+#define HP45XXX_EN_TIMER_MASK BIT(3)\r
+#define HP45XXX_EN_TIMER_ENABLE 1\r
+#define HP45XXX_EN_TIMER_BIT_SHIFT 3\r
+\r
+#define HP45XXX_NUM_CHG_TIMER_VAL 4\r
+#define HP45XXX_CHG_TIMER_MASK GENMASK(2, 1)\r
+#define HP45XXX_CHG_TIMER_BIT_SHIFT 1\r
+\r
+#define HP45XXX_TERM_TMR_MASK BIT(0)\r
+#define HP45XXX_TERM_TMR_ENABLE 1\r
+#define HP45XXX_TERM_TMR_BIT_SHIFT 0\r
+\r
+#define HP45XXX_NTC_EN_MASK BIT(7)\r
+#define HP45XXX_NTC_EN_ENABLE 1\r
+#define HP45XXX_NTC_EN_BIT_SHIFT 7\r
+\r
+#define HP45XXX_TMR2X_EN_MASK BIT(6)\r
+#define HP45XXX_TMR2X_EN_ENABLE 1\r
+#define HP45XXX_TMR2X_EN_BIT_SHIFT 6\r
+\r
+#define HP45XXX_BATFET_DIS_MASK BIT(5)\r
+#define HP45XXX_BATFET_DIS_ENABLE 1\r
+#define HP45XXX_BATFET_DIS_BIT_SHIFT 5\r
+\r
+#define HP45XXX_PG_INT_CONTROL_MASK BIT(4)\r
+#define HP45XXX_PG_INT_CONTROL_ENABLE 0\r
+#define HP45XXX_PG_INT_CONTROL_BIT_SHIFT 4\r
+\r
+#define HP45XXX_CHG_DONE_INT_EN_MASK BIT(3)\r
+#define HP45XXX_CHG_DONE_INT_EN_ENABLE 0\r
+#define HP45XXX_CHG_DONE_INT_EN_BIT_SHIFT 3\r
+\r
+#define HP45XXX_CHG_STAT_INT_EN_MASK BIT(2)\r
+#define HP45XXX_CHG_STAT_INT_EN_ENABLE 0\r
+#define HP45XXX_CHG_STAT_INT_EN_BIT_SHIFT 2\r
+\r
+#define HP45XXX_NTC_TRANSITION_EN_MASK BIT(1)\r
+#define HP45XXX_NTC_TRANSITION_EN_ENABLE 0\r
+#define HP45XXX_NTC_TRANSITION_EN_BIT_SHIFT 1\r
+\r
+#define HP45XXX_BATOVP_INT_EN_MASK BIT(0)\r
+#define HP45XXX_BATOVP_INT_EN_ENABLE 0\r
+#define HP45XXX_BATOVP_INT_EN_BIT_SHIFT 0\r
+\r
+#define HP45XXX_EN_PCB_OTP_MASK BIT(7)\r
+#define HP45XXX_EN_PCB_OTP_ENABLE 0\r
+#define HP45XXX_EN_PCB_OTP_BIT_SHIFT 7\r
+\r
+#define HP45XXX_VINDPM_EN_MASK BIT(6)\r
+#define HP45XXX_VINDPM_EN_ENABLE 1\r
+#define HP45XXX_VINDPM_EN_BIT_SHIFT 6\r
+\r
+#define HP45XXX_NUM_THERMAL_REG_VAL 4\r
+#define HP45XXX_THERMAL_REG_MASK GENMASK(5, 4)\r
+#define HP45XXX_THERMAL_REG_BIT_SHIFT 4\r
+\r
+#define HP45XXX_VSYS_REG_MASK GENMASK(2, 0)\r
+#define HP45XXX_VSYS_REG_STEP_mV 100\r
+#define HP45XXX_VSYS_REG_OFFSET_mV 4250\r
+#define HP45XXX_VSYS_REG_MIN_mV 4250\r
+#define HP45XXX_VSYS_REG_MAX_mV 4950\r
+#define HP45XXX_VSYS_REG_BIT_SHIFT 0\r
+\r
+#define HP45XXX_CHRG_STAT_MASK GENMASK(5, 3)\r
+#define HP45XXX_CHRG_STAT_BIT_SHIFT 3\r
+#define HP45XXX_CHRG_STAT_NOT_CHRG 0\r
+#define HP45XXX_CHRG_STAT_DEAD_CHRG (BIT(5) | BIT(3))\r
+#define HP45XXX_CHRG_STAT_PRE_CHRG BIT(3)\r
+#define HP45XXX_CHRG_STAT_FAST_CHRG BIT(4)\r
+#define HP45XXX_CHRG_STAT_CHRG_DONE (BIT(4) | BIT(3))\r
+\r
+#define HP45XXX_WDT_FAULT_MASK BIT(7)\r
+#define HP45XXX_VIN_DPM_STAT_MASK BIT(2)\r
+#define HP45XXX_VBUS_PG_STAT_MASK BIT(1)\r
+#define HP45XXX_THERM_STAT_MASK BIT(0)\r
+\r
+#define HP45XXX_NUM_SHIP_DGL_VAL 4\r
+#define HP45XXX_SHIP_DGL_MASK GENMASK(7, 6)\r
+#define HP45XXX_SHIP_DGL_BIT_SHIFT 6\r
+\r
+#define HP45XXX_VIN_FAULT_MASK BIT(5)\r
+#define HP45XXX_TSHUT_MASK BIT(4)\r
+#define HP45XXX_VBAT_OVP_MASK BIT(3)\r
+#define HP45XXX_SAFETY_MODE_MASK BIT(2)\r
+#define HP45XXX_NTC_HOT_MASK BIT(1)\r
+#define HP45XXX_NTC_COLD_MASK BIT(0)\r
+\r
+#define HP45XXX_IIN_DPM_STAT_MASK BIT(6)\r
+\r
+#define HP45XXX_NUM_IN_EXIT_SHIP_TSET_VAL 2\r
+#define HP45XXX_IN_EXIT_SHIP_TSET_MASK BIT(5)\r
+#define HP45XXX_IN_EXIT_SHIP_TSET_BIT_SHIFT 5\r
+\r
+#define HP45XXX_IPRE_MASK GENMASK(3, 0)\r
+#define HP45XXX_IPRE_STEP_mA 2\r
+#define HP45XXX_IPRE_OFFSET_mA 1\r
+#define HP45XXX_IPRE_MIN_mA 1\r
+#define HP45XXX_IPRE_MAX_mA 31\r
+#define HP45XXX_IPRE_BIT_SHIFT 0\r
+\r
+#define HP45XXX_VIN_ENTRY_RST_EN_MASK BIT(4)\r
+#define HP45XXX_VIN_ENTRY_RST_EN_ENABLE 1\r
+#define HP45XXX_VIN_ENTRY_RST_EN_BIT_SHIFT 4\r
+\r
+#define HP45XXX_IDEADBAT_MASK GENMASK(3, 0)\r
+#define HP45XXX_IDEADBAT_STEP_mA 2\r
+#define HP45XXX_IDEADBAT_OFFSET_mA 1\r
+#define HP45XXX_IDEADBAT_MIN_mA 1\r
+#define HP45XXX_IDEADBAT_MAX_mA 31\r
+#define HP45XXX_IDEADBAT_BIT_SHIFT 0\r
+\r
+#define HP45XXX_VSYS_RST_MASK BIT(7)\r
+#define HP45XXX_VSYS_RST_RESET 1\r
+#define HP45XXX_VSYS_RST_BIT_SHIFT 7\r
+\r
+#define HP45XXX_EN_IINDPM_MASK BIT(5)\r
+#define HP45XXX_EN_IINDPM_ENABLE 1\r
+#define HP45XXX_EN_IINDPM_BIT_SHIFT 5\r
+\r
+#define HP45XXX_NUM_KEY_WK_SET_VAL 2\r
+#define HP45XXX_KEY_WK_SET_MASK BIT(2)\r
+#define HP45XXX_KEY_WK_SET_BIT_SHIFT 2\r
+\r
+#define HP45XXX_NUM_T_HICCUP_VAL 2\r
+#define HP45XXX_T_HICCUP_MASK BIT(0)\r
+#define HP45XXX_T_HICCUP_BIT_SHIFT 0\r
+\r
+#define HP45XXX_WDT_VSYS_RST_MASK BIT(3)\r
+#define HP45XXX_WDT_VSYS_RST_ENABLE 1\r
+#define HP45XXX_WDT_VSYS_RST_BIT_SHIFT 3\r
+\r
+#define HP45XXX_EN_SHIP_DGL_MASK BIT(2)\r
+#define HP45XXX_EN_SHIP_DGL_ENABLE 1\r
+#define HP45XXX_EN_SHIP_DGL_BIT_SHIFT 2\r
+\r
+#define HP45XXX_EN_WDT_CHG_MASK BIT(7)\r
+#define HP45XXX_EN_WDT_CHG_ENABLE 1\r
+#define HP45XXX_EN_WDT_CHG_BIT_SHIFT 7\r
+\r
+#define HP45XXX_EN_PWRKEY_RST_MASK BIT(5)\r
+#define HP45XXX_EN_PWRKEY_RST_ENABLE 1\r
+#define HP45XXX_EN_PWRKEY_RST_BIT_SHIFT 5\r
+\r
+#define HP45XXX_VSYS_RST_WVBUS_MASK BIT(4)\r
+#define HP45XXX_VSYS_RST_WVBUS_ENABLE 1\r
+#define HP45XXX_VSYS_RST_WVBUS_BIT_SHIFT 4\r
+\r
+#define HP45XXX_PWRKEY_EN_MASK BIT(2)\r
+#define HP45XXX_PWRKEY_EN_ENABLE 1\r
+#define HP45XXX_PWRKEY_EN_BIT_SHIFT 2\r
+\r
+#define HP45XXX_VBUS_WK_EN_MASK BIT(1)\r
+#define HP45XXX_VBUS_WK_EN_ENABLE 1\r
+#define HP45XXX_VBUS_WK_EN_BIT_SHIFT 1\r
+\r
+#define HP45XXX_PWRKEY_WK_EN_MASK BIT(0)\r
+#define HP45XXX_PWRKEY_WK_EN_ENABLE 1\r
+#define HP45XXX_PWRKEY_WK_EN_BIT_SHIFT 0\r
+\r
+#define HP45XXX_ENTRY_RST_STAT_MASK BIT(7)\r
+#define HP45XXX_PWRKEY_RST_STAT_MASK BIT(5)\r
+#define HP45XXX_HICCUP_LATCH_STAT_MASK BIT(4)\r
+#define HP45XXX_PWRKEY_WK_MASK BIT(1)\r
+#define HP45XXX_VBUS_WK_MASK BIT(0)\r
+\r
+#define HP45XXX_WATCHDOG_INT_EN_MASK BIT(7)\r
+#define HP45XXX_WATCHDOG_INT_EN_ENABLE 0\r
+#define HP45XXX_WATCHDOG_INT_EN_BIT_SHIFT 7\r
+\r
+#define HP45XXX_CHG_SAFETY_EXPIRED_MASK BIT(1)\r
+#define HP45XXX_CHG_SAFETY_EXPIRED_ENABLE 0\r
+#define HP45XXX_CHG_SAFETY_EXPIRED_BIT_SHIFT 1\r
+\r
+#define HP45XXX_WATCHDOG_INT_MASK BIT(7)\r
+\r
+static const uint32_t hp45xxx_trst_dgl_time[HP45XXX_NUM_TRST_DGL_VAL] = {\r
+ 80000, 120000, 160000, 200000\r
+};\r
+static const uint16_t hp45xxx_trst_dur_time[HP45XXX_NUM_TRST_DUR_VAL] = {\r
+ 2000, 4000\r
+};\r
+static const uint16_t hp45xxx_vbat_pre_voltage[HP45XXX_NUM_VBAT_PRE_VAL] = {\r
+ 2800, 3000, 3200, 3300\r
+};\r
+static const uint8_t hp45xxx_vre_chg_voltage[HP45XXX_NUM_VRE_CHG_VAL] = {\r
+ 100, 200\r
+};\r
+static const uint32_t hp45xxx_watchdog_time[HP45XXX_NUM_WDT_TIMER_VAL] = {\r
+ 0, 40000, 80000, 160000\r
+};\r
+static const uint8_t hp45xxx_fast_chg_time[HP45XXX_NUM_CHG_TIMER_VAL] = {\r
+ 3, 5, 8, 12\r
+};\r
+static const uint8_t hp45xxx_thermal_reg_degree[HP45XXX_NUM_THERMAL_REG_VAL] = {\r
+ 80, 100, 120, 130\r
+};\r
+static const uint16_t hp45xxx_ship_dgl_time[HP45XXX_NUM_SHIP_DGL_VAL] = {\r
+ 1000, 2000, 4000, 8000\r
+};\r
+static const uint16_t hp45xxx_in_exit_ship_tset_time[HP45XXX_NUM_IN_EXIT_SHIP_TSET_VAL] = {\r
+ 50, 2000\r
+};\r
+static const uint16_t hp45xxx_key_wk_set_time[HP45XXX_NUM_KEY_WK_SET_VAL] = {\r
+ 2000, 200\r
+};\r
+static const uint16_t hp45xxx_t_hiccup_time[HP45XXX_NUM_T_HICCUP_VAL] = {\r
+ 256, 512\r
+};\r
+\r
+//Default value for a register.\r
+#define HP45XXX_REG_DPM_SET_DEF 0x84\r
+#define HP45XXX_REG_SYS_CTRL0_DEF 0xA4\r
+#define HP45XXX_REG_SYS_CTRL1_DEF 0x00\r
+#define HP45XXX_REG_IDSG_ITERM_SET_DEF 0x91\r
+#define HP45XXX_REG_BAT_VOL_SET_DEF 0x43\r
+#define HP45XXX_REG_SYS_CTRL2_DEF 0x3A\r
+#define HP45XXX_REG_SYS_CTRL3_DEF 0x40\r
+#define HP45XXX_REG_SYS_CTRL4_DEF 0x24\r
+#define HP45XXX_REG_CHIP_STAT1_DEF 0x00\r
+#define HP45XXX_REG_VIPRE_DEF 0x01\r
+#define HP45XXX_REG_EXT_CTRL_DEF 0x11\r
+#define HP45XXX_REG_SYS_CTRL5_DEF 0x31\r
+#define HP45XXX_REG_SYS_CTRL6_DEF 0x0C\r
+#define HP45XXX_REG_SYS_CTRL7_DEF 0xB6\r
+#define HP45XXX_REG_INT0_ENABLE_DEF 0x4C\r
+#define HP45XXX_REG_INT0_STAT_DEF 0x00\r
+#define HP45XXX_REG_VID_LSB_DEF 0xC6\r
+#define HP45XXX_REG_VID_MSB_DEF 0x34\r
+#define HP45XXX_REG_PID_LSB_DEF 0x81\r
+#define HP45XXX_REG_PID_MSB_DEF 0x00\r
+\r
+#define HP4570J_REG_SYS_CTRL0_DEF 0xAC\r
+\r
+// Function Declarations\r
+bool hp45xxx_init(uint8_t chip_ver);\r
+bool hp45xxx_identify(uint8_t chip_ver);\r
+\r
+void hp45xxx_set_pwrkey_en(bool en);// PWRKEY function enable control \r
+bool hp45xxx_set_trst_dgl_mS(uint32_t time);// Pull INT low to disconnect the battery then auto on\r
+\r
+void hp45xxx_reg_rst(void);// Register reset\r
+void hp45xxx_wdt_rst(void);// Watchdog timer reset\r
+void hp45xxx_vsys_rst(void);// VSYS reset\r
+void hp45xxx_set_rst_vin_entry_en(bool en);// VIN 4 pulse Reset Enable\r
+void hp45xxx_set_rst_pwrkey_en(bool en);// VSYS reset enable PWRKEY operation Enable\r
+void hp45xxx_set_rst_vsys_wvbus_en(bool en);// VSYS reset operation when VBUS is present\r
+\r
+void hp45xxx_entry_shipmode(void);\r
+bool hp45xxx_set_batfet_dis(bool en);// BATFET force off\r
+void hp45xxx_set_vbus_wk_en(bool en);// VBUS plug in to exit ship mode\r
+void hp45xxx_set_pwrkey_wk_en(bool en);// PWRKEY be low to exit ship mode\r
+bool hp45xxx_set_vin_exit_ship_tset_mS(uint16_t time);// IN Port Power Good Time Setting for Exit Shipmode\r
+bool hp45xxx_set_key_wk_time_mS(uint16_t time);// KEY wake up time set\r
+void hp45xxx_set_ship_dgl_en(bool en);// Enter ship mode deglitch enable control\r
+bool hp45xxx_set_ship_dgl_mS(uint16_t time);// Enter ship mode deglitch time \r
+\r
+\r
+void hp45xxx_set_hiz_en(bool en);// VBUS power path Hi-Z mode enable\r
+void hp45xxx_set_ceb_en(bool en);// Enable or disable charging function\r
+\r
+bool hp45xxx_set_vsys_reg_mV(float voltage);// VSYS regulation\r
+bool hp45xxx_set_trst_dur_mS(uint16_t time);// VSYS off time before auto on\r
+void hp45xxx_set_vindpm_en(bool en);\r
+void hp45xxx_set_iindpm_en(bool en);\r
+bool hp45xxx_set_vindpm_mV(uint16_t voltage);\r
+bool hp45xxx_set_iindpm_mA(uint16_t current);\r
+\r
+bool hp45xxx_set_chrg_vpre_mV(uint8_t voltage);// Battery pre-charge voltage set\r
+bool hp45xxx_set_chrg_vbat_mV(float voltage);\r
+bool hp45xxx_set_chrg_vre_mV(uint8_t voltage);// Battery re-charge voltage set\r
+bool hp45xxx_set_chrg_idead_mA(uint16_t current);\r
+bool hp45xxx_set_chrg_ipre_mA(uint16_t current);// Battery pre-charge current set\r
+bool hp45xxx_set_chrg_ichg_mA(uint16_t current);\r
+bool hp4570i_set_chrg_ichg_mA(uint16_t current);\r
+bool hp45xxx_set_chrg_iterm_mA(uint8_t current);\r
+void hp45xxx_set_chrg_term_en(bool en);// Termination is allowed or not\r
+void hp45xxx_set_chrg_term_tmr(bool en);// Termination timer control\r
+void hp45xxx_set_chrg_timer_en(bool en);// Safety timer set during charging\r
+bool hp45xxx_set_chrg_timer_hour(uint8_t time);// Fast charging mode timer set \r
+void hp45xxx_set_chrg_tmr2x_en(bool en);// Safety timer double during DPM/Thermal\r
+\r
+bool hp45xxx_set_ibatfet_ocp_mA(uint16_t current);\r
+bool hp45xxx_set_vbat_uvlo_mV(uint16_t voltage);// Battery UVLO falling threshold,hys is about =150mV\r
+bool hp45xxx_set_t_hiccup_mS(uint16_t time);// Hiccup timer set\r
+\r
+void hp45xxx_set_wdt_timer_en(bool en);// If watchdog timer already enable, function will do noting, otherwise will set as default \r
+bool hp45xxx_set_wdt_timer_mS(uint32_t time);\r
+void hp45xxx_set_wdt_chg_en(bool en);// Watchdog timer function enable control during charging\r
+void hp45xxx_set_wdt_dsg_en(bool en);// Watchdog timer function enable control during discharging\r
+void hp45xxx_set_wdt_vsys_rst_en(bool en);// Watch dog fault VSYS reset enable control \r
+\r
+void hp45xxx_set_ntc_en(bool en);// NTC enable during charging\r
+void hp45xxx_set_pcb_otp_en(bool en);// PCB_OTP enable\r
+bool hp45xxx_set_thermal_reg_degree(uint8_t degree);// Die temp control by Thermal loop\r
+\r
+void hp45xxx_set_int_pg_en(bool en);// Power good int enable control\r
+void hp45xxx_set_int_chrg_done_en(bool en);// Charge complete int enable control\r
+void hp45xxx_set_int_chrg_stat_en(bool en);// Charging status dynamic change int enable control\r
+void hp45xxx_set_int_ntc_transition_en(bool en);// Battery temp region change int enable control\r
+void hp45xxx_set_int_batovp_en(bool en);// Battery OVP int enable control\r
+void hp45xxx_set_int_wdt_en(bool en);// Watch dog time expire int enable control\r
+void hp45xxx_set_int_chg_safety_expired_en(bool en);// Charger enter safety int enable control\r
+\r
+bool hp45xxx_read_chrg_stat_not_chrg(void);\r
+bool hp45xxx_read_chrg_stat_dead_chrg(void);\r
+bool hp45xxx_read_chrg_stat_pre_chrg(void);\r
+bool hp45xxx_read_chrg_stat_fast_chrg(void);\r
+bool hp45xxx_read_chrg_stat_chrg_done(void);\r
+\r
+bool hp45xxx_read_status_wdt_fault(void);// Watchdog timer expired 1: Expired; 0: Not Expired\r
+bool hp45xxx_read_status_vindpm(void);// 1: In DPM; 0: Not DPM\r
+bool hp45xxx_read_status_vbus_pg(void);// 1: Power Good; 0: Not Good\r
+bool hp45xxx_read_status_thermal(void);// 1: In thermal; 0: Not thermal\r
+bool hp45xxx_read_status_vin_fault(void);// 1: Input fault ovp or bad source plug out; 0: normal \r
+bool hp45xxx_read_status_tshut(void);// 1: Thermal shutdown; 0: Normal\r
+bool hp45xxx_read_status_vbat_ovp(void);// 1: BAT_OVP; 0: Not BAT_OVP\r
+bool hp45xxx_read_status_safety_mode(void);// Charger safety timer expired 1: Expired; 0: Not Expired\r
+bool hp45xxx_read_status_ntc_hot(void);// 1: Hot; 0: Not hot\r
+bool hp45xxx_read_status_ntc_cold(void);// 1: Cold; 0: Not cold\r
+bool hp45xxx_read_status_iindpm(void);// 1: In DPM; 0: Not DPM\r
+bool hp45xxx_read_status_vin_entry_rst(void);// VIN_ENTRY_RST once happenned\r
+bool hp45xxx_read_status_pwrkey_rst(void);// PWRKEY reset once happened\r
+bool hp45xxx_read_status_hiccup_latch(void);// Hiccup once happened\r
+bool hp45xxx_read_status_pwrkey_wk(void);// PWRKEY 2S low time wake up from ship mode\r
+bool hp45xxx_read_status_vbus_wk(void);// VBUS plug in wake up from ship mode\r
+bool hp45xxx_read_status_watchdog_int(void);// Watch dog time expire IRQ\r
+\r
+#endif // HP4570_CHARGER_H
\ No newline at end of file
--- /dev/null
+/*
+ * @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;
+}
--- /dev/null
+/*
+ * @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 <stdint.h>
+#include <stdio.h>
+#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
--- /dev/null
+#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
--- /dev/null
+/*
+ * @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
/* Set Cmm_en bit '0', Disable continuous mode */ \r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL2, 0x00);\r
\r
- MMC5603_Delay_Ms(20);\r
+ // MMC5603_Delay_Ms(20);\r
+ LOS_Mdelay(20);\r
\r
/* Write reg 0x1B */\r
/* Set Auto_SR_en bit '0', Disable the function of automatic set/reset */\r
/* Write 0x01 to register 0x1B, set Take_meas_M bit '1' */\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_TMM); \r
/* Delay 10 ms to finish the TM operation */\r
- MMC5603_Delay_Ms(10); \r
+ // MMC5603_Delay_Ms(10); \r
+ LOS_Mdelay(10); \r
/* Read register data */\r
I2C_MultiRead_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_DATA, 6, data_reg);\r
/* Get high 16bits data */\r
/* Write 0x01 to register 0x1B, set Take_meas_M bit '1' */\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS,CUSTOM_MMC5603_REG_CTRL0,CUSTOM_MMC5603_CMD_TMM); \r
/* Delay 10 ms to finish the TM operation */\r
- MMC5603_Delay_Ms(10); \r
+ // MMC5603_Delay_Ms(10); \r
+ LOS_Mdelay(10); \r
/* Read register data */\r
I2C_MultiRead_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_DATA, 6, data_reg);\r
/* Get high 16bits data */\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_SET); \r
\r
/* Delay to finish the SET operation */\r
- MMC5603_Delay_Ms(1);\r
+ // MMC5603_Delay_Ms(1);\r
+ LOS_Mdelay(1);\r
\r
return; \r
}\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_RESET);\r
\r
/* Delay to finish the RESET operation */\r
- MMC5603_Delay_Ms(1);\r
+ // MMC5603_Delay_Ms(1);\r
+ LOS_Mdelay(1);\r
\r
return; \r
}\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_AUTO_ST_EN);\r
\r
/* Delay 15ms to finish the selftest process */\r
- MMC5603_Delay_Ms(15);\r
+ // MMC5603_Delay_Ms(15);\r
+ LOS_Mdelay(15);\r
\r
/* Read register 0x18, check Sat_sensor bit */\r
I2C_Read_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_STATUS1, ®_status); \r
\r
/* Do TM_M after selftest operation */\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS,CUSTOM_MMC5603_REG_CTRL0,CUSTOM_MMC5603_CMD_TMM); \r
- MMC5603_Delay_Ms(8);\r
+ // MMC5603_Delay_Ms(8);\r
+ LOS_Mdelay(8);\r
}\r
\r
return ret;\r
\r
/* Disable continuous mode */ \r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL2, 0x00);\r
- MMC5603_Delay_Ms(15);//Delay 15ms to finish the last sampling\r
+ // MMC5603_Delay_Ms(15);//Delay 15ms to finish the last sampling\r
+ LOS_Mdelay(15);\r
\r
/* Do SET operation */\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL0, CUSTOM_MMC5603_CMD_SET); \r
- MMC5603_Delay_Ms(1);//Delay 1ms to finish the SET operation\r
+ // MMC5603_Delay_Ms(1);//Delay 1ms to finish the SET operation\r
+ LOS_Mdelay(1);\r
\r
/* Do TM_M before next data reading */\r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS,CUSTOM_MMC5603_REG_CTRL0,CUSTOM_MMC5603_CMD_TMM); \r
- MMC5603_Delay_Ms(8);//Delay 8ms to finish the TM_M operation \r
+ // MMC5603_Delay_Ms(8);//Delay 8ms to finish the TM_M operation\r
+ LOS_Mdelay(8); \r
} \r
}\r
else if(sensor_state == 2)\r
/* Set Cmm_en bit '0', Disable continuous mode */ \r
I2C_Write_Reg(CUSTOM_MMC5603_7BITI2C_ADDRESS, CUSTOM_MMC5603_REG_CTRL2, 0x00);\r
\r
- MMC5603_Delay_Ms(20);\r
+ // MMC5603_Delay_Ms(20);\r
+ LOS_Mdelay(20);\r
\r
return;\r
}\r
/* Work mode setting */\r
CUSTOM_MMC5603_Continuous_Mode_With_Auto_SR(CUSTOM_MMC5603_CMD_BW00, 50);\r
\r
- MMC5603_Delay_Ms(20);\r
+ // MMC5603_Delay_Ms(20);\r
+ LOS_Mdelay(20);\r
\r
return;\r
}\r
+/*
+ * @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"
int mmc5603_savePara_infile(void);
int mmc5603_readPara_infile(void);
+void mmc5603_poweron(void);
+void mmc5603_poweroff(void);
+
#ifdef __cplusplus
#if __cplusplus
}
#include "mmc_customer.h"\r
#include "MMC5603.h" \r
\r
+#ifdef BOARD_U8\r
+#include "pm_control.h"\r
+#include "platform_core.h"\r
+#include "pinctrl_porting.h"\r
+#include "hal_gpio.h"\r
+#endif\r
+\r
#ifdef ACC_LIS2DOC\r
#include "acc_service.h"\r
#endif\r
#define A_LAYOUT 7\r
#define M_LAYOUT 0\r
\r
+// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚\r
+#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0\r
+\r
/* These variables are used to save the magnetic sensor calibrated data. */ \r
float calMagX, calMagY, calMagZ; \r
\r
/* This variable is used to save calibrated mag para that need to be saved in system file */\r
static float saveData[4] = {0.0f};\r
\r
+void mmc5603_poweron(void)\r
+{\r
+#ifdef BOARD_U8\r
+ uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+ uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT);\r
+ uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH);\r
+ LOS_Mdelay(100);\r
+#endif\r
+}\r
+void mmc5603_poweroff(void)\r
+{\r
+#ifdef BOARD_U8\r
+ uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+ uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT);\r
+ uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW);\r
+ LOS_Mdelay(1);\r
+#endif\r
+}\r
int mmc5603_start(void)\r
{\r
+\r
+ mmc5603_poweron();\r
+\r
int i;\r
/* magnetic sensor soft iron calibration matrix, default is unit matrix */\r
float mag_smm[9] = { 1.0f, 0.0f, 0.0f, \\r
int mmc5603_stop(void)\r
{\r
CUSTOM_MMC5603_Disable();\r
+\r
+ mmc5603_poweroff();\r
+\r
return 0;\r
}\r
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2024-12-16 09:56:44\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2024-12-16 10:33:24\r
+ * @FilePath: /sdk615/code/sdk/drivers/peripheral/mag/mmc5603/mmc_customer.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
#ifndef __MMC5603_PORTING_H__\r
#define __MMC5603_PORTING_H__\r
#include <string.h>\r
\r
\r
#ifndef XTS_SUPPORT\r
-// #define MMC_DEBUG\r
+#define MMC_DEBUG\r
#endif \r
\r
#ifdef MMC_DEBUG\r
#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里定义,对外开放
*/
// 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();
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;
+/*
+ * @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
*
set(SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/ppg_at_cmd.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ppg_service.cpp
+
)
set(COMPONENT_PUBLIC_CCFLAGS
#include <string.h>
#include <math.h>
+#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
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)
#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里定义,对外开放
*/
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)
keep_in_wear_det_mod = mod;
}
+#if 0
//漏光测试
errcode_t update_leaklight_event_notify(uint8_t *data)
{
}
}
+#endif
+
void uapi_ppg_service_deinit(void)
{
ppg_service_running_stat = false;
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;
}
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);
{
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){
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;
{
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)
{
PRINT("uapi_ppg_service_init !\r\n");
-
+ tyhx_poweron();
#ifdef PPG_HX3695
- tyhx_poweron();
+
if ( hx3695_chip_check() == false)
{
//TODO 没找到3695,退出线程
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;
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");
* @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:
*
#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
#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);
//设置佩戴检测模式
void set_keep_in_wear_det_mode(uint8_t mod);
+void ppg_int_callback(pin_t pin, uintptr_t param);
+
#ifdef __cplusplus
#if __cplusplus
}
--- /dev/null
+#===============================================================================
+# @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()
+
--- /dev/null
+\r
+\r
+#ifndef BIODETECT\r
+#define BIODETECT\r
+\r
+#include <stdbool.h>\r
+#include <stdint.h>\r
+#include <stdio.h>\r
+\r
+void f_BIOInit(int32_t gapDeltaBIO, int32_t gapDeltaPS);\r
+\r
+uint8_t f_BIOdetect(int32_t inputBIO, int32_t inputPS, int32_t PSth);\r
+\r
+char* bioVersion(void);\r
+\r
+#endif /* BIODETECT */
\ No newline at end of file
--- /dev/null
+\r
+#ifndef APP_ALGO_ALGO_H\r
+#define APP_ALGO_ALGO_H\r
+\r
+#include <stdbool.h>\r
+#include <stdint.h>\r
+\r
+typedef enum\r
+{\r
+ SPORT_TYPE_NORMAL =0x00, // 日常\r
+ SPORT_TYPE_RUNNING =0x01, // 跑步\r
+ SPORT_TYPE_RIDE_BIKE =0X02, // 骑行\r
+ SPORT_TYPE_JUMP_ROPE =0X03, // 跳绳\r
+ SPORT_TYPE_SWIMMING =0X04, // 游泳\r
+ SPORT_TYPE_BADMINTON =0X05, // 羽毛球\r
+ SPORT_TYPE_TABLE_TENNIS=0X06, // 乒乓球\r
+ SPORT_TYPE_TENNIS =0X07, // 网球\r
+ SPORT_TYPE_CLIMBING =0X08, // 爬山\r
+ SPORT_TYPE_WALKING =0X09, // 椭圆机\r
+ SPORT_TYPE_BASKETBALL =0X0A, // 篮球\r
+ SPORT_TYPE_FOOTBALL =0X0B, // 足球\r
+ SPORT_TYPE_BASEBALL =0X0C, // 棒球\r
+ SPORT_TYPE_VOLLEYBALL =0X0D, // 排球\r
+ SPORT_TYPE_CRICKET = 0X0E, // 板球\r
+ SPORT_TYPE_RUGBY = 0X0F, // 橄榄球\r
+ SPORT_TYPE_HOCKEY =0X10, // 曲棍球\r
+ SPORT_TYPE_DANCE = 0X11, // 跳舞\r
+ SPORT_TYPE_SPINNING = 0X12, // 动感单车\r
+ SPORT_TYPE_YOGA = 0X13, // 瑜伽\r
+ SPORT_TYPE_SIT_UP =0X14, // 仰卧起坐\r
+ SPORT_TYPE_TREADMILL =0X15, // 跑步机\r
+ SPORT_TYPE_GYMNASTICS =0X16, // 体操\r
+ SPORT_TYPE_BOATING = 0X17, // 划船\r
+ SPORT_TYPE_JUMPING_JACK = 0X18, // 开合跳\r
+ SPORT_TYPE_FREE_TRAINING = 0X19,// 自由训练\r
+ SPORT_TYPE_PERIODIC_MONITORING = 0X1A,// 定时监测模式\r
+} AlgoSportMode;\r
+//未出现在上表中的运动形式均先以跑步输入\r
+\r
+\r
+typedef struct\r
+{\r
+ int32_t x;\r
+ int32_t y;\r
+ int32_t z;\r
+}AlgoAxesData_t;\r
+\r
+typedef struct\r
+{\r
+ int32_t hrData;\r
+ int32_t reliability;\r
+}AlgoOutputData_t;\r
+\r
+typedef struct\r
+{\r
+ AlgoAxesData_t axes;\r
+ int32_t ppgSample;\r
+ int32_t envSample;\r
+}AlgoInputData_t;\r
+\r
+void Algo_Init(void);\r
+void Algo_Input(AlgoInputData_t *pInputData,int32_t gaptime,AlgoSportMode sportMode,int16_t surfaceRecogMode,int16_t opticalAidMode);\r
+void Algo_Output(AlgoOutputData_t *pOutputData);\r
+\r
+\r
+\r
+#endif /* APP_ALGO_ALGO_H_ */\r
+\r
+\r
+\r
--- /dev/null
+#ifndef __SPO2ALGO_H__
+#define __SPO2ALGO_H__
+
+#include <stdint.h>
+
+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
--- /dev/null
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2024-12-07 16:04:22\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2024-12-09 10:32:42\r
+ * @FilePath: /sdk615/code/sdk/drivers/peripheral/ppg/vc9202/vc30x91x92x_common.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc30x91x92x_common.h\r
+ * @brief configuration file for vc30x,vc91x,vc92x.\r
+ * @details \r
+ * @author \r
+ * @date\r
+ * @version \r
+ *********************************************************************************************************/\r
+#ifndef __VC30x91x92x_COMMON_H__\r
+#define __VC30x91x92x_COMMON_H__\r
+\r
+#include "algo.h"\r
+#include "spo2Algo.h"\r
+#include "vcSportMotionIntAlgo.h"\r
+\r
+#ifndef SUB\r
+#define SUB(a, b) ((a) - (b))\r
+#endif\r
+#ifndef ABS\r
+#define ABS(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))\r
+#endif\r
+\r
+#define FUNC_DISABLE (0)\r
+#define FUNC_ENABLE (!FUNC_DISABLE)\r
+#define WEAR_IS_DROP (0)\r
+#define WEAR_IS_HOLD (1)\r
+\r
+typedef enum\r
+{\r
+ WEAR_STA_NONE = 0,\r
+ WEAR_STA_HOLD = 1,\r
+ WEAR_STA_DROP = 2,\r
+}WearStatusTypeDef;\r
+\r
+typedef enum\r
+{\r
+ WORK_MODE_NONE = 0,\r
+ WORK_MODE_HR = 1,\r
+ WORK_MODE_SPO2 = 2,\r
+ WORK_MODE_HRV = 3, /* 100hz������ʹ��BIO������Ҫ��֤�ܹ��õ���ʱ��Ӧ��������Ȼ���ܻᵼ�¶��жϣ����������� */\r
+ WORK_MODE_STRESS = 4,\r
+ WORK_MODE_WEAR = 5,\r
+ WORK_MODE_FACTORY = 6,\r
+ WORK_MODE_TEMPERATURE = 7,\r
+ WORK_MODE_FPC_TEST = 8,\r
+}WorkModeTypeDef;\r
+\r
+typedef struct\r
+{\r
+ unsigned short sampling_gap_time;\r
+ WorkModeTypeDef work_mode;\r
+}InitParamTypeDef;\r
+\r
+typedef struct\r
+{\r
+ unsigned char led_cur[3];\r
+ unsigned char pd_res[3];\r
+ unsigned char env_val[3];\r
+ unsigned char pre_val[2];\r
+ unsigned char ps_val;\r
+ unsigned char aenv_val[3];\r
+ unsigned char apdbias_val[4];\r
+ unsigned int pdbias;\r
+ unsigned char apre_val[2];\r
+ unsigned char aps_val;\r
+ unsigned int ppg_data[128];\r
+ unsigned short int bio_val_i;\r
+ unsigned short int bio_val_o;\r
+ signed short int temp_val_i;\r
+ signed short int temp_val_o;\r
+}SamplingDataTypeDef;\r
+\r
+extern unsigned char usr_iic_write_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size);\r
+extern unsigned char usr_iic_read_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size);\r
+extern unsigned int usr_get_clock_ticks(void);\r
+\r
+#endif \r
--- /dev/null
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2024-12-07 16:04:22\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2024-12-10 18:40:24\r
+ * @FilePath: /sdk615/code/sdk/drivers/peripheral/ppg/vc9202/inc/vc9202_common.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc9202_common.h\r
+ * @brief configuration file for the hardware driver layer\r
+ * @details \r
+ * @author \r
+ * @date\r
+ * @version \r
+ *********************************************************************************************************/\r
+#ifndef __VC9202_COMMON_H__\r
+#define __VC9202_COMMON_H__\r
+\r
+#include "vc30x91x92x_common.h"\r
+\r
+#define VC9202_CFG_DRV_BY_TIMER (FUNC_DISABLE)\r
+/* VC_COMMON_VC9202_CFG_SAMPLE_RATE: default 25hz */\r
+#define VC9202_CFG_SAMPLE_RATE (25)\r
+/*VC_COMMON_CFG_GPIO_TIME: 0-50us, 1-100us, 2-200us, 3-400us */\r
+#define VC9202_CFG_INTERRUPT_TIME (3)\r
+/* 0:rising edge 1:descending edge */\r
+#define VC9202_CFG_INTERRUPT_MODE (0)\r
+\r
+#define VC9202_CFG_CLK_CHECK_FREQUENCY (32000) //counter 32K\r
+#define VC9202_CFG_CLK_CHECK_MAX (0xFFFFFF) //24bits counter\r
+#define VC9202_CFG_CLK_CHECK_GAPTIME (10) //seconds \r
+#define VC9202_CFG_CLK_CHECK_DEVIATION (3)\r
+\r
+/****************************************************************************\r
+ * Configuration wear parameters \r
+ ***************************************************************************/\r
+#define VC9202_CFG_WEAR_DETECTION (FUNC_ENABLE) // FUNC_DISABLE FUNC_ENABLE\r
+#define VC9202_CFG_WEAR_DEFAULT_STATUS (WEAR_IS_HOLD) //1 is default wear,0 is default not wear WEAR_IS_HOLD WEAR_IS_DROP\r
+#define VC9202_CFG_WEAR_BIO_EN (FUNC_ENABLE)\r
+#define VC9202_CFG_WEAR_ALG_EN (FUNC_DISABLE) //开启心率摘下功能,必须开启满足(ATC|BIO)为真\r
+#define VC9202_CFG_WEAR_ACT_EN (FUNC_DISABLE)\r
+#define VC9202_CFG_WEAR_THRESHOLD_EN (FUNC_ENABLE) //绝对阈值宏开关\r
+#define VC9202_CFG_WEAR_HOLD_CNT (1)\r
+#define VC9202_CFG_WEAR_DROP_CNT (3)\r
+\r
+/* sensor serial default wear param */\r
+#define VC9202_CFG_WEAR_PARAM_PS (128)\r
+#define VC9202_CFG_WEAR_PARAM_PSIN (100)\r
+#define VC9202_CFG_WEAR_PARAM_ENVMAX (128) //8*16\r
+#define VC9202_CFG_WEAR_PARAM_ENVMIN (64) //4*16\r
+#define VC9202_CFG_WEAR_PARAM_BIOIN (40)\r
+\r
+#define VC9202_CFG_PS_SLOT_CUR (0x3A) /* 0x5A */\r
+#define VC9202_CFG_PS_SLOT_RES (0x47)\r
+\r
+/* board cap halve,电容减半,需要提高一倍采样率的配置 */\r
+#define VC9202_CFG_IS_HALVE_CAP 0\r
+\r
+/* VC9202 function */\r
+extern unsigned char vc9202_drv_reg_init(InitParamTypeDef *pInit_Param);\r
+extern unsigned char vc9202_drv_get_chip_id(void);\r
+extern void vc9202_drv_start_sampling(void);\r
+extern void vc9202_drv_stop_sampling(void);\r
+extern void vc9202_drv_soft_reset(void);\r
+extern unsigned char vc9202_drv_channel_switch(unsigned char num_channel, unsigned char enable_flag);\r
+extern unsigned char vc9202_drv_get_int_reason(void);\r
+extern void vc9202_drv_set_algo_wear_status(WearStatusTypeDef status);\r
+extern void vc9202_drv_set_gsensor_actuating_quantity(unsigned int axis_diff);\r
+extern WearStatusTypeDef vc9202_drv_get_wear_status(void);\r
+extern unsigned char vc9202_drv_get_sampling_data(SamplingDataTypeDef *pSamplingData, unsigned char *psize);\r
+/* electrostatic patch */\r
+extern void vc9202_drv_electrostatic_death( void );\r
+\r
+#endif\r
--- /dev/null
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ *********************************************************************************************************\r
+ * @file vc9202_driver.h\r
+ * @brief vc9202 driver layer interface implementation.\r
+ * @details \r
+ * @author \r
+ * @date\r
+ * @version\r
+ *********************************************************************************************************/\r
+\r
+#ifndef __VC9202_DRIVER_H__\r
+#define __VC9202_DRIVER_H__\r
+\r
+#include "vc9202_common.h"\r
+\r
+#define VC9202_STATUS_CONFLICT (1<<4)\r
+#define VC9202_STATUS_INSAMPLE (1<<3)\r
+#define VC9202_STATUS_OVERLOAD2 (1<<2)\r
+#define VC9202_STATUS_OVERLOAD1 (1<<1)\r
+#define VC9202_STATUS_OVERLOAD0 (1<<0)\r
+\r
+#define VC9202_EVENT_TEMP_MARK (1<<6) //128\r
+#define VC9202_EVENT_BIO_MARK (1<<5) //64\r
+#define VC9202_EVENT_PS_MARK (1<<4) //32\r
+#define VC9202_EVENT_OV_MARK (1<<3) //8\r
+#define VC9202_EVENT_FIFO_MARK (1<<2) //4 \r
+#define VC9202_EVENT_ENV_MARK (1<<1) //2\r
+#define VC9202_EVENT_PPG_MARK (1<<0) //1\r
+\r
+#define VC9202_MAX_RES_LEVEL 17 //21 9202offset只有0-2,3和2一样、所以表中只有17个等效\r
+#define VC9202_MAX_CUR_LEVEL 0x6F\r
+\r
+#define VC9202_ENV_MAX_TH 8*16\r
+\r
+/* adjust marco */\r
+#define VC9202_PPG_TH_CELL 10 // Causes of PPG interruption PPG_TH = 300\r
+#define VC9202_ADJUST_INCREASE 22 // 1.4 << 4 = 22.4//1.4f\r
+#define VC9202_ADJUST_DECREASE 11 // 0.7 << 4 = 11.2//0.7f\r
+#define VC9202_ADJUST_STEP_MAX 32\r
+#define VC9202_ADJUST_STEP_MIN 1\r
+#define VC9202_SLOTCHNU 3\r
+\r
+/* bio算法运算结果宏定义 */\r
+#define VC9202_BIO_STA_NONE 0\r
+#define VC9202_BIO_STA_DROP 1\r
+#define VC9202_BIO_STA_HOLD 2\r
+\r
+/****************************************************************************\r
+ * driver ret enum\r
+ ***************************************************************************/\r
+typedef enum\r
+{\r
+ RET_OK = 0,\r
+ RET_STATUS_ERR = (1<<0),\r
+ RET_OVERLOAD_ERR = (1<<1),\r
+ RET_ENV_ERR = (1<<2),\r
+ RET_PPG_ERR = (1<<3),\r
+ RET_OSC_ERR = (1<<4),\r
+ RET_FIFO_ERR = (1<<5),\r
+}VC9202DrvRetTypeDef;\r
+\r
+/****************************************************************************\r
+ * clock calibration_struct\r
+ ***************************************************************************/\r
+typedef struct\r
+{\r
+ unsigned int last_clk_count;\r
+ unsigned int osc_gap_cnt;\r
+ unsigned char count_index;\r
+ unsigned int osc_count[6];\r
+ unsigned int clk_count[6];\r
+ unsigned int last_clk_check; /* 2023.06.05,check running gaptime */\r
+}VC9202OscClkTypeDef;\r
+\r
+/****************************************************************************\r
+ * WearStatus_struct\r
+ ***************************************************************************/\r
+typedef struct\r
+{\r
+ unsigned char wear_ps;\r
+ unsigned char wear_env;\r
+ short int wear_bio;\r
+ unsigned char wear_hold_cnt;\r
+ unsigned char wear_drop_cnt;\r
+ WearStatusTypeDef wear_status;\r
+ WearStatusTypeDef last_status;\r
+}VC9202WearInfoTypeDef;\r
+\r
+typedef enum\r
+{\r
+ WEAR_NO_CHANGE = 0,\r
+ DROP_TO_HOLD = 1,\r
+ HOLD_TO_DROP = 2,\r
+}VC9202WearChangeTypeDef;\r
+\r
+/****************************************************************************\r
+ * ADJUST_struct\r
+ ***************************************************************************/\r
+typedef struct\r
+{\r
+ unsigned char res;\r
+ unsigned char offset;\r
+ unsigned char low;\r
+}VC9202ResTableTypeDef; \r
+\r
+typedef struct\r
+{\r
+ unsigned char res_val;\r
+ unsigned char low_res;\r
+ unsigned char offset;\r
+ unsigned char offset3;\r
+}VC9202ResLevelTypeDef;\r
+\r
+typedef enum\r
+{\r
+ AGC_DIR_NULL = 0,\r
+ AGC_DIR_UP = 1,\r
+ AGC_DIR_DOWN = 2,\r
+}VC9202AgcDirTypeDef;\r
+\r
+typedef struct\r
+{\r
+ VC9202AgcDirTypeDef dir;\r
+ VC9202AgcDirTypeDef last_dir;\r
+ unsigned char current_step;\r
+}VC9202AgcInfoTypeDef;\r
+\r
+typedef struct\r
+{\r
+ unsigned char max_current;\r
+ unsigned char max_res_level;\r
+ unsigned char record_env;\r
+ unsigned char slot_env;\r
+ unsigned char current;\r
+ unsigned char res_level;\r
+ VC9202AgcInfoTypeDef info;\r
+}VC9202AdjustSlotTypeDef;\r
+\r
+/****************************************************************************\r
+ * Dev_struct\r
+ ***************************************************************************/\r
+typedef struct\r
+{\r
+ unsigned short fifo_time;\r
+ unsigned char work_frequency;\r
+ unsigned char enable_bio;\r
+ WorkModeTypeDef work_mode;\r
+ \r
+ unsigned char work_status;\r
+ unsigned int int_event;\r
+\r
+ WearStatusTypeDef wear_status;\r
+ unsigned char osc_clk_status; \r
+ unsigned char enfifo_div;\r
+ unsigned char enslot[2];\r
+ unsigned char slot_number;\r
+ unsigned char read_fifo_address;\r
+ \r
+}VC9202DrvInfoTypeDef;\r
+\r
+/****************************************************************************\r
+ * test_struct\r
+ ***************************************************************************/\r
+typedef struct\r
+{\r
+ unsigned char wait_cnt;\r
+ unsigned char step1_ret; // step1_ret/step2_ret/step3_ret:0-wait test,1-pass,2-failed\r
+ unsigned char icid;\r
+ unsigned char reason;\r
+ unsigned char leak_pre_value;\r
+ unsigned char max_current;\r
+ signed short temperature;\r
+ unsigned int frequency;\r
+\r
+ unsigned char step2_ret;\r
+ unsigned char ps_value;\r
+ unsigned short biovalue_max;\r
+ unsigned short biovalue_now[2];\r
+ unsigned short biovalue_gap[2];\r
+} VC9202TestInfoTypeDef;\r
+\r
+\r
+#endif\r
--- /dev/null
+/*
+ * @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
--- /dev/null
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2024-12-07 16:04:22\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2024-12-21 17:20:35\r
+ * @FilePath: /sdk615/code/sdk/drivers/peripheral/ppg/vc9202/inc/vc9202_user.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc9202_user.h\r
+ * @brief functional Module Layer\r
+ * @details The functional interface is implemented by calling the driver.contain init_func,irq_handler\r
+ * @author \r
+ * @date\r
+ * @version \r
+ *********************************************************************************************************/\r
+\r
+#ifndef __VC9202_USER_H__\r
+#define __VC9202_USER_H__\r
+\r
+#include "vc9202_common.h"\r
+\r
+/* gsensor struct */\r
+typedef struct\r
+{\r
+ unsigned char sampling_rate; /* 25hz,50hz */\r
+ unsigned char sensing_range; /* ±4G, ±8G, ±16G*/\r
+ unsigned char effective_bits; /* 11(12)bit, 15(16)bit */\r
+\r
+ int gsensor_x_axis[40];\r
+ int gsensor_y_axis[40];\r
+ int gsensor_z_axis[40];\r
+}GsensorTypeDef;\r
+\r
+\r
+typedef struct\r
+{\r
+ short int hr_rate;\r
+ unsigned char spo2_val;\r
+ unsigned char hrv_results;\r
+ unsigned char stress_results;\r
+ signed short int temperature_value;\r
+}AlgoCalcResultsTypeDef;\r
+\r
+void vc9202_usr_init( InitParamTypeDef *pInitParam );\r
+void vc9202_usr_get_chip_id( unsigned char *pchip_id, unsigned char *pvers_id );\r
+void vc9202_usr_start_sampling(void);\r
+void vc9202_usr_stop_sampling(void);\r
+void vc9202_usr_soft_reset(void);\r
+unsigned char vc9202_usr_channel_switch(unsigned char num_channel, unsigned char enable_flag);\r
+unsigned char vc9202_usr_get_int_reason(void);\r
+unsigned char vc9202_usr_get_wear_status(void);\r
+void vc9202_usr_interrupt_handler( AlgoSportMode hr_alg_mode, unsigned char spo2_alg_mode );\r
+\r
+#endif\r
+\r
--- /dev/null
+#ifndef __VCSPORTMOTIONALGOH__
+#define __VCSPORTMOTIONALGOH__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+
+void vcSportMotionAlgoInit(void);
+int32_t vcSportMotionCalculate(int32_t x, int32_t y, int32_t z);
+char* version_info_SportMotion(void);
+
+#endif
--- /dev/null
+C:\Users\zwj\Documents\WXWork\1688852039096625\WeDrive\维客昕微\技术支持组和应用方案开发组公共文件\1.心率IC\1.心率+血氧资料\2.驱动文件\VCHR9202\drv_9202_sensor_v218\algo
\ No newline at end of file
--- /dev/null
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc9202_driver.c\r
+ * @brief vc9202 driver layer interface implementation.\r
+ * @details\r
+ * @author\r
+ * @date\r
+ * @version\r
+ *********************************************************************************************************/\r
+#include "vc9202_common.h"\r
+#include "vc9202_driver.h"\r
+#include "BIODetect_V15_1.h"\r
+\r
+/* static wear status declaration */\r
+static int bio_result = VC9202_BIO_STA_NONE;\r
+static WearStatusTypeDef alg_wear_status = WEAR_STA_HOLD;\r
+static unsigned int gsnesor_axis_diff = 0;\r
+static VC9202WearInfoTypeDef dev9202_wear = {0};\r
+/* static adjust data declaration */\r
+static VC9202AdjustSlotTypeDef dev9202_adjust[3] = {0};\r
+static unsigned char ppg_mark[128 / 2] = {0};\r
+/* static device data declaration */\r
+static VC9202DrvInfoTypeDef dev9202_info = {0};\r
+/* static oscclk data declaration */\r
+static VC9202OscClkTypeDef dev9202_clk = {0};\r
+\r
+static int Bio_Max_Value = 0;\r
+static int Bio_Max_Diff_Value = 0;\r
+static int Bio_Min_Diff_Value = 0;\r
+static int Bio_Old_Value = 0;\r
+static uint8_t Bio_cnt = 0;\r
+static uint8_t Bio_HOLD_cnt = 0;\r
+static uint8_t BIO_HOLD_DROP_FLAG = 2;\r
+/* global test infomation declaration */\r
+extern VC9202TestInfoTypeDef vc9202_test_info;\r
+extern void vc9202_test_handler(SamplingDataTypeDef *pResult, VC9202TestInfoTypeDef *ptest_info);\r
+extern void vc9202_test_init(VC9202TestInfoTypeDef *ptest_info);\r
+/* res-level tab */\r
+const static VC9202ResTableTypeDef res_table[22] = {\r
+ /* level: 0 */ {0, 0, 1},\r
+ /* level: 1 */ {1, 0, 1},\r
+ /* level: 2 */ {2, 0, 1},\r
+ /* level: 3 */ {3, 0, 1},\r
+ /* level: 4 */ {4, 0, 1},\r
+ /* level: 5 */ {5, 0, 1},\r
+ /* level: 6 */ {0, 0, 0},\r
+ /* level: 7 */ {1, 0, 0},\r
+ /* level: 8 */ {2, 0, 0},\r
+ /* level: 9 */ {3, 0, 0},\r
+ /* level:10 */ {4, 0, 0},\r
+ /* level:11 */ {5, 0, 0},\r
+ /* level:12 */ {6, 0, 0},\r
+ /* level:13 */ {7, 0, 0},\r
+ /* level:14 */ {6, 1, 0}, /* +2 */\r
+ /* level:15 */ {7, 1, 0},\r
+ /* level:16 */ {6, 2, 0}, /* +4 */\r
+ /* level:17 */ {7, 2, 0},\r
+ /* level:18 */ {6, 3, 0}, /* +6 */\r
+ /* level:19 */ {7, 3, 0},\r
+ /* level:20 */ {6, 4, 0}, /* +8 */\r
+ /* level:21 */ {7, 4, 0},\r
+}; // 21-5 = 16\r
+\r
+void vc9202_drv_set_gsensor_actuating_quantity(unsigned int axis_diff)\r
+{\r
+ gsnesor_axis_diff = axis_diff;\r
+}\r
+\r
+void vc9202_drv_set_algo_wear_status(WearStatusTypeDef status)\r
+{\r
+ alg_wear_status = status;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * 时钟校准部分\r
+ ********************************************************************************************************/\r
+static void vc9202_drv_clear_clk(void)\r
+{\r
+ dev9202_clk.osc_gap_cnt = 0;\r
+ dev9202_clk.count_index = 0;\r
+ dev9202_clk.last_clk_count = 0;\r
+ dev9202_info.osc_clk_status = 0;\r
+\r
+ dev9202_clk.last_clk_check = 0;\r
+}\r
+/**\r
+ * @brief 时钟校验,与原来的VC9201系列一致\r
+ * @param 无\r
+ * @retval\r
+ 0 校验正常通过\r
+ 1 vc9202计数当次就溢出\r
+ 2 mcu tick或vc9202后两次中断的时候有计数溢出\r
+ 3 频率计算没有通过\r
+ */\r
+static unsigned char vc9202_drv_calibration_osc_clk(void)\r
+{\r
+ unsigned char count_vaild = 1;\r
+ unsigned char i = 0;\r
+ unsigned char osc_buf[4] = {0};\r
+ unsigned int osc_tick[2] = {0};\r
+ unsigned int clock_tick[2] = {0};\r
+ unsigned short int calc_div[2] = {0};\r
+ unsigned short int mean_div = 0;\r
+ unsigned char reg_div1[2] = {0};\r
+ /* 判断是否需要校准时钟,如不需则直接返回 */\r
+ unsigned int sec_gap_cnt = VC9202_CFG_CLK_CHECK_GAPTIME * 1000 / dev9202_info.fifo_time;\r
+ if (dev9202_info.osc_clk_status && dev9202_clk.osc_gap_cnt++ <= sec_gap_cnt)\r
+ {\r
+ return 0;\r
+ }\r
+ /* 获取时钟计数 */\r
+ clock_tick[0] = usr_get_clock_ticks();\r
+ usr_iic_read_bytes(0x07, osc_buf, 4);\r
+ clock_tick[1] = usr_get_clock_ticks();\r
+ osc_tick[0] = (osc_buf[0] << 8) + osc_buf[1];\r
+ osc_tick[1] = (osc_buf[2] << 8) + osc_buf[3];\r
+ if ((osc_tick[0] > osc_tick[1]) || (clock_tick[0] > clock_tick[1]))\r
+ {\r
+ dev9202_clk.count_index = 0;\r
+ return 1;\r
+ }\r
+ /* 存入校准缓存 */\r
+ dev9202_clk.osc_count[dev9202_clk.count_index * 2] = osc_tick[0];\r
+ dev9202_clk.osc_count[dev9202_clk.count_index * 2 + 1] = osc_tick[1];\r
+ dev9202_clk.clk_count[dev9202_clk.count_index * 2] = clock_tick[0];\r
+ dev9202_clk.clk_count[dev9202_clk.count_index * 2 + 1] = clock_tick[1];\r
+ dev9202_clk.count_index++;\r
+ if (dev9202_clk.count_index >= 3)\r
+ {\r
+ dev9202_clk.count_index = 0;\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ 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);\r
+ 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);\r
+ count_vaild = count_vaild && (!(dev9202_clk.clk_count[2 * i + 2] == dev9202_clk.clk_count[2 * i])); /* avoid divisor==0, diffCountIsOk set false */\r
+ }\r
+ if (count_vaild)\r
+ {\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ 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;\r
+ if (calc_div[i] < (20000 / dev9202_info.work_frequency * 0.75f) || calc_div[i] > (20000 / dev9202_info.work_frequency * 1.25f))\r
+ {\r
+ return 3;\r
+ }\r
+ }\r
+ /* 比较两次计算偏差是否合理 */\r
+ if ((calc_div[1] - calc_div[0] <= 20) || (calc_div[0] - calc_div[1] <= 20))\r
+ {\r
+ mean_div = (calc_div[1] + calc_div[0]) / 2;\r
+ reg_div1[0] = mean_div >> 8;\r
+ reg_div1[1] = mean_div;\r
+ usr_iic_write_bytes(0x14, reg_div1, 2);\r
+ dev9202_clk.count_index = 0;\r
+ dev9202_clk.osc_gap_cnt = 0;\r
+ dev9202_info.osc_clk_status = 1;\r
+ return 0;\r
+ }\r
+ }\r
+ }\r
+ return 2;\r
+}\r
+/********************************************************************************************************\r
+ * 摘配带判断部分\r
+ ********************************************************************************************************/\r
+/**\r
+ * @brief 佩戴检测,bio检测计算(内部阅读:f_BIOdetect,在BIO+PS均由佩戴产生的边缘时输出2佩戴;摘下时只依赖PS边缘)\r
+ * @param\r
+ bio_value bio采样值\r
+ ps_value ps采样值\r
+ * @retval bio结果\r
+ */\r
+static int vc9202_drv_calc_biology_sense(unsigned short int bio_value, unsigned char ps_value, unsigned char env)\r
+{\r
+ static unsigned char calc_ps = 0;\r
+ static unsigned short int calc_bio = 0;\r
+ static int Bio_Diff_Value = 0;\r
+ int ret = 0;\r
+ if (bio_value)\r
+ {\r
+ calc_bio = bio_value;\r
+ Bio_Diff_Value = abs(Bio_Old_Value - calc_bio);\r
+ Bio_Old_Value = calc_bio;\r
+ }\r
+ if (ps_value)\r
+ {\r
+ calc_ps = ps_value;\r
+ }\r
+ if ((calc_ps < 100) && (env > 4))\r
+ {\r
+ if (Bio_Diff_Value < VC9202_CFG_WEAR_PARAM_BIOIN * 0.2)\r
+ {\r
+ Bio_Max_Value = calc_bio;\r
+ Bio_Max_Diff_Value = Bio_Max_Value - (VC9202_CFG_WEAR_PARAM_BIOIN * 0.8);\r
+ Bio_Min_Diff_Value = Bio_Max_Value - (VC9202_CFG_WEAR_PARAM_BIOIN * 1.5);\r
+ }\r
+ }\r
+ if (Bio_Max_Diff_Value)\r
+ {\r
+ if ((calc_bio > Bio_Max_Diff_Value) && (Bio_Diff_Value < VC9202_CFG_WEAR_PARAM_BIOIN * 0.2))\r
+ {\r
+ Bio_HOLD_cnt++;\r
+ if (Bio_HOLD_cnt > 4)\r
+ {\r
+ BIO_HOLD_DROP_FLAG = 1;\r
+ }\r
+ }\r
+ else if (calc_bio < Bio_Min_Diff_Value)\r
+ {\r
+ Bio_cnt++;\r
+ if (Bio_cnt > 2)\r
+ {\r
+ BIO_HOLD_DROP_FLAG = 2;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Bio_cnt = 0;\r
+ Bio_HOLD_cnt = 0;\r
+ BIO_HOLD_DROP_FLAG = 0;\r
+ }\r
+ }\r
+ uint32_t tm;\r
+ uapi_get_timestampe_ms(&tm);\r
+ printf("before f_BIOdetect bio_value :%d , ps_value : %d , env : %d , tm : %d\n",bio_value,ps_value,env,tm);\r
+ 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);\r
+ ret = f_BIOdetect(calc_bio, calc_ps, VC9202_CFG_WEAR_PARAM_PS);\r
+ 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);\r
+ printf("after f_BIOdetect bio_value :%d , ps_value : %d , env : %d , tm : %d\n",bio_value,ps_value,env,tm);\r
+ if (VC9202_BIO_STA_HOLD == ret)\r
+ {\r
+ vc9202_drv_set_algo_wear_status(WEAR_STA_HOLD); /* bio */\r
+ bio_result = VC9202_BIO_STA_HOLD;\r
+ }\r
+ else if (VC9202_BIO_STA_DROP == ret)\r
+ {\r
+ bio_result = VC9202_BIO_STA_DROP;\r
+ }\r
+ return bio_result;\r
+}\r
+/**\r
+ * @brief 佩戴检测过程及状态\r
+ * @param *pwear-佩戴结构体,env-环境光,ps-ps值,bio-活体值\r
+ * @retval 识别改变结果\r
+ */\r
+static VC9202WearChangeTypeDef vc9202_drv_wear_status_identify(VC9202WearInfoTypeDef *pwear, unsigned char env, unsigned char ps, unsigned short int bio)\r
+{\r
+ printf("vc9202_drv_wear_status_identify bio : %d \n",bio);\r
+ VC9202WearChangeTypeDef ret_change = WEAR_NO_CHANGE;\r
+ int ret_bio_algo = VC9202_BIO_STA_NONE;\r
+ /* bio算法运算 */\r
+ if (dev9202_info.enable_bio)\r
+ {\r
+ ret_bio_algo = vc9202_drv_calc_biology_sense(bio, ps, env);\r
+ }\r
+ else\r
+ {\r
+ ret_bio_algo = VC9202_BIO_STA_HOLD; /* 20230614 因为下面的条件把(ret_bio_algo== )佩戴的条件删了,所以此处必须添加,不然在未开bio的模式下无法佩戴*/\r
+ }\r
+#if (FUNC_DISABLE == VC9202_CFG_WEAR_THRESHOLD_EN)\r
+ BIO_HOLD_DROP_FLAG = 2;\r
+#endif\r
+#if (FUNC_DISABLE == VC9202_CFG_WEAR_BIO_EN)\r
+ ret_bio_algo = VC9202_BIO_STA_NONE;\r
+ BIO_HOLD_DROP_FLAG = 2;\r
+#endif\r
+#if (FUNC_DISABLE == VC9202_CFG_WEAR_ALG_EN)\r
+ alg_wear_status = WEAR_STA_HOLD;\r
+#endif\r
+#if (FUNC_DISABLE == VC9202_CFG_WEAR_ACT_EN)\r
+ gsnesor_axis_diff = 1;\r
+#endif\r
+ switch (pwear->wear_status)\r
+ {\r
+ case WEAR_STA_DROP:\r
+ 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);\r
+ if ((ps >= VC9202_CFG_WEAR_PARAM_PS) && (env <= VC9202_CFG_WEAR_PARAM_ENVMIN) && (VC9202_BIO_STA_HOLD == ret_bio_algo) &&\r
+ (WEAR_STA_HOLD == alg_wear_status) && (1 == gsnesor_axis_diff) && (BIO_HOLD_DROP_FLAG == 2))\r
+ {\r
+ if (--pwear->wear_hold_cnt <= 0)\r
+ {\r
+ pwear->wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT;\r
+ pwear->wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT;\r
+ ret_change = DROP_TO_HOLD;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ pwear->wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT;\r
+ }\r
+ break;\r
+\r
+ case WEAR_STA_HOLD:\r
+ 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);\r
+ 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))\r
+ {\r
+ if ((WEAR_STA_DROP == alg_wear_status) || (ret_bio_algo == VC9202_BIO_STA_DROP))\r
+ {\r
+ pwear->wear_drop_cnt = 1;\r
+ }\r
+ if (--pwear->wear_drop_cnt <= 0)\r
+ {\r
+ pwear->wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT;\r
+ pwear->wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT;\r
+ ret_change = HOLD_TO_DROP;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ pwear->wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ return ret_change;\r
+}\r
+\r
+/**\r
+ * @brief 佩戴检测及通道的开关\r
+ * @param 无\r
+ * @retval 佩戴检测状态\r
+ */\r
+WearStatusTypeDef vc9202_drv_get_wear_status(void)\r
+{\r
+ WearStatusTypeDef wear_status = dev9202_wear.last_status; /* last status */\r
+ VC9202WearChangeTypeDef calc_status = WEAR_NO_CHANGE;\r
+ unsigned char event = 0;\r
+ unsigned char en_int = 0;\r
+ unsigned char env_value = 0, ps_value = 0;\r
+ unsigned char bio_buffer[4] = {0};\r
+ unsigned short int bio_value = 0;\r
+ unsigned char wear_interrupt = 0;\r
+ unsigned char slot_index = 0;\r
+#if (VC9202_CFG_WEAR_DETECTION != FUNC_ENABLE)\r
+ return WEAR_IS_HOLD;\r
+#endif\r
+ usr_iic_read_bytes(0x11, &en_int, 1);\r
+#if 0\r
+ usr_iic_read_bytes(0x02, &event, 1);\r
+#else\r
+ event = dev9202_info.int_event;\r
+#endif\r
+#if (FUNC_ENABLE == VC9202_CFG_DRV_BY_TIMER) /* 定时触发时,不看中断原因,可能被清掉 */\r
+ wear_interrupt = 1;\r
+#else\r
+ /* 使能了PsInt,且使能PS */\r
+ if ((event & VC9202_EVENT_PS_MARK) && (en_int & (1 << 4)))\r
+ {\r
+ wear_interrupt = 1;\r
+ }\r
+ /* 未使能PsInt下,ps_ppg同频通过fifo中断去识别摘配带 */\r
+ if (event & VC9202_EVENT_FIFO_MARK)\r
+ {\r
+ wear_interrupt = 1;\r
+ }\r
+#endif\r
+ /* 非心率模式,就算使能了运动量,也没有去做处理,直接置1忽略 */\r
+ if (dev9202_info.work_mode != WORK_MODE_HR && dev9202_info.work_mode != WORK_MODE_WEAR)\r
+ {\r
+ gsnesor_axis_diff = 1;\r
+ }\r
+ if (wear_interrupt)\r
+ {\r
+/* 读取佩戴检测所需的数据 */\r
+#if 0\r
+ usr_iic_read_bytes(0x43, &env_value, 1);\r
+ usr_iic_read_bytes(0x46, &ps_value, 1);\r
+ usr_iic_read_bytes(0x4B, bio_buffer, 4);\r
+ bio_value = (bio_buffer[2] << 8) + bio_buffer[3];\r
+#else\r
+ env_value = dev9202_wear.wear_env;\r
+ ps_value = dev9202_wear.wear_ps;\r
+ bio_value = dev9202_wear.wear_bio;\r
+#endif\r
+ /* 根据数据得出佩戴状态 */\r
+ calc_status = vc9202_drv_wear_status_identify(&dev9202_wear, env_value, ps_value, bio_value);\r
+ if (DROP_TO_HOLD == calc_status)\r
+ {\r
+ wear_status = WEAR_STA_HOLD;\r
+ dev9202_wear.wear_status = wear_status;\r
+ dev9202_wear.last_status = wear_status;\r
+ InitParamTypeDef init_param = {dev9202_info.fifo_time, dev9202_info.work_mode};\r
+ vc9202_drv_reg_init(&init_param);\r
+ }\r
+ else if (HOLD_TO_DROP == calc_status)\r
+ {\r
+ wear_status = WEAR_STA_DROP;\r
+ dev9202_wear.wear_status = wear_status;\r
+ dev9202_wear.last_status = wear_status;\r
+ /* 关灯操作:获取那些ppg通道使能/记录当前使能的通道,然后关闭通道 */\r
+ for (slot_index = 0; slot_index <= 1; slot_index++)\r
+ {\r
+ if (dev9202_info.enslot[slot_index])\r
+ {\r
+ vc9202_drv_channel_switch(slot_index, 0);\r
+ }\r
+ }\r
+ } /* end of(HOLD_TO_DROP == calc_status) */\r
+ }\r
+ return wear_status;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * IC状态读取部分,包括IC异常状态处理,常规数据的读取,ENV、PPG调整部分\r
+ ********************************************************************************************************/\r
+/**\r
+ * @brief 等效电阻等级转化为寄存器参数\r
+ * @param level 等效电阻等级\r
+ * @retval 寄存器参数\r
+ */\r
+static VC9202ResLevelTypeDef vc9202_drv_res_level_to_register(unsigned char level)\r
+{\r
+ VC9202ResLevelTypeDef reg;\r
+ reg.res_val = res_table[level].res;\r
+ reg.low_res = res_table[level].low;\r
+ if (res_table[level].offset >= 4)\r
+ {\r
+ reg.offset = 0;\r
+ reg.offset3 = 1;\r
+ }\r
+ else\r
+ {\r
+ reg.offset = res_table[level].offset;\r
+ reg.offset3 = 0;\r
+ }\r
+ return reg;\r
+}\r
+\r
+/**\r
+ * @brief 寄存器参数转化为等效电阻等级\r
+ * @param 寄存器参数\r
+ * @retval 等效电阻等级\r
+ */\r
+static unsigned char vc9202_drv_res_register_to_level(VC9202ResLevelTypeDef *preg)\r
+{\r
+ unsigned char index = 0;\r
+ unsigned char level = 0;\r
+ VC9202ResTableTypeDef table = {0};\r
+ if (preg->offset3 == 1)\r
+ {\r
+ table.offset = 4;\r
+ }\r
+ else\r
+ {\r
+ table.offset = preg->offset;\r
+ }\r
+ table.res = preg->res_val;\r
+ table.low = preg->low_res;\r
+ for (index = 0; index < sizeof(res_table) / sizeof(res_table[0]); index++)\r
+ {\r
+ if (res_table[index].res == table.res && res_table[index].offset == table.offset && res_table[index].low == table.low)\r
+ {\r
+ level = index;\r
+ break;\r
+ }\r
+ }\r
+ return level;\r
+}\r
+\r
+/**\r
+ * @brief 设置通道电流参数\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+static void vc9202_drv_set_ppgSlot_current(unsigned char slot_index, unsigned char cur)\r
+{\r
+ unsigned char reg = 0;\r
+ unsigned char addr = 0x17 + slot_index;\r
+ cur = (cur > 0x7f) ? 0x7f : cur;\r
+ usr_iic_read_bytes(addr, ®, 1);\r
+ reg &= (1 << 7);\r
+ reg |= cur;\r
+ usr_iic_write_bytes(addr, ®, 1);\r
+}\r
+\r
+/**\r
+ * @brief 设置通道电阻参数\r
+ * @param 设置的通道号,设定的值\r
+ * @retval 无\r
+ */\r
+static void vc9202_drv_set_ppgSlot_resistance(unsigned char slot_index, unsigned char level)\r
+{\r
+ unsigned char reg_addr = 0x1A + slot_index;\r
+ unsigned char res_reg = 0;\r
+ unsigned char res_ext[2] = {0};\r
+ VC9202ResLevelTypeDef res = {0};\r
+ level = (level > VC9202_MAX_RES_LEVEL) ? VC9202_MAX_RES_LEVEL : level;\r
+ res = vc9202_drv_res_level_to_register(level);\r
+ usr_iic_read_bytes(0x22, res_ext, 2);\r
+ switch (slot_index)\r
+ {\r
+ case 0:\r
+ res_ext[0] &= ~(3 << 4); /* offset */\r
+ res_ext[0] |= (res.offset << 4);\r
+ res_ext[0] &= ~(1 << 0); /* lowres */\r
+ res_ext[0] |= (res.low_res << 0);\r
+ res_ext[1] &= ~(1 << 0);\r
+ res_ext[1] |= (res.offset3 << 0);\r
+ break;\r
+ case 1:\r
+ res_ext[0] &= ~(3 << 6); /* offset */\r
+ res_ext[0] |= (res.offset << 6);\r
+ res_ext[0] &= ~(1 << 1); /* lowres */\r
+ res_ext[0] |= (res.low_res << 1);\r
+ res_ext[1] &= ~(1 << 2);\r
+ res_ext[1] |= (res.offset3 << 2);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ usr_iic_read_bytes(reg_addr, &res_reg, 1);\r
+ res_reg &= (0x8f);\r
+ res_reg |= (res.res_val << 4);\r
+ usr_iic_write_bytes(reg_addr, &res_reg, 1);\r
+ usr_iic_write_bytes(0x22, res_ext, 2);\r
+}\r
+/**\r
+ * @brief 读取PPG饱和中断时的采样值\r
+ * @param enfifo-是否使能fifo,slot_num-通道数,slot_index-通道号, *pdata 数据指针\r
+ * @retval 返回当前读取地址\r
+ */\r
+static unsigned char vc9202_drv_adjust_ppg_read(unsigned char enfifo, unsigned char slot_num, unsigned char slot_index, unsigned int *pdata)\r
+{\r
+ unsigned char write_index = 0, fifo_addr = 0;\r
+ unsigned char fifo_buff[2] = {0};\r
+ /* PPG IRQ addr */\r
+ usr_iic_read_bytes(0x03, &write_index, 1);\r
+ fifo_addr = write_index - slot_num * 2 + slot_index * 2;\r
+ fifo_addr = (fifo_addr < 0x80) ? (fifo_addr + 0x80) : (fifo_addr);\r
+ fifo_addr = enfifo ? fifo_addr : 0x80 + slot_index * 2;\r
+ /* read PPG data */\r
+ usr_iic_read_bytes(fifo_addr, fifo_buff, 2);\r
+ *pdata = (fifo_buff[0] << 8) + fifo_buff[1];\r
+ return write_index;\r
+}\r
+\r
+/**\r
+ * @brief 参数调整时,添加调整标志位\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+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 )\r
+{\r
+ unsigned char mark_ppg_index = 0;\r
+ unsigned char mark_offset = 0;\r
+ unsigned char rindex = dev9202_info.read_fifo_address;\r
+ unsigned char windex = 0;\r
+ usr_iic_read_bytes(0x03, &windex, 1);\r
+ /* calc PPGOffset */\r
+ if (windex > rindex)\r
+ {\r
+ mark_offset = (windex - rindex);\r
+ }\r
+ else\r
+ {\r
+ mark_offset = windex + 128 - rindex;\r
+ }\r
+ if ((mark_offset < 2) || (mark_offset > 128))\r
+ {\r
+ return;\r
+ }\r
+ mark_ppg_index = mark_offset / 2 - dev9202_info.slot_number + slot_index; /* 如果是双通道,要判断是那个通道产生的调整 */\r
+ ppg_mark[mark_ppg_index] = 1;\r
+}\r
+\r
+/**\r
+ * @brief 检测因电阻过大,电流的最小步长调整都会反复饱和的情况\r
+ * @param dir 调整方向, slot_index 当前通道, res_level 当前电阻等级, cur 当前电流值\r
+ * @retval 1:错误,0:正常\r
+ */\r
+static unsigned char vc9202_drv_adjust_res_error(VC9202AgcDirTypeDef dir, unsigned char slot_index, uint8_t res_level, uint8_t cur)\r
+{\r
+ static VC9202AgcDirTypeDef lastDir = AGC_DIR_NULL;\r
+ static uint8_t last_level = 0;\r
+ static uint8_t last_cur[2][3] = {0};\r
+ static uint8_t log_cnt = 0;\r
+ if (lastDir != dir && last_level == res_level)\r
+ {\r
+ last_cur[slot_index][0] = last_cur[slot_index][1];\r
+ last_cur[slot_index][1] = last_cur[slot_index][2];\r
+ last_cur[slot_index][2] = cur;\r
+ if (last_cur[slot_index][0] == last_cur[slot_index][2])\r
+ log_cnt++;\r
+ }\r
+ else\r
+ {\r
+ log_cnt = 0;\r
+ }\r
+ lastDir = dir;\r
+ last_level = res_level;\r
+ if (log_cnt >= 3)\r
+ {\r
+ log_cnt = 0;\r
+ return 1;\r
+ }\r
+ else\r
+ {\r
+ return 0;\r
+ }\r
+}\r
+\r
+/**\r
+ * @brief PPG饱和时,上/下调整电流电阻配置参数\r
+ * @param *padjust-调整结构体,thh_res-电阻限值,thh_cur-电流限值,slot_index-通道编号\r
+ * @retval 执行结果\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_adjust_ppg_slot_current_res_config(VC9202AdjustSlotTypeDef *padjust, unsigned char thh_res, unsigned char thh_cur, unsigned char slot_index)\r
+{\r
+ unsigned char old_res_lvl = 0;\r
+ unsigned char old_current = 0;\r
+ unsigned short int old_current_step = 0;\r
+ old_res_lvl = padjust->res_level;\r
+ old_current = padjust->current;\r
+ old_current_step = padjust->info.current_step;\r
+ /* 电流已经最大,调电阻 */\r
+ if (padjust->current == thh_cur)\r
+ {\r
+ if (old_res_lvl == thh_res)\r
+ {\r
+ return RET_PPG_ERR;\r
+ }\r
+ else\r
+ {\r
+ if (padjust->info.dir == AGC_DIR_UP)\r
+ {\r
+ padjust->res_level = (old_res_lvl >= VC9202_MAX_RES_LEVEL) ? (VC9202_MAX_RES_LEVEL) : (old_res_lvl + 1);\r
+ }\r
+ else\r
+ {\r
+ padjust->res_level = (old_res_lvl < 1) ? (0) : (old_res_lvl - 1);\r
+ }\r
+ vc9202_drv_adjust_set_fifo_mark(slot_index);\r
+ }\r
+ }\r
+ else /* 电流可调 */\r
+ {\r
+ /* step calc */\r
+ if (padjust->info.last_dir == AGC_DIR_NULL)\r
+ {\r
+ old_current_step *= 16;\r
+ }\r
+ else if (padjust->info.dir == padjust->info.last_dir)\r
+ {\r
+ if ((old_current_step == 1) || (old_current_step == 2))\r
+ {\r
+ old_current_step = (old_current_step + 1) * 16;\r
+ }\r
+ else\r
+ {\r
+ old_current_step *= VC9202_ADJUST_INCREASE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ old_current_step *= VC9202_ADJUST_DECREASE;\r
+ }\r
+ padjust->info.current_step = old_current_step >> 4;\r
+ padjust->info.current_step = (padjust->info.current_step <= VC9202_ADJUST_STEP_MIN) ? VC9202_ADJUST_STEP_MIN : padjust->info.current_step;\r
+ padjust->info.current_step = (padjust->info.current_step >= VC9202_ADJUST_STEP_MAX) ? VC9202_ADJUST_STEP_MAX : padjust->info.current_step;\r
+ /* 调整方向 */\r
+ if (padjust->info.dir == AGC_DIR_UP)\r
+ {\r
+ padjust->current = ((old_current + padjust->info.current_step) > thh_cur) ? thh_cur : (old_current + padjust->info.current_step);\r
+ }\r
+ else\r
+ {\r
+ padjust->current = (old_current < padjust->info.current_step) ? thh_cur : old_current - padjust->info.current_step;\r
+ }\r
+ vc9202_drv_adjust_set_fifo_mark(slot_index);\r
+ padjust->info.last_dir = padjust->info.dir;\r
+ }\r
+ if (vc9202_drv_adjust_res_error(padjust->info.dir, slot_index, padjust->res_level, padjust->current))\r
+ {\r
+ if (padjust->res_level >= 13)\r
+ {\r
+ padjust->res_level--;\r
+ }\r
+ }\r
+ /* 调整后的电流电阻写入寄存器 */\r
+ vc9202_drv_set_ppgSlot_resistance(slot_index, padjust->res_level);\r
+ vc9202_drv_set_ppgSlot_current(slot_index, padjust->current);\r
+ return RET_OK;\r
+}\r
+\r
+/**\r
+ * @brief 环境光饱和中断调整电阻\r
+ * @param *padjust-调整结构体,slot_index-通道编号\r
+ * @retval 执行结果\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_adjust_env_configure(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index)\r
+{\r
+ if (padjust->slot_env > VC9202_ENV_MAX_TH)\r
+ {\r
+ padjust->record_env = padjust->slot_env;\r
+ if (padjust->res_level != 0)\r
+ {\r
+ padjust->res_level--;\r
+ padjust->max_res_level = padjust->res_level;\r
+ vc9202_drv_adjust_set_fifo_mark(slot_index);\r
+ vc9202_drv_set_ppgSlot_resistance(slot_index, padjust->res_level);\r
+ }\r
+ else\r
+ {\r
+ return RET_ENV_ERR;\r
+ }\r
+ }\r
+ return RET_OK;\r
+}\r
+\r
+/**\r
+ * @brief 如果产生overload,降低电流,和电流的最大限制,过载电流-1\r
+ * @param *padjust-调整结构体,slot_index-通道编号,status-状态值\r
+ * @retval 执行结果\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_adjust_over_load_configure(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index, unsigned char status)\r
+{\r
+ unsigned char overload[3] = {status & VC9202_STATUS_OVERLOAD0, status & VC9202_STATUS_OVERLOAD1, status & VC9202_STATUS_OVERLOAD2};\r
+ if (overload[slot_index])\r
+ {\r
+ if (padjust->current != 0)\r
+ {\r
+ padjust->current--;\r
+ padjust->max_current = padjust->current;\r
+ vc9202_drv_adjust_set_fifo_mark(slot_index);\r
+ vc9202_drv_set_ppgSlot_current(slot_index, padjust->current);\r
+ }\r
+ else\r
+ {\r
+ return RET_OVERLOAD_ERR;\r
+ }\r
+ }\r
+ return RET_OK;\r
+}\r
+\r
+/**\r
+ * @brief 获取PPG进行电流电阻的调整\r
+ * @param *padjust-调整结构体,slot_index-通道编号,enfifo-是否使能fifo, slot_num-通道数\r
+ * @retval 执行结果\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_adjust_ppg_configure(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index, unsigned char enfifo, unsigned char slot_num)\r
+{\r
+ static unsigned char last_index = 0, cnt = 0;\r
+ VC9202DrvRetTypeDef vc_ret = RET_OK;\r
+ unsigned char windex = 0;\r
+ unsigned char index_gap = 0;\r
+ unsigned int data = 0;\r
+ // 根据通道号和是否enfifo获取产生ppg中断的ppg值。\r
+ windex = vc9202_drv_adjust_ppg_read(enfifo, slot_num, slot_index, &data);\r
+ /* 修改last dir */\r
+ if (enfifo)\r
+ {\r
+ index_gap = (windex > last_index) ? (windex - last_index) : (windex - last_index + 0x80);\r
+ if (index_gap != slot_num * 2)\r
+ {\r
+ padjust->info.last_dir = AGC_DIR_NULL;\r
+ }\r
+ cnt++;\r
+ if (cnt >= slot_num)\r
+ {\r
+ cnt = 0;\r
+ last_index = windex;\r
+ }\r
+ }\r
+ /* 根据ppg值进行电流、等效电阻上下调节 */\r
+ if (data >= 3770)\r
+ {\r
+ padjust->info.dir = AGC_DIR_UP;\r
+ vc_ret |= vc9202_drv_adjust_ppg_slot_current_res_config(padjust, padjust->max_res_level, padjust->max_current, slot_index);\r
+ }\r
+ else if (data < 320)\r
+ {\r
+ padjust->info.dir = AGC_DIR_DOWN;\r
+ vc_ret |= vc9202_drv_adjust_ppg_slot_current_res_config(padjust, 0, 0, slot_index);\r
+ }\r
+ return vc_ret;\r
+}\r
+\r
+/**\r
+ * @brief 最大电阻的调整,通过判断环境光,来恢复电阻的最大限制\r
+ * @param *padjust-调整结构体,slot_index-通道编号\r
+ * @retval 无\r
+ */\r
+static void vc9202_drv_res_max_resize(VC9202AdjustSlotTypeDef *padjust, unsigned char slot_index)\r
+{\r
+ static unsigned short int count_qares[2] = {0};\r
+ static unsigned short int count_pdres[2] = {0};\r
+ unsigned char min_env = 0;\r
+ // 该通道得最大电阻已经是最大的等级了,无需恢复退出\r
+ if (padjust->max_res_level >= VC9202_MAX_RES_LEVEL)\r
+ {\r
+ return;\r
+ }\r
+ /* 获取一个环境光比较值,取上一次环境光调整时的一半或者环境光中断阈值 */\r
+ min_env = (padjust->record_env / 2 < VC9202_ENV_MAX_TH) ? (padjust->record_env / 2) : VC9202_ENV_MAX_TH;\r
+ if (padjust->slot_env < min_env)\r
+ {\r
+ /* 环境光一直小于1,持续超过30次,那么直接将电阻限制设置为最大 */\r
+ if (padjust->slot_env <= 1)\r
+ {\r
+ count_pdres[slot_index] = 0;\r
+ count_qares[slot_index] = (count_qares[slot_index] == 30) ? 0 : count_qares[slot_index] + 1;\r
+ padjust->max_res_level = (count_qares[slot_index] == 30) ? VC9202_MAX_RES_LEVEL : padjust->max_res_level;\r
+ }\r
+ else\r
+ {\r
+ /* 环境光一直小于比较值,持续超过120次,那么直接将电阻限制+1 */\r
+ count_qares[slot_index] = 0;\r
+ count_pdres[slot_index] = count_pdres[slot_index] + 1;\r
+ padjust->max_res_level = (count_pdres[slot_index] == 120) ? padjust->max_res_level + 1 : padjust->max_res_level;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ count_pdres[slot_index] = 0;\r
+ count_qares[slot_index] = 0;\r
+ }\r
+}\r
+\r
+/* 判断PS通道的过载和环境光是否异常 */\r
+VC9202DrvRetTypeDef vc9202_drv_ps_slot_status(VC9202AdjustSlotTypeDef *p_slot_ps, unsigned char event, unsigned char status)\r
+{\r
+ VC9202DrvRetTypeDef vc_ret = RET_OK;\r
+#if (FUNC_ENABLE == VC9202_CFG_DRV_BY_TIMER) /* 定时触发时,不看中断原因,因为可能被清掉 */\r
+ if (status & VC9202_STATUS_OVERLOAD2)\r
+ {\r
+ vc_ret |= RET_OVERLOAD_ERR;\r
+ }\r
+ if (p_slot_ps->slot_env > VC9202_ENV_MAX_TH)\r
+ {\r
+ vc_ret |= RET_ENV_ERR;\r
+ }\r
+#else\r
+ if ((event & VC9202_EVENT_OV_MARK) && (status & VC9202_STATUS_OVERLOAD2))\r
+ {\r
+ vc_ret |= RET_OVERLOAD_ERR;\r
+ }\r
+ if ((event & VC9202_EVENT_ENV_MARK) && (p_slot_ps->slot_env > VC9202_ENV_MAX_TH))\r
+ {\r
+ vc_ret |= RET_ENV_ERR;\r
+ }\r
+#endif\r
+ return vc_ret;\r
+}\r
+/**\r
+ * @brief 识别IC的中断状态及中断事件,并对不同的情况进行调整处理等\r
+ * @param status-工作状态, event-中断事件\r
+ * @retval 执行结果\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_status_event_verify(unsigned char status, unsigned char event)\r
+{\r
+ VC9202DrvRetTypeDef vc_ret = RET_OK;\r
+ unsigned char index = 0;\r
+ unsigned char index_slot = 0;\r
+ if (status & (VC9202_STATUS_CONFLICT | VC9202_STATUS_INSAMPLE))\r
+ {\r
+ return RET_STATUS_ERR;\r
+ }\r
+ /* PS通道异常判断 */\r
+ vc_ret |= vc9202_drv_ps_slot_status(&dev9202_adjust[2], event, status);\r
+ /* PPG通道的环境光读取,异常中断处理 */\r
+ for (index = 0; index < dev9202_info.slot_number; index++)\r
+ {\r
+ index_slot = (dev9202_info.slot_number == 2) ? index : (dev9202_info.enslot[0] ? 0 : 1);\r
+ /* 恢复最大电阻的限制,根据当前 */\r
+ vc9202_drv_res_max_resize(&dev9202_adjust[index_slot], index_slot);\r
+ /* over load, max current */\r
+ if (event & VC9202_EVENT_OV_MARK)\r
+ {\r
+ printf("event & VC9202_EVENT_OV_MARK \n");\r
+ vc_ret |= vc9202_drv_adjust_over_load_configure(&dev9202_adjust[index_slot], index_slot, status);\r
+ }\r
+ /* env, max res */\r
+ if (event & VC9202_EVENT_ENV_MARK)\r
+ {\r
+ printf("event & VC9202_EVENT_ENV_MARK \n");\r
+ vc_ret |= vc9202_drv_adjust_env_configure(&dev9202_adjust[index_slot], index_slot);\r
+ }\r
+ /* ppg interruput */\r
+ if (event & VC9202_EVENT_PPG_MARK)\r
+ {\r
+ vc_ret |= vc9202_drv_adjust_ppg_configure(&dev9202_adjust[index_slot], index_slot, dev9202_info.enfifo_div, dev9202_info.slot_number);\r
+ printf("event & VC9202_EVENT_PPG_MARK vc_ret : 0x%x\n",vc_ret);\r
+ }\r
+ else\r
+ {\r
+ printf("event : 0x%x \n",event);\r
+ dev9202_adjust[index].info.dir = AGC_DIR_NULL;\r
+ dev9202_adjust[index].info.last_dir = AGC_DIR_NULL;\r
+ }\r
+ }\r
+ return vc_ret;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * fifo 读取部分\r
+ ********************************************************************************************************/\r
+/**\r
+ * @brief 校验fifo读写的偏移的可用性,及fifo是否翻转等错误。\r
+ * @param rindex-读地址,windex-写地址,slot_num-通道数量,fifo_div-fifo深度\r
+ * @retval 无\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_fifo_infomation_check(unsigned char *rindex, unsigned char *windex, unsigned char slot_num, unsigned char fifo_div)\r
+{\r
+ unsigned int clk_diffs = 0;\r
+ unsigned int clk_count = usr_get_clock_ticks();\r
+ /* 间隔时间的校验,后续看是否需要补充 */\r
+ 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);\r
+ if (clk_diffs > (unsigned int)((64.0f / dev9202_info.work_frequency) * 0.8f * VC9202_CFG_CLK_CHECK_FREQUENCY / dev9202_info.slot_number))\r
+ {\r
+ *windex = 0;\r
+ *rindex = 0x80;\r
+ dev9202_clk.last_clk_count = clk_count;\r
+ return RET_FIFO_ERR;\r
+ }\r
+ /* 读写地址的校验 */\r
+ if (*windex < 0x80)\r
+ {\r
+ *rindex = *rindex + (fifo_div + 1) * 2;\r
+ if (*rindex < 0x80)\r
+ {\r
+ *rindex += 0x80;\r
+ }\r
+ dev9202_clk.last_clk_count = clk_count;\r
+ return RET_FIFO_ERR;\r
+ }\r
+ if (*rindex < 0x80)\r
+ {\r
+ *rindex = *windex;\r
+ dev9202_clk.last_clk_count = clk_count;\r
+ return RET_FIFO_ERR;\r
+ }\r
+ if (*windex == *rindex)\r
+ {\r
+ dev9202_clk.last_clk_count = clk_count;\r
+ return RET_FIFO_ERR;\r
+ }\r
+ dev9202_clk.last_clk_count = clk_count;\r
+ return RET_OK;\r
+}\r
+\r
+/**\r
+ * @brief 获取fifos数据\r
+ * @param enfifo-是否使能fifo,p_result-数据地址,psize-数据大小,rindex-读地址,windex-写地址,slot_num-通道数量\r
+ * @retval 无\r
+ */\r
+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)\r
+{\r
+ unsigned char i = 0;\r
+ unsigned char fifo_length = 0;\r
+ unsigned char fifoData[128] = {0};\r
+ unsigned char fifo_index_offset = 0; /*正常情况下:r=w, 异常情况下,r=w-fifo_index_offset */\r
+ /*------------- disable fifo -------------*/\r
+ if (!enfifo)\r
+ {\r
+ *psize = slot_num;\r
+ usr_iic_read_bytes(0x80, fifoData, slot_num * 2);\r
+ for (i = 0; i < *psize; i++)\r
+ {\r
+ p_result->ppg_data[i] = (fifoData[i * 2] << 8) + fifoData[i * 2 + 1];\r
+ if (ppg_mark[i])\r
+ {\r
+ ppg_mark[i] = 0;\r
+ p_result->ppg_data[i] |= 0x1000; // 0x01000000;\r
+ }\r
+ }\r
+ return;\r
+ }\r
+ /*------------- enable fifo -------------*/\r
+ /* 读取解析fifo数据 */\r
+ if (*windex > *rindex)\r
+ {\r
+ fifo_length = *windex - *rindex;\r
+ if ((fifo_length % (dev9202_info.slot_number * 2)) && (dev9202_info.slot_number >= 2)) /* 当是多通道,但是通道数与字节数对应不上的异常处理 */\r
+ {\r
+ fifo_index_offset = fifo_length % (dev9202_info.slot_number * 2);\r
+ fifo_length = fifo_length - fifo_index_offset; /* 只读取满足通道数的fifo数量,如果未出现异常,fifo_index_offset=0,跟之前处理一样 */\r
+ }\r
+ usr_iic_read_bytes(*rindex, fifoData, fifo_length);\r
+ *rindex = *windex - fifo_index_offset;\r
+ }\r
+ else\r
+ {\r
+ fifo_length = *windex + 0x80 - *rindex;\r
+ if ((fifo_length % (dev9202_info.slot_number * 2)) && (dev9202_info.slot_number >= 2)) /* 当是多通道,但是通道数与字节数对应不上的异常处理 */\r
+ {\r
+ fifo_index_offset = fifo_length % (dev9202_info.slot_number * 2);\r
+ fifo_length = fifo_length - fifo_index_offset; /* 只读取满足通道数的fifo数量 */\r
+ }\r
+ if (*windex == 0x80) /* 数据刚好在0xfe-0xff截至 */\r
+ {\r
+ usr_iic_read_bytes(*rindex, fifoData, fifo_length);\r
+ if (fifo_index_offset)\r
+ {\r
+ *rindex = *windex + 0x80 - fifo_index_offset;\r
+ }\r
+ else\r
+ {\r
+ *rindex = *windex - fifo_index_offset; /* fifo_index_offset=0 */\r
+ }\r
+ }\r
+ else /* (*windex != 0x80): 0x80及以后还有数据 */\r
+ {\r
+ usr_iic_read_bytes(*rindex, fifoData, (256 - *rindex)); /* 获取rindex-0xff的数据 */\r
+ usr_iic_read_bytes(0x80, &fifoData[256 - *rindex], (*windex - 0x80) - fifo_index_offset); /* 剩下的数据部分如果存在 */\r
+ *rindex = *windex - fifo_index_offset;\r
+ }\r
+ }\r
+\r
+ *psize = fifo_length / 2;\r
+ for (i = 0; i < *psize; i++)\r
+ {\r
+ p_result->ppg_data[i] = (fifoData[i * 2] << 8) + fifoData[i * 2 + 1];\r
+ if (ppg_mark[i])\r
+ {\r
+ ppg_mark[i] = 0;\r
+ p_result->ppg_data[i] |= 0x1000; // 0x01000000;\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ * @brief 校验fifo并获取结果\r
+ * @param p_result-数据地址,psize-数据大小\r
+ * @retval 执行结果\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_read_fifo_result(SamplingDataTypeDef *p_result, unsigned char *psize)\r
+{\r
+ VC9202DrvRetTypeDef vc_ret = RET_OK;\r
+ unsigned char write_index = 0;\r
+ unsigned char event = 0;\r
+ event = dev9202_info.int_event;\r
+#if (VC9202_CFG_DRV_BY_TIMER == FUNC_ENABLE)\r
+ event = VC9202_EVENT_FIFO_MARK;\r
+#endif\r
+ if (event & VC9202_EVENT_FIFO_MARK)\r
+ {\r
+ usr_iic_read_bytes(0x03, &write_index, 1);\r
+ vc_ret |= vc9202_drv_fifo_infomation_check(&dev9202_info.read_fifo_address, &write_index, dev9202_info.slot_number, dev9202_info.enfifo_div);\r
+ if (RET_OK == vc_ret && dev9202_info.osc_clk_status)\r
+ {\r
+ vc9202_drv_read_fifo_data(dev9202_info.enfifo_div, p_result, psize, &dev9202_info.read_fifo_address, &write_index, dev9202_info.slot_number);\r
+ }\r
+ }\r
+ return vc_ret;\r
+}\r
+\r
+/*********************************************************************************************************/\r
+/**\r
+ * @brief 读取相关采样值和寄存器值\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+static unsigned char vc9202_drv_read_reg(SamplingDataTypeDef *read_reg)\r
+{\r
+ unsigned char reg_val[6] = {0};\r
+ unsigned char res_ext[2] = {0};\r
+ VC9202ResLevelTypeDef res = {0};\r
+\r
+ /* 4bit数据读取 */\r
+ usr_iic_read_bytes(0x04, reg_val, 3);\r
+ read_reg->pre_val[0] = reg_val[0] & 0x0F;\r
+ read_reg->pre_val[1] = reg_val[1] & 0x0F;\r
+ read_reg->env_val[0] = (reg_val[0] >> 4) & 0x0F;\r
+ read_reg->env_val[1] = (reg_val[1] >> 4) & 0x0F;\r
+ read_reg->env_val[2] = (reg_val[2] >> 4) & 0x0F;\r
+ read_reg->ps_val = reg_val[2] & 0x0F;\r
+\r
+ /* old param */\r
+ usr_iic_read_bytes(0x17, reg_val, 6);\r
+ read_reg->led_cur[0] = reg_val[0] & 0x7F;\r
+ read_reg->led_cur[1] = reg_val[1] & 0x7F;\r
+ read_reg->led_cur[2] = reg_val[2] & 0x7F;\r
+ read_reg->pd_res[0] = (reg_val[3] >> 4) & 0x07;\r
+ read_reg->pd_res[1] = (reg_val[4] >> 4) & 0x07;\r
+ read_reg->pd_res[2] = (reg_val[5] >> 4) & 0x07;\r
+ /* 8bit数据读取 */\r
+ usr_iic_read_bytes(0x41, reg_val, 6);\r
+ read_reg->aenv_val[0] = reg_val[0];\r
+ read_reg->aenv_val[1] = reg_val[1];\r
+ read_reg->aenv_val[2] = reg_val[2];\r
+ read_reg->apre_val[0] = reg_val[3];\r
+ read_reg->apre_val[1] = reg_val[4];\r
+ read_reg->aps_val = reg_val[5];\r
+ /* new param */\r
+ usr_iic_read_bytes(0x22, res_ext, 2);\r
+ /* slot0 */\r
+ dev9202_adjust[0].slot_env = read_reg->aenv_val[0];\r
+ dev9202_adjust[0].current = read_reg->led_cur[0];\r
+ res.res_val = read_reg->pd_res[0];\r
+ res.low_res = (res_ext[0] >> 0) & 0x01;\r
+ res.offset = (res_ext[0] >> 4) & 0x03;\r
+ res.offset3 = 0;\r
+ dev9202_adjust[0].res_level = vc9202_drv_res_register_to_level(&res);\r
+ /* slot1 */\r
+ dev9202_adjust[1].slot_env = read_reg->aenv_val[1];\r
+ dev9202_adjust[1].current = read_reg->led_cur[1];\r
+ res.res_val = read_reg->pd_res[1];\r
+ res.low_res = (res_ext[0] >> 1) & 0x01;\r
+ res.offset = (res_ext[0] >> 6) & 0x03;\r
+ res.offset3 = 0;\r
+ dev9202_adjust[1].res_level = vc9202_drv_res_register_to_level(&res);\r
+ /* slot2 */\r
+ dev9202_adjust[2].slot_env = read_reg->aenv_val[2];\r
+ dev9202_adjust[2].current = read_reg->led_cur[2];\r
+ dev9202_adjust[2].res_level = read_reg->pd_res[2];\r
+ /* 如果有等效电阻的等级,那么传出等效等级 */\r
+ read_reg->pd_res[0] = dev9202_adjust[0].res_level;\r
+ read_reg->pd_res[1] = dev9202_adjust[1].res_level;\r
+ read_reg->pd_res[2] = dev9202_adjust[2].res_level;\r
+ /* pdbias */\r
+ usr_iic_read_bytes(0x47, reg_val, 4);\r
+ read_reg->apdbias_val[0] = reg_val[0];\r
+ read_reg->apdbias_val[1] = reg_val[1];\r
+ read_reg->apdbias_val[2] = reg_val[2];\r
+ read_reg->apdbias_val[3] = reg_val[3] & 0xf;\r
+ read_reg->pdbias = read_reg->apdbias_val[2] * 16 + read_reg->apdbias_val[3];\r
+\r
+ usr_iic_read_bytes(0x4B, reg_val, 4);\r
+ read_reg->bio_val_i = (reg_val[0] << 8) + reg_val[1];\r
+ read_reg->bio_val_o = (reg_val[2] << 8) + reg_val[3];\r
+\r
+ if ((read_reg->aps_val >> 4) == read_reg->ps_val) /* 防止数据错误,4bit与8bit不匹配,则不对佩戴数据进行更新,防止因为异常摘下 */\r
+ {\r
+ dev9202_wear.wear_ps = read_reg->aps_val;\r
+ dev9202_wear.wear_env = read_reg->pdbias;\r
+ dev9202_wear.wear_bio = read_reg->bio_val_o;\r
+ }\r
+ return 0;\r
+}\r
+\r
+// 注意,该部分需要分为两部分,一部分为中断调用,一部分为定时调用,保证低端客户的可用性较高\r
+/**\r
+ * @brief 通过宏定义#if (FUNC_ENABLE==VC9202_CFG_DRV_BY_TIMER) 已经对定时器调用方式做了对应的处理,现在通用一个函数接口即可\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+static VC9202DrvRetTypeDef vc9202_drv_gpio_event_handler(SamplingDataTypeDef *pResult, unsigned char *psize)\r
+{\r
+ VC9202DrvRetTypeDef vc_ret = RET_OK;\r
+ switch (dev9202_info.work_mode)\r
+ {\r
+ case WORK_MODE_HR:\r
+ vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event);\r
+ vc9202_drv_calibration_osc_clk();\r
+ vc_ret |= vc9202_drv_read_fifo_result(pResult, psize);\r
+ break;\r
+ case WORK_MODE_SPO2:\r
+ vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event);\r
+ vc9202_drv_calibration_osc_clk();\r
+ vc_ret |= vc9202_drv_read_fifo_result(pResult, psize);\r
+ break;\r
+ case WORK_MODE_HRV:\r
+ vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event);\r
+ vc9202_drv_calibration_osc_clk();\r
+ vc_ret |= vc9202_drv_read_fifo_result(pResult, psize);\r
+ break;\r
+ case WORK_MODE_STRESS:\r
+ vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event);\r
+ vc9202_drv_calibration_osc_clk();\r
+ vc_ret |= vc9202_drv_read_fifo_result(pResult, psize);\r
+ break;\r
+ case WORK_MODE_WEAR:\r
+ vc_ret |= vc9202_drv_status_event_verify(dev9202_info.work_status, dev9202_info.int_event);\r
+ vc9202_drv_calibration_osc_clk();\r
+ break;\r
+ case WORK_MODE_FACTORY:\r
+ if (dev9202_info.int_event & VC9202_EVENT_OV_MARK)\r
+ {\r
+ vc_ret |= vc9202_drv_adjust_over_load_configure(&dev9202_adjust[0], 0, dev9202_info.work_status);\r
+ }\r
+ pResult->led_cur[0] = dev9202_adjust[0].max_current;\r
+ break;\r
+ case WORK_MODE_FPC_TEST:\r
+ vc9202_test_handler(pResult, &vc9202_test_info);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ return vc_ret;\r
+}\r
+\r
+/**\r
+ * @brief 初始化驱动参数\r
+ * @param\r
+ @pInit fifo_div fifo分频深度\r
+ @pInit enslot 通道使能配置\r
+ * @retval 无\r
+ */\r
+void vc9202_drv_system_param_init(unsigned char fifo_div, unsigned char enslot)\r
+{\r
+ unsigned char i = 0;\r
+ /* dev info param init */\r
+ dev9202_info.enfifo_div = fifo_div;\r
+ dev9202_info.enslot[0] = (enslot & 0x01);\r
+ dev9202_info.enslot[1] = (enslot & 0x02) >> 1;\r
+ dev9202_info.slot_number = dev9202_info.enslot[0] + dev9202_info.enslot[1];\r
+\r
+ dev9202_info.osc_clk_status = 0;\r
+ dev9202_info.read_fifo_address = 0x80;\r
+ /* dev9202_adjust info param init */\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ dev9202_adjust[i].max_current = VC9202_MAX_CUR_LEVEL;\r
+ dev9202_adjust[i].max_res_level = VC9202_MAX_RES_LEVEL;\r
+ dev9202_adjust[i].record_env = 0;\r
+ dev9202_adjust[i].info.dir = AGC_DIR_NULL;\r
+ dev9202_adjust[i].info.last_dir = AGC_DIR_NULL;\r
+ dev9202_adjust[i].info.current_step = 4;\r
+ }\r
+ dev9202_adjust[2].max_res_level = VC9202_MAX_RES_LEVEL;\r
+ /* dev9202_wear param init */\r
+#if (VC9202_CFG_WEAR_DEFAULT_STATUS == WEAR_IS_HOLD)\r
+ dev9202_info.wear_status = WEAR_STA_HOLD;\r
+ dev9202_wear.wear_status = WEAR_STA_HOLD;\r
+ dev9202_wear.last_status = (WEAR_STA_NONE == dev9202_wear.last_status) ? WEAR_STA_HOLD : dev9202_wear.last_status;\r
+#else\r
+ dev9202_wear.wear_status = WEAR_STA_DROP;\r
+ dev9202_wear.last_status = (WEAR_STA_NONE == dev9202_wear.last_status) ? WEAR_STA_DROP : dev9202_wear.last_status;\r
+#endif\r
+#if (VC9202_CFG_WEAR_DETECTION != FUNC_ENABLE)\r
+ dev9202_info.wear_status = WEAR_STA_HOLD;\r
+ dev9202_wear.wear_status = WEAR_STA_HOLD;\r
+ dev9202_wear.last_status = WEAR_STA_HOLD;\r
+#endif\r
+ if (dev9202_wear.last_status == WEAR_STA_DROP && dev9202_info.work_mode != WORK_MODE_FACTORY && dev9202_info.work_mode != WORK_MODE_FPC_TEST)\r
+ {\r
+ if (dev9202_info.enslot[0])\r
+ {\r
+ vc9202_drv_channel_switch(0, 0);\r
+ }\r
+ if (dev9202_info.enslot[1])\r
+ {\r
+ vc9202_drv_channel_switch(1, 0);\r
+ }\r
+ }\r
+ dev9202_wear.wear_status = dev9202_wear.last_status;\r
+ dev9202_info.wear_status = dev9202_wear.wear_status;\r
+ alg_wear_status = WEAR_STA_HOLD;\r
+ dev9202_wear.wear_drop_cnt = VC9202_CFG_WEAR_DROP_CNT;\r
+ dev9202_wear.wear_hold_cnt = VC9202_CFG_WEAR_HOLD_CNT;\r
+ vc9202_drv_clear_clk();\r
+#if 0\r
+ f_BIOInit(VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN);\r
+ bio_result = VC9202_BIO_STA_NONE;\r
+ if( dev9202_wear.last_status==WEAR_STA_HOLD )\r
+ {\r
+ bio_result = VC9202_BIO_STA_HOLD;\r
+ }\r
+ else\r
+ {\r
+ bio_result = VC9202_BIO_STA_NONE;\r
+ }\r
+#else\r
+ printf("fifo_div : %d, enslot : %d \n", fifo_div, enslot );\r
+ printf("f_BIOedgeinit(%d, %d) \n", VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN );\r
+ if (VC9202_BIO_STA_NONE == bio_result)\r
+ {\r
+ uint32_t irq_sts = osal_irq_lock();\r
+ f_BIOInit(VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN);\r
+ osal_irq_restore(irq_sts);\r
+ printf(" VC9202_BIO_STA_DROP == bio_result f_BIOedgeinit(%d, %d) \n", VC9202_CFG_WEAR_PARAM_BIOIN, VC9202_CFG_WEAR_PARAM_PSIN );\r
+ }\r
+#endif\r
+}\r
+\r
+/*********************************************************************************************************\r
+ * 对外功能函数\r
+ ********************************************************************************************************/\r
+\r
+/**\r
+ * @brief 获取chip_id\r
+ * @param 无\r
+ * @retval chip_id值\r
+ */\r
+unsigned char vc9202_drv_get_chip_id(void)\r
+{\r
+ unsigned char chip_id = 0;\r
+ usr_iic_read_bytes(0x00, &chip_id, 1);\r
+ printf("vc9202 chip id : 0x%x\n",chip_id);\r
+ return chip_id;\r
+}\r
+\r
+/**\r
+ * @brief 开始采样\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_drv_start_sampling(void)\r
+{\r
+ unsigned char temp = 0x00;\r
+ usr_iic_read_bytes(0x10, &temp, 1);\r
+ temp |= (1 << 7);\r
+ usr_iic_write_bytes(0x10, &temp, 1);\r
+}\r
+\r
+/**\r
+ * @brief 停止采样\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_drv_stop_sampling(void)\r
+{\r
+ unsigned char temp = 0x00;\r
+ usr_iic_read_bytes(0x10, &temp, 1);\r
+ temp &= ~(1 << 7);\r
+ usr_iic_write_bytes(0x10, &temp, 1);\r
+ bio_result = VC9202_BIO_STA_NONE;\r
+}\r
+\r
+/**\r
+ * @brief 软复位\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_drv_soft_reset(void)\r
+{\r
+ unsigned char reset_reg_cfg = 0x5A;\r
+ usr_iic_write_bytes(0x3B, &reset_reg_cfg, 1);\r
+}\r
+\r
+/**\r
+ * @brief 独立使/失能某一物理通道\r
+ * @param\r
+ @num_channel 通道编号(0,1,2)\r
+ @enable_flag 使能或失能标志位\r
+ * @retval 0执行成功\r
+ */\r
+unsigned char vc9202_drv_channel_switch(unsigned char num_channel, unsigned char enable_flag)\r
+{\r
+ unsigned char temp = 0x00;\r
+ usr_iic_read_bytes(0x10, &temp, 1);\r
+ if (num_channel > 2)\r
+ {\r
+ return 1;\r
+ }\r
+ if (enable_flag == 1)\r
+ {\r
+ temp |= (1 << num_channel);\r
+ usr_iic_write_bytes(0x10, &temp, 1);\r
+ /* 同频处理 */\r
+ if (WORK_MODE_SPO2 == dev9202_info.work_mode)\r
+ {\r
+ usr_iic_read_bytes(0x11, &temp, 1);\r
+ temp &= ~(1 << 4);\r
+ usr_iic_write_bytes(0x11, &temp, 1);\r
+ temp = 0;\r
+ usr_iic_write_bytes(0x16, &temp, 1);\r
+ }\r
+ }\r
+ else if (enable_flag == 0)\r
+ {\r
+ temp &= ~(1 << num_channel);\r
+ usr_iic_write_bytes(0x10, &temp, 1);\r
+ /* 同频处理 */\r
+ usr_iic_read_bytes(0x11, &temp, 1);\r
+ temp |= (1 << 4);\r
+ usr_iic_write_bytes(0x11, &temp, 1);\r
+ temp = dev9202_info.enfifo_div;\r
+ usr_iic_write_bytes(0x16, &temp, 1);\r
+ }\r
+ else\r
+ {\r
+ return 2;\r
+ }\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * @brief 获取中断原因\r
+ * @param 无\r
+ * @retval 中断原因\r
+ */\r
+unsigned char vc9202_drv_get_int_reason(void)\r
+{\r
+ unsigned char int_reason = 0;\r
+ unsigned char int_enable = 0;\r
+ usr_iic_read_bytes(0x02, &int_reason, 1);\r
+ usr_iic_read_bytes(0x11, &int_enable, 1);\r
+ /* 在同频时,获取到的ps中断,并非ps所需要的中断 */\r
+ if (!(int_enable & (1 << 4)))\r
+ {\r
+ int_reason &= ~(1 << 4);\r
+ }\r
+#if (VC9202_CFG_DRV_BY_TIMER == FUNC_ENABLE)\r
+ int_reason = (VC9202_EVENT_PS_MARK | VC9202_EVENT_FIFO_MARK);\r
+#endif\r
+ return int_reason;\r
+}\r
+\r
+/**\r
+ * @brief 防止静电打死,自动恢复,定时去调用检查即可\r
+ * @param 无\r
+ * @retval\r
+ */\r
+void vc9202_drv_electrostatic_death(void)\r
+{\r
+ unsigned char work_reg = 1;\r
+ unsigned char bio_reg[2] = {1, 1};\r
+ unsigned short bio_val = 0;\r
+ usr_iic_read_bytes(0x10, &work_reg, 1);\r
+ if(dev9202_info.enable_bio)\r
+ {\r
+ usr_iic_read_bytes(0x4D, bio_reg, 2);\r
+ }\r
+ bio_val = (bio_reg[1] << 8) + bio_reg[0];\r
+ /* dev9202 death */\r
+ if (0 == work_reg || 0 == bio_val)\r
+ {\r
+ InitParamTypeDef init_param = {dev9202_info.fifo_time, dev9202_info.work_mode};\r
+ vc9202_drv_soft_reset();\r
+ vc9202_drv_reg_init(&init_param);\r
+ }\r
+}\r
+\r
+/**\r
+ * @brief 防止任务队列堆积处理,导致短时间连续执行\r
+ * @param 无\r
+ * @retval 0-pass,-1-fail\r
+ */\r
+#define CHECK_GAPTIME_RATIO 3/4 /* 最短中断时间的3/4,30ms,算上频率在[16K,24K]波动,限制的时间为[25~37]ms以内会被过滤掉 */\r
+static int vc9202_drv_check_running_gaptime(void)\r
+{\r
+ unsigned int last_count = dev9202_clk.last_clk_check;\r
+ unsigned int now_count = 0;\r
+\r
+ unsigned int count1 = 0, count2 = 0;\r
+ unsigned int count_diff = 0;\r
+ unsigned char cnt_reg[4] = {0};\r
+ int ret = 0;\r
+ unsigned char check_gap_time = (1000/dev9202_info.work_frequency)*CHECK_GAPTIME_RATIO;\r
+ usr_iic_read_bytes(0x07, cnt_reg, 4);\r
+ count1 = (cnt_reg[0] << 8) + cnt_reg[1];\r
+ count2 = (cnt_reg[2] << 8) + cnt_reg[3];\r
+ count_diff = (count1 <= count2) ? (count2 - count1) : (count2 - count1 + 0xffff);\r
+ /* count值获取正确有效 */\r
+ if (count_diff <= 5)\r
+ {\r
+ now_count = count1;\r
+ }\r
+ count_diff = 8000;\r
+ if ((0 != now_count) && (0 != last_count))\r
+ {\r
+ count_diff = (last_count <= now_count) ? (now_count - last_count) : (now_count - last_count + 0xffff);\r
+ }\r
+ /* 间隔时间过小,算上频率在[16K,24K]波动,限制的时间为[25~37]ms以内会被过滤掉 */\r
+ if (count_diff <= 20 * check_gap_time)\r
+ {\r
+ ret = -1;\r
+ }\r
+ dev9202_clk.last_clk_check = now_count;\r
+ return ret;\r
+}\r
+\r
+/**\r
+ * @brief 寄存器配置\r
+ * @param\r
+ @pInit_Param->work_mode 工作模式\r
+ @pInit_Param->sampling_gap_time FIFO中断间隔时间,FIFO深度\r
+ * @retval 无\r
+ */\r
+unsigned char vc9202_drv_reg_init(InitParamTypeDef *pInit_Param)\r
+{\r
+ unsigned short int clk_div = 0x0000;\r
+ unsigned char fifo_div = 0;\r
+ unsigned char reg_cfg[17] = {0x00, 0x1F, 0x8A, 0x00, 0x03, 0x1F, 0x00, 0x00, 0x80, 0x00, 0x57, 0x57, 0x07, 0x16, 0x56, 0x16, 0x00};\r
+ unsigned char reg_new = (1 << 3);\r
+ unsigned char reg_bio_cfg[2] = {0x00, 0xA2};\r
+/* 设置中断触发方式 0上升沿 1下降沿 */\r
+#if VC9202_CFG_INTERRUPT_MODE\r
+ reg_cfg[1] |= (1 << 7);\r
+#endif\r
+\r
+/* 设置中断电平保持时间 */\r
+#ifdef VC9202_CFG_INTERRUPT_TIME\r
+ reg_cfg[1] |= (VC9202_CFG_INTERRUPT_TIME << 5);\r
+#endif\r
+\r
+ /* 设置FIFO深度,FIFO/PS中断间隔时间,同时设置采样分频 */\r
+ dev9202_info.work_frequency = VC9202_CFG_SAMPLE_RATE;\r
+ dev9202_info.work_mode = (WorkModeTypeDef)pInit_Param->work_mode;\r
+ dev9202_info.fifo_time = pInit_Param->sampling_gap_time;\r
+ if (WORK_MODE_HRV == dev9202_info.work_mode)\r
+ {\r
+ dev9202_info.work_frequency = 100;\r
+ dev9202_info.fifo_time = 200;\r
+ }\r
+ fifo_div = dev9202_info.fifo_time / (1000 / dev9202_info.work_frequency) - 1;\r
+ clk_div = (20000 / dev9202_info.work_frequency) - 1;\r
+ reg_cfg[3] = fifo_div;\r
+ reg_cfg[4] = (clk_div >> 8) & 0xFF;\r
+ reg_cfg[5] = (clk_div & 0xFF);\r
+ reg_cfg[6] = fifo_div;\r
+\r
+ /* 设置PS通道PD电阻,LED电流 */\r
+ reg_cfg[9] = VC9202_CFG_PS_SLOT_CUR;\r
+ reg_cfg[12] = VC9202_CFG_PS_SLOT_RES;\r
+\r
+ switch (dev9202_info.work_mode)\r
+ {\r
+ case WORK_MODE_HR:\r
+ reg_cfg[0] = 0x45;\r
+#if VC9202_CFG_IS_HALVE_CAP\r
+ reg_cfg[10] = 0x54; /* 根据发光时间设置滤波电阻 */\r
+ reg_cfg[13] = 0x03; // 0x03; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */\r
+ reg_cfg[16] = 0x01; /* 发光时间减半,开1倍过采 */\r
+#else\r
+ reg_cfg[10] = 0x57; /* 根据发光时间设置滤波电阻 0x57 */\r
+ reg_cfg[13] = 0x16; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */\r
+ reg_cfg[16] = 0x00; /* 发光时间减半,开1倍过采 */\r
+#endif\r
+ break;\r
+\r
+ case WORK_MODE_SPO2:\r
+ reg_cfg[0] = 0x47;\r
+ reg_cfg[1] &= ~(1 << 4); /* 关闭PS中断 */\r
+ reg_cfg[6] = 0x00; /* PS开同频,避免引入同频干扰 */\r
+ reg_cfg[7] = 0x80; /* slot0(红光)开32倍增益 */\r
+ reg_cfg[13] = 0xB6; /*B6-3 红外(物理通道2)映射到逻辑通道0,并设置采样时长为200us */\r
+ reg_cfg[14] = 0x76; /*76-3 红光(物理通道1)映射到逻辑通道0,并设置采样时长为200us */\r
+ reg_cfg[16] = 0x04; /* 开16倍过采 */\r
+ break;\r
+\r
+ case WORK_MODE_HRV:\r
+ reg_cfg[0] = 0x45;\r
+#if VC9202_CFG_IS_HALVE_CAP\r
+ reg_cfg[10] = 0x54; /* 根据发光时间设置滤波电阻 */\r
+ reg_cfg[13] = 0x03; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */\r
+ reg_cfg[16] = 0x01; /* 发光时间减半,开1倍过采 */\r
+#else\r
+ reg_cfg[10] = 0x57; /* 根据发光时间设置滤波电阻 */\r
+ reg_cfg[13] = 0x16; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */\r
+ reg_cfg[16] = 0x00; /* 发光时间减半,开1倍过采 */\r
+#endif\r
+ reg_bio_cfg[1] = 0x00;\r
+ break;\r
+\r
+ case WORK_MODE_STRESS:\r
+ reg_cfg[0] = 0x45;\r
+#if VC9202_CFG_IS_HALVE_CAP\r
+ reg_cfg[10] = 0x54; /* 根据发光时间设置滤波电阻 */\r
+ reg_cfg[13] = 0x03; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */\r
+ reg_cfg[16] = 0x01; /* 发光时间减半,开1倍过采 */\r
+#else\r
+ reg_cfg[10] = 0x57; /* 根据发光时间设置滤波电阻 */\r
+ reg_cfg[13] = 0x16; /* 绿灯(物理通道0)映射到逻辑通道0,并设置采样时长为50us */\r
+ reg_cfg[16] = 0x00; /* 发光时间减半,开1倍过采 */\r
+#endif\r
+ break;\r
+\r
+ case WORK_MODE_WEAR:\r
+ reg_cfg[0] = 0x44;\r
+ reg_cfg[1] = (reg_cfg[1] | (1 << 4)) & 0xF0;\r
+ break;\r
+\r
+ case WORK_MODE_FACTORY:\r
+ reg_cfg[0] = 0x47;\r
+ reg_cfg[7] = 0xEF;\r
+ reg_cfg[8] = 0xEF;\r
+ reg_cfg[10] = 0x77;\r
+ reg_cfg[11] = 0x77;\r
+ break;\r
+ case WORK_MODE_FPC_TEST:\r
+ reg_cfg[0] = 0x47;\r
+ reg_cfg[7] = 0xEF;\r
+ reg_cfg[8] = 0xEF;\r
+ reg_cfg[10] = 0x77;\r
+ reg_cfg[11] = 0x77;\r
+ vc9202_test_init(&vc9202_test_info);\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ usr_iic_write_bytes(0x10, reg_cfg, 17); /* 心率血氧相关寄存器配置 */\r
+ usr_iic_write_bytes(0x22, ®_new, 1);\r
+ usr_iic_write_bytes(0x23, reg_bio_cfg, 2); /*BIO相关寄存器配置 */\r
+ if (reg_bio_cfg[1] & 0x80)\r
+ {\r
+ dev9202_info.enable_bio = 1;\r
+ }\r
+ else\r
+ {\r
+ dev9202_info.enable_bio = 0;\r
+ }\r
+ vc9202_drv_system_param_init(fifo_div, reg_cfg[0]);\r
+ /* mode位置1,芯片开始工作 */\r
+ vc9202_drv_start_sampling();\r
+ return 0;\r
+}\r
+\r
+/**\r
+ * @brief 传递采样数据\r
+ * @param 采样数据保存地址,ppg数量\r
+ * @retval 执行结果\r
+ */\r
+unsigned char vc9202_drv_get_sampling_data(SamplingDataTypeDef *pSamplingData, unsigned char *psize)\r
+{\r
+ unsigned char ret = 0;\r
+ /* 读取状态及中断事件 */\r
+ usr_iic_read_bytes(0x01, &dev9202_info.work_status, 1);\r
+ usr_iic_read_bytes(0x02, (unsigned char *)&dev9202_info.int_event, 1);\r
+\r
+ printf("dev9202_info.work_status : 0x%x ,dev9202_info.int_event : 0x%x\n",dev9202_info.work_status,dev9202_info.int_event);\r
+\r
+ if (dev9202_info.work_status & 0xf8) /* 防止insample和conflict时数据错误,则不对设备进行处理 */\r
+ {\r
+ printf("dev9202_info.work_status & 0xf8 \n");\r
+ dev9202_info.int_event = 0; /* 异常时,避免执行佩戴检测 */\r
+ return 1;\r
+ }\r
+ if (-1 == vc9202_drv_check_running_gaptime())\r
+ {\r
+ printf("-1 == vc9202_drv_check_running_gaptime() \n");\r
+ dev9202_info.int_event = 0; /* 异常时,避免执行佩戴检测 */\r
+ return 1;\r
+ }\r
+ ret = vc9202_drv_read_reg(pSamplingData);\r
+ ret = (unsigned char)vc9202_drv_gpio_event_handler(pSamplingData, psize);\r
+ return ret;\r
+}\r
--- /dev/null
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc9202_driver_testmode.c\r
+ * @brief \r
+ * @details\r
+ * @author\r
+ * @date \r
+ * @version \r
+ *********************************************************************************************************/\r
+//!!!注意:本文文件包含step1(id,频率,温度的读取判断),step2(bio是否满足变化/ps是否能够达到阈值)两步进行FPC测试,用于那些不使用测试板的测试的用户,排查基础问题\r
+//!!!注意:本文文件包含step1(id,频率,温度的读取判断),step2(bio是否满足变化/ps是否能够达到阈值)两步进行FPC测试,用于那些不使用测试板的测试的用户,排查基础问题\r
+//如果不需要,删除本文件和其他报错的地方即可\r
+#include "vc9202_common.h"\r
+#include "vc9202_driver.h"\r
+\r
+VC9202TestInfoTypeDef vc9202_test_info = {0};\r
+\r
+const static unsigned char disp_green[17] = {0xC5, 0x30, 0x8A, 0x40, 0x03, 0x1F, 0x00,\r
+ 0x30, 0x40, 0x5A,\r
+ 0x57, 0x37, 0x47,\r
+ 0x16, 0x56, 0x16, 0x00};\r
+const static unsigned char disp_red[17] = {0xC6, 0x30, 0x8A, 0x40, 0x03, 0x1F, 0x00,\r
+ 0x30, 0x40, 0x5A,\r
+ 0x57, 0x37, 0x47,\r
+ 0x16, 0x56, 0x16, 0x00};\r
+static unsigned int mcu_cnt[2] = {0}, chip_cnt[2] = {0};\r
+void vc9202_test_init(VC9202TestInfoTypeDef *ptest_info)\r
+{\r
+ mcu_cnt[0] = 0;\r
+ mcu_cnt[1] = 0;\r
+ chip_cnt[0] = 0;\r
+ chip_cnt[1] = 0;\r
+ memset(ptest_info, 0, sizeof(VC9202TestInfoTypeDef));\r
+}\r
+\r
+static unsigned int vc9202_test_real_frequency(void)\r
+{\r
+ unsigned char cnt_reg[4] = {0};\r
+ unsigned int mcu_cnt_dif = 0;\r
+ unsigned int chp_cnt_dif = 0;\r
+ unsigned int calc_freq = 0;\r
+\r
+ mcu_cnt[1] = mcu_cnt[0];\r
+ chip_cnt[1] = chip_cnt[0];\r
+ mcu_cnt[0] = usr_get_clock_ticks();\r
+ usr_iic_read_bytes(0x07, cnt_reg, 4);\r
+ chip_cnt[0] = (cnt_reg[0] << 8) + cnt_reg[1];\r
+ unsigned short cnt1 = (cnt_reg[0] << 8) + cnt_reg[1];\r
+ unsigned short cnt2 = (cnt_reg[2] << 8) + cnt_reg[3];\r
+ if (abs(cnt1 - cnt2) >= 10)\r
+ {\r
+ return 0xffff;\r
+ }\r
+ if ((0 == mcu_cnt[1]) || (0 == mcu_cnt[0]))\r
+ return 20 * 1000;\r
+ if ((0 == chip_cnt[1]) || (0 == chip_cnt[0]))\r
+ return 20 * 1000;\r
+ 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]);\r
+ chp_cnt_dif = (chip_cnt[0] > chip_cnt[1]) ? (chip_cnt[0] - chip_cnt[1]) : (0xffff - chip_cnt[1] + chip_cnt[0]);\r
+ float timeDiff = (float)mcu_cnt_dif / (float)VC9202_CFG_CLK_CHECK_FREQUENCY;\r
+ calc_freq = (float)chp_cnt_dif / timeDiff;\r
+ if (calc_freq >= 0xffff)\r
+ calc_freq = 0xffff;\r
+ if (calc_freq <= 0)\r
+ calc_freq = 0;\r
+ return calc_freq;\r
+}\r
+\r
+static int vc9202_test_led_glint(VC9202TestInfoTypeDef *ptest_info)\r
+{\r
+ static unsigned char glint_count = 0;\r
+ if (ptest_info->step1_ret && ptest_info->step2_ret)\r
+ {\r
+ glint_count++;\r
+ if (glint_count == 25)\r
+ {\r
+ usr_iic_write_bytes(0x10, (unsigned char *)disp_green, 17);\r
+ }\r
+ else if (glint_count == 50)\r
+ {\r
+ glint_count = 0;\r
+ usr_iic_write_bytes(0x10, (unsigned char *)disp_red, 17);\r
+ }\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+/*记录bio变化值的最大的差值,用于判断bio变化是否满足阈值判断*/\r
+static void vc9202_test_bio_variation(VC9202TestInfoTypeDef *ptest_info, unsigned short bio)\r
+{\r
+ unsigned short now_gap = 0;\r
+ ptest_info->biovalue_now[1] = ptest_info->biovalue_now[0];\r
+ ptest_info->biovalue_now[0] = bio;\r
+ if (0 == ptest_info->biovalue_now[1] || 0 == ptest_info->biovalue_now[0])\r
+ {\r
+ return;\r
+ }\r
+ 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]);\r
+ if (now_gap > ptest_info->biovalue_max)\r
+ {\r
+ ptest_info->biovalue_max = now_gap;\r
+ ptest_info->biovalue_gap[0] = ptest_info->biovalue_now[0];\r
+ ptest_info->biovalue_gap[1] = ptest_info->biovalue_now[1];\r
+ }\r
+ return;\r
+}\r
+void vc9202_test_handler(SamplingDataTypeDef *pResult, VC9202TestInfoTypeDef *ptest_info)\r
+{\r
+ // 判断是否测试完成,只执行交替闪\r
+ if (vc9202_test_led_glint(ptest_info))\r
+ {\r
+ return;\r
+ }\r
+ // step1 计算频率 + 读取ID及中断原因\r
+ if (0 == ptest_info->step1_ret)\r
+ {\r
+ ptest_info->max_current = pResult->led_cur[0];\r
+ ptest_info->leak_pre_value = pResult->apre_val[0];\r
+ ptest_info->frequency = vc9202_test_real_frequency();\r
+ usr_iic_read_bytes(0x00, &ptest_info->icid, 1);\r
+ usr_iic_read_bytes(0x02, &ptest_info->reason, 1);\r
+ return;\r
+ }\r
+ // step2 bio.ps\r
+ if (0 != ptest_info->step1_ret && 0 == ptest_info->step2_ret)\r
+ {\r
+ ptest_info->ps_value = pResult->aps_val;\r
+ vc9202_test_bio_variation(ptest_info, pResult->bio_val_o);\r
+ }\r
+ return;\r
+}\r
+\r
+// 在xx_user.c中调用 case WORK_MODE_FACTORY: factory_test_function( &data ); break;\r
+#if 0\r
+static void fpc_test_function(SamplingDataTypeDef *pdata)\r
+{\r
+ extern VC9202TestInfoTypeDef vc9202_test_info;\r
+ /* 等待5次中断工作稳定 */\r
+ if (vc9202_test_info.wait_cnt <= 5)\r
+ {\r
+ vc9202_test_info.wait_cnt++;\r
+ return;\r
+ }\r
+ /* 步骤一:常规数据读取判断是否在范围内,此处得数据请根据实际设计对参数进行调整 */\r
+ if (0 == vc9202_test_info.step1_ret)\r
+ {\r
+ if (vc9202_test_info.icid == 0x21 && vc9202_test_info.reason & 0x3f && \r
+ vc9202_test_info.frequency >= 16000 && vc9202_test_info.frequency <= 24000)\r
+ {\r
+ vc9202_test_info.step1_ret = 1;\r
+ }\r
+ else\r
+ {\r
+ vc9202_test_info.step1_ret = 2;\r
+ }\r
+ }\r
+ /* 步骤二:bio/ps数据读取判断是否在范围内 */\r
+ else if (0 == vc9202_test_info.step2_ret)\r
+ {\r
+ if (vc9202_test_info.biovalue_max >= 400 && vc9202_test_info.ps_value >= 200)\r
+ {\r
+ vc9202_test_info.step2_ret = 1;\r
+ }\r
+ }\r
+ /*注意:上述方式会一直等待,直到检测通过,也可以使用人为触发记录,进行比较两次触发时的记录值差距是否满足。\r
+ 记录两次不同状态(模拟佩戴和摘下)下时的pdata->bio_val_o,比较差值\r
+ 记录模拟佩戴下的pdata->ps_val,判断是否满足PS范围\r
+ */\r
+ /* 其中step1_ret和step2_ret,分别表示测试是否通过,由于step2_ret需要检测变化量,所以需要一直等待操作,如果测试通过后,驱动会控制红绿灯交替闪烁 */\r
+ 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);\r
+ 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]);\r
+ printf("[FAT]-ret(%d,%d)", vc9202_test_info.step1_ret, vc9202_test_info.step2_ret);\r
+}\r
+\r
+#endif\r
--- /dev/null
+/*
+ * @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 <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+
+#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
--- /dev/null
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc9202_user.c\r
+ * @brief functional Module Layer\r
+ * @details The functional interface is implemented by calling the driver.contain init_func,irq_handler\r
+ * @author \r
+ * @date\r
+ * @version \r
+ *********************************************************************************************************/\r
+#include "algo.h"\r
+#include "spo2Algo.h"\r
+#include "vcSportMotionIntAlgo.h"\r
+#include "vc9202_common.h"\r
+#include "vc9202_user.h"\r
+#include "vc9202_driver.h"\r
+#include "custom_utils.h"\r
+#include "platform_core.h"\r
+#include "systick.h"\r
+#include "pinctrl_porting.h"\r
+#include "hal_gpio.h"\r
+#include "los_tick.h"\r
+\r
+static WorkModeTypeDef work_mode = WORK_MODE_NONE;\r
+AlgoCalcResultsTypeDef vc9202_alg_results = {0};\r
+\r
+/* 蓝牙发送原始数据接口 */\r
+extern void vc9202_debug_send_heart_rate_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char heart_rate, unsigned char algo_mode, unsigned char ppgsize );\r
+extern void vc9202_debug_send_spo2_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char spo2_val, unsigned char ppgsize );\r
+\r
+/*********************************************************************************************************\r
+ * PERIPHERAL FUNCTIONS\r
+ ********************************************************************************************************/\r
+#define CHIP_I2C_ADDRESS 0x33\r
+#define VC9202_I2C_BUS I2C_BUS_2\r
+\r
+/**\r
+ * @brief iic多字节写\r
+ * @param\r
+ * @arg reg_addr:寄存器地址\r
+ * @arg pBuffer:缓冲区指针\r
+ * @arg num_bytes:写的字节数\r
+ * @retval 无\r
+ */\r
+unsigned char usr_iic_write_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size)\r
+{\r
+ custom_i2c_write_reg(CHIP_I2C_ADDRESS, reg_addr, 1, pBuffer, buf_size, VC9202_I2C_BUS);\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ * @brief iic多字节读\r
+ * @param\r
+ * @arg reg_addr:寄存器地址\r
+ * @arg pBuffer:缓冲区指针\r
+ * @arg num_bytes:读的字节数\r
+ * @retval 无\r
+ */\r
+unsigned char usr_iic_read_bytes(unsigned char reg_addr, unsigned char *pBuffer, unsigned char buf_size)\r
+{\r
+ custom_i2c_read_regs(CHIP_I2C_ADDRESS, reg_addr, 1 , pBuffer, buf_size, VC9202_I2C_BUS);\r
+ return 0;\r
+}\r
+\r
+\r
+/**\r
+ * @brief 校验用时钟tick获取\r
+ * @param 无\r
+ * @retval 时钟tick\r
+ */\r
+unsigned int usr_get_clock_ticks(void)\r
+{\r
+ return uapi_systick_get_count();\r
+}\r
+\r
+/*********************************************************************************************************\r
+ * API FUNCTIONS\r
+ ********************************************************************************************************/\r
+/**\r
+ * @brief 获取chip_id\r
+ * @param 无\r
+ * @retval chip_id值\r
+ */\r
+void vc9202_usr_get_chip_id( unsigned char *pchip_id, unsigned char *pvers_id )\r
+{\r
+ usr_iic_read_bytes( 0x00, pchip_id, 1 );\r
+ usr_iic_read_bytes( 0x40, pvers_id, 1 );\r
+}\r
+\r
+/**\r
+ * @brief 初始化\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_usr_init( InitParamTypeDef *pInitParam )\r
+{\r
+ memset( &vc9202_alg_results, 0 ,sizeof(vc9202_alg_results) );\r
+ // vcSpo2AlgoInit();\r
+ spo2AlgoInit();\r
+ Algo_Init();\r
+ vcSportMotionAlgoInit();\r
+ work_mode = (WorkModeTypeDef)pInitParam->work_mode;\r
+ vc9202_drv_soft_reset();\r
+ vc9202_drv_reg_init( pInitParam );\r
+}\r
+\r
+/**\r
+ * @brief 开始采样\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_usr_start_sampling(void)\r
+{\r
+ vc9202_drv_start_sampling();\r
+}\r
+\r
+\r
+/**\r
+ * @brief 停止采样\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_usr_stop_sampling(void)\r
+{\r
+ vc9202_drv_stop_sampling();\r
+}\r
+\r
+\r
+/**\r
+ * @brief 软复位\r
+ * @param 无\r
+ * @retval 无\r
+ */\r
+void vc9202_usr_soft_reset(void)\r
+{\r
+ vc9202_drv_soft_reset();\r
+}\r
+\r
+/**\r
+ * @brief 独立使/失能某一物理通道\r
+ * @param\r
+ @num_channel 通道编号(1,2,3)\r
+ @enable_flag 使能或失能标志位\r
+ * @retval 0-成功,其他-失败\r
+ */\r
+unsigned char vc9202_usr_channel_switch(unsigned char num_channel, unsigned char enable_flag)\r
+{\r
+ return vc9202_drv_channel_switch(num_channel, enable_flag);\r
+}\r
+\r
+/**\r
+ * @brief 获取中断原因\r
+ * @param @无\r
+ @ int_reason 中断原因\r
+ * @retval 中断原因\r
+ */\r
+unsigned char vc9202_usr_get_int_reason(void)\r
+{\r
+ /* bit2:fifo,bit4:ps */\r
+ return vc9202_drv_get_int_reason();\r
+}\r
+/**\r
+ * @brief 获取佩戴检测结果\r
+ * @param @无\r
+ @ 无\r
+ * @retval 佩戴检测结果\r
+ */\r
+unsigned char vc9202_usr_get_wear_status(void)\r
+{\r
+ unsigned char sta = 0;\r
+ WearStatusTypeDef retSta = vc9202_drv_get_wear_status();\r
+ if( WEAR_STA_DROP == retSta )\r
+ {\r
+ sta = 0;\r
+ }\r
+ else\r
+ {\r
+ sta = 1;\r
+ }\r
+ return sta;\r
+}\r
+\r
+/**********************************************************************/\r
+\r
+#define ENABLE_GSENSOR 0\r
+/* gsensor 相关的示例代码 */\r
+#if ENABLE_GSENSOR\r
+typedef struct\r
+{\r
+ int16_t AXIS_X;\r
+ int16_t AXIS_Y;\r
+ int16_t AXIS_Z;\r
+} AxesRaw_t;\r
+static void gsensor_data_match(AxesRaw_t *org_data, GsensorTypeDef *pGsensorParam, unsigned char ppg_size)\r
+{\r
+ const unsigned char arry10[] = {0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12};\r
+ 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};\r
+ /* ppglen = 10 抽样 */\r
+ if( 10<=ppg_size )\r
+ {\r
+ for (uint8_t i = 0; i < ppg_size; i++)\r
+ {\r
+ pGsensorParam->gsensor_x_axis[i] = org_data[arry10[i]].AXIS_X;\r
+ pGsensorParam->gsensor_y_axis[i] = org_data[arry10[i]].AXIS_Y;\r
+ pGsensorParam->gsensor_z_axis[i] = org_data[arry10[i]].AXIS_Z;\r
+ }\r
+ }\r
+ else /* ppglen = 20 、25抽样 */\r
+ {\r
+ for (uint8_t i = 0; i < ppg_size; i++)\r
+ {\r
+ pGsensorParam->gsensor_x_axis[i] = org_data[arry20[i]].AXIS_X;\r
+ pGsensorParam->gsensor_y_axis[i] = org_data[arry20[i]].AXIS_Y;\r
+ pGsensorParam->gsensor_z_axis[i] = org_data[arry20[i]].AXIS_Z;\r
+ }\r
+ }\r
+}\r
+#endif\r
+\r
+static void get_gsensor_data( GsensorTypeDef *pGsensorParam, unsigned char *pgsensor_len, unsigned char ppg_size )\r
+{\r
+ /*\r
+ Gsensor精度要求 ReadGsensorFIFO(+-4G11bit or +-8G12bit 256/g)\r
+ 一个fifo周期为800ms,20组ppg数据,需要获取800ms内至少获取ppgCount组gsensor数据(40ms*20),用于匹配20组ppg信号,此函数需要根据用户实际的gsensor进行匹配处理。\r
+ */\r
+#if ENABLE_GSENSOR\r
+ unsigned char i = 0;\r
+ unsigned char gsensor_len = 0;\r
+ AxesRaw_t gsensor_buff[40] = {0};\r
+ pGsensorParam->sampling_rate = 25;\r
+ pGsensorParam->sensing_range = 4;\r
+ pGsensorParam->effective_bits = 12;\r
+ // stk8321_get_fifo_data(&gsensor_len, gsensor_buff);\r
+ if (ppg_size == 0)\r
+ {\r
+ *pgsensor_len = gsensor_len;\r
+ /* 不抽样 */\r
+ for (i = 0; i < *pgsensor_len; i++)\r
+ {\r
+ pGsensorParam->gsensor_x_axis[i] = gsensor_buff[i].AXIS_X;\r
+ pGsensorParam->gsensor_y_axis[i] = gsensor_buff[i].AXIS_Y;\r
+ pGsensorParam->gsensor_z_axis[i] = gsensor_buff[i].AXIS_Z;\r
+ }\r
+ }\r
+ /* 此demo中gsensor的采样频率高于ppg采样,所以正常情况下,gsensor的数量一定是大于ppg的数据。特殊情况需要考虑ppg数量大于gsensor数量。需要对gsensor数据进行补长 */\r
+ if( (gsensor_len>=ppg_size)&&(ppg_size!=0) )\r
+ {\r
+ *pgsensor_len = ppg_size;\r
+ // gsensor_data_match( gsensor_buff,pGsensorParam, ppg_size );\r
+ }\r
+ else if( (gsensor_len<ppg_size)&&(gsensor_len!=0) ) /* gsensor不足补全 */\r
+ {\r
+ *pgsensor_len = gsensor_len;\r
+ for( i=0; i<gsensor_len; i++ )\r
+ {\r
+ pGsensorParam->gsensor_x_axis[i] = gsensor_buff[i].AXIS_X;\r
+ pGsensorParam->gsensor_y_axis[i] = gsensor_buff[i].AXIS_Y;\r
+ pGsensorParam->gsensor_z_axis[i] = gsensor_buff[i].AXIS_Z;\r
+ }\r
+ for( i=gsensor_len; i<ppg_size; i++ )\r
+ {\r
+ pGsensorParam->gsensor_x_axis[i] = gsensor_buff[gsensor_len-1].AXIS_X;\r
+ pGsensorParam->gsensor_y_axis[i] = gsensor_buff[gsensor_len-1].AXIS_Y;\r
+ pGsensorParam->gsensor_z_axis[i] = gsensor_buff[gsensor_len-1].AXIS_Z;\r
+ }\r
+ }\r
+#endif\r
+}\r
+\r
+static unsigned int vc9202_usr_gsensor_actuating_quantity(int x_axis, int y_axis, int z_axis)\r
+{\r
+ unsigned int ret_atc = 0;\r
+ unsigned int abs_sum_current = 0;\r
+ static unsigned int abs_sum_last = 0;\r
+ if(x_axis < 0)\r
+ {\r
+ x_axis = -x_axis;\r
+ }\r
+ if(y_axis < 0)\r
+ {\r
+ y_axis = -y_axis;\r
+ }\r
+ if(z_axis < 0)\r
+ {\r
+ z_axis = -z_axis;\r
+ }\r
+ abs_sum_current = x_axis + y_axis + z_axis;\r
+ if(abs_sum_last&&abs_sum_current)\r
+ {\r
+ if( ABS(abs_sum_last,abs_sum_current)>=40 )\r
+ {\r
+ ret_atc = 1;\r
+ }\r
+ }\r
+ abs_sum_last = abs_sum_current;\r
+ /* 存在运动量时处理,释放掉心率算法摘下的状态 */\r
+ if( ret_atc )\r
+ {\r
+ vc9202_drv_set_algo_wear_status( WEAR_STA_HOLD );\r
+ }\r
+ vc9202_drv_set_gsensor_actuating_quantity( ret_atc );\r
+ return ret_atc;\r
+}\r
+\r
+static short int alg_calculate_hr_handler( short int last_hr_val, SamplingDataTypeDef *pdata, unsigned char ppg_size, GsensorTypeDef *pgsensor, AlgoSportMode hr_alg_mode )\r
+{\r
+ unsigned char i=0;\r
+ short int heart_rate_value = last_hr_val;\r
+ AlgoInputData_t alg_i_data={0};\r
+ AlgoOutputData_t alg_o_data={0};\r
+ /* 如果没有fifo则直接推出,此处return需要返回上一次的值 */\r
+ if( ppg_size <= 0 )\r
+ {\r
+ return heart_rate_value;\r
+ }\r
+ if(ppg_size>=40)\r
+ {\r
+ ppg_size = 40;\r
+ }\r
+ // printf("ppg_size : %d \n",ppg_size);\r
+ alg_i_data.envSample = pdata->env_val[0];\r
+ for( i=0; i<ppg_size; i++ )\r
+ {\r
+ alg_i_data.axes.x = pgsensor->gsensor_x_axis[i];\r
+ alg_i_data.axes.y = pgsensor->gsensor_y_axis[i];\r
+ alg_i_data.axes.z = pgsensor->gsensor_z_axis[i];\r
+ alg_i_data.ppgSample = pdata->ppg_data[i];\r
+ printf("pdata->ppg_data[%d] : %d \n",i,pdata->ppg_data[i]);\r
+ // 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);\r
+ Algo_Input( &alg_i_data, 1000/25, hr_alg_mode, 1, 1 );\r
+ }\r
+ Algo_Output( &alg_o_data );\r
+ // printf("alg_o_data.hrData : %d \n",alg_o_data.hrData);\r
+ if( -1 == alg_o_data.hrData )\r
+ {\r
+ vc9202_drv_set_algo_wear_status( WEAR_STA_DROP );\r
+ }\r
+ else if( alg_o_data.hrData > 0 )\r
+ {\r
+ heart_rate_value = alg_o_data.hrData; \r
+ }\r
+ return heart_rate_value;\r
+}\r
+\r
+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 )\r
+{\r
+ unsigned char i=0;\r
+ unsigned char spo2_value = last_spo2_val;\r
+ float ret_spo2 = 0.0f;\r
+ float ir_PPG = 0.0f;\r
+ float red_PPG = 0.0f;\r
+ float sport_flag = 0.0f;\r
+ /* 如果没有fifo则直接推出,此处return需要返回上一次的值 */\r
+ if( ppg_size<=0 )\r
+ {\r
+ return spo2_value;\r
+ }\r
+ for( i=0; i<ppg_size; i++ )\r
+ {\r
+ ir_PPG = (float)pdata->ppg_data[i*2];\r
+ red_PPG = (float)pdata->ppg_data[i*2+1];\r
+ // ret_spo2 = vcSpo2Calculate( red_PPG, ir_PPG );\r
+ ret_spo2 = spo2Algo(red_PPG,ir_PPG,1);\r
+ sport_flag = vcSportMotionCalculate( pgsensor->gsensor_x_axis[i], pgsensor->gsensor_y_axis[i], pgsensor->gsensor_z_axis[i] );\r
+ if ( (-1!=ret_spo2)&&(!sport_flag))\r
+ {\r
+ spo2_value = (unsigned char)ret_spo2;\r
+ }\r
+ }\r
+ return spo2_value;\r
+}\r
+\r
+static void factory_test_function( SamplingDataTypeDef *pdata )\r
+{\r
+ // /* 最大电流 */\r
+ // unsigned char ledMaxCur = pdata->led_cur[0]; //最大电流,黑箱通道2\r
+ // /* 获取测试数据 */\r
+ // unsigned int pre0 = pdata->apre_val[0];//绿灯强度,漏光模式通道1\r
+ // unsigned int ps = pdata->aps_val;//红外强度,灰卡模式通道3\r
+ // /* 温度 */\r
+ // signed short int temp0 = pdata->temp_val_i;\r
+ // signed short int temp1 = pdata->temp_val_o;\r
+ // /* compare abs(bio0,bio1) */\r
+ // unsigned short int bio0 = pdata->bio_val_o;\r
+ // unsigned short int bio1 = pdata->bio_val_o;\r
+}\r
+static void fpc_test_function(SamplingDataTypeDef *pdata)\r
+{\r
+ extern VC9202TestInfoTypeDef vc9202_test_info;\r
+ /* 等待5次中断工作稳定 */\r
+ if (vc9202_test_info.wait_cnt <= 5)\r
+ {\r
+ vc9202_test_info.wait_cnt++;\r
+ return;\r
+ }\r
+ /* 步骤一:常规数据读取判断是否在范围内,此处得数据请根据实际设计对参数进行调整 */\r
+ if (0 == vc9202_test_info.step1_ret)\r
+ {\r
+ if (vc9202_test_info.icid == 0x21 && vc9202_test_info.reason & 0x3f && \r
+ vc9202_test_info.frequency >= 16000 && vc9202_test_info.frequency <= 24000 )\r
+ {\r
+ vc9202_test_info.step1_ret = 1;\r
+ }\r
+ else\r
+ {\r
+ vc9202_test_info.step1_ret = 2;\r
+ }\r
+ }\r
+ /* 步骤二:bio/ps数据读取判断是否在范围内 */\r
+ else if (0 == vc9202_test_info.step2_ret)\r
+ {\r
+ if (vc9202_test_info.biovalue_max >= 60 && vc9202_test_info.ps_value >= 200)\r
+ {\r
+ vc9202_test_info.step2_ret = 1;\r
+ }\r
+ }\r
+ /*注意:上述方式会一直等待,直到检测通过,也可以使用人为触发记录,进行比较两次触发时的记录值差距是否满足。\r
+ 记录两次不同状态(模拟佩戴和摘下)下时的pdata->bio_val_o,比较差值\r
+ 记录模拟佩戴下的pdata->ps_val,判断是否满足PS范围\r
+ */\r
+ /* 其中step1_ret和step2_ret,分别表示测试是否通过,由于step2_ret需要检测变化量,所以需要一直等待操作,如果测试通过后,驱动会控制红绿灯交替闪烁 */\r
+ 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);\r
+ 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]);\r
+ printf("[FAT]-ret(%d,%d) \n", vc9202_test_info.step1_ret, vc9202_test_info.step2_ret);\r
+}\r
+\r
+void vc9202_usr_interrupt_handler( AlgoSportMode hr_alg_mode, unsigned char spo2_alg_mode )\r
+{\r
+ unsigned char wear_status = WEAR_STA_NONE;\r
+ SamplingDataTypeDef data = {0};\r
+ GsensorTypeDef gsensor_data = {0};\r
+ unsigned char gsensor_size = 0;\r
+ unsigned char ppg_size = 0;\r
+ VC9202DrvRetTypeDef ret = vc9202_drv_get_sampling_data( &data, &ppg_size );\r
+ printf("ppg_size : %d work_mode : %d ret : %d\n",ppg_size,work_mode,ret);\r
+ switch ( work_mode )\r
+ {\r
+ case WORK_MODE_HR:\r
+ printf("11111 vc9202_usr_get_int_reason : 0x%x \n",vc9202_usr_get_int_reason());\r
+ if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) )\r
+ {\r
+ wear_status = vc9202_usr_get_wear_status();\r
+ printf("11111 wear_status : %d \n",wear_status);\r
+ get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size);\r
+ if( gsensor_size>0 )\r
+ {\r
+ vc9202_usr_gsensor_actuating_quantity( gsensor_data.gsensor_x_axis[0], gsensor_data.gsensor_y_axis[0], gsensor_data.gsensor_z_axis[0] );\r
+ }\r
+ if(wear_status)\r
+ {\r
+ vc9202_alg_results.hr_rate = alg_calculate_hr_handler( vc9202_alg_results.hr_rate, &data, ppg_size, &gsensor_data, hr_alg_mode );\r
+ printf("vc9202_alg_results.hr_rate : %d \n",vc9202_alg_results.hr_rate);\r
+ vc9202_debug_send_heart_rate_data( &data, &gsensor_data, vc9202_alg_results.hr_rate, hr_alg_mode, ppg_size );\r
+ }\r
+ else\r
+ {\r
+ vc9202_alg_results.hr_rate = 0;\r
+ Algo_Init();\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WORK_MODE_SPO2:\r
+ if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) )\r
+ {\r
+ wear_status = vc9202_usr_get_wear_status();\r
+ get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size);\r
+ if(wear_status)\r
+ {\r
+ vc9202_alg_results.spo2_val = alg_calculate_spo2_handler( vc9202_alg_results.spo2_val, &data, ppg_size/2, &gsensor_data, spo2_alg_mode );\r
+ printf("vc9202_alg_results.spo2_val : %d \n",vc9202_alg_results.spo2_val);\r
+ vc9202_debug_send_spo2_data( &data, &gsensor_data, vc9202_alg_results.spo2_val, ppg_size/2 );\r
+ }\r
+ else\r
+ {\r
+ vc9202_alg_results.spo2_val = 0;\r
+ // vcSpo2AlgoInit();\r
+ spo2AlgoInit();\r
+ vcSportMotionAlgoInit();\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WORK_MODE_HRV:\r
+ if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) )\r
+ {\r
+ wear_status = vc9202_usr_get_wear_status();\r
+ get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size);\r
+ if(wear_status)\r
+ {\r
+ vc9202_alg_results.hr_rate = alg_calculate_hr_handler( vc9202_alg_results.hr_rate, &data, ppg_size, &gsensor_data, hr_alg_mode );\r
+ /* 校验+算法HRV */\r
+ }\r
+ else\r
+ {\r
+ vc9202_alg_results.hr_rate = 0;\r
+ Algo_Init();\r
+ /* 清空数据+初始化算法 */\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WORK_MODE_STRESS:\r
+ if( vc9202_usr_get_int_reason()&(VC9202_EVENT_PS_MARK|VC9202_EVENT_FIFO_MARK) )\r
+ {\r
+ wear_status = vc9202_usr_get_wear_status();\r
+ get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size);\r
+ if(wear_status)\r
+ {\r
+ /* 校验+算法STRESS */\r
+ }\r
+ else\r
+ {\r
+ /* 清空数据+初始化算法 */\r
+ }\r
+ }\r
+ break;\r
+\r
+ case WORK_MODE_WEAR:\r
+ if( vc9202_usr_get_int_reason() & VC9202_EVENT_PS_MARK )\r
+ {\r
+ wear_status = vc9202_usr_get_wear_status();\r
+ get_gsensor_data(&gsensor_data, &gsensor_size, ppg_size);\r
+ if( gsensor_size>0 )\r
+ {\r
+ vc9202_usr_gsensor_actuating_quantity( gsensor_data.gsensor_x_axis[0], gsensor_data.gsensor_y_axis[0], gsensor_data.gsensor_z_axis[0] );\r
+ }\r
+ /* 根据佩戴状态添加对应的处理代码 */\r
+ if(wear_status)\r
+ {\r
+ printf("111 wear \n");\r
+ }\r
+ else\r
+ {\r
+ printf("222 nowear \n");\r
+ }\r
+ }\r
+ break;\r
+ case WORK_MODE_FACTORY:\r
+ factory_test_function( &data );\r
+ break;\r
+ case WORK_MODE_FPC_TEST:\r
+ fpc_test_function(&data);\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+}\r
+\r
+#if 0\r
+int main(int argc, char *argv[])\r
+{\r
+ board_driver_init(); //MCU外设初始化\r
+ InitParamTypeDef config={400,WORK_MODE_HR}; //修改fifo间隔时间(关系到fifolength), 设定工作模式\r
+ vc9102_usr_init( &config );\r
+ while(1)\r
+ {\r
+ if( irq_msg )\r
+ {\r
+ //调用时传入心率算法模式(日常、运动...)和血氧算法参数。\r
+ vc9102_usr_interrupt_handler( algo_mode, 1 );\r
+ }\r
+ }\r
+ return 0\r
+}\r
+#endif\r
+\r
--- /dev/null
+/*********************************************************************************************************\r
+ * Copyright(c) 2022, vcare Corporation. All rights reserved.\r
+ **********************************************************************************************************\r
+ * @file vc9202_user_debug.c\r
+ * @brief example,debug send original data\r
+ * @details \r
+ * @author \r
+ * @date\r
+ * @version \r
+ *********************************************************************************************************/\r
+\r
+#include "vc9202_common.h"\r
+#include "vc9202_user.h"\r
+\r
+// #include "os_timer.h"\r
+// #include <simple_ble_service.h>\r
+// #include "wristband_global_data.h"\r
+// extern RtkWristBandSysType_t RtkWristbandSys;\r
+\r
+static unsigned char ble_buf[1024]={0};\r
+static unsigned short int buf_size = 0;\r
+static unsigned short int buf_index = 0;\r
+#define BLE_PACK_SIZE 160\r
+#define TIMER_BLE_GAP 100\r
+\r
+/**********************************************************************************************************\r
+ * 对苹果手机APP不能连续接收长段数据,利用软件定时器,进行分包发送\r
+ * 创建软件定时器及数据分包处理\r
+ */\r
+static void send_data_by_ble( unsigned char *pbuf, unsigned short int size )\r
+{\r
+ // if (RtkWristbandSys.gap_conn_state == GAP_CONN_STATE_CONNECTED)\r
+ // {\r
+ // hr_ble_service_send_v3_notify(RtkWristbandSys.wristband_conn_id, hr_ser_id, pbuf, size);\r
+ // DBG_DIRECT("ble_send_buffer_size=%d",size);\r
+ // }\r
+}\r
+\r
+static int timer_send_data_function(void)\r
+{\r
+ unsigned short int residue_size = 0;\r
+ //数据发送已经完成\r
+ if( buf_index >= buf_size )\r
+ {\r
+ return 0;\r
+ }\r
+ //判断剩余数据长度是否还需要分包\r
+ residue_size = buf_size-buf_index;\r
+ if( residue_size <= BLE_PACK_SIZE )\r
+ {\r
+ send_data_by_ble( &ble_buf[buf_index], residue_size );\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ send_data_by_ble( &ble_buf[buf_index], BLE_PACK_SIZE );\r
+ buf_index +=BLE_PACK_SIZE;\r
+ return 1;\r
+ }\r
+}\r
+\r
+\r
+/* 创建软件定时器,如果数据太长通过软件定时器发送 */\r
+#define TIMER_ID 0xf0\r
+static void *debug_send_timer = NULL;\r
+static void debug_send_timer_start(void)\r
+{\r
+ if( debug_send_timer )\r
+ {\r
+ // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP);\r
+ }\r
+}\r
+static void debug_send_timer_stop(void)\r
+{\r
+ if( debug_send_timer )\r
+ {\r
+ os_timer_stop(&debug_send_timer);\r
+ }\r
+}\r
+\r
+static void debug_send_timer_callback( void *p_handle )\r
+{\r
+ if( timer_send_data_function() )\r
+ {\r
+ /* 定时器继续循环 */\r
+ // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP);\r
+ }\r
+ else\r
+ {\r
+ /* 关闭定时器 */\r
+ debug_send_timer_stop();\r
+ }\r
+}\r
+\r
+void vc9202_debug_send_timer_init( void )\r
+{\r
+ if(debug_send_timer == NULL)\r
+ {\r
+ os_timer_create(&debug_send_timer, "debug_send_timer", TIMER_ID, TIMER_BLE_GAP, false, debug_send_timer_callback);\r
+ }\r
+ // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP);\r
+ os_timer_stop(&debug_send_timer);\r
+}\r
+\r
+static void debug_orginal_data_send( unsigned short int size )\r
+{\r
+ buf_index = 0;\r
+ buf_size = size;\r
+ if( buf_size <= BLE_PACK_SIZE )\r
+ {\r
+ send_data_by_ble( ble_buf, size );\r
+ }\r
+ else\r
+ {\r
+ send_data_by_ble( ble_buf, BLE_PACK_SIZE );\r
+ buf_index += BLE_PACK_SIZE;\r
+ debug_send_timer_start();\r
+ }\r
+}\r
+\r
+/**********************************************************************************************************/\r
+#define ORIGINAL_DATA_DEBUG_ENABLE (1)\r
+\r
+#if ORIGINAL_DATA_DEBUG_ENABLE\r
+\r
+void vc9202_debug_send_heart_rate_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char heart_rate, unsigned char algo_mode, unsigned char ppgsize )\r
+{\r
+ unsigned short int i = 0;\r
+ for( i=0; i<ppgsize; i++ )\r
+ {\r
+ ble_buf[i*16 + 0 ] = presult->ppg_data[i] >> 8;\r
+ ble_buf[i*16 + 1 ] = presult->ppg_data[i] & 0xff;\r
+ ble_buf[i*16 + 2 ] = paxis->gsensor_x_axis[i] >> 8;\r
+ ble_buf[i*16 + 3 ] = paxis->gsensor_x_axis[i] & 0xff;\r
+ ble_buf[i*16 + 4 ] = paxis->gsensor_y_axis[i] >> 8;\r
+ ble_buf[i*16 + 5 ] = paxis->gsensor_y_axis[i] & 0xff;\r
+ ble_buf[i*16 + 6 ] = paxis->gsensor_z_axis[i] >> 8;\r
+ ble_buf[i*16 + 7 ] = paxis->gsensor_z_axis[i] & 0xff;\r
+ ble_buf[i*16 + 8 ] = heart_rate;\r
+ ble_buf[i*16 + 9 ] = presult->pd_res[0];\r
+ ble_buf[i*16 + 10] = presult->led_cur[0];\r
+ ble_buf[i*16 + 11] = presult->env_val[2];\r
+ ble_buf[i*16 + 12] = presult->pre_val[0];\r
+ ble_buf[i*16 + 13] = presult->bio_val_o>>8;\r
+ ble_buf[i*16 + 14] = presult->bio_val_o&0xff;\r
+ ble_buf[i*16 + 15] = presult->aps_val;\r
+ }\r
+ if( ppgsize > 0 )\r
+ {\r
+ debug_orginal_data_send( ppgsize*16 );\r
+ }\r
+}\r
+\r
+/****************************************************************************************\r
+ * \r
+ */\r
+void vc9202_debug_send_spo2_data( SamplingDataTypeDef* presult ,GsensorTypeDef* paxis, unsigned char spo2_val, unsigned char ppgsize )\r
+{\r
+ unsigned short int i = 0;\r
+ for( i=0; i<ppgsize; i++ )\r
+ {\r
+ ble_buf[i*16 + 0 ] = presult->ppg_data[i*2] >> 8;\r
+ ble_buf[i*16 + 1 ] = presult->ppg_data[i*2] & 0xff;\r
+ ble_buf[i*16 + 2 ] = paxis->gsensor_x_axis[i] >> 8;\r
+ ble_buf[i*16 + 3 ] = paxis->gsensor_x_axis[i] & 0xff;\r
+ ble_buf[i*16 + 4 ] = paxis->gsensor_y_axis[i] >> 8;\r
+ ble_buf[i*16 + 5 ] = paxis->gsensor_y_axis[i] & 0xff;\r
+ ble_buf[i*16 + 6 ] = presult->pre_val[0];\r
+ ble_buf[i*16 + 7 ] = presult->pre_val[1];\r
+ ble_buf[i*16 + 8 ] = presult->ppg_data[i*2+1] >> 8;\r
+ ble_buf[i*16 + 9 ] = presult->ppg_data[i*2+1] & 0xff;\r
+ ble_buf[i*16 + 10] = spo2_val;\r
+ ble_buf[i*16 + 11] = presult->env_val[2];\r
+ ble_buf[i*16 + 12] = presult->pd_res[0];\r
+ ble_buf[i*16 + 13] = presult->led_cur[0];\r
+ ble_buf[i*16 + 14] = presult->pd_res[1];\r
+ ble_buf[i*16 + 15] = presult->led_cur[1];\r
+ }\r
+ if( ppgsize > 0 )\r
+ {\r
+ debug_orginal_data_send( ppgsize*16 );\r
+ }\r
+}\r
+\r
+#endif\r
+\r
+\r
+\r
--- /dev/null
+#===============================================================================
+# @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()
+
--- /dev/null
+/*\r
+ *\r
+ * Created on: 2023-6-04\r
+ * Author: runningHorse\r
+ */\r
+\r
+#ifndef BIODETECT\r
+#define BIODETECT\r
+\r
+#include <stdbool.h>\r
+#include <stdint.h>\r
+\r
+void f_BIOInit(int32_t gapDeltaBIO, int32_t gapDeltaPS);\r
+\r
+uint8_t f_BIOdetect(int32_t inputBIO, int32_t inputPS, int32_t PSth);\r
+\r
+char* bioVersion(void);\r
+\r
+#endif /* BIODETECT */
\ No newline at end of file
--- /dev/null
+\r
+#ifndef APP_ALGO_ALGO_H\r
+#define APP_ALGO_ALGO_H\r
+\r
+#include <stdbool.h>\r
+#include <stdint.h>\r
+\r
+typedef enum\r
+{\r
+ SPORT_TYPE_NORMAL =0x00, // 日常\r
+ SPORT_TYPE_RUNNING =0x01, // 跑步\r
+ SPORT_TYPE_RIDE_BIKE =0X02, // 骑行\r
+ SPORT_TYPE_JUMP_ROPE =0X03, // 跳绳\r
+ SPORT_TYPE_SWIMMING =0X04, // 游泳\r
+ SPORT_TYPE_BADMINTON =0X05, // 羽毛球\r
+ SPORT_TYPE_TABLE_TENNIS=0X06, // 乒乓球\r
+ SPORT_TYPE_TENNIS =0X07, // 网球\r
+ SPORT_TYPE_CLIMBING =0X08, // 爬山\r
+ SPORT_TYPE_WALKING =0X09, // 徒步\r
+ SPORT_TYPE_BASKETBALL =0X0A, // 篮球\r
+ SPORT_TYPE_FOOTBALL =0X0B, // 足球\r
+ SPORT_TYPE_BASEBALL =0X0C, // 棒球\r
+ SPORT_TYPE_VOLLEYBALL =0X0D, // 排球\r
+ SPORT_TYPE_CRICKET = 0X0E, // 板球\r
+ SPORT_TYPE_RUGBY = 0X0F, // 橄榄球\r
+ SPORT_TYPE_HOCKEY =0X10, // 曲棍球\r
+ SPORT_TYPE_DANCE = 0X11, // 跳舞\r
+ SPORT_TYPE_SPINNING = 0X12, // 动感单车\r
+ SPORT_TYPE_YOGA = 0X13, // 瑜伽\r
+ SPORT_TYPE_SIT_UP =0X14, // 仰卧起坐\r
+ SPORT_TYPE_TREADMILL =0X15, // 跑步机\r
+ SPORT_TYPE_GYMNASTICS =0X16, // 体操\r
+ SPORT_TYPE_BOATING = 0X17, // 划船\r
+ SPORT_TYPE_JUMPING_JACK = 0X18, // 开合跳\r
+ SPORT_TYPE_FREE_TRAINING = 0X19,// 自由训练\r
+ SPORT_TYPE_PERIODIC_MONITORING = 0X1A,// 定时监测模式\r
+} AlgoSportMode;\r
+//未出现在上表中的运动形式均先以跑步输入\r
+\r
+\r
+typedef struct\r
+{\r
+ int32_t x;\r
+ int32_t y;\r
+ int32_t z;\r
+}AlgoAxesData_t;\r
+\r
+typedef struct\r
+{\r
+ int32_t hrData;\r
+ int32_t reliability;\r
+}AlgoOutputData_t;\r
+\r
+typedef struct\r
+{\r
+ AlgoAxesData_t axes;\r
+ int32_t ppgSample;\r
+ int32_t envSample;\r
+}AlgoInputData_t;\r
+\r
+void Algo_Init(void);\r
+void Algo_Input(AlgoInputData_t *pInputData,int32_t gaptime,AlgoSportMode sportMode,int16_t surfaceRecogMode,int16_t opticalAidMode);\r
+void Algo_Output(AlgoOutputData_t *pOutputData);\r
+\r
+\r
+\r
+#endif /* APP_ALGO_ALGO_H_ */\r
+\r
+\r
+\r
--- /dev/null
+/*
+ * 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 <float.h>
+#include <math.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+//#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]
+ */
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-03-21 15:58:48\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+\r
+#ifndef __VC921x_CORE_H__\r
+#define __VC921x_CORE_H__\r
+\r
+#ifndef VC_PACKED\r
+#define VC921x_PACKED //__attribute__((packed))\r
+#endif\r
+\r
+/*===============================================================\r
+regist_list_map start...\r
+================================================================*/\r
+#define CORE921x_DEV_VER_ID_H_ADDR (0x00)\r
+#define CORE921x_FDY_EXT_ID_L_ADDR (0x01)\r
+#define CORE921x_WORK_STATUS1_ADDR (0x02)\r
+#define CORE921x_WORK_STATUS2_ADDR (0x03)\r
+#define CORE921x_FIFO_W_INDEX_ADDR (0x04)\r
+#define CORE921x_OSC_CNT0_H_ADDR (0x05)\r
+#define CORE921x_OSC_CNT0_L_ADDR (0x06)\r
+#define CORE921x_OSC_CNT1_H_ADDR (0x07)\r
+#define CORE921x_OSC_CNT1_L_ADDR (0x08)\r
+\r
+/****************************************************************\r
+ * ic sample param structure, 0x09 - 0x23 = 28byte\r
+ ***************************************************************/\r
+#define CORE921x_SAMPLE_DATA_ADDR_BASE (0x09)\r
+typedef struct\r
+{\r
+ /* env data, 6byte_12bit[12,0] */\r
+ unsigned char slot0_envh6;\r
+ unsigned char slot0_envl6;\r
+ unsigned char slot1_envh6;\r
+ unsigned char slot1_envl6;\r
+ unsigned char slot2_envh6;\r
+ unsigned char slot2_envl6;\r
+ /* ps data 3byte */\r
+ unsigned char slot0_ps;\r
+ unsigned char slot1_ps;\r
+ unsigned char slot2_ps;\r
+ /* bio data 4byte */\r
+ unsigned char bioinn_valh;\r
+ unsigned char bioinn_vall;\r
+ unsigned char bioext_valh;\r
+ unsigned char bioext_vall;\r
+ /* temp data 6byte */\r
+ unsigned char tempslot0_valh; /* temp0-inside */\r
+ unsigned char tempslot0_vall;\r
+ unsigned char tempslot1_valh; /* temp1-external */\r
+ unsigned char tempslot1_vall;\r
+ unsigned char tempref_valh; /* temp_ext_ref */\r
+ unsigned char tempref_vall;\r
+} VC921x_PACKED core921x_reg_result_t;\r
+\r
+/****************************************************************\r
+ * ic config param structure.[SLOT_CONFIG]\r
+ ***************************************************************/\r
+#define CORE921x_CONFIG_SLOT_ADDR_BASE (0x40)\r
+typedef struct\r
+{\r
+ unsigned char oversample : 3;\r
+ unsigned char freq_isps : 1;\r
+ unsigned char rxgain : 3;\r
+ unsigned char enable : 1;\r
+} VC921x_PACKED core921x_slot_ppg_cfg0bit;\r
+typedef struct\r
+{\r
+ unsigned char env_time : 4;\r
+ unsigned char sample_time : 2;\r
+ unsigned char txch : 2;\r
+} VC921x_PACKED core921x_slot_ppg_cfg1bit;\r
+typedef struct\r
+{\r
+ unsigned char current : 7;\r
+ unsigned char storefifo : 1;\r
+} VC921x_PACKED core921x_slot_cfg2bit;\r
+typedef struct\r
+{\r
+ unsigned char sc : 4;\r
+ unsigned char resistance : 4;\r
+} VC921x_PACKED core921x_slot_cfg3bit;\r
+/*---[slot regist map]---*/\r
+typedef struct\r
+{\r
+ union /* 1_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_slot_ppg_cfg0bit bits;\r
+ } slot_cfg0;\r
+ union /* 2_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_slot_ppg_cfg1bit bits;\r
+ } slot_cfg1;\r
+ union /* 3_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_slot_cfg2bit bits;\r
+ } slot_cfg2;\r
+ union /* 4_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_slot_cfg3bit bits;\r
+ } slot_cfg3;\r
+} VC921x_PACKED core921x_slot_config_t;\r
+\r
+/****************************************************************\r
+ * ic config param structure.[PD_CONFIG + IRQ_RATE_CONFIG + IRQ_CONFIG]\r
+ ***************************************************************/\r
+#define CORE921x_INT_RATE_IRQ_CONFIG_ADDR_BASE (0x4C)\r
+\r
+typedef struct\r
+{\r
+ unsigned char slot0_pdch : 2;\r
+ unsigned char slot1_pdch : 2;\r
+ unsigned char slot2_pdch : 2;\r
+ unsigned char reserved : 2;\r
+} VC921x_PACKED core921x_pd_cfgbit;\r
+\r
+typedef struct\r
+{\r
+ unsigned char anti_current : 3;\r
+ unsigned char reserved1 : 1;\r
+ unsigned char deslot0 : 1;\r
+ unsigned char deslot1 : 1;\r
+ unsigned char deslot2 : 1;\r
+ unsigned char reserved2 : 1;\r
+} VC921x_PACKED core921x_anti_cfgbit_1120mpw;\r
+\r
+typedef struct\r
+{\r
+ unsigned char anti_current : 3;\r
+ unsigned char deslot0 : 1;\r
+ unsigned char deslot1 : 1;\r
+ unsigned char deslot2 : 1;\r
+ unsigned char antiTxch : 2;\r
+} VC921x_PACKED core921x_anti_cfgbit;\r
+\r
+typedef struct\r
+{\r
+ unsigned char cpd : 3;\r
+ unsigned char fifo_en : 1;\r
+ unsigned char fifoformat : 1;\r
+ unsigned char bio_disfreqHop : 1; /* del function */\r
+ unsigned char i2crelease_en : 1;\r
+ unsigned char deenv_en : 1;\r
+} VC921x_PACKED core921x_com_cfgbit;\r
+typedef struct\r
+{\r
+ unsigned char ppgthl : 4;\r
+ unsigned char ppgthh : 4;\r
+} VC921x_PACKED core921x_ppgth_cfgbit;\r
+\r
+typedef struct\r
+{\r
+ unsigned char intppg_en : 1;\r
+ unsigned char intov_en : 1;\r
+ unsigned char intfifo_en : 1;\r
+ unsigned char intfreq2_en : 1;\r
+ unsigned char intlen : 2;\r
+ unsigned char intdir : 1;\r
+ unsigned char intmode : 1;\r
+} VC921x_PACKED core921x_int_cfgbit;\r
+\r
+typedef struct\r
+{\r
+ /* 1byte pdch_config */\r
+ union\r
+ {\r
+ unsigned char byte;\r
+ core921x_pd_cfgbit bits;\r
+ } pd_cfg;\r
+ /* 2_byte:anti_slot */\r
+ union\r
+ {\r
+ unsigned char byte;\r
+ core921x_anti_cfgbit bits;\r
+ };\r
+ /* 3_byte:com&pdcfg */\r
+ union\r
+ {\r
+ unsigned char byte;\r
+ core921x_com_cfgbit bits;\r
+ } com_cfg;\r
+ /* 4~7_byte */\r
+ unsigned char freq1_divH;\r
+ unsigned char freq1_divL; /* ppg_freq1_div = 20K / rete1 */\r
+ unsigned char freq2_div; /* ps_freq2_div = ppg_freq / rate2 */\r
+ unsigned char freq3_div; /* fifo_freq3_div = ps_freq / rate3 */\r
+ /* 8_byte */\r
+ union\r
+ {\r
+ unsigned char byte;\r
+ core921x_ppgth_cfgbit bits;\r
+ } ppgth_cfg;\r
+ /* 9_byte */\r
+ union\r
+ {\r
+ unsigned char byte;\r
+ core921x_int_cfgbit bits;\r
+ } int_cfg;\r
+} VC921x_PACKED core921x_common_config_t;\r
+\r
+/****************************************************************\r
+ * ic config param structure.[EXTRA_CONFIG]\r
+ ***************************************************************/\r
+#define CORE921x_EXTRA_CONFIG_ADDR_BASE (0x54)\r
+\r
+typedef struct\r
+{\r
+ /* byte1 */\r
+ unsigned char bio_freq : 2;\r
+ unsigned char bio_pdch : 2;\r
+ unsigned char bio_mode : 2; /* 00/01 work in freq2,noFIFO/inFIFO, single sample data\r
+ 10/11 work in freq1,inFIFO, single sample data / the sum data on freq2 */\r
+ unsigned char bio_inn_en : 1;\r
+ unsigned char bio_ext_en : 1;\r
+} VC921x_PACKED core921x_bio_cfg0bit;\r
+typedef struct\r
+{\r
+ unsigned char bio_time : 3;\r
+ unsigned char bio_capadd : 5;\r
+} VC921x_PACKED core921x_bio_cfg1bit;\r
+\r
+typedef struct\r
+{\r
+ unsigned char temp_currset : 3;\r
+ unsigned char temp_reserved_1 : 1;\r
+ unsigned char temp_slotch : 2;\r
+ unsigned char temp_reserved_2 : 1;\r
+ unsigned char temp_enable : 1;\r
+} VC921x_PACKED core921x_temp_cfgbit;\r
+typedef struct\r
+{\r
+ union /* 1_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_bio_cfg0bit bits;\r
+ } bio_cfg0;\r
+ union /* 2_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_bio_cfg1bit bits;\r
+ } bio_cfg1;\r
+ union /* 3_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_temp_cfgbit bits;\r
+ } temp0_cfg;\r
+ union /* 4_byte */\r
+ {\r
+ unsigned char byte;\r
+ core921x_temp_cfgbit bits;\r
+ } temp1_cfg;\r
+} VC921x_PACKED core921x_extra_config_t; // core921x_extra_config_t\r
+\r
+typedef struct\r
+{\r
+ unsigned char ovtype : 1;\r
+ unsigned char cmpset : 2;\r
+ unsigned char reserved : 1;\r
+ unsigned char ppg_resulution : 2;\r
+ unsigned char adc_speed : 1; /* reserved */\r
+ unsigned char env_clkdiv : 1; /* reserved */\r
+} VC921x_PACKED core921x_adc_config_t;\r
+\r
+typedef struct\r
+{\r
+ unsigned char ovtype : 1;\r
+ unsigned char reserved : 3;\r
+ unsigned char ppg_resulution : 2;\r
+ unsigned char adc_speed : 1; /* reserved */\r
+ unsigned char env_clkdiv : 1; /* reserved */\r
+} VC921x_PACKED core921x_adc_config_t_1120mpw;\r
+\r
+/****************************************************************\r
+ * work_cmd & fifo_data structure\r
+ ***************************************************************/\r
+#define CORE921x_WORK_CMD_ADDR_BASE (0X7B)\r
+#define CORE921x_WORK_CMD_SIZE (1)\r
+/* fifo addr */\r
+#define CORE921x_FIFO_READADDR_INDEX (0xFE)\r
+#define CORE921x_FIFO_DATA_ADDR (0xff)\r
+\r
+/****************************************************************\r
+ * inline func: vc921x_core_memset,vc921x_core_memcpy\r
+ ***************************************************************/\r
+#ifndef NULL\r
+#define NULL (void *)0\r
+#endif\r
+static inline void *vc921x_core_memset(void *dest, int set, unsigned int n)\r
+{\r
+ if (dest == NULL || n <= 0)\r
+ {\r
+ return NULL;\r
+ }\r
+ char *pdest = (char *)dest;\r
+ while (n-- > 0)\r
+ {\r
+ *pdest++ = set;\r
+ }\r
+ return dest;\r
+}\r
+static inline void *vc921x_core_memcpy(void *dest, void *src, unsigned int n)\r
+{\r
+ if (dest == NULL || src == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ char *pdest = (char *)dest;\r
+ char *psrc = (char *)src;\r
+ while (n--)\r
+ {\r
+ *pdest++ = *psrc++;\r
+ }\r
+ return dest;\r
+}\r
+\r
+#endif /* __VC921x_CORE_H__ */\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-04-09 15:26:54\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+//!!!!!!注意:本头文件不允许用户自己包含及调用相关的API,仅允许vc921x_driver.c包含,避免出错或者是产生的ROM占用\r
+//!!!!!!注意:本头文件不允许用户自己包含及调用相关的API,仅允许vc921x_driver.c包含,避免出错或者是产生的ROM占用\r
+#ifndef __VC921x_CORE_COM_H__\r
+#define __VC921x_CORE_COM_H__\r
+\r
+#include "vc921x_sample_result.h"\r
+#include "vc921x_driver_config.h"\r
+\r
+/* 如果需要指定变量到对应的字段在次定义,且重新编译 */\r
+#define CORE921x_DATA_RAM_SECTION //__attribute__((section(".core921xdata")))\r
+#define CORE921x_FUNC_RAM_SECTION //__attribute__((section(".core921xfunc")))\r
+/*============================================================================\r
+ * CORE921x_DEBUG :debug interface\r
+ ===========================================================================*/\r
+// #define CORE921x_DEBUG_VERSION\r
+/* 在编译库的时候,-D CORE921x_DEBUG_VERSION 对代码进行分版本生成库(debug/release) */\r
+#ifdef CORE921x_DEBUG_VERSION\r
+extern void log_direct(unsigned int info, const char *fmt, ...);\r
+#define CORE921x_DEBUG_LOG(fmt, ...) \\r
+ do \\r
+ { \\r
+ log_direct((33 << 24), "[CORE921x_LOG]line(%d)" fmt, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+#define CORE921x_DEBUG_ERR(fmt, ...) \\r
+ do \\r
+ { \\r
+ log_direct((33 << 24), "[CORE921x_ERR]line(%d)" fmt, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+#else\r
+#define CORE921x_DEBUG_LOG(fmt, ...)\r
+#define CORE921x_DEBUG_ERR(fmt, ...)\r
+#endif\r
+\r
+#if 0 // CORE921x_DEBUG_LOG example\r
+extern int (*vc921x_dbglog_user)(const char *, ...);\r
+#define CORE921x_DEBUG_LOG(fmt, ...) \\r
+ do \\r
+ { \\r
+ if (vc921x_dbglog_user) \\r
+ vc921x_dbglog_user("[CORE921x_LOG]%s(%d)" fmt, __func__, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+#define CORE921x_DEBUG_ERR(fmt, ...) \\r
+ do \\r
+ { \\r
+ if (vc921x_dbglog_user) \\r
+ vc921x_dbglog_user("[CORE921x_ERR]%s(%d)" fmt, __func__, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+//#else\r
+#define CORE921x_DEBUG_LOG(fmt, ...)\r
+#define CORE921x_DEBUG_ERR(fmt, ...)\r
+#endif\r
+\r
+/*============================================================================\r
+ * IC resources marco\r
+ ===========================================================================*/\r
+ /* VC921x IC type ID */\r
+#define VC921x_DEV_REV_ID 0x24\r
+#define VC921x_FDY_VER_ID0 0x10\r
+\r
+#define VC921x_FDY_VER_ID1 0x30\r
+\r
+#define VC921x_DEFAULT_FREQ (20000) /* 20K */\r
+/* work event */\r
+#define VC921x_EVENT_BIO_FLOW (1 << 6)\r
+#define VC921x_EVENT_INSAMPLE (1 << 5)\r
+#define VC921x_EVENT_CONFLICT (1 << 4)\r
+#define VC921x_EVENT_INTPS_RDY (1 << 3)\r
+#define VC921x_EVENT_INTFIFO_RDY (1 << 2)\r
+#define VC921x_EVENT_INTOVLOAD (1 << 1)\r
+#define VC921x_EVENT_INTPPG_STA (1 << 0)\r
+/* work status */\r
+#define VC921x_STATUS_CH2_OVERLOAD (1 << 2)\r
+#define VC921x_STATUS_CH1_OVERLOAD (1 << 1)\r
+#define VC921x_STATUS_CH0_OVERLOAD (1 << 0)\r
+/* enable event */\r
+#define VC921x_EN_EVT_FREQ2 (1 << 3)\r
+#define VC921x_EN_EVT_FIFO (1 << 2)\r
+#define VC921x_EN_EVT_OVLD (1 << 1)\r
+#define VC921x_EN_EVT_PPG (1 << 0)\r
+\r
+typedef enum\r
+{\r
+ VC921x_CFG_DISABLE = 0,\r
+ VC921x_CFG_ENABLE = 1,\r
+} VC921x_CFG_FUNC;\r
+\r
+typedef enum\r
+{\r
+ VC921x_PPG_SLOT_0 = 0,\r
+ VC921x_PPG_SLOT_1 = 1,\r
+ VC921x_PPG_SLOT_2 = 2, /* fix=ps */\r
+} VC921x_PPG_SLOT_I; /* 逻辑工作通道 */\r
+\r
+typedef enum\r
+{\r
+ VC921x_PPG_TXCH_0 = 0, /* default:green */\r
+ VC921x_PPG_TXCH_1 = 1, /* default: red */\r
+ VC921x_PPG_TXCH_2 = 2, /* fix=ps,or irled */\r
+} VC921x_PPG_TXCH_I; /* 物理发光通道 */\r
+\r
+typedef enum\r
+{\r
+ VC921x_FREQ_PPG = 0, /* high */\r
+ VC921x_FREQ_PS = 1, /* low */\r
+} VC921x_FREQ_SEL;\r
+\r
+typedef enum\r
+{\r
+ VC921x_NO_STORE = 0,\r
+ VC921x_IN_STORE = 1,\r
+} VC921x_STORE_FIFO;\r
+\r
+typedef enum\r
+{\r
+ VC921x_IO_PUSH_PULL = 0,\r
+ VC921x_IO_OPEN_DRAIN = 1,\r
+} VC921x_IO_MODE;\r
+typedef enum\r
+{\r
+ VC921x_IO_DIR_UP_EDGE = 0,\r
+ VC921x_IO_DIR_DOWN_EDGE = 1,\r
+} VC921x_IO_DIR;\r
+\r
+typedef enum\r
+{\r
+ VC921x_IO_PULSE_TIM_100US = 0,\r
+ VC921x_IO_PULSE_TIM_200US = 1,\r
+ VC921x_IO_PULSE_TIM_400US = 2,\r
+ VC921x_IO_PULSE_TIM_800US = 3,\r
+} VC921x_IO_PULSE_TIM;\r
+\r
+typedef enum\r
+{\r
+ VC921x_SAMPLE_TIM_50US = 0,\r
+ VC921x_SAMPLE_TIM_100US = 1,\r
+ VC921x_SAMPLE_TIM_150US = 2,\r
+ VC921x_SAMPLE_TIM_200US = 3,\r
+} VC921x_SAMPLE_TIM;\r
+\r
+typedef enum\r
+{\r
+ VC921x_SLOT_CHSEL_NONE= 0,\r
+ VC921x_SLOT_CHSEL_PD01= 1,\r
+ VC921x_SLOT_CHSEL_PD10= 2,\r
+ VC921x_SLOT_CHSEL_PD11= 3,\r
+}VC921x_SLOT_CHSEL;\r
+\r
+typedef enum\r
+{\r
+ VC921x_BIO_NOFIFO_PS_SGL= 0,\r
+ VC921x_BIO_INFIFO_PS_SGL= 1,\r
+ VC921x_BIO_INFIFO_PPG_SGL= 2,\r
+ VC921x_BIO_INFIFO_PPG_SUM= 3,\r
+}VC921x_BIO_MODE;\r
+\r
+typedef enum\r
+{\r
+ VC921x_BIO_CHSEL_NONE= 0,\r
+ VC921x_BIO_CHSEL_ETP0= 1,\r
+ VC921x_BIO_CHSEL_ETP1= 2,\r
+ VC921x_BIO_CHSEL_PD11= 3,\r
+}VC921x_BIO_CHSEL;\r
+\r
+typedef enum\r
+{\r
+ VC921x_TEMP_SLOT_INN = 0,\r
+ VC921x_TEMP_SLOT_EXT0 = 1,\r
+ VC921x_TEMP_SLOT_EXT1 = 2,\r
+}VC921x_TEMP_SLOT;\r
+\r
+typedef enum\r
+{\r
+ VC921x_ADC_RESOLUTION_16BIT = 0,\r
+ VC921x_ADC_RESOLUTION_18BIT = 1,\r
+ VC921x_ADC_RESOLUTION_20BIT = 2,\r
+ VC921x_ADC_RESOLUTION_22BIT = 3,\r
+}VC921x_ADC_RESOLUTION;\r
+\r
+typedef enum\r
+{\r
+ VC921x_STOP_WORK_CMD = 0,\r
+ VC921x_START_WORK_CMD,\r
+ VC921x_RESET_SOFT_CMD,\r
+ VC921x_WORK_CMD_NUM,\r
+} VC921x_WORK_CMD;\r
+/*============================================================================\r
+ * VC921x_CORE_API\r
+ ===========================================================================*/\r
+/****************************************************************************\r
+ * @description: 获取内核驱动版本信息\r
+ * @param {char} **ppver\r
+ * @return {int} 0(success),-1(read/write/ticks func_pointer error)\r
+ ****************************************************************************/\r
+static inline int core921x_read_software_version(char **ppver)\r
+{\r
+ extern int __core921x_read_software_version(char **ppver);\r
+ return __core921x_read_software_version(ppver);\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 读取ic的ID参数\r
+ * @param {unsigned char} *pid1 版本ID\r
+ * @param {unsigned char} *pid2 扩展ID\r
+ * @return {int} 0(success),-1(read/write error),1(parameter error),2(ic_id error)\r
+ ****************************************************************************/\r
+static inline int core921x_read_id(unsigned char *pid1, unsigned char *pid2)\r
+{\r
+ extern int __core921x_read_id(unsigned char *pid1, unsigned char *pid2);\r
+ return __core921x_read_id(pid1, pid2);\r
+}\r
+\r
+/****************************************************\r
+ * @description: 读取中断事件和过载状态\r
+ * @param {int} *pevt 事件状态\r
+ * @param {unsigned char} *povsta 过载状态\r
+ * @return {int} 0(success),-1(read/write error)\r
+ ****************************************************/\r
+static inline int core921x_read_event_status(unsigned char *pevt, unsigned char *povsta, unsigned char *pwindex_bak, unsigned char *pwindex_rel )\r
+{\r
+ extern int __core921x_read_event_status(unsigned char *pevt, unsigned char *povsta, unsigned char *pwindex_bak, unsigned char *pwindex_rel);\r
+ return __core921x_read_event_status(pevt, povsta, pwindex_bak, pwindex_rel );\r
+}\r
+\r
+/***************************************************************************\r
+ * @description: 读取时钟tick\r
+ * @param {unsigned int} *ptick0\r
+ * @param {unsigned int} *ptick1\r
+ * @return {int} 0(success),-1(read/write error)\r
+ ****************************************************************************/\r
+static inline int core921x_read_rcosc_tick(unsigned short int *ptick0, unsigned short int *ptick1)\r
+{\r
+ extern int __core921x_read_rcosc_tick(unsigned short int *ptick0, unsigned short int *ptick1);\r
+ return __core921x_read_rcosc_tick(ptick0, ptick1);\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 读取基础采样数据\r
+ * @param {result_t} *psample_ret\r
+ * @return {int} 0(success),-1(read/write error)\r
+ ****************************************************************************/\r
+static inline int core921x_read_output(vc921x_sample_info_t *psample_ret)\r
+{\r
+ extern int __core921x_read_output(vc921x_sample_info_t * psample_ret);\r
+ return __core921x_read_output(psample_ret);\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 读取fifo_PPG数据\r
+ * @param {result_t} *psample_ret\r
+ * @param {unsigned char} *pread_fifoaddr\r
+ * @return {int} 0(success),-1(read/write error),1(analysis err)\r
+ ****************************************************************************/\r
+static inline int core921x_read_fifo_data(vc921x_sample_info_t *psample_ret, unsigned char *pread_fifoaddr, unsigned char read_windex)\r
+{\r
+ extern int __core921x_read_fifo_data(vc921x_sample_info_t * psample_ret, unsigned char *pread_fifoaddr, unsigned char read_windex);\r
+ return __core921x_read_fifo_data(psample_ret, pread_fifoaddr, read_windex);\r
+}\r
+\r
+/* 通道相关配置 */\r
+static inline int core921x_set_enable_config(VC921x_PPG_SLOT_I slot_index, VC921x_CFG_FUNC config_enable)\r
+{\r
+ extern int __core921x_set_slot_enable_config(VC921x_PPG_SLOT_I slot_index, VC921x_CFG_FUNC config_enable);\r
+ return __core921x_set_slot_enable_config(slot_index, config_enable);\r
+}\r
+\r
+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 )\r
+{\r
+ 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 );\r
+ return __core921x_set_slot_fix_param_config(slot_index, rxgain, freq_isps, oversample, txslot, sample_tim, slot_infifo );\r
+}\r
+\r
+static inline int core921x_read_slot_adjust_param(unsigned char *pmax_res, unsigned char *pmin_res, unsigned char *pmax_curr, unsigned char *pmin_curr)\r
+{\r
+ extern int __core921x_read_slot_adjust_param(unsigned char *pmax_res, unsigned char *pmin_res, unsigned char *pmax_curr, unsigned char *pmin_curr);\r
+ return __core921x_read_slot_adjust_param(pmax_res, pmin_res, pmax_curr, pmin_curr);\r
+}\r
+static inline int core921x_read_slot_current_res(VC921x_PPG_SLOT_I slot_index, unsigned char *pslot_curr, unsigned char *pslot_reslvl)\r
+{\r
+ extern int __core921x_read_slot_current_res(VC921x_PPG_SLOT_I slot_index, unsigned char *pslot_curr, unsigned char *pslot_reslvl);\r
+ return __core921x_read_slot_current_res(slot_index, pslot_curr, pslot_reslvl);\r
+}\r
+\r
+static inline int core921x_set_ppgslot_current(VC921x_PPG_SLOT_I slot_index, unsigned char current)\r
+{\r
+ extern int __core921x_set_ppgslot_current(VC921x_PPG_SLOT_I slot_index, unsigned char current);\r
+ return __core921x_set_ppgslot_current(slot_index, current);\r
+}\r
+\r
+static inline int core921x_set_ppgslot_resistance(VC921x_PPG_SLOT_I slot_index, unsigned char res_level, unsigned char allow_oversample )\r
+{\r
+ extern int __core921x_set_ppgslot_resistance(VC921x_PPG_SLOT_I slot_index, unsigned char res_level, unsigned char allow_oversample );\r
+ return __core921x_set_ppgslot_resistance(slot_index, res_level, allow_oversample );\r
+}\r
+/*--------------------------------------------------------------*/\r
+extern int __core921x_set_slotx_pd_config( VC921x_SLOT_CHSEL slot0_pd, VC921x_SLOT_CHSEL slot1_pd, VC921x_SLOT_CHSEL slot2_pd );\r
+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 );\r
+extern int __core921x_set_adc_config( VC921x_ADC_RESOLUTION adc_resulution, VC921x_CFG_FUNC ovdata_sum_enable );\r
+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);\r
+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 )\r
+{\r
+ VC921x_CFG_FUNC fifo_enable_cfg = (fifo_enable) ? VC921x_CFG_ENABLE : VC921x_CFG_DISABLE;\r
+ VC921x_CFG_FUNC fifo_format_cfg = (fifo_format) ? VC921x_CFG_ENABLE : VC921x_CFG_DISABLE;\r
+ VC921x_ADC_RESOLUTION adc_resolution_cfg = VC921x_ADC_RESOLUTION_16BIT;\r
+ switch ( adc_resolution )\r
+ {\r
+ case 16:adc_resolution_cfg=VC921x_ADC_RESOLUTION_16BIT; break;\r
+ case 18:adc_resolution_cfg=VC921x_ADC_RESOLUTION_18BIT; break;\r
+ case 20:adc_resolution_cfg=VC921x_ADC_RESOLUTION_20BIT; break;\r
+ case 22:adc_resolution_cfg=VC921x_ADC_RESOLUTION_22BIT; break;\r
+ default:adc_resolution_cfg=VC921x_ADC_RESOLUTION_16BIT; break;\r
+ }\r
+ __core921x_set_slotx_pd_config( slot0_pd, slot1_pd, slot2_pd );\r
+ __core921x_set_anti_slot_config( 0/*0-7*/, VC921x_CFG_DISABLE,VC921x_CFG_DISABLE,VC921x_CFG_DISABLE, VC921x_PPG_TXCH_2 );\r
+ __core921x_set_adc_config( adc_resolution_cfg, VC921x_CFG_DISABLE /* ov_type */ );\r
+ return __core921x_set_common_config(VC921x_CFG_ENABLE, VC921x_CFG_ENABLE, VC921x_CFG_ENABLE/*dis_biofreq_hop*/, fifo_format_cfg, fifo_enable_cfg, 0);\r
+}\r
+/* 频率设置相关API */\r
+/****************************************************************************\r
+ * @description: (ppg=20K/div1,ps=ppg/div2,fifo=ps/div3)\r
+ * @param {unsigned short int} div1\r
+ * @param {unsigned char} div2\r
+ * @param {unsigned char} div3\r
+ * @return {int} 0(success),-1(read/write error)\r
+ ****************************************************************************/\r
+static inline int core921x_set_sample_frequency(unsigned short int div1, unsigned char div2, unsigned char div3)\r
+{\r
+ extern int __core921x_set_sample_frequency(unsigned short int div1, unsigned char div2, unsigned char div3);\r
+ return __core921x_set_sample_frequency(div1 - 1, div2 - 1, div3 - 1);\r
+}\r
+\r
+static inline int core921x_set_threshold_config(unsigned char ppgth_h, unsigned char ppgth_l)\r
+{\r
+ extern int __core921x_set_threshold_config(unsigned char ppgth_h, unsigned char ppgth_l);\r
+ return __core921x_set_threshold_config(ppgth_h, ppgth_l);\r
+}\r
+static inline int core921x_set_interrupt_config(unsigned char evt_en)\r
+{\r
+ 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);\r
+ return __core921x_set_interrupt_config(VC921x_IO_PUSH_PULL, VC921x_IO_DIR_UP_EDGE, VC921x_IO_PULSE_TIM_100US, evt_en);\r
+}\r
+\r
+static inline int core921x_set_bioslot_config(vc921x_sample_info_t *psample_info, unsigned char addcap)\r
+{\r
+ unsigned char bio_time = 6;\r
+ if( VC921x_BIO_INFIFO_PPG_SGL==psample_info->extra_result.biofifo_mode || VC921x_BIO_INFIFO_PPG_SUM==psample_info->extra_result.biofifo_mode )\r
+ {\r
+#if (VC921x_PS_WORK_FREQUENCY_CONFIG==1)\r
+ bio_time = 3; /* (ps=(25/13)hz~520ms,ps_div=13,fifo_div=1) 5200us */\r
+#elif (VC921x_PS_WORK_FREQUENCY_CONFIG==0)\r
+ switch (psample_info->ps_div) /* time = 2^n * 50 * ps_div */\r
+ {\r
+ case 5: /* ppg=25,ps=5 */\r
+ bio_time = 5; /* default 8ms:5-4-3-2-1 , 4ms:4-3-2-1-0 */\r
+ break;\r
+ case 10:\r
+ bio_time = 4;\r
+ break;\r
+ case 20:\r
+ bio_time = 3;\r
+ break;\r
+ case 40:\r
+ bio_time = 2;\r
+ break;\r
+ case 80:\r
+ bio_time = 1;\r
+ break;\r
+ default:\r
+ CORE921x_DEBUG_ERR("fifo time error when underclocking");\r
+ break;\r
+ }\r
+#endif\r
+ }\r
+ 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) ;\r
+ return __core921x_set_bioslot_config((VC921x_CFG_FUNC)psample_info->extra_result.bioinn_enwork,\r
+ (VC921x_CFG_FUNC)psample_info->extra_result.bioext_enwork,\r
+ (VC921x_BIO_MODE)psample_info->extra_result.biofifo_mode,\r
+ VC921x_CFG_BIO_CHANNL_SELECT,\r
+ 2, addcap, bio_time);\r
+}\r
+static inline int core921x_set_bioinn_addcap(vc921x_sample_info_t *psample_info,unsigned char biocap)\r
+{\r
+ extern int __core921x_set_bioinn_addcap(unsigned char biocap);\r
+ return __core921x_set_bioinn_addcap(biocap);\r
+}\r
+\r
+static inline int core921x_set_temperature_config(vc921x_sample_info_t *psample_info)\r
+{\r
+ extern int __core921x_set_temperature_config(VC921x_CFG_FUNC tempslot0_en, VC921x_TEMP_SLOT tempslot0_chsel, unsigned char tempslot0_current, \r
+ VC921x_CFG_FUNC tempslot1_en, VC921x_TEMP_SLOT tempslot1_chsel, unsigned char tempslot1_current );\r
+ return __core921x_set_temperature_config((VC921x_CFG_FUNC)psample_info->extra_result.tempslot0_enwork, VC921x_TEMP_SLOT_INN, psample_info->extra_result.tempslot0_setcur,\r
+ (VC921x_CFG_FUNC)psample_info->extra_result.tempslot1_enwork, VC921x_TEMP_SLOT_EXT1, psample_info->extra_result.tempslot1_setcur );\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 设置RCOSC校准值\r
+ * @param {unsigned char} oscfreq\r
+ * @return {int} 0(success),-1(read/write error)\r
+ ****************************************************************************/\r
+static inline int core921x_set_rcosc_frequency(unsigned char oscfreq)\r
+{\r
+ extern int __core921x_set_rcosc_frequency(unsigned char oscset);\r
+ return __core921x_set_rcosc_frequency(oscfreq);\r
+}\r
+\r
+/****************************************************************************\r
+ * @description:\r
+ * @param {VC921x_WORK_CMD} cmd\r
+ * @return {int} 0(success),-1(read/write error),1(parameter error)\r
+ ****************************************************************************/\r
+static inline int core921x_write_work_cmd(VC921x_WORK_CMD cmd)\r
+{\r
+ extern int __core921x_write_work_cmd(VC921x_WORK_CMD cmd);\r
+ return __core921x_write_work_cmd(cmd);\r
+}\r
+\r
+/*============================================================================\r
+ * IC config ppg/ps slot function\r
+ ===========================================================================*/\r
+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)\r
+{\r
+ /* ppg slot0 config */\r
+ VC921x_CFG_FUNC freq_isps = (1==psample_info->slot_result[slot_index].slot_freq_sel)?VC921x_CFG_ENABLE:VC921x_CFG_DISABLE;\r
+ if (psample_info->slot_result[slot_index].slot_enwork)\r
+ {\r
+ core921x_set_ppgslot_current(slot_index, psample_info->slot_result[slot_index].slot_current);\r
+ core921x_set_ppgslot_resistance(slot_index, psample_info->slot_result[slot_index].slot_resistance, 0 );\r
+ core921x_set_slot_fix_param_config(slot_index, rxgain, freq_isps, oversample, ppg_tx, sampletime, psample_info->slot_result[slot_index].slot_storefifo );\r
+ core921x_set_enable_config(slot_index, VC921x_CFG_ENABLE);\r
+ }\r
+ return 0;\r
+}\r
+/*=====================================================================================================================================*/\r
+extern int core921x_check_nto_version_init(void);\r
+/****************************************************************\r
+ * CORE_API.write()/set()\r
+ * common interface to write/read configuration\r
+ * write or set config registers, debug or other function.\r
+ ***************************************************************/\r
+\r
+extern int vc921x_param_write_flash(unsigned char *pdata, unsigned int size);\r
+extern int vc921x_param_read_flash(unsigned char *pdata, unsigned int size);\r
+\r
+extern void *vc921x_malloc(unsigned int size);\r
+extern void vc921x_free(void *ptr);\r
+\r
+extern int vc921x_read_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size);\r
+extern int vc921x_write_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size);\r
+extern unsigned int vc921x_get_cputimer_tick(void);\r
+\r
+#endif /* __VC921x_CORE_COM_H__ */\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2023-12-21 15:37:20\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+\r
+#ifndef __VC921x_DRIVER_H__\r
+#define __VC921x_DRIVER_H__\r
+\r
+#include "vcare_device_com.h"\r
+/****************************************************************************\r
+ * WearStatus_t\r
+ ***************************************************************************/\r
+#define VC921x_BIO_STA_NONE 0\r
+#define VC921x_BIO_STA_DROP 1\r
+#define VC921x_BIO_STA_HOLD 2\r
+\r
+typedef enum\r
+{\r
+ VC921x_WEAR_NO_CHANGE = 0,\r
+ VC921x_HOLD_TO_DROP,\r
+ VC921x_DROP_TO_HOLD,\r
+} vc921x_wear_change;\r
+\r
+typedef struct\r
+{\r
+ unsigned char hold_cnt;\r
+ unsigned char drop_cnt;\r
+ wear_status wear_status;\r
+ wear_status last_status;\r
+ wear_status algo_wear_status;\r
+ wear_status acce_wear_status;\r
+ int bio_wear_result;\r
+ unsigned short int last_ps_data[2];\r
+\r
+} vc921x_wear_info;\r
+\r
+/****************************************************************************\r
+ * oscclk_t\r
+ ***************************************************************************/\r
+typedef struct\r
+{\r
+ /* calc real frequency */\r
+ unsigned int osc_count[6];\r
+ unsigned int clk_count[6];\r
+ unsigned char count_index;\r
+ unsigned char osc_gap_cnt;\r
+ unsigned short int rcosc_frequency;\r
+ /* check interrupt gaptime */\r
+ unsigned short int last_check_ticks;\r
+ /* startup need get calc value */\r
+ unsigned char rcosc_calibration;\r
+ unsigned char clk_calc_freq_status; /* calculate frequency finished */\r
+ unsigned char clk_calc_status; /* calculate rcsoc status finished */\r
+\r
+} vc921x_clk_info;\r
+\r
+/****************************************************************************\r
+ * adjust_t\r
+ ***************************************************************************/\r
+#define VC921x_ADJUST_DIR_NONE 0\r
+#define VC921x_ADJUST_DIR_UP 1\r
+#define VC921x_ADJUST_DIR_DOWN 2\r
+\r
+typedef struct\r
+{\r
+ unsigned char direction;\r
+ unsigned char direction_last;\r
+ unsigned short int current_step;\r
+} vc921x_adjust_param;\r
+\r
+typedef struct\r
+{\r
+ unsigned char const_max_current; /* ic参数确定的最大电流电阻,固定 */\r
+ unsigned char const_min_current;\r
+ unsigned char const_max_res_level;\r
+ unsigned char const_min_res_level;\r
+ unsigned char max_current; /* ic工作环境的最大电流电阻,可变 */\r
+ unsigned char max_res_level;\r
+ unsigned char current; /* ic当前工作的最大电流电阻,可变 */\r
+ unsigned char res_level;\r
+\r
+ vc921x_adjust_param adj_param;\r
+\r
+} vc921x_adjust_info;\r
+typedef struct\r
+{\r
+ int work_mode;\r
+ unsigned short ppg_div;\r
+ unsigned char ps_div;\r
+ unsigned char fifo_div;\r
+ unsigned char drop_div;\r
+ unsigned char hr_algo_mode;\r
+\r
+ unsigned char int_event;\r
+ unsigned char ov_status;\r
+ unsigned char read_fifo_address;\r
+ unsigned char write_fifo_address_bak; /* write_addr when fifo event */\r
+ unsigned char write_fifo_address_rel; /* write_addr at present */\r
+\r
+ int optimal_bio_gap;\r
+ int optimal_bio_temp;\r
+ unsigned char optimal_cap;\r
+ unsigned char optimal_bio_valid;\r
+ unsigned char ppg_max_thval;\r
+ unsigned char ppg_min_thval;\r
+ \r
+ unsigned char ppg_convert_ps; /* 如果不使用PS频率采集PS,使用PPGir来对佩戴检测进行识别,需要设置为1 */\r
+\r
+ unsigned char param_read_finished_sync;\r
+ unsigned char fifo_read_finished_sync;\r
+ unsigned char fifo_read_data_valid; /* 0-havn't fifo data, 1-normal fifo data, 2-read fifo data when fifo_windex offset */\r
+ unsigned char event_read_finished_sync;\r
+\r
+} vc921x_drv_info;\r
+\r
+typedef struct\r
+{\r
+ work_mode mode;\r
+ int (*mode_init)(void);\r
+ int (*mode_handler)(const void *ops_self, vcare_ppg_device_t *pdev);\r
+} vc921x_mode_ops;\r
+\r
+#endif /* __VC9211x_DRIVER_H__ */\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2023-09-26 15:22:19\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+\r
+#ifndef __VC921x_DRIVER_COM_H__\r
+#define __VC921x_DRIVER_COM_H__\r
+\r
+#include "vcare_device_com.h"\r
+/*********************************************************************************************************\r
+ * DRV_API\r
+ ********************************************************************************************************/\r
+/* 注意:\r
+VC921x - fifo长度最长只有192字节,在多通道时,一次fifo的缓存不能超过192字节\r
+\r
+typical:\r
+ppg_div=800, ps_div=5, fifo_div=5 (ppg-25hz, psbio-5hz, fifo-1hz) 1000ms (921x_max=20*4+4*6=104)\r
+ppg_div=800, ps_div=5, fifo_div=4 (ppg-25hz, psbio-5hz, fifo-1.25hz) 800ms (921x_max=20*4+4*6=104)\r
+ppg_div=400, ps_div=10, fifo_div=2 (ppg-50hz, psbio-5hz, fifo-2.5hz) 400ms (921x_max=20*4+2*6=92)\r
+ppg_div=200, ps_div=20, fifo_div=1 (ppg-100hz,psbio-5hz, fifo-5hz) 200ms (921x_max=20*4+1*6=88)\r
+*/\r
+/****************************************************************************\r
+ * @description: 初始化并且开始进行采样\r
+ * @param {void} *pdevice\r
+ * @param {int} workmode\r
+ * @param {unsigned short int} ppgdiv\r
+ * @param {unsigned char} psdiv\r
+ * @param {unsigned char} fifodiv\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_init_start_work(void *pdevice, int workmode, unsigned short int ppgdiv, unsigned char psdiv, unsigned char fifodiv, unsigned char dropdiv);\r
+/****************************************************************************\r
+ * @description: 获取驱动版本,IC的主ID,次ID\r
+ * @param {char} *\r
+ * @param {unsigned char} *pid1\r
+ * @param {unsigned char} *pid2\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_get_hwsw_infomation(char **str_drv_ver, unsigned char *pid1, unsigned char *pid2);\r
+/****************************************************************************\r
+ * @description: 软复位IC并且退出工作(如需重新工作需要重新调用初始化)\r
+ * @param {void} *device\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_exit_stop_work(void *device);\r
+/****************************************************************************\r
+ * @description: 软复位IC(如需重新工作需要重新调用初始化)\r
+ * @param {void} *device\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_software_reset(void *device);\r
+/****************************************************************************\r
+ * @description: 唤醒工作(可以唤醒调用sleep停止工作)\r
+ * @param {void} *device\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_wakeup_work(void *device);\r
+/****************************************************************************\r
+ * @description: 休眠工作(休眠后可以用wakeup唤醒工作)\r
+ * @param {void} *device\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_sleep_work(void *device);\r
+/****************************************************************************\r
+ * @description: 心率算法扩展的摘下状态设置\r
+ * @param {void} *device\r
+ * @param {int} status\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_set_algo_wear_status(void *device, int status);\r
+/****************************************************************************\r
+ * @description: 运动量判断佩戴的状态设置\r
+ * @param {void} *device\r
+ * @param {int} status\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_set_acce_wear_status(void *device, int status);\r
+/****************************************************************************\r
+ * @description: 获取参数并且进行佩戴状态判断\r
+ * @param {void} *device\r
+ * @return {*}\r
+ ****************************************************************************/\r
+wear_status vc921x_drv_get_wear_status(void *device);\r
+/****************************************************************************\r
+ * @description: 获取具体的佩戴状态各子状态\r
+ * @param {unsigned char} *bio_ret\r
+ * @param {unsigned char} *algo_ret\r
+ * @param {unsigned char} *acce_ret\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_drv_get_wear_detail_result( unsigned char *bio_ret, unsigned char *algo_ret, unsigned char *acce_ret );\r
+/****************************************************************************\r
+ * @description: 获取采样数据,包含PPG,PS,BIO,TMEP\r
+ * @param {void} *device\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_get_result_handler(void *device);\r
+/****************************************************************************\r
+ * @description: 是否为fifo中断事件\r
+ * @param {void} *pdevice\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_is_fifo_event(void *pdevice);\r
+/****************************************************************************\r
+ * @description: 是否为PS中断事件\r
+ * @param {void} *pdevice\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_is_ps_event(void *pdevice);\r
+/****************************************************************************\r
+ * @description: 是否为PPG中断事件\r
+ * @param {void} *pdevice\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_is_ppg_event(void *pdevice);\r
+/****************************************************************************\r
+ * @description: 配平校准活体\r
+ * @param {void} *pdevice\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_clear_reset_bio_param(void *pdevice);\r
+/****************************************************************************\r
+ * @description: 同步驱动状态,清理状态数据\r
+ * @param {void} *pdevice\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_drv_finished_sync(void *pdevice);\r
+/****************************************************************************\r
+ * @description: 提前读取中断信息,避免任务延时响应导致信息被刷掉\r
+ * @param {*}\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_drv_read_event_infomation_byIRQ(void);\r
+/****************************************************************************\r
+ * @description: 软件定时器读取RO信息,用于定时温度检测\r
+ * @param {*}\r
+ * @return {*}\r
+ ****************************************************************************/\r
+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 );\r
+\r
+int vc921x_drv_memroy_alloc(void);\r
+int vc921x_drv_memroy_free(void);\r
+\r
+#endif /* __DRV_DEV_MANAGER_H__ */\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-03-21 11:16:25\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+#ifndef __VC921x_DRIVER_CONFIG_H__\r
+#define __VC921x_DRIVER_CONFIG_H__\r
+\r
+/* wear default status select */\r
+#define VC921x_WEAR_DFT_NONE (0)\r
+#define VC921x_WEAR_DFT_DROP (1)\r
+#define VC921x_WEAR_DFT_HOLD (2)\r
+/* function enable select */\r
+#define VC921x_FUNC_DISABLE (0)\r
+#define VC921x_FUNC_ENABLE (1)\r
+\r
+#define VC921x_FREQUENCY_MAX 20000\r
+#define VC921x_FREQUENCY_MIN 19900\r
+//#define VC921x_CFG_MCU_TICK_FREQUENCY 32000 // counter 32K\r
+extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; /* extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; */\r
+#define VC921x_CFG_MCU_TICK_MAX 0xffffff // 24-bit counters\r
+#define VC921x_CFG_CLK_CALC_DEVIATION 3\r
+#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 )\r
+\r
+#define VC921x_CFG_CLK_CLAC_IRQGAP_EN (VC921x_FUNC_DISABLE)\r
+/* interrupt run check timegap,dont write "(3/4)" !!! */\r
+/* 25hz(40ms~30ms), 50hz(20ms~15ms), 100hz(10ms~7ms) */\r
+#define VC921x_IRQ_GAP_RATIO 3/4\r
+\r
+#define VC921x_CFG_IRQ_BY_TIMER_EN (VC921x_FUNC_DISABLE)\r
+/* notice:ps_freq = ppg_freq/drop_div, and VC921x_PS_WORK_FREQUENCY_CONFIG(0). */\r
+#define VC921x_CFG_DROP_REDUCE_FREQ (VC921x_FUNC_ENABLE) \r
+\r
+#define VC921x_CFG_DEFAULT_PPGGAIN_EN (1) /* 1-最小使用2倍增益, 0-最小使用单倍增益 */\r
+\r
+/****************************************************************************\r
+ * Configuration hardware:PD/BIO channl; sport heartrate param;\r
+ ***************************************************************************/\r
+/* (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*/\r
+#define VC921x_CFG_PPG_CHANNL_SELECT (VC921x_SLOT_CHSEL_PD11)\r
+/* (VC921x_BIO_CHSEL_PD11),setting biochx pd0+pd1, (VC921x_BIO_CHSEL_ETP1),setting extern touch vc921x_core_com.h@VC921x_BIO_CHSEL*/\r
+#define VC921x_CFG_BIO_CHANNL_SELECT (VC921x_BIO_CHSEL_PD11) \r
+#define VC921x_CFG_SPORT_HR_OVERSAMPLE (3) /* oversample = 2^N */\r
+#define VC921x_CFG_SPORT_HR_SAMPLETIME (VC921x_SAMPLE_TIM_200US)\r
+\r
+/****************************************************************************\r
+ * Configuration wear parameters\r
+ ***************************************************************************/\r
+#define VC921x_CFG_WEAR_DETECTION (VC921x_FUNC_ENABLE)\r
+#define VC921x_CFG_WEAR_DEFAULT_STA (VC921x_WEAR_DFT_HOLD)\r
+#define VC921x_CFG_WEAR_BIO_EN (VC921x_FUNC_ENABLE)\r
+#define VC921x_CFG_WEAR_ALG_EN (VC921x_FUNC_DISABLE)\r
+#define VC921x_CFG_WEAR_ACC_EN (VC921x_FUNC_DISABLE)\r
+#define VC921x_CFG_WEAR_HOLD_CNT (1)\r
+#define VC921x_CFG_WEAR_DROP_CNT (3)\r
+/* sensor serial default wear param */\r
+#define VC921x_CFG_WEAR_BIO_OLD_EN (VC921x_FUNC_DISABLE) /* 使用算法相对的方式计算活体的佩戴状态 */\r
+#define VC921x_WEAR_PARAM_ENVMIN 100 /* 80nA/D */\r
+#define VC921x_WEAR_PARAM_ENVMAX 400\r
+#define VC921x_WEAR_PARAM_PSTH 0xA000 /* 16bit:0xA400~40960 , 8bit:0xA0~160 */\r
+#define VC921x_WEAR_PARAM_PS_DELTA 0x3000 /* 16bit:0x3000~12288 , 8bit:0x30~48 */\r
+#define VC921x_WEAR_PARAM_BIO_DELTA 100 /* bio0/1,建议取测试变化量的45%作为参数设置 */\r
+\r
+//#define VC921x_WEAR_PARAM_BIO_ABS_HOLD 200 /* 80% */\r
+//#define VC921x_WEAR_PARAM_BIO_ABS_DROP 160 /* 50% */\r
+extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; */\r
+extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP; */\r
+\r
+/* 约定最后的一个slot一定作为红外采样 */\r
+#define VC921x_WEAR_PARAM_PS_CURRENT 0x25 /*range:0-0x7F */\r
+#define VC921x_WEAR_PARAM_PS_RESISTANCE 6 /*range:0-13 */\r
+#define VC921x_WEAR_PARAM_PS_GAIN 1 /* 2^n */\r
+\r
+#if VC921x_CFG_DEFAULT_PPGGAIN_EN\r
+#define VC921x_PPG_CURT 0x40\r
+#define VC921x_PPG_RESISTANCE 9 /* 9-1 ~ 4.48M */\r
+#define VC921x_PPG_GAIN 1\r
+/* Set the maximum current parameter in FAT1/FAT2 work_mode */\r
+#define VC921x_FAT_GREEN_MAX_CURT 0x60 /* 0-0x7F */\r
+#define VC921x_FAT_RED_MAX_CURT 0x60 /* 0-0x7F */\r
+#define VC921x_FAT_IR_MAX_CURT 0x60 /* 0-0x7F */\r
+#define VC921x_FAT_RESISTANCE 9 /* 9~4.48M, 11~8.96M */\r
+#define VC921x_FAT_GAIN 1\r
+#else\r
+#define VC921x_PPG_CURT 0x40\r
+#define VC921x_PPG_RESISTANCE 11 /* 9-1 ~ 4.48M */\r
+#define VC921x_PPG_GAIN 0\r
+/* Set the maximum current parameter in FAT1/FAT2 work_mode */\r
+#define VC921x_FAT_GREEN_MAX_CURT 0x60 /* 0-0x7F */\r
+#define VC921x_FAT_RED_MAX_CURT 0x60 /* 0-0x7F */\r
+#define VC921x_FAT_IR_MAX_CURT 0x60 /* 0-0x7F */\r
+#define VC921x_FAT_RESISTANCE 11 /* 9~4.48M, 11~8.96M */\r
+#define VC921x_FAT_GAIN 0\r
+#endif\r
+\r
+/****************************************************************************\r
+ * PPG AUTO ADJUST PARAMETERS\r
+ ***************************************************************************/\r
+#define VC921x_PPG_MIN_DEFT_THVAL (0x6)\r
+#define VC921x_PPG_MAX_DEFT_THVAL (0xA) /*0xA~0xB*/\r
+#define VC921x_PPG_SPO2_MIN_DEFT_THVAL (0x09)\r
+#define VC921x_PPG_SPO2_MAX_DEFT_THVAL (0x0A) /* 0x0A~0x0B */\r
+#define VC921x_ADJ_I_INCREASE 22 // 1.4 << 4 = 22.4//1.4f\r
+#define VC921x_ADJ_I_DECREASE 11 // 0.7 << 4 = 11.2//0.7f\r
+#define VC921x_ADJ_I_STEP_MAX 8\r
+#define VC921x_ADJ_I_STEP_MIN 1\r
+#define VC921x_ADJ_I_STEP_DFT 4 // default step\r
+\r
+/* fix 16bit ppg */\r
+#define VC921x_PPG_CONV_BIT4(data) ((data)>>4)\r
+\r
+#endif /* __VC921x_DRIVER_CONFIG_H__ */\r
--- /dev/null
+/*
+ * @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
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-03-21 10:49:02\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+#ifndef __VC921x_SAMPLE_RESULT_H__\r
+#define __VC921x_SAMPLE_RESULT_H__\r
+\r
+/****************************************************************************\r
+drviver vc921x RAM:\r
+core+driver: 400bytes + fifo_data_memory <= 1kb\r
+fifo_data_memory static: 128*2 + 64*(2*2+2*1) = 448 bytes\r
+fifo_data_memory dynamic: 128*x + 64*(2*y+2*z) = 0~448 bytes\r
+fifo_data_memory fixdync:\r
+*/\r
+#define VC921x_USE_STATIC_MEMORY (0) \r
+#define VC921x_USE_FIXDYNC_MEMORY (1) /* memory is allocated when the device is registered and freed when the device is deregistered */\r
+#define VC921x_USE_MEMORY_SELECT (VC921x_USE_STATIC_MEMORY)\r
+#define VC921x_PPGSLOT_BUFFER_NUM (64) /* memory_buffer(40~64) = enable_ppgslot_num * ( VC921x_PPGSLOT_BUFFER_NUM * sizeof(unsigned short int) ) */\r
+#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) ) */\r
+\r
+/* ps sample frequency config, if work_fast,the frequency=12.5hz, otherwise is 5hz \r
+[0] ps= 5hz~200ms, fifo_time=1000ms, 800ms, 600ms, 400ms, 200ms\r
+[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). \r
+ !!!notice: need config bio_param_time @ vc30fx_core_com.h @ core30fx_set_bioslot_config\r
+[2]........\r
+*/\r
+#define VC921x_PS_WORK_FREQUENCY_CONFIG (0)\r
+\r
+/* ppg/ps slot parameter description:\r
+slot_config: structure handle.\r
+enwork: slot configuration enable work, 0-disbale, 1-work_ppg, 2-work_ps.\r
+freqsel: frequency selection, 0-ppg_frequency, 1-ps_frequency. vc921x_core_com.h:enum@VC921x_FREQ_SEL.\r
+storefifo: fifo configuration, 0-nofifo,1-infifo, available when slot_freq_sel is ps_frequency. @VC921x_STORE_FIFO.\r
+current: ppg_slot work current set(0x00~0x7f).\r
+resistance: ppg_slot work resistance set(0~13).\r
+*/\r
+#define VC921x_SLOT_PARAM_CONFIG(slot_config, enwork, freqsel, storefifo, current, resistance) \\r
+ { \\r
+ slot_config.slot_enwork = enwork; \\r
+ slot_config.slot_freq_sel = freqsel; \\r
+ slot_config.slot_storefifo = storefifo; \\r
+ slot_config.slot_current = current; \\r
+ slot_config.slot_resistance = resistance; \\r
+ }\r
+#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)\r
+/*------PS slot default use slot2------*/\r
+#define VC921x_PS_SLOT_PARAM_CONFIG(slot_config, storefifo, current, resistance) VC921x_SLOT_PARAM_CONFIG(slot_config, 2, VC921x_FREQ_PS, storefifo, current, resistance)\r
+/* bio slot parameter description:\r
+bio_config: structure handle.\r
+inn_enable: inside slot configuration enable work, @VC921x_CFG_FUNC.\r
+ext_enable: external slot configuration enable work, @VC921x_CFG_FUNC.\r
+fifo_mode: fifo and ppgmode configuration, @VC921x_BIO_MODE.\r
+*/\r
+#define VC921x_BIO_SLOT_PARAM_CONFIG(bio_config, inn_enable, ext_enable, fifo_mode ) \\r
+ { \\r
+ bio_config.bioinn_enwork = inn_enable; \\r
+ bio_config.bioext_enwork = ext_enable; \\r
+ bio_config.biofifo_mode = fifo_mode; \\r
+ }\r
+/* tmp slot parameter description:\r
+tmp_config: structure handle.\r
+inn_enable: inside slot configuration enable work, @VC921x_CFG_FUNC.\r
+ext_enable: external slot configuration enable work, @VC921x_CFG_FUNC.\r
+setcur: external slot config work current(0~7).\r
+*/\r
+#define VC921x_TMP_SLOT_PARAM_CONFIG(tmp_config, slot0_enable, slot1_enable, setcur) \\r
+ { \\r
+ tmp_config.tempslot0_enwork = slot0_enable; \\r
+ tmp_config.tempslot1_enwork = slot1_enable; \\r
+ tmp_config.tempslot0_setcur = setcur; \\r
+ tmp_config.tempslot1_setcur = setcur; \\r
+ }\r
+\r
+/****************************************************************\r
+ * structures:vc921x_sample_info_t\r
+ ***************************************************************/\r
+typedef struct\r
+{\r
+ /* slot_config */\r
+ unsigned char slot_enwork; /* slot_enwork, 0-disbale, 1-work_ppg, 2-work_ps. */\r
+ unsigned char slot_freq_sel; /* 0-ppg_frequency, 1-ps_frequency. vc921x_core_com.h, @VC921x_FREQ_SEL. */\r
+ unsigned char slot_storefifo; /* 0-nofifo,1-infifo, available when slot_freq_sel is ps_frequency. */\r
+ unsigned char slot_led_sel; /* 0-green led, 1-red led, 2-infrared led */\r
+ /* slot_variable_config */\r
+ unsigned char slot_current; /* 0~0x7F */\r
+ unsigned char slot_resistance; /* 0~13/0~23 */\r
+ /* slot_result */\r
+ unsigned short int env_data;\r
+ union\r
+ {\r
+ unsigned short int ps_data;\r
+ unsigned short int pre_data;\r
+ } u;\r
+ unsigned char ppg_num;\r
+ unsigned char ppg_buffer[VC921x_PPGSLOT_BUFFER_NUM*3]; /* 按字节存储,可以节省最大RAM */\r
+} vc921x_sample_slot_t;\r
+\r
+typedef struct\r
+{\r
+ /* bio_slot config */\r
+ unsigned char bioinn_enwork;\r
+ unsigned char bioext_enwork;\r
+ unsigned char biofifo_mode; /* @VC921x_BIO_MODE */\r
+ /* temp_slot config */\r
+ unsigned char tempslot0_enwork;\r
+ unsigned char tempslot0_setcur;\r
+ unsigned char tempslot1_enwork;\r
+ unsigned char tempslot1_setcur;\r
+ /* extern result */\r
+ unsigned char bio_fifo_num;\r
+ unsigned short int bioinn_data;\r
+ unsigned short int bioext_data;\r
+ unsigned short int bioabs_calc; /* abs(base-ext_now)?thh */\r
+ unsigned short int temp0_data;\r
+ unsigned short int temp1_data;\r
+ unsigned short int tempref_data;\r
+ unsigned short int bioinn_buffer[VC921x_PS2SLOT_BUFFER_NUM];\r
+ unsigned short int bioext_buffer[VC921x_PS2SLOT_BUFFER_NUM];\r
+} vc921x_sample_extra_t;\r
+\r
+typedef struct\r
+{\r
+ unsigned char ic_type_id;\r
+ unsigned char ic_ficv_id;\r
+ unsigned short int ppg_div; /* ppg_frequency = 20K / ppg_div */\r
+ unsigned char ps_div; /* ps_frequency = ppg_frequency / ps_div */\r
+ unsigned char fifo_div; /* fifo_frequency = ps_frequency / fifo_div */\r
+ unsigned char hold_div; /* ps/fifo_frequency = ppg_frequency / hold_div */\r
+ unsigned char drop_div; /* ps/fifo_frequency = ppg_frequency / drop_div */\r
+ unsigned char fifo_enable; /* fifo_enable = 1*/\r
+ unsigned char fifo_format; /* fifo_format,0:16bit, 1:24bit */\r
+ unsigned char adc_resolution; /* */\r
+ unsigned char wear_drop_flag; /* send original data flag as drop event happens */\r
+ vc921x_sample_extra_t extra_result;\r
+ vc921x_sample_slot_t slot_result[3];\r
+} vc921x_sample_info_t;\r
+\r
+static inline unsigned int VC921x_GET_SLOT_SAMPLE_DATA( vc921x_sample_info_t* psample_info, unsigned char slot_index, unsigned char ppg_index )\r
+{\r
+ if( psample_info->fifo_format == 0 )\r
+ {\r
+ 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] );\r
+ }\r
+ else\r
+ {\r
+ 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] );\r
+ }\r
+}\r
+static inline unsigned int VC921x_GET_SLOT_PS_DATA( vc921x_sample_info_t* psample_info, unsigned char ppg_index )\r
+{\r
+ return (psample_info->slot_result[2].ppg_buffer[ppg_index*2]<<8) + (psample_info->slot_result[2].ppg_buffer[ppg_index*2+1] );\r
+}\r
+\r
+#endif /* __VC921x_SAMPLE_RESULT_H__ */\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2023-10-17 09:50:21\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+#ifndef __VC921x_USER_APP_H__\r
+#define __VC921x_USER_APP_H__\r
+\r
+#include "vcare_device_com.h"\r
+\r
+/* vc921x设备函数接口 */\r
+void vc921x_usr_device_init( InitParamTypeDef *pinitconfig );\r
+void vc921x_usr_get_dev_info(unsigned char *pchip_id, unsigned char *pvers_id, char **drv_name, char **dev_name);\r
+void vc921x_usr_start_work(void);\r
+void vc921x_usr_stop_work(void);\r
+void vc921x_usr_soft_reset(void);\r
+void vc921x_usr_reset_bio_param(void);\r
+int vc921x_usr_get_wear_status(void);\r
+void vc921x_usr_get_event_status_byIRQ(void);\r
+void vc921x_usr_device_handler( unsigned char heart_algo_mode, unsigned char spo2_algo_mode );\r
+void vc921x_usr_check_temperature_abnormal(void);\r
+\r
+\r
+void tyhx_poweron(void);\r
+void tyhx_poweroff(void);\r
+\r
+\r
+/* 获取vc921x设备/如果动态内存则会申请驱动内存,以下为获取的设备API,设备对象中会记录一部分计算参数和结果,用户需要直接使用即可,具体参考头文件"vcare_device_com.h":\r
+{\r
+ .dev_init = vc921x_usr_device_init,\r
+ .get_dev_info = vc921x_usr_get_dev_info,\r
+ .start_work = vc921x_usr_start_work,\r
+ .stop_work = vc921x_usr_stop_work,\r
+ .soft_reset = vc921x_usr_soft_reset,\r
+ .get_events = NULL,\r
+ .set_slot_enable = NULL,\r
+ .reset_bio_param = vc921x_usr_reset_bio_param,\r
+ .get_wear_status = vc921x_usr_get_wear_status,\r
+ .dev_irq_handler = vc921x_usr_device_handler,\r
+};\r
+*/\r
+vcare_ppg_device_t *get_vc921x_device(void);\r
+\r
+#endif // !\r
--- /dev/null
+#ifndef VC_SPORT_MOTION_ALGO_H
+#define VC_SPORT_MOTION_ALGO_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+
+void vcSportMotionAlgoInit(void);
+int32_t vcSportMotionCalculate(int32_t x, int32_t y, int32_t z);
+char *sportMotionVersion(void);
+#endif
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-02-23 17:47:18\r
+ * @LastEditTime: 2023-11-14 17:38:46\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+\r
+#ifndef __VCARE_DEVICE_COM_H__\r
+#define __VCARE_DEVICE_COM_H__\r
+\r
+/* parameter type sleep and retain */\r
+#ifndef PARAM_RETAIN\r
+#define PARAM_RETAIN\r
+#endif\r
+/* define NULL 0 */\r
+#ifndef NULL\r
+#define NULL ((void *)0)\r
+#endif\r
+\r
+/* gsensor struct,user peripheral data */\r
+typedef struct\r
+{\r
+ short int xData[40];\r
+ short int yData[40];\r
+ short int zData[40];\r
+} gsensor_axes;\r
+\r
+typedef enum\r
+{\r
+ WEAR_STA_NONE = 0,\r
+ WEAR_STA_DROP,\r
+ WEAR_STA_HOLD,\r
+} wear_status;\r
+\r
+typedef enum\r
+{\r
+ WORK_MODE_HR = 0,\r
+ WORK_MODE_SPO2, \r
+ WORK_MODE_HRV,\r
+ WORK_MODE_STRESS,\r
+ WORK_MODE_BLOODPRESSURE,\r
+ WORK_MODE_WEAR,\r
+ WORK_MODE_TEMPERATURE,\r
+ WORK_MODE_FACTORY0,\r
+ WORK_MODE_FACTORY1,\r
+ WORK_MODE_HRSPO2,\r
+ \r
+ WORK_MODE_UNDEFINED,\r
+ WORK_MODE_NUMBER,\r
+} work_mode;\r
+\r
+typedef struct\r
+{\r
+ unsigned short sampling_gap_time; /* reserved. */\r
+ unsigned char work_mode; /* work_mode,WorkModeTypeDef/unsigned char */\r
+ unsigned char hr_algo_mode;\r
+}InitParamTypeDef;\r
+\r
+\r
+typedef void (*FUNC_DEV_INIT)( InitParamTypeDef *pInitconfig );\r
+typedef void (*FUNC_GET_DEV_INFO)(unsigned char *pchip_id, unsigned char *pvers_id, char **drv_name, char **dev_name);\r
+typedef void (*FUNC_START_WORK)(void);\r
+typedef void (*FUNC_STOP_WORK)(void);\r
+typedef void (*FUNC_SOFT_RESET)(void);\r
+typedef int (*FUNC_GET_EVENTS)(void);\r
+typedef int (*FUNC_GET_WEAR_STATUS)(void);\r
+typedef void (*FUNC_SET_SLOT_ENABLE)(unsigned char slot_index, unsigned char slot_enable);\r
+typedef void (*FUNC_BIO_RESET_PARAM)(void);\r
+typedef void (*FUNC_DEV_IRQ_HANDLER)(unsigned char heart_algo_mode, unsigned char spo2_algo_mode);\r
+typedef void (*FUNC_DEV_CHK_TEMP_ERR)(void);\r
+\r
+typedef struct\r
+{\r
+ FUNC_DEV_INIT dev_init;\r
+ FUNC_GET_DEV_INFO get_dev_info; /* reserved */\r
+ FUNC_START_WORK start_work;\r
+ FUNC_STOP_WORK stop_work;\r
+ FUNC_SOFT_RESET soft_reset;\r
+ FUNC_GET_EVENTS get_events; /* reserved */\r
+ FUNC_GET_WEAR_STATUS get_wear_status;\r
+ FUNC_SET_SLOT_ENABLE set_slot_enable; /* reserved */\r
+ FUNC_BIO_RESET_PARAM reset_bio_param;\r
+ FUNC_DEV_IRQ_HANDLER dev_irq_handler;\r
+ FUNC_DEV_CHK_TEMP_ERR dev_check_temp_error;\r
+} dev_ops;\r
+\r
+typedef struct\r
+{\r
+ char *dev_name;\r
+ unsigned char id1;\r
+ unsigned char id2;\r
+ unsigned char dev_work_status; /* 0-don't work, 1-working */\r
+\r
+ unsigned char heart_algo_mode;\r
+ unsigned char spo2_algo_mode;\r
+ work_mode workmode;\r
+ wear_status wear;\r
+ /* raw result */\r
+ void *result;\r
+ /* device ops */\r
+ const dev_ops *ops;\r
+ /* calc result */\r
+ int heart_rate;\r
+ int spo2;\r
+ int hrv;\r
+ int stress;\r
+ int ecg;\r
+ int temperature0;\r
+ int temperature1;\r
+ int blood_pressure;\r
+} vcare_ppg_device_t;\r
+\r
+/**-------------------- defined functions --------------------**/\r
+#define ENABLE_MY_MEMFUNC 1\r
+#if ENABLE_MY_MEMFUNC\r
+static inline void *vcare_memset(void *dest, int set, unsigned int n)\r
+{\r
+ if (dest == NULL || n <= 0)\r
+ {\r
+ return NULL;\r
+ }\r
+ char *pdest = (char *)dest;\r
+ while (n-- > 0)\r
+ {\r
+ *pdest++ = set;\r
+ }\r
+ return dest;\r
+}\r
+\r
+static inline void *vcare_memcpy(void *dest, void *src, unsigned int n)\r
+{\r
+ if (dest == NULL || src == NULL)\r
+ {\r
+ return NULL;\r
+ }\r
+ char *pdest = (char *)dest;\r
+ char *psrc = (char *)src;\r
+ while (n--)\r
+ {\r
+ *pdest++ = *psrc++;\r
+ }\r
+ return dest;\r
+}\r
+\r
+/* 2^(n/16) */\r
+static const float exponent_tab[]={1.000000,1.044274,1.090508,1.138789,1.189207,1.241858,1.296840,1.354256,1.414214,\r
+ 1.476826,1.542211,1.610490,1.681793,1.756252,1.834008,1.915207,2.000000};\r
+static inline float vcare_I_exponent_func( float base_i, unsigned char data_i )\r
+{\r
+ unsigned char data_h = (data_i>>4)&0xf;\r
+ unsigned char data_l = (data_i>>0)&0xf;\r
+ return (base_i*(1<<data_h)*exponent_tab[data_l]);\r
+}\r
+static inline float vcare_R_exponent_func( float base_r, unsigned char data_r )\r
+{\r
+ unsigned char data_h = data_r/2;\r
+ unsigned char data_l = data_r%2;\r
+ float data_l_value = (data_l)?(exponent_tab[8]):(1.0f);\r
+ return (base_r*(1<<data_h)*data_l_value);\r
+}\r
+\r
+\r
+#endif\r
+\r
+/**-------------------- debug functions --------------------**/\r
+extern void log_direct(unsigned int info, const char *fmt, ...);\r
+#define VCARE_DBG_LEVEL 0\r
+\r
+#if (VCARE_DBG_LEVEL == 0)\r
+#define VCARE_DBG_LOG(fmt, ...)\r
+#define VCARE_DBG_ERR(fmt, ...)\r
+#elif (VCARE_DBG_LEVEL == 1)\r
+#define VCARE_DBG_LOG(fmt, ...)\r
+#define VCARE_DBG_ERR(fmt, ...) \\r
+ do \\r
+ { \\r
+ log_direct((33 << 24), "[VCARE_ERR](%d)" fmt, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+#elif (VCARE_DBG_LEVEL == 2)\r
+#define VCARE_DBG_LOG(fmt, ...) \\r
+ do \\r
+ { \\r
+ log_direct((33 << 24), "[VCARE_LOG](%d)" fmt, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+#define VCARE_DBG_ERR(fmt, ...) \\r
+ do \\r
+ { \\r
+ log_direct((33 << 24), "[VCARE_ERR](%d)" fmt, __LINE__, ##__VA_ARGS__); \\r
+ } while (0)\r
+#endif\r
+\r
+/*\r
+extern int p_debuglog_user(const char *fmt, ...);\r
+#define VCARE_DBG_LOG(fmt, ...) do{ if(p_debuglog_user)p_debuglog_user("[VCARE_LOG]%s(%d)"fmt, __func__, __LINE__, ##__VA_ARGS__); }while(0)\r
+#define VCARE_DBG_ERR(fmt, ...) do{ if(p_debuglog_user)p_debuglog_user("[VCARE_ERR]%s(%d)"fmt, __func__, __LINE__, ##__VA_ARGS__); }while(0)\r
+*/\r
+\r
+#endif\r
--- /dev/null
+C:\Users\zwj\Documents\WXWork\1688852039096625\WeDrive\维客昕微\技术支持组和应用方案开发组公共文件\1.心率IC\1.心率+血氧资料\2.驱动文件\VCHR9202\drv_9202_sensor_v218\algo
\ No newline at end of file
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-03-21 14:38:58\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+\r
+#include "vc921x_core.h"\r
+#include "vc921x_core_com.h"\r
+\r
+#define CORE921x_FORMAT_ADCBIT_COMPARE(format_n,bit_n) ( ((format_n)>(bit_n))?((format_n)-(bit_n)):0)\r
+#define CORE921x_DATA_FORMAT_COVNVERT(format_n,bit_n,data) ( (data)>>( CORE921x_FORMAT_ADCBIT_COMPARE( format_n, bit_n ) ) )\r
+\r
+static const char CORE921x_VERSION[] = "core921x_v0.22";\r
+\r
+/* rxgain+pdres ~ level */\r
+struct vc921x_core_res_table\r
+{\r
+ unsigned char level;\r
+ unsigned char pdres;\r
+ unsigned char rxgain;\r
+};\r
+#if VC921x_CFG_DEFAULT_PPGGAIN_EN\r
+#define MAX_RES_LEVEL 21\r
+#define MIN_RES_LEVEL 0\r
+#define MAX_CURRENT 0x7f\r
+#define MIN_CURRENT 0\r
+const struct vc921x_core_res_table vc921x_res_table[] =\r
+ {\r
+ /* level, pdres, rxgain */\r
+ {0, 0, 1}, /* 200K */\r
+ {1, 1, 1},\r
+ {2, 2, 1}, /* 400K */\r
+ {3, 3, 1}, \r
+ {4, 4, 1}, /* 800K */\r
+ {5, 5, 1},\r
+ {6, 6, 1}, /* 1.6M */\r
+ {7, 7, 1},\r
+ {8, 8, 1},/* 3.2M */\r
+ {9, 9, 1},\r
+ {10, 10, 1}, /* 6.4M */\r
+ {11, 11, 1}, /*8.96M*/\r
+ {12, 12, 1}, \r
+ {13, 13, 1}, /*17.92*/\r
+ {14, 12, 2}, \r
+ {15, 13, 2},/*35.84*/\r
+ {16, 12, 3},\r
+ {17, 13, 3},/*71.68*/\r
+ {18, 12, 4},\r
+ {19, 13, 4}, /* 143.36 */\r
+ {20, 12, 5},\r
+ {21, 13, 5}, /* 286.72 */\r
+};\r
+#else\r
+#define MAX_RES_LEVEL 23\r
+#define MIN_RES_LEVEL 0\r
+#define MAX_CURRENT 0x7f\r
+#define MIN_CURRENT 0\r
+const struct vc921x_core_res_table vc921x_res_table[] =\r
+ {\r
+ /* level, pdres, rxgain */\r
+ {0, 0, 0}, /* 100K */\r
+ {1, 1, 0},\r
+ {2, 2, 0}, /* 200K */\r
+ {3, 3, 0},\r
+ {4, 4, 0}, /* 400K */\r
+ {5, 5, 0}, \r
+ {6, 6, 0}, /* 800K */\r
+ {7, 7, 0},\r
+ {8, 8, 0}, /* 1.6M */\r
+ {9, 9, 0},\r
+ {10, 10, 0},/* 3.2M */\r
+ {11, 11, 0},\r
+ {12, 12, 0}, /* 6.4M */\r
+ {13, 13, 0}, /*8.96M*/\r
+ {14, 12, 1}, \r
+ {15, 13, 1}, /*17.92*/\r
+ {16, 12, 2}, \r
+ {17, 13, 2},/*35.84*/\r
+ {18, 12, 3},\r
+ {19, 13, 3},/*71.68*/\r
+ {20, 12, 4},\r
+ {21, 13, 4}, /* 143.36 */\r
+ {22, 12, 5},\r
+ {23, 13, 5}, /* 286.72 */\r
+};\r
+#endif\r
+\r
+static unsigned char core921x_nto_version=0; /* 0127nto or(0808-1120mpw) */\r
+static unsigned char core921x_0808mpw=0; /* 0808mpw ~ 1120mpw */\r
+/* 需要在刚刚初始化完成之后去调用判断 */\r
+CORE921x_FUNC_RAM_SECTION int core921x_check_nto_version_init(void)\r
+{\r
+ unsigned char mpw0808_test=0xA0;\r
+ unsigned char read_buffer[4]={0};\r
+ unsigned short count1=0, count2=0;\r
+ unsigned int delay_tick=1000;\r
+ vc921x_write_register(0x5C, &mpw0808_test, 1);\r
+ mpw0808_test=0;\r
+ vc921x_read_register(0x5C, &mpw0808_test, 1);\r
+ if( mpw0808_test==0xA0 )\r
+ {\r
+ core921x_0808mpw=0;\r
+ mpw0808_test=0;\r
+ vc921x_write_register(0x5C, &mpw0808_test, 1); /* write 0, clear DEBUG register. */\r
+ }\r
+ else\r
+ {\r
+ core921x_0808mpw=1;\r
+ }\r
+ /* 0127nto ~ 0808_1120mpw */\r
+ vc921x_read_register( 0x05, &read_buffer[0], 2 );\r
+ while(delay_tick--);\r
+ vc921x_read_register( 0x07, &read_buffer[2], 2 );\r
+ count1 = (read_buffer[0]<<8)+read_buffer[1];\r
+ count2 = (read_buffer[2]<<8)+read_buffer[3];\r
+ if( count2-count1>=1 && count2-count1<=255 )\r
+ {\r
+ core921x_nto_version=0;\r
+ }\r
+ else\r
+ {\r
+ core921x_nto_version=1;\r
+ }\r
+ CORE921x_DEBUG_LOG("0127nto=%d~0808mpw=%d", core921x_nto_version,core921x_0808mpw);\r
+ return core921x_nto_version;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION static unsigned char get_level_by_res_rxgain(unsigned char pdres, unsigned char rxgain)\r
+{\r
+ unsigned char index = 0;\r
+ for (index = 0; index < sizeof(vc921x_res_table) / sizeof(vc921x_res_table[0]); index++)\r
+ {\r
+ if ((vc921x_res_table[index].pdres == pdres) && (vc921x_res_table[index].rxgain == rxgain))\r
+ {\r
+ return vc921x_res_table[index].level;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+CORE921x_FUNC_RAM_SECTION static int get_res_rxgain_by_level(unsigned char level, unsigned char *ppdres, unsigned char *prxgain)\r
+{\r
+ *ppdres = vc921x_res_table[level].pdres;\r
+ *prxgain = vc921x_res_table[level].rxgain;\r
+ return 0;\r
+}\r
+\r
+/****************************************************************\r
+ * CORE_API.read()\r
+ * read IC event or sample data\r
+ ***************************************************************/\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_software_version(char **ppver) //\r
+{\r
+ if (ppver)\r
+ {\r
+ *ppver = (char *)CORE921x_VERSION;\r
+ return 0;\r
+ }\r
+ return -1;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_id(unsigned char *pid1, unsigned char *pid2) //\r
+{\r
+ int ret = 0;\r
+ if ((NULL == pid1) || (NULL == pid2))\r
+ {\r
+ return 1;\r
+ }\r
+ ret = vc921x_read_register(CORE921x_DEV_VER_ID_H_ADDR, pid1, 1);\r
+ ret = vc921x_read_register(CORE921x_FDY_EXT_ID_L_ADDR, pid2, 1);\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_event_status(unsigned char *pevt, unsigned char *povsta, unsigned char *pwindex_bak, unsigned char *pwindex_rel ) //\r
+{\r
+ int ret = 0;\r
+ unsigned char reg[4] = {0};\r
+ ret = vc921x_read_register(CORE921x_WORK_STATUS1_ADDR, reg, 4);\r
+ if (pevt)\r
+ {\r
+ *pevt = reg[0];\r
+ }\r
+ if (povsta)\r
+ {\r
+ *povsta = reg[1];\r
+ }\r
+ if( core921x_nto_version )\r
+ {\r
+ if (pwindex_bak)\r
+ {\r
+ *pwindex_bak = reg[2];\r
+ }\r
+ if (pwindex_rel)\r
+ {\r
+ *pwindex_rel = reg[3];\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (pwindex_bak)\r
+ {\r
+ *pwindex_bak = reg[2];\r
+ }\r
+ } \r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_rcosc_tick(unsigned short int *ptick0, unsigned short int *ptick1) //\r
+{\r
+ int ret = 0;\r
+ unsigned char reg[4] = {0};\r
+ if( core921x_nto_version==1 )\r
+ {\r
+ ret = vc921x_read_register(CORE921x_OSC_CNT0_H_ADDR+1, reg, 4);\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_read_register(CORE921x_OSC_CNT0_H_ADDR, reg, 4);\r
+ }\r
+ if (ptick0)\r
+ {\r
+ *ptick0 = (reg[0] << 8) + reg[1];\r
+ }\r
+ if (ptick1)\r
+ {\r
+ *ptick1 = (reg[2] << 8) + reg[3];\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_output(vc921x_sample_info_t *psample_ret)\r
+{\r
+ int ret = 0;\r
+ core921x_reg_result_t reg_result = {0};\r
+ if( core921x_nto_version==1 )\r
+ {\r
+ ret = vc921x_read_register(CORE921x_SAMPLE_DATA_ADDR_BASE+1, (unsigned char *)®_result, sizeof(core921x_reg_result_t));\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_read_register(CORE921x_SAMPLE_DATA_ADDR_BASE, (unsigned char *)®_result, sizeof(core921x_reg_result_t));\r
+ }\r
+ \r
+ if (psample_ret)\r
+ {\r
+ psample_ret->slot_result[0].env_data = (reg_result.slot0_envh6 << 8) | reg_result.slot0_envl6;\r
+ psample_ret->slot_result[1].env_data = (reg_result.slot1_envh6 << 8) | reg_result.slot1_envl6;\r
+ psample_ret->slot_result[2].env_data = (reg_result.slot2_envh6 << 8) | reg_result.slot2_envl6;\r
+\r
+ psample_ret->slot_result[0].u.ps_data = reg_result.slot0_ps;\r
+ psample_ret->slot_result[1].u.ps_data = reg_result.slot1_ps;\r
+ psample_ret->slot_result[2].u.ps_data = reg_result.slot2_ps;\r
+ \r
+ psample_ret->extra_result.bioinn_data = (reg_result.bioinn_valh << 8) | reg_result.bioinn_vall;\r
+ psample_ret->extra_result.bioext_data = (reg_result.bioext_valh << 8) | reg_result.bioext_vall;\r
+ psample_ret->extra_result.temp0_data = (reg_result.tempslot0_valh << 8) | reg_result.tempslot0_vall;\r
+ psample_ret->extra_result.temp1_data = (reg_result.tempslot1_valh << 8) | reg_result.tempslot1_vall;\r
+ psample_ret->extra_result.tempref_data = (reg_result.tempref_valh << 8) | reg_result.tempref_vall;\r
+ }\r
+ return ret;\r
+}\r
+\r
+/*-------------------------------------------------------------------------------------------------------------------------------------\r
+fifo 解析数据相关的函数功能模块\r
+-------------------------------------------------------------------------------------------------------------------------------------*/\r
+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)\r
+{\r
+ /* 1 ppg slot infomation */\r
+ for( unsigned char i=0; i<3; i++ )\r
+ {\r
+ if( psample_ret->slot_result[i].slot_enwork==1 && psample_ret->slot_result[i].slot_freq_sel==VC921x_FREQ_PPG )\r
+ {\r
+ (*p_ppgfreq_slotnum)++; \r
+ }\r
+ 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 )\r
+ {\r
+ (*p_psfreq_slotnum)++;\r
+ }\r
+ }\r
+\r
+ /* 3 bio slot infomation */\r
+ 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))\r
+ {\r
+ if (psample_ret->extra_result.bioext_enwork == 1)\r
+ {\r
+ (*p_psfreq_slotnum)++;\r
+ }\r
+ if (psample_ret->extra_result.bioinn_enwork == 1)\r
+ {\r
+ (*p_psfreq_slotnum)++;\r
+ }\r
+ }\r
+ 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))\r
+ {\r
+ if (psample_ret->extra_result.bioext_enwork == 1)\r
+ {\r
+ (*p_bioppgfreq_slotnum)++;\r
+ }\r
+ if (psample_ret->extra_result.bioinn_enwork == 1)\r
+ {\r
+ (*p_bioppgfreq_slotnum)++;\r
+ }\r
+ }\r
+ CORE921x_DEBUG_LOG("slotnum_ppgfreq[%d],slotnum_psfreq[%d], slotnum_bioppg[%d]", *p_ppgfreq_slotnum, *p_psfreq_slotnum, *p_bioppgfreq_slotnum);\r
+ return 0;\r
+}\r
+\r
+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 )\r
+{\r
+ int data = 0;\r
+ if( fifo_format_is24bit )\r
+ {\r
+ if( (*poffset)+2 >=192 ) return 0;\r
+ data = (pbuffer[(*poffset)]<<16) + (pbuffer[(*poffset)+1]<<8) + pbuffer[(*poffset)+2];\r
+ data = CORE921x_DATA_FORMAT_COVNVERT( 24, adc_resolution, data );\r
+ *poffset += 3;\r
+ }\r
+ else\r
+ {\r
+ if( (*poffset)+1 >=192 ) return 0;\r
+ data = (pbuffer[(*poffset)] << 8) + pbuffer[(*poffset) + 1];\r
+ data = CORE921x_DATA_FORMAT_COVNVERT( 16, adc_resolution, data );\r
+ *poffset += 2;\r
+ }\r
+ return data;\r
+}\r
+\r
+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 )\r
+{\r
+ if( fifo_format_is24bit )\r
+ {\r
+ if( offset*3+2>=VC921x_PPGSLOT_BUFFER_NUM*3 ) return -1;\r
+ pbuffer[offset*3+0]=(ppg_data>>16)&0xff;\r
+ pbuffer[offset*3+1]=(ppg_data>>8) &0xff;\r
+ pbuffer[offset*3+2]=(ppg_data>>0) &0xff;\r
+ }\r
+ else\r
+ {\r
+ if( offset*2+1>=VC921x_PPGSLOT_BUFFER_NUM*3 ) return -1;\r
+ pbuffer[offset*2+0]=(ppg_data>>8) &0xff;\r
+ pbuffer[offset*2+1]=(ppg_data>>0) &0xff;\r
+ }\r
+ return 0;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_fifo_data(vc921x_sample_info_t *psample_ret, unsigned char *pread_fifoaddr, unsigned char read_windex) //\r
+{\r
+ int ret = 0;\r
+ unsigned char i = 0, j = 0;\r
+ unsigned char rindex = *pread_fifoaddr;\r
+ unsigned char read_size = 0, wait_size = 0;;\r
+ unsigned char fifo_data[192] = {0};\r
+ /* fifo有效通道数量 */\r
+ unsigned char ppg_freq_slot_num = 0; /* ppg频率下ppg_slot的数量*/\r
+ unsigned char ps_freq_slot_num = 0; /* ps频率下psbio_slot的数量*/\r
+ unsigned char bio_ppgfreq_slot_num = 0; /* ppg频率下bio_slot的数量 */\r
+ unsigned char ppg_ps_fifo_ratio = 0; /* ppg频率与ps频率的占比,用于计算有效ps频率的fifo数据位置 */\r
+\r
+ unsigned char fifo_bytes= 0; /* fifo_bytes= group_len*fifo_div */\r
+ unsigned char group_len = 0; /* ppg0(slot1,2) ppg1(slot1,2) ps(1,2) */\r
+ unsigned char group_num = 0; /* group_len * group_num = fifosize */\r
+ /* array(ppg_freq+ps_freq) */\r
+ unsigned char ppg_freq_array_len = 0;\r
+ unsigned char ps_freq_array_len = 0;\r
+ unsigned char array_offset = 0; /* group 组内偏移 */\r
+ unsigned char slot_index = 0;\r
+ /* 当bio模式为VC921x_BIO_INFIFO_PPG_SGL,需要驱动进行加算 */\r
+ unsigned short int bioext_ppgsgl_sum=0,bioinn_ppgsgl_sum=0;\r
+ /* 解析临时缓存ppg数据 */\r
+ unsigned int analysis_ppg_data=0;\r
+ /************* 1.获取配置参数 *************/\r
+ if (!psample_ret)\r
+ return 1;\r
+ ppg_ps_fifo_ratio = psample_ret->ps_div; /* 假设25/10=2.5hz,ppg频率中间隔10个,插入一个ps */\r
+ fifo_calc_sample_slot_nums(psample_ret, &ppg_freq_slot_num, &ps_freq_slot_num, &bio_ppgfreq_slot_num); /* 获取各个fifo信息 */\r
+ /* calc ppgfreq_fifodata/psfreq_fifodata array length, group length=ppg*ratio+ps */\r
+ if( 1==psample_ret->fifo_format )\r
+ {\r
+ ppg_freq_array_len += (ppg_freq_slot_num*3);\r
+ }\r
+ else\r
+ {\r
+ ppg_freq_array_len += (ppg_freq_slot_num*2);\r
+ }\r
+ ppg_freq_array_len+= (bio_ppgfreq_slot_num*2);\r
+ ps_freq_array_len += (ps_freq_slot_num * 2);\r
+ group_len = ppg_freq_array_len * ppg_ps_fifo_ratio + ps_freq_array_len;\r
+ fifo_bytes= group_len*psample_ret->fifo_div;\r
+ CORE921x_DEBUG_LOG("group_len(%d)=(%d*%d)+%d", group_len, ppg_freq_array_len, ppg_ps_fifo_ratio, ps_freq_array_len);\r
+ if(group_len==0||fifo_bytes==0)\r
+ {\r
+ return -1;\r
+ }\r
+ /************** 2.校验参数读取 *************/\r
+ /* group=[ ppg0(slot0,slot1)+ppg1(slot0,slot1)+...ppgN(slot0,slot1)+ps(ps,bioinn,bioext) ]\r
+ fifo =[ group0,group1... ]n */\r
+ if (0 == psample_ret->fifo_enable)\r
+ {\r
+ CORE921x_DEBUG_LOG("psample_ret->fifo_enable=%d", psample_ret->fifo_enable);\r
+ rindex = 0x00; /*disable fifo:fifo=ps频率,数据始于,0x00 */\r
+ }\r
+ if (read_windex == rindex) /* 数据溢出或则无数据 */\r
+ {\r
+ return -2;\r
+ }\r
+ if (read_windex > rindex) /* rindex-windex */\r
+ {\r
+ wait_size = (read_windex - rindex);\r
+ }\r
+ else /* [rindex-192]+[0-windex] */\r
+ {\r
+ wait_size = 192 - rindex + read_windex;\r
+ }\r
+ if( wait_size < fifo_bytes )\r
+ {\r
+ CORE921x_DEBUG_ERR("[%x~%x]waite_size=%d, fifo_bytes=%d", rindex, read_windex, wait_size, fifo_bytes );\r
+ return -3;\r
+ }\r
+ /* windex error process, the windex cover all fifo area and more than the rindex. */\r
+ if (wait_size % fifo_bytes)\r
+ {\r
+ read_size = (wait_size/fifo_bytes)*fifo_bytes;\r
+ CORE921x_DEBUG_ERR("read_fifo_bytes(%d)/group_len(%d) != 0 read_size[%d]", wait_size, fifo_bytes, read_size );\r
+ ret=1;\r
+ if( core921x_nto_version )\r
+ {\r
+ return ret;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ read_size=wait_size;\r
+ }\r
+ *pread_fifoaddr = ((rindex + read_size) >= 192) ? (rindex + read_size - 192) : (rindex + read_size);\r
+ ret = vc921x_write_register(CORE921x_FIFO_READADDR_INDEX, &rindex, 1);\r
+ ret = vc921x_read_register(CORE921x_FIFO_DATA_ADDR, &fifo_data[0], read_size);\r
+\r
+ CORE921x_DEBUG_LOG("[%#x]-[%#x],fifo_bytes=%d,", rindex, read_windex, read_size);\r
+ 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]);\r
+ 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]);\r
+ 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]);\r
+ /******** 3.group,array,cell analysis ********/\r
+ if(group_len==0)\r
+ {\r
+ return 3;\r
+ }\r
+ group_num = read_size / group_len;\r
+ for (i = 0; i < group_num; i++) /* i=0~N,每次所有通道的采样PPG群数,每个群的处理 */\r
+ {\r
+ array_offset = i * group_len;\r
+ bioinn_ppgsgl_sum=0,bioext_ppgsgl_sum=0;\r
+ /* ppg_freq array analysis*/\r
+ for (j = 0; j < ppg_ps_fifo_ratio; j++) /* j=0-n,每个群里面拥有的ppg_freq的组数轮询 */\r
+ {\r
+ for (slot_index = 0; slot_index < 3; slot_index++)\r
+ {\r
+ if (1 == psample_ret->slot_result[slot_index].slot_enwork && VC921x_FREQ_PPG == psample_ret->slot_result[slot_index].slot_freq_sel)\r
+ {\r
+ psample_ret->slot_result[slot_index].ppg_num += 1;\r
+ analysis_ppg_data = read_data_from_fifo_buffer(fifo_data, &array_offset, psample_ret->fifo_format, psample_ret->adc_resolution );\r
+ 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 );\r
+ CORE921x_DEBUG_LOG("slot_result[%d].ppg_data[%d]=%d", slot_index, i*ppg_ps_fifo_ratio+j, analysis_ppg_data );\r
+ }\r
+ }\r
+ if( bio_ppgfreq_slot_num && VC921x_BIO_INFIFO_PPG_SGL==psample_ret->extra_result.biofifo_mode ) /* VC921x_BIO_INFIFO_PPG_SGL */\r
+ {\r
+ if (1 == psample_ret->extra_result.bioinn_enwork) bioinn_ppgsgl_sum+=read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ if (1 == psample_ret->extra_result.bioext_enwork) bioext_ppgsgl_sum+=read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ }\r
+ }\r
+ if( bio_ppgfreq_slot_num && VC921x_BIO_INFIFO_PPG_SGL==psample_ret->extra_result.biofifo_mode )\r
+ {\r
+ psample_ret->extra_result.bio_fifo_num += 1;\r
+ if (1 == psample_ret->extra_result.bioinn_enwork)\r
+ {\r
+ psample_ret->extra_result.bioinn_buffer[i] = bioinn_ppgsgl_sum;\r
+ CORE921x_DEBUG_LOG("result.bioinn_buffer[%d]=%d", i, psample_ret->extra_result.bioinn_buffer[i]);\r
+ }\r
+ if (1 == psample_ret->extra_result.bioext_enwork)\r
+ {\r
+ psample_ret->extra_result.bioext_buffer[i] = bioext_ppgsgl_sum;\r
+ CORE921x_DEBUG_LOG("result.bioext_buffer[%d]=%d", i, psample_ret->extra_result.bioext_buffer[i]);\r
+ }\r
+ }\r
+ /* ps_freq array analysis */\r
+ // CORE921x_DEBUG_LOG("PS_ARRAY_OFFSET=(%d)?(%d)", ppg_freq_array_len * ppg_ps_fifo_ratio, array_offset);\r
+ /* 数据交换处理 */\r
+ if ( VC921x_BIO_INFIFO_PS_SGL==psample_ret->extra_result.biofifo_mode )\r
+ {\r
+ if (2 == psample_ret->slot_result[2].slot_enwork && VC921x_IN_STORE == psample_ret->slot_result[2].slot_storefifo)\r
+ {\r
+ psample_ret->slot_result[2].ppg_num += 1;\r
+ analysis_ppg_data = read_data_from_fifo_buffer( fifo_data, &array_offset, 0, 16 );\r
+ write_data_to_fifo_buffer( psample_ret->slot_result[2].ppg_buffer, psample_ret->slot_result[2].ppg_num-1, analysis_ppg_data, 0 );\r
+ CORE921x_DEBUG_LOG("slot_result[2].ps_data[%d]=%d", i, analysis_ppg_data);\r
+ }\r
+ if ( 1 == psample_ret->extra_result.bioinn_enwork || 1 == psample_ret->extra_result.bioext_enwork)\r
+ {\r
+ psample_ret->extra_result.bio_fifo_num += 1;\r
+ if (1 == psample_ret->extra_result.bioinn_enwork)\r
+ {\r
+ psample_ret->extra_result.bioinn_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ CORE921x_DEBUG_LOG("result.bioinn_buffer[%d]=%d", i, psample_ret->extra_result.bioinn_buffer[i]);\r
+ }\r
+ if (1 == psample_ret->extra_result.bioext_enwork)\r
+ {\r
+ psample_ret->extra_result.bioext_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ CORE921x_DEBUG_LOG("result.bioext_buffer[%d]=%d", i, psample_ret->extra_result.bioext_buffer[i]);\r
+ }\r
+ }\r
+ }\r
+ else if(VC921x_BIO_INFIFO_PPG_SUM == psample_ret->extra_result.biofifo_mode)\r
+ {\r
+ if ( 1==psample_ret->extra_result.bioinn_enwork||1==psample_ret->extra_result.bioext_enwork )\r
+ {\r
+ psample_ret->extra_result.bio_fifo_num += 1;\r
+ if (1 == psample_ret->extra_result.bioinn_enwork)\r
+ {\r
+ psample_ret->extra_result.bioinn_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ CORE921x_DEBUG_LOG("result.bioinn_buffer[%d]=%d", i, psample_ret->extra_result.bioinn_buffer[i]);\r
+ }\r
+ if (1 == psample_ret->extra_result.bioext_enwork)\r
+ {\r
+ psample_ret->extra_result.bioext_buffer[i] = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ CORE921x_DEBUG_LOG("result.bioext_buffer[%d]=%d", i, psample_ret->extra_result.bioext_buffer[i]);\r
+ }\r
+ }\r
+ if (2 == psample_ret->slot_result[2].slot_enwork && VC921x_IN_STORE == psample_ret->slot_result[2].slot_storefifo)\r
+ {\r
+ psample_ret->slot_result[2].ppg_num += 1;\r
+ analysis_ppg_data = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ write_data_to_fifo_buffer( psample_ret->slot_result[2].ppg_buffer, psample_ret->slot_result[2].ppg_num-1, analysis_ppg_data, 0 );\r
+ CORE921x_DEBUG_LOG("slot_result[2].ps_data[%d]=%d", i, analysis_ppg_data);\r
+ }\r
+ }\r
+ else /* VC921x_BIO_NOFIFO_PS_SGL VC921x_BIO_INFIFO_PPG_SGL */\r
+ {\r
+ if (2 == psample_ret->slot_result[2].slot_enwork && VC921x_IN_STORE == psample_ret->slot_result[2].slot_storefifo)\r
+ {\r
+ psample_ret->slot_result[2].ppg_num += 1;\r
+ analysis_ppg_data = read_data_from_fifo_buffer(fifo_data, &array_offset, 0, 16 );\r
+ write_data_to_fifo_buffer( psample_ret->slot_result[2].ppg_buffer, psample_ret->slot_result[2].ppg_num-1, analysis_ppg_data, 0 );\r
+ CORE921x_DEBUG_LOG("slot_result[2].ps_data[%d]=%d", i, analysis_ppg_data);\r
+ }\r
+ }\r
+ } /* end of for(i<group_num), all fifodata */\r
+ return ret;\r
+}\r
+\r
+/****************************************************************\r
+ * CORE_API.write()/set()\r
+ * slot configuration,adjust current,resistance and sampleTime\r
+ * write or set config registers\r
+ ***************************************************************/\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_slot_enable_config(VC921x_PPG_SLOT_I slot_index, VC921x_CFG_FUNC config_enable)\r
+{\r
+ int ret = 0;\r
+ core921x_slot_config_t slotcfg = {0};\r
+ unsigned char cfg0_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + 4 * slot_index;\r
+ ret = vc921x_read_register(cfg0_addr, (unsigned char *)&slotcfg.slot_cfg0.byte, 1);\r
+ slotcfg.slot_cfg0.bits.enable = config_enable;\r
+ ret = vc921x_write_register(cfg0_addr, (unsigned char *)&slotcfg.slot_cfg0.byte, 1);\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION 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 )\r
+{\r
+ int ret = 0;\r
+ core921x_slot_config_t slotcfg = {0};\r
+ unsigned char slot_base_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + 4 * slot_index;\r
+ ret = vc921x_read_register(slot_base_addr, (unsigned char *)&slotcfg, sizeof(core921x_slot_config_t));\r
+ slotcfg.slot_cfg0.bits.rxgain = rxgain;\r
+ slotcfg.slot_cfg0.bits.freq_isps = freq_isps;\r
+ slotcfg.slot_cfg0.bits.oversample = (oversample > 7) ? 7 : oversample;\r
+ slotcfg.slot_cfg1.bits.txch = txchsel;\r
+ slotcfg.slot_cfg2.bits.storefifo = slot_infifo;\r
+ \r
+ switch (sample_tim)\r
+ {\r
+ case VC921x_SAMPLE_TIM_50US:\r
+ slotcfg.slot_cfg1.bits.env_time = 2;\r
+ slotcfg.slot_cfg1.bits.sample_time = 0;\r
+ slotcfg.slot_cfg3.bits.sc = 3; /* env_time_config+1 */\r
+ break;\r
+ case VC921x_SAMPLE_TIM_100US:\r
+ slotcfg.slot_cfg1.bits.env_time = 5;\r
+ slotcfg.slot_cfg1.bits.sample_time = 1;\r
+ slotcfg.slot_cfg3.bits.sc = 6;\r
+ break;\r
+ case VC921x_SAMPLE_TIM_150US:\r
+ slotcfg.slot_cfg1.bits.env_time = 8;\r
+ slotcfg.slot_cfg1.bits.sample_time = 2;\r
+ slotcfg.slot_cfg3.bits.sc = 9;\r
+ break;\r
+ case VC921x_SAMPLE_TIM_200US:\r
+ slotcfg.slot_cfg1.bits.env_time = 11;\r
+ slotcfg.slot_cfg1.bits.sample_time = 3;\r
+ slotcfg.slot_cfg3.bits.sc = 12;\r
+ break;\r
+ default:\r
+ slotcfg.slot_cfg1.bits.env_time = 5;\r
+ slotcfg.slot_cfg1.bits.sample_time = 1;\r
+ slotcfg.slot_cfg3.bits.sc = 6;\r
+ break;\r
+ }\r
+ ret = vc921x_write_register(slot_base_addr, (unsigned char *)&slotcfg, sizeof(core921x_slot_config_t));\r
+ return ret;\r
+}\r
+\r
+/* PPG通道及调整的函数接口 */\r
+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)\r
+{\r
+ *pmax_res = MAX_RES_LEVEL;\r
+ *pmin_res = MIN_RES_LEVEL;\r
+ *pmax_curr = MAX_CURRENT;\r
+ *pmin_curr = MIN_CURRENT;\r
+ return 0;\r
+}\r
+\r
+/* 电流+电阻等级的读写,这部分是在使用过程中会反复调用的 */\r
+CORE921x_FUNC_RAM_SECTION int __core921x_read_slot_current_res(VC921x_PPG_SLOT_I slot_index, unsigned char *pslot_curr, unsigned char *pslot_reslvl)\r
+{\r
+ int ret = 0;\r
+ core921x_slot_config_t slotcfg = {0};\r
+ /* read current */\r
+ unsigned char cfg2_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 2;\r
+ ret = vc921x_read_register(cfg2_addr, (unsigned char *)&slotcfg.slot_cfg2, 1);\r
+ if (pslot_curr)\r
+ {\r
+ *pslot_curr = slotcfg.slot_cfg2.bits.current;\r
+ }\r
+ /* read reslvl */\r
+ unsigned char cfg0_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4);\r
+ unsigned char cfg3_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 3;\r
+ vc921x_read_register(cfg0_addr, (unsigned char *)&slotcfg.slot_cfg0, 1);\r
+ vc921x_read_register(cfg3_addr, (unsigned char *)&slotcfg.slot_cfg3, 1);\r
+ if (pslot_reslvl)\r
+ {\r
+ //*pslot_reslvl = slotcfg.slot_cfg3.bits.resistance;\r
+ *pslot_reslvl = get_level_by_res_rxgain(slotcfg.slot_cfg3.bits.resistance, slotcfg.slot_cfg0.bits.rxgain);\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_ppgslot_current(VC921x_PPG_SLOT_I slot_index, unsigned char current)\r
+{\r
+ int ret = 0;\r
+ core921x_slot_cfg2bit slotcfg2 = {0};\r
+ unsigned char cfg2_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 2;\r
+ ret = vc921x_read_register(cfg2_addr, (unsigned char *)&slotcfg2, 1);\r
+ slotcfg2.current = (current >= MAX_CURRENT) ? MAX_CURRENT : current;\r
+ ret = vc921x_write_register(cfg2_addr, (unsigned char *)&slotcfg2, 1);\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_ppgslot_resistance(VC921x_PPG_SLOT_I slot_index, unsigned char res_level, unsigned char allow_oversample )\r
+{\r
+ int ret = 0;\r
+ unsigned char res = 0, rxgain = 0;\r
+ core921x_slot_ppg_cfg0bit slotcfg0 = {0};\r
+ core921x_slot_cfg3bit slotcfg3 = {0};\r
+ unsigned char cfg0_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4);\r
+ unsigned char cfg3_addr = CORE921x_CONFIG_SLOT_ADDR_BASE + (slot_index * 4) + 3;\r
+ ret = vc921x_read_register(cfg0_addr, (unsigned char *)&slotcfg0, 1);\r
+ ret = vc921x_read_register(cfg3_addr, (unsigned char *)&slotcfg3, 1);\r
+ res_level = (res_level >= MAX_RES_LEVEL) ? MAX_RES_LEVEL : res_level;\r
+ get_res_rxgain_by_level(res_level, &res, &rxgain);\r
+ slotcfg3.resistance = res;\r
+ slotcfg0.rxgain=rxgain;\r
+#if 1\r
+ if (slot_index <= 1 && allow_oversample)\r
+ {\r
+ slotcfg0.oversample = 1 * rxgain;\r
+ }\r
+#endif\r
+ ret = vc921x_write_register(cfg0_addr, (unsigned char *)&slotcfg0, 1);\r
+ ret = vc921x_write_register(cfg3_addr, (unsigned char *)&slotcfg3, 1);\r
+ return ret;\r
+}\r
+\r
+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 )\r
+{\r
+ int ret = 0;\r
+ core921x_pd_cfgbit pd_config = {0};\r
+ pd_config.slot0_pdch = slot0_pd;\r
+ pd_config.slot1_pdch = slot1_pd;\r
+ pd_config.slot2_pdch = slot2_pd;\r
+ ret = vc921x_write_register(0x4C, (unsigned char *)&pd_config, sizeof(pd_config));\r
+ return ret;\r
+}\r
+\r
+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 )\r
+{\r
+ int ret = 0;\r
+ core921x_anti_cfgbit anti_config = {0};\r
+ core921x_anti_cfgbit_1120mpw anti_config_1120mpw={0};\r
+ if( core921x_nto_version )\r
+ {\r
+ anti_config.anti_current = anti_current>=7?7:anti_current;\r
+ anti_config.deslot0 = deslot0;\r
+ anti_config.deslot1 = deslot1;\r
+ anti_config.deslot2 = deslot2;\r
+ anti_config.antiTxch=antich;\r
+ ret = vc921x_write_register(0x4D, (unsigned char *)&anti_config, sizeof(core921x_anti_cfgbit));\r
+ }\r
+ else\r
+ {\r
+ if( core921x_0808mpw ) return ret;\r
+ anti_config_1120mpw.anti_current = anti_current>=7?7:anti_current;\r
+ anti_config_1120mpw.deslot0 = deslot0;\r
+ anti_config_1120mpw.deslot1 = deslot1;\r
+ anti_config_1120mpw.deslot2 = deslot2;\r
+ ret = vc921x_write_register(0x4D, (unsigned char *)&anti_config_1120mpw, sizeof(core921x_anti_cfgbit_1120mpw));\r
+ }\r
+ return ret;\r
+}\r
+\r
+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)\r
+{\r
+ int ret = 0;\r
+ core921x_com_cfgbit com_config = {0};\r
+ com_config.deenv_en = deenv_en;\r
+ com_config.i2crelease_en = i2crelease_en;\r
+ com_config.bio_disfreqHop = bio_disfreqHop;\r
+ com_config.fifoformat = fifo_format;\r
+ com_config.fifo_en = fifo_en;\r
+ com_config.cpd = cpd;\r
+ if( core921x_0808mpw )\r
+ {\r
+ com_config.bio_disfreqHop = 0; /* deFlick */\r
+ ret = vc921x_write_register(0x4D, (unsigned char *)&com_config, sizeof(com_config));\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x4E, (unsigned char *)&com_config, sizeof(com_config));\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_sample_frequency(unsigned short int div1, unsigned char div2, unsigned char div3)\r
+{\r
+ int ret = 0;\r
+ unsigned char freq_config[4] = {0};\r
+ freq_config[0] = (div1 >> 8);\r
+ freq_config[1] = (div1 & 0xFF);\r
+ freq_config[2] = div2;\r
+ freq_config[3] = div3;\r
+ if( core921x_0808mpw )\r
+ {\r
+ ret = vc921x_write_register(0x4E, freq_config, sizeof(freq_config));\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x4F, freq_config, sizeof(freq_config));\r
+ }\r
+ return ret;\r
+}\r
+\r
+/****************************************************************\r
+ * CORE_API.write()/set()\r
+ * txchx_comconfig & ppg threshold configuration\r
+ * write or set config registers\r
+ ***************************************************************/\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_threshold_config(unsigned char ppgth_h, unsigned char ppgth_l)\r
+{\r
+ int ret = 0;\r
+ core921x_ppgth_cfgbit ppgth_config = {0};\r
+ ppgth_config.ppgthh = (ppgth_h >= 0xf) ? 0xf : ppgth_h;\r
+ ppgth_config.ppgthl = (ppgth_l >= 0xf) ? 0xf : ppgth_l;\r
+ if( core921x_0808mpw )\r
+ {\r
+ ret = vc921x_write_register(0x52, (unsigned char *)&ppgth_config, 1);\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x53, (unsigned char *)&ppgth_config, 1);\r
+ }\r
+ return ret;\r
+}\r
+/****************************************************************\r
+ * CORE_API.write()/set()\r
+ * extra(ADC,BIO,temperature,AT/DT) configuration\r
+ * write or set config registers\r
+ ***************************************************************/\r
+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)\r
+{\r
+ int ret = 0;\r
+ core921x_int_cfgbit int_config = {0};\r
+ int_config.intmode = (unsigned char)int_mode;\r
+ int_config.intdir = (unsigned char)int_dir;\r
+ int_config.intlen = (unsigned char)int_len;\r
+ if (evt_en & VC921x_EN_EVT_FREQ2)\r
+ {\r
+ int_config.intfreq2_en = 1;\r
+ }\r
+ if (evt_en & VC921x_EN_EVT_FIFO)\r
+ {\r
+ int_config.intfifo_en = 1;\r
+ }\r
+ if (evt_en & VC921x_EN_EVT_OVLD)\r
+ {\r
+ int_config.intov_en = 1;\r
+ }\r
+ if (evt_en & VC921x_EN_EVT_PPG)\r
+ {\r
+ int_config.intppg_en = 1;\r
+ }\r
+ if( core921x_0808mpw )\r
+ {\r
+ ret = vc921x_write_register(0x53, (unsigned char *)&int_config, sizeof(int_config));\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x54, (unsigned char *)&int_config, sizeof(int_config));\r
+ }\r
+ return ret;\r
+}\r
+\r
+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) \r
+{\r
+ int ret = 0;\r
+ core921x_bio_cfg0bit bio_config0 = {0};\r
+ core921x_bio_cfg1bit bio_config1 = {0};\r
+ bio_config0.bio_inn_en = bioinn_en;\r
+ bio_config0.bio_ext_en = bioext_en;\r
+ bio_config0.bio_mode = biofifo_mode;\r
+ bio_config0.bio_pdch = bio_chsel;\r
+ bio_config0.bio_freq = (biofreq > 3) ? 3 : biofreq;\r
+\r
+ bio_config1.bio_capadd = (biocap > 0x1f) ? (0x1f) : biocap;\r
+ bio_config1.bio_time = (biotime > 0x7) ? (0xf) : biotime;\r
+ if( core921x_0808mpw )\r
+ {\r
+ ret = vc921x_write_register(0x54, (unsigned char *)&bio_config0, 1);\r
+ ret = vc921x_write_register(0x55, (unsigned char *)&bio_config1, 1);\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x55, (unsigned char *)&bio_config0, 1);\r
+ ret = vc921x_write_register(0x56, (unsigned char *)&bio_config1, 1);\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_bioinn_addcap(unsigned char biocap)\r
+{\r
+ int ret = 0;\r
+ core921x_bio_cfg1bit bio_config1 = {0};\r
+ if( core921x_0808mpw )\r
+ {\r
+ vc921x_read_register(0x55, (unsigned char *)&bio_config1, 1);\r
+ bio_config1.bio_capadd = (biocap > 0x1f) ? (0x1f) : biocap;\r
+ ret = vc921x_write_register(0x55, (unsigned char *)&bio_config1, 1);\r
+ }\r
+ else\r
+ {\r
+ vc921x_read_register(0x56, (unsigned char *)&bio_config1, 1);\r
+ bio_config1.bio_capadd = (biocap > 0x1f) ? (0x1f) : biocap;\r
+ ret = vc921x_write_register(0x56, (unsigned char *)&bio_config1, 1);\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_temperature_config(VC921x_CFG_FUNC tempslot0_en, VC921x_TEMP_SLOT tempslot0_chsel, unsigned char tempslot0_current, \r
+VC921x_CFG_FUNC tempslot1_en, VC921x_TEMP_SLOT tempslot1_chsel, unsigned char tempslot1_current )\r
+{\r
+ int ret = 0;\r
+ core921x_temp_cfgbit temp_config[2] = {0};\r
+ temp_config[0].temp_enable = tempslot0_en;\r
+ temp_config[0].temp_slotch = tempslot0_chsel;\r
+ temp_config[0].temp_currset = (tempslot0_current >= 7) ? 7 : tempslot0_current;\r
+ temp_config[1].temp_enable = tempslot1_en;\r
+ temp_config[1].temp_slotch = tempslot1_chsel;\r
+ temp_config[1].temp_currset = (tempslot1_current >= 7) ? 7 : tempslot1_current;\r
+ if(core921x_0808mpw)\r
+ {\r
+ ret = vc921x_write_register(0x56, (unsigned char *)&temp_config, sizeof(temp_config));\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x57, (unsigned char *)&temp_config, sizeof(temp_config));\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_adc_config( VC921x_ADC_RESOLUTION adc_resulution, VC921x_CFG_FUNC ovdata_sum_enable )\r
+{\r
+ int ret=0;\r
+ core921x_adc_config_t adc_config={0};\r
+ core921x_adc_config_t_1120mpw adc_config_1120mpw={0};\r
+ if( core921x_nto_version )\r
+ {\r
+ adc_config.ppg_resulution=adc_resulution;\r
+ adc_config.ovtype = ovdata_sum_enable;\r
+ adc_config.cmpset = 3;\r
+ adc_config.env_clkdiv=0;\r
+ adc_config.adc_speed=0;\r
+ ret = vc921x_write_register(0x59, (unsigned char *)&adc_config, sizeof(adc_config));\r
+ }\r
+ else\r
+ {\r
+ adc_config_1120mpw.ppg_resulution=adc_resulution;\r
+ adc_config_1120mpw.ovtype = ovdata_sum_enable;\r
+ adc_config_1120mpw.reserved = 0;\r
+ adc_config_1120mpw.env_clkdiv=0;\r
+ adc_config_1120mpw.adc_speed=0;\r
+ if( core921x_0808mpw )\r
+ {\r
+ ret = vc921x_write_register(0x58, (unsigned char *)&adc_config_1120mpw, sizeof(adc_config_1120mpw));\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x59, (unsigned char *)&adc_config_1120mpw, sizeof(adc_config_1120mpw));\r
+ }\r
+ }\r
+ //CORE921x_DEBUG_LOG("write register adc_resulution=[%d],ovdata_sum_enable=[%d]", adc_resulution, ovdata_sum_enable);\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_set_rcosc_frequency(unsigned char oscset)\r
+{\r
+ int ret = 0;\r
+ if( core921x_0808mpw )\r
+ {\r
+ ret = vc921x_write_register(0x59, &oscset, 1);\r
+ }\r
+ else\r
+ {\r
+ ret = vc921x_write_register(0x5A, &oscset, 1);\r
+ }\r
+ return ret;\r
+}\r
+\r
+CORE921x_FUNC_RAM_SECTION int __core921x_write_work_cmd(VC921x_WORK_CMD cmd) //\r
+{\r
+ int ret = 0;\r
+ unsigned char wcmd = 0;\r
+ switch (cmd)\r
+ {\r
+ case VC921x_STOP_WORK_CMD:\r
+ wcmd = 0x00;\r
+ break;\r
+ case VC921x_START_WORK_CMD:\r
+ wcmd = 0x5A;\r
+ break;\r
+ case VC921x_RESET_SOFT_CMD:\r
+ wcmd = 0xA5;\r
+ break;\r
+ default:\r
+ return 1;\r
+ }\r
+ ret = vc921x_write_register(CORE921x_WORK_CMD_ADDR_BASE, &wcmd, 1);\r
+ return ret;\r
+}\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-11-03 01:20:20\r
+ * @LastEditTime: 2024-04-11 20:37:31\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+#include "vc921x_core_com.h"\r
+#include "vc921x_driver_config.h"\r
+#include "vc921x_driver.h"\r
+\r
+#if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE)\r
+#include "BIODetect_V14_1.h"\r
+#endif\r
+\r
+#ifndef VC_ABS_MAX\r
+#define VC_ABS_MAX(a, b, max) (((a) > (b)) ? ((a) - (b)) : (max + (a) - (b)))\r
+#endif\r
+#ifndef VC_ABS\r
+#define VC_ABS(a, b) (((a) > (b)) ? ((a) - (b)) : ((b) - (a)))\r
+#endif\r
+\r
+#ifndef VC921x_ENV_CONVERT\r
+#define VC921x_ENV_CONVERT( hex_env ) (((hex_env)>>8)*50+((hex_env)&0xff))\r
+#endif\r
+\r
+unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY=32000; /* extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; */\r
+unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD=100; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; */\r
+unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP=100; /* extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; */\r
+\r
+unsigned int vc921x_calc_ps_reflect_thh( unsigned char psI, unsigned char psR, unsigned char ps_adcbit )\r
+{\r
+ unsigned int calc_psthh = 0;\r
+ float fix_I = vcare_I_exponent_func( 0.8f, VC921x_WEAR_PARAM_PS_CURRENT );\r
+ float fix_R = vcare_R_exponent_func( 100.0f, VC921x_WEAR_PARAM_PS_RESISTANCE );\r
+ float real_I= vcare_I_exponent_func( 0.8f, psI );\r
+#if VC921x_CFG_DEFAULT_PPGGAIN_EN\r
+ float real_R= vcare_R_exponent_func( 200.0f, psR ); /* !!notice:gain_min=1 */\r
+#else\r
+ float real_R= vcare_R_exponent_func( 100.0f, psR ); /* !!notice:gain_min=0 */\r
+#endif\r
+ unsigned int adc_gain=1<<(ps_adcbit-16);\r
+ float k = (real_I*real_R)/(fix_I*fix_R*(1<<VC921x_WEAR_PARAM_PS_GAIN));\r
+ calc_psthh=k*VC921x_WEAR_PARAM_PSTH*adc_gain;\r
+ \r
+ VCARE_DBG_LOG( "fix_I=%d(%f)mA, fix_R=%d(%f)K", VC921x_WEAR_PARAM_PS_CURRENT, fix_I, VC921x_WEAR_PARAM_PS_RESISTANCE, fix_R );\r
+ VCARE_DBG_LOG( "real_I=%d(%f)mA,real_R=%d(%f)K", psI, real_I, psR, real_R );\r
+ VCARE_DBG_LOG("adcgain(%d,k=%f),fix_psthh=%d,calc_psthh=%d",adc_gain,k, VC921x_WEAR_PARAM_PSTH, calc_psthh );\r
+ return calc_psthh;\r
+}\r
+\r
+static unsigned short startup_inntemperature=0;\r
+static unsigned int check_cpu_tick[2]={0}, check_dev_tick[2]={0};\r
+static int drv921x_nto_version=0;\r
+/* [dichotomy] startup will calc rcosc */\r
+static unsigned char rcosc_max = 127;\r
+static unsigned char rcosc_min = 0;\r
+static unsigned char rcosc_mid = 63;\r
+\r
+/* [dichotomy] reset bio param */\r
+#define VC921x_CALC_BIOINN_OFFSET 100\r
+static unsigned short int last_ext_bio=0; /* 判断外部bio的稳定性 */\r
+/* 二分夹为二选一时,分别测试记录得到最合适得值 */\r
+static unsigned char remember_biomax_mark=0; \r
+static unsigned char remember_biomin_mark=0;\r
+static unsigned short int remember_biomax_value = 0;\r
+static unsigned short int remember_biomin_value = 0;\r
+/* 二分中值及采样标志 */\r
+static unsigned short int last_inn_bio_mid=0; \r
+static unsigned char set_flg_mid=0;\r
+/* 二分初始数据 */\r
+static unsigned char set_cap_max=31; \r
+static unsigned char set_cap_mid=16;\r
+static unsigned char set_cap_min=1;\r
+\r
+#if (VC921x_USE_MEMORY_SELECT == VC921x_USE_STATIC_MEMORY)\r
+static vc921x_sample_info_t sample_info = {0}; /* sample config & sample result */\r
+static vc921x_adjust_info adjust_info[3] = {0}; /* slot_adjust_infomation */\r
+static vc921x_wear_info wear_info = {0}; /* wear_status_infomation */\r
+static vc921x_clk_info clk_info = {0}; /* oscclk_calibration_infomation */\r
+static vc921x_drv_info drv_info = {0}; /* driver_param_infomation */\r
+static vc921x_sample_info_t *sample_info_handle = &sample_info;\r
+static vc921x_adjust_info *adjust_info_handle[3] = { &adjust_info[0], &adjust_info[1], &adjust_info[2] };\r
+static vc921x_wear_info *wear_info_handle = &wear_info;\r
+static vc921x_clk_info *clk_info_handle = &clk_info;\r
+static vc921x_drv_info *drv_info_handle = &drv_info;\r
+\r
+#elif (VC921x_USE_MEMORY_SELECT==VC921x_USE_FIXDYNC_MEMORY)\r
+static vc921x_sample_info_t *sample_info_handle = NULL;\r
+static vc921x_adjust_info *adjust_info_handle[3] = {NULL, NULL,NULL};\r
+static vc921x_wear_info *wear_info_handle = NULL;\r
+static vc921x_clk_info *clk_info_handle = NULL;\r
+static vc921x_drv_info *drv_info_handle = NULL;\r
+#endif\r
+\r
+static void drv_calibration_clk_clear(void);\r
+static int drv_read_sample_param(vc921x_sample_info_t *psample_ret);\r
+static int drv_read_fifo_data(vc921x_sample_info_t *psample_result);\r
+static int drv_read_event_status(vc921x_drv_info *pdrv_info);\r
+\r
+/********************************************************************************************************\r
+ * 驱动参数内存申请/释放,初始化/结束使用\r
+ ********************************************************************************************************/\r
+int vc921x_drv_memroy_alloc(void)\r
+{\r
+#if (VC921x_USE_MEMORY_SELECT == VC921x_USE_FIXDYNC_MEMORY)\r
+ sample_info_handle = vc921x_malloc(sizeof(vc921x_sample_info_t));\r
+ if (NULL == sample_info_handle)\r
+ {\r
+ VCARE_DBG_ERR("sample_info_handle malloc failed");\r
+ goto SAMPLE_INFO_MEM_ERROR;\r
+ }\r
+ vcare_memset(sample_info_handle, 0, sizeof(vc921x_sample_info_t));\r
+\r
+ adjust_info_handle[0] = vc921x_malloc(sizeof(vc921x_adjust_info));\r
+ if (NULL == adjust_info_handle[0])\r
+ {\r
+ VCARE_DBG_ERR("adjust_info_handle[0] malloc failed");\r
+ goto ADJ_INFO0_MEM_ERROR;\r
+ }\r
+ vcare_memset(adjust_info_handle[0], 0, sizeof(vc921x_adjust_info));\r
+\r
+ adjust_info_handle[1] = vc921x_malloc(sizeof(vc921x_adjust_info));\r
+ if (NULL == adjust_info_handle[1])\r
+ {\r
+ VCARE_DBG_ERR("adjust_info_handle[1] malloc failed");\r
+ goto ADJ_INFO1_MEM_ERROR;\r
+ }\r
+ vcare_memset(adjust_info_handle[1], 0, sizeof(vc921x_adjust_info));\r
+ \r
+ adjust_info_handle[2] = vc921x_malloc(sizeof(vc921x_adjust_info));\r
+ if (NULL == adjust_info_handle[2])\r
+ {\r
+ VCARE_DBG_ERR("adjust_info_handle[2] malloc failed");\r
+ goto ADJ_INFO1_MEM_ERROR;\r
+ }\r
+ vcare_memset(adjust_info_handle[2], 0, sizeof(vc921x_adjust_info));\r
+\r
+ wear_info_handle = vc921x_malloc(sizeof(vc921x_wear_info));\r
+ if (NULL == wear_info_handle)\r
+ {\r
+ VCARE_DBG_ERR("wear_info_handle malloc failed");\r
+ goto WEAR_INFO_MEM_ERROR;\r
+ }\r
+ vcare_memset(wear_info_handle, 0, sizeof(vc921x_wear_info));\r
+\r
+ clk_info_handle = vc921x_malloc(sizeof(vc921x_clk_info));\r
+ if (NULL == clk_info_handle)\r
+ {\r
+ VCARE_DBG_ERR("clk_info_handle malloc failed");\r
+ goto CLK_INFO_MEM_ERROR;\r
+ }\r
+ vcare_memset(clk_info_handle, 0, sizeof(vc921x_clk_info));\r
+\r
+ drv_info_handle = vc921x_malloc(sizeof(vc921x_drv_info));\r
+ if (NULL == drv_info_handle)\r
+ {\r
+ VCARE_DBG_ERR("drv_info_handle malloc failed");\r
+ goto DRV_INFO_MEM_ERROR;\r
+ }\r
+ vcare_memset(drv_info_handle, 0, sizeof(vc921x_drv_info));\r
+ return 0;\r
+\r
+DRV_INFO_MEM_ERROR:\r
+ vc921x_free(clk_info_handle);\r
+CLK_INFO_MEM_ERROR:\r
+ vc921x_free(wear_info_handle);\r
+WEAR_INFO_MEM_ERROR:\r
+ vc921x_free(adjust_info_handle[1]);\r
+ADJ_INFO1_MEM_ERROR:\r
+ vc921x_free(adjust_info_handle[0]);\r
+ADJ_INFO0_MEM_ERROR:\r
+ vc921x_free(sample_info_handle);\r
+SAMPLE_INFO_MEM_ERROR:\r
+ return -1;\r
+#else\r
+ return 0;\r
+#endif\r
+}\r
+int vc921x_drv_memroy_free(void)\r
+{\r
+#if (VC921x_USE_MEMORY_SELECT == VC921x_USE_FIXDYNC_MEMORY)\r
+ vc921x_free(drv_info_handle);\r
+ vc921x_free(clk_info_handle);\r
+ vc921x_free(wear_info_handle);\r
+ vc921x_free(adjust_info_handle[1]);\r
+ vc921x_free(adjust_info_handle[0]);\r
+ vc921x_free(sample_info_handle);\r
+#endif\r
+ return 0;\r
+}\r
+static void drv_sample_result_memroy_finished(vc921x_sample_info_t *presult_info)\r
+{\r
+ unsigned char i = 0;\r
+ presult_info->wear_drop_flag = 0;\r
+ if (drv_info_handle->fifo_read_data_valid)\r
+ {\r
+ /* ppg ps slot */\r
+ for (i = 0; i < 3; i++)\r
+ {\r
+ presult_info->slot_result[i].ppg_num = 0;\r
+ vcare_memset(presult_info->slot_result[i].ppg_buffer, 0, sizeof(presult_info->slot_result[i].ppg_buffer));\r
+ }\r
+ /* bioinn bioext */\r
+ presult_info->extra_result.bio_fifo_num = 0;\r
+ vcare_memset(presult_info->extra_result.bioinn_buffer, 0, sizeof(presult_info->extra_result.bioinn_buffer));\r
+ vcare_memset(presult_info->extra_result.bioext_buffer, 0, sizeof(presult_info->extra_result.bioext_buffer));\r
+ }\r
+}\r
+\r
+/********************************************************************************************************\r
+ * 驱动参数保存部分\r
+ ********************************************************************************************************/\r
+static int drv_infomation_param_save(void)\r
+{\r
+ int ret = 0;\r
+ unsigned char save_buf[12] = {0};\r
+ save_buf[0] = 0xAA;\r
+ save_buf[1] = drv_info_handle->optimal_bio_valid = 1;\r
+ save_buf[2] = drv_info_handle->optimal_cap;\r
+\r
+ save_buf[3] = (drv_info_handle->optimal_bio_gap >> 24) & 0xff; /* calibration deviation */\r
+ save_buf[4] = (drv_info_handle->optimal_bio_gap >> 16) & 0xff;\r
+ save_buf[5] = (drv_info_handle->optimal_bio_gap >> 8) & 0xff;\r
+ save_buf[6] = (drv_info_handle->optimal_bio_gap >> 0) & 0xff;\r
+ save_buf[7] = (drv_info_handle->optimal_bio_temp >> 24) & 0xff; /* temperature deviation */\r
+ save_buf[8] = (drv_info_handle->optimal_bio_temp >> 16) & 0xff;\r
+ save_buf[9] = (drv_info_handle->optimal_bio_temp >> 8) & 0xff;\r
+ save_buf[10] = (drv_info_handle->optimal_bio_temp >> 0) & 0xff;\r
+ ret = vc921x_param_write_flash(save_buf, sizeof(save_buf));\r
+ 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);\r
+ return ret; /* successed return 0 */\r
+}\r
+static int drv_infomation_param_load(void)\r
+{\r
+ int ret = 0;\r
+ unsigned char load_buf[12] = {0};\r
+ ret = vc921x_param_read_flash(load_buf, sizeof(load_buf));\r
+ if (load_buf[0] == 0xAA)\r
+ {\r
+ drv_info_handle->optimal_bio_valid = load_buf[1];\r
+ drv_info_handle->optimal_cap = load_buf[2];\r
+ drv_info_handle->optimal_bio_gap = (int)((load_buf[3] << 24) + (load_buf[4] << 16) + (load_buf[5] << 8) + (load_buf[6]));\r
+ drv_info_handle->optimal_bio_temp= (int)((load_buf[7] << 24) + (load_buf[8] << 16) + (load_buf[9] << 8) + (load_buf[10]));\r
+ }\r
+ else\r
+ {\r
+ drv_info_handle->optimal_bio_valid = 0;\r
+ drv_info_handle->optimal_cap = 0;\r
+ drv_info_handle->optimal_bio_gap = 0;\r
+ drv_info_handle->optimal_bio_temp=0;\r
+ ret=0;\r
+ }\r
+ 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);\r
+ return ret; /* successed return 0 */\r
+}\r
+/* clear param,and */\r
+static int drv_infomation_param_reset(void)\r
+{\r
+ drv_info_handle->optimal_bio_valid = 0;\r
+ drv_info_handle->optimal_cap = 0;\r
+ drv_info_handle->optimal_bio_gap = 0;\r
+ drv_info_handle->optimal_bio_temp=0;\r
+ /* init [dichotomy]param */\r
+ last_ext_bio=0;\r
+ remember_biomax_mark=0; \r
+ remember_biomin_mark=0;\r
+ remember_biomax_value = 0;\r
+ remember_biomin_value = 0;\r
+ /* 二分中值及采样标志 */\r
+ last_inn_bio_mid=0; \r
+ set_flg_mid=0;\r
+ /* 二分初始数据 */\r
+ set_cap_max=31; \r
+ set_cap_mid=16;\r
+ set_cap_min=1;\r
+ return 0;\r
+}\r
+/*****************************************************************************\r
+ * driver_work_mode table:\r
+ * {WORK_MODE, MODE_INIT_FUNC, MODE_HANDLER_FUNC }\r
+ *****************************************************************************/\r
+static const vc921x_mode_ops *sel_mode_ops = NULL;\r
+static int drv_heartrate_mode_init(void);\r
+static int drv_spo2_mode_init(void);\r
+static int drv_bloodpressure_mode_init(void);\r
+static int drv_wear_mode_init(void);\r
+static int drv_temperature_mode_init(void);\r
+static int drv_factory_green_ps_mode_init(void);\r
+static int drv_factory_ir_red_mode_init(void);\r
+static int drv_hrspo2_mode_init(void);\r
+/*handler*/\r
+static int drv_ppg_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev);\r
+static int drv_factory_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev);\r
+\r
+static const vc921x_mode_ops mode_ops[] =\r
+ {\r
+ /* work_mode, work_mode_init, work_mode_handler */\r
+ {WORK_MODE_HR, drv_heartrate_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_SPO2, drv_spo2_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_HRV, drv_heartrate_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_STRESS, drv_heartrate_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_BLOODPRESSURE, drv_bloodpressure_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_WEAR, drv_wear_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_TEMPERATURE, drv_temperature_mode_init, drv_ppg_mode_handler},\r
+ {WORK_MODE_FACTORY0, drv_factory_green_ps_mode_init, drv_factory_mode_handler},\r
+ {WORK_MODE_FACTORY1, drv_factory_ir_red_mode_init, drv_factory_mode_handler},\r
+ {WORK_MODE_HRSPO2, drv_hrspo2_mode_init, drv_ppg_mode_handler},\r
+};\r
+\r
+/******************************************************************************\r
+ * 初始化部分\r
+ ******************************************************************************/\r
+static void drv_infomation_param_init(vcare_ppg_device_t *pdev)\r
+{\r
+ int i;\r
+ unsigned char max_cur = 0, min_cur = 0, max_res_lvl = 0, min_res_lvl = 0;\r
+ /* slot_adjust param */\r
+ core921x_read_slot_adjust_param(&max_res_lvl, &min_res_lvl, &max_cur, &min_cur);\r
+ for (i = 0; i < 3; i++)\r
+ {\r
+ adjust_info_handle[i]->const_max_current = max_cur;\r
+ adjust_info_handle[i]->const_min_current = min_cur;\r
+ adjust_info_handle[i]->max_current = max_cur;\r
+ adjust_info_handle[i]->const_max_res_level = max_res_lvl;\r
+ adjust_info_handle[i]->const_min_res_level = min_res_lvl;\r
+ adjust_info_handle[i]->max_res_level = max_res_lvl;\r
+ adjust_info_handle[i]->adj_param.current_step = VC921x_ADJ_I_STEP_DFT;\r
+ adjust_info_handle[i]->adj_param.direction = VC921x_ADJUST_DIR_NONE;\r
+ adjust_info_handle[i]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE;\r
+ }\r
+ /* dev_wear param */\r
+ drv_info_handle->optimal_bio_valid =1; /* 先置1,等待在factory模式下主动清除后进行配平 */\r
+#if (VC921x_WEAR_DFT_HOLD == VC921x_CFG_WEAR_DEFAULT_STA)\r
+ wear_info_handle->last_status = (WEAR_STA_NONE == wear_info_handle->last_status) ? WEAR_STA_HOLD : wear_info_handle->last_status;\r
+#else\r
+ #if (VC921x_CFG_WEAR_BIO_OLD_EN!=VC921x_FUNC_ENABLE)\r
+ /* 注意:只能非边沿活体的条件下,第一次或者停止工作后,重置活体状态为DROP。边沿的方式调用stop因为机制问题,无论如何都不能完美处理stop之后的状态 */\r
+ wear_info_handle->bio_wear_result = (WEAR_STA_NONE == wear_info_handle->last_status) ? VC921x_BIO_STA_DROP : wear_info_handle->bio_wear_result;\r
+ #endif\r
+ wear_info_handle->last_status = (WEAR_STA_NONE == wear_info_handle->last_status) ? WEAR_STA_DROP : wear_info_handle->last_status;\r
+#endif\r
+#if (VC921x_FUNC_ENABLE != VC921x_CFG_WEAR_DETECTION)\r
+ wear_info_handle->last_status = WEAR_STA_HOLD;\r
+#endif\r
+ /* 切换模式如果为摘下时,需要关灯 */\r
+ 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))\r
+ {\r
+ for (i = 0; i < 3; i++)\r
+ {\r
+ if (sample_info_handle->slot_result[i].slot_enwork == 1)\r
+ {\r
+ core921x_set_enable_config((VC921x_PPG_SLOT_I)i, VC921x_CFG_DISABLE);\r
+ sample_info_handle->slot_result[i].slot_enwork = 0;\r
+ }\r
+ if( drv_info_handle->ppg_convert_ps )\r
+ {\r
+ drv_info_handle->ppg_convert_ps=0;\r
+ 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*/);\r
+ 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);\r
+ }\r
+ }\r
+ }\r
+ wear_info_handle->wear_status = wear_info_handle->last_status;\r
+ pdev->wear = wear_info_handle->last_status;\r
+\r
+ wear_info_handle->drop_cnt = VC921x_CFG_WEAR_DROP_CNT;\r
+ wear_info_handle->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT;\r
+ wear_info_handle->acce_wear_status = WEAR_STA_HOLD;\r
+ wear_info_handle->algo_wear_status = WEAR_STA_HOLD;\r
+ /* dev_clk param */\r
+ drv_calibration_clk_clear();\r
+ /* read_fifo_address */\r
+ drv_info_handle->read_fifo_address = 0;\r
+ if( drv_info_handle->work_mode==WORK_MODE_SPO2 || drv_info_handle->work_mode==WORK_MODE_HRSPO2 )\r
+ {\r
+ drv_info_handle->ppg_max_thval = VC921x_PPG_SPO2_MAX_DEFT_THVAL;\r
+ drv_info_handle->ppg_min_thval = VC921x_PPG_SPO2_MIN_DEFT_THVAL;\r
+ }\r
+ else\r
+ {\r
+ drv_info_handle->ppg_max_thval = VC921x_PPG_MAX_DEFT_THVAL;\r
+ drv_info_handle->ppg_min_thval = VC921x_PPG_MIN_DEFT_THVAL;\r
+ }\r
+ if (wear_info_handle->bio_wear_result == VC921x_BIO_STA_NONE)\r
+ {\r
+#if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE)\r
+ f_BIOInit( VC921x_WEAR_PARAM_BIO_DELTA, VC921x_WEAR_PARAM_PS_DELTA );\r
+ VCARE_DBG_LOG("f_BIOedgeinit(%d, %d, %d)", VC921x_WEAR_PARAM_BIO_DELTA, VC921x_WEAR_PARAM_PS_DELTA );\r
+#endif\r
+ }\r
+}\r
+\r
+static int drv_calc_bioinn_auto_addcap(unsigned char status, vc921x_sample_info_t *psample_info)\r
+{\r
+ unsigned char finished_set=0;\r
+ unsigned char finished_mark=0;\r
+ if (status & VC921x_EVENT_INTPS_RDY)\r
+ {\r
+ if (drv_info_handle->optimal_bio_valid)\r
+ {\r
+ return 0;\r
+ }\r
+ /* 判断是否bioext发生变化,如果变化太大,那么直接校准失败 */\r
+ if( last_ext_bio!=0 && VC_ABS(last_ext_bio,psample_info->extra_result.bioext_data)>=20 )\r
+ {\r
+ VCARE_DBG_ERR("calc bioinn error, bioext running...");\r
+ }\r
+ last_ext_bio = psample_info->extra_result.bioext_data;\r
+ /* 二分法校准,循环赋值,设置参数与采样值呈负相关 */\r
+ if( set_flg_mid==1 )\r
+ {\r
+ set_flg_mid=0;\r
+ last_inn_bio_mid=psample_info->extra_result.bioinn_data;\r
+ }\r
+ if( last_inn_bio_mid==0 )\r
+ {\r
+ core921x_set_bioinn_addcap(psample_info,set_cap_mid);\r
+ set_flg_mid=1;\r
+ return 0;\r
+ }\r
+ /* 在合理范围内快速退出 */\r
+ 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 )\r
+ {\r
+ finished_set=set_cap_mid;\r
+ finished_mark=1;\r
+ 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,\r
+ last_inn_bio_mid, psample_info->extra_result.bioext_data, last_inn_bio_mid );\r
+ }\r
+ else /* 不在范围,范围比较大,继续二分 */\r
+ {\r
+ /* 检索完成,需要再min和max中取一个值 */\r
+ if( (set_cap_max-set_cap_min)<=1 )\r
+ {\r
+ if(remember_biomax_mark==1)\r
+ {\r
+ remember_biomax_mark=0;\r
+ remember_biomax_value = psample_info->extra_result.bioinn_data;\r
+ }\r
+ if( remember_biomin_mark==1 )\r
+ {\r
+ remember_biomin_mark=0;\r
+ remember_biomin_value = psample_info->extra_result.bioinn_data;\r
+ }\r
+ if( remember_biomax_value==0 )\r
+ {\r
+ remember_biomax_mark=1;\r
+ core921x_set_bioinn_addcap(psample_info,set_cap_max);\r
+ return 0;\r
+ }\r
+ if( remember_biomin_value==0 )\r
+ {\r
+ remember_biomin_mark=1;\r
+ core921x_set_bioinn_addcap(psample_info,set_cap_min);\r
+ return 0;\r
+ }\r
+ if( VC_ABS(remember_biomin_value,psample_info->extra_result.bioext_data) <= VC_ABS(remember_biomax_value,psample_info->extra_result.bioext_data) )\r
+ {\r
+ finished_set=set_cap_min;/* 取min,结束 */\r
+ last_inn_bio_mid = remember_biomin_value;\r
+ }\r
+ else \r
+ {\r
+ finished_set=set_cap_max;/* 取max,结束 */\r
+ last_inn_bio_mid = remember_biomax_value;\r
+ }\r
+ finished_mark=1;\r
+ VCARE_DBG_LOG("mingap(%d)[%d],maxgap(%d)[%d]->(%d)",set_cap_min,VC_ABS(remember_biomin_value,psample_info->extra_result.bioext_data),\r
+ set_cap_max,VC_ABS(remember_biomax_value,psample_info->extra_result.bioext_data), finished_set);\r
+ }\r
+ /* 继续执行二分逼近 */\r
+ if( last_inn_bio_mid<psample_info->extra_result.bioext_data )\r
+ {\r
+ 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,\r
+ last_inn_bio_mid, psample_info->extra_result.bioext_data, (set_cap_min+set_cap_mid)/2 );\r
+ set_cap_max = set_cap_mid;\r
+ set_cap_mid = (set_cap_min+set_cap_mid)/2;\r
+ set_flg_mid = 1;\r
+ core921x_set_bioinn_addcap(psample_info,set_cap_mid);\r
+ }\r
+ else if( last_inn_bio_mid>psample_info->extra_result.bioext_data )\r
+ {\r
+ 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,\r
+ last_inn_bio_mid, psample_info->extra_result.bioext_data, (set_cap_max+set_cap_mid)/2 );\r
+ set_cap_min = set_cap_mid;\r
+ set_cap_mid = (set_cap_max+set_cap_mid)/2;\r
+ set_flg_mid = 1;\r
+ core921x_set_bioinn_addcap(psample_info,set_cap_mid);\r
+ }\r
+ else if( last_inn_bio_mid==psample_info->extra_result.bioext_data ) /* 完全相等,直接结束 */\r
+ {\r
+ 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,\r
+ last_inn_bio_mid, psample_info->extra_result.bioext_data, set_cap_mid);\r
+ finished_set=set_cap_mid;\r
+ finished_mark=1;\r
+ }\r
+ }\r
+ if( finished_mark ) /* 查找结束处理 */\r
+ {\r
+ drv_info_handle->optimal_cap = finished_set;\r
+ drv_info_handle->optimal_bio_gap = last_inn_bio_mid - psample_info->extra_result.bioext_data;\r
+ drv_info_handle->optimal_bio_temp= psample_info->extra_result.temp0_data; /* inn_temp */\r
+ /* set optimal_cap */\r
+ core921x_set_bioinn_addcap(psample_info,drv_info_handle->optimal_cap);\r
+ VCARE_DBG_LOG("optimal_cap=%d, optimal_bio_gap=%d", drv_info_handle->optimal_cap, drv_info_handle->optimal_bio_gap );\r
+ /* save flash_ok */\r
+ drv_infomation_param_save();\r
+ }\r
+ }\r
+ return -1;\r
+}\r
+\r
+static void drv_calibration_entry_fast_irq( void )\r
+{\r
+ core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2|VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD | VC921x_EN_EVT_PPG );\r
+}\r
+static void drv_calibration_exit_fast_irq( void )\r
+{\r
+ if( drv_info_handle->work_mode==WORK_MODE_FACTORY0 || drv_info_handle->work_mode==WORK_MODE_FACTORY1 )\r
+ {\r
+ core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2 | VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD );\r
+ }\r
+ else\r
+ {\r
+ core921x_set_interrupt_config( VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD | VC921x_EN_EVT_PPG );\r
+ }\r
+}\r
+\r
+static void drv_common_register_config( vc921x_drv_info *pdrv_info )\r
+{\r
+ sample_info_handle->ppg_div = pdrv_info->ppg_div;\r
+ sample_info_handle->ps_div = pdrv_info->ps_div;\r
+ sample_info_handle->fifo_div = pdrv_info->fifo_div;\r
+ sample_info_handle->hold_div = pdrv_info->ps_div;\r
+ sample_info_handle->drop_div = pdrv_info->drop_div;\r
+#if (VC921x_CFG_DROP_REDUCE_FREQ==VC921x_FUNC_ENABLE && 0==VC921x_PS_WORK_FREQUENCY_CONFIG)\r
+ if( WEAR_STA_DROP==wear_info_handle->wear_status )\r
+ {\r
+ sample_info_handle->ps_div= pdrv_info->drop_div;\r
+ sample_info_handle->fifo_div=1;\r
+ }\r
+#endif\r
+ sample_info_handle->fifo_enable = 1;\r
+ sample_info_handle->adc_resolution = 16; /* adc位数设置=16,18,20,22,注意初版0808mp的22bitADC不可用 */\r
+ sample_info_handle->fifo_format = ( sample_info_handle->adc_resolution>=18 )?1:0;\r
+ core921x_set_common_config(sample_info_handle->fifo_enable, sample_info_handle->fifo_format, sample_info_handle->adc_resolution,\r
+ VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT);\r
+ /* set frequency and enable IRQ */\r
+ core921x_set_sample_frequency(sample_info_handle->ppg_div, sample_info_handle->ps_div, sample_info_handle->fifo_div);\r
+ core921x_set_interrupt_config( VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD | VC921x_EN_EVT_PPG );\r
+ /* ps2 */\r
+ 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*/);\r
+ 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);\r
+ /* bio */\r
+#if (VC921x_FUNC_ENABLE == VC921x_CFG_WEAR_BIO_EN)\r
+ 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*/);\r
+ core921x_set_bioslot_config(sample_info_handle, drv_info_handle->optimal_cap);\r
+#endif\r
+ /* inn-slot0,用于修正活体问题偏差及检验IC异常状态 */\r
+ VC921x_TMP_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*tmpslot0_enable*/, VC921x_CFG_ENABLE /*tmpslot1_enable*/, 6 /*tmp_setcur*/);\r
+ core921x_set_temperature_config(sample_info_handle);\r
+}\r
+\r
+static int drv_heartrate_mode_init(void)\r
+{\r
+ unsigned char hr_over_sample_config=0;\r
+ VC921x_SAMPLE_TIM sample_time_config = VC921x_SAMPLE_TIM_100US;\r
+ if( WORK_MODE_HR==sel_mode_ops->mode )\r
+ {\r
+ hr_over_sample_config = 0;\r
+ sample_info_handle->adc_resolution = 16; /* adc位数设置=16,18,20 */\r
+ if( drv_info_handle->hr_algo_mode != 0 ) /* 20240531.心率普通模式特殊配置,开启16倍过采,200us发光@algo.h */\r
+ {\r
+ hr_over_sample_config = VC921x_CFG_SPORT_HR_OVERSAMPLE;\r
+ sample_time_config = VC921x_CFG_SPORT_HR_SAMPLETIME;\r
+ }\r
+ sample_info_handle->fifo_format = ( sample_info_handle->adc_resolution>=18 )?1:0;\r
+ core921x_set_common_config(sample_info_handle->fifo_enable, sample_info_handle->fifo_format, sample_info_handle->adc_resolution,\r
+ VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT);\r
+ }\r
+ /* ppg0 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ return 0;\r
+}\r
+\r
+static int drv_spo2_mode_init(void)\r
+{\r
+ sample_info_handle->adc_resolution = 16; /* adc位数设置=16,18,20,22 */\r
+ sample_info_handle->fifo_format = ( sample_info_handle->adc_resolution>=18 )?1:0;\r
+ core921x_set_common_config(sample_info_handle->fifo_enable, sample_info_handle->fifo_format, sample_info_handle->adc_resolution,\r
+ VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT, VC921x_CFG_PPG_CHANNL_SELECT);\r
+ /* ppg0 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ppg1 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ return 0;\r
+}\r
+static int drv_bloodpressure_mode_init(void)\r
+{\r
+ /* ppg0 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ return 0;\r
+}\r
+static int drv_wear_mode_init(void)\r
+{\r
+ return 0;\r
+}\r
+static int drv_factory_green_ps_mode_init(void)\r
+{\r
+ /* ppg0 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_FAT_GREEN_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ppg1 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_FAT_RED_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ps2 */\r
+ 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*/);\r
+ 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);\r
+ /* bio/temp */\r
+#if (VC921x_FUNC_ENABLE == VC921x_CFG_WEAR_BIO_EN)\r
+ 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*/ );\r
+ core921x_set_bioslot_config(sample_info_handle, drv_info_handle->optimal_cap);\r
+#endif\r
+ /* += enable freq2ps irq */\r
+ core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2 | VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD );\r
+ return 0;\r
+}\r
+static int drv_factory_ir_red_mode_init(void)\r
+{\r
+ /* ppg0 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_FAT_IR_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ppg1 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_FAT_RED_MAX_CURT /*current*/, VC921x_FAT_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ps2 */\r
+ 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*/);\r
+ 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);\r
+ /* bio/temp */\r
+#if (VC921x_FUNC_ENABLE == VC921x_CFG_WEAR_BIO_EN)\r
+ 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*/ );\r
+ core921x_set_bioslot_config(sample_info_handle, drv_info_handle->optimal_cap);\r
+#endif\r
+ VC921x_TMP_SLOT_PARAM_CONFIG(sample_info_handle->extra_result, VC921x_CFG_ENABLE /*tmpslot0_enable*/, VC921x_CFG_ENABLE /*tmpslot1_enable*/, 6 /*tmp_setcur*/);\r
+ core921x_set_temperature_config(sample_info_handle);\r
+ /* += enable freq2ps irq */\r
+ core921x_set_interrupt_config( VC921x_EN_EVT_FREQ2 | VC921x_EN_EVT_FIFO | VC921x_EN_EVT_OVLD );\r
+ return 0;\r
+}\r
+static int drv_temperature_mode_init(void)\r
+{\r
+ return 0;\r
+}\r
+\r
+static int drv_hrspo2_mode_init(void)\r
+{\r
+ drv_info_handle->ppg_convert_ps=1;\r
+ /* ppg0 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[0] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ppg1 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[1] /*slot0_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ /* ppg-ps2 */\r
+ VC921x_PPG_SLOT_PARAM_CONFIG(sample_info_handle->slot_result[2] /*slot2_ppg*/, VC921x_PPG_CURT /*current*/, VC921x_PPG_RESISTANCE /*resistance*/);\r
+ 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);\r
+ return 0;\r
+}\r
+\r
+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)\r
+{\r
+ if( VC921x_DEV_REV_ID==pdev->id1 && VC921x_FDY_VER_ID0==pdev->id2 )\r
+ {\r
+ sample_info_handle->ic_type_id = VC921x_DEV_REV_ID;\r
+ sample_info_handle->ic_ficv_id = VC921x_FDY_VER_ID0;\r
+ }\r
+ else\r
+ {\r
+ VCARE_DBG_ERR("vc921x id error");\r
+ return ;\r
+ }\r
+ /* set & init param */\r
+ drv_info_handle->work_mode = mode;\r
+ drv_info_handle->ppg_div = ppg_div;\r
+ drv_info_handle->ps_div = ps_div;\r
+ drv_info_handle->fifo_div = fifo_div;\r
+ drv_info_handle->drop_div = drop_div;\r
+ drv_info_handle->hr_algo_mode = algo_mode; /* 新增传入算法模式,配置不同心率配置 */\r
+ drv_info_handle->ppg_convert_ps=0;\r
+ drv_infomation_param_load();\r
+ core921x_write_work_cmd(VC921x_RESET_SOFT_CMD);\r
+ core921x_write_work_cmd(VC921x_STOP_WORK_CMD);\r
+ core921x_write_work_cmd(VC921x_START_WORK_CMD);\r
+ drv921x_nto_version = core921x_check_nto_version_init(); /* 初始化判断1120mpw和0127nto */\r
+ core921x_write_work_cmd(VC921x_RESET_SOFT_CMD);\r
+ core921x_write_work_cmd(VC921x_STOP_WORK_CMD);\r
+ /* 公共配置初始化 */\r
+ drv_common_register_config( drv_info_handle );\r
+ /* 模式配置初始化 */\r
+ if (sel_mode_ops)\r
+ {\r
+ if (sel_mode_ops->mode_init) sel_mode_ops->mode_init();\r
+ }\r
+ else\r
+ {\r
+ return;\r
+ }\r
+ /* 驱动参数初始化*/\r
+ drv_infomation_param_init(pdev);\r
+ /* 血样模式配置不同的阈值 */\r
+ core921x_set_threshold_config(drv_info_handle->ppg_max_thval, drv_info_handle->ppg_min_thval);\r
+#if 1\r
+ unsigned char config_debug_reg[32] = {0};\r
+ unsigned char debug_index = 0;\r
+ vc921x_read_register(0x40, config_debug_reg, 26);\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+#endif\r
+ core921x_write_work_cmd(VC921x_START_WORK_CMD);\r
+}\r
+\r
+/********************************************************************************************************\r
+ *佩戴检测部分代码\r
+ ********************************************************************************************************/\r
+#if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE)\r
+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 )\r
+{\r
+ static unsigned int calc_ps = 0;\r
+ static int calc_bio_ext=0;\r
+ int ret = 0;\r
+ /* bio ps 有效判断 */\r
+ if( bioext_data && ps_data )\r
+ {\r
+ calc_bio_ext = bioext_data;\r
+ calc_ps = ps_data;\r
+ }\r
+ ret = f_BIOdetect(calc_bio_ext, calc_ps, VC921x_WEAR_PARAM_PSTH);\r
+ 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);\r
+ if ( VC921x_BIO_STA_HOLD == ret)\r
+ {\r
+ pwear_info->bio_wear_result = VC921x_BIO_STA_HOLD;\r
+ pwear_info->algo_wear_status = WEAR_STA_HOLD; /* bio重新佩戴重置心率算法佩戴状态 */\r
+ }\r
+ else if ( VC921x_BIO_STA_DROP == ret)\r
+ {\r
+ pwear_info->bio_wear_result = VC921x_BIO_STA_DROP;\r
+ }\r
+ return pwear_info->bio_wear_result;\r
+}\r
+#else\r
+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)\r
+{\r
+ unsigned short int bio_refence_base = 0;\r
+ unsigned char bio_ps_decline = 0; /* 1-单次下降满足,2-连续下降满足 */\r
+ if (presult->extra_result.bioinn_enwork == 0 && presult->extra_result.bioext_enwork ==0 )\r
+ {\r
+ return VC921x_BIO_STA_NONE;\r
+ }\r
+ if( !drv_info_handle->optimal_bio_valid )\r
+ {\r
+ return VC921x_BIO_STA_NONE;\r
+ }\r
+ /* ps 有效判断 */\r
+ if (ps_data)\r
+ {\r
+ /* 单次下降达到阈值 */\r
+ if (pwear_info->last_ps_data[0] > ps_data && (pwear_info->last_ps_data[0] - ps_data) >= VC921x_WEAR_PARAM_PS_DELTA)\r
+ {\r
+ bio_ps_decline = 1;\r
+ }\r
+ /*连续两次供下降达到了阈值的1.5倍,避免刚好遇到两次采样缓慢下降的情况*/\r
+ 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))\r
+ {\r
+ bio_ps_decline = 2;\r
+ }\r
+ /* buffer move */\r
+ pwear_info->last_ps_data[1] = pwear_info->last_ps_data[0];\r
+ pwear_info->last_ps_data[0] = ps_data;\r
+ }\r
+ /* bio 有效判断 */\r
+ if (bioinn_data && bioext_data)\r
+ {\r
+ 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;\r
+ VCARE_DBG_LOG("calc_temp=%f", (drv_info_handle->optimal_bio_temp-presult->extra_result.temp0_data)/36.0f*1.735f );\r
+ bio_refence_base = bioinn_data - real_bio_gap;\r
+ VCARE_DBG_LOG("bio_gap=%d(real=%d), bio_base=%d, bio_ext=%d, abs_gap(%d?[%d,%d])",\r
+ drv_info_handle->optimal_bio_gap, real_bio_gap, bio_refence_base,\r
+ bioext_data, VC_ABS(bioext_data, bio_refence_base), VC921x_WEAR_PARAM_BIO_ABS_DROP, VC921x_WEAR_PARAM_BIO_ABS_HOLD);\r
+ presult->extra_result.bioabs_calc = VC_ABS(bioext_data, bio_refence_base);\r
+ if (VC_ABS(bioext_data, bio_refence_base) >= VC921x_WEAR_PARAM_BIO_ABS_HOLD)\r
+ {\r
+ pwear_info->bio_wear_result = VC921x_BIO_STA_HOLD;\r
+ pwear_info->algo_wear_status = WEAR_STA_HOLD; /* bio重新佩戴重置心率算法佩戴状态 */\r
+ }\r
+ else if ((VC_ABS(bioext_data, bio_refence_base) <= VC921x_WEAR_PARAM_BIO_ABS_DROP) && bio_ps_decline)\r
+ {\r
+ pwear_info->bio_wear_result = VC921x_BIO_STA_DROP;\r
+ }\r
+ }\r
+ return pwear_info->bio_wear_result;\r
+}\r
+#endif\r
+\r
+static vc921x_wear_change drv_wear_status_identify(vc921x_wear_info *pwear_info, vc921x_sample_info_t *presult)\r
+{\r
+ vc921x_wear_change ret_change = VC921x_WEAR_NO_CHANGE;\r
+ int ret_bio_algo = VC921x_BIO_STA_NONE;\r
+ /* 根据是否存入fifo对参数进行取值 和 采样次数进行判断 */\r
+ unsigned char data_index = 0;\r
+ unsigned char sample_num = 1;\r
+ unsigned int ps = 0;\r
+ unsigned short int env = 0;\r
+ unsigned short int bioinn = 0;\r
+ unsigned short int bioext = 0;\r
+ unsigned int calc_psthh=VC921x_WEAR_PARAM_PSTH;\r
+ \r
+ if (presult->slot_result[2].slot_storefifo == 1)\r
+ {\r
+ sample_num = presult->slot_result[2].ppg_num;\r
+ }\r
+ if( drv_info_handle->ppg_convert_ps )\r
+ {\r
+ sample_num=1;\r
+ }\r
+ for (data_index = 0; data_index < sample_num; data_index++)\r
+ {\r
+ if (presult->slot_result[2].slot_storefifo == 1)\r
+ {\r
+ ps = VC921x_GET_SLOT_PS_DATA(presult, data_index );\r
+ }\r
+ else\r
+ {\r
+ ps = presult->slot_result[2].u.ps_data << 8;\r
+ }\r
+ if (presult->extra_result.biofifo_mode == VC921x_BIO_NOFIFO_PS_SGL)\r
+ {\r
+ bioinn = presult->extra_result.bioinn_data;\r
+ bioext = presult->extra_result.bioext_data;\r
+ }\r
+ else\r
+ {\r
+ bioinn = presult->extra_result.bioinn_buffer[data_index];\r
+ bioext = presult->extra_result.bioext_buffer[data_index];\r
+ }\r
+ env = presult->slot_result[2].env_data;\r
+#if (VC921x_FUNC_DISABLE == VC921x_CFG_WEAR_BIO_EN)\r
+ ret_bio_algo = VC921x_BIO_STA_NONE;\r
+#else\r
+ if( drv_info_handle->ppg_convert_ps )\r
+ {\r
+ ret_bio_algo = VC921x_BIO_STA_NONE;\r
+ }\r
+ else\r
+ {\r
+ #if (VC921x_CFG_WEAR_BIO_OLD_EN==VC921x_FUNC_ENABLE)\r
+ ret_bio_algo = drv_calc_biology_sense( pwear_info, presult, bioinn, bioext, ps );\r
+ #else\r
+ ret_bio_algo = drv_calc_biology_sense_absolute(pwear_info, presult, bioinn, bioext, ps);\r
+ #endif\r
+ }\r
+#endif\r
+ 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);\r
+ VCARE_DBG_LOG("extern heart_algo_ret=%d,gsnesor_axis_ret=%d", pwear_info->algo_wear_status, pwear_info->acce_wear_status);\r
+#if (VC921x_FUNC_DISABLE == VC921x_CFG_WEAR_ALG_EN)\r
+ pwear_info->algo_wear_status = WEAR_STA_HOLD;\r
+#endif\r
+#if (VC921x_FUNC_DISABLE == VC921x_CFG_WEAR_ACC_EN)\r
+ pwear_info->acce_wear_status = WEAR_STA_HOLD;\r
+#endif\r
+ if( drv_info_handle->ppg_convert_ps )\r
+ {\r
+ calc_psthh=vc921x_calc_ps_reflect_thh( presult->slot_result[2].slot_current, presult->slot_result[2].slot_resistance, presult->adc_resolution );\r
+ VCARE_DBG_LOG("PS,fix(%d-%d),dyn(%d-%d)", ps, VC921x_WEAR_PARAM_PSTH, \\r
+ VC921x_GET_SLOT_SAMPLE_DATA(presult, 2, presult->slot_result[2].ppg_num-1 ) ,calc_psthh );\r
+ ps=VC921x_GET_SLOT_SAMPLE_DATA(presult, 2, presult->slot_result[2].ppg_num-1 );\r
+ }\r
+ switch (pwear_info->wear_status)\r
+ {\r
+ case WEAR_STA_DROP:\r
+ if ((ps >= calc_psthh) && (env <= VC921x_WEAR_PARAM_ENVMIN) && (VC921x_BIO_STA_NONE == ret_bio_algo || VC921x_BIO_STA_HOLD == ret_bio_algo) &&\r
+ (WEAR_STA_HOLD == pwear_info->algo_wear_status) && (WEAR_STA_HOLD == pwear_info->acce_wear_status))\r
+ {\r
+ VCARE_DBG_LOG("drop->hold_cnt=%d", pwear_info->hold_cnt);\r
+ if (--pwear_info->hold_cnt <= 0)\r
+ {\r
+ pwear_info->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT;\r
+ pwear_info->drop_cnt = VC921x_CFG_WEAR_DROP_CNT;\r
+ pwear_info->wear_status = WEAR_STA_HOLD;\r
+ ret_change = VC921x_DROP_TO_HOLD;\r
+ goto CHANGE_RETURN;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ pwear_info->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT;\r
+ }\r
+ break;\r
+ case WEAR_STA_HOLD:\r
+ if ((ps < calc_psthh) || (env > VC921x_WEAR_PARAM_ENVMAX) || (VC921x_BIO_STA_DROP == ret_bio_algo) || (WEAR_STA_DROP == pwear_info->algo_wear_status))\r
+ {\r
+ if ((WEAR_STA_DROP == pwear_info->algo_wear_status) || (VC921x_BIO_STA_DROP == ret_bio_algo))\r
+ {\r
+ pwear_info->drop_cnt = 1;\r
+ }\r
+ VCARE_DBG_LOG("hold->drop_cnt=%d", pwear_info->drop_cnt);\r
+ if (--pwear_info->drop_cnt <= 0)\r
+ {\r
+ pwear_info->hold_cnt = VC921x_CFG_WEAR_HOLD_CNT;\r
+ pwear_info->drop_cnt = VC921x_CFG_WEAR_DROP_CNT;\r
+ pwear_info->wear_status = WEAR_STA_DROP;\r
+ ret_change = VC921x_HOLD_TO_DROP;\r
+ goto CHANGE_RETURN;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ pwear_info->drop_cnt = VC921x_CFG_WEAR_DROP_CNT;\r
+ }\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+CHANGE_RETURN:\r
+ return ret_change;\r
+}\r
+\r
+static int drv_read_wear_sample_data(vc921x_sample_info_t *pwear_result_info)\r
+{\r
+ drv_read_sample_param(pwear_result_info);\r
+ drv_read_fifo_data(pwear_result_info);\r
+ if( !clk_info_handle->clk_calc_status )\r
+ {\r
+ pwear_result_info->slot_result[0].ppg_num=0;/* clear ppg_data number, the clock_frequency wait calibration */\r
+ pwear_result_info->slot_result[1].ppg_num=0;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static wear_status drv_get_wear_status(vcare_ppg_device_t *pdev)\r
+{\r
+ wear_status calc_status = wear_info_handle->last_status;\r
+ vc921x_wear_change wear_change = VC921x_WEAR_NO_CHANGE;\r
+ vc921x_sample_info_t *result_info_ptr = pdev->result;\r
+#if (VC921x_CFG_WEAR_DETECTION == VC921x_FUNC_DISABLE)\r
+ return WEAR_STA_HOLD;\r
+#endif\r
+ drv_read_event_status(drv_info_handle);\r
+ drv_read_wear_sample_data(result_info_ptr);\r
+ VCARE_DBG_LOG("fifo_read_data_valid=%d", drv_info_handle->fifo_read_data_valid);\r
+ /* 数据读取及处理 */\r
+ if ( drv_info_handle->fifo_read_data_valid )\r
+ {\r
+ wear_change = drv_wear_status_identify(wear_info_handle, result_info_ptr);\r
+ if (VC921x_DROP_TO_HOLD == wear_change)\r
+ {\r
+ calc_status = WEAR_STA_HOLD;\r
+ wear_info_handle->wear_status = calc_status;\r
+ wear_info_handle->last_status = calc_status;\r
+ pdev->wear = calc_status;\r
+ drv_calibration_clk_clear();\r
+ 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 );\r
+ }\r
+ else if (VC921x_HOLD_TO_DROP == wear_change)\r
+ {\r
+ calc_status = WEAR_STA_DROP;\r
+ wear_info_handle->wear_status = calc_status;\r
+ wear_info_handle->last_status = calc_status;\r
+ pdev->wear = calc_status;\r
+ /* 必须重新初始化,重置windex,否则摘下的瞬间,会出现windex错误偏移,导致数据解析出错 */\r
+ 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);\r
+ result_info_ptr->wear_drop_flag = 1; /* 用于发送摘下时原始数据标志 */\r
+ }\r
+ }\r
+ return calc_status;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * 自动化调整部分代码\r
+ ********************************************************************************************************/\r
+static int drv_adjust_overload_max_current(vc921x_sample_info_t *psample_result_info, unsigned char overload, int event)\r
+{\r
+ int ret = 0;\r
+ unsigned char slot_i = 0;\r
+ vc921x_adjust_info *padjust_info = NULL;\r
+ unsigned char ovload_mark[3] = {overload & VC921x_STATUS_CH0_OVERLOAD, overload & VC921x_STATUS_CH1_OVERLOAD, overload & VC921x_STATUS_CH2_OVERLOAD};\r
+ for (slot_i = 0; slot_i < 3; slot_i++)\r
+ {\r
+ padjust_info = adjust_info_handle[slot_i];\r
+ if (ovload_mark[slot_i])\r
+ {\r
+ VCARE_DBG_LOG("ovload_mark[%d] now_cur=%d", slot_i, padjust_info->current);\r
+ if (padjust_info->current != 0)\r
+ {\r
+ padjust_info->current--;\r
+ padjust_info->max_current = padjust_info->current;\r
+ padjust_info->const_max_current = padjust_info->max_current;\r
+ /* set adjust mark & adjust param */\r
+ core921x_set_ppgslot_current((VC921x_PPG_SLOT_I)slot_i, padjust_info->current);\r
+ }\r
+ else\r
+ {\r
+ ret = -1;\r
+ }\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+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)\r
+{\r
+ unsigned char allow_oversample = 0;\r
+ unsigned char old_res_level = padjust_info->res_level;\r
+ unsigned char old_current = padjust_info->current;\r
+ unsigned short int old_current_step = padjust_info->adj_param.current_step;\r
+ 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);\r
+ if (padjust_info->current == thh_current)\r
+ {\r
+ if (padjust_info->res_level == thh_res_level)\r
+ {\r
+ VCARE_DBG_ERR("RESLVL-OFFSET-LOW IS MAX/MIN--[%d]>=[%d]", old_res_level, thh_res_level);\r
+ return -1;\r
+ }\r
+ else\r
+ {\r
+ if (padjust_info->adj_param.direction == VC921x_ADJUST_DIR_UP)\r
+ {\r
+ padjust_info->res_level = (old_res_level >= thh_res_level) ? (thh_res_level) : (old_res_level + 1);\r
+ }\r
+ else\r
+ {\r
+ padjust_info->res_level = (old_res_level <= thh_res_level) ? (thh_res_level) : (old_res_level - 1);\r
+ }\r
+ /* 20241030.电阻降到默认+4以下时,限制最大电流到约0x65,下调故当前电流置为最小 */\r
+ 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 )\r
+ {\r
+ padjust_info->max_current = 0x65;\r
+ padjust_info->current = (padjust_info->adj_param.direction == VC921x_ADJUST_DIR_UP)? padjust_info->max_current: padjust_info->const_min_current;\r
+ }\r
+ 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 )\r
+ {\r
+ padjust_info->max_current = padjust_info->const_max_current;\r
+ padjust_info->current = (padjust_info->adj_param.direction == VC921x_ADJUST_DIR_UP)? padjust_info->max_current: padjust_info->const_min_current;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /* calc step */\r
+ if (padjust_info->adj_param.direction_last == VC921x_ADJUST_DIR_NONE)\r
+ {\r
+ old_current_step *= 16;\r
+ }\r
+ else if (padjust_info->adj_param.direction_last == padjust_info->adj_param.direction)\r
+ {\r
+ 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 */\r
+ }\r
+ else\r
+ {\r
+ old_current_step = old_current_step * VC921x_ADJ_I_DECREASE;\r
+ }\r
+ padjust_info->adj_param.current_step = old_current_step >> 4;\r
+ 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;\r
+ 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;\r
+ /* adjust current */\r
+ if (VC921x_ADJUST_DIR_UP == padjust_info->adj_param.direction)\r
+ {\r
+ padjust_info->current = ((old_current + padjust_info->adj_param.current_step) > thh_current) ? thh_current : (old_current + padjust_info->adj_param.current_step);\r
+ }\r
+ else if (VC921x_ADJUST_DIR_DOWN == padjust_info->adj_param.direction)\r
+ {\r
+ padjust_info->current = (old_current < padjust_info->adj_param.current_step) ? thh_current : old_current - padjust_info->adj_param.current_step;\r
+ }\r
+ padjust_info->adj_param.direction_last = padjust_info->adj_param.direction;\r
+ }\r
+ 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);\r
+ if (WORK_MODE_HR == drv_info_handle->work_mode) /* 暂定得是只有心率模式下支持修改过采配置 */\r
+ {\r
+ allow_oversample = 0;\r
+ }\r
+ core921x_set_ppgslot_resistance((VC921x_PPG_SLOT_I)slot_index, padjust_info->res_level, allow_oversample );\r
+ core921x_set_ppgslot_current((VC921x_PPG_SLOT_I)slot_index, padjust_info->current);\r
+ return 0;\r
+}\r
+\r
+static int drv_adjust_slot_ppg_overflow(vc921x_sample_info_t *psample_result_info, int event)\r
+{\r
+ unsigned char slot_i = 0;\r
+ unsigned int over_ppgdata = 0;\r
+ vc921x_adjust_info *padjust_info = NULL;\r
+ vc921x_sample_slot_t *pslot_ret = NULL;\r
+ for (slot_i = 0; slot_i < 3; slot_i++)\r
+ {\r
+ padjust_info = adjust_info_handle[slot_i];\r
+ pslot_ret = &psample_result_info->slot_result[slot_i];\r
+ over_ppgdata = pslot_ret->u.pre_data;\r
+ if (1 == pslot_ret->slot_enwork)\r
+ {\r
+ VCARE_DBG_LOG("ppg_overflow(%d)=4bit[%d]", over_ppgdata, VC921x_PPG_CONV_BIT4(over_ppgdata) );\r
+ if (VC921x_PPG_CONV_BIT4(over_ppgdata) > drv_info_handle->ppg_max_thval)\r
+ {\r
+ padjust_info->adj_param.direction = VC921x_ADJUST_DIR_DOWN;\r
+ drv_adjust_slot_current_res(padjust_info, slot_i, padjust_info->const_min_res_level, padjust_info->const_min_current);\r
+ }\r
+ else if (VC921x_PPG_CONV_BIT4(over_ppgdata) < drv_info_handle->ppg_min_thval)\r
+ {\r
+ padjust_info->adj_param.direction = VC921x_ADJUST_DIR_UP;\r
+ drv_adjust_slot_current_res(padjust_info, slot_i, padjust_info->max_res_level, padjust_info->max_current);\r
+ }\r
+ else\r
+ {\r
+ padjust_info->adj_param.direction = VC921x_ADJUST_DIR_NONE;\r
+ padjust_info->adj_param.direction_last = VC921x_ADJUST_DIR_NONE;\r
+ VCARE_DBG_LOG("slot[%d] in the range,clear slot adjustment direction", slot_i);\r
+ }\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int drv_auto_adjust_slot_config(int event, unsigned char ov_status)\r
+{\r
+ if( wear_info_handle->wear_status==WEAR_STA_DROP )\r
+ {\r
+ return -1;\r
+ }\r
+ if ((event&VC921x_EVENT_INTOVLOAD)||VC921x_CFG_IRQ_BY_TIMER_EN)\r
+ {\r
+ drv_adjust_overload_max_current(sample_info_handle, ov_status, event);\r
+ }\r
+ if((event&VC921x_EVENT_INTPPG_STA)||VC921x_CFG_IRQ_BY_TIMER_EN)\r
+ {\r
+ drv_adjust_slot_ppg_overflow(sample_info_handle, event);\r
+ }\r
+ else\r
+ {\r
+ /* clear adjust_param */\r
+ adjust_info_handle[0]->adj_param.direction = VC921x_ADJUST_DIR_NONE;\r
+ adjust_info_handle[0]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE;\r
+ adjust_info_handle[1]->adj_param.direction = VC921x_ADJUST_DIR_NONE;\r
+ adjust_info_handle[1]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE;\r
+ adjust_info_handle[2]->adj_param.direction = VC921x_ADJUST_DIR_NONE;\r
+ adjust_info_handle[2]->adj_param.direction_last = VC921x_ADJUST_DIR_NONE;\r
+ }\r
+ return 0;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * 时钟校准部分\r
+ *******************************************************************************************************/\r
+static int drv_calibration_oscclk_frequency(vc921x_clk_info *pclk_info)\r
+{\r
+ unsigned char count_vaild = 1;\r
+ unsigned char i = 0;\r
+ unsigned int clock_tick[2] = {0};\r
+ unsigned short int osc_tick[2] = {0};\r
+ unsigned short osc_frequency[2];\r
+\r
+ clock_tick[0] = vc921x_get_cputimer_tick();\r
+ core921x_read_rcosc_tick(&osc_tick[0], &osc_tick[1]);\r
+ clock_tick[1] = vc921x_get_cputimer_tick();\r
+ if ((osc_tick[0] > osc_tick[1]) || (clock_tick[0] > clock_tick[1]))\r
+ {\r
+ pclk_info->count_index = 0;\r
+ VCARE_DBG_ERR("osc/clk ticks is error\n");\r
+ return 1;\r
+ }\r
+ pclk_info->osc_count[pclk_info->count_index * 2] = osc_tick[0];\r
+ pclk_info->osc_count[pclk_info->count_index * 2 + 1] = osc_tick[1];\r
+ pclk_info->clk_count[pclk_info->count_index * 2] = clock_tick[0];\r
+ pclk_info->clk_count[pclk_info->count_index * 2 + 1] = clock_tick[1];\r
+ pclk_info->count_index++;\r
+ if (pclk_info->count_index >= 3)\r
+ {\r
+ pclk_info->count_index = 0;\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ 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);\r
+ 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);\r
+ count_vaild = count_vaild && (!(pclk_info->clk_count[2 * i + 2] == pclk_info->clk_count[2 * i])); /* avoid divisor==0, diffCountIsOk set false */\r
+ count_vaild = count_vaild && (!(pclk_info->osc_count[2 * i + 2] == pclk_info->osc_count[2 * i])); /* avoid divisor==0, diffCountIsOk set false */\r
+ }\r
+ if (count_vaild)\r
+ {\r
+ for (i = 0; i < 2; i++)\r
+ {\r
+ 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);\r
+ VCARE_DBG_LOG("f20kOsc[20K_%d]=(%d)", i, osc_frequency[i]);\r
+ }\r
+ if (VC_ABS(osc_frequency[0], osc_frequency[1]) <= 20)\r
+ {\r
+ pclk_info->rcosc_frequency = (osc_frequency[0] + osc_frequency[1]) / 2;\r
+ pclk_info->clk_calc_freq_status = 1;\r
+ }\r
+ return 0;\r
+ }\r
+ }\r
+ return 2;\r
+}\r
+\r
+static int drv_auto_calibration_oscclk(vc921x_clk_info *pclk_info)\r
+{\r
+ /* calibration the osc frequency by method of bisection */\r
+ if (pclk_info->clk_calc_freq_status && pclk_info->rcosc_frequency)\r
+ {\r
+ pclk_info->clk_calc_freq_status = 0;\r
+ if (pclk_info->rcosc_frequency >= VC921x_FREQUENCY_MAX)\r
+ {\r
+ if( drv921x_nto_version )\r
+ {\r
+ rcosc_min = (rcosc_mid <= 0xfe) ? rcosc_mid + 1 : 0xff;\r
+ }\r
+ else\r
+ {\r
+ rcosc_min = (rcosc_mid <= 0x7e) ? rcosc_mid + 1 : 0x7f;\r
+ }\r
+ }\r
+ else if (pclk_info->rcosc_frequency <= VC921x_FREQUENCY_MIN)\r
+ {\r
+ rcosc_max = (rcosc_mid >= 1) ? (rcosc_mid - 1) : 0;\r
+ }\r
+ else\r
+ {\r
+ pclk_info->clk_calc_status = 1; /* calibration finished mark */\r
+ pclk_info->osc_gap_cnt = 0;\r
+ rcosc_max = rcosc_mid + 2; /* 修正成功后,扩张一个调整点的范围,以便温漂时调整余量 */\r
+ rcosc_min = rcosc_mid - 2;\r
+ }\r
+ rcosc_mid = (rcosc_max + rcosc_min) / 2;\r
+ VCARE_DBG_LOG("min,max[%d,%d]~min(%d)", rcosc_min, rcosc_max, rcosc_mid);\r
+ core921x_set_rcosc_frequency(rcosc_mid);\r
+ pclk_info->rcosc_calibration = rcosc_mid;\r
+ /* 如果发生温漂,修改收缩的上下限,进行缓慢修正时钟 */\r
+ if ((pclk_info->rcosc_frequency <= VC921x_FREQUENCY_MIN) && VC_ABS(rcosc_max, rcosc_min) <= 2)\r
+ {\r
+ rcosc_min -= 2;\r
+ VCARE_DBG_LOG("!!!temp->min,max[%d,%d]~min(%d)", rcosc_min, rcosc_max, rcosc_mid);\r
+ }\r
+ if ((pclk_info->rcosc_frequency >= VC921x_FREQUENCY_MAX) && VC_ABS(rcosc_max, rcosc_min) <= 2)\r
+ {\r
+ rcosc_max += 2;\r
+ VCARE_DBG_LOG("!!!temp->min,max[%d,%d]~min(%d)", rcosc_min, rcosc_max, rcosc_mid);\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int drv_calibration_oscclk_config(vcare_ppg_device_t *pdev)\r
+{\r
+ vc921x_clk_info *pclk_info = clk_info_handle;\r
+#if 1\r
+ if (pclk_info->clk_calc_status)\r
+#else\r
+ if (pclk_info->clk_calc_status && pclk_info->osc_gap_cnt <= VC921x_CFG_CLK_CALC_GAPTIME)\r
+#endif\r
+ {\r
+ pclk_info->osc_gap_cnt++;\r
+ return 0;\r
+ }\r
+ /* calibration clk running, enter fast irq config */\r
+ drv_calibration_entry_fast_irq( );\r
+ drv_calibration_oscclk_frequency(pclk_info);\r
+ drv_auto_calibration_oscclk(pclk_info);\r
+ if( pclk_info->clk_calc_status ) /* calibration clk finished, exit fast irq config */\r
+ {\r
+ startup_inntemperature = sample_info_handle->extra_result.temp0_data;\r
+ drv_calibration_exit_fast_irq( );\r
+ }\r
+ return 1;\r
+}\r
+static void drv_calibration_clk_clear(void)\r
+{\r
+ static unsigned char is_first_run = 1;\r
+ vc921x_clk_info *pclk_info = clk_info_handle;\r
+ pclk_info->last_check_ticks = 0;\r
+ pclk_info->osc_gap_cnt = 0;\r
+ pclk_info->count_index = 0;\r
+ pclk_info->clk_calc_freq_status = 0;\r
+ /* 校验频率温度清空 */\r
+ check_cpu_tick[0]=0,check_cpu_tick[1]=0;\r
+ check_dev_tick[0]=0,check_dev_tick[1]=0;\r
+ if (is_first_run == 1)\r
+ {\r
+ is_first_run = 0;\r
+ if( drv921x_nto_version )\r
+ {\r
+ rcosc_max = 255,rcosc_min = 0,rcosc_mid = 127;\r
+ }\r
+ else\r
+ {\r
+ rcosc_max = 127,rcosc_min = 0,rcosc_mid = 63;\r
+ }\r
+ pclk_info->clk_calc_status = 0;\r
+ core921x_set_rcosc_frequency(rcosc_mid);\r
+ }\r
+ else\r
+ {\r
+ if( pclk_info->rcosc_calibration==0 ) \r
+ {\r
+ if( drv921x_nto_version )\r
+ {\r
+ rcosc_max = 255,rcosc_min = 0,rcosc_mid = 127;\r
+ }\r
+ else\r
+ {\r
+ rcosc_max = 127,rcosc_min = 0,rcosc_mid = 63;\r
+ }\r
+ pclk_info->clk_calc_status = 0;\r
+ pclk_info->rcosc_calibration=rcosc_mid;\r
+ }\r
+ core921x_set_rcosc_frequency(pclk_info->rcosc_calibration);\r
+ }\r
+}\r
+\r
+static int drv_check_running_gaptime(void)\r
+{\r
+#if VC921x_CFG_CLK_CLAC_IRQGAP_EN\r
+ int ret = 0;\r
+ unsigned short int curr_ticks = 0;\r
+ unsigned short int ticks_chk, ticks_gap = 0;\r
+ unsigned short int ticks1 = 0, ticks2 = 0;\r
+ unsigned char times_gap = 0;\r
+ core921x_read_rcosc_tick(&ticks1, &ticks2);\r
+ times_gap = (1000 * drv_info_handle->ppg_div / VC921x_DEFAULT_FREQ) * VC921x_IRQ_GAP_RATIO;\r
+ ticks_chk = (ticks2 >= ticks1) ? (ticks2 - ticks1) : (0xffff + ticks2 - ticks1);\r
+ if (ticks_chk <= 10)\r
+ {\r
+ curr_ticks = ticks1;\r
+ }\r
+ else\r
+ { /* IC问题,可能出现其中一个tick低位出现异常,如果出现异常则取另外一共tick作为运算准 */\r
+ curr_ticks = (ticks2&0xff)?(ticks2):(ticks1);\r
+ VCARE_DBG_ERR("read check tick failed(%d,%d)", ticks1, ticks2);\r
+ }\r
+ // ticks_gap = 2000;\r
+ if (0 != curr_ticks && 0 != clk_info_handle->last_check_ticks)\r
+ {\r
+ 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);\r
+ }\r
+ if (ticks_gap <= 20 * times_gap) /* 20k,1ms~20ticks */\r
+ {\r
+ VCARE_DBG_ERR("last(%d)now(%d)gap[%d<%d]", clk_info_handle->last_check_ticks, curr_ticks, ticks_gap, 20 * times_gap);\r
+ ret = -1;\r
+ }\r
+ clk_info_handle->last_check_ticks = curr_ticks;\r
+ return ret;\r
+#else\r
+ return 0;\r
+#endif\r
+}\r
+\r
+static void drv_fifo_error_softreset( void )\r
+{\r
+ static unsigned char last_add_mark=0;\r
+ unsigned char save_config[32]={0};\r
+ /* 软复位,清空所有数据,避免传入算法或者引起其他异常 */\r
+ drv_sample_result_memroy_finished( sample_info_handle );\r
+ vc921x_read_register( 0x40, save_config, sizeof(save_config) );\r
+ core921x_write_work_cmd( VC921x_STOP_WORK_CMD );\r
+ core921x_write_work_cmd( VC921x_RESET_SOFT_CMD );\r
+ drv_info_handle->read_fifo_address = 0;\r
+ vc921x_write_register( 0x40, save_config, sizeof(save_config) );\r
+ core921x_write_work_cmd( VC921x_START_WORK_CMD );\r
+ if( last_add_mark==0 )\r
+ {\r
+ last_add_mark=1;\r
+ core921x_set_rcosc_frequency( clk_info_handle->rcosc_calibration-1 );\r
+ }\r
+ else\r
+ {\r
+ last_add_mark=0;\r
+ core921x_set_rcosc_frequency( clk_info_handle->rcosc_calibration+1 );\r
+ }\r
+ #if 1\r
+ unsigned char config_debug_reg[32] = {0};\r
+ unsigned char debug_index = 0;\r
+ vc921x_read_register(0x40, config_debug_reg, 32);\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ #endif\r
+}\r
+/********************************************************************************************************\r
+ *数据读取部分\r
+ ********************************************************************************************************/\r
+static int drv_read_fifo_data(vc921x_sample_info_t *psample_result)\r
+{\r
+ int read_fifo_ret = 0;\r
+ vc921x_sample_info_t *sample_result_ptr = psample_result;\r
+ unsigned char bio_fifo_error_cnt=0;\r
+ unsigned char bio_fifo_error_flg=0;\r
+ unsigned char ps_fifo_error_flg=0;\r
+ if (!sample_result_ptr)\r
+ {\r
+ return -1;\r
+ }\r
+ /* fifo中断 */\r
+ if (0 != drv_info_handle->fifo_read_finished_sync)\r
+ {\r
+ return 0;\r
+ }\r
+ drv_info_handle->fifo_read_finished_sync = 1;\r
+ read_fifo_ret = core921x_read_fifo_data(sample_result_ptr, &drv_info_handle->read_fifo_address, drv_info_handle->write_fifo_address_bak);\r
+ 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 );\r
+ if (read_fifo_ret>=0)\r
+ {\r
+ drv_info_handle->fifo_read_data_valid = 1;\r
+ /* nto版本直接更新read_addr */\r
+ if( drv921x_nto_version )\r
+ {\r
+ if( read_fifo_ret==1 )\r
+ {\r
+ drv_info_handle->read_fifo_address = drv_info_handle->write_fifo_address_bak;\r
+ /* fifo错误,清空fifo数据 */\r
+ VCARE_DBG_LOG("===PS_FIFO_ERROR===") ;\r
+ drv_sample_result_memroy_finished( sample_info_handle );\r
+ return read_fifo_ret;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if( read_fifo_ret==1 && (drv_info_handle->int_event&VC921x_EN_EVT_FIFO) && !(drv_info_handle->int_event&VC921x_EVENT_INSAMPLE) ) /* 当出现了fifo中断,且并不是fifo数量的倍数时,可以认定为错位,进行纠错处理 */\r
+ {\r
+ drv_info_handle->read_fifo_address = drv_info_handle->write_fifo_address_bak;\r
+ drv_info_handle->fifo_read_data_valid = 2;\r
+ 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);\r
+ }\r
+ /* 20240119.校验RO_PS与fifo_PS是否异常(如果异常则可以判断为fifo异常错位:1.过度延后导致的fifo覆盖反转,2.ICfifo数据异常丢失) \r
+ * 20240229.添加bio的全部出现0xff的情况,判断为fifo异常错位\r
+ */\r
+ if( sample_result_ptr->extra_result.bioext_enwork && sample_result_ptr->extra_result.bio_fifo_num!=0 )\r
+ {\r
+ for( bio_fifo_error_cnt=0; bio_fifo_error_cnt<sample_result_ptr->extra_result.bio_fifo_num; bio_fifo_error_cnt++ )\r
+ {\r
+ VCARE_DBG_LOG("bio=%x ~ 0xff",sample_result_ptr->extra_result.bioext_buffer[bio_fifo_error_cnt] );\r
+ if( (sample_result_ptr->extra_result.bioext_buffer[bio_fifo_error_cnt]&0xff) != 0xff )\r
+ {\r
+ bio_fifo_error_cnt=0;\r
+ break;\r
+ }\r
+ }\r
+ VCARE_DBG_LOG("bio_num=%d,%d",sample_result_ptr->extra_result.bio_fifo_num, bio_fifo_error_cnt);\r
+ if( sample_result_ptr->extra_result.bio_fifo_num==bio_fifo_error_cnt )\r
+ {\r
+ bio_fifo_error_flg=1;\r
+ }\r
+ }\r
+ if( sample_result_ptr->slot_result[2].slot_enwork==2 && sample_result_ptr->slot_result[2].ppg_num!=0 )\r
+ {\r
+ 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 );\r
+ 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 )\r
+ {\r
+ ps_fifo_error_flg=1;\r
+ }\r
+ }\r
+ /* bio_fifo_error || ps_fifo_error */\r
+ if( bio_fifo_error_flg || ps_fifo_error_flg )\r
+ {\r
+ VCARE_DBG_LOG("===PS_FIFO_ERROR===") ;\r
+ drv_fifo_error_softreset();\r
+ return read_fifo_ret;\r
+ }\r
+ }\r
+ /* 20241018.在insample的时候,如果出现中断延时处理/定时器,获取到的RO_bio的值可能还未完全采样计算完成,需要从fifo中更新数据 */\r
+ 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) )\r
+ {\r
+ if( sample_result_ptr->extra_result.bioext_enwork &&\r
+ sample_result_ptr->extra_result.bioext_data != sample_result_ptr->extra_result.bioext_buffer[sample_result_ptr->extra_result.bio_fifo_num-1] )\r
+ {\r
+ sample_result_ptr->extra_result.bioext_data = sample_result_ptr->extra_result.bioext_buffer[sample_result_ptr->extra_result.bio_fifo_num-1];\r
+ VCARE_DBG_ERR("INSAMPLE_ERR_EXTBIO-modify=%d",sample_result_ptr->extra_result.bioext_data);\r
+ }\r
+ if( sample_result_ptr->extra_result.bioinn_enwork &&\r
+ sample_result_ptr->extra_result.bioinn_data != sample_result_ptr->extra_result.bioinn_buffer[sample_result_ptr->extra_result.bio_fifo_num-1])\r
+ {\r
+ sample_result_ptr->extra_result.bioinn_data = sample_result_ptr->extra_result.bioinn_buffer[sample_result_ptr->extra_result.bio_fifo_num-1];\r
+ VCARE_DBG_ERR("INSAMPLE_ERR_INNBIO-modify=%d",sample_result_ptr->extra_result.bioinn_data);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ VCARE_DBG_ERR("read_fifo_ret error(%d)", read_fifo_ret);\r
+ return read_fifo_ret;\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int drv_read_sample_param(vc921x_sample_info_t *psample_ret)\r
+{\r
+ unsigned char slot_i = 0;\r
+ unsigned char slot_current = 0, slot_res_lvl = 0;\r
+ if (0 == drv_info_handle->param_read_finished_sync)\r
+ {\r
+ core921x_read_output(psample_ret);\r
+ VCARE_DBG_LOG("env(0x)=%x-%x-%x(%d,%d,%d)", psample_ret->slot_result[0].env_data, \r
+ psample_ret->slot_result[1].env_data, \r
+ psample_ret->slot_result[2].env_data,\r
+ VC921x_ENV_CONVERT(psample_ret->slot_result[0].env_data), \r
+ VC921x_ENV_CONVERT(psample_ret->slot_result[1].env_data), \r
+ VC921x_ENV_CONVERT(psample_ret->slot_result[2].env_data));\r
+ 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);\r
+ VCARE_DBG_LOG("bio01_data=%d-%d", psample_ret->extra_result.bioinn_data, psample_ret->extra_result.bioext_data);\r
+ 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);\r
+ \r
+ psample_ret->slot_result[0].env_data = VC921x_ENV_CONVERT(psample_ret->slot_result[0].env_data);\r
+ psample_ret->slot_result[1].env_data = VC921x_ENV_CONVERT(psample_ret->slot_result[1].env_data);\r
+ psample_ret->slot_result[2].env_data = VC921x_ENV_CONVERT(psample_ret->slot_result[2].env_data);\r
+ for (slot_i = 0; slot_i < 3; slot_i++)\r
+ {\r
+ core921x_read_slot_current_res((VC921x_PPG_SLOT_I)slot_i, &slot_current, &slot_res_lvl);\r
+ psample_ret->slot_result[slot_i].slot_current = slot_current;\r
+ psample_ret->slot_result[slot_i].slot_resistance = slot_res_lvl;\r
+ adjust_info_handle[slot_i]->current = slot_current;\r
+ adjust_info_handle[slot_i]->res_level = slot_res_lvl;\r
+ }\r
+ drv_info_handle->param_read_finished_sync = 1;\r
+ VCARE_DBG_LOG("slot[0]cur%d,res%d ^ slot[1]cur%d,res%d ^ slot[2]cur%d,res%d",\r
+ psample_ret->slot_result[0].slot_current, psample_ret->slot_result[0].slot_resistance,\r
+ psample_ret->slot_result[1].slot_current, psample_ret->slot_result[1].slot_resistance,\r
+ psample_ret->slot_result[2].slot_current, psample_ret->slot_result[2].slot_resistance);\r
+ }\r
+ return 0;\r
+}\r
+\r
+static int drv_read_event_status(vc921x_drv_info *pdrv_info)\r
+{\r
+ if (0 == pdrv_info->event_read_finished_sync)\r
+ {\r
+ core921x_read_event_status(&pdrv_info->int_event, &pdrv_info->ov_status, &pdrv_info->write_fifo_address_bak, &pdrv_info->write_fifo_address_rel);\r
+ pdrv_info->event_read_finished_sync = 1;\r
+ 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 );\r
+ }\r
+ return 0;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * 中断事件处理部分调用逻辑\r
+ ********************************************************************************************************/\r
+static int drv_ppg_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev)\r
+{\r
+ int ret = 0;\r
+ vc921x_sample_info_t *sample_result_ptr = pdev->result;\r
+ vc921x_mode_ops *self_ptr = (vc921x_mode_ops *)ops_self;\r
+ drv_calibration_oscclk_config( pdev );\r
+ if( 1 == clk_info_handle->clk_calc_status )\r
+ {\r
+ ret = drv_auto_adjust_slot_config(drv_info_handle->int_event, drv_info_handle->ov_status);\r
+ }\r
+ if (ret >= 0 && 1 == clk_info_handle->clk_calc_status)\r
+ {\r
+ drv_read_fifo_data(sample_result_ptr);\r
+ }\r
+ else\r
+ {\r
+ VCARE_DBG_ERR("WORK_MODE_[%d] clk_status[%d]", self_ptr->mode, clk_info_handle->clk_calc_status);\r
+ }\r
+ return ret;\r
+}\r
+static int drv_factory_mode_handler(const void *ops_self, vcare_ppg_device_t *pdev)\r
+{\r
+ int ret = 0;\r
+ unsigned short int base =0;\r
+ vc921x_sample_info_t *sample_result_ptr = pdev->result;\r
+ drv_calibration_oscclk_config( pdev );\r
+ if (drv_info_handle->int_event & VC921x_EVENT_INTOVLOAD)\r
+ {\r
+ ret = drv_adjust_overload_max_current(sample_result_ptr, drv_info_handle->ov_status, drv_info_handle->int_event);\r
+ }\r
+ drv_read_fifo_data(sample_result_ptr);\r
+ if( 1==clk_info_handle->clk_calc_status )\r
+ {\r
+ drv_calc_bioinn_auto_addcap(drv_info_handle->int_event, sample_result_ptr);\r
+ }\r
+ base = sample_result_ptr->extra_result.bioinn_data - drv_info_handle->optimal_bio_gap;\r
+ sample_result_ptr->extra_result.bioabs_calc = VC_ABS( sample_result_ptr->extra_result.bioext_data, base );\r
+ return ret;\r
+}\r
+\r
+/*********************************************************************************************************\r
+ * DRV_API 对外功能模块部分\r
+ ********************************************************************************************************/\r
+int vc921x_drv_init_start_work(void *pdevice, int workmode, unsigned short int ppgdiv, unsigned char psdiv, unsigned char fifodiv, unsigned char dropdiv)\r
+{\r
+ vcare_ppg_device_t *pdev = (vcare_ppg_device_t *)pdevice;\r
+ char *drv_ver = NULL;\r
+ unsigned char mode_count = 0;\r
+ unsigned char mode_index = 0;\r
+ vcare_memset(sample_info_handle, 0, sizeof(vc921x_sample_info_t));\r
+ pdev->result = sample_info_handle; /* 采样指针传递 */\r
+ core921x_read_software_version(&drv_ver);\r
+ core921x_read_id(&pdev->id1, &pdev->id2); /* 0x24, 0x10 */\r
+ VCARE_DBG_LOG("[%s]devID0-2=0x%02x 0x%02x", drv_ver, pdev->id1, pdev->id2);\r
+ mode_count = sizeof(mode_ops) / sizeof(mode_ops[0]);\r
+ sel_mode_ops = NULL;\r
+ for (mode_index = 0; mode_index < mode_count; mode_index++)\r
+ {\r
+ if (workmode == mode_ops[mode_index].mode)\r
+ {\r
+ sel_mode_ops = &mode_ops[mode_index];\r
+ break;\r
+ }\r
+ }\r
+ if (!sel_mode_ops)\r
+ {\r
+ VCARE_DBG_ERR("work_mode is error(NULL),please code mode");\r
+ return -1;\r
+ }\r
+ drv_work_init(pdev, workmode, ppgdiv, psdiv, fifodiv, dropdiv, pdev->heart_algo_mode);\r
+ return 0;\r
+}\r
+int vc921x_drv_get_hwsw_infomation(char **str_drv_ver, unsigned char *pid1, unsigned char *pid2)\r
+{\r
+ core921x_read_software_version(str_drv_ver);\r
+ core921x_read_id(pid1, pid2);\r
+ return 0;\r
+}\r
+int vc921x_drv_exit_stop_work(void *pdevice)\r
+{\r
+ wear_info_handle->last_status = WEAR_STA_NONE;\r
+ core921x_write_work_cmd(VC921x_RESET_SOFT_CMD);\r
+ core921x_write_work_cmd(VC921x_STOP_WORK_CMD);\r
+ return 0;\r
+}\r
+int vc921x_drv_software_reset(void *pdevice)\r
+{\r
+ wear_info_handle->last_status = WEAR_STA_NONE;\r
+ return core921x_write_work_cmd(VC921x_RESET_SOFT_CMD);\r
+}\r
+int vc921x_drv_wakeup_work(void *pdevice)\r
+{\r
+ return core921x_write_work_cmd(VC921x_START_WORK_CMD);\r
+}\r
+int vc921x_drv_sleep_work(void *pdevice)\r
+{\r
+ wear_info_handle->last_status = WEAR_STA_NONE;\r
+ return core921x_write_work_cmd(VC921x_STOP_WORK_CMD);\r
+}\r
+int vc921x_drv_set_algo_wear_status(void *pdevice, int status)\r
+{\r
+ wear_info_handle->algo_wear_status = (status == -1) ? (WEAR_STA_DROP) : (WEAR_STA_HOLD);\r
+ return 0;\r
+}\r
+int vc921x_drv_set_acce_wear_status(void *pdevice, int status)\r
+{\r
+ /* 产生运动量,清除心率摘下标志 */\r
+ if (0 == status)\r
+ {\r
+ wear_info_handle->acce_wear_status = WEAR_STA_DROP;\r
+ }\r
+ else\r
+ {\r
+ wear_info_handle->acce_wear_status = WEAR_STA_HOLD;\r
+ wear_info_handle->algo_wear_status = WEAR_STA_HOLD;\r
+ }\r
+ return 0;\r
+}\r
+wear_status vc921x_drv_get_wear_status(void *pdevice)\r
+{\r
+ vcare_ppg_device_t *pdev = (vcare_ppg_device_t *)pdevice;\r
+ if (!sel_mode_ops)\r
+ {\r
+ return WEAR_STA_HOLD;\r
+ }\r
+ if (pdev->workmode == WORK_MODE_FACTORY0 || pdev->workmode == WORK_MODE_FACTORY1)\r
+ {\r
+ return WEAR_STA_HOLD;\r
+ }\r
+ return drv_get_wear_status(pdevice);\r
+}\r
+\r
+void vc921x_drv_get_wear_detail_result( unsigned char *bio_ret, unsigned char *algo_ret, unsigned char *acce_ret )\r
+{\r
+ *bio_ret = (VC921x_BIO_STA_HOLD==wear_info_handle->bio_wear_result)?1:0;\r
+ *algo_ret = (WEAR_STA_HOLD==wear_info_handle->algo_wear_status)?1:0;\r
+ *acce_ret = (WEAR_STA_HOLD==wear_info_handle->acce_wear_status)?1:0;\r
+}\r
+\r
+/* irq/timer callback interface. */\r
+int vc921x_drv_get_result_handler(void *pdevice)\r
+{\r
+ vcare_ppg_device_t *pdev = (vcare_ppg_device_t *)pdevice;\r
+ pdev->result = sample_info_handle;\r
+ vc921x_sample_info_t *sample_result_ptr = pdev->result;\r
+ if (!sample_result_ptr || !sel_mode_ops )\r
+ {\r
+ return -2;\r
+ }\r
+ /* 读取基础采样数据 */\r
+ drv_read_event_status(drv_info_handle);\r
+ if( drv_info_handle->int_event==0 )\r
+ {\r
+ return -1;\r
+ }\r
+ if (drv_info_handle->int_event & VC921x_EVENT_CONFLICT)\r
+ {\r
+ VCARE_DBG_ERR("work_status=%x", drv_info_handle->int_event);\r
+ return -1;\r
+ }\r
+ /* check gap time */\r
+ if (0 != drv_check_running_gaptime())\r
+ {\r
+ VCARE_DBG_ERR("running gaptime");\r
+ return -1;\r
+ }\r
+ drv_read_sample_param(sample_result_ptr);\r
+ /* 模式数据处理 */\r
+ if (sel_mode_ops->mode_handler)\r
+ {\r
+ sel_mode_ops->mode_handler(sel_mode_ops, pdev);\r
+ }\r
+ return 0;\r
+}\r
+\r
+void vc921x_drv_read_event_infomation_byIRQ(void)\r
+{\r
+ drv_read_event_status(drv_info_handle);\r
+}\r
+\r
+int vc921x_drv_is_fifo_event(void *pdevice)\r
+{\r
+ if( drv_info_handle->fifo_read_data_valid )\r
+ {\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+int vc921x_drv_is_ps_event(void *pdevice)\r
+{\r
+ if (drv_info_handle->int_event & (VC921x_EVENT_INTPS_RDY))\r
+ {\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+int vc921x_drv_is_ppg_event(void *pdevice)\r
+{\r
+ if (drv_info_handle->int_event & (VC921x_EVENT_INTPPG_STA))\r
+ {\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+int vc921x_drv_clear_reset_bio_param(void *pdevice)\r
+{\r
+ drv_infomation_param_reset();\r
+ core921x_set_bioinn_addcap( sample_info_handle, set_cap_mid );\r
+ return 0;\r
+}\r
+\r
+unsigned char vc921x_drv_check_frequency_abnormal( unsigned short dev_tick1, unsigned short dev_tick2, unsigned int cpu_tick1, unsigned int cpu_tick2 )\r
+{\r
+ static unsigned short calc_freq[2]={0};\r
+ unsigned int cpu_tick_diff=0,dev_tick_diff=0;\r
+ float gap_time_diff=0.0f;\r
+ if( !clk_info_handle->clk_calc_status ) return 0;\r
+ check_cpu_tick[1] = check_cpu_tick[0];\r
+ check_dev_tick[1] = check_dev_tick[0];\r
+ check_cpu_tick[0] = cpu_tick1;\r
+ check_dev_tick[0] = dev_tick1;\r
+ if( VC_ABS_MAX(dev_tick2,dev_tick1,0xffff)>=20 || VC_ABS_MAX(cpu_tick2, cpu_tick1, VC921x_CFG_MCU_TICK_MAX)>=32 )\r
+ {\r
+ check_cpu_tick[0]=0,check_cpu_tick[1]=0;\r
+ check_dev_tick[0]=0,check_dev_tick[1]=0;\r
+ return 0;\r
+ }\r
+ if (0 == check_cpu_tick[1]||0 == check_cpu_tick[0])\r
+ {\r
+ return 0;\r
+ }\r
+ if (0 == check_dev_tick[1]||0==check_dev_tick[0])\r
+ {\r
+ return 0;\r
+ }\r
+ cpu_tick_diff = VC_ABS_MAX( check_cpu_tick[0], check_cpu_tick[1], VC921x_CFG_MCU_TICK_MAX );\r
+ dev_tick_diff = VC_ABS_MAX( check_dev_tick[0], check_dev_tick[1], 0xFFFF );\r
+ gap_time_diff = (float)cpu_tick_diff/(float)VC921x_CFG_MCU_TICK_FREQUENCY;\r
+ calc_freq[1] = calc_freq[0];\r
+ calc_freq[0] = (float)dev_tick_diff/gap_time_diff;\r
+ if( calc_freq[0]&& calc_freq[1] && VC_ABS( calc_freq[0], calc_freq[1] )<=100 )\r
+ {\r
+ VCARE_DBG_LOG("check temp freq=[%d][%d](%d,%d)", calc_freq[0],calc_freq[1], cpu_tick_diff, dev_tick_diff );\r
+ if( 20000>=calc_freq[0] && (20000-calc_freq[0])/40 >= 60 ) /* 相较于上电时的频率温升60即返回出错 */\r
+ {\r
+ check_cpu_tick[0]=0,check_cpu_tick[1]=0;\r
+ check_dev_tick[0]=0,check_dev_tick[1]=0;\r
+ return 1;\r
+ }\r
+ }\r
+ return 0;\r
+}\r
+#define CHECK_BUFF_SIZE 20\r
+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 )\r
+{\r
+ static unsigned char fiil_mark=0;\r
+ static unsigned char fill_index=0;\r
+ static unsigned short check_innbio_buff[CHECK_BUFF_SIZE]={0};\r
+ static unsigned short check_extbio_buff[CHECK_BUFF_SIZE]={0};\r
+ static unsigned short check_tick1_buff[CHECK_BUFF_SIZE]={0};\r
+ static unsigned short check_tick2_buff[CHECK_BUFF_SIZE]={0};\r
+ unsigned int check_clk_tick[2]={0};\r
+ unsigned char i=0;\r
+ int check_ret=0;\r
+ *p_freq_ret = 0;\r
+ *p_temp_ret = 0;\r
+ \r
+ drv_read_sample_param( sample_info_handle );\r
+ drv_info_handle->param_read_finished_sync = 0; /* 读取完成之后不置同步标志,该数据仅做异常检测 */\r
+ /****** 进入临界区 ******/\r
+ check_clk_tick[0] = vc921x_get_cputimer_tick();\r
+ core921x_read_rcosc_tick( pdev_cnt1, pdev_cnt2 );\r
+ check_clk_tick[1] = vc921x_get_cputimer_tick();\r
+ /****** 退出临界区 ******/\r
+ check_innbio_buff[fill_index]=sample_info_handle->extra_result.bioinn_data;\r
+ check_extbio_buff[fill_index]=sample_info_handle->extra_result.bioext_data;\r
+ check_tick1_buff[fill_index]=*pdev_cnt1;\r
+ check_tick2_buff[fill_index]=*pdev_cnt2;\r
+ /* 检验频率温度是否正常 */\r
+ *p_freq_ret = vc921x_drv_check_frequency_abnormal( *pdev_cnt1, *pdev_cnt2, check_clk_tick[0], check_clk_tick[1] );\r
+ /* 检验内部温度是否正常 */\r
+#if 0 /* 使用上电时的内部温度和当前的相对温度进行比较 或者是 内部一致就使用绝对比较 */\r
+ 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 )\r
+#else\r
+ if( sample_info_handle->extra_result.temp0_data>0 && sample_info_handle->extra_result.temp0_data<=18000 ) /* 如果客户那边内部得温度常温都在19000左右,就可以直接判断绝对值 */\r
+#endif\r
+ {\r
+ *p_temp_ret = 1;\r
+ }\r
+ /* 校验bio/rctick是否卡死且不为0 */\r
+ if( ++fill_index >=CHECK_BUFF_SIZE )\r
+ {\r
+ fill_index=0;\r
+ fiil_mark=1;\r
+ }\r
+ if( fiil_mark )\r
+ {\r
+ for( i=0; i<CHECK_BUFF_SIZE-1; i++ )\r
+ {\r
+ if( 0==sample_info_handle->extra_result.bioext_enwork||0==sample_info_handle->extra_result.bioinn_enwork )\r
+ {\r
+ check_ret++;break; /* bio未使能,忽略++ */\r
+ }\r
+ if( check_innbio_buff[i]!=check_innbio_buff[i+1]||check_extbio_buff[i]!=check_extbio_buff[i+1] )\r
+ {\r
+ check_ret++;break; /* bio未卡死,通过++ */\r
+ }\r
+ }\r
+ for( i=0; i<CHECK_BUFF_SIZE-1; i++ )\r
+ {\r
+ if( check_tick1_buff[i]!=check_tick1_buff[i+1]||check_tick2_buff[i]!=check_tick2_buff[i+1] )\r
+ {\r
+ check_ret++;break; /* cnt未卡死,通过++ */\r
+ }\r
+ }\r
+ check_ret=(check_ret<2)?1:0; /* 至少一项已经卡死了,结果置1 */\r
+ }\r
+ return check_ret;\r
+}\r
+\r
+\r
+int vc921x_drv_finished_sync(void *pdevice)\r
+{\r
+ drv_sample_result_memroy_finished(sample_info_handle);\r
+ drv_info_handle->param_read_finished_sync = 0;\r
+ drv_info_handle->fifo_read_finished_sync = 0;\r
+ drv_info_handle->event_read_finished_sync = 0;\r
+ drv_info_handle->fifo_read_data_valid = 0;\r
+ \r
+#if 1\r
+ unsigned char config_debug_reg[32] = {0};\r
+ unsigned char debug_index = 0;\r
+ vc921x_read_register(0x40, config_debug_reg, 32);\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+ debug_index += 8;\r
+ 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],\r
+ config_debug_reg[4 + debug_index], config_debug_reg[5 + debug_index], config_debug_reg[6 + debug_index], config_debug_reg[7 + debug_index]);\r
+#endif\r
+ return 0;\r
+}\r
--- /dev/null
+/*
+ * @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 <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#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
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-02-26 09:49:05\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+/* system include */\r
+// #include "os_timer.h"\r
+// #include <simple_ble_service.h>\r
+// #include "wristband_global_data.h"\r
+// extern RtkWristBandSysType_t RtkWristbandSys;\r
+/* vcare include */\r
+#include "vcare_device_com.h"\r
+#include "vc921x_sample_result.h"\r
+\r
+static unsigned char ble_buf[2000] = {0};\r
+static unsigned short int buf_size = 0;\r
+static unsigned short int buf_index = 0;\r
+#define BLE_PACK_SIZE 200\r
+#define TIMER_BLE_GAP 10\r
+\r
+static void debug_orginal_data_send(unsigned short int size);\r
+/*********************************************************************************************************\r
+ * 调试蓝牙数据格式:\r
+ * [0~7]slot0_8bytes\r
+ * {\r
+ * .[0~2]ppg_data(h,m,l)\r
+ * .[3]ppg_mark\r
+ * .[4]resistance\r
+ * .[5]current\r
+ * .[6~7]env_bit14(h,l)\r
+ * }\r
+ * [ 8~15]slot1_8bytes{...}\r
+ * [16~23]slot2_8bytes{...}\r
+ * [24~25]bio0_2bytes(h,l)\r
+ * [26~27]bio1_2bytes(h,l)\r
+ * [28~29]ps_slot3_2bytes(h,l)\r
+ * [30~35]gsensorx/y/z(h,l) or tempRefADC, tempExtADC, temperature\r
+ * [36]hr\r
+ * [37]spo2\r
+ * [38]algo_mode\r
+ * [39]wear_bioret(bit7) | algoret(bit6) | acceret(bit5) | wear_drv(bit3~bit0)\r
+ *\r
+ * #define FRAME_SIZE 40\r
+ *********************************************************************************************************/\r
+#define ORIGINAL_DATA_DEBUG_ENABLE (1)\r
+#if ORIGINAL_DATA_DEBUG_ENABLE\r
+\r
+#define HR_PPG_SLOT 0\r
+#define IR_PPG_SLOT 1\r
+#define RD_PPG_SLOT 2\r
+#define PS_PPG_SLOT 3\r
+/* 单采样帧字节数 */\r
+#define FRAME_SIZE 40\r
+\r
+float vc921x_calc_sample_data_coefficient( unsigned int ppg_data, unsigned char ppg_I, unsigned char ppg_R, unsigned char ppg_bits );\r
+extern void vc921x_drv_get_wear_detail_result( unsigned char *bio_ret, unsigned char *algo_ret, unsigned char *acce_ret );\r
+\r
+void vc921x_send_orginal_data(vcare_ppg_device_t *pdev, gsensor_axes *pgsensor, unsigned char ppgsize)\r
+{\r
+ unsigned char i = 0;\r
+ unsigned char j = 0;\r
+ unsigned char slot_k = 0;\r
+ unsigned char psfreq_index = 0;\r
+ /* wear all result param */\r
+ unsigned char bio_result=0, algo_result=0, acce_result=0;\r
+ vc921x_sample_info_t *presult = (vc921x_sample_info_t *)pdev->result;\r
+ memset(ble_buf, 0, sizeof(ble_buf));\r
+ vc921x_drv_get_wear_detail_result( &bio_result, &algo_result, &acce_result );\r
+ unsigned char calc_slot=0;\r
+ 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,\r
+ presult->adc_resolution );\r
+\r
+ for (i = 0; i < ppgsize; i++)\r
+ {\r
+ j = 0;\r
+ /* 0-23,slot_ppg:3*8=24 */\r
+ for (slot_k = 0; slot_k < 3; slot_k++)\r
+ {\r
+ ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_SAMPLE_DATA(presult, slot_k, i)>>16)&0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_SAMPLE_DATA(presult, slot_k, i)>>8) &0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_SAMPLE_DATA(presult, slot_k, i)>>0) &0xff;\r
+ \r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->adc_resolution-16)/2;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->slot_result[slot_k].slot_resistance;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->slot_result[slot_k].slot_current;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[slot_k].env_data >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[slot_k].env_data >> 0) & 0xff;\r
+ }\r
+ /*24-29 bio:2*2 + ps:2 */\r
+ psfreq_index =(presult->wear_drop_flag)?(i/presult->hold_div):(i / presult->ps_div);\r
+ if (presult->extra_result.biofifo_mode != 0) //VC921x_BIO_NOFIFO_PS_SGL\r
+ {\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_buffer[psfreq_index] >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_buffer[psfreq_index] >> 0) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_buffer[psfreq_index] >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_buffer[psfreq_index] >> 0) & 0xff;\r
+ }\r
+ else\r
+ {\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_data >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioinn_data >> 0) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_data >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->extra_result.bioext_data >> 0) & 0xff;\r
+ }\r
+ if (presult->slot_result[2].slot_storefifo)\r
+ {\r
+ ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_PS_DATA(presult, psfreq_index) >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (VC921x_GET_SLOT_PS_DATA(presult, psfreq_index) >> 0) & 0xff;\r
+ }\r
+ else\r
+ {\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[2].u.ps_data >> 8) & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = (presult->slot_result[2].u.ps_data >> 0) & 0xff;\r
+ }\r
+/* 30-35 xyz:2*3=6*/\r
+#if 1\r
+ ble_buf[i * FRAME_SIZE + j++] = pgsensor->xData[i] >> 8;\r
+ ble_buf[i * FRAME_SIZE + j++] = pgsensor->xData[i] & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = pgsensor->yData[i] >> 8;\r
+ ble_buf[i * FRAME_SIZE + j++] = pgsensor->yData[i] & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = pgsensor->zData[i] >> 8;\r
+ ble_buf[i * FRAME_SIZE + j++] = pgsensor->zData[i] & 0xff;\r
+#else /* temp result */\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.tempref_data >> 8;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.tempref_data & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp0_data >> 8;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp0_data & 0xff;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp1_data >> 8;\r
+ ble_buf[i * FRAME_SIZE + j++] = presult->extra_result.temp1_data & 0xff;\r
+#endif\r
+ /* 36-spo2,37-hr,38-algo_mode */\r
+ ble_buf[i * FRAME_SIZE + j++] = pdev->heart_rate;\r
+ ble_buf[i * FRAME_SIZE + j++] = pdev->spo2;\r
+ ble_buf[i * FRAME_SIZE + j++] = pdev->heart_algo_mode;\r
+ /* [39]wear_bioret(bit7) | algoret(bit6) | acceret(bit5) | wear_drv(bit3~bit0) */\r
+ ble_buf[i * FRAME_SIZE + j++] = (bio_result<<7)|(algo_result<<6)|(acce_result<<5)| (pdev->wear & 0xf);\r
+ }\r
+ debug_orginal_data_send(ppgsize * FRAME_SIZE);\r
+}\r
+\r
+#endif\r
+\r
+void vc921x_send_orginal_data_debug_mark_data( void )\r
+{\r
+ for(int i=0; i<FRAME_SIZE; i++)\r
+ {\r
+ ble_buf[i]=0xff;\r
+ }\r
+ debug_orginal_data_send(FRAME_SIZE);\r
+}\r
+\r
+#define VC921x_VLOT_REF 2.5f\r
+float vc921x_calc_sample_data_coefficient( unsigned int ppg_data, unsigned char ppg_I, unsigned char ppg_R, unsigned char ppg_bits )\r
+{\r
+ float real_I = vcare_I_exponent_func(0.8f, ppg_I); /*mA*/\r
+ float real_R = vcare_R_exponent_func(100.0f, ppg_R ); /*kR*/\r
+ float calc_coeff = (ppg_data*VC921x_VLOT_REF)/(real_I*real_R*(1<<ppg_bits));\r
+ // printf( "real_I=%d(%f)mA,real_R=%d(%f)K =[%f]", ppg_I, real_I, ppg_R, real_R, calc_coeff );\r
+ return calc_coeff;\r
+}\r
+\r
+\r
+/**********************************************************************************************************\r
+ * 对苹果手机APP不能连续接收长段数据,利用软件定时器,进行分包发送\r
+ * 创建软件定时器及数据分包处理\r
+ */\r
+static void send_data_by_ble(unsigned char *pbuf, unsigned short int size)\r
+{\r
+ // if (RtkWristbandSys.gap_conn_state == GAP_CONN_STATE_CONNECTED)\r
+ // {\r
+ // hr_ble_service_send_v3_notify(RtkWristbandSys.wristband_conn_id, hr_ser_id, pbuf, size);\r
+ // }\r
+ // printf("send_data_by_ble=%d", size);\r
+}\r
+\r
+static int timer_send_data_function(void)\r
+{\r
+ unsigned short int residue_size = 0;\r
+ // 数据发送已经完成\r
+ if (buf_index >= buf_size)\r
+ {\r
+ return 0;\r
+ }\r
+ // 判断剩余数据长度是否还需要分包\r
+ residue_size = buf_size - buf_index;\r
+ if (residue_size <= BLE_PACK_SIZE)\r
+ {\r
+ send_data_by_ble(&ble_buf[buf_index], residue_size);\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ send_data_by_ble(&ble_buf[buf_index], BLE_PACK_SIZE);\r
+ buf_index += BLE_PACK_SIZE;\r
+ return 1;\r
+ }\r
+}\r
+\r
+/* 创建软件定时器,如果数据太长通过软件定时器发送 */\r
+#define TIMER_ID 0xf0\r
+static void *debug_send_timer = NULL;\r
+static void debug_send_timer_start(void)\r
+{\r
+ if (debug_send_timer)\r
+ {\r
+ os_timer_restart(&debug_send_timer, TIMER_BLE_GAP);\r
+ }\r
+}\r
+static void debug_send_timer_stop(void)\r
+{\r
+ if (debug_send_timer)\r
+ {\r
+ os_timer_stop(&debug_send_timer);\r
+ }\r
+}\r
+\r
+static void debug_send_timer_callback(void *p_handle)\r
+{\r
+ if (timer_send_data_function())\r
+ {\r
+ /* 定时器继续循环 */\r
+ os_timer_restart(&debug_send_timer, TIMER_BLE_GAP);\r
+ }\r
+ else\r
+ {\r
+ /* 关闭定时器 */\r
+ debug_send_timer_stop();\r
+ }\r
+}\r
+\r
+void vc921x_send_orginal_data_timer_init(void)\r
+{\r
+ // if (debug_send_timer == NULL)\r
+ // {\r
+ // os_timer_create(&debug_send_timer, "debug_send_timer", TIMER_ID, TIMER_BLE_GAP, false, debug_send_timer_callback);\r
+ // }\r
+ // os_timer_restart(&debug_send_timer, TIMER_BLE_GAP);\r
+ // os_timer_stop(&debug_send_timer);\r
+}\r
+\r
+static void debug_orginal_data_send(unsigned short int size)\r
+{\r
+ buf_index = 0;\r
+ buf_size = size;\r
+ printf("debug_orginal_data_send = %d", size);\r
+#if 1\r
+ if (buf_size <= BLE_PACK_SIZE)\r
+ {\r
+ send_data_by_ble(ble_buf, size);\r
+ }\r
+ else\r
+ {\r
+ send_data_by_ble(ble_buf, BLE_PACK_SIZE);\r
+ buf_index += BLE_PACK_SIZE;\r
+ debug_send_timer_start();\r
+ }\r
+#else\r
+ for (unsigned char i = 0; i * 8 < size; i++)\r
+ {\r
+ printf("[%d~%d]:%02x %02x %02x %02x , %02x %02x %02x %02x", i * 8, (i + 1) * 8,\r
+ 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]);\r
+ }\r
+#endif\r
+}\r
--- /dev/null
+/**********************************************************************************************\r
+ * @Copyright(c) 2023, Chengdu vcaresensor Microelectronics Corporation. All rights reserved.\r
+ * @Author: Tse\r
+ * @Date: 2023-09-22 17:39:10\r
+ * @LastEditTime: 2024-04-11 20:38:21\r
+ * @LastEditors: Tse\r
+ * @Description: \r
+ **********************************************************************************************/\r
+/* 驱动头文件 */\r
+#include "vc921x_driver_com.h"\r
+#include "vc921x_sample_result.h"\r
+#include "vc921x_user_app.h"\r
+/* 算法头文件 */\r
+#include "algo.h"\r
+#include "spo2Algo_16bit.h"\r
+#include "vcSportMotionIntAlgo.h"\r
+#include "custom_utils.h"\r
+#include "custom_utils.h"\r
+#include "pinctrl_porting.h"\r
+#include "hal_gpio.h"\r
+#include "vcare_device_com.h"\r
+\r
+#define VC921X_I2C_BUS I2C_BUS_2\r
+#define CHIP_I2C_ADDRESS 0x33\r
+\r
+/* vcare_ppg_device */\r
+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};\r
+/* G-Sensor Data */\r
+static gsensor_axes vc921x_gsensor_data = {0};\r
+\r
+static void vc921x_get_board_gsensor_data(unsigned short int *pgsensor_len, unsigned short int ppg_count);\r
+static unsigned int vc921x_gsensor_actuating_quantity(int x_axis, int y_axis, int z_axis);\r
+static int vc921x_heart_rate_calculate(vcare_ppg_device_t *pdev, unsigned char hr_slot );\r
+static int vc921x_spo2_calculate(vcare_ppg_device_t *pdev, unsigned char ir_slot, unsigned char red_slot);\r
+\r
+\r
+// S_AGPIO_L26 心率复位 PPG reset\r
+#define GPIO_PIN_PRG_RESET S_AGPIO_L26\r
+// S_AGPIO_R0 PRG_LED_POWER ON 心率等电源控制脚\r
+#define GPIO_PIN_PRG_LED_ON S_AGPIO_R0\r
+\r
+void tyhx_poweron(void)\r
+{\r
+ // uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+ // uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT);\r
+ // uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_HIGH);\r
+ \r
+ uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+ uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT);\r
+ uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH);\r
+ LOS_Mdelay(50);\r
+}\r
+void tyhx_poweroff(void)\r
+{\r
+ // uapi_pin_set_mode(GPIO_PIN_PRG_RESET, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+ // uapi_gpio_set_dir(GPIO_PIN_PRG_RESET, GPIO_DIRECTION_OUTPUT);\r
+ // uapi_gpio_set_val(GPIO_PIN_PRG_RESET, GPIO_LEVEL_LOW);\r
+ \r
+ uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+ uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT);\r
+ uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_LOW);\r
+\r
+ LOS_Mdelay(1);\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 驱动参数保存/读取\r
+ * @param {unsigned int} size\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_param_write_flash(unsigned char *pdata, unsigned int size)\r
+{\r
+ uapi_save_file_data("/user/userdata/vc921x.bin",pdata,size,"wb");\r
+ return 0;\r
+}\r
+int vc921x_param_read_flash(unsigned char *pdata, unsigned int size)\r
+{\r
+ uapi_get_file_data("/user/userdata/vc921x.bin",pdata,&size);\r
+ return 0;\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 内存申请\r
+ * @param {unsigned int} size\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void *vc921x_malloc(unsigned int size)\r
+{\r
+ return malloc(size);\r
+}\r
+/****************************************************************************\r
+ * @description: 内存释放\r
+ * @param {void} *ptr\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_free(void *ptr)\r
+{\r
+ if (ptr)\r
+ {\r
+ free(ptr);\r
+ }\r
+}\r
+/****************************************************************************\r
+ * @description:\r
+ * @param {unsigned char} regaddr\r
+ * @param {unsigned char*} pbuf\r
+ * @param {unsigned short int} size\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_read_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size)\r
+{\r
+ custom_i2c_read_regs(CHIP_I2C_ADDRESS, regaddr, 1 , pbuf, size, VC921X_I2C_BUS);\r
+ return 0;\r
+}\r
+int vc921x_write_register(unsigned char regaddr, unsigned char *pbuf, unsigned short int size)\r
+{\r
+ custom_i2c_write_reg(CHIP_I2C_ADDRESS, regaddr, 1, pbuf, size, VC921X_I2C_BUS);\r
+ return 0;\r
+}\r
+unsigned int vc921x_get_cputimer_tick(void)\r
+{\r
+ return uapi_systick_get_count();\r
+}\r
+\r
+/*********************************************************************************************************/\r
+/* user gsensor code */\r
+#define ENABLE_GSENSOR 0\r
+//#include "module_gsensor_stk8321.h"\r
+//#include "hub_gsensor.h"\r
+const unsigned char arry10[] = {0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12};\r
+const unsigned char arry20[] = {0, 2, 3, 5, 6, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21, 22, 24, 25, 27, 28};\r
+static void vc921x_get_board_gsensor_data(unsigned short int *pgsensor_len, unsigned short int ppg_count)\r
+{\r
+ int i = 0;\r
+ unsigned char gsensor_len = 0;\r
+ memset(&vc921x_gsensor_data, 0, sizeof(vc921x_gsensor_data));\r
+#if ENABLE_GSENSOR\r
+ /* Gsensor精度要求 ReadGsensorFIFO(+-4G11bit or +-8G12bit 256/g) 例如一个fifo周期为1sec,25组ppg数据,需要获取1sec内25组gsensor数据(40ms*25),用于匹配25组ppg信号。\r
+ 如果ppg频率高于ppg频率则对进行抽样处理,以下代码仅参考 */\r
+ AxesRaw_t gsensor_buff[40] = {0};\r
+ stk8321_get_fifo_data(&gsensor_len, gsensor_buff);\r
+ VCARE_DBG_LOG("gsensor_len[%d]-ppgsize[%d]", gsensor_len, ppg_count);\r
+ if (0 == ppg_count)\r
+ {\r
+ /* 不抽样 */\r
+ *pgsensor_len = gsensor_len;\r
+ for (i = 0; i < *pgsensor_len; i++)\r
+ {\r
+#if (BOARD_VERSION == BOARD_NEW_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_X;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_Y;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z;\r
+#elif (BOARD_VERSION == BOARD_OLD_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_Y;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_X;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z;\r
+#endif\r
+ }\r
+ }\r
+ /* 此demo中gsensor的采样频率高于ppg采样,所以正常情况下,gsensor的数量一定是大于ppg的数据。特殊情况需要考虑ppg数量大于gsensor数量。需要对gsensor数据进行补长 */\r
+ if ((gsensor_len >= ppg_count) && (ppg_count != 0))\r
+ {\r
+ *pgsensor_len = ppg_count;\r
+ /* ppglen = 10 抽样 */\r
+ if (10 == ppg_count)\r
+ {\r
+ for (i = 0; i < ppg_count; i++)\r
+ {\r
+#if (BOARD_VERSION == BOARD_NEW_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[arry10[i]].AXIS_X;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[arry10[i]].AXIS_Y;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[arry10[i]].AXIS_Z;\r
+#elif (BOARD_VERSION == BOARD_OLD_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[arry10[i]].AXIS_Y;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[arry10[i]].AXIS_X;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[arry10[i]].AXIS_Z;\r
+#endif\r
+ }\r
+ }\r
+ else /* ppglen = 20 、25抽样 */\r
+ {\r
+ for (i = 0; i < ppg_count; i++)\r
+ {\r
+#if (BOARD_VERSION == BOARD_NEW_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[arry20[i]].AXIS_X;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[arry20[i]].AXIS_Y;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[arry20[i]].AXIS_Z;\r
+#elif (BOARD_VERSION == BOARD_OLD_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[arry20[i]].AXIS_Y;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[arry20[i]].AXIS_X;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[arry20[i]].AXIS_Z;\r
+#endif\r
+ }\r
+ }\r
+ }\r
+ else if ((gsensor_len < ppg_count) && (gsensor_len != 0)) /* gsensor不足补全 */\r
+ {\r
+ *pgsensor_len = ppg_count;\r
+ for (i = 0; i < gsensor_len; i++)\r
+ {\r
+#if (BOARD_VERSION == BOARD_NEW_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_X;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_Y;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z;\r
+#elif (BOARD_VERSION == BOARD_OLD_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[i].AXIS_Y;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[i].AXIS_X;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[i].AXIS_Z;\r
+#endif\r
+ }\r
+ for (i = gsensor_len; i < ppg_count; i++)\r
+ {\r
+#if (BOARD_VERSION == BOARD_NEW_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[gsensor_len - 1].AXIS_X;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[gsensor_len - 1].AXIS_Y;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[gsensor_len - 1].AXIS_Z;\r
+#elif (BOARD_VERSION == BOARD_OLD_BOARD)\r
+ vc921x_gsensor_data.xData[i] = gsensor_buff[gsensor_len - 1].AXIS_Y;\r
+ vc921x_gsensor_data.yData[i] = gsensor_buff[gsensor_len - 1].AXIS_X;\r
+ vc921x_gsensor_data.zData[i] = gsensor_buff[gsensor_len - 1].AXIS_Z;\r
+#endif\r
+ }\r
+ }\r
+#endif\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: gsensor判断是否存在运动\r
+ * @param {int} x_axis\r
+ * @param {int} y_axis\r
+ * @param {int} z_axis\r
+ * @return {*}\r
+ ****************************************************************************/\r
+static unsigned int vc921x_gsensor_actuating_quantity(int x_axis, int y_axis, int z_axis)\r
+{\r
+ unsigned int ret_atc = 0;\r
+ unsigned int abs_sum_current = 0;\r
+ static unsigned int abs_sum_last = 0;\r
+ if (x_axis < 0)\r
+ {\r
+ x_axis = -x_axis;\r
+ }\r
+ if (y_axis < 0)\r
+ {\r
+ y_axis = -y_axis;\r
+ }\r
+ if (z_axis < 0)\r
+ {\r
+ z_axis = -z_axis;\r
+ }\r
+ abs_sum_current = x_axis + y_axis + z_axis;\r
+ if (abs_sum_last && abs_sum_current)\r
+ {\r
+ if (((abs_sum_last > abs_sum_current) ? (abs_sum_last - abs_sum_current) : (abs_sum_current - abs_sum_last)) >= 40)\r
+ {\r
+ VCARE_DBG_LOG("ACTIVE...");\r
+ ret_atc = 1;\r
+ }\r
+ }\r
+ abs_sum_last = abs_sum_current;\r
+ vc921x_drv_set_acce_wear_status(&vc921x_dev, ret_atc);\r
+ return ret_atc;\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: ppg数据加入心率算法\r
+ * @param {vcare_ppg_device_t} *pdev\r
+ * @return {*}\r
+ ****************************************************************************/\r
+static int vc921x_heart_rate_calculate(vcare_ppg_device_t *pdev, unsigned char hr_slot )\r
+{\r
+ int heartRate = 0;\r
+ unsigned char reliability = 0;\r
+ AlgoInputData_t algoInputData_t = {0};\r
+ AlgoOutputData_t algoOutputData = {0};\r
+ vc921x_sample_info_t *result_info = NULL;\r
+ vc921x_sample_slot_t *result = NULL;\r
+ unsigned char adc_param = 0;\r
+ int i = 0;\r
+ if (!pdev)\r
+ {\r
+ return -1;\r
+ }\r
+ heartRate = pdev->heart_rate;\r
+ result_info = (vc921x_sample_info_t *)pdev->result;\r
+ result = &result_info->slot_result[hr_slot]; /* 驱动中初始化slot0为心率绿光ppg */\r
+ adc_param = (result_info->adc_resolution-16)/2;\r
+ for (i = 0; i < result->ppg_num; i++)\r
+ {\r
+ algoInputData_t.axes.x = vc921x_gsensor_data.xData[i];\r
+ algoInputData_t.axes.y = vc921x_gsensor_data.yData[i];\r
+ algoInputData_t.axes.z = vc921x_gsensor_data.zData[i];\r
+ algoInputData_t.envSample = result->env_data;\r
+ algoInputData_t.ppgSample = (adc_param<<24)|VC921x_GET_SLOT_SAMPLE_DATA(result_info, hr_slot, i ); /* 驱动中初始化slot0为心率绿光ppg */\r
+ Algo_Input(&algoInputData_t, 1000 / 25, (AlgoSportMode)pdev->heart_algo_mode, 0, 0);\r
+ 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, \\r
+ algoInputData_t.axes.x, algoInputData_t.axes.y, algoInputData_t.axes.z);\r
+ }\r
+ Algo_Output(&algoOutputData);\r
+ heartRate = algoOutputData.hrData;\r
+ reliability = algoOutputData.reliability;\r
+ if (-1 == heartRate)\r
+ {\r
+ Algo_Init();\r
+ /* call heart algo wear status check,[-1] */\r
+ vc921x_drv_set_algo_wear_status(pdev, heartRate);\r
+ VCARE_DBG_LOG("ALGO_STA=-1");\r
+ }\r
+ VCARE_DBG_LOG("ALGO-HR[%d][%d]", heartRate, reliability);\r
+ return heartRate;\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 血氧PPG数据加入血氧算法\r
+ * @param {vcare_ppg_device_t} *pdev\r
+ * @return {*}\r
+ ****************************************************************************/\r
+static int vc921x_spo2_calculate(vcare_ppg_device_t *pdev, unsigned char red_slot, unsigned char ir_slot)\r
+{\r
+ vc921x_sample_info_t *result_info = NULL;\r
+ float spo2CalValue = -1.0f;\r
+ int spo2Value = 0;\r
+ unsigned char sportFlag = 0;\r
+ unsigned char adc_param = 0;\r
+ unsigned int ir_ppg_data = 0, red_ppg_data = 0;\r
+ if (!pdev)\r
+ {\r
+ return -1;\r
+ }\r
+ spo2Value = pdev->spo2;\r
+ result_info = (vc921x_sample_info_t *)pdev->result;\r
+ adc_param = (result_info->adc_resolution-16)/2;\r
+ for (int i = 0; i < result_info->slot_result[ir_slot].ppg_num; i++)\r
+ {\r
+ red_ppg_data= (adc_param<<24)|VC921x_GET_SLOT_SAMPLE_DATA(result_info, red_slot, i );\r
+ ir_ppg_data = (adc_param<<24)|VC921x_GET_SLOT_SAMPLE_DATA(result_info, ir_slot, i );\r
+ spo2CalValue = vcSpo2Calculate_16bit( red_ppg_data, ir_ppg_data, 1);\r
+ sportFlag = vcSportMotionCalculate(vc921x_gsensor_data.xData[i], vc921x_gsensor_data.yData[i], vc921x_gsensor_data.zData[i]);\r
+ if (-1 != (int)spo2CalValue && spo2CalValue <= 100 && 0 == sportFlag)\r
+ {\r
+ spo2Value = (int)spo2CalValue;\r
+ }\r
+ VCARE_DBG_LOG("[%d](%d) ppg_ir=%d, ppg_red=%d, x=%d, y=%d, z=%d", i, adc_param, \\r
+ ir_ppg_data&0xffffff, red_ppg_data&0xffffff, \\r
+ vc921x_gsensor_data.xData[i], vc921x_gsensor_data.yData[i], vc921x_gsensor_data.zData[i]);\r
+ }\r
+ VCARE_DBG_LOG("ALGO-SPO2[%d][%f]", (unsigned short int)spo2Value, spo2CalValue);\r
+ return spo2Value;\r
+}\r
+\r
+/********************************************************************************************************\r
+ * 温度功能部分,需要进行对数运算,必须包含math库\r
+ ********************************************************************************************************/\r
+#include "math.h"\r
+/* fix Rref = 10K R */\r
+#define REF_R 10\r
+/* NTC parameter */\r
+#define NTC_B 3380\r
+#define NTC_T (273.15f + 25) /* 25摄氏度下的绝对温度 */\r
+#define NTC_R 10 /* 10K */\r
+/* vc921x parameter */\r
+const unsigned char vc921x_temperature_current[] = {0, 2, 4, 8, 12, 16, 20, 24};\r
+static signed short int get_ntc_temperature(float ntc_value)\r
+{\r
+ signed short int temperature = 0;\r
+ float tmp = 0.0f;\r
+ tmp = 1 / (1 / NTC_T + (log(ntc_value / NTC_R) / NTC_B)) - 273.15f;\r
+ temperature = (signed short int)(tmp * 10);\r
+ VCARE_DBG_LOG("[CALC_TMP]=%d(%4.2f)", temperature, tmp);\r
+ return temperature;\r
+}\r
+static void vc921x_temperature_ntc_calculate(vcare_ppg_device_t *pdev)\r
+{\r
+ unsigned char ext_I = 0;\r
+ float ext_R = 0.0f;\r
+ vc921x_sample_info_t *presult_t = (vc921x_sample_info_t *)pdev->result;\r
+ if(presult_t->extra_result.tempslot1_enwork && presult_t->extra_result.temp1_data && presult_t->extra_result.tempref_data )\r
+ {\r
+ /* 采样值转换为电阻值 */\r
+ ext_I = vc921x_temperature_current[presult_t->extra_result.tempslot1_setcur];\r
+ if (0 != ext_I)\r
+ {\r
+ ext_R = (float)(20 * REF_R * presult_t->extra_result.temp1_data) / (float)(presult_t->extra_result.tempref_data * ext_I);\r
+ VCARE_DBG_LOG("ext_R=%f", ext_R);\r
+ pdev->temperature1 = get_ntc_temperature(ext_R);\r
+ }\r
+ }\r
+}\r
+\r
+/*********************************************************************************************************\r
+ * USER_API\r
+ ********************************************************************************************************/\r
+/*\r
+!!!只针对[心率/摘配带]模式,其他模式均为自适应固定时间fifo时间,注意修改之前需要确认在使用的配置模式下,fifo不会溢出,否则将无法正确获取数据\r
+if( vc921x_PS_WORK_FAST_FREQUENCY==1 ) (ms)\r
+{ps=12.5hz: fifotime=800,720,640,560...80}\r
+else\r
+{ps=5hz: fifotime=1000,800,600,400,200}\r
+*/\r
+/****************************************************************************\r
+ * @description: 初始化IC并启动工作\r
+ * @param {InitParamTypeDef} *pinitconfig\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_device_init( InitParamTypeDef *pinitconfig )\r
+{\r
+ // tyhx_poweron();\r
+ int algo_confirm_ret=0;\r
+ unsigned short int ppgdiv = 0;\r
+ unsigned char psdiv = 0;\r
+ unsigned char fifodiv = 0;\r
+ unsigned char dropdiv =20; /* drop_sta:ps_freq = ppg_hz/drop_div */\r
+ unsigned char frequency=25; /* default frequency=25hz */\r
+ /* ppg_freq=20K/ppgdiv, ps_freq=ppg_freq/psdiv, fifodiv=psfreq/fifodiv\r
+ * fifo_max=192byte. The amount of byte by once sampling must not be greater than fifo_max(192bytes).\r
+ */\r
+ extern unsigned short int VC921x_CFG_MCU_TICK_FREQUENCY; /* mcu tick frequency parameter */\r
+ extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_HOLD; /* factory calibration parameter-hold */\r
+ extern unsigned short int VC921x_WEAR_PARAM_BIO_ABS_DROP; /* factory calibration parameter-drop */\r
+ VC921x_CFG_MCU_TICK_FREQUENCY=32000;\r
+ VC921x_WEAR_PARAM_BIO_ABS_HOLD=150; /* save_diff*8/10 */\r
+ VC921x_WEAR_PARAM_BIO_ABS_DROP=100; /* save_diff*5/10 */\r
+\r
+ vc921x_dev.workmode = (work_mode)pinitconfig->work_mode;\r
+ vc921x_dev.heart_algo_mode = pinitconfig->hr_algo_mode;\r
+ switch (pinitconfig->work_mode)\r
+ {\r
+ case WORK_MODE_HR:\r
+ case WORK_MODE_SPO2:\r
+ case WORK_MODE_WEAR:\r
+ case WORK_MODE_FACTORY0:\r
+ case WORK_MODE_FACTORY1:\r
+ case WORK_MODE_UNDEFINED:\r
+ case WORK_MODE_HRSPO2:\r
+ frequency=25;\r
+ break;\r
+ case WORK_MODE_STRESS:\r
+ frequency=50;\r
+ break;\r
+ case WORK_MODE_HRV:\r
+ case WORK_MODE_BLOODPRESSURE:\r
+ frequency=100;\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ ppgdiv = 20000 / frequency; /* ppg_freq = frequency */\r
+#if (VC921x_PS_WORK_FREQUENCY_CONFIG==1)\r
+ psdiv = pinitconfig->sampling_gap_time*25/1000; /* 520ms ~ ps_div=13, fifo_div=1, 注意设置初始化参数的时间时,要估算一次fifo长度和fifo总长度的关系 */\r
+ fifodiv = 1;\r
+ if( WORK_MODE_FACTORY0==pinitconfig->work_mode || WORK_MODE_FACTORY1==pinitconfig->work_mode )\r
+ {\r
+ frequency=50;\r
+ ppgdiv = 20000 / frequency;\r
+ psdiv = pinitconfig->sampling_gap_time*25/1000; /* 注意:别修改psdiv,在有活体的配置里面,会影响活体的时间参数.所以此处通过提高一倍ppg频率,进而加快FAT模式的中断数据更新 */\r
+ fifodiv=1; \r
+ }\r
+#elif( VC921x_PS_WORK_FREQUENCY_CONFIG==0 ) /* ps=5hz */\r
+ dropdiv =20;\r
+ if (frequency == 25)\r
+ {\r
+ psdiv = 5;\r
+ fifodiv = 4; /* ppg=25hz, psbio=5hz, fifo=1.25hz,fifotime=800ms */\r
+ if( WORK_MODE_SPO2==pinitconfig->work_mode ) \r
+ {\r
+ fifodiv=2;\r
+ }\r
+ }\r
+ else if (frequency == 50)\r
+ {\r
+ psdiv = 10;\r
+ fifodiv = 2; /* ppg=50hz, psbio=5hz, fifo=2.5hz,fifotime=400ms */\r
+ }\r
+ else if (frequency == 100)\r
+ {\r
+ psdiv = 20;\r
+ fifodiv = 1; /* ppg=100hz, psbio=5hz, fifo=5hz, fifotime=200ms */\r
+ }\r
+ if( WORK_MODE_HR==pinitconfig->work_mode || WORK_MODE_WEAR==pinitconfig->work_mode )\r
+ {\r
+ fifodiv = pinitconfig->sampling_gap_time*50/10000;\r
+ }\r
+ if( WORK_MODE_HRSPO2==pinitconfig->work_mode ) \r
+ {\r
+ fifodiv=2;\r
+ }\r
+ if( WORK_MODE_FACTORY0==pinitconfig->work_mode || WORK_MODE_FACTORY1==pinitconfig->work_mode )\r
+ {\r
+ dropdiv = psdiv;\r
+ fifodiv=1; \r
+ }\r
+#endif\r
+ /* 先初始化启动心率芯片 */\r
+ vc921x_drv_init_start_work(&vc921x_dev, pinitconfig->work_mode, ppgdiv, psdiv, fifodiv, dropdiv);\r
+ vc921x_dev.dev_work_status = 1;\r
+ /* 如果需要保持测试值,比如24h的心率模式,初始化时则不清除记录值心率值,避免初始化后出现一段为0的情况 */\r
+ vc921x_dev.heart_rate = 0;\r
+ vc921x_dev.stress=0;\r
+ vc921x_dev.hrv = 0;\r
+ vc921x_dev.spo2 = 0;\r
+ vc921x_dev.blood_pressure=0;\r
+ vc921x_dev.ecg=0;\r
+ /****** algo_identify_init ******/\r
+ //algo_confirm_ret = Algo_Confirm_init( RtkWristbandSys.SecondCountRTC ); //1704038400\r
+ Algo_Init();\r
+ vcSpo2AlgoInit_16bit();\r
+ vcSportMotionAlgoInit();\r
+ VCARE_DBG_LOG("work_mode=%d,algo_confirm=%d", pinitconfig->work_mode, algo_confirm_ret );\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 获取IC及驱动相关参数\r
+ * @param {unsigned char} *pchip_id\r
+ * @param {unsigned char} *pvers_id\r
+ * @param {char} *\r
+ * @param {char} *\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_get_dev_info(unsigned char *pchip_id, unsigned char *pvers_id, char **drv_name, char **dev_name)\r
+{\r
+ /* pchip_id=0x24, pvers_id=0x10... */\r
+ vc921x_drv_get_hwsw_infomation(drv_name, pchip_id, pvers_id);\r
+}\r
+/****************************************************************************\r
+ * @description: 开始工作\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_start_work(void)\r
+{\r
+ vc921x_drv_wakeup_work(&vc921x_dev);\r
+ vc921x_dev.dev_work_status = 1;\r
+}\r
+/****************************************************************************\r
+ * @description: 停止工作\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_stop_work(void)\r
+{\r
+ vc921x_drv_sleep_work(&vc921x_dev);\r
+ vc921x_dev.dev_work_status = 0;\r
+}\r
+/****************************************************************************\r
+ * @description: 软复位\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_soft_reset(void)\r
+{\r
+ vc921x_drv_software_reset(&vc921x_dev);\r
+ vc921x_dev.dev_work_status = 0;\r
+}\r
+/****************************************************************************\r
+ * @description: 活体IC参数重置校准\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_reset_bio_param(void)\r
+{\r
+ vc921x_drv_clear_reset_bio_param(&vc921x_dev);\r
+}\r
+/****************************************************************************\r
+ * @description: 获取佩戴状态\r
+ * @return {*}\r
+ ****************************************************************************/\r
+int vc921x_usr_get_wear_status(void)\r
+{\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ {\r
+ return 1;\r
+ }\r
+ return 0;\r
+}\r
+/****************************************************************************\r
+ * @description: 定时器校验当前IC状态,如果发生异常,则重启LDO后初始化\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_check_temperature_abnormal(void)\r
+{\r
+ unsigned char check_same_ret = 0, check_freq_ret = 0, check_temp_ret = 0;\r
+ unsigned short check_cnt1 = 0, check_cnt2 = 0;\r
+ check_same_ret = vc921x_drv_read_check_temperature_abnormal(&vc921x_dev, &check_freq_ret, &check_temp_ret, &check_cnt1, &check_cnt2);\r
+ vc921x_temperature_ntc_calculate(&vc921x_dev);\r
+ vc921x_sample_info_t *result_info = (vc921x_sample_info_t *)vc921x_dev.result;\r
+ 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, \r
+ result_info->slot_result[2].u.ps_data, result_info->extra_result.bioext_data, check_cnt1, check_cnt2, \r
+ check_same_ret, check_freq_ret, check_temp_ret, vc921x_dev.temperature1);\r
+ \r
+ if (1 == vc921x_dev.dev_work_status && /* IC处于工作状态 */\r
+ ((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异常 */\r
+ || (check_cnt1 == 0 && check_cnt2 == 0) \r
+ || (1 == check_same_ret) /* bio-cnt其中之一已经不再变化 */\r
+ || (1 == check_freq_ret) /* 频率温度异常 */\r
+ || (1 == check_temp_ret) /* 内部温度异常 */\r
+ || vc921x_dev.temperature1 >= 600)) /* NTC温度异常,如果硬件NC则会固定250 */\r
+ {\r
+ /* 1.close ldo, 2.delay(200ms), 3.open ldo, 4.delay(10ms), 5.init_dev */\r
+ //extern void vcare_ldo_power_ctrl(unsigned char onoff);\r
+ //vcare_ldo_power_ctrl(0);\r
+ //platform_delay_ms(200);\r
+ //vcare_ldo_power_ctrl(1);\r
+ //platform_delay_ms(10);\r
+ 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);\r
+ }\r
+}\r
+\r
+/****************************************************************************\r
+ * @description: 中断事件处理事件\r
+ * @param {unsigned char} heart_algo_mode\r
+ * @param {unsigned char} spo2_algo_mode\r
+ * @return {*}\r
+ ****************************************************************************/\r
+void vc921x_usr_device_handler( unsigned char heart_algo_mode, unsigned char spo2_algo_mode )\r
+{\r
+ unsigned short int ppg_num = 0;\r
+ unsigned short int gsensor_num = 0;\r
+ vc921x_sample_info_t *sample_result_info_ptr = (vc921x_sample_info_t *)vc921x_dev.result;\r
+ if( !vc921x_dev.dev_work_status ) return;\r
+ VCARE_DBG_LOG("------------------");\r
+ vc921x_dev.heart_algo_mode = heart_algo_mode;\r
+ vc921x_dev.spo2_algo_mode = spo2_algo_mode;\r
+ vc921x_drv_get_result_handler(&vc921x_dev);\r
+ vc921x_dev.wear = vc921x_drv_get_wear_status(&vc921x_dev);\r
+ if (vc921x_drv_is_ps_event(&vc921x_dev) || vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ //disp_data.wear_sta = vc921x_dev.wear;\r
+ //disp_data.disp_bio_val = sample_result_info_ptr->extra_result.bioext_data;\r
+ //disp_data.disp_bio_abs = sample_result_info_ptr->extra_result.bioabs_calc;\r
+ //VCARE_DBG_LOG("bio_absgap=%d, bioext=%d", disp_data.disp_bio_abs, disp_data.disp_bio_val );\r
+ }\r
+ switch (vc921x_dev.workmode)\r
+ {\r
+ case WORK_MODE_HR:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ ppg_num = sample_result_info_ptr->slot_result[0].ppg_num;\r
+ if (ppg_num > 40)\r
+ break;\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (gsensor_num)\r
+ {\r
+ vc921x_gsensor_actuating_quantity(vc921x_gsensor_data.xData[0], vc921x_gsensor_data.yData[0], vc921x_gsensor_data.zData[0]);\r
+ }\r
+ printf("vc921x_dev.wear : %d \n",vc921x_dev.wear);\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ {\r
+ vc921x_dev.heart_rate = vc921x_heart_rate_calculate(&vc921x_dev, 0);\r
+ printf("vc921x_dev.heart_rate : %d \n",vc921x_dev.heart_rate);\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num);\r
+ }\r
+ else\r
+ {\r
+ vc921x_dev.heart_rate = 0;\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, (ppg_num?ppg_num:1) );\r
+ Algo_Init();\r
+ }\r
+ //disp_data.hr_rate = vc921x_dev.heart_rate;\r
+ }\r
+ break;\r
+ case WORK_MODE_SPO2:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ ppg_num = sample_result_info_ptr->slot_result[1].ppg_num;\r
+ if (ppg_num > 40)\r
+ break;\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ {\r
+ vc921x_dev.spo2 = vc921x_spo2_calculate(&vc921x_dev, 1, 0);\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num);\r
+ }\r
+ else\r
+ {\r
+ vc921x_dev.spo2 = 0;\r
+ vcSpo2AlgoInit_16bit();\r
+ vcSportMotionAlgoInit();\r
+ }\r
+ printf("vc921x_dev.spo2 : %d \n",vc921x_dev.spo2);\r
+ //disp_data.spo2_val = vc921x_dev.spo2;\r
+ }\r
+ break;\r
+ case WORK_MODE_HRV:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ ppg_num = sample_result_info_ptr->slot_result[0].ppg_num;\r
+ if (ppg_num > 40)\r
+ break;\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ { /*wear is hold,call_algo_func*/\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num);\r
+ }\r
+ else\r
+ { /*wear is drop,clear_algo_data*/\r
+ }\r
+ }\r
+ break;\r
+ case WORK_MODE_STRESS:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ ppg_num = sample_result_info_ptr->slot_result[0].ppg_num;\r
+ if (ppg_num > 40)\r
+ break;\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ { /*wear is hold,call_algo_func*/\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num);\r
+ }\r
+ else\r
+ { /*wear is drop,clear_algo_data*/\r
+ }\r
+ //disp_data.hr_rate = vc921x_dev.heart_rate;\r
+ }\r
+ break;\r
+ case WORK_MODE_BLOODPRESSURE:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ ppg_num = sample_result_info_ptr->slot_result[0].ppg_num;\r
+ if (ppg_num > 40)\r
+ break;\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ { /*wear is hold,call_algo_func*/\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num);\r
+ }\r
+ else\r
+ { /*wear is drop,clear_algo_data*/\r
+ }\r
+ }\r
+ break;\r
+ case WORK_MODE_WEAR:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (gsensor_num)\r
+ {\r
+ vc921x_gsensor_actuating_quantity(vc921x_gsensor_data.xData[0], vc921x_gsensor_data.yData[0], vc921x_gsensor_data.zData[0]);\r
+ }\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, sample_result_info_ptr->slot_result[2].ppg_num);\r
+ }\r
+ break;\r
+ case WORK_MODE_TEMPERATURE:\r
+ vc921x_temperature_ntc_calculate(&vc921x_dev);\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, 1);\r
+ //disp_data.temperature_value0 = vc921x_dev.temperature0;\r
+ //disp_data.temperature_value1 = vc921x_dev.temperature1;\r
+ break;\r
+ case WORK_MODE_FACTORY0:\r
+ //disp_data.gImx = sample_result_info_ptr->slot_result[0].slot_current;\r
+ //disp_data.gPre = sample_result_info_ptr->slot_result[0].u.pre_data;\r
+ //disp_data.rImx = sample_result_info_ptr->slot_result[1].slot_current;\r
+ //disp_data.rPre = sample_result_info_ptr->slot_result[1].u.pre_data;\r
+ //disp_data.ps = sample_result_info_ptr->slot_result[2].u.ps_data;\r
+ break;\r
+ case WORK_MODE_FACTORY1:\r
+ //disp_data.iImx = sample_result_info_ptr->slot_result[0].slot_current;\r
+ //disp_data.iPre = sample_result_info_ptr->slot_result[0].u.pre_data;\r
+ //disp_data.rImx = sample_result_info_ptr->slot_result[1].slot_current;\r
+ //disp_data.rPre = sample_result_info_ptr->slot_result[1].u.pre_data;\r
+ break;\r
+ case WORK_MODE_HRSPO2:\r
+ if (vc921x_drv_is_fifo_event(&vc921x_dev))\r
+ {\r
+ ppg_num = sample_result_info_ptr->slot_result[0].ppg_num;\r
+ if (ppg_num > 40)\r
+ break;\r
+ vc921x_get_board_gsensor_data(&gsensor_num, ppg_num);\r
+ if (WEAR_STA_HOLD == vc921x_dev.wear)\r
+ {\r
+ vc921x_dev.heart_rate = vc921x_heart_rate_calculate(&vc921x_dev, 0);\r
+ vc921x_dev.spo2 = vc921x_spo2_calculate(&vc921x_dev, 1, 2);\r
+ //vc921x_send_orginal_data(&vc921x_dev, &vc921x_gsensor_data, ppg_num);\r
+ }\r
+ else\r
+ {\r
+ vc921x_dev.spo2 = 0;\r
+ vcSpo2AlgoInit_16bit();\r
+ vcSportMotionAlgoInit();\r
+ vc921x_dev.heart_rate = 0;\r
+ Algo_Init();\r
+ }\r
+ //disp_data.spo2_val = vc921x_dev.spo2;\r
+ //disp_data.hr_rate = vc921x_dev.heart_rate;\r
+ }\r
+ break;\r
+ case WORK_MODE_UNDEFINED:\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ /* 同步处理数据,清理fifo_buffer内存,为下次采样做准备 */\r
+ vc921x_drv_finished_sync(&vc921x_dev);\r
+}\r
+\r
+static const dev_ops vc921x_ops =\r
+ {\r
+ .dev_init = vc921x_usr_device_init,\r
+ .get_dev_info = vc921x_usr_get_dev_info,\r
+ .start_work = vc921x_usr_start_work,\r
+ .stop_work = vc921x_usr_stop_work,\r
+ .soft_reset = vc921x_usr_soft_reset,\r
+ .get_events = NULL,\r
+ .set_slot_enable = NULL,\r
+ .reset_bio_param = vc921x_usr_reset_bio_param,\r
+ .get_wear_status = vc921x_usr_get_wear_status,\r
+ .dev_irq_handler = vc921x_usr_device_handler,\r
+ .dev_check_temp_error = vc921x_usr_check_temperature_abnormal,\r
+};\r
+\r
+vcare_ppg_device_t *get_vc921x_device(void)\r
+{\r
+ vc921x_dev.ops = &vc921x_ops;\r
+ if (vc921x_drv_memroy_alloc())\r
+ {\r
+ return NULL;\r
+ }\r
+ return &vc921x_dev;\r
+}\r
+\r
+/************************************************************************\r
+ * 以下为MCU外设初始化,任务调用\r
+ * example function task_demo_application\r
+ ***********************************************************************/\r
+#if 0\r
+/* 系统头文件 */\r
+#include "os_task.h"\r
+//.....\r
+/* 驱动头文件 */\r
+#include "task_vcare_demo.h"\r
+#include "vc921x_user_app.h"\r
+/* 心率算法头文件 */\r
+#include "algo.h"\r
+\r
+#define DEMO_TASK_PRIORITY 2 //!< Task priorities\r
+#define DEMO_TASK_STACK_SIZE 1024 * 3 //!< Task stack size\r
+void *demo_task_handle; //!< APP Task handle\r
+void *demo_queue_handle;\r
+static void board_init(void);\r
+void task_demo_application(void *pvParameters)\r
+{\r
+ T_IO_MSG demo_msg;\r
+ AlgoSportMode demo_heart_algo_mode = SPORT_TYPE_NORMAL;\r
+ unsigned char demo_spo2_algo_mode = 0;\r
+ InitParamTypeDef init_config={ 800, WORK_MODE_HR };\r
+ vcare_ppg_device_t *ppg_dev = NULL;\r
+ os_msg_queue_create(&demo_queue_handle, 0x10, sizeof(T_IO_MSG));\r
+ /* 通过芯片固定的id寄存器去获取ID,辨别不同的ppg设备,并且获取对应的设备对象 */\r
+ unsigned char id0=0,id1=0;\r
+ i2c_read(0x00,&id0,1);\r
+ i2c_read(0x01,&id1,1);\r
+ if( id0==0x24) /* id0=0x24 */\r
+ {\r
+ ppg_dev = get_vc921x_device();\r
+ }\r
+ if( ppg_dev )\r
+ {\r
+ board_init();\r
+ init_config.work_mode = WORK_MODE_HR;\r
+ //init_config.work_mode = WORK_MODE_SPO2;\r
+ //init_config.work_mode = WORK_MODE_HRV;\r
+ //init_config.work_mode = WORK_MODE_BLOODPRESSURE;\r
+ //init_config.work_mode = WORK_MODE_WEAR;\r
+ //init_config.work_mode = WORK_MODE_TEMPERATURE;\r
+ //init_config.work_mode = WORK_MODE_FACTORY0;\r
+ //init_config.work_mode = WORK_MODE_FACTORY1;\r
+ ppg_dev->ops->dev_init( &init_config );\r
+ }\r
+ while (1)\r
+ {\r
+ if (os_msg_recv(demo_queue_handle, &demo_msg, 0xFFFFFFFF) == true)\r
+ {\r
+ switch (demo_msg.subtype)\r
+ {\r
+ case DEMO_MSG_VC_IRQ_EVENT:\r
+ ppg_dev->ops->dev_irq_handler( demo_heart_algo_mode, demo_spo2_algo_mode );\r
+ break;\r
+ case DEMO_MSG_KEY_IRQ_EVENT:\r
+ //调用初始化切换工作模式,调用ppg_dev->ops->dev_init(...)进行模式切换\r
+ //demo_work_mode_switch();\r
+ break;\r
+ case DEMO_MSG_ERR_IRQ:\r
+ ppg_device->ops->dev_check_temp_error(); /* 定时校验IC工作状态,并处理异常 */\r
+ break;\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ } /* while(1) */\r
+}\r
+\r
+void task_demo_creat(void)\r
+{ \r
+ //example app creat\r
+ if (os_task_create(&demo_task_handle, "demo", task_demo_application, NULL, DEMO_TASK_STACK_SIZE, DEMO_TASK_PRIORITY) != true)\r
+ {\r
+ VCARE_DBG_LOG(" demo_task creat is failed\r\n ");\r
+ }\r
+}\r
+\r
+#endif /* end of example function */\r
)
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()
--- /dev/null
+/*
+ * @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;
+}
--- /dev/null
+/*
+ * @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 <stdint.h>
+#include <stdio.h>
+#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
--- /dev/null
+#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
--- /dev/null
+/**
+ * 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 <stdint.h>
+#include <stdio.h>
+#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
--- /dev/null
+/**
+ * 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 <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#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
+
+
--- /dev/null
+/**
+ * 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
#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"
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);
{
/**灭屏,关闭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)
void uapi_ppg_get_id(uint8_t *chip_id)
{
+#ifdef PPG_HX3695
hx3695_get_id(chip_id);
+#endif
}
#include "hal_i2c.h"