添加w9血压心率驱动,增加u8GPS蓝牙产测 1624/2 1624/head
authorpenglei <1624952103@qq.com>
Fri, 17 Jan 2025 10:23:42 +0000 (18:23 +0800)
committerpenglei <1624952103@qq.com>
Fri, 17 Jan 2025 10:23:42 +0000 (18:23 +0800)
42 files changed:
code/sdk/application/brandy/brandy_standard/service_init.c
code/sdk/application/brandy/brandy_standard/thread_pri_init.c
code/sdk/build/config/target_config/brandy/config.py
code/sdk/drivers/boards/brandy_evb/board_config/board_w9.h
code/sdk/drivers/chips/brandy/clocks/drivers/acore/clocks_config_priv.c
code/sdk/zhihui/UI/producttest/src/testhrsenson.cpp
code/sdk/zhihui/drivers/CMakeLists.txt
code/sdk/zhihui/drivers/bp/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/drivers/bp/bn02/bn02.c [new file with mode: 0644]
code/sdk/zhihui/drivers/bp/bn02/bn02.h [new file with mode: 0644]
code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c [new file with mode: 0644]
code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h [new file with mode: 0644]
code/sdk/zhihui/drivers/bp/service/bp_service.c [new file with mode: 0644]
code/sdk/zhihui/drivers/bp/service/bp_service.h [new file with mode: 0644]
code/sdk/zhihui/drivers/charge/CMakeLists.txt
code/sdk/zhihui/drivers/charge/service/charge_at_cmd.h
code/sdk/zhihui/drivers/ppg/CMakeLists.txt
code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c [new file with mode: 0644]
code/sdk/zhihui/drivers/ppg/service/ppg_service.cpp
code/sdk/zhihui/drivers/slip/cat1Service/cat1_ctl.cpp
code/sdk/zhihui/services/battery/service/battery_driver.cpp
code/sdk/zhihui/services/factorytest_service/factorytest_protocol.c
code/sdk/zhihui/services/factorytest_service/factorytest_protocol.h
code/sdk/zhihui/services/gnss/inc/NMEA0183.h
code/sdk/zhihui/services/gnss/src/NMEA0183.c
code/sdk/zhihui/utils/custom_utils.c
code/sdk/zhihui/utils/custom_utils_at_cmd.c

index dd608c9..0a7399e 100644 (file)
@@ -95,6 +95,9 @@
 #ifdef SUPPORT_AT_GYRO\r
 #include "gyro_at_cmd.h"\r
 #endif\r
+#ifdef SUPPORT_AT_BP\r
+#include "bp_at_cmd.h"\r
+#endif\r
 static void register_at_service(void)\r
 {\r
 #ifdef SUPPORT_AT_GRAPHIC\r
@@ -218,6 +221,11 @@ static void register_at_service(void)
     at_cmd_table_t *gyro_table = get_gyro_cmd_table(&gyro_cmd_count);\r
     at_cmd_add_moudle(gyro_table, gyro_cmd_count);\r
 #endif\r
+#ifdef SUPPORT_AT_BP\r
+    uint32_t bp_cmd_count;\r
+    at_cmd_table_t *bp_table = get_bp_cmd_table(&bp_cmd_count);\r
+    at_cmd_add_moudle(bp_table, bp_cmd_count);\r
+#endif\r
 }\r
 \r
 #ifdef CONFIG_OTA_UPDATE_SUPPORT\r
index 5304530..c672e65 100644 (file)
 #include "lqbp_service.h"\r
 #endif\r
 \r
+#ifdef ENABLE_BN02\r
+#include "bp_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
@@ -500,15 +504,8 @@ uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
 #endif\r
     \r
 #ifdef ENABLE_CUSTOM_I2C\r
-\r
-#ifdef ENABLE_HP4507\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
-    custom_i2c_init(HP4570_I2C_BUS);\r
-#endif\r
+    custom_i2c_init(I2C_BUS_3);\r
+    custom_i2c_init(I2C_BUS_0);\r
     custom_i2c_init(I2C_BUS_2);\r
 \r
 #ifdef MAG_MMC5603\r
@@ -527,6 +524,10 @@ uapi_pm_remove_sleep_veto(PM_ID_DEBUG);
     uapi_lqbp_service_init();\r
 #endif \r
  \r
+#ifdef ENABLE_BN02\r
+    uapi_bp_service_init();\r
+#endif\r
+\r
 #endif\r
 \r
     /*启动蓝牙ble服务,cywee有重置 mac地址的操作,会需要把 蓝牙服务开启放在cywee服务之后*/\r
index eb9a6bd..512d802 100644 (file)
@@ -547,7 +547,7 @@ target = {
                                        'FT_SINGLE_UART',
                     # 'WEARABLE_LOG_DEBUG',
                     'SUPPORT_RC_CALIBRATION',
-                    'PPG_HX3695',
+                    #'PPG_HX3695',
                     'VIB_USE_PWM',
                     'CONFIG_PWM_SUPPORT',
                     # 'ACC_LIS2DOC',
@@ -589,6 +589,7 @@ target = {
                     'NANDFLASH_F35UQA',
                     #'BLE_INSTRUCT',
                     'FACTORYTEST_SERVICE',
+                    'PPG_GH3X2X',
                     ],
                'ram_component': [
                         #'baidumapsdk',
@@ -620,7 +621,9 @@ target = {
                           "factorytest_service",
                          "hid_service",
                          "producttest",
-                        "cywee"
+                        "cywee",
+                        "ppg_sensor_gh3x2x",
+                        "bp_sensor",
                            ],
                'image_analysis': False,
                'fs_image_path':'evb',
index 73b7d58..b15d665 100644 (file)
 #include "gpio_porting.h"
 #include "platform_types.h"
 
+#ifdef ENABLE_BN02
+extern void bp_int_callback(pin_t pin, uintptr_t param);
+#endif
+
 /**
  * @addtogroup connectivity_config_boards
  * @{
@@ -98,8 +102,8 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = {
     { HAL_PIO_FUNC_SPI1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_ENBALE },   // S_MGPIO9 SPI1 CS0
     { HAL_PIO_FUNC_SPI1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE },   // S_MGPIO10 SPI1 CS1 NC
 
-    { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO11 i2c0 SCL NC
-    { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE }, // S_MGPIO12 I2C0 SDA
+    { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE }, // S_MGPIO11 i2c0 SCL NC
+    { HAL_PIO_FUNC_I2C0_M1, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, 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
 #ifdef BOARD_W9
@@ -204,7 +208,7 @@ const hal_pio_config_t g_pio_function_config[PIN_MAX_NUMBER] = {
 //   #else
     { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE },   // S_AGPIO_R2     VIBR_PWM 马达控制脚 兼容预留马达驱动复位脚
 //   #endif
-    { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_DOWN, HAL_PIO_IE_DISABLE  },   // S_AGPIO_R3     NC   
+    { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_ENBALE  },   // S_AGPIO_R3     NC   
     { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_UP, HAL_PIO_IE_DISABLE  },    // S_AGPIO_R4     tp reset
     { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE  },   // S_AGPIO_R5     touch int
     { HAL_PIO_FUNC_GPIO, HAL_PIO_DRIVE_MAX, HAL_PIO_PULL_MAX, HAL_PIO_IE_ENBALE },    // S_AGPIO_R6     PRG_INT 心率中断
@@ -317,6 +321,9 @@ const hal_gpio_config_t g_gpio_function_config[PIN_MAX_NUMBER] = {
   /**S_AGPIO_L32 GPO gps reset*/
     // {   S_AGPIO_L32, HAL_GPIO_DIRECTION_OUTPUT, HAL_GPIO_LEVEL_LOW, 0, NULL },
 #endif
+#ifdef ENABLE_BN02
+     {   S_AGPIO_R3, HAL_GPIO_DIRECTION_INPUT, NULL, GPIO_INTERRUPT_FALLING_EDGE, bp_int_callback },
+#endif
 };
 /**
  * @}
index 025bdb9..9ea7761 100644 (file)
@@ -369,7 +369,11 @@ static const system_mcu_perip_clk_t g_system_mcu_perp_clk_set_config[] = {
     {HAL_CLOCKS_APP_SPI2_MS_CLK, TURN_OFF},    // spi2 clock\r
     {HAL_CLOCKS_APP_UART_H0_CLK, TURN_ON},     // uart h0 clock\r
     {HAL_CLOCKS_APP_UART_H1_CLK, TURN_ON},     // uart h1 clock\r
+#ifdef ENABLE_BN02\r
+    {HAL_CLOCKS_APP_I2C0_CLK, TURN_ON},       // i2c0 clock\r
+#else\r
     {HAL_CLOCKS_APP_I2C0_CLK, TURN_OFF},       // i2c0 clock\r
+#endif\r
     {HAL_CLOCKS_APP_I2C1_CLK, TURN_ON},        // i2c1 clock\r
     {HAL_CLOCKS_APP_I2C2_CLK, TURN_ON},          // i2c2 clock\r
     {HAL_CLOCKS_APP_I2C3_CLK, TURN_ON},        // i2c3 clock\r
index ac738ad..6bde9cd 100644 (file)
@@ -19,6 +19,9 @@ extern "C"
 #endif
     #include "pm_veto.h"
     #include "pm.h"
+#ifdef PPG_VC9202
+    #include "vc9202_user.h"
+#endif
 #ifdef __cplusplus
 #if __cplusplus
 }
@@ -97,7 +100,7 @@ namespace OHOS
     static bool button_falg=true;
     void testhrsenson1View:: setgrayvalue(int g,int r,int ir)
     {
-        
+#ifdef PPG_HX3695
         if(label_hrsenson_value_vison!=NULL)
         {
 
@@ -110,23 +113,38 @@ namespace OHOS
             send_ppg_cmd_msg(md);
             button_falg=true;
         }
-        
+#endif
     }
     void testhrsenson1View:: setlightvalue(int g,int r,int ir)
     {
-        
+        char buf[124]={0};
+ 
         if(label_hrsenson_value_vison!=nullptr)
         {
-            char buf[124]={0};
+#ifdef PPG_HX3695    
             sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",g,r,ir);
             WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf);
             label_hrsenson_value_vison->SetText(buf);
             RootView::GetInstance()->Invalidate();
             int8_t md = PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST;
             send_ppg_cmd_msg(md);
-             button_falg=true;
-        }
-        
+            button_falg=true;
+#elif defined PPG_VC9202
+            //漏光测试
+            // send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST);
+            LOS_Msleep(500);
+            uint32_t led_cur = 0;
+            uint32_t apre_val = 0;
+            uint32_t aps_val = 9;
+            vc9202_get_leaklight_data(&led_cur,&apre_val,&aps_val);
+            send_ppg_cmd_msg(PPG_SERVICE_CMD_TYPE_STOP_PPG_TEST);
+            sprintf(buf,"leaklight:\ngreen:%d\nred:%d\nir:%d",led_cur,apre_val,aps_val);
+            WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "%s",buf);
+            label_hrsenson_value_vison->SetText(buf);
+            RootView::GetInstance()->Invalidate();
+            button_falg=true;
+#endif 
+        }    
     }
 
     UILabelButtonExt *testhrsenson1View::SetTheButton_ext(ButtonConfig_ext_t &buttonconfig)
@@ -179,7 +197,11 @@ namespace OHOS
             int8_t md = PPG_SERVICE_CMD_TYPE_DO_LEAKLIGHT_TEST;
             send_ppg_cmd_msg(md);
              button_falg=false;
+#ifdef PPG_VC9202
+            testhrsenson1View::setlightvalue(0,0,0);
+#endif
         }  
+
     }
 
      UILabel *testhrsenson1View::InitLabel(LabelConfig &labelConfig)
index 5ce5f28..d1d65e1 100644 (file)
@@ -6,8 +6,6 @@
 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)
@@ -20,3 +18,4 @@ add_subdirectory_if_exist(barometer)
 add_subdirectory_if_exist(charge)
 add_subdirectory_if_exist(charge/hp4570)
 add_subdirectory_if_exist(gyro)
+add_subdirectory_if_exist(bp)
diff --git a/code/sdk/zhihui/drivers/bp/CMakeLists.txt b/code/sdk/zhihui/drivers/bp/CMakeLists.txt
new file mode 100644 (file)
index 0000000..16351bc
--- /dev/null
@@ -0,0 +1,47 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "bp_sensor")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/bn02/bn02.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/service/bp_at_cmd.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/service/bp_service.c
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}/bn02/
+    ${CMAKE_CURRENT_SOURCE_DIR}/service/
+    
+)
+
+set(PRIVATE_HEADER
+)
+
+set(PRIVATE_DEFINES
+    TARGET_NAME="${TARGET_COMMAND}"
+    BUILD_TIME="${BUILD_TIME}"
+)
+
+set(PUBLIC_DEFINES
+SUPPORT_AT_BP
+ENABLE_BN02
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
+
+build_component()
diff --git a/code/sdk/zhihui/drivers/bp/bn02/bn02.c b/code/sdk/zhihui/drivers/bp/bn02/bn02.c
new file mode 100644 (file)
index 0000000..4330510
--- /dev/null
@@ -0,0 +1,110 @@
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2025-01-16 12:35:15\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2025-01-17 14:35:00\r
+ * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/bn02/bn02.c\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
+#include "stdint.h"\r
+#include "bn02.h"\r
+#include "custom_utils.h"\r
+#include "pinctrl_porting.h"\r
+#include "hal_gpio.h"\r
+#include "i2c.h"\r
+\r
+#define BN02_I2C_ADDR 0x05\r
+#define BN02_I2C_BUS I2C_BUS_0\r
+#define I2C_ADDR_BN02_W      0x0a\r
+#define I2C_ADDR_BN02_R      0x0b\r
+#define P_EN          S_AGPIO_L24\r
+#define P_INT         S_AGPIO_R3\r
+\r
+#define POWER_EN      S_AGPIO_R0\r
+\r
+bool Bn02_write_reg(uint8_t data)\r
+{\r
+       i2c_data_t i2c_data;\r
+       i2c_data.send_buf = &data;\r
+    i2c_data.send_len = sizeof(data);\r
+    i2c_data.receive_buf = NULL;\r
+    i2c_data.receive_len = 0;\r
+       // custom_i2c_write_reg(BN02_I2C_ADDR, 0x00, 1, &data, 1, BN02_I2C_BUS);\r
+       errcode_t ret = uapi_i2c_master_write(BN02_I2C_BUS, BN02_I2C_ADDR, &i2c_data);\r
+       if (ret != ERRCODE_SUCC)\r
+        printf("i2c Write data write fail! ret=0x%x\n", ret);\r
+\r
+    return 1;\r
+}\r
+\r
+bool Bn02_reads(uint8_t *data,int len)\r
+{\r
+       i2c_data_t i2c_data;\r
+       i2c_data.send_buf = NULL;\r
+    i2c_data.send_len = 0;\r
+    i2c_data.receive_buf = data;\r
+    i2c_data.receive_len = len;\r
+       // custom_i2c_write_reg(BN02_I2C_ADDR, 0x00, 1, &data, 1, BN02_I2C_BUS);\r
+       errcode_t ret = uapi_i2c_master_read(BN02_I2C_BUS, BN02_I2C_ADDR, &i2c_data);\r
+       if (ret != ERRCODE_SUCC) \r
+        printf("i2c read data fail! ret=0x%x\n", ret);\r
+\r
+       return 1;\r
+}\r
+\r
+static void delay_ms(int cnt)\r
+{\r
+       LOS_Mdelay(cnt);\r
+}\r
+\r
+void Bn02_Power_Ctrl(int onoff)\r
+{\r
+    if(onoff == 1)\r
+       {\r
+               uapi_pin_set_mode(POWER_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+               uapi_gpio_set_dir(POWER_EN, GPIO_DIRECTION_OUTPUT);\r
+               uapi_gpio_set_val(POWER_EN, GPIO_LEVEL_HIGH);\r
+               LOS_Mdelay(1);\r
+               uapi_pin_set_mode(P_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+               uapi_gpio_set_dir(P_EN, GPIO_DIRECTION_OUTPUT);\r
+               uapi_gpio_set_val(P_EN, GPIO_LEVEL_HIGH);\r
+               // delay_ms(20);\r
+               LOS_Mdelay(50);\r
+       }\r
+       else\r
+       {\r
+               uapi_pin_set_mode(P_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+               uapi_gpio_set_dir(P_EN, GPIO_DIRECTION_OUTPUT);\r
+               uapi_gpio_set_val(P_EN, GPIO_LEVEL_LOW);\r
+\r
+               uapi_pin_set_mode(POWER_EN, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+               uapi_gpio_set_dir(POWER_EN, GPIO_DIRECTION_OUTPUT);\r
+               uapi_gpio_set_val(POWER_EN, GPIO_LEVEL_LOW);\r
+       }\r
+}\r
+\r
+void bn02_int_handle(void)\r
+{\r
+    uint8_t bn02_buf[48] = {0};\r
+       int i;\r
+       memset(bn02_buf,0,sizeof(bn02_buf));\r
+       Bn02_reads(bn02_buf,48);\r
+       for(i = 0;i<48;i++)\r
+       {\r
+               printf("[%d]= 0x%x\n",i,bn02_buf[i]);\r
+       }\r
+}\r
+\r
+void bn02_start(void)\r
+{\r
+       Bn02_Power_Ctrl(1);\r
+       Bn02_write_reg(BN02_START_CMD);\r
+}\r
+\r
+void bn02_stop(void)\r
+{\r
+       Bn02_write_reg(BN02_STOP_CMD);\r
+       Bn02_Power_Ctrl(0);\r
+}\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/bp/bn02/bn02.h b/code/sdk/zhihui/drivers/bp/bn02/bn02.h
new file mode 100644 (file)
index 0000000..c4216a9
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2025-01-16 12:35:15\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2025-01-16 14:55:48\r
+ * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/bn02/bn02.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
+#ifndef _BN02_H_\r
+#define _BN02_H_\r
+\r
+enum\r
+{\r
+\r
+       BN02_INT_HANDLE,\r
+       BN02_INIT_ENABLE,\r
+       BN02_START,\r
+       BN02_POWER_DISABLE,\r
+       BN02_STOP,\r
+};\r
+\r
+#define BN02_START_CMD  0x04\r
+#define BN02_STOP_CMD   0x08\r
+\r
+void bn02_int_handle(void);\r
+\r
+void bn02_start(void);\r
+\r
+void bn02_stop(void);\r
+\r
+#endif // _HRS3300_H_\r
+\r
diff --git a/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c b/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.c
new file mode 100644 (file)
index 0000000..f9771b4
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-12-23 15:11:01
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2025-01-16 18:02:23
+ * @FilePath: /sdk615/code/sdk/zhihui/drivers/bp/HP4570/service/bp_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 "bp_service.h"
+#include "custom_utils.h"
+
+#define ARRAY_COUNT(array) (sizeof(array) / sizeof(array[0]))
+#define BP_MAX_ARGC            8
+#define BP_MAX_ARGV_LEN        64
+
+#define BP_SUCCESS             0
+#define BP_FAILED              (-1)
+
+static int ConvertCmdToParam(uint8_t *para, uint32_t paraLen,
+        uint8_t argv[BP_MAX_ARGC][BP_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 >= BP_MAX_ARGC) {
+                return BP_FAILED;
+            }
+        } else {
+            argv[*argc][pos] = para[i];
+            pos++;
+            if (pos >= BP_MAX_ARGV_LEN) {
+                return BP_FAILED;
+            }
+        }
+    }
+    if (pos != 0) {
+        *argc += 1;
+    }
+
+    return BP_SUCCESS;
+}
+
+static uint8_t g_bp_test_started = 0;
+static uint32_t bn02_test(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
+{
+    UNUSED(strCommonCmd);
+    uint8_t argv[BP_MAX_ARGC][BP_MAX_ARGV_LEN] = { 0 };
+    uint32_t argc = 0;
+
+    int ret = ConvertCmdToParam(para, paraLen, argv, &argc);
+    if (ret != BP_SUCCESS) {
+        PRINT("BPTEST ATCMD Convert Command Failed\n");
+        return ERRCODE_FAIL;
+    }
+
+    if (argc != 1) {
+        PRINT("BPTEST 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_bp_test_started == 1) 
+        // {
+        //     PRINT("SKIP bptest start, already start\r\n");
+        //     return 0;
+        // }
+        do_bp_service_check_msg(BP_SERVICE_CMD_START_CHECK);
+        g_bp_test_started = 1;
+    }else if (start == 2){
+        // if (g_bp_test_started == 0) 
+        // {
+        //     PRINT("SKIP bptest stop, already stopped\r\n");
+        //     return 0;
+        // }
+        do_bp_service_check_msg(BP_SERVICE_CMD_STOP_CHECK);
+        g_bp_test_started = 0 ;
+    }else if (start == 3){
+        // if (g_bp_test_started == 0) 
+        // {
+        //     PRINT("SKIP bptest stop, already stopped\r\n");
+        //     return 0;
+        // }
+        do_bp_service_check_msg(BP_SERVICE_CMD_TIMER_CHECK);
+        g_bp_test_started = 0 ;
+    }else{
+    }
+    return ERRCODE_SUCC;
+}
+static const at_cmd_table_t g_bp_cmd[] = {
+    { (char *)"AT^BN02TEST",      bn02_test, (char *)"1" },
+};
+
+at_cmd_table_t *get_bp_cmd_table(uint32_t *cmd_count)
+{
+    *cmd_count = ARRAY_COUNT(g_bp_cmd);
+    return (at_cmd_table_t *)g_bp_cmd;
+}
diff --git a/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h b/code/sdk/zhihui/drivers/bp/service/bp_at_cmd.h
new file mode 100644 (file)
index 0000000..3409d1d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-12-18 10:23:22
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2025-01-16 15:07:33
+ * @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 BP_AT_PROCESS_H
+#define BP_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_bp_cmd_table(uint32_t *cmd_count);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
diff --git a/code/sdk/zhihui/drivers/bp/service/bp_service.c b/code/sdk/zhihui/drivers/bp/service/bp_service.c
new file mode 100644 (file)
index 0000000..d319d6a
--- /dev/null
@@ -0,0 +1,132 @@
+#include "pinctrl.h"
+#include "debug_print.h"
+#include "rtc.h"
+#include "timer.h"
+#include "systick.h"
+
+#include "tcxo.h"
+
+#include "cmsis_os2.h"
+#include "input_app.h"
+#include "bp_service.h"
+#include "custom_utils.h"
+#include "bn02.h"
+// #include "custom_runtime.h"
+/***
+ * 其他cmd在Header里定义,对外开放
+*/
+
+#define BP_CHECK_MS 40
+
+osTimerId_t g_bp_service_timer = NULL;
+
+static bool g_bp_sensor_exist = false;
+
+static bool g_bat_timer_is_running = false;
+
+static unsigned long g_app_queue= 0xFFFFFFFF;
+
+static bool bp_service_running_stat = false;
+
+void do_bp_service_check_msg(int cmd);
+
+static void bp_service_check_timer_callback(void* data)
+{
+    do_bp_service_check_msg(BP_SERVICE_CMD_TIMER_CHECK);
+}
+
+void do_bp_service_check_msg(int cmd)
+{
+    int ret;
+    if (g_bp_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 bp Check MSG 0x%02X send failed! err=0x%x! \r\n",cmd, ret);
+    }
+    
+}
+
+static void bp_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 == BP_SERVICE_CMD_TIMER_CHECK) {
+            PRINT("bn02_int_handle \n");
+            bn02_int_handle();
+        }else if (mail.comm.app == BP_SERVICE_CMD_START_CHECK){
+            PRINT("bn02_start \n");
+            bn02_start();
+            if(g_bp_service_timer)
+                osTimerStart(g_bp_service_timer,150);
+        }else if (mail.comm.app == BP_SERVICE_CMD_STOP_CHECK){
+            PRINT("bn02_stop \n");
+            bn02_stop();
+            if(g_bp_service_timer)
+                osTimerStop(g_bp_service_timer);
+        }
+    }
+}
+void create_bp_queue(void)
+{
+
+    if (osal_msg_queue_create("bp_service_queue", APP_BOARD_MSG_COUNT, &g_app_queue,
+                              0, sizeof(common_notify_mail_t)) != ERRCODE_SUCC) {
+        PRINT("[bp][service] app create mail fail\n");
+    }
+}
+
+#define BP_BOARD_TASK_SIZE   0x1000
+errcode_t uapi_bp_service_init(void)
+{
+    PRINT("uapi_bp_service_init !\r\n");
+
+    g_bp_sensor_exist = true;
+
+    app_task_definition_t taskcfg={0};
+    taskcfg.create_queue_handle = create_bp_queue;
+    taskcfg.attr.name="bp_service";
+    taskcfg.attr.priority = osPriorityBelowNormal4;
+    taskcfg.attr.stack_size = BP_BOARD_TASK_SIZE;
+    taskcfg.func = bp_service_check_task;
+    taskcfg.use_mem = USE_EXTEND_MEM;
+    
+    errcode_t ret=uapi_create_osThread_custom(&taskcfg);
+    if(ret != ERRCODE_SUCC)
+    {
+        PRINT("create bp_service failed %d!\r\n",ret);
+        return ERRCODE_FAIL;
+    }
+
+    // g_bp_service_timer = osTimerNew((osTimerFunc_t)bp_service_check_timer_callback, osTimerPeriodic, NULL, NULL);
+
+    return ERRCODE_SUCC;
+}
+
+void bp_int_callback(pin_t pin, uintptr_t param)
+{
+    PRINT("bp_int_callback %d 0x%X\n",pin,param);
+    uapi_gpio_clear_interrupt(pin);
+    do_bp_service_check_msg(BP_SERVICE_CMD_TIMER_CHECK);
+}
+
+// void bp_service_service_resume(void)
+// {
+//     MMC_LOG("bp_service_service resume!\r\n");
+//     bp_service_check_timer_callback(0);
+// }
+// void bp_service_service_suspend(void)
+// {
+//     MMC_LOG("bp_service_service suspend!\r\n");
+// }
\ No newline at end of file
diff --git a/code/sdk/zhihui/drivers/bp/service/bp_service.h b/code/sdk/zhihui/drivers/bp/service/bp_service.h
new file mode 100644 (file)
index 0000000..ba02c9a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-12-23 15:11:01
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2025-01-16 17:39:43
+ * @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 BP_SERVICE_H__
+#define BP_SERVICE_H__
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#include "stdint.h"
+#include "errcode.h"
+
+#define BP_SERVICE_CMD_START_CHECK 0x12
+#define BP_SERVICE_CMD_STOP_CHECK 0x13
+#define BP_SERVICE_CMD_TIMER_CHECK 0x11
+
+errcode_t uapi_bp_service_init(void);
+void bp_int_callback(pin_t pin, uintptr_t param);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
index b100dae..97149a1 100644 (file)
@@ -26,6 +26,7 @@ set(PRIVATE_DEFINES
 
 set(PUBLIC_DEFINES
 SUPPORT_AT_CHARGE
+ENABLE_HP4507
 )
 
 # use this when you want to add ccflags like -include xxx
index e54f7be..0e55c55 100644 (file)
@@ -2,7 +2,7 @@
  * @Author: penglei 1624952103@qq.com
  * @Date: 2024-12-18 10:23:22
  * @LastEditors: penglei 1624952103@qq.com
- * @LastEditTime: 2024-12-24 17:58:19
+ * @LastEditTime: 2025-01-16 15:07:23
  * @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
  */
@@ -14,8 +14,8 @@
  * History: \n
  * 2022-07-20, Create file. \n
  */
-#ifndef HX3509_AT_PROCESS_H
-#define HX3509_AT_PROCESS_H
+#ifndef CHARGE_AT_PROCESS_H
+#define CHARGE_AT_PROCESS_H
 
 #include <stdint.h>
 #include <stdio.h>
index 958ca1f..88975a2 100644 (file)
@@ -1,3 +1,6 @@
 add_subdirectory_if_exist(service)
 add_subdirectory_if_exist(hx3695)
-add_subdirectory_if_exist(ppgBleService)
\ No newline at end of file
+add_subdirectory_if_exist(ppgBleService)
+add_subdirectory_if_exist(vc9202)
+add_subdirectory_if_exist(vc921x)
+add_subdirectory_if_exist(gh3x2x)
\ No newline at end of file
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt b/code/sdk/zhihui/drivers/ppg/gh3x2x/CMakeLists.txt
new file mode 100644 (file)
index 0000000..1cea5b7
--- /dev/null
@@ -0,0 +1,57 @@
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) @CompanyNameMagicTag 2022-2023. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "ppg_sensor_gh3x2x")
+
+if("PPG_GH3X2X" IN_LIST DEFINES)
+
+set(PUBLIC_HEADER
+    ${CMAKE_CURRENT_SOURCE_DIR}/inc
+)
+
+set(SOURCES ${SOURCES}
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_adt.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_agc.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_demo.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_drv.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_lead_off.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_afe_user.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/src/gh3x2x_hal.c
+)
+
+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
+)
+
+build_component()
+
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_adt.h
new file mode 100644 (file)
index 0000000..d165a76
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef _GH3X2X_AFE_ADT_H_\r
+#define _GH3X2X_AFE_ADT_H_\r
+#include "gh3x2x_afe_drv.h"\r
+ \r
+\r
+#define __HARD_ADT_WAER_ON_THRD__               8600000\r
+#define __HARD_ADT_WAER_OFF_THRD__              8538608\r
+#define __HARD_ADT_WAER_ON_DIFF_THRD__          100000\r
+\r
+\r
+\r
+typedef enum\r
+{\r
+    WEAR_DETECT_WEAR_ON = 0,   /**< detect wear on */\r
+    WEAR_DETECT_WEAR_OFF,      /**< detect wear off */\r
+} EMWearDetectType;\r
+\r
+typedef enum\r
+{\r
+    WEAR_STATUS_WEAR_ON = 0,   /**< detect wear on */\r
+    WEAR_STATUS_WEAR_OFF,      /**< detect wear off */\r
+} EMWearStatus;\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+GS8  GH3x2xAdtAlgoInit(void);\r
+GS8 GH3x2xAdtAlgoDeinit(void);\r
+void GH3x2xAdtAlgoExe(GU32* punRawdata,EMWearStatus* pemWearStatus);\r
+\r
+\r
+\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_agc.h
new file mode 100644 (file)
index 0000000..ae3bd7b
--- /dev/null
@@ -0,0 +1,264 @@
+#ifndef _GH3X2X_AFE_AGC_H_\r
+#define _GH3X2X_AFE_AGC_H_\r
+#include "gh3x2x_afe_drv.h"\r
+#include <string.h> \r
+\r
+\r
+#define __SUPPORT_SOFT_AGC_CONFIG__          1\r
+#define GH3X2X_NEW_AGC_SLOT_NUM_LIMIT       (8)\r
+#define GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT   (32-8)\r
+\r
+#define  GH3X2X_LED_AGC_DISABLE             (0)\r
+#define  GH3X2X_LED_AGC_ENABLE              (1)\r
+\r
+\r
+/// led agc adc num max\r
+#define  GH3X2X_AGC_ADC_NUM_MAX             (4u)\r
+\r
+/// led agc gain limit number\r
+#define  GH3X2X_AGC_LIMIT_NUM_MAX           (4u)\r
+\r
+/// raw data base line value\r
+#define  GH3X2X_DATA_BASE_LINE              (8388608)   //2^23 \r
+\r
+/// sys sample rate, 32kHz\r
+#define  GH3X2X_SYS_SAMPLE_RATE             (32000)\r
+ \r
+/* slot register ctrl index */\r
+#define  GH3X2X_SLOT_REG_CTRL_0             (0)    /**< slot x ctrl 0 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_1             (1)    /**< slot x ctrl 1 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_2             (2)    /**< slot x ctrl 2 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_3             (3)    /**< slot x ctrl 3 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_4             (4)    /**< slot x ctrl 4 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_5             (5)    /**< slot x ctrl 5 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_6             (6)    /**< slot x ctrl 6 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_7             (7)    /**< slot x ctrl 7 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_8             (8)    /**< slot x ctrl 8 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_9             (9)    /**< slot x ctrl 9 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_10            (10)   /**< slot x ctrl 10 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_11            (11)   /**< slot x ctrl 11 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_12            (12)   /**< slot x ctrl 12 reg */\r
+#define  GH3X2X_SLOT_REG_CTRL_13            (13)   /**< slot x ctrl 13 reg */\r
+\r
+#define GH3X2X_BG_LEVEL_BIT_MASK            (0x0030)\r
+#define GH3X2X_ADC_BG_CANCEL_32_UA          (0x0)\r
+#define GH3X2X_ADC_BG_CANCEL_64_UA          (0x1)\r
+#define GH3X2X_ADC_BG_CANCEL_128_UA         (0x2)\r
+#define GH3X2X_ADC_BG_CANCEL_256_UA         (0x3)\r
+\r
+/// amb slot select\r
+#define GH3X2X_AGC_AMB_SLOT_DISABLE         (0x0)\r
+#define GH3X2X_AGC_AMB_SLOT_USER_DEFINED    (0x1)\r
+#define GH3X2X_AGC_AMB_SLOT_FOLLOW_CFG      (0x2)\r
+\r
+/// get bits data\r
+#define GH3X2X_GET_REG_BITS_U16(reg_data, lsb, msb)       (((reg_data) & ((0xFFFF << (lsb)) & \\r
+                                                            (0xFFFF >> (15 - (msb))))) >> (lsb))\r
+\r
+/// set bits data\r
+#define GH3X2X_SET_REG_BITS_U16(reg, lsb, msb, value)     ((reg) = (((reg) & ((0xFFFF << (lsb)) ^ \\r
+                                                                  (0xFFFF >> (15 - (msb))))) | ((value) << (lsb))))\r
+\r
+/// get adc gain\r
+#define GH3X2X_GET_ADC_GAIN(reg_data, adc_no)             GH3X2X_GET_REG_BITS_U16((reg_data), ((adc_no) * 4), \\r
+                                                                ((adc_no) * 4 + 3))\r
+\r
+/// set adc gain\r
+#define GH3X2X_SET_ADC_GAIN(reg_data, adc_no, gain)       GH3X2X_SET_REG_BITS_U16((reg_data), ((adc_no) * 4), \\r
+                                                                ((adc_no) * 4 + 3), (gain))\r
+\r
+/// get bg cancel i_dacfs\r
+#define GH3X2X_GET_BGC_I_DACFS(reg_data, adc_no)          GH3X2X_GET_REG_BITS_U16((reg_data), ((adc_no) << 1), \\r
+                                                                ((adc_no) * 2 + 1))\r
+\r
+/// set bg cancel i_dacfs\r
+#define GH3X2X_SET_BGC_I_DACFS(reg_data, adc_no, i_dacfs) GH3X2X_SET_REG_BITS_U16((reg_data), ((adc_no) * 2), \\r
+                                                              ((adc_no) * 2 + 1), (i_dacfs))\r
+                                                                                         \r
+#define ABS(x) ((x) > 0 ? (x) : -(x))\r
+\r
+/// transfer int to float\r
+#define GH3X2X_TRANS_INT_TO_FLOAT           (1.0f)\r
+\r
+/// agc calc seconds (250ms)\r
+#define GH3X2X_AGC_CALC_SECONDS             (0.25f)\r
+\r
+/// agc bgc donw cnt, 5s\r
+#define GH3X2X_AGC_BGC_DOWN_CNT             (20)\r
+\r
+/// slot tia gain val min\r
+#define GH3X2X_AGC_GAIN_MIN_VAL             (0)\r
+\r
+/// slot tia gain val max, 5s, equal (GH3X2X_SLOT_TIA_GAIN_VAL_MAX - 1)\r
+#define GH3X2X_AGC_GAIN_MAX_VAL             (12)\r
+\r
+/// Less than thr, include rawdata < thr\r
+#define GH3X2X_AGC_EXCD_FLAG_LESS           (0x01)\r
+\r
+/// greater than thr, include rawdatamix > thr | rawdata > thr\r
+#define GH3X2X_AGC_EXCD_FLAG_GREATER        (0x06)\r
+\r
+/// AGC failure reason\r
+#define GH3X2X_AGC_FAILURE_REASON_1         (0x1) \r
+#define GH3X2X_AGC_FAILURE_REASON_2         (0x2)\r
+#define GH3X2X_AGC_FAILURE_REASON_4         (0x4)\r
+#define GH3X2X_AGC_FAILURE_REASON_5         (0x5)\r
+#define GH3X2X_AGC_FAILURE_REASON_6         (0x6)\r
+\r
+#define GH3X2X_AGC_CHECK_EN_BITS(x)         (((x) & (0x03 << 8)) != 0)      /**< check enable bits of ctrl3 */\r
+#define GH3X2X_AGC_GET_SRC_BITS(x)          (((x) >> 6) & 0x03)             /**< get agc src bits of ctrl3 */\r
+#define GH3X2X_AGC_CHECK_BG_2X2_BITS(x)     (((x) & (0x03 << 4)) == 0x03)   /**< check 2x2 bg lvl bits of ctrl3 */\r
+#define GH3X2X_AGC_SET_SRC_BITS(x, n)       (((x) & 0xFF3Fu) | ((n) << 6u)) /**< set agc src bits of ctrl3 */\r
+\r
+#define GH3X2X_AGC_GET_DONE_FAIL_BIT(x, i)  (((x) >> (i)) & 0x01)           /**< get tune done/fail bit of flag */\r
+#define GH3X2X_AGC_REG_BIT(x, i)            (((x) >> (i)) & 0x01)           /**< get reg bit value */\r
+#define GH3X2X_AGC_GET_RESULT_BITS(x, i)    (((x) >> (i)) & 0x07)           /**< get result bits of flag  */\r
+#define GH3X2X_AGC_RESULT_BITS_SIZE         (3u)                           /**< one result 3 bits size of flag  */\r
+\r
+#define GH3X2X_FRAME_FLAG_NUM                     8\r
+#define GH3X2X_AGC_MAIN_SLOT_NUM                  8\r
+\r
+/**\r
+ * @brief soft lead result\r
+ */\r
+typedef struct\r
+{\r
+    GU8 uchAmbSampleEn  : 2;                /**< AMB sampling enable */\r
+    GU8 uchAmbSlot      : 3;                /**< slot of amb sampling */\r
+    GU8 uchRes          : 3;                /**< reserved */\r
+} STAmbSlotCtrl;\r
+ \r
+ /**\r
+ * @brief gain limit\r
+ */\r
+typedef struct\r
+{\r
+    GU8 uchGainLimitBg32uA  : 4;          /**< gain limit bg current */\r
+    GU8 uchGainLimitBg64uA  : 4;          \r
+    GU8 uchGainLimitBg128uA : 4;        \r
+    GU8 uchGainLimitBg256uA : 4;\r
+} STSoftAgcGainLimit;\r
+\r
+ /**\r
+  * @brief soft agc parameter\r
+  */\r
+typedef struct\r
+{\r
+    GU8 uchSlotxSoftAgcAdjEn;              /**< soft agc enable */\r
+    GU8 uchSlotxSoftBgAdjEn;               /**< soft bg cancel adjust enable */\r
+    STAmbSlotCtrl stAmbSlotCtrl;           /**< amb slot ctrl */\r
+    GU8 uchRes0;                           /**< reserved */\r
+    GU8 uchSpo2RedSlotCfgEn;\r
+    GU8 uchSpo2IrSlotCfgEn;\r
+    STSoftAgcGainLimit stSoftAgcGainLimit; /**< soft gain limit */\r
+    GU32 unAgcTrigThd_H;                   /**< trig threshold(high) of soft agc */\r
+    GU32 unAgcTrigThd_L;                   /**< trig threshold(low) of soft agc */\r
+    GU32 unAgcRestrainThd_H;               /**< restrain threshold(high) of soft agc */\r
+    GU32 unAgcRestrainThd_L;               /**< restrain threshold(low) of soft agc */\r
+} STSoftAgcCfg;\r
+\r
+\r
+\r
+typedef struct\r
+{\r
+    GU8 uchEnable;\r
+    GU8 uchSpo2ChnlIndex;      //0: is not spo2 channel   N(N > 0):  is spo2 channl  \r
+    GU8 uchSlotAdc;\r
+    GU8  uchCurrentTiaGain;\r
+    GU8  uchCurrentDrv;\r
+    GU8  uchTiaGainUpLimit;\r
+    GU8  uchHaveBakRegFlag;\r
+    GU8  uchBakRegAgcEn;\r
+    GU8  uchBakRegAgcSrc;\r
+    GU8  uchBakRegLedCurrentMin;\r
+    GU8  uchBakRegLedCurrentMax;\r
+    GU8  uchBakTiaGain;\r
+} STGh3x2xNewAgcMainChnlInfo;\r
+\r
+typedef struct \r
+{\r
+    GU16 Sat_CheckCnt[GH3X2X_AGC_MAIN_SLOT_NUM];  /* num of data checked*/\r
+    GU16 Sat_cnt[GH3X2X_AGC_MAIN_SLOT_NUM]; /* sat num of each channel*/\r
+    GU8 Sat_flag; /* sat flag one bit each channel*/\r
+} STGh3x2xNewAgcMainChnlSat;\r
+\r
+typedef struct\r
+{\r
+    GU32 unMaxRawdata;\r
+    GU32 unMinRawdata;\r
+    GU32 unSumAdjust;     //  cacluate drv current and gain\r
+    GU32 unSumTrige;      //  judge whether AGC\r
+    GU32 unRawdataMean;\r
+    GU32 unLastRawdataMean;\r
+    GU16 usSampleRate;\r
+    GU16 usAnalysisCnt;   // numble of nalysis data\r
+    GU8 uchHaveAgcAtLastReadPrd;    //0: no agc action at last fifo read period  1: have agc action at last fifo read preiod\r
+    GU8 uchDropFlag;\r
+} STGh3x2xNewAgcMainChnlMeanInfo;\r
+\r
+typedef struct\r
+{\r
+    GU8  uchIniteFirst;   // inite first time   0:yes   1:not\r
+    GU8  uchSeconsCnt;    // \r
+} STGh3x2xNewAgcMainChnlIdaelAdjInfo;\r
+\r
+typedef struct\r
+{\r
+    GU32 unLastRawdata;\r
+    GU32 unLastLastRawdata;\r
+    GU32 unRawdataSum;\r
+    GU16 usAnalysisCnt;\r
+    GU16 usMoreThanUpLimitPointCnt;\r
+    GU16 usMoreThanUpLimitPointCntForBiggerGain;\r
+    GU16 usTrigeUpLimitForBiggerGain;   //  rawdate/256\r
+    GU8 uchEn;\r
+    GU8 uchSlotAdcNo;\r
+    GU8 uchCurrentGain;\r
+}STGh3x2xNewAgcSubChnlRxInfo;\r
+\r
+\r
+void GH3X2X_LedAgcReset(void);\r
+void GH3X2X_LedAgcPramWrite(GU16 usRegAddr, GU16 usRegData);\r
+void GH3X2X_LedAgcInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo);\r
+void GH3X2X_LedAgc_Close(void);\r
+void GH3X2X_LedAgc_Open(void);\r
+void Gh3x2xNewAgcSubChnlModuleReset(void);\r
+GU8 GH3x2xNewAgcSetNewSubChnl(GU8 uchSlotNo, GU8 uchRxEn, STGh3x2xAgcInfo *STGh3x2xAgcInfo);\r
+void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo);\r
+void GH3X2X_LedAgcInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo);\r
+void GH3X2X_LedAgcPramConfig(STSoftAgcCfg* stSoftAgcCfg);\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_demo.h
new file mode 100644 (file)
index 0000000..e1d45e9
--- /dev/null
@@ -0,0 +1,68 @@
+#ifndef __GH3X2X_AFE_DEMO_H__\r
+#define __GH3X2X_AFE_DEMO_H__\r
+#include "gh3x2x_afe_drv.h"\r
+\r
+/**\r
+ * @brief channel map for function id\r
+ */\r
+#define GH3X2X_FUNC_OFFSET_ADT              (0)    /**<0 ADT FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_HR               (1)    /**<1 HR FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_HRV              (2)    /**<2 HRV FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_HSM              (3)    /**<3 HSM FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_FPBP             (4)    /**<4 BPD FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_PWA              (5)    /**<5 PFA FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_SPO2             (6)    /**<6 SPO2 FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_ECG              (7)    /**<7 ECG FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_PWTT             (8)    /**<8 PWTT FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_SOFT_ADT_GREEN   (9)    /**<9 SOFT ADT GREEN FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_BT               (10)   /**<10 BT FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_RESP             (11)   /**<11 RESP FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_AF               (12)   /**<12 AF ADT FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_TEST1            (13)   /**<13 TEST1 FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_TEST2            (14)   /**<14 TEST2 ADT FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_SOFT_ADT_IR      (15)   /**<15 SOFT ADT IR FUNC_OFFSET */\r
+#define GH3X2X_FUNC_OFFSET_RS0              (16)   /**<16 */\r
+#define GH3X2X_FUNC_OFFSET_RS1              (17)   /**<17 */\r
+#define GH3X2X_FUNC_OFFSET_RS2              (18)   /**<18 */\r
+#define GH3X2X_FUNC_OFFSET_LEAD_DET         (19)   /**<19 */\r
+#define GH3X2X_FUNC_OFFSET_MAX              (20) \r
+\r
+/* Function mode. */\r
+#define   GH3X2X_NO_FUNCTION                        (0)                                             /**<0x00000000 NO function */\r
+#define   GH3X2X_FUNCTION_ADT                       ((0x1) << (GH3X2X_FUNC_OFFSET_ADT))             /**<0x00000001 ADT function */\r
+#define   GH3X2X_FUNCTION_HR                        ((0x1) << (GH3X2X_FUNC_OFFSET_HR))              /**<0x00000002 HR function */\r
+#define   GH3X2X_FUNCTION_HRV                       ((0x1) << (GH3X2X_FUNC_OFFSET_HRV))             /**<0x00000004 HRV function */\r
+#define   GH3X2X_FUNCTION_HSM                       ((0x1) << (GH3X2X_FUNC_OFFSET_HSM))             /**<0x00000008 HSM function */\r
+#define   GH3X2X_FUNCTION_FPBP                      ((0x1) << (GH3X2X_FUNC_OFFSET_FPBP))            /**<0x00000010 FPBP function */\r
+#define   GH3X2X_FUNCTION_PWA                       ((0x1) << (GH3X2X_FUNC_OFFSET_PWA))             /**<0x00000020 PWA function */\r
+#define   GH3X2X_FUNCTION_SPO2                      ((0x1) << (GH3X2X_FUNC_OFFSET_SPO2))            /**<0x00000040 SPO2 function */\r
+#define   GH3X2X_FUNCTION_ECG                       ((0x1) << (GH3X2X_FUNC_OFFSET_ECG))             /**<0x00000080 ECG function */\r
+#define   GH3X2X_FUNCTION_PWTT                      ((0x1) << (GH3X2X_FUNC_OFFSET_PWTT))            /**<0x00000100 PWTT function */\r
+#define   GH3X2X_FUNCTION_SOFT_ADT_GREEN            ((0x1) << (GH3X2X_FUNC_OFFSET_SOFT_ADT_GREEN))  /**<0x00000200 SOFT ADT GREEN function */\r
+#define   GH3X2X_FUNCTION_BT                        ((0x1) << (GH3X2X_FUNC_OFFSET_BT))              /**<0x00000400 BT function */\r
+#define   GH3X2X_FUNCTION_RESP                      ((0x1) << (GH3X2X_FUNC_OFFSET_RESP))            /**<0x00000800 RESP function */\r
+#define   GH3X2X_FUNCTION_AF                        ((0x1) << (GH3X2X_FUNC_OFFSET_AF))              /**<0x00001000 AF function */\r
+#define   GH3X2X_FUNCTION_TEST1                     ((0x1) << (GH3X2X_FUNC_OFFSET_TEST1))           /**<0x00002000 TEST1 function */\r
+#define   GH3X2X_FUNCTION_TEST2                     ((0x1) << (GH3X2X_FUNC_OFFSET_TEST2))           /**<0x00004000 TEST2 function */\r
+#define   GH3X2X_FUNCTION_SOFT_ADT_IR               ((0x1) << (GH3X2X_FUNC_OFFSET_SOFT_ADT_IR))     /**<0x00008000 SOFT ADT IR function */\r
+#define   GH3X2X_FUNCTION_RS0                       ((0x1) << (GH3X2X_FUNC_OFFSET_RS0))\r
+#define   GH3X2X_FUNCTION_RS1                       ((0x1) << (GH3X2X_FUNC_OFFSET_RS1))\r
+#define   GH3X2X_FUNCTION_RS2                       ((0x1) << (GH3X2X_FUNC_OFFSET_RS2))\r
+#define   GH3X2X_FUNCTION_LEAD_DET                  ((0x1) << (GH3X2X_FUNC_OFFSET_LEAD_DET))\r
+\r
+#define   GH3X2X_ADT_FUNC_ENABLE                     (1)\r
+#define   GH3X2X_ECG_FUNC_ENABLE                     (1)\r
+\r
+#define   GH3X2X_ECG_SLOT_NUM                        (0)\r
+#define   GH3X2X_ADT_SLOT_NUM                        (1)\r
+\r
+#define   GH3X2X_ADT_ADC_NUM                         (0)\r
+\r
+#define   GH3X2X_ECG_DOWN_FS                        (250) //ecg fs:800, 320, 256\r
+#define   GH3X2X_ECG_FS                             (320) //down sample ecg fs: 500 OR 250\r
+#define   GH3X2X_PPG_DOWN_FS                        (250) //down sample ppg fs:\r
+\r
+void GH3X2X_DemoLedAgcPramConfig(void);\r
+\r
+#endif\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_drv.h
new file mode 100644 (file)
index 0000000..1687590
--- /dev/null
@@ -0,0 +1,447 @@
+/**\r
+ * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved.\r
+ *\r
+ * @file    gh3x2x_afe_drv.h\r
+ *\r
+ * @brief   gh3x2x afe driver functions\r
+ *\r
+ * @version v3.2.4.6\r
+ *\r
+ * @author  Gooidx Iot Team\r
+ *\r
+ */\r
+#ifndef __GH3X2X_AFE_DRV_H__\r
+#define __GH3X2X_AFE_DRV_H__\r
+\r
+#include "gh3x2x_afe_user.h"\r
+#include "gh3x2x_afe_version.h"\r
+\r
+#ifndef GH3X2X_AFE_UNUSED_VAR\r
+#define GH3X2X_AFE_UNUSED_VAR(X) ((void)(X))\r
+#endif  // GH3X2X_AFE_UNUSED_VAR\r
+\r
+\r
+#if defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */\r
+  #ifndef __weak\r
+    #define __weak   __attribute__((weak))\r
+  #endif /* __weak */\r
+  #ifndef __packed\r
+    #define __packed __attribute__((__packed__))\r
+  #endif /* __packed */\r
+#endif /* __GNUC__ */\r
+\r
+\r
+\r
+\r
+\r
+\r
+/* type redefine */\r
+typedef unsigned char       GU8;    /**< 8bit unsigned integer type */\r
+typedef signed char         GS8;    /**< 8bit signed integer type */\r
+typedef unsigned short      GU16;   /**< 16bit unsigned integer type */\r
+typedef signed short        GS16;   /**< 16bit signed integer type */\r
+typedef int                 GS32;   /**< 32bit signed integer type */\r
+typedef unsigned int        GU32;   /**< 32bit unsigned integer type */\r
+typedef float               GF32;   /**< float type */\r
+typedef double              GD64;   /**< double type */\r
+typedef char                GCHAR;  /**< char type */\r
+typedef unsigned char       GBOOL; \r
+typedef long long           GS64;   /**< 64bit signed integer type */\r
+\r
+\r
+\r
+\r
+#define GH3020_ID                           (0x00)\r
+#define GH3026_ID                           (0x01)\r
+\r
+#define GH3X2X_MP_DISABLE                   (0)\r
+#define GH3X2X_MP_ENABLE                    (1)\r
+\r
+/********************* communication interface type******************************/\r
+#define GH3X2X_AFE_COM_INTERFACE_SPI  0\r
+#define GH3X2X_AFE_COM_INTERFACE_I2C  1\r
+\r
+\r
+/*********************  spi type ************************************************/\r
+#define GH3X2X_AFE_SPI_SOFTWARE_CS        0\r
+#define GH3X2X_AFE_SPI_HARDWEAR_CS        1\r
+\r
+\r
+/*********************  chip process type ***************************************/\r
+#define GH3X2X_AFE_PRO_BY_INT             0\r
+#define GH3X2X_AFE_PRO_BY_POLLING         1\r
+\r
+/*********************  chip reset type ***************************************/\r
+#define GH3X2X_AFE_RESET_HARDWARE         0\r
+#define GH3X2X_AFE_RESET_SOFTWARE         1         \r
+\r
+\r
+\r
+#define GH3X2X_AFE_SPI_CS_CTRL_LOW        0\r
+#define GH3X2X_AFE_SPI_CS_CTRL_HIGH       1\r
+\r
+\r
+\r
+\r
+#define GH3X2X_AFE_CMD_SLEEP  0xC4\r
+#define GH3X2X_AFE_CMD_WAKEUP 0xC3\r
+#define GH3X2X_AFE_CMD_RESET  0xC2\r
+#define GH3X2X_AFE_SPI_CMD_WRITE              (0xF0)\r
+#define GH3X2X_AFE_SPI_CMD_READ               (0xF1)\r
+\r
+\r
+\r
+#define   GH3X2X_AFE_RET_OK                             (0)             /**< there is no error */\r
+#define   GH3X2X_AFE_RET_GENERIC_ERROR                  (-1)            /**< a generic error happens */\r
+\r
+// special reg addr\r
+#define   GH3X2X_AFE_FIFO_REG_ADDR                      (0xAAAA)    /**< fifo reg addr */\r
+#define   GH3X2X_AFE_I2C_CMD_ADDR                       (0xDDDD)    /**< i2c cmd reg addr */\r
+\r
+\r
+#define GH3X2X_AFE_SPI_END_DELAY_X_US         (3)\r
+#define GH3X2X_AFE_SPI_WAIT_DELAY_X_US        (4)\r
+\r
+#define GH3X2X_AFE_WAKE_UP_CMD_DELAY_X_US   (500)\r
+#define GH3X2X_AFE_HARD_RESET_DELAY_X_US    (100)\r
+\r
+/// null val\r
+#define   GH3X2X_PTR_NULL                           ((void *) 0)\r
+\r
+\r
+\r
+#define GH3X2X_AFE_CHANGE_BYTE_U16(x)                  ((((u16)(((u8*)(&x))[0]))<<8) + ((u16)(((u8 *)(&x))[1])))\r
+/// get high byte from word\r
+#define   GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(sValue)    ((GU8)(((sValue) >> 8) & 0xFFU))\r
+/// get low byte from word\r
+#define   GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(sValue)     ((GU8)((sValue) & 0xFFU))\r
+#define   GH3X2X_AFE_MAKEUP_WORD(uchHighByte, uchLowByte)              ((GU16)(((((GU16)(uchHighByte)) << 8)& 0xFF00) |\\r
+                                                                            (((GU16)(uchLowByte))& 0x00FF)))\r
+\r
+/// makeup dword from bytes\r
+#define   GH3X2X_AFE_MAKEUP_DWORD(uchByte3, uchByte2, uchByte1, uchByte0)     (((((GU32)(uchByte3)) << 24) & 0xFF000000U)|\\r
+                                                                          ((((GU32)(uchByte2)) << 16) & 0x00FF0000U) |\\r
+                                                                          ((((GU32)(uchByte1)) << 8) & 0x0000FF00U) |\\r
+                                                                          (((GU32)(uchByte0)) & 0x000000FFU))\r
+\r
+\r
+/// rawdata clear all flag\r
+#define   GH3X2X_RAWDATA_CLEAR_ALL_FLAG(x)              ((x) & 0x00FFFFFF)\r
+\r
+\r
+/// macro of val get bits\r
+#define   GH3X2X_AFE_VAL_GET_BIT(x, b)          ((x) &= (b))\r
+\r
+\r
+\r
+#define GH3X2X_AFE_EVENT_BIT(x)   ((GU16)1 << x)\r
+\r
+\r
+\r
+#define GH3X2X_AFE_REG_IS_VALID(x)             ((x) <= 0x0780)\r
+/// macro of val clear bits\r
+#define   GH3X2X_VAL_CLEAR_BIT(x, b)        ((x) &= (~(b)))\r
+/// macro of val set bits\r
+#define   GH3X2X_VAL_SET_BIT(x, b)          ((x) |= (b))\r
+\r
+\r
+#define GH3X2X_PIN_STATUS_CS_0_MISO_0   (0)\r
+#define GH3X2X_PIN_STATUS_CS_1_MISO_0   (1)\r
+#define GH3X2X_PIN_STATUS_CS_0_MISO_1   (2)\r
+#define GH3X2X_PIN_STATUS_CS_1_MISO_1   (3)\r
+\r
+\r
+/// get byte3 from dword\r
+#define   GH3X2X_AFE_GET_BYTE3_FROM_DWORD(unValue)      ((GU8)(((unValue) >> 24) & 0x000000FFU))\r
+/// get byte2 from dword\r
+#define   GH3X2X_AFE_GET_BYTE2_FROM_DWORD(unValue)      ((GU8)(((unValue) >> 16) & 0x000000FFU))\r
+/// get byte1 from dword\r
+#define   GH3X2X_AFE_GET_BYTE1_FROM_DWORD(unValue)      ((GU8)(((unValue) >> 8) & 0x000000FFU))\r
+/// get byte0 from dword\r
+#define   GH3X2X_AFE_GET_BYTE0_FROM_DWORD(unValue)      ((GU8)((unValue) & 0x000000FFU))\r
+\r
+/// macro of val set bits\r
+#define   GH3X2X_VAL_SET_BIT(x, b)          ((x) |= (b))\r
+\r
+/// macro of clear bits\r
+#define   GH3X2X_CLEAR_BIT(x, b)            ((x) & (~(b)))\r
+\r
+/// macro of val clear bits\r
+#define   GH3X2X_VAL_CLEAR_BIT(x, b)        ((x) &= (~(b)))\r
+\r
+/// macro of val get bits\r
+#define   GH3X2X_VAL_GET_BIT(x, b)          ((x) &= (b))\r
+\r
+\r
+#define GH3X2X_AFE_I2C_DEVICE_BASE        (0x28)\r
+#define GH3X2X_AFE_I2C_DEVICE_ADDR        (GH3X2X_AFE_I2C_DEVICE_BASE | (GH3X2X_AFE_I2C_DEVICE_CTRL_PIN_STATUS << 1))\r
+\r
+\r
+#define   GH3X2X_AFE_FIFO_RAWDATA_SIZE                           (4)\r
+#define   GH3X2X_AFE_SLOT_ADC_NUM_BITS                       (0xF8)\r
+#define   GH3X2X_AFE_CHANNEL_MAP_GET(x)                     ((x) & GH3X2X_AFE_SLOT_ADC_NUM_BITS)\r
+\r
+/// number of channel map id\r
+#define  CHANNEL_MAP_ID_NUM                               (32)\r
+/// number of channel map id\r
+#define  CHANNEL_SLOT_NUM                                 (8)\r
+\r
+\r
+/**\r
+ * @brief register struct\r
+ */\r
+typedef struct\r
+{\r
+    GU16 usRegAddr;     /**< register address */\r
+    GU16 usRegData;     /**< register val */\r
+} STGH3X2X_AFEReg;\r
+\r
+typedef struct\r
+{\r
+    GU8 uchAddrOffset;\r
+    GU8 uchMsb;\r
+    GU8 uchLsb;\r
+} STGh3x2xAgcReg;\r
+\r
+typedef struct\r
+{\r
+    /// save gain\r
+               GU8  uchTiaGainRecord[CHANNEL_MAP_ID_NUM];\r
+               GU8  uchTiaGainAfterSoftAgc[CHANNEL_MAP_ID_NUM];\r
+               /// save current of drv0 and drv1\r
+               GU16  uchDrvCurrentAfterSoftAgc[CHANNEL_SLOT_NUM];\r
+               GU16 uchDrvCurrentRecord[CHANNEL_SLOT_NUM];\r
+} STGh3x2xAgcInfo;\r
+\r
+extern void GH3X2X_AFE_SpiSendCmd(GU8 uchCmd);\r
+extern void GH3X2X_AFE_SpiWriteReg(GU16 usRegAddr, GU16 usRegValue);\r
+extern GU16 GH3X2X_AFE_SpiReadReg(GU16 usRegAddr);\r
+extern void GH3X2X_AFE_SpiReadRegs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen);\r
+\r
+extern void GH3X2X_AFE_SpiWriteRegHardwareCs(GU16 usRegAddr, GU16 usRegValue);\r
+extern void GH3X2X_AFE_SpiReadRegsHardwareCs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen);\r
+extern GU16 GH3X2X_AFE_SpiReadRegHardwareCs(GU16 usRegAddr);\r
+extern void GH3X2X_AFE_I2cWriteReg(GU16 usRegAddr, GU16 usRegValue);\r
+extern GU16 GH3X2X_AFE_I2cReadReg(GU16 usRegAddr);\r
+extern void GH3X2X_I2cReadRegs(GU16 usRegAddr, GU16 *pusRegValueArr, GU8 uchLen);\r
+extern void GH3X2X_AFE_Reset(void);\r
+extern void GH3X2X_AFE_SpiSendCmdHardwareCs(GU8 uchCmd);\r
+extern void GH3X2X_AFE_I2cSendCmd(GU8 uchCmd);\r
+\r
+\r
+/****************  cmd/read/write  funciton define **************************/\r
+#if(GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_SPI)\r
+#if(GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS)\r
+#define GH3X2X_AFE_SEND_CMD(cmd)                                               GH3X2X_AFE_SpiSendCmd(cmd)\r
+#define GH3X2X_AFE_WRITE_REG(usRegAddr,  usRegValue)                           GH3X2X_AFE_SpiWriteReg(usRegAddr, usRegValue)\r
+#define GH3X2X_AFE_READ_REG(usRegAddr)                                         GH3X2X_AFE_SpiReadReg(usRegAddr)\r
+#define GH3X2X_AFE_READ_FIFO(buf, len)                                         GH3X2X_AFE_SpiReadFifo(buf, len)\r
+#define GH3X2X_AFE_READ_REGS(usRegAddr,pusRegValueBuffer,uchLen)               GH3X2X_AFE_SpiReadRegs(usRegAddr,pusRegValueBuffer,uchLen)\r
+#else\r
+#define GH3X2X_AFE_SEND_CMD(cmd)                                               GH3X2X_AFE_SpiSendCmdHardwareCs(cmd)\r
+#define GH3X2X_AFE_WRITE_REG(usRegAddr,  usRegValue)                           GH3X2X_AFE_SpiWriteRegHardwareCs(usRegAddr, usRegValue)\r
+#define GH3X2X_AFE_READ_REG(usRegAddr)                                         GH3X2X_AFE_SpiReadRegHardwareCs(usRegAddr)\r
+#define GH3X2X_AFE_READ_FIFO(buf, len)                                         GH3X2X_AFE_SpiReadFifoHardwareCs(buf, len)\r
+#define GH3X2X_AFE_READ_REGS(usRegAddr,pusRegValueBuffer,uchLen)               GH3X2X_AFE_SpiReadRegsHardwareCs(usRegAddr,pusRegValueBuffer,uchLen)\r
+\r
+#endif\r
+#else\r
+#define GH3X2X_AFE_SEND_CMD(cmd)                                                GH3X2X_AFE_I2cSendCmd(cmd)\r
+#define GH3X2X_AFE_WRITE_REG(usRegAddr,  usRegValue)                            GH3X2X_AFE_I2cWriteReg(usRegAddr, usRegValue)\r
+#define GH3X2X_AFE_READ_REG(usRegAddr)                                          GH3X2X_AFE_I2cReadReg(usRegAddr)\r
+#define GH3X2X_AFE_READ_FIFO(buf, len)                                          GH3X2X_AFE_I2cReadFifo(buf, len)\r
+#define GH3X2X_AFE_READ_REGS(usRegAddr,pusRegValueBuffer,uchLen)                GH3X2X_I2cReadRegs(usRegAddr,pusRegValueBuffer,uchLen)\r
+\r
+#endif\r
+\r
+\r
+/***************************** GH3X2X event *************************************************/\r
+\r
+#define GH3X2X_AFE_EVENT_COM_READY                    (0)\r
+#define GH3X2X_AFE_EVENT_LEAD_ON                      (1)\r
+#define GH3X2X_AFE_EVENT_LEAD_OFF                     (2)\r
+#define GH3X2X_AFE_EVENT_FAST_RECOVER_DONE            (3)\r
+#define GH3X2X_AFE_EVENT_ADC_DONE                     (4)\r
+#define GH3X2X_AFE_EVENT_FIFO_FULL                    (5)\r
+#define GH3X2X_AFE_EVENT_FIFO_OV                      (6)\r
+#define GH3X2X_AFE_EVENT_FIFO_UN                      (7)\r
+#define GH3X2X_AFE_EVENT_LED_TUNE_FAIL     (8)\r
+#define GH3X2X_AFE_EVENT_LED_TUNE_DONE     (9)\r
+#define GH3X2X_AFE_EVENT_WEAR_ON           (10)\r
+#define GH3X2X_AFE_EVENT_WEAR_OFF          (11)\r
+#define GH3X2X_AFE_EVENT_SLOT_TIME_OUT     (12)\r
+#define GH3X2X_AFE_EVENT_SAMPLE_RATE_ERROR (13)\r
+#define GH3X2X_AFE_EVENT_ERSET             (14)\r
+\r
+\r
+\r
+\r
+\r
+\r
+/***************************** GH3X2X registers *********************************************/\r
+\r
+\r
+#define GH3X2X_AFE_REG_INT_EVENT_ADDR                          0x0508\r
+#define GH3X2X_AFE_REG_FIFO_USE_ADDR                           0x050A\r
+#define GH3X2X_AFE_REG_CHIP_READY_CODE_REG_ADDR                0x0036\r
+#define GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR                      0x01EC\r
+#define GH3X2X_AFE_REG_INT_EVENT_EN_ADDR                       0x0502\r
+\r
+#define GH3X2X_AFE_REG_SLOT_EN_ADDR                            0x0108\r
+\r
+\r
+#define GH3X2X_AFE_REG_START_ADDR                              0x0000\r
+#define GH3X2X_AFE_REG_START_MSB                               0\r
+#define GH3X2X_AFE_REG_START_LSB                               0\r
+\r
+\r
+/**************************** GH3X2X ppg control reg index ***********************************************/\r
+#define GH3X2X_AFE_PPG_CTRL_REG_AGC_EN                     0\r
+#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_UP_LIMIT       1\r
+#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DOWN_LIMIT     2\r
+#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV0           3\r
+#define GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV1           4\r
+#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX0               5\r
+#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX1               6\r
+#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX2               7\r
+#define GH3X2X_AFE_PPG_CTRL_REG_TIA_GAIN_RX3               8\r
+#define GH3X2X_AFE_PPG_CTRL_REG_AGC_SRC                    9\r
+#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX0              10\r
+#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX1              11\r
+#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX2              12\r
+#define GH3X2X_AFE_PPG_CTRL_REG_BG_CANCEL_RX3              13\r
+#define GH3X2X_AFE_PPG_CTRL_REG_SR_MULIPLIPER              14\r
+#define GH3X2X_AFE_PPG_CTRL_ECG_PPG_RX_EN                  15\r
+\r
+#define  GH3X2X_DRV0_FULL_SCAL_CURRENT_LSB          (4)\r
+#define  GH3X2X_DRV0_FULL_SCAL_CURRENT_MSB          (5)\r
+\r
+#define  GH3X2X_DRV1_FULL_SCAL_CURRENT_LSB          (0)\r
+#define  GH3X2X_DRV1_FULL_SCAL_CURRENT_MSB          (1)\r
+\r
+#define  GH3X2X_WHO_AM_I_LSB                        (5)\r
+#define  GH3X2X_WHO_AM_I_MSB                        (7)\r
+\r
+#define  GH3X2X_EFUSE_MODE_LSB                      (0)\r
+#define  GH3X2X_EFUSE_MODE_MSB                      (1)\r
+\r
+#define  GH3X2X_EFUSE_CHOOSE_LSB                    (2)\r
+#define  GH3X2X_EFUSE_CHOOSE_MSB                    (3)\r
+\r
+#define  GH3X2X_EFUSE_START_LSB                     (4)\r
+#define  GH3X2X_EFUSE_START_MSB                     (4)\r
+\r
+#define  GH3X2X_EFUSE_CLK_EN_LSB                    (5)\r
+#define  GH3X2X_EFUSE_CLK_EN_MSB                    (5)\r
+\r
+\r
+\r
+\r
+#define   GH3X2X_LED_DRV_AD_REG_REG_ADDR                (0x0692)\r
+#define   GH3X2X_WHO_AM_I_REG_ADDR                      (0x0724)\r
+\r
+\r
+// efuse_ctrl block, start addr: 0x0700\r
+#define   GH3X2X_EFUSE_CTRL_CMD_REG_ADDR                (0x0700)\r
+#define   GH3X2X_EFUSE_CTRL_PASSWORD_REG_ADDR           (0x0702)\r
+#define   GH3X2X_EFUSE_CTRL_TIMING_CFG_0_REG_ADDR       (0x0704)\r
+#define   GH3X2X_EFUSE_CTRL_TIMING_CFG_1_REG_ADDR       (0x0706)\r
+#define   GH3X2X_EFUSE_CTRL_WDATA_0_REG_ADDR            (0x0708)\r
+#define   GH3X2X_EFUSE_CTRL_WDATA_1_REG_ADDR            (0x070A)\r
+#define   GH3X2X_EFUSE_CTRL_WDATA_2_REG_ADDR            (0x070C)\r
+#define   GH3X2X_EFUSE_CTRL_WDATA_3_REG_ADDR            (0x070E)\r
+#define   GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR            (0x0710)\r
+#define   GH3X2X_EFUSE_CTRL_RDATA_1_REG_ADDR            (0x0712)\r
+#define   GH3X2X_EFUSE_CTRL_RDATA_2_REG_ADDR            (0x0714)\r
+#define   GH3X2X_EFUSE_CTRL_RDATA_3_REG_ADDR            (0x0716)\r
+#define   GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR             (0x0718)\r
+#define   GH3X2X_EFUSE_CTRL_REG_MODE_REG_ADDR           (0x071A)\r
+  \r
+\r
+extern GU8 g_uchGh3x2xAfeIntCallBackIsCalled;\r
+\r
+\r
+extern void GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(GU8 uchFlag);\r
+extern void hal_gh3x2x_afe_DelayUs(GU16 usUsec);\r
+extern void hal_gh3x2x_afe_DelayMs(GU16 usMsec);\r
+\r
+extern void hal_gh3x2x_afe_i2c_init(void);\r
+extern GU8 hal_gh3x2x_afe_i2c_write(GU8 device_id, const GU8 write_buffer[], GU16 length);\r
+extern GU8 hal_gh3x2x_afe_i2c_read(GU8 device_id, const GU8 write_buffer[], GU16 write_length, GU8 read_buffer[], GU16 read_length);\r
+\r
+extern void hal_gh3x2x_afe_spi_init(void);\r
+extern GU8 hal_gh3x2x_afe_spi_write(GU8 write_buffer[], GU16 length);\r
+extern GU8 hal_gh3x2x_afe_spi_read(GU8 read_buffer[], GU16 length);\r
+extern GU8 hal_gh3x2x_afe_spi_write_F1_and_read(GU8 read_buffer[], GU16 length);\r
+extern void hal_gh3x2x_afe_spi_cs_ctrl(GU8 cs_pin_level);\r
+\r
+extern void hal_gh3x2x_afe_reset_pin_init(void);\r
+extern void hal_gh3x2x_afe_reset_pin_ctrl(GU8 pin_level);\r
+\r
+extern void hal_gh3x2x_afe_int_init(void);\r
+extern void hal_gh3x2x_afe_int_handler_call_back(void);\r
+\r
+extern void GH3X2X_AFE_Log(GCHAR *log_string);\r
+\r
+\r
+\r
+\r
+\r
+extern void GH3X2X_AFE_ChipPro(void);\r
+extern void GH3X2X_AFE_Init(void);\r
+extern void GH3X2X_AFE_StartSampling(GU8 SlotCfgEnable);\r
+extern void GH3X2X_AFE_StopSampling(void);\r
+extern void GH3X2X_AFE_SwitchSlot(GU8 SlotCfgEnable);\r
+\r
+extern void GH3x2xSetPpgCtrlReg(GU8 uchPpgCtrlReg,  GU8 uchSlot, GU16 usValue);\r
+extern GU16 GH3x2xGetPpgCtrlReg(GU8 uchPpgCtrlReg,  GU8 uchSlot);\r
+\r
+GU16 GH3X2X_AFE_SetLedDrvCurrent(GU8 uchCurrent_mA, GU8 uchDrvNum, GS8 chECODE);\r
+GF32 GH3X2X_AFE_GetLedDrvCurrent(GU16 usDrvCode, GU8 uchDrvNum, GS8 chECODE);\r
+void GH3X2X_AFE_GetEfuseCode(GS8* pchLedDrvEcode,GS8* pchTiaEcode,GS8* pchEcgEcode);\r
+GF32 GH3X2X_AFE_GetTiaCalCode(GS8 chECODE);\r
+GF32 GH3X2X_AFE_GetEcgCalCode(GS8 chECODE);\r
+GCHAR *GH3X2X_GetAfeLibVersion(void);\r
+GU8 GH3X2X_AFE_GetChipId(void);\r
+GS8 GH3X2X_AFE_CheckChipId(void);\r
+void GH3X2X_AFE_LoadEfuse(GU8* puchEfuseBuffer,GU16 EfuseByteLen);\r
+GS8 GH3X2X_AFE_CheckEfuseCrc(void);\r
+void GH3X2X_AFE_WriteRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb, GU16 usValue);\r
+GU16 GH3X2X_AFE_ReadRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb);\r
+GU8 GH3X2X_AFE_GetSoftEvent(void);\r
+void GH3X2X_AFE_SetSoftEvent(GU32 unEvent);\r
+void GH3X2X_AFE_ClearSoftEvent(GU32 unEvent);\r
+void GH3X2X_AFE_StartFunction(GU32 unFuncMode);\r
+\r
+void GH3x2x_AFESetAgcReg(GU8 uchAgcReg,  GU8 uchSlot, GU16 usValue);\r
+GU16 GH3x2x_AFEGetAgcReg(GU8 uchAgcReg,  GU8 uchSlot);\r
+void *GH3X2X_Memcpy(void *pDest, const void *pSrc, GU32 unByteSize);\r
+void *GH3X2X_Memset(void* pDest, GCHAR chVal, GU32 unByteSize);\r
+void GH3X2X_RecordAgcInfo(void);\r
+void GH3X2X_UpdateAgcInfo(void);\r
+/*********************************************** master-slaver interface lib function *********************************/\r
+#define GH3X2X_INFO_LOG(...)                    do {\\r
+                                                char GH3X2X_AFE_GH3X2X_INFO_LOG[128] = {0};\\r
+                                                snprintf(GH3X2X_AFE_GH3X2X_INFO_LOG, 128, __VA_ARGS__);\\r
+                                                GH3X2X_AFE_Log((char *)GH3X2X_AFE_GH3X2X_INFO_LOG);\\r
+                                            } while(0)\r
+\r
+\r
+\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_ecg.h
new file mode 100644 (file)
index 0000000..50d3c8d
--- /dev/null
@@ -0,0 +1,110 @@
+#ifndef __GH3X2X_AFE_ECG_H__\r
+#define __GH3X2X_AFE_ECG_H__\r
+#include "gh3x2x_afe_drv.h"\r
+\r
+/**\r
+ * @brief Downsample Function\r
+*/\r
+typedef enum\r
+{\r
+       DOWNSAMPLE_ECG = 0,\r
+       DOWNSAMPLE_PPG,\r
+}EmDownSampleFunction;\r
+\r
+/**\r
+ * @brief Downsample type\r
+*/\r
+typedef enum\r
+{\r
+       DOWNSAMPLE_DEFAULT = 0,\r
+       DOWNSAMPLE_800HZ_TO_500HZ = 1,\r
+       DOWNSAMPLE_800HZ_TO_250HZ = 2,\r
+       DOWNSAMPLE_400HZ_TO_250HZ = 3,\r
+       DOWNSAMPLE_320HZ_TO_250HZ = 4,\r
+       DOWNSAMPLE_256HZ_TO_250HZ = 5,\r
+}EmDownSampleType;\r
+\r
+typedef struct\r
+{\r
+    GS32 snRsXbuf[100/1 + 1];\r
+    GS32 snBufHead;\r
+    GS32 snRsFirState;\r
+    GU32 nRsIcounter;\r
+    GU32 nRrsDcounter;\r
+    GU8 uchFlagFrPrev;\r
+    GU32 nRsLastRaw;\r
+    GU32 fDownStep;\r
+    GU8  uchLinearInterState;\r
+    GU8  uchLinearDataUpdate;\r
+} STGh3x2xRsInfo;\r
+\r
+\r
+typedef struct\r
+{\r
+    GS32 snCounter;\r
+    GS32 sniqCounter;\r
+    long long snniVal;\r
+    long long snnqVal;\r
+    GU8 uchFlagFrPrev;\r
+    GU8 uchFastRecoryHistory;\r
+    long long snniqAmp[5];\r
+} STGh3x2xSoftLeadOffDetInfo;\r
+\r
+\r
+typedef struct\r
+{\r
+    GU8   uchRsFirOrder;\r
+    GU8   uchRsI;\r
+    GU8   uchRsD;\r
+    GU8   uchRsFirCoefNum;\r
+    GU8   uchRsBufSize;\r
+    GU8   uchRsEnable;\r
+    GU32  ufStep;\r
+    GS32* rsFirCoef;\r
+               GU8   uchDownSampleType;\r
+} STGh3x2xDownSampleCalParamInfo;\r
+\r
+#define __SUPPORT_ECG_PPG_DOWNSAMP__  0\r
+  \r
+/* ecg sample event type */\r
+#define  ECG_SAMPLE_EVENT_TYPE_SAMPLE                     (0x01)     /**< sample evt type sample config */\r
+#define  ECG_SAMPLE_EVENT_TYPE_SLOT                       (0x02)     /**< sample evt type slot config */\r
+#define  ECG_SAMPLE_EVENT_TYPE_LEAD                       (0x04)     /**< sample evt type lead irq */\r
+#define  ECG_SAMPLE_EVENT_ALL                             (ECG_SAMPLE_EVENT_TYPE_SAMPLE | ECG_SAMPLE_EVENT_TYPE_SLOT | \\r
+                                                            ECG_SAMPLE_EVENT_TYPE_LEAD)     /**< sample evt all */\r
+\r
+#define   GH3X2X_ECG_CTRL_REG_ADDR                      (0x01EA)\r
+#define   GH3X2X_ECG_FAST_RECV_EN_LSB               (10)        /**< ecg fast recv en lsb @GH3X2X_ECG_CTRL_REG */\r
+#define   GH3X2X_ECG_FAST_RECV_EN_MSB               (10)        /**< ecg fast recv en msb @GH3X2X_ECG_CTRL_REG */\r
+/// ecg fast recover enable config\r
+#define  ECG_FAST_RECV_EN_CONFIG(en)        do {\\r
+                                                GH3X2X_AFE_WriteRegBitField(GH3X2X_ECG_CTRL_REG_ADDR, \\r
+                                                    GH3X2X_ECG_FAST_RECV_EN_LSB, GH3X2X_ECG_FAST_RECV_EN_MSB, (en)); \\r
+                                            } while (0)\r
+\r
+#define   GH3X2X_ADT_LEADON_CR_REG_ADDR                 (0x0400)\r
+#define   GH3X2X_ECG_LEAD_DET_EN_LSB                (0)         /**< ecg lead det en lsb @GH3X2X_ADT_LEADON_CR_REG */\r
+#define   GH3X2X_ECG_LEAD_DET_EN_MSB                (0)         /**< ecg lead det en msb @GH3X2X_ADT_LEADON_CR_REG */\r
+                                            \r
+  /// ecg lead detect enable config\r
+#define  ECG_LEAD_DET_EN_CONFIG(en)         do {\\r
+                                                GH3X2X_AFE_WriteRegBitField(GH3X2X_ADT_LEADON_CR_REG_ADDR, \\r
+                                                    GH3X2X_ECG_LEAD_DET_EN_LSB, GH3X2X_ECG_LEAD_DET_EN_MSB, (en)); \\r
+                                            } while (0)                                          \r
+                                            \r
+                                            \r
+#define GET_ECG_LEAD_DET_EN_VAL()              (GH3X2X_AFE_ReadRegBitField(GH3X2X_ADT_LEADON_CR_REG_ADDR, \\r
+                                                    GH3X2X_ECG_LEAD_DET_EN_LSB, GH3X2X_ECG_LEAD_DET_EN_MSB))\r
+ \r
+ \r
+\r
+GU8 GH3X2X_AFE_EcgRsHandle(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum, GU16 usEcgSampleRate);\r
+GS32 GH3X2X_LeadOffDetectInit(void);\r
+void GH3X2X_ECGResampleConfig(GU16 usEcgSampleRate);\r
+void GH3X2X_PPGResampleConfig(GU16 usEcgSampleRate);                                                                                                                                                                   \r
+GU8 GH3X2X_LeadOffDetect(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum);\r
+void GH3X2X_AFE_Leadon_hook(void);\r
+void GH3X2X_AFE_Leadoff_hook(void);\r
+void GH3x2xSetEcgOutputFs(GU16 usEcgOutputFs);\r
+\r
+#endif\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h
new file mode 100644 (file)
index 0000000..f22e31a
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+ * @Author: penglei 1624952103@qq.com\r
+ * @Date: 2025-01-13 10:11:20\r
+ * @LastEditors: penglei 1624952103@qq.com\r
+ * @LastEditTime: 2025-01-17 15:57:59\r
+ * @FilePath: /sdk615/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_user.h\r
+ * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\r
+ */\r
+#ifndef __GH3X2X_AFE_USER_H__\r
+#define __GH3X2X_AFE_USER_H__\r
+#include "gh3x2x_afe_drv.h"\r
+\r
+\r
+#define   GH3X2X_CHIP_ID               GH3020_ID\r
+#define   GH3X2X_AFE_MP_MODE           GH3X2X_MP_ENABLE\r
+\r
+\r
+/******  communication type config **************************/\r
+#define GH3X2X_AFE_COM_INTERFACE_TYPE  GH3X2X_AFE_COM_INTERFACE_I2C\r
+#define GH3X2X_AFE_SPI_TYPE            GH3X2X_AFE_SPI_SOFTWARE_CS\r
+\r
+\r
+/****** I2C device id ***************************************/\r
+#define GH3X2X_AFE_I2C_DEVICE_CTRL_PIN_STATUS    GH3X2X_PIN_STATUS_CS_0_MISO_0\r
+\r
+\r
+\r
+/******  chip process type config ***************************/\r
+#define GH3X2X_AFE_PRO_TYPE            GH3X2X_AFE_PRO_BY_INT\r
+\r
+\r
+\r
+/******  chip reset type config ***************************/\r
+#define GH3X2X_AFE_RESET_TYPE          GH3X2X_AFE_RESET_SOFTWARE\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_afe_version.h
new file mode 100644 (file)
index 0000000..a5b7620
--- /dev/null
@@ -0,0 +1,45 @@
+\r
+/**\r
+ * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved.\r
+ *\r
+ * @file    gh3x2x_afe_version.h\r
+ *\r
+ * @brief   gh3x2x afe driver version and change log\r
+ *\r
+ * @par  history:\r
+ * @verbatim\r
+ * Date            Version     Notes\r
+ * 2021-11-04      v3.2.4.2    1.add calibration code\r
+ * 2021-11-05      v3.2.4.4    1.fix Efuse calibration bug\r
+ * 2021-11-05      v3.2.4.5    1.add Ffuse Crc Process\r
+ *                             2.add Check Chip Id process\r
+ *\r
+ * 2021-11-05      v3.2.4.6    1.update Head file\r
+ * 2021-11-05      v3.2.4.7    1.add ecg lead off det lib\r
+ * 2021-11-05      v3.2.4.8    1.add 5Hz adt\r
+ * 2023-12-06      v3.2.4.9    1.update ecg and agc\r
+ * @endverbatim  */\r
+\r
+#ifndef _GH3X2X_AFE_VERSION_H_\r
+#define _GH3X2X_AFE_VERSION_H_\r
+\r
+\r
+#define   GH3X2X_DRV_MAJOR_VERSION_NUMBER        3      /**< major version number */\r
+#define   GH3X2X_DRV_MINOR_VERSION_NUMBER        2      /**< minor version number */\r
+#define   GH3X2X_DRV_REVISION_VERSION_NUMBER     4      /**< revision version number */\r
+#define   GH3X2X_DRV_FIXED_VERSION_NUMBER        9      /**< fixed version number */\r
+\r
+#define   GH3X2X_TO_STRING(x)       #x                      /**< number to char */\r
+#define   GH3X2X_STR(x)             GH3X2X_TO_STRING(x)     /**< number to char */\r
+\r
+/// makeup version string\r
+#define   GH3X2X_VERSION_STRING     "v" GH3X2X_STR(GH3X2X_DRV_MAJOR_VERSION_NUMBER)\\r
+                                    "." GH3X2X_STR(GH3X2X_DRV_MINOR_VERSION_NUMBER)\\r
+                                    "." GH3X2X_STR(GH3X2X_DRV_REVISION_VERSION_NUMBER)\\r
+                                    "." GH3X2X_STR(GH3X2X_DRV_FIXED_VERSION_NUMBER)\\r
+                                    " (build:"__DATE__"_"__TIME__")"\r
+\r
+\r
+#endif /* _GH3X2X_AFE_VERSION_H_ */\r
+\r
+/********END OF FILE********* Copyright (c) 2003 - 2022, Goodix Co., Ltd. ********/\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h b/code/sdk/zhihui/drivers/ppg/gh3x2x/inc/gh3x2x_hal.h
new file mode 100644 (file)
index 0000000..fce1cdf
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-06-07 11:18:26
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2025-01-13 14:09:50
+ * @FilePath: /FD230/code/sdk/drivers/peripheral/ppg/hx3695/hx3695_hal.h
+ * @Description: 
+ * 
+ * Copyright (c) 2024 by ${git_name_email}, All Rights Reserved. 
+ */
+#ifndef GH_3X2X_HAL_H__
+#define GH_3X2X_HAL_H__
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#include "stdint.h"
+
+typedef uint32_t PPG_CMD_TYPE_T ;
+
+void ppg_send_cmd_to_gh3x2x_driver(char* mode, uint8_t enable);
+
+uint32_t tyhx_poweron(void);
+uint32_t tyhx_poweroff(void);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
\ No newline at end of file
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_adt.c
new file mode 100644 (file)
index 0000000..561922b
--- /dev/null
@@ -0,0 +1,156 @@
+/**\r
+ * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved.\r
+ *\r
+ * @file    gh3x2x_afe_adt.c\r
+ *\r
+ * @brief   gh3x2x led agc process functions\r
+ *\r
+ * @version \r
+ *\r
+ */\r
+\r
+\r
+#include <stdio.h>\r
+#include "gh3x2x_afe_adt.h"\r
+\r
+#define GH3X2X_MOVINF_AVA_WINDOW_SIZE  6\r
+\r
+\r
+\r
+EMWearDetectType g_uchWearDetectStatus = WEAR_DETECT_WEAR_ON;\r
+\r
+GU32 g_punGh3x2xMovingAvaFilterBuf[GH3X2X_MOVINF_AVA_WINDOW_SIZE];\r
+GU8  g_uchGh3x2xMovingAvaFilterPointCnt;\r
+GU8  g_Gh3x2xFilterHaveOutputFlag;\r
+\r
+\r
+\r
+void Gh3x2xMovingAvaFilterInit(void)\r
+{\r
+    g_uchGh3x2xMovingAvaFilterPointCnt = 0;\r
+    g_Gh3x2xFilterHaveOutputFlag = 0;\r
+}\r
+GU8 Gh3x2xMovingAvaFilter(GU32 *Rawdata, GU8 uchBypass)\r
+{\r
+    GU32 unSum = 0;\r
+\r
+    if(uchBypass)\r
+    {\r
+        return 1;\r
+    }\r
+    else\r
+    {\r
+        if(g_uchGh3x2xMovingAvaFilterPointCnt >= GH3X2X_MOVINF_AVA_WINDOW_SIZE)\r
+        {\r
+            for(GU8 uchCnt = 1; uchCnt < GH3X2X_MOVINF_AVA_WINDOW_SIZE; uchCnt ++)\r
+            {\r
+                g_punGh3x2xMovingAvaFilterBuf[uchCnt - 1] = g_punGh3x2xMovingAvaFilterBuf[uchCnt];\r
+            }\r
+            g_uchGh3x2xMovingAvaFilterPointCnt = GH3X2X_MOVINF_AVA_WINDOW_SIZE - 1;\r
+        }\r
+        g_punGh3x2xMovingAvaFilterBuf[g_uchGh3x2xMovingAvaFilterPointCnt] = Rawdata[0];\r
+        g_uchGh3x2xMovingAvaFilterPointCnt ++;\r
+            \r
+        if(g_uchGh3x2xMovingAvaFilterPointCnt > 1)\r
+        {\r
+            for(GU8 uchCnt = 0; uchCnt < g_uchGh3x2xMovingAvaFilterPointCnt - 1; uchCnt ++)\r
+            {\r
+                unSum += g_punGh3x2xMovingAvaFilterBuf[uchCnt];\r
+            }\r
+            Rawdata[0] = unSum/(g_uchGh3x2xMovingAvaFilterPointCnt - 1);\r
+        }\r
+        return 1;\r
+    }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+GS8  GH3x2xAdtAlgoInit(void)\r
+{\r
+    Gh3x2xMovingAvaFilterInit();\r
+    g_uchWearDetectStatus = WEAR_DETECT_WEAR_ON;\r
+    return GH3X2X_AFE_RET_OK;\r
+}\r
+GS8 GH3x2xAdtAlgoDeinit(void)\r
+{\r
+    return GH3X2X_AFE_RET_OK;\r
+}\r
+\r
+void GH3x2xAdtAlgoExe(GU32* punRawdata,EMWearStatus* pemWearStatus)\r
+{\r
+    \r
+    GU32 unCurrentFrameRawdata;\r
+\r
+    GU32 unRawDataBeforeFilter;\r
+    unCurrentFrameRawdata = *punRawdata;\r
+    unRawDataBeforeFilter = *punRawdata;\r
+    GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] punFrameRawdata = %d\r\n", unCurrentFrameRawdata);\r
+\r
+    Gh3x2xMovingAvaFilter(&unCurrentFrameRawdata, 0);\r
+    GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] punFrameRawdata after filter = %d\r\n", unCurrentFrameRawdata);\r
+\r
+\r
+\r
+    GS32 snDiffRawdata;\r
+\r
+    GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] start check...\r\n");\r
+\r
+    snDiffRawdata = (GS32)unRawDataBeforeFilter - (GS32)unCurrentFrameRawdata;\r
+\r
+    if(WEAR_DETECT_WEAR_ON == g_uchWearDetectStatus)\r
+    {\r
+        \r
+        *pemWearStatus = WEAR_STATUS_WEAR_OFF;\r
+        if((unRawDataBeforeFilter > __HARD_ADT_WAER_ON_THRD__)&&((snDiffRawdata > (GS32)__HARD_ADT_WAER_ON_DIFF_THRD__)))\r
+        {\r
+            *pemWearStatus = WEAR_STATUS_WEAR_ON;\r
+            g_uchWearDetectStatus = WEAR_DETECT_WEAR_OFF;\r
+            GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] wear on !\r\n");\r
+        }\r
+        else\r
+        {\r
+            if(unRawDataBeforeFilter > __HARD_ADT_WAER_ON_THRD__)\r
+            {\r
+                GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] wear on condition is not match ! r = %d, r_diff = %d\r\n",unCurrentFrameRawdata,snDiffRawdata);\r
+            }\r
+        }\r
+        if(snDiffRawdata > 30000)\r
+        {\r
+        GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe]ppg 5Hz diff big event, Rawdata = %d, unRawdataDiff = %d\r\n",*punRawdata,snDiffRawdata);\r
+        }\r
+    }\r
+    else if(WEAR_DETECT_WEAR_OFF == g_uchWearDetectStatus)\r
+    {\r
+        *pemWearStatus = WEAR_STATUS_WEAR_ON;\r
+        if(unRawDataBeforeFilter < __HARD_ADT_WAER_OFF_THRD__)\r
+        {\r
+            *pemWearStatus = WEAR_STATUS_WEAR_OFF;\r
+            g_uchWearDetectStatus = WEAR_DETECT_WEAR_ON;\r
+            GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe]ppg 5Hz wear off event, Rawdata = %d, unRawdataDiff = %d\r\n",*punRawdata,snDiffRawdata);\r
+            GH3X2X_INFO_LOG("[GH3x2xAdtAlgoExe] wear off !\r\n");\r
+        }\r
+    }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_agc.c
new file mode 100644 (file)
index 0000000..7cfbe6d
--- /dev/null
@@ -0,0 +1,1131 @@
+/**\r
+ * @copyright (c) 2003 - 2022, Goodix Co., Ltd. All rights reserved.\r
+ *\r
+ * @file    gh3x2x_afe_agc.c\r
+ *\r
+ * @brief   gh3x2x led agc process functions\r
+ *\r
+ * @version \r
+ *\r
+ */\r
+\r
+\r
+#include <stdio.h>\r
+#include "gh3x2x_afe_agc.h"\r
+#include "gh3x2x_afe_drv.h"\r
+\r
+#define __GH3X2X_AGC_GENERAL_TRIG_H_THD__  ((8388608 + 8388608*0.85f))\r
+#define __GH3X2X_AGC_GENERAL_TRIG_L_THD__  ((8388608 + 8388608*0.15f))\r
+#define __GH3X2X_AGC_GENERAL_IDEAL_VALUE__ ((8388608 + 8388608*0.56f))\r
+#define __GH3X2X_AGC_SPO2_TRIG_H_THD__  ((8388608 + 8388608*0.9f))\r
+#define __GH3X2X_AGC_SPO2_TRIG_L_THD__  ((8388608 + 8388608*0.5f))\r
+#define __GH3X2X_AGC_SPO2_IDEAL_VALUE__  ((8388608 + 8388608*0.7f))\r
+#define __GH3X2X_AGC_CONVERGENCE_LEVEL__  (16)  // The values that can be set are 8, 16 and 32, and the recommended value is 16. The larger the value, the smaller the convergence range of AGC. \r
+\r
+//sub channel\r
+\r
+#define GH3X2X_NEW_AGC_SUB_CHNNL_ANAYLSIS_TIME_SEC 1\r
+\r
+#define GH3X2X_AGC_REG_AGC_EN                     0\r
+#define GH3X2X_AGC_REG_LED_CURRENT_UP_LIMIT       1\r
+#define GH3X2X_AGC_REG_LED_CURRENT_DOWN_LIMIT     2\r
+#define GH3X2X_AGC_REG_LED_CURRENT_DRV0           3\r
+#define GH3X2X_AGC_REG_LED_CURRENT_DRV1           4\r
+#define GH3X2X_AGC_REG_TIA_GAIN_RX0               5\r
+#define GH3X2X_AGC_REG_TIA_GAIN_RX1               6\r
+#define GH3X2X_AGC_REG_TIA_GAIN_RX2               7\r
+#define GH3X2X_AGC_REG_TIA_GAIN_RX3               8\r
+#define GH3X2X_AGC_REG_AGC_SRC                    9\r
+#define GH3X2X_AGC_REG_BG_CANCEL_RX0              10\r
+#define GH3X2X_AGC_REG_BG_CANCEL_RX1              11\r
+#define GH3X2X_AGC_REG_BG_CANCEL_RX2              12\r
+#define GH3X2X_AGC_REG_BG_CANCEL_RX3              13\r
+#define GH3X2X_AGC_REG_SR_MULIPLIPER              14\r
+#define GH3X2X_AGC_ECG_PPG_RX_EN                  15\r
+\r
+\r
+#if __SUPPORT_SOFT_AGC_CONFIG__\r
+//main chnl\r
+STGh3x2xNewAgcMainChnlInfo  g_pstGh3x2xNewAgcMainChnlInfoEntity[GH3X2X_NEW_AGC_SLOT_NUM_LIMIT];\r
+STGh3x2xNewAgcMainChnlMeanInfo g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[GH3X2X_NEW_AGC_SLOT_NUM_LIMIT];\r
+STGh3x2xNewAgcMainChnlIdaelAdjInfo g_pstGh3x2xNewAgcMainChnlIdaelAdjInfoEntity[GH3X2X_NEW_AGC_SLOT_NUM_LIMIT];\r
+//sub chnl\r
+#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+STGh3x2xNewAgcSubChnlRxInfo    g_pstGh3x2xNewAgcSubChnlRxInfoEntity[GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT];\r
+#endif\r
+\r
+\r
+STGh3x2xNewAgcMainChnlSat g_pstGh3x2xNewAgcMainChnlSat;\r
+const GU32 g_unNewAgcSpo2Trig_H_Thd = __GH3X2X_AGC_SPO2_TRIG_H_THD__;\r
+const GU32 g_unNewAgcSpo2Trig_L_Thd = __GH3X2X_AGC_SPO2_TRIG_L_THD__;\r
+const GU32 g_unNewAgcSpo2Ideal_value = __GH3X2X_AGC_SPO2_IDEAL_VALUE__;\r
+const GU32 g_unNewAgcGeneTrig_H_Thd = __GH3X2X_AGC_GENERAL_TRIG_H_THD__;\r
+const GU32 g_unNewAgcGeneTrig_L_Thd = __GH3X2X_AGC_GENERAL_TRIG_L_THD__;\r
+const GU32 g_unNewAgcGeneIdeal_value = __GH3X2X_AGC_GENERAL_IDEAL_VALUE__;\r
+const GU8  g_uchAgcConvergence_level = __GH3X2X_AGC_CONVERGENCE_LEVEL__;\r
+\r
+\r
+// soft agc parameter\r
+static STSoftAgcCfg g_stSoftAgcCfg;\r
+extern const GU16 g_usGH3x2xTiaGainR[];\r
+\r
+GU8 g_Gh3x2xNewAgcInitFlag = 0;\r
+\r
+void GH3X2X_LedAgcPramConfig(STSoftAgcCfg* stSoftAgcCfg)\r
+{\r
+    g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn = stSoftAgcCfg->uchSlotxSoftAgcAdjEn;   //bit0: slot0\r
+       g_stSoftAgcCfg.uchSlotxSoftBgAdjEn = stSoftAgcCfg->uchSlotxSoftBgAdjEn;\r
+       g_stSoftAgcCfg.stAmbSlotCtrl.uchAmbSampleEn = stSoftAgcCfg->stAmbSlotCtrl.uchAmbSampleEn;\r
+    g_stSoftAgcCfg.uchSpo2RedSlotCfgEn = stSoftAgcCfg->uchSpo2RedSlotCfgEn;\r
+    g_stSoftAgcCfg.uchSpo2IrSlotCfgEn = stSoftAgcCfg->uchSpo2IrSlotCfgEn;\r
+       g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg32uA;\r
+       g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg64uA;\r
+       g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg128uA;\r
+       g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA = stSoftAgcCfg->stSoftAgcGainLimit.uchGainLimitBg256uA;\r
+       g_stSoftAgcCfg.unAgcTrigThd_H = stSoftAgcCfg->unAgcTrigThd_H;\r
+       g_stSoftAgcCfg.unAgcTrigThd_L = stSoftAgcCfg->unAgcTrigThd_L;\r
+       g_stSoftAgcCfg.unAgcRestrainThd_H = stSoftAgcCfg->unAgcRestrainThd_H;\r
+       g_stSoftAgcCfg.unAgcRestrainThd_L = stSoftAgcCfg->unAgcRestrainThd_L;\r
+    \r
+    GH3X2X_INFO_LOG("uchSlotxSoftAgcAdjEn = 0x%X, uchSlotxSoftBgAdjEn = 0x%X\r\n",(int)g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn,(int)g_stSoftAgcCfg.uchSlotxSoftBgAdjEn);\r
+    GH3X2X_INFO_LOG("uchAmbSampleEn = 0x%X, uchAmbSlot = 0x%X\r\n",(int)g_stSoftAgcCfg.stAmbSlotCtrl.uchAmbSampleEn,(int)g_stSoftAgcCfg.stAmbSlotCtrl.uchAmbSlot);\r
+    GH3X2X_INFO_LOG("uchSpo2RedSlotCfgEn = 0x%X,uchSpo2IrSlotCfgEn = 0x%X\r\n",(int)g_stSoftAgcCfg.uchSpo2RedSlotCfgEn,(int)g_stSoftAgcCfg.uchSpo2IrSlotCfgEn);\r
+    GH3X2X_INFO_LOG("stSoftAgcGainLimit = 0x%X,0x%X,0x%X,0x%X\r\n",g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA,g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA,g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA,g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA);\r
+    GH3X2X_INFO_LOG("unAgcTrigThd_H = %d,unAgcTrigThd_L = %d\r\n",(int)g_stSoftAgcCfg.unAgcTrigThd_H,(int)g_stSoftAgcCfg.unAgcTrigThd_L);\r
+    GH3X2X_INFO_LOG("unAgcRestrainThd_H = %d,unAgcRestrainThd_L = %d\r\n",(int)g_stSoftAgcCfg.unAgcRestrainThd_H,(int)g_stSoftAgcCfg.unAgcRestrainThd_L);\r
+\r
+}\r
+\r
+void GH3X2X_StoreRxTiaGainAfterAgc(GU8 uchGain, GU8 uchSlotNo, GU8 uchAdcNo, GU8* puchGainRecord)\r
+{\r
+    puchGainRecord[uchSlotNo*4 + uchAdcNo] = uchGain;\r
+}\r
+\r
+void GH3X2X_StoreDrvCurrentAfterAgc(GU8 DrvCurrent, GU8 uchSlotNo, GU8 uchDrvIndex, GU16* puchDrvCurrentRecord)\r
+{\r
+       if(!uchDrvIndex)\r
+       {\r
+               puchDrvCurrentRecord[uchSlotNo] = (puchDrvCurrentRecord[uchSlotNo]&0xFF00)|DrvCurrent;\r
+       }\r
+       else\r
+       {\r
+         puchDrvCurrentRecord[uchSlotNo] = (puchDrvCurrentRecord[uchSlotNo]&0x00FF)|(DrvCurrent<<8);\r
+       }       \r
+}\r
+\r
+\r
+void GH3x2xNewAgcModuleReset(void)\r
+{\r
+    g_Gh3x2xNewAgcInitFlag = 0;\r
+    GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcMainChnlInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SLOT_NUM_LIMIT*sizeof(STGh3x2xNewAgcMainChnlInfo));\r
+    GH3X2X_Memset( (GU8*)(&g_pstGh3x2xNewAgcMainChnlSat),0,sizeof(STGh3x2xNewAgcMainChnlSat)); // init  variable\r
+    GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcMainChnlMeanInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SLOT_NUM_LIMIT*sizeof(STGh3x2xNewAgcMainChnlMeanInfo)); \r
+    GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcMainChnlIdaelAdjInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SLOT_NUM_LIMIT*sizeof(STGh3x2xNewAgcMainChnlIdaelAdjInfo));                           \r
+               \r
+         #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+    Gh3x2xNewAgcSubChnlModuleReset();   \r
+               #endif\r
+}\r
+ \r
+void GH3X2X_NewAgcRecoveryAgcRegToMainChnl(GU8 uchSlotIdx, STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo)\r
+{\r
+    GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_UP_LIMIT, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegLedCurrentMax);\r
+    GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DOWN_LIMIT, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegLedCurrentMin);\r
+    GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_AGC_SRC, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegAgcSrc);\r
+    GH3X2X_INFO_LOG("[NewAgc] recover agc src:agc_src = %d, SlotNo = %d\r\n",pstAgcMainChnlInfo ->uchBakRegAgcSrc,uchSlotIdx);\r
+}\r
+\r
+GU8 GH3X2X_NewAgcFindSubChnlSlotInfo(GU8 uchSlot)\r
+{\r
+    for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++)\r
+    {\r
+        STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt];\r
+        if(pstAgcMainChnlInfo ->uchEnable)\r
+        {\r
+            if(uchSlot == (pstAgcMainChnlInfo ->uchSlotAdc >> 2))\r
+            {\r
+                return uchSlotCnt;\r
+            }\r
+        }\r
+    }\r
+    return 0;\r
+}\r
+\r
+GU16 GH3x2xCalTrigerUpLimitForBiggerGain(GU8 uchCurrentGain ,GU8 uchSlotNo)\r
+{\r
+    GU32 unTempRawdata;\r
+    GU32 unTempTrigThd_H;\r
+\r
+    GU8 uchSlotCnt = GH3X2X_NewAgcFindSubChnlSlotInfo(uchSlotNo);\r
+    STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt];\r
+    if(pstAgcMainChnlInfo->uchSpo2ChnlIndex)\r
+    {\r
+        unTempTrigThd_H = g_unNewAgcSpo2Trig_H_Thd;\r
+    }else\r
+    {\r
+        unTempTrigThd_H = g_unNewAgcGeneTrig_H_Thd;\r
+    }\r
+        \r
+    if(12 <= uchCurrentGain)\r
+    {\r
+        return 0xFFFF;\r
+    }\r
+    else\r
+    {\r
+        unTempRawdata = unTempTrigThd_H - 8388608;\r
+        unTempRawdata = 8388608 + (GU32)(((float)unTempRawdata)/(float)1.3*(float)g_usGH3x2xTiaGainR[uchCurrentGain]/(float)g_usGH3x2xTiaGainR[uchCurrentGain + 1]);\r
+        return unTempRawdata>>8;\r
+    }\r
+}\r
+\r
+\r
+#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+void GH3x2xNewAgcSubChnlClearAnalysisCntAndSetGain(GU8 uchSlotNo, GU8 uchRxEn ,GU8 uchNextGain)\r
+{\r
+    for(GU8 uchRxCnt = 0; uchRxCnt < 4; uchRxCnt ++)\r
+    {\r
+        if(uchRxEn&(1 << uchRxCnt))\r
+        {\r
+            for(GU8 uchChnlCnt = 0; uchChnlCnt < GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT; uchChnlCnt ++)\r
+            {\r
+                STGh3x2xNewAgcSubChnlRxInfo *pstSTGh3x2xNewAgcSubChnlRxInfo = &(g_pstGh3x2xNewAgcSubChnlRxInfoEntity[uchChnlCnt]);\r
+                if(pstSTGh3x2xNewAgcSubChnlRxInfo->uchEn)\r
+                {\r
+                    if(((uchSlotNo << 2) + uchRxCnt) == pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo)\r
+                    {\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->usAnalysisCnt = 0;\r
+                        if(0xFF != uchNextGain)\r
+                        {\r
+                            GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + uchRxCnt, uchSlotNo, 0);\r
+                            pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain = uchNextGain;\r
+                            pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain = GH3x2xCalTrigerUpLimitForBiggerGain(uchNextGain,pstSTGh3x2xNewAgcSubChnlRxInfo->uchSlotAdcNo >> 2);\r
+                        }\r
+                    }    \r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+#endif\r
+  \r
+  \r
+void GH3x2xNewAgcMeanInfoReset(GU8 uchSlotEnChange)\r
+{\r
+     for(GU8 uchSlotCnt = 0; uchSlotCnt < 8; uchSlotCnt++)\r
+     {\r
+        if( uchSlotEnChange & (1<<uchSlotCnt)) // SlotEn Change \r
+        {\r
+            for(GU8 uchAgcSlotCnt = 0; uchAgcSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchAgcSlotCnt ++) //// uchAgcSlotCnt'??????slot????\r
+            {\r
+                GU8  uchSlotIdx = ((g_pstGh3x2xNewAgcMainChnlInfoEntity[uchAgcSlotCnt].uchSlotAdc >> 2) & 0x0f);\r
+                GU8  uchEnable = g_pstGh3x2xNewAgcMainChnlInfoEntity[uchAgcSlotCnt].uchEnable;\r
+                if( uchEnable )  \r
+                { \r
+                   if( uchSlotIdx == uchSlotCnt)  \r
+                   {\r
+                       g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchAgcSlotCnt].usAnalysisCnt = 0;\r
+                       #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+                       GH3x2xNewAgcSubChnlClearAnalysisCntAndSetGain(uchSlotIdx, 0x0F, 0xFF); //clear all rx analysis cnt in this slot\r
+                       #endif \r
+                   }\r
+                }\r
+            }\r
+        }\r
+     }\r
+}    \r
+\r
+GU8 GH3x2xGetDrvCurrent(GU8 uchSlotIdx ,GU8 uchAgcEn)\r
+{\r
+    GU8 uchTempDrv;\r
+    if(2 == uchAgcEn)\r
+    {    \r
+        uchTempDrv = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV1, uchSlotIdx);\r
+    }\r
+    else\r
+    {\r
+        uchTempDrv = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV0, uchSlotIdx);\r
+    }\r
+    return uchTempDrv;\r
+}\r
+\r
+void GH3x2xNewAgcChnlInfoInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+{\r
+    if(0 == GH3X2X_NEW_AGC_SLOT_NUM_LIMIT)\r
+    {\r
+        return;\r
+    }\r
+    if(0 == g_Gh3x2xNewAgcInitFlag)\r
+    {\r
+        GU8 uchNewAgcSlotCnt = 0;\r
+        for(GU8 uchSlotCnt = 0; uchSlotCnt < 8; uchSlotCnt ++)\r
+        {\r
+            if((g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn & (1 << uchSlotCnt)))\r
+            {\r
+                if(uchNewAgcSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT)\r
+                {\r
+                    g_pstGh3x2xNewAgcMainChnlInfoEntity[uchNewAgcSlotCnt].uchEnable = 1;\r
+                    g_pstGh3x2xNewAgcMainChnlInfoEntity[uchNewAgcSlotCnt].uchSlotAdc = (uchSlotCnt << 2); \r
+                                    \r
+                    /******* slot function Distinguish   START******************************************************/          \r
+                    if((g_stSoftAgcCfg.uchSpo2RedSlotCfgEn & (1 << uchSlotCnt))||(g_stSoftAgcCfg.uchSpo2IrSlotCfgEn & (1 << uchSlotCnt)))\r
+                    {\r
+                        g_pstGh3x2xNewAgcMainChnlInfoEntity[uchNewAgcSlotCnt].uchSpo2ChnlIndex =  1;\r
+                        GH3X2X_INFO_LOG("[NewAgc] uchNewAgcSpo2SlotCnt = %d\r\n",uchNewAgcSlotCnt);\r
+                    }\r
+                    /******* slot function Distinguish   END******************************************************/\r
+                    GH3X2X_INFO_LOG("[NewAgc] uchNewAgcSlotCnt = %d\r\n",uchNewAgcSlotCnt);\r
+                    uchNewAgcSlotCnt ++;\r
+                }\r
+                else\r
+                {\r
+                    GH3X2X_INFO_LOG("[NewAgc] error !!! main chnl info is no enough! \r\n");\r
+                    while(1);\r
+                }\r
+            }\r
+        }\r
+        g_Gh3x2xNewAgcInitFlag = 1;\r
+    }\r
+\r
+    for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++)\r
+    {    \r
+        STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt];\r
+        //GH3X2X_INFO_LOG_PARAM("AGC_InitValue %d: Enable = %d, AgcAdjEn = %d\r\n",uchSlotCnt, pstAgcMainChnlInfo->uchEnable,g_stSoftAgcCfg.uchSlotxSoftAgcAdjEn);\r
+        if(pstAgcMainChnlInfo->uchEnable)\r
+        {\r
+            GU8 uchSlotIdx;\r
+            uchSlotIdx = pstAgcMainChnlInfo ->uchSlotAdc >> 2;\r
+            //GH3X2X_INFO_LOG_PARAM("AGC_InitFlag%d: SlotCfgX=%d, Vaule = %d\r\n",uchSlotCnt, uchSlotIdx, pstAgcMainChnlInfo->uchHaveBakRegFlag);\r
+            if(0 == pstAgcMainChnlInfo ->uchHaveBakRegFlag)\r
+            {\r
+                GU8 uchBgCancel;\r
+                GU8 uchGainLimit;\r
+                GU16 usSampleRate;\r
+                GU16 usEcgPpgRxEn;\r
+\r
+                //bak reg\r
+                pstAgcMainChnlInfo ->uchBakRegAgcEn = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_AGC_EN, uchSlotIdx);\r
+                pstAgcMainChnlInfo ->uchBakRegAgcSrc = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_AGC_SRC, uchSlotIdx);\r
+                pstAgcMainChnlInfo ->uchSlotAdc = (uchSlotIdx << 2) + pstAgcMainChnlInfo ->uchBakRegAgcSrc;\r
+                pstAgcMainChnlInfo ->uchBakRegLedCurrentMax = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_UP_LIMIT, uchSlotIdx);                \r
+                pstAgcMainChnlInfo ->uchBakRegLedCurrentMin = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DOWN_LIMIT, uchSlotIdx);    \r
+                pstAgcMainChnlInfo ->uchBakTiaGain = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx);\r
+                pstAgcMainChnlInfo ->uchCurrentTiaGain = pstAgcMainChnlInfo ->uchBakTiaGain;\r
+                pstAgcMainChnlInfo ->uchCurrentDrv =  GH3x2xGetDrvCurrent(uchSlotIdx, pstAgcMainChnlInfo->uchBakRegAgcEn); \r
+                //GH3X2X_StoreDrvCurrentAfterAgc(pstAgcMainChnlInfo ->uchCurrentDrv, uchSlotIdx,g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc);                                                        \r
+                uchBgCancel = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_BG_CANCEL_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx);\r
+                GH3X2X_StoreRxTiaGainAfterAgc(pstAgcMainChnlInfo->uchBakTiaGain, uchSlotIdx, pstAgcMainChnlInfo->uchBakRegAgcSrc, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc);\r
+                if(0 == uchBgCancel)\r
+                {\r
+                    uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA;\r
+                }\r
+                else if(1 == uchBgCancel)\r
+                {\r
+                    uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA;\r
+                }\r
+                else if(2 == uchBgCancel)\r
+                {\r
+                    uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA;\r
+                }\r
+                else\r
+                {\r
+                    uchGainLimit = g_stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA;\r
+                }\r
+                GH3X2X_INFO_LOG("[NewAgc] uchGainLimit = %d, uchSlotIdx = %d\r\n",uchGainLimit, uchSlotIdx);\r
+                pstAgcMainChnlInfo ->uchTiaGainUpLimit = uchGainLimit;\r
+                usSampleRate = 1000/(GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_SR_MULIPLIPER, uchSlotIdx) + 1);\r
+                usEcgPpgRxEn = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_ECG_PPG_RX_EN, uchSlotIdx);\r
+                GH3X2X_INFO_LOG("[NewAgc] usEcgPpgRxEn = 0x%X\r\n",usEcgPpgRxEn);\r
+                if(usEcgPpgRxEn&0x0001)  // ecg is enable\r
+                {\r
+                    usEcgPpgRxEn = ((usEcgPpgRxEn>>1) & (~0x0008));  //clear RX3 enable bit\r
+                }\r
+                else\r
+                {\r
+                    usEcgPpgRxEn = (usEcgPpgRxEn>>1);\r
+                }\r
+                usEcgPpgRxEn &= (~(1 << pstAgcMainChnlInfo ->uchBakRegAgcSrc));   //clear main channel RX enable bit\r
+                \r
+                g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].usSampleRate = usSampleRate;  //init\r
+                GH3X2X_INFO_LOG("[AgcInit] SlotCnt = %d, SampleRate = %d\r\n", uchSlotCnt, usSampleRate); \r
+                //sub channel slot\r
+#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+                GH3x2xNewAgcSetNewSubChnl(uchSlotIdx,usEcgPpgRxEn,STGh3x2xAgcInfo);\r
+#endif\r
+                pstAgcMainChnlInfo ->uchHaveBakRegFlag = 1;                \r
+                GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_AGC_EN, uchSlotIdx, 0);   // disable hardware agc \r
+            }\r
+            else\r
+            {\r
+              pstAgcMainChnlInfo ->uchCurrentTiaGain = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx);\r
+              pstAgcMainChnlInfo ->uchCurrentDrv =  GH3x2xGetDrvCurrent(uchSlotIdx, pstAgcMainChnlInfo->uchBakRegAgcEn);\r
+              //GH3X2X_INFO_LOG_PARAM("Drv Gian inite read %d: IniteDrv = %d, IniteGain = %d\r\n",uchSlotIdx, pstAgcMainChnlInfo ->uchCurrentDrv, pstAgcMainChnlInfo ->uchCurrentTiaGain);\r
+              ////get initial DRV and current in case them change before StartSampling()\r
+//              GH3X2X_NewAgcRecoveryAgcRegToMainChnl(uchSlotIdx,pstAgcMainChnlInfo);\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+\r
+GU32 GH32x2xMedSel(GU32 unData0, GU32 unData1, GU32 unData2)\r
+{\r
+    if((unData0 >= unData1)&&(unData0 <= unData2))\r
+    {\r
+        return unData0;\r
+    }\r
+    if((unData0 >= unData2)&&(unData0 <= unData1))\r
+    {\r
+        return unData0;\r
+    }\r
+    if((unData1 >= unData0)&&(unData1 <= unData2))\r
+    {\r
+        return unData1;\r
+    }\r
+    if((unData1 >= unData2)&&(unData1 <= unData0))\r
+    {\r
+        return unData1;\r
+    }\r
+    return unData2;\r
+}\r
+\r
+float GH3X2X_CalcfRelativeVpp(GU32 unRawdata, GU8 uchDrv, GU8 uchGain)\r
+{\r
+    return ((float)unRawdata/(float)uchDrv/(float)g_usGH3x2xTiaGainR[uchGain]);\r
+}\r
+\r
+void GH3X2X_StoreTiaGainAfterAgc(GU16 usGainRegValue, GU8 uchSlotNo, GU8* puchGainRecord)\r
+{\r
+    for(GU8 uchAdcCnt = 0; uchAdcCnt < 4; uchAdcCnt ++)\r
+    {\r
+        puchGainRecord[uchSlotNo*4 + uchAdcCnt] = (usGainRegValue>>(uchAdcCnt*4))&0x000F;\r
+        GH3X2X_INFO_LOG("StoreTiaGainAfterAgc slot no = %d, adc no = %d, usGainRegValue = %d\r\n", uchSlotNo,uchAdcCnt,usGainRegValue);\r
+    }\r
+}\r
+\r
+void GH3X_AgcGetThreshold( GU8 uchSpo2ChnlIndex, GU32* punTemp_H_Thd, GU32* punTemp_L_Thd )\r
+{  \r
+   if(uchSpo2ChnlIndex) // is  spo2 slot\r
+   {\r
+      *punTemp_H_Thd = g_unNewAgcSpo2Trig_H_Thd; \r
+      *punTemp_L_Thd = g_unNewAgcSpo2Trig_L_Thd; \r
+   }else\r
+   { \r
+      *punTemp_H_Thd = g_unNewAgcGeneTrig_H_Thd;\r
+      *punTemp_L_Thd = g_unNewAgcGeneTrig_L_Thd;      \r
+   }\r
+}\r
+\r
+#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+void Gh3x2xNewAgcSubChnlModuleReset(void)\r
+{\r
+    #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+    GH3X2X_Memset((GU8*)g_pstGh3x2xNewAgcSubChnlRxInfoEntity,0,(GU16)GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT*sizeof(STGh3x2xNewAgcSubChnlRxInfo));\r
+    #endif\r
+}\r
+\r
+GU8 GH3x2xNewAgcSetNewSubChnl(GU8 uchSlotNo, GU8 uchRxEn, STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+{\r
+    GU8 uchSetSuccess = 1;\r
+    for(GU8 uchRxCnt = 0; uchRxCnt < 4; uchRxCnt ++)\r
+    {\r
+        if(uchRxEn&(1 << uchRxCnt))\r
+        {\r
+            uchSetSuccess = 0;\r
+            for(GU8 uchChnlCnt = 0; uchChnlCnt < GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT; uchChnlCnt ++)\r
+            {\r
+                STGh3x2xNewAgcSubChnlRxInfo *pstSTGh3x2xNewAgcSubChnlRxInfo = &(g_pstGh3x2xNewAgcSubChnlRxInfoEntity[uchChnlCnt]);\r
+                if(0 ==  pstSTGh3x2xNewAgcSubChnlRxInfo->uchEn)\r
+                {\r
+                    pstSTGh3x2xNewAgcSubChnlRxInfo->uchEn = 1;\r
+                    pstSTGh3x2xNewAgcSubChnlRxInfo->uchSlotAdcNo = (uchSlotNo << 2) + uchRxCnt;\r
+                    //read current gain\r
+                    pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain = GH3x2x_AFEGetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + uchRxCnt, uchSlotNo);\r
+                    GH3X2X_INFO_LOG("[NewAgc] Sub chnl current Gain = %d, Slot = %d, Rx = %d\r\n",pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain,uchSlotNo,uchRxCnt);\r
+                    pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain = GH3x2xCalTrigerUpLimitForBiggerGain(pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain, uchSlotNo);\r
+                    GH3X2X_INFO_LOG("[NewAgc] usTrigeUpLimitForBiggerGain = %d, Slot = %d, Rx = %d\r\n",((GU32)pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain)<<8,uchSlotNo,uchRxCnt);\r
+                    GH3X2X_StoreRxTiaGainAfterAgc(pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain, uchSlotNo, uchRxCnt, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc);\r
+                    uchSetSuccess = 1;\r
+                    break;\r
+                }\r
+            }\r
+            if(0 == uchSetSuccess)\r
+            {\r
+                GH3X2X_INFO_LOG("[NewAgc] Set new sub chnl fail !!! Slot = %d, Rx = %d\r\n",uchSlotNo,uchRxCnt);\r
+                while(1);\r
+            }\r
+        }\r
+    }\r
+    return uchSetSuccess;\r
+}\r
+#endif\r
+\r
+#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+void GH3X2X_NewAgcSubChnlGainAdj(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+{\r
+    for(GU8 uchChnlCnt = 0; uchChnlCnt < GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT; uchChnlCnt ++)\r
+    {    \r
+        GU16 usAnalysisDiscardLen;\r
+        GU16 usAnalysisEndLen;\r
+        GU8  uchSlotCnt;\r
+        GU8  uchSlotIdx;\r
+        GU8  uchAdcNo;\r
+        GU32 unTempTrigThd_L;\r
+        GU32 unTempTrigThd_H;\r
+        STGh3x2xNewAgcSubChnlRxInfo *pstSTGh3x2xNewAgcSubChnlRxInfo = &(g_pstGh3x2xNewAgcSubChnlRxInfoEntity[uchChnlCnt]);\r
+        uchSlotIdx = pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo >> 2;\r
+        uchAdcNo = pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo&0x03;\r
+        uchSlotCnt = GH3X2X_NewAgcFindSubChnlSlotInfo(uchSlotIdx);\r
+        GU16 usSampleRate = g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].usSampleRate;\r
+        GU8 uchTiaGainLimit = g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt].uchTiaGainUpLimit;\r
+        usAnalysisDiscardLen = (usSampleRate<<1)/5;    //  2/5 Fs\r
+        usAnalysisEndLen = usAnalysisDiscardLen + usSampleRate * GH3X2X_NEW_AGC_SUB_CHNNL_ANAYLSIS_TIME_SEC;\r
+ \r
+        GH3X_AgcGetThreshold(g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt].uchSpo2ChnlIndex,&unTempTrigThd_H, &unTempTrigThd_L);    \r
+             \r
+        if(pstSTGh3x2xNewAgcSubChnlRxInfo ->uchEn)\r
+        {\r
+           // prevent unRawdataSum(GU32) overflow\r
+           if( (usAnalysisEndLen - usAnalysisDiscardLen) > 200 )  \r
+           {\r
+              usAnalysisDiscardLen = usAnalysisEndLen - 200;   // maximum number of accumulated rawdata is 200\r
+           }\r
+   \r
+            for (GU16 usIndex = 0; usIndex < usFifoLen; usIndex += GH3X2X_AFE_FIFO_RAWDATA_SIZE) \r
+            {\r
+                GU32 unFifoVal;\r
+                GU8  uchSlotAdcNo;\r
+                GU32 unDataRaw; \r
+                unFifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchReadFifoBuffer[usIndex], puchReadFifoBuffer[usIndex + 1], \r
+                                                puchReadFifoBuffer[usIndex + 2], puchReadFifoBuffer[usIndex + 3]);\r
+                uchSlotAdcNo = ((unFifoVal >> 27)&0x0000001F);\r
+                unDataRaw = GH3X2X_RAWDATA_CLEAR_ALL_FLAG(unFifoVal);\r
+                if(uchSlotAdcNo == pstSTGh3x2xNewAgcSubChnlRxInfo ->uchSlotAdcNo)\r
+                {\r
+                    if(usAnalysisDiscardLen == pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt) //init\r
+                    {\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->unRawdataSum = 0;\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastLastRawdata = unDataRaw;\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata = unDataRaw;\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCnt = 0;\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCntForBiggerGain = 0;\r
+                    }\r
+                    if(pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt < usAnalysisEndLen)  //analysising\r
+                    {                \r
+                        GU32 unTempRawdata = GH32x2xMedSel(pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastLastRawdata, pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata, unDataRaw);\r
+                        if(usAnalysisDiscardLen == pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt)\r
+                        {\r
+                            GH3X2X_INFO_LOG("[NewAgc] sub chnl unTempRawdata  = %d, Slot = %d, rx = %d\r\n",unTempRawdata, uchSlotIdx, uchAdcNo);\r
+                        }\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->unRawdataSum += unTempRawdata;\r
+                        if(unTempRawdata > unTempTrigThd_H)\r
+                        {\r
+                            pstSTGh3x2xNewAgcSubChnlRxInfo->usMoreThanUpLimitPointCnt ++;\r
+                        }\r
+                        if((unTempRawdata >> 8) > pstSTGh3x2xNewAgcSubChnlRxInfo->usTrigeUpLimitForBiggerGain)\r
+                        {\r
+                            pstSTGh3x2xNewAgcSubChnlRxInfo->usMoreThanUpLimitPointCntForBiggerGain ++;\r
+                        }\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastLastRawdata = pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata;\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo ->unLastRawdata = unDataRaw;\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt ++;                    \r
+                    }\r
+                    else //anlysis finished\r
+                    {\r
+                        GU32 unAvaRawdata;\r
+                        GU16 unRealAnaylsisNum = usAnalysisEndLen - usAnalysisDiscardLen;\r
+                        GU8  uchNextGain = 0xFF;\r
+                        GU8  uchCurrentGain = pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain;\r
+                        unAvaRawdata = pstSTGh3x2xNewAgcSubChnlRxInfo ->unRawdataSum/unRealAnaylsisNum;\r
+                        GH3X2X_INFO_LOG("[NewAgc] sub chnl rawdata ava  = %d,DownLimit = %d, Slot = %d, rx = %d\r\n",unAvaRawdata, unTempTrigThd_L,uchSlotIdx, uchAdcNo);\r
+                        GH3X2X_INFO_LOG("[NewAgc] usMoreThanUpLimitPointCnt  = %d,UpLimit = %d, Slot = %d, rx = %d\r\n",pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCnt, unTempTrigThd_H,uchSlotIdx, uchAdcNo);\r
+                        GH3X2X_INFO_LOG("[NewAgc] usMoreThanUpLimitPointCntForBiggerGain = %d,UpLimit = %d, Slot = %d, rx = %d\r\n",pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCntForBiggerGain, ((GU32)pstSTGh3x2xNewAgcSubChnlRxInfo->usTrigeUpLimitForBiggerGain)<<8, uchSlotIdx, uchAdcNo);\r
+                        if(pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCnt > (unRealAnaylsisNum >> 3))  // 1/8 points is bigger than trige up limit\r
+                        {\r
+                            if(uchCurrentGain > 0)\r
+                            {\r
+                                uchNextGain = uchCurrentGain - 1;\r
+                            }\r
+                        }\r
+                        if((pstSTGh3x2xNewAgcSubChnlRxInfo ->usMoreThanUpLimitPointCntForBiggerGain < (unRealAnaylsisNum >> 3))&&(unAvaRawdata < unTempTrigThd_L))\r
+                        {\r
+                            if(uchCurrentGain < uchTiaGainLimit)\r
+                            {\r
+                                uchNextGain = uchCurrentGain + 1;\r
+                            }\r
+                        }\r
+                        if(0xFF != uchNextGain)\r
+                        {                            \r
+                            GH3X2X_INFO_LOG("[NewAgc] sub chnl gain change: NewGain = %d, OldGain = %d, Slot = %d, rx = %d\r\n",uchNextGain,uchCurrentGain, uchSlotIdx, uchAdcNo);\r
+                            GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + uchAdcNo, uchSlotIdx, uchNextGain);\r
+                            pstSTGh3x2xNewAgcSubChnlRxInfo ->uchCurrentGain = uchNextGain;\r
+                            pstSTGh3x2xNewAgcSubChnlRxInfo ->usTrigeUpLimitForBiggerGain = GH3x2xCalTrigerUpLimitForBiggerGain(uchNextGain, uchSlotIdx);                                    \r
+                            GH3X2X_StoreRxTiaGainAfterAgc(uchNextGain, uchSlotIdx, uchAdcNo, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc);\r
+                        }\r
+                        pstSTGh3x2xNewAgcSubChnlRxInfo->usAnalysisCnt = 0;    \r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+}\r
+\r
+#endif\r
+\r
+\r
+/*********************************************self-test function start*****************************************/\r
+#define GH3X2X_SPO2_SELF_TEST 0\r
+\r
+#if GH3X2X_SPO2_SELF_TEST\r
+const GU32 g_uchSpo2AgcSelftestSlotAdc = 0x01;  //slot0, adc1\r
+const GU32 g_usSpo2AgcFifoLen = 25*4;\r
+const GU32 g_unSpo2AgcRawdata[] = \r
+{\r
+    10111744,9818116,10074798,9832931,10038819,9812989,10067119,9791632,10220862,9843610,9888564,9974512,10041146,10117796,9858828,10260863,9900963,10159857,10259720,10054459,10247477,9957985,10078474,9916146,9821879\r
+};\r
+\r
+GU8 g_uchSpo2AgcFifoBuffer[4*100];\r
+\r
+void GH3X2X_Spo2AgcFifoDataGen(void)\r
+{\r
+    for (GU16 usIndex = 0; usIndex < g_usSpo2AgcFifoLen; usIndex += GH3X2X_AFE_FIFO_RAWDATA_SIZE) \r
+    {\r
+        if(usIndex >= sizeof(g_uchSpo2AgcFifoBuffer))\r
+        {\r
+            break;\r
+        }\r
+        g_uchSpo2AgcFifoBuffer[usIndex + 0] = (g_uchSpo2AgcSelftestSlotAdc<<3);\r
+        g_uchSpo2AgcFifoBuffer[usIndex + 1] = (0x000000FF&(g_unSpo2AgcRawdata[usIndex/4] >> 16));\r
+        g_uchSpo2AgcFifoBuffer[usIndex + 2] = (0x000000FF&(g_unSpo2AgcRawdata[usIndex/4] >> 8));\r
+        g_uchSpo2AgcFifoBuffer[usIndex + 3] = (0x000000FF&(g_unSpo2AgcRawdata[usIndex/4] >> 0));\r
+    }\r
+}\r
+#endif\r
+/*********************************************self-test function end*****************************************/\r
+\r
+\r
+/****************************************************************\r
+* Description: calculate mean value of main channel  \r
+* Input:  rawdata  \r
+* Return: none\r
+******************************************************************/\r
+static void GH3X2X_NewAgcMainChnlMeanValueCal(GU8* puchReadFifoBuffer, GU16 usFifoLen, GU32 *punRawdataMean, GU8 *pAdjFlag)\r
+{\r
+    for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++)\r
+    {\r
+        STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt];\r
+        GU8 uchMainChnlSlotAdcNo = pstAgcMainChnlInfo ->uchSlotAdc;\r
+        \r
+        if(pstAgcMainChnlInfo ->uchEnable)   // is  enabled  slot\r
+        {        \r
+            GU32 unTemp_Trig_H_Thd;    \r
+            GU32 unTemp_Trig_L_Thd;    \r
+            GU32 unTemp_Ideal_value;\r
+            GU16 usAnalysisEndLen; \r
+            GU16 usAnalysisDiscardLenAdjust = 0;\r
+            GU16 usAnalysisDiscardLenTrige;\r
+            GU32 TrigeMean  = 0; \r
+\r
+            if(pstAgcMainChnlInfo->uchSpo2ChnlIndex) // is  spo2 slot\r
+            {\r
+                unTemp_Ideal_value= g_unNewAgcSpo2Ideal_value;\r
+            }else\r
+            {                        \r
+                unTemp_Ideal_value= g_unNewAgcGeneIdeal_value;\r
+            }\r
+            GH3X_AgcGetThreshold( pstAgcMainChnlInfo->uchSpo2ChnlIndex, &unTemp_Trig_H_Thd, &unTemp_Trig_L_Thd);  \r
+                      \r
+            STGh3x2xNewAgcMainChnlMeanInfo *pstNewAgcMainChnlMeanInfo = &g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt];\r
+            STGh3x2xNewAgcMainChnlIdaelAdjInfo *pstNewAgcMainChnlIdaelAdjInfo = &g_pstGh3x2xNewAgcMainChnlIdaelAdjInfoEntity[uchSlotCnt];\r
+            GU16 usSampleRate =  pstNewAgcMainChnlMeanInfo->usSampleRate;\r
+            usAnalysisEndLen = (usSampleRate<<2)/5;            // 4/5 Fs  \r
+            usAnalysisDiscardLenTrige =  (usSampleRate<<1)/5;  // drop the first 2/5 data    \r
+            //have agc motion at last fifo read period or first init                        \r
+            if(pstNewAgcMainChnlMeanInfo->uchHaveAgcAtLastReadPrd)   \r
+            {\r
+                usAnalysisDiscardLenAdjust = (usSampleRate<<1)/5;  // drop the first 2/5 data\r
+                //// After AGC, the previous data is drop to calcluate precise mean\r
+                if(!pstNewAgcMainChnlMeanInfo->uchDropFlag)\r
+                {  // The frame count is only cleared for the first time to prevent data num cannot to be SampleRate\r
+                    pstNewAgcMainChnlMeanInfo->usAnalysisCnt = 0;  \r
+                    pstNewAgcMainChnlMeanInfo->uchDropFlag = 1;\r
+                }         \r
+            }\r
+            //The data fluctuates when initializing the early stage  \r
+            if(!pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst)  \r
+            {\r
+                usAnalysisDiscardLenAdjust =  (usSampleRate<<1)/5;  // drop the first 2/5 data\r
+            }\r
+\r
+           // prevent unSumAdjust(GU32) overflow\r
+           if( (usAnalysisEndLen - usAnalysisDiscardLenAdjust) > 200 )\r
+           {\r
+              usAnalysisDiscardLenAdjust = usAnalysisEndLen - 200; // maximum number of accumulated rawdata is 200\r
+           }\r
+           \r
+           if( (usAnalysisEndLen - usAnalysisDiscardLenTrige) > 200 )\r
+           {\r
+              usAnalysisDiscardLenTrige = usAnalysisEndLen - 200;\r
+           }\r
+\r
+            for (GU16 usIndex = 0; usIndex < usFifoLen; usIndex += GH3X2X_AFE_FIFO_RAWDATA_SIZE) \r
+            {\r
+                GU32 unFifoVal;\r
+                GU8  uchSlotAdcNo;\r
+                GU32 unDataRaw; \r
+                unFifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchReadFifoBuffer[usIndex], puchReadFifoBuffer[usIndex + 1], \r
+                                                puchReadFifoBuffer[usIndex + 2], puchReadFifoBuffer[usIndex + 3]);\r
+                uchSlotAdcNo = ((unFifoVal >> 27)&0x0000001F);\r
+                unDataRaw = GH3X2X_RAWDATA_CLEAR_ALL_FLAG(unFifoVal); \r
+                //GH3X2X_INFO_LOG_SPO2("uchSlotAdcNo = %d\r\n",uchSlotAdcNo);\r
+                //GH3X2X_INFO_LOG_SPO2("uchMainChnlSlotAdcNo = %d\r\n",uchMainChnlSlotAdcNo);\r
+                if(uchSlotAdcNo == uchMainChnlSlotAdcNo)\r
+                {\r
+                    // begin Saturation judge   \r
+                    {  \r
+                        GU16 usSat_Check_Num_Max =   (usSampleRate<<2) + usSampleRate;   //// 5 seconds window\r
+                        g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt]++;\r
+                        if( unDataRaw > unTemp_Trig_H_Thd)\r
+                        {\r
+                            g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt]++;\r
+                        }\r
+                        //// as soon as posible set the Saturation flag \r
+                        if( g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt] >= (usSat_Check_Num_Max>>4) ) // about 8% of all checked data\r
+                        {\r
+                            g_pstGh3x2xNewAgcMainChnlSat.Sat_flag |= (1<<uchSlotCnt);  \r
+                            g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt] = 0; \r
+                        }     \r
+\r
+                        if(g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt] >= usSat_Check_Num_Max ) \r
+                        {                                      \r
+                            g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt] = 0;\r
+                            g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt] = 0;  \r
+                        }                                 \r
+                    } \r
+                    // end Saturation judge   \r
+                    \r
+                    //// begin mean calculate    \r
+                    ////GH3X2X_INFO_LOG_PARAM("slot = %d, uchSlotAdcNo = %d\r\n",uchSlotCnt,uchSlotAdcNo);\r
+                                     \r
+                   if(usAnalysisDiscardLenAdjust == pstNewAgcMainChnlMeanInfo->usAnalysisCnt) //init\r
+                    {\r
+                        pstNewAgcMainChnlMeanInfo->unSumAdjust =  0;\r
+                        pstNewAgcMainChnlMeanInfo->unMaxRawdata =  0;      \r
+                        pstNewAgcMainChnlMeanInfo->unMinRawdata =  16777216;\r
+                    }\r
+                                        \r
+                    if(usAnalysisDiscardLenTrige == pstNewAgcMainChnlMeanInfo->usAnalysisCnt) //init\r
+                    {\r
+                        pstNewAgcMainChnlMeanInfo->unSumTrige  =  0;\r
+                    }    \r
+                                        \r
+                    if(pstNewAgcMainChnlMeanInfo->usAnalysisCnt  < usAnalysisEndLen)   //analysising\r
+                    {\r
+                    pstNewAgcMainChnlMeanInfo->unSumAdjust +=  unDataRaw;\r
+                    pstNewAgcMainChnlMeanInfo->unSumTrige +=  unDataRaw;\r
+                    pstNewAgcMainChnlMeanInfo->usAnalysisCnt++;   \r
+                    pstNewAgcMainChnlMeanInfo->unMaxRawdata = ((unDataRaw > pstNewAgcMainChnlMeanInfo->unMaxRawdata)? unDataRaw: pstNewAgcMainChnlMeanInfo->unMaxRawdata ); // Max of  rawdata\r
+                    pstNewAgcMainChnlMeanInfo->unMinRawdata = ((unDataRaw < pstNewAgcMainChnlMeanInfo->unMinRawdata)? unDataRaw: pstNewAgcMainChnlMeanInfo->unMinRawdata ); // Min of  rawdata\r
+                    }\r
+                    else //anlysis finished   calculate mean and judge whether AGC\r
+                    {    \r
+                        // mean value to calculate gain and current\r
+                        if(usAnalysisEndLen > usAnalysisDiscardLenAdjust)\r
+                        {\r
+                            punRawdataMean[uchSlotCnt] = pstNewAgcMainChnlMeanInfo->unSumAdjust/(usAnalysisEndLen - usAnalysisDiscardLenAdjust);    \r
+                            TrigeMean = pstNewAgcMainChnlMeanInfo->unSumTrige / (usAnalysisEndLen - usAnalysisDiscardLenTrige);\r
+                        }else //  The normal case will not be executed, in case the division by 0 in abnormal case\r
+                        {\r
+                            punRawdataMean[uchSlotCnt] =   unDataRaw; \r
+                            TrigeMean =   unDataRaw; \r
+                        }\r
+                        pstNewAgcMainChnlMeanInfo ->unRawdataMean = punRawdataMean[uchSlotCnt];\r
+                        pstNewAgcMainChnlMeanInfo->usAnalysisCnt=0;\r
+                        // The mean calculation key variable is cleared    (Prevent mean calculation from being too small:Accumulation lost some data, but numble of raw is all)    \r
+                        usAnalysisDiscardLenAdjust = 0; \r
+                        pstNewAgcMainChnlMeanInfo->uchHaveAgcAtLastReadPrd = 0; //  clear  after caculate mean!!!       \r
+                        //// end mean calculate\r
+\r
+                        ///////////////////// whether AGC  and adjust the mean value to calculate gain and current\r
+                        if( (TrigeMean < unTemp_Trig_L_Thd) || (TrigeMean > unTemp_Trig_H_Thd) )\r
+                        {\r
+                            *pAdjFlag |= (1<<uchSlotCnt);  //need adjust gain and current \r
+                        }\r
+                        \r
+                        if( g_pstGh3x2xNewAgcMainChnlSat.Sat_flag & (1<<uchSlotCnt)) //if the channel is saturation\r
+                        {\r
+                            GU32 unTempMean = 0;         //Pay attention to initialization of local variables\r
+                            if( pstNewAgcMainChnlMeanInfo->unMaxRawdata > unTemp_Trig_H_Thd)\r
+                            {\r
+                                /////////// Pay attention to data truncation, use 64-bi\r
+                                unTempMean =   (GS64)unTemp_Ideal_value*(GS64)(pstNewAgcMainChnlMeanInfo->unMaxRawdata)/15099494;  // to adjust the max data to (0.8*2^23 + 2^23)\r
+                                *pAdjFlag |= (1<<uchSlotCnt);  //need adjust gain and current \r
+                            }\r
+                            \r
+                            if( punRawdataMean[uchSlotCnt] > unTemp_Ideal_value)\r
+                            {\r
+                                // adjust the mean value to calculate gain and current (reduce the DC amount)\r
+                                punRawdataMean[uchSlotCnt] = ( (punRawdataMean[uchSlotCnt]>unTempMean)? punRawdataMean[uchSlotCnt]:unTempMean );\r
+                                *pAdjFlag |= (1<<uchSlotCnt);  //need adjust gain and current \r
+                            } \r
+                            else if( pstNewAgcMainChnlMeanInfo->unMaxRawdata > unTemp_Trig_H_Thd)\r
+                            {\r
+                                punRawdataMean[uchSlotCnt] = unTempMean; //  Increasing the mean value to reduce the DC amount\r
+                            } \r
+                        }\r
+                        ////////////////////////////////////////////////////\r
+                        //////////////begin ideal value adjust \r
+                        if( (!((*pAdjFlag) & (1<<uchSlotCnt))) && (!( g_pstGh3x2xNewAgcMainChnlSat.Sat_flag & (1<<uchSlotCnt))))//if the channel not adjust and satuartion\r
+                        {\r
+                            //// The deviation of the mean and the ideal target value is above 1/16  and   Data fluctuation is less than a certain value\r
+                            if(((pstNewAgcMainChnlMeanInfo->unRawdataMean< ((unTemp_Ideal_value*(g_uchAgcConvergence_level-1))/g_uchAgcConvergence_level) ) \\r
+                                || (pstNewAgcMainChnlMeanInfo->unRawdataMean > ((unTemp_Ideal_value*(g_uchAgcConvergence_level+1))/g_uchAgcConvergence_level))) \\r
+                                &&( 10*pstNewAgcMainChnlMeanInfo->unMaxRawdata< 12*pstNewAgcMainChnlMeanInfo->unMinRawdata) ) \r
+                            {\r
+                                if( !pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst ) //// Inite First time \r
+                                {\r
+                                    pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst = 1;\r
+                                    *pAdjFlag |= (1<<uchSlotCnt);  //need adjust gain and current \r
+                                }\r
+                                else\r
+                                {\r
+                                    pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt++;\r
+                                    if(pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt >= 19)\r
+                                    {\r
+                                        *pAdjFlag |= (1<<uchSlotCnt);  //need adjust gain and current \r
+                                        pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt  = 0; \r
+                                    }    \r
+                                }             \r
+                            }\r
+                            else\r
+                            {\r
+                                 pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt  = 0;\r
+                            }                    \r
+                        }\r
+                        else\r
+                        {\r
+                             pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt  = 0;\r
+                        }\r
+                        pstNewAgcMainChnlIdaelAdjInfo->uchIniteFirst = 1;  //// Must be set to 1 after the first second!!!    \r
+                        ////end ideal value adjust \r
+                        //GH3X2X_INFO_LOG_PARAM("Mean cal: Slot_num = %d, Rawmean = %d, Adjmean = %d, TrigeMean = %d, AdjFlag= %d\r\n", uchSlotCnt,pstNewAgcMainChnlMeanInfo->unRawdataMean, punRawdataMean[uchSlotCnt]);\r
+                        //GH3X2X_INFO_LOG_PARAM("Sat flag: SatCnt = %d, SatCheck = %d, CheckMaxNum = %d, Satflag = %d\r\n", g_pstGh3x2xNewAgcMainChnlSat.Sat_cnt[uchSlotCnt], g_pstGh3x2xNewAgcMainChnlSat.Sat_CheckCnt[uchSlotCnt], g_pstGh3x2xNewAgcMainChnlSat.Sat_Check_Num_Max[uchSlotCnt], g_pstGh3x2xNewAgcMainChnlSat.Sat_flag);\r
+                        //GH3X2X_INFO_LOG_PARAM("Ideal adjust: SeconsCnt = %d\r\n", pstNewAgcMainChnlIdaelAdjInfo->uchSeconsCnt);\r
+                        //GH3X2X_INFO_LOG_PARAM("Adj flag: Slot_num = %d, Trigmean = %d, L_Thd = %d, H_Thd = %d, Adjflag = %d\r\n", uchSlotCnt,TrigeMean, unTemp_Trig_L_Thd, unTemp_Trig_H_Thd, *pAdjFlag);                                     \r
+                        g_pstGh3x2xNewAgcMainChnlSat.Sat_flag &= (~(1<<uchSlotCnt)) ; ////clear the Sat flag  \r
+\r
+                    }\r
+                }  \r
+             }\r
+        }\r
+        \r
+    }\r
+}\r
+\r
+/**\r
+ * @fn     GU8 GH3X2X_NewAgcCalDrvCurrentAndGain(GU32 CurRawdata, GU32 IdealRawdata, STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo, GU8* puchIdealDrvCurrent, GU8* puchIdealGain)\r
+ *\r
+ * @brief  mark abnormal chnl\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]   CurRawdata, IdealRawdata, uchMainChnlInfoIndex\r
+ * @param[out]  puchIdealDrvCurrent, puchIdealGain\r
+ *\r
+ * @return  0:DrvCurrent or gain will NOT change  1: DrvCurrent or gain will  change\r
+ */\r
+GU8 GH3X2X_NewAgcCalDrvCurrentAndGain(GU32 CurRawdata, GU8 uchMainChnlInfoIndex,  GU8* puchIdealDrvCurrent, GU8* puchIdealGain)\r
+{\r
+    STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchMainChnlInfoIndex];\r
+    STGh3x2xNewAgcMainChnlMeanInfo *pstMainChnlExtralInfo = &g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchMainChnlInfoIndex];\r
+\r
+    GU8 uchDefaultGain = pstAgcMainChnlInfo->uchBakTiaGain;\r
+    GU8 uchGainUpLimit = pstAgcMainChnlInfo->uchTiaGainUpLimit;\r
+    GU8 uchLedCurrentMin = pstAgcMainChnlInfo->uchBakRegLedCurrentMin;\r
+    GU8 uchLedCurrentMax = pstAgcMainChnlInfo->uchBakRegLedCurrentMax;\r
+    GU8 uchCurrentDrv = pstAgcMainChnlInfo->uchCurrentDrv;\r
+    GU8 uchCurrentTiaGain = pstAgcMainChnlInfo->uchCurrentTiaGain;\r
+ \r
+    GU8 uchNewGain = uchDefaultGain;\r
+    GU32 unIdealRawdata_no;\r
+    GU32 unTempDrvCurrent;\r
+    GU8 uchChangeFlag = 0;  //bit0: drv current flag  bit1: gain flag\r
+    GU8 uchCalFinish = 0;\r
+    GU32 unTrigUpLimit;\r
+    GU8  unCalNum = 12;\r
+  \r
+    if(0 != pstAgcMainChnlInfo->uchSpo2ChnlIndex) // is  spo2 slot\r
+    {\r
+        unTrigUpLimit = g_unNewAgcSpo2Trig_H_Thd;\r
+        unIdealRawdata_no= g_unNewAgcSpo2Ideal_value - 8388608;\r
+    }else\r
+    {\r
+        unTrigUpLimit = g_unNewAgcGeneTrig_H_Thd;\r
+        unIdealRawdata_no = g_unNewAgcGeneIdeal_value - 8388608;\r
+    }\r
+    \r
+    //GH3X2X_INFO_LOG_PARAM("Drv cal: UpLimit = %d, Mean = %d, LastMean = %d\r\n",unTrigUpLimit, pstMainChnlExtralInfo->unRawdataMean, pstMainChnlExtralInfo->unLastRawdataMean);\r
+    // reduce rawdata as soon as posible\r
+    if((unTrigUpLimit < pstMainChnlExtralInfo->unRawdataMean)&&(unTrigUpLimit < pstMainChnlExtralInfo->unLastRawdataMean)&&(uchCurrentTiaGain > 0)) \r
+    {             \r
+       uchNewGain = 0;  \r
+       unTempDrvCurrent =  uchLedCurrentMin;\r
+       uchCalFinish = 1;\r
+    }\r
+    pstMainChnlExtralInfo ->unLastRawdataMean = pstMainChnlExtralInfo ->unRawdataMean;\r
+         \r
+    if(0 == uchCalFinish)\r
+    {\r
+        //remove offset\r
+        if(CurRawdata > (8388608 + 2048))  //// Can't open DC Cance !!!\r
+        {\r
+            CurRawdata -= 8388608;\r
+        }\r
+        else\r
+        {\r
+            //The value may be less than 2^23, preventing division by 0\r
+            CurRawdata = 2048;  // Take an appropriately large number to prevent calculated DRV current overflow 32bit\r
+        }\r
+        //Rawdata stretch  (The principle of magnification: the mean divided by the ideal target value is the data reduction factor )\r
+        if(CurRawdata < 8000000)\r
+        {\r
+        }\r
+        else if(CurRawdata < 8100000)\r
+        {\r
+            CurRawdata = 8000000 + (CurRawdata - 8000000)*6;\r
+        }\r
+        else if(CurRawdata < 8200000)\r
+        {\r
+            CurRawdata = 8000000 + ((CurRawdata - 8000000)<<3);\r
+        }\r
+        else\r
+        {\r
+            // The more saturated the data, the bigger the stretch, the key is that the data is really saturated\r
+            CurRawdata = 8000000 + (CurRawdata - 8000000)*14;   //  Blood oxygen drops 1 times, heart rate drops 2.5 times  \r
+        }\r
+\r
+        //find new drv current and gain\r
+        do\r
+        {   \r
+            unTempDrvCurrent = (GS64)(((GU32)uchCurrentDrv*(GU32)g_usGH3x2xTiaGainR[uchCurrentTiaGain]))* \\r
+            (GS64)unIdealRawdata_no/g_usGH3x2xTiaGainR[uchNewGain]/CurRawdata;\r
+\r
+#if 0\r
+           //GH3X2X_INFO_LOG_PARAM("Drv cal %d: CurrentDrv = %d, CurrentGain = %d, IdealRawdata_no = %d\r\n",uchMainChnlInfoIndex, uchCurrentDrv, uchCurrentTiaGain, unIdealRawdata_no);\r
+           //GH3X2X_INFO_LOG_PARAM("Drv cal %d: unTempDrvCurrent = %d, uchNewGain = %d, Meanraw = %d, CurRawdata = %d\r\n",uchMainChnlInfoIndex,unTempDrvCurrent, uchNewGain, pstMainChnlExtralInfo->unRawdataMean, CurRawdata);\r
+#endif\r
+          \r
+            if(unTempDrvCurrent > uchLedCurrentMax)  //drv is too big, need increase gain\r
+            {\r
+                if(uchNewGain < uchGainUpLimit)\r
+                {\r
+                    uchNewGain ++ ;\r
+                }\r
+                else\r
+                {\r
+                    unTempDrvCurrent = uchLedCurrentMax;\r
+                    break;\r
+                }\r
+            }\r
+            else if(unTempDrvCurrent < uchLedCurrentMin)  //drv is too small, need dncrease gain\r
+            {\r
+                if(uchNewGain > 0)\r
+                {\r
+                    uchNewGain -- ;\r
+                }\r
+                else\r
+                {\r
+                    unTempDrvCurrent = uchLedCurrentMin;\r
+                    break;\r
+                }\r
+            }\r
+            else   //got right drv\r
+            {\r
+                break;\r
+            }\r
+            unCalNum --;\r
+        }\r
+        while (unCalNum);\r
+    }\r
+\r
+    puchIdealDrvCurrent[0] = (GU8)unTempDrvCurrent;\r
+    puchIdealGain[0] = (GU8)uchNewGain;\r
+\r
+    if(puchIdealDrvCurrent[0] != uchCurrentDrv)\r
+    {\r
+        uchChangeFlag |= 0x01;\r
+        //GH3X2X_INFO_LOG_PARAM("Drv change %d: CurrentDrv = %d,  IdealDrv = %d\r\n",uchMainChnlInfoIndex, uchCurrentDrv, puchIdealDrvCurrent[0]);\r
+    }\r
+    if(puchIdealGain[0] != uchCurrentTiaGain)\r
+    {\r
+        uchChangeFlag |= 0x02;\r
+        //GH3X2X_INFO_LOG_PARAM("Gain change %d: CurrentGain = %d,  IdealGain = %d\r\n",uchMainChnlInfoIndex, uchCurrentTiaGain, puchIdealGain[0]);\r
+    }\r
+        \r
+    return uchChangeFlag;\r
+}\r
+\r
+GU8 NewAgcMainChelFlag = 0;\r
+\r
+void GH3X2X_NewAgcMainChnlPro(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+{\r
+    GU32 unNewAgcRawdataMeanChnl[8] = {0};\r
+    GU8 uchAdjFlag = 0;     // Local variables used as judgments must be initialized to 0\r
+    GU8 uchNewDrvCurrent;\r
+    GU8 uchNewGain;    \r
+    GU8 uchChangeFlag = 0;  //bit0: drv current flag  bit1: gain flag\r
+    \r
+    if(0 == GH3X2X_NEW_AGC_SLOT_NUM_LIMIT)\r
+    {\r
+        return;\r
+    }\r
+\r
+#if GH3X2X_SPO2_SELF_TEST\r
+\r
+    GH3X2X_Spo2AgcFifoDataGen();\r
+    puchReadFifoBuffer = g_uchSpo2AgcFifoBuffer;\r
+    usFifoLen = g_usSpo2AgcFifoLen;\r
+#endif\r
+    \r
+            \r
+    GH3X2X_NewAgcMainChnlMeanValueCal( puchReadFifoBuffer,usFifoLen,unNewAgcRawdataMeanChnl,&uchAdjFlag); // caculate mean and whther adjust gain  current \r
+               \r
+    for(GU8 uchSlotCnt = 0; uchSlotCnt < GH3X2X_NEW_AGC_SLOT_NUM_LIMIT; uchSlotCnt ++)\r
+    {\r
+        if( uchAdjFlag & (1<<uchSlotCnt)) // need to AGC\r
+        {\r
+            STGh3x2xNewAgcMainChnlInfo *pstAgcMainChnlInfo = &g_pstGh3x2xNewAgcMainChnlInfoEntity[uchSlotCnt];\r
+            uchChangeFlag = GH3X2X_NewAgcCalDrvCurrentAndGain(unNewAgcRawdataMeanChnl[uchSlotCnt], uchSlotCnt, &uchNewDrvCurrent,&uchNewGain);\r
+            GU8  uchSlotIdx = ((pstAgcMainChnlInfo ->uchSlotAdc >> 2) & 0x0f);\r
+            if(uchChangeFlag&0x02)  //write tia gain to chip\r
+            {    \r
+                GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_TIA_GAIN_RX0 + pstAgcMainChnlInfo ->uchBakRegAgcSrc, uchSlotIdx, uchNewGain);    \r
+                pstAgcMainChnlInfo->uchCurrentTiaGain = uchNewGain;\r
+                GH3X2X_StoreRxTiaGainAfterAgc(uchNewGain, uchSlotIdx, pstAgcMainChnlInfo ->uchBakRegAgcSrc, STGh3x2xAgcInfo->uchTiaGainAfterSoftAgc);\r
+            }\r
+            if(uchChangeFlag&0x01)  //write drv current to chip\r
+            {\r
+                //change drv0/1\r
+                pstAgcMainChnlInfo ->uchCurrentDrv = uchNewDrvCurrent;\r
+                \r
+                if((pstAgcMainChnlInfo ->uchBakRegAgcEn)&0x01)\r
+                {\r
+                    GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV0, uchSlotIdx, uchNewDrvCurrent);    \r
+                                                                               GH3X2X_StoreDrvCurrentAfterAgc(pstAgcMainChnlInfo ->uchCurrentDrv, uchSlotIdx,0,STGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc); \r
+                }\r
+                if((pstAgcMainChnlInfo ->uchBakRegAgcEn)&0x02)\r
+                {\r
+                    GH3x2x_AFESetAgcReg(GH3X2X_AGC_REG_LED_CURRENT_DRV1, uchSlotIdx, uchNewDrvCurrent);    \r
+                                                                               GH3X2X_StoreDrvCurrentAfterAgc(pstAgcMainChnlInfo ->uchCurrentDrv, uchSlotIdx,1,STGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc);  \r
+                }\r
+                #if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+                GH3x2xNewAgcSubChnlClearAnalysisCntAndSetGain(uchSlotIdx, 0x0F, 0xFF); //clear all rx analysis cnt in this slot\r
+                #endif\r
+            }\r
+            if(uchChangeFlag)\r
+            {\r
+                g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].uchHaveAgcAtLastReadPrd = 1; // current or  gain change at last time\r
+                g_pstGh3x2xNewAgcMainChnlMeanInfoEntity[uchSlotCnt].uchDropFlag = 0;\r
+                NewAgcMainChelFlag |= (1<<uchSlotCnt); // ADjFlag write to CSV file\r
+            }                          \r
+        }                   \r
+    }     \r
+}\r
+\r
+#if  __SUPPORT_SOFT_AGC_CONFIG__\r
+/**\r
+ * @fn     static void GH3X2X_LedAgcInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+ * \r
+ * @brief  init led agc\r
+ *\r
+ * @attention   just use to show function support\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_LedAgcInit(STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+{\r
+               GH3X2X_RecordAgcInfo(); //record agc info\r
+    GH3x2xNewAgcChnlInfoInit(STGh3x2xAgcInfo);\r
+}\r
+/**\r
+ * @fn     void GH3X2X_LedAgcPramWrite(GU16 usRegVal, GU16 usRegPosi)\r
+ *\r
+ * @brief  write AGC parameter\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegVal         reg value\r
+ * @param[in]   uchRegPosi         reg posi\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_LedAgcPramWrite(GU16 usRegVal, GU16 usRegPosi)\r
+{\r
+\r
+    GU16 usByteOffset;\r
+    GU8 uchByteVal;\r
+    GU8 uchByteCnt;\r
+    for(uchByteCnt = 0; uchByteCnt < 2; uchByteCnt ++)\r
+    {\r
+        uchByteVal = ((usRegVal >> (8*uchByteCnt))&0x00FF);\r
+        usByteOffset = (usRegPosi * 2) + uchByteCnt;\r
+        if(usByteOffset < sizeof(g_stSoftAgcCfg))\r
+        {\r
+            GH3X2X_Memcpy(((GU8 *)(&g_stSoftAgcCfg)) + usByteOffset, (GU8*)(&uchByteVal), 1);\r
+        }      \r
+    }\r
+}\r
+\r
+/**\r
+ * @fn  void GH3X2X_LedAgcReset(void)\r
+ *\r
+ * @brief   reset agc parameter\r
+ *\r
+ * @attention    None\r
+ *\r
+ * @param[in]    None\r
+ * @param[out]   None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_LedAgcReset(void)\r
+{\r
+    GH3X2X_Memset(&g_stSoftAgcCfg, 0, sizeof(STSoftAgcCfg));\r
+    GH3x2xNewAgcModuleReset();\r
+}\r
+\r
+/**\r
+ * @fn     void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen)\r
+ * \r
+ * @brief  led agc process function\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   puchReadFifoBuffer         pointer to read fifo data buffer\r
+ * @param[in]   usFifoLen           read fifo data buffer length\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen, STGh3x2xAgcInfo *STGh3x2xAgcInfo)\r
+{\r
+               GH3X2X_UpdateAgcInfo();\r
+    if(usFifoLen==0)\r
+    {\r
+        return;\r
+    }\r
+    \r
+    GH3X2X_NewAgcMainChnlPro(puchReadFifoBuffer, usFifoLen,STGh3x2xAgcInfo);\r
+    \r
+#if GH3X2X_NEW_AGC_SUB_CHNL_NUM_LIMIT > 0\r
+    GH3X2X_NewAgcSubChnlGainAdj(puchReadFifoBuffer, usFifoLen,STGh3x2xAgcInfo);\r
+#endif\r
+               \r
+}\r
+#endif\r
+#endif\r
+/********END OF FILE********* Copyright (c) 2003 - 2022, Goodix Co., Ltd. ********/\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_demo.c
new file mode 100644 (file)
index 0000000..148fc99
--- /dev/null
@@ -0,0 +1,94 @@
+#include "gh3x2x_afe_ecg.h"\r
+#include "gh3x2x_afe_adt.h"\r
+#include "gh3x2x_afe_agc.h"\r
+#include "gh3x2x_afe_demo.h"\r
+\r
+\r
+\r
+GU32 g_unFuncMode = GH3X2X_NO_FUNCTION;\r
+\r
+\r
+\r
+void GH3X2X_AFE_StartFunction(GU32 unFuncMode)\r
+{\r
+    if(unFuncMode & (GH3X2X_FUNCTION_ADT))\r
+    {\r
+                   GH3x2xAdtAlgoInit();\r
+        GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ADT_SLOT_NUM,GH3X2X_ADT_SLOT_NUM,1);\r
+    }\r
+       \r
+    if(unFuncMode & (GH3X2X_FUNCTION_ECG))\r
+    {\r
+        GH3X2X_LeadOffDetectInit();                    \r
+        GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ECG_SLOT_NUM,GH3X2X_ECG_SLOT_NUM,1);\r
+        ECG_FAST_RECV_EN_CONFIG(1);\r
+    }\r
+                       \r
+    if(g_unFuncMode == GH3X2X_NO_FUNCTION)\r
+    {\r
+        GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,1);\r
+    }\r
+    g_unFuncMode |= unFuncMode;\r
+\r
+}\r
+\r
+\r
+void GH3X2X_AFE_StopFunction(GU32 unFuncMode)\r
+{\r
+    if(unFuncMode & (GH3X2X_FUNCTION_ADT))\r
+    {\r
+        GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ADT_SLOT_NUM,GH3X2X_ADT_SLOT_NUM,0);\r
+                   GH3x2xAdtAlgoDeinit();\r
+    }\r
+    if(unFuncMode & (GH3X2X_FUNCTION_ECG))\r
+    {\r
+        GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_SLOT_EN_ADDR,GH3X2X_ECG_SLOT_NUM,GH3X2X_ECG_SLOT_NUM,0);\r
+        ECG_FAST_RECV_EN_CONFIG(0);\r
+\r
+    }\r
+    g_unFuncMode &= (~unFuncMode);\r
+    if(g_unFuncMode == GH3X2X_NO_FUNCTION)\r
+    {\r
+        GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,0);\r
+    }\r
+    \r
+}\r
+\r
+\r
+void GH3X2X_AFE_Leadon_hook(void)\r
+{\r
+    GH3X2X_AFE_StartFunction(GH3X2X_FUNCTION_ECG);\r
+}\r
+\r
+void GH3X2X_AFE_Leadoff_hook(void)\r
+{\r
+    GH3X2X_AFE_StopFunction(GH3X2X_FUNCTION_ECG);\r
+    ECG_LEAD_DET_EN_CONFIG(0);// enable lead detect\r
+    ECG_LEAD_DET_EN_CONFIG(1);// enable lead detect\r
+    \r
+}\r
+\r
+\r
+void GH3X2X_DemoLedAgcPramConfig(void)\r
+{\r
+    static STSoftAgcCfg stSoftAgcCfg;\r
+\r
+         stSoftAgcCfg.uchSlotxSoftAgcAdjEn = 1;   //bit0-bit7: slot0 -slot7 \r
+         stSoftAgcCfg.uchSlotxSoftBgAdjEn = 0;\r
+         stSoftAgcCfg.stAmbSlotCtrl.uchAmbSampleEn = 0;\r
+         stSoftAgcCfg.uchSpo2RedSlotCfgEn =  2;  //bit0-bit7: slot0 -slot7 for spo2 red \r
+         stSoftAgcCfg.uchSpo2IrSlotCfgEn =  4;   //bit0-bit7: slot0 -slot7 for spo2 ir\r
+         stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg32uA = 8;\r
+         stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg64uA = 6;\r
+         stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg128uA = 5;\r
+         stSoftAgcCfg.stSoftAgcGainLimit.uchGainLimitBg256uA = 4;\r
+         stSoftAgcCfg.unAgcTrigThd_H = (GU32)(8388608 + 8388608*0.85f);\r
+         stSoftAgcCfg.unAgcTrigThd_L = (GU32)(8388608 + 8388608*0.15f);\r
+         stSoftAgcCfg.unAgcRestrainThd_H = 12868608;\r
+         stSoftAgcCfg.unAgcRestrainThd_L = 10692608;\r
+    \r
+    GH3X2X_LedAgcPramConfig(&stSoftAgcCfg);\r
+}\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_drv.c
new file mode 100644 (file)
index 0000000..b0e72b3
--- /dev/null
@@ -0,0 +1,1544 @@
+/**\r
+ * @copyright (c) 2019 - 2024, Goodix Co., Ltd. All rights reserved.\r
+ * \r
+ * @file    gh3x2x_afe_drv.c\r
+ * \r
+ * @brief   gh3x2x driver example code\r
+ *\r
+ * @author  Gooidx Iot Team\r
+ * \r
+ * @attention\r
+ *  This file just show how to init and control gh3x2x sampling.\r
+ */\r
+#include "stdio.h"\r
+#include "gh3x2x_afe_drv.h"\r
+#include "gh3x2x_afe_user.h"\r
+#include "gh3x2x_afe_ecg.h"\r
+#include "gh3x2x_afe_agc.h"\r
+#include "gh3x2x_afe_adt.h"\r
+#include "gh3x2x_afe_demo.h"\r
+\r
+#include "custom_utils.h"\r
+\r
+ \r
+#define SWAP_SIZE_OF_GU16               (2)\r
+#define SWAP_INDEX_OF_NEXT_BYTE         (1)\r
+\r
+#define GH3X2X_I2C_BUS I2C_BUS_2\r
+\r
+//extern void GH3X2X_SoftLedADJAutoADJInt(void);\r
+//extern void GH3X2X_LedAgcProcess(GU8* puchReadFifoBuffer, GU16 usFifoLen);\r
+//extern void GH3X2X_LedAgcReset(void);\r
+//extern void GH3X2X_LedAgcPramWrite(void);\r
+//extern void GH3X2X_LedAgcInit(void);\r
+\r
+STGh3x2xAgcInfo g_stGh3x2xAgcInfo = {0};\r
+STGh3x2xAgcInfo *g_pstGh3x2xAgcInfo = &g_stGh3x2xAgcInfo;\r
+\r
+GU8 g_uchNeedWakeUpGh3x2xAfe = 1; // 0: do not need wake up gh3x2x  1: need wake up gh3x2x\r
+GU8 g_uchGh3x2xAfeIntCallBackIsCalled = 0;  //0: no new interrupt    1:  have new interrupt\r
+\r
+/*********************************************** reg cfg package *******************************************/\r
+STGH3X2X_AFEReg GH3X2X_AFE_reg_list[] =\r
+{\r
+//    {0x0000, 0x0610}, {0x0004, 0x001F}, {0x0006, 0x0001}, {0x000A, 0x0010}, {0x000E, 0x000D}, {0x0100, 0x0100},\r
+//    {0x010A, 0x27FC}, {0x0110, 0x0F65}, {0x0114, 0x00AA}, {0x011E, 0x021F}, {0x0120, 0x041F}, {0x0122, 0x137F},\r
+//    {0x0126, 0xC77C}, {0x012C, 0x0C10}, {0x012E, 0x2222}, {0x0130, 0x00AA}, {0x013A, 0x010C}, {0x013C, 0x0400},\r
+//    {0x01EC, 0x027C}, {0x01EE, 0x00AC}, {0x0200, 0x0120}, {0x0208, 0x0551}, {0x0280, 0x0A00}, {0x0282, 0xF530},\r
+//    {0x0284, 0x9388}, {0x0286, 0xC45C}, {0x0288, 0xA328}, {0x0408, 0x0001}, {0x0410, 0x49F0}, {0x0412, 0x0082},\r
+//    {0x0414, 0x49F0}, {0x0416, 0x0082}, {0x0422, 0x0011}, {0x0424, 0x0901}, {0x0426, 0x0108}, {0x0428, 0x0102},\r
+//    {0x0502, 0x4360}, {0x0504, 0x000A}, {0x0588, 0x0008}, {0x0692, 0x0233}, {0x0694, 0x0400}, {0x0698, 0x2310},\r
+//    {0x0700, 0x0000}, \r
+               \r
+//             {0x0000, 0x0602}, {0x0004, 0x0013}, {0x0006, 0x0201}, {0x000A, 0x005F}, {0x000E, 0x000D}, {0x0074, 0x0048},\r
+//    {0x0100, 0x0100}, {0x010A, 0x0462}, {0x010C, 0x0000}, {0x010E, 0x0000}, {0x0110, 0x0000}, {0x0120, 0x0400},\r
+//    {0x0126, 0xC73C}, {0x0128, 0x0404}, {0x012A, 0x0404}, {0x012C, 0x0C10}, {0x012E, 0x2222}, {0x0130, 0x00AA},\r
+//    {0x0136, 0x00FF}, {0x013A, 0x000C}, {0x013C, 0x0400}, {0x01EA, 0x0033}, {0x01EC, 0x0030}, {0x01EE, 0x0098},\r
+//    {0x0200, 0x1020}, {0x0402, 0x5555}, {0x0404, 0x4120}, {0x0406, 0x0041}, {0x0408, 0x0001}, {0x0410, 0x49F0},\r
+//    {0x0412, 0x0082}, {0x0414, 0x49F0}, {0x0416, 0x0082}, {0x0422, 0x0011}, {0x0424, 0x0901}, {0x0426, 0x0109},\r
+//    {0x0428, 0x0108}, {0x0480, 0x6550}, {0x0502, 0x4C66}, {0x0506, 0x0020}, {0x0588, 0x0008}, {0x0692, 0x0233},\r
+//    {0x0694, 0x0404}, {0x0698, 0x3310}, {0x069A, 0x1101}, {0x0700, 0x0000}, {0x0400, 0x5557}, {0x1000, 0x0000},\r
+//    {0x1002, 0x3197}, {0x1004, 0x0000}, {0x1006, 0x6C91}, {0x1008, 0x2CE1}, {0x100A, 0x0001}, {0x10E0, 0x0000},\r
+//    {0x10E2, 0xFFFF}, {0x10E4, 0xFFFF}, {0x10E6, 0xFFFF}, {0x10E8, 0x0202}, {0x10EA, 0x0202}, {0x10EC, 0x0202},\r
+//    {0x10EE, 0x0202}, {0x1120, 0x005F}, {0x1122, 0x0005}, {0x1124, 0x0000}, {0x2000, 0x0004}, {0x2002, 0x2A22},\r
+//    {0x2004, 0x3A32}, {0x20EE, 0x0001}, {0x20F0, 0x001C}, {0x2880, 0x0005}, {0x288E, 0x00FA}, {0x3000, 0x0101},\r
+//    {0x3002, 0x0000}, {0x3004, 0x49F0}, {0x3006, 0x0082}, {0x4500, 0x46C9}, {0x4502, 0x0F0F}, {0x4504, 0x0002},\r
+//    {0x4506, 0x0140}, {0xFFFF, 0x0001}\r
+\r
+               {0x0000, 0x0610}, {0x0004, 0x001F}, {0x0006, 0x0001}, {0x000A, 0x0050}, {0x000E, 0x000D}, {0x0100, 0x0100},\r
+    {0x010A, 0x277C}, {0x0110, 0x0D14}, {0x0112, 0x5555}, {0x0114, 0x00AA}, {0x011E, 0x0019}, {0x0120, 0x0400},\r
+    {0x0122, 0x0CFF}, {0x0126, 0xC704}, {0x0128, 0x0001}, {0x012A, 0x0000}, {0x012C, 0x0C10}, {0x012E, 0x4442},\r
+    {0x0130, 0x0002}, {0x0136, 0x0003}, {0x013A, 0x010C}, {0x013C, 0x0400}, {0x01EC, 0x0136}, {0x01EE, 0x00AC},\r
+    {0x0200, 0x0120}, {0x0208, 0x0551}, {0x0280, 0x0A00}, {0x0282, 0xF530}, {0x0284, 0x9388}, {0x0286, 0xC45C},\r
+    {0x0288, 0xA328}, {0x0408, 0x0001}, {0x0410, 0x49F0}, {0x0412, 0x0082}, {0x0414, 0x49F0}, {0x0416, 0x0082},\r
+    {0x0422, 0x0011}, {0x0424, 0x0901}, {0x0426, 0x0108}, {0x0428, 0x0102}, {0x0502, 0x4F60}, {0x0504, 0x000A},\r
+    {0x0588, 0x0008}, {0x0692, 0x0233}, {0x0694, 0x0400}, {0x0698, 0x2310}, {0x0700, 0x0000}, {0x1000, 0x0000},\r
+    {0x1002, 0x3197}, {0x1004, 0x0000}, {0x1006, 0x6904}, {0x1008, 0x2AF6}, {0x100A, 0x0001}, {0x10E0, 0x0000},\r
+    {0x10E2, 0xFFFF}, {0x10E4, 0xFFFF}, {0x10E6, 0xFFFF}, {0x10E8, 0x0202}, {0x10EA, 0x0202}, {0x10EC, 0x0202},\r
+    {0x10EE, 0x0202}, {0x1100, 0x0004}, {0x1102, 0x0000}, {0x1120, 0x0050}, {0x1122, 0x0005}, {0x1124, 0x0000},\r
+    {0x1140, 0x0000}, {0x1142, 0x00C8}, {0x1144, 0x0001}, {0x1160, 0x0001}, {0x1162, 0x0000}, {0x1164, 0x0000},\r
+    {0x1166, 0x4568}, {0x1168, 0xCCCC}, {0x116A, 0x00EC}, {0x116C, 0x3333}, {0x116E, 0x0093}, {0x1170, 0x5C00},\r
+    {0x1172, 0x00C4}, {0x1174, 0x2800}, {0x1176, 0x00A3}, {0x2000, 0x0001}, {0x2002, 0x0022}, {0x2022, 0x0004},\r
+    {0x2024, 0x0901}, {0x2026, 0x1911}, {0x2880, 0x0005}, {0x2882, 0x0019}, {0x3000, 0x0001}, {0x3002, 0x0000},\r
+    {0x3004, 0x49F0}, {0x3006, 0x0082}, {0xFFFF, 0x0001}\r
+};\r
+\r
+GU16 GH3X2X_AFE_reg_list_len = sizeof(GH3X2X_AFE_reg_list) / sizeof(GH3X2X_AFE_reg_list[0]);\r
+\r
+\r
+void GH3X2X_SwapLittleBigEndianData(GU8 *puchDataBuffer, GU16 usDataLength)\r
+{\r
+    GU16 usIndex = 0;\r
+\r
+    for (usIndex = 0; usIndex < (usDataLength / SWAP_SIZE_OF_GU16); usIndex++)\r
+    {\r
+        puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16] ^= \\r
+                                                puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16 + SWAP_INDEX_OF_NEXT_BYTE];\r
+        puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16 + SWAP_INDEX_OF_NEXT_BYTE] ^= \\r
+                                                puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16];\r
+        puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16] ^= \\r
+                                                puchDataBuffer[usIndex * SWAP_SIZE_OF_GU16 + SWAP_INDEX_OF_NEXT_BYTE];\r
+    }\r
+}\r
+\r
+\r
+#if ( GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_SPI )\r
+\r
+\r
+/**\r
+ * @fn     static void GH3X2X_AFE_SpiSendCmd(GU8 uchCmd)\r
+ *\r
+ * @brief  Send cmd via spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   uchCmd      spi cmd\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) \r
+void GH3X2X_AFE_SpiSendCmd(GU8 uchCmd)\r
+{\r
+    GU8 uchBuffArr[1];\r
+\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = uchCmd;\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 1);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+}\r
+#endif\r
+\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) \r
+void GH3X2X_AFE_SpiSendCmdHardwareCs(GU8 uchCmd)\r
+{\r
+    GU8 uchBuffArr[1];\r
+    uchBuffArr[0] = uchCmd;\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 1);\r
+}\r
+#endif\r
+\r
+\r
+/**\r
+ * @fn     static void GH3X2X_AFE_SpiWriteReg(GU16 usRegAddr, GU16 usRegValue)\r
+ *\r
+ * @brief  Write register via spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr       register addr\r
+ * @param[in]   usRegValue      register data\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) \r
+void GH3X2X_AFE_SpiWriteReg(GU16 usRegAddr, GU16 usRegValue)\r
+{\r
+    GU8 uchBuffArr[7];\r
+\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE;\r
+    uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr);\r
+    uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr);\r
+    uchBuffArr[3] = 0;\r
+    uchBuffArr[4] = 2;\r
+    uchBuffArr[5] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegValue);\r
+    uchBuffArr[6] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegValue);\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 7);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+}\r
+#endif\r
+\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) \r
+void GH3X2X_AFE_SpiWriteRegHardwareCs(GU16 usRegAddr, GU16 usRegValue)\r
+{\r
+    GU8 puchWriteBuf[7];\r
+    puchWriteBuf[0] = 0xF0;\r
+    puchWriteBuf[1] = usRegAddr>>8;\r
+    puchWriteBuf[2] = usRegAddr&0x00FF;\r
+    puchWriteBuf[3] = 0;\r
+    puchWriteBuf[4] = 2;\r
+    puchWriteBuf[5] = usRegValue>>8;\r
+    puchWriteBuf[6] = usRegValue&0x00FF;\r
+    hal_gh3x2x_afe_spi_write(puchWriteBuf, 7);\r
+}\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+/**\r
+ * @fn     static GU16 GH3X2X_AFE_SpiReadReg(GU16 usRegAddr)\r
+ *\r
+ * @brief  Read register via spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr      register addr\r
+ * @param[out]  None\r
+ *\r
+ * @return  register data\r
+ */\r
+ \r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) \r
+GU16 GH3X2X_AFE_SpiReadReg(GU16 usRegAddr)\r
+{\r
+    GU8 uchBuffArr[3] = {0};\r
+\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE;\r
+    uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr);\r
+    uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr);\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 3);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_READ;\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 1);\r
+    hal_gh3x2x_afe_spi_read(uchBuffArr, 2);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+    return GH3X2X_AFE_MAKEUP_WORD(uchBuffArr[0], uchBuffArr[1]);\r
+}\r
+\r
+/**\r
+ * @fn      void GH3X2X_SpiReadRegs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen)\r
+ *\r
+ * @brief  Read multi register via spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr           register addr\r
+ * @param[in]   pusRegValueBuffer   pointer to register value buffer\r
+ * @param[in]   uchLen              registers len\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_SpiReadRegs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen)\r
+{\r
+    GU8 uchBuffArr[3] = {0};\r
+\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE;\r
+    uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr);\r
+    uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr);\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 3);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_READ;\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 1);\r
+    hal_gh3x2x_afe_spi_read((GU8 *)pusRegValueBuffer, uchLen * 2);\r
+    GH3X2X_SwapLittleBigEndianData((GU8 *)pusRegValueBuffer, (GU16)((GU16)uchLen * 2));\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+}\r
+\r
+#endif\r
+\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) \r
+GU16 GH3X2X_AFE_SpiReadRegHardwareCs(GU16 usRegAddr)\r
+{\r
+    GU8 puchWriteBuf[7];\r
+    GU8 puchReadBuf[2];\r
+    puchWriteBuf[0] = 0xF0;\r
+    puchWriteBuf[1] = usRegAddr>>8;\r
+    puchWriteBuf[2] = usRegAddr&0x00FF;\r
+    hal_gh3x2x_afe_spi_write(puchWriteBuf, 3);\r
+    hal_gh3x2x_afe_spi_write_F1_and_read(puchReadBuf, 2);\r
+    return ((((GU16)puchReadBuf[0])<<8) + puchReadBuf[1]);\r
+}\r
+\r
+\r
+\r
+void GH3X2X_AFE_SpiReadRegsHardwareCs(GU16 usRegAddr, GU16 *pusRegValueBuffer, GU8 uchLen)\r
+{\r
+    GU8 puchWriteBuf[3];\r
+    puchWriteBuf[0] = 0xF0;\r
+    puchWriteBuf[1] = usRegAddr>>8;\r
+    puchWriteBuf[2] = usRegAddr&0x00FF;\r
+    hal_gh3x2x_afe_spi_write(puchWriteBuf, 3);\r
+    hal_gh3x2x_afe_spi_write_F1_and_read((GU8 *)pusRegValueBuffer, uchLen * 2);\r
+    GH3X2X_SwapLittleBigEndianData((GU8 *)pusRegValueBuffer, (GU16)((GU16)uchLen * 2));\r
+}\r
+\r
+\r
+#endif\r
+\r
+\r
+\r
+\r
+\r
+/**\r
+ * @fn     static void GH3X2X_AFE_SpiReadFifo(GU8 *puchDataBuffer, GU16 usLen)\r
+ *\r
+ * @brief  Read fifo via spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   puchDataBuffer      pointer to buffer for fifo rawdata\r
+ * @param[in]   usLen               fifo bytes len\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+ \r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) \r
+static void GH3X2X_AFE_SpiReadFifo(GU8 *puchDataBuffer, GU16 usLen)\r
+{\r
+    GU8 uchBuffArr[3] = {0};\r
+\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_WRITE;\r
+    uchBuffArr[1] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR);\r
+    uchBuffArr[2] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR);\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 3);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_LOW);\r
+    uchBuffArr[0] = GH3X2X_AFE_SPI_CMD_READ;\r
+    hal_gh3x2x_afe_spi_write(uchBuffArr, 1);\r
+    hal_gh3x2x_afe_spi_read(puchDataBuffer, usLen);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_WAIT_DELAY_X_US);\r
+    hal_gh3x2x_afe_spi_cs_ctrl(GH3X2X_AFE_SPI_CS_CTRL_HIGH);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_SPI_END_DELAY_X_US);\r
+}\r
+\r
+#endif\r
+\r
+\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS) \r
+void GH3X2X_AFE_SpiReadFifoHardwareCs(GU8 *puchDataBuffer, GU16 usLen)\r
+{\r
+    GU8 puchWriteBuf[3];\r
+    puchWriteBuf[0] = 0xF0;\r
+    puchWriteBuf[1] = 0xAAAA>>8;\r
+    puchWriteBuf[2] = 0xAAAA&0x00FF;\r
+    hal_gh3x2x_afe_spi_write(puchWriteBuf, 3);\r
+    hal_gh3x2x_afe_spi_write_F1_and_read(puchDataBuffer, usLen);\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+#if ( GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_I2C )\r
+\r
+/**\r
+ * @fn     static void GH3X2X_AFE_I2cSendCmd(GU8 uchCmd)\r
+ *\r
+ * @brief  Send cmd via i2c\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   uchCmd      i2c cmd\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_I2cSendCmd(GU8 uchCmd)\r
+{\r
+    GU8 uchBuffArr[3] = {0};\r
+\r
+    uchBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(GH3X2X_AFE_I2C_CMD_ADDR);\r
+    uchBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_I2C_CMD_ADDR);\r
+    uchBuffArr[2] = uchCmd;\r
+    hal_gh3x2x_afe_i2c_write(GH3X2X_AFE_I2C_DEVICE_ADDR, uchBuffArr, 3);\r
+    // custom_i2c_write_reg(GH3X2X_AFE_I2C_DEVICE_ADDR, GH3X2X_AFE_I2C_CMD_ADDR, 1 , &uchCmd, 1, GH3X2X_I2C_BUS);\r
+}\r
+\r
+/**\r
+ * @fn     static void GH3X2X_AFE_I2cWriteReg(GU16 usRegAddr, GU16 usRegValue)\r
+ *\r
+ * @brief  Write register via i2c\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr       register addr\r
+ * @param[in]   usRegValue      register data\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_I2cWriteReg(GU16 usRegAddr, GU16 usRegValue)\r
+{\r
+    GU8 uchBuffArr[4] = {0};\r
+\r
+    uchBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr);\r
+    uchBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr);\r
+    uchBuffArr[2] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegValue);\r
+    uchBuffArr[3] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegValue);\r
+    hal_gh3x2x_afe_i2c_write(GH3X2X_AFE_I2C_DEVICE_ADDR, uchBuffArr, 4);\r
+    // custom_i2c_write_reg(GH3X2X_AFE_I2C_DEVICE_ADDR, usRegAddr, 1 , &usRegValue, szieof(usRegValue), GH3X2X_I2C_BUS);\r
+}\r
+\r
+\r
+\r
+/**\r
+ * @fn     static GU16 GH3X2X_I2cReadReg(GU16 usRegAddr)\r
+ *\r
+ * @brief  Read register via i2c\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr      register addr\r
+ * @param[out]  None\r
+ *\r
+ * @return  register data\r
+ */\r
+GU16 GH3X2X_AFE_I2cReadReg(GU16 usRegAddr)\r
+{\r
+    GU8 uchCmdBuffArr[2] = {0};\r
+    GU8 uchReadBuffArr[2] = {0};\r
+\r
+    uchCmdBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr);\r
+    uchCmdBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr);\r
+    hal_gh3x2x_afe_i2c_read(GH3X2X_AFE_I2C_DEVICE_ADDR, uchCmdBuffArr, 2, uchReadBuffArr, 2);\r
+\r
+    // custom_i2c_read_regs(GH3X2X_AFE_I2C_DEVICE_ADDR, usRegAddr, 1 , uchReadBuffArr, sizeof(uchReadBuffArr), GH3X2X_I2C_BUS);\r
+\r
+    return GH3X2X_AFE_MAKEUP_WORD(uchReadBuffArr[0], uchReadBuffArr[1]);\r
+}\r
+\r
+/**\r
+ * @fn    void GH3X2X_I2cReadRegs(GU16 usRegAddr, GU16 *pusRegValueArr, GU8 uchLen)\r
+ *\r
+ * @brief  Read multi register via i2c\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr           register addr\r
+ * @param[in]   pusRegValueBuffer   pointer to register value buffer\r
+ * @param[in]   uchLen              registers len\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_I2cReadRegs(GU16 usRegAddr, GU16 *pusRegValueArr, GU8 uchLen)\r
+{\r
+    GU8 uchBuffArr[2] = {0};\r
+\r
+    // uchBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegAddr);\r
+    // uchBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegAddr);\r
+\r
+    custom_i2c_read_regs(GH3X2X_AFE_I2C_DEVICE_ADDR, usRegAddr,1, pusRegValueArr, uchLen ,GH3X2X_I2C_BUS);\r
+\r
+    // hal_gh3x2x_afe_i2c_read(GH3X2X_AFE_I2C_DEVICE_ADDR, uchBuffArr, 2, \\r
+    //                     (GU8 *)pusRegValueArr, uchLen * 2);\r
+    GH3X2X_SwapLittleBigEndianData((GU8 *)pusRegValueArr, (GU16)uchLen * 2);\r
+}\r
+\r
+\r
+\r
+\r
+/**\r
+ * @fn     static void GH3X2X_I2cReadFifo(GU8 *puchDataBuffer, GU16 usLen)\r
+ *\r
+ * @brief  Read fifo via i2c\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   puchDataBuffer      pointer to buffer for fifo rawdata\r
+ * @param[in]   usLen               fifo bytes len\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_I2cReadFifo(GU8 *puchDataBuffer, GU16 usLen)\r
+{\r
+    GU8 uchCmdBuffArr[2] = {0};\r
+\r
+    uchCmdBuffArr[0] = GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR);\r
+    uchCmdBuffArr[1] = GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_FIFO_REG_ADDR);\r
+    hal_gh3x2x_afe_i2c_read(GH3X2X_AFE_I2C_DEVICE_ADDR, uchCmdBuffArr, 2, puchDataBuffer, usLen);\r
+}\r
+\r
+#endif\r
+\r
+/**\r
+ * @fn     void GH3X2X_WriteRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb, GU16 usValue)\r
+ *\r
+ * @brief  write register bit field via i2c or spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr      register addr\r
+ * @param[in]   uchLsb         lsb of bit field\r
+ * @param[in]   uchMsb         msb of bit field\r
+ * @param[in]   usRegValue     register data\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_WriteRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb, GU16 usValue)\r
+{\r
+    GU16 usMakData = ((((GU16)0x0001) << (uchMsb - uchLsb + 1)) - 1) << uchLsb;\r
+    GU16 usRegData = 0;\r
+    usRegData = GH3X2X_AFE_READ_REG(usRegAddr);\r
+    GH3X2X_VAL_CLEAR_BIT(usRegData, usMakData);\r
+    GH3X2X_VAL_SET_BIT(usRegData, (usValue << uchLsb) & usMakData);\r
+    GH3X2X_AFE_WRITE_REG(usRegAddr, usRegData);\r
+}\r
+\r
+/**\r
+ * @fn     GU16 GH3X2X_AFE_READ_REGBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb)\r
+ *\r
+ * @brief  Read register bit field via i2c or spi\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   usRegAddr      register addr\r
+ * @param[in]   uchLsb         lsb of bit field\r
+ * @param[in]   uchMsb         msb of bit field\r
+ * @param[out]  None\r
+ *\r
+ * @return  register bit field data\r
+ */\r
+GU16 GH3X2X_AFE_ReadRegBitField(GU16 usRegAddr, GU8 uchLsb, GU8 uchMsb)\r
+{\r
+    GU16 usMakData = ((((GU16)0x0001) << (uchMsb - uchLsb + 1)) - 1) << uchLsb;\r
+    GU16 usRegData = 0;\r
+    usRegData = GH3X2X_AFE_READ_REG(usRegAddr);\r
+    GH3X2X_AFE_VAL_GET_BIT(usRegData, usMakData);\r
+    usRegData >>= uchLsb;\r
+    return usRegData;\r
+}\r
+\r
+\r
+void GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(GU8 uchFlag)\r
+{\r
+    g_uchNeedWakeUpGh3x2xAfe = uchFlag;\r
+}\r
+\r
+GU8 GH3X2X_AFE_GetNeedWakeUpGh3x2xFlag(void)\r
+{\r
+    return g_uchNeedWakeUpGh3x2xAfe;\r
+}\r
+\r
+\r
+\r
+void GH3X2X_AFE_ExitLowPowerMode(void)\r
+{\r
+    GH3X2X_AFE_SEND_CMD(GH3X2X_AFE_CMD_WAKEUP);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_WAKE_UP_CMD_DELAY_X_US);\r
+}\r
+\r
+void GH3X2X_AFE_EnterLowPowerMode(void)\r
+{\r
+    GH3X2X_AFE_SEND_CMD(GH3X2X_AFE_CMD_SLEEP);\r
+    GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(1);\r
+}\r
+\r
+\r
+void GH3X2X_AFE_ClearEvent(GU16 usEvent)\r
+{\r
+    GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_INT_EVENT_ADDR,usEvent);\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_SendRegPackage(STGH3X2X_AFEReg* GH3X2X_AFE_reg_list,  GU16 reg_list_len)\r
+ *\r
+ * @brief  send register package (for initialize GH3X2X_AFE chip)\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  GH3X2X_AFE_reg_list      reg list that will be written to GH3X2X_AFE\r
+ * @param[in]  reg_list_len         reg count that contained in reg list\r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_SendRegPackage(STGH3X2X_AFEReg* GH3X2X_AFE_reg_list,  GU16 reg_list_len)\r
+{\r
+    GU16 luwIndex  = 0;\r
+\r
+    if ((GH3X2X_AFE_reg_list != NULL) && (reg_list_len > 0))\r
+    {\r
+        for (luwIndex = 0; luwIndex < reg_list_len; luwIndex++)\r
+        {\r
+            if (GH3X2X_AFE_REG_IS_VALID(GH3X2X_AFE_reg_list->usRegAddr))\r
+            {\r
+                GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_reg_list->usRegAddr, GH3X2X_AFE_reg_list->usRegData); \r
+            }            \r
+            GH3X2X_AFE_reg_list++;\r
+        }\r
+    }\r
+\r
+    if(GH3X2X_AFE_PRO_TYPE == GH3X2X_AFE_PRO_BY_POLLING)\r
+    {\r
+        //int pin should not action when poling mode\r
+        GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_INT_EVENT_EN_ADDR, 0); \r
+    }\r
+\r
+}\r
+\r
+\r
+\r
+/**\r
+ * @fn     GS8 GH3X2X_HardReset(void)\r
+ *\r
+ * @brief  Gh3x2x softreset via i2c/spi, can read&write reg with gh3x2x after reset\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ * @retval  #GH3X2X_RET_OK               return successfully\r
+ * @retval  #GH3X2X_RET_GENERIC_ERROR    reset pin control function not register\r
+ */\r
+void GH3X2X_AFE_Reset(void)\r
+{\r
+    GH3X2X_AFE_ClearEvent(0xFFFF);\r
+    #if(GH3X2X_AFE_RESET_TYPE == GH3X2X_AFE_RESET_HARDWARE)\r
+    hal_gh3x2x_afe_reset_pin_ctrl(0);\r
+    hal_gh3x2x_afe_DelayUs(GH3X2X_AFE_HARD_RESET_DELAY_X_US); \r
+    hal_gh3x2x_afe_reset_pin_ctrl(1); \r
+    #else\r
+    GH3X2X_AFE_SEND_CMD(GH3X2X_AFE_CMD_RESET);\r
+    #endif\r
+    hal_gh3x2x_afe_DelayMs(10);\r
+}\r
+\r
+\r
+\r
+/**\r
+ * @fn     GS8 GH3X2X_CommunicateConfirm(void)\r
+ *\r
+ * @brief  Communication operation interface confirm\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_CommunicateConfirm(void)\r
+{\r
+    GU16 uchReadData;\r
+    GU16 uchWriteData;\r
+   \r
+    if (GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_CHIP_READY_CODE_REG_ADDR) == 0xAA55)\r
+    {\r
+        uchReadData = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR);\r
+        GH3X2X_INFO_LOG("slot_time0 reg = %d\r\n", (int)uchReadData);\r
+        uchWriteData = ~uchReadData;\r
+        GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR, uchWriteData);\r
+        uchReadData = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR);\r
+        GH3X2X_INFO_LOG("slot_time0 reg = %d\r\n", (int)uchReadData);\r
+        if (uchWriteData == uchReadData)\r
+        {\r
+            uchWriteData = ~uchReadData;\r
+            GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_TMR0_REG_ADDR, uchWriteData);\r
+        }\r
+        else\r
+        {\r
+            GH3X2X_INFO_LOG("[%s]read fail or write fail!!! \r\n", __FUNCTION__);\r
+            while(1);\r
+        }\r
+    }\r
+    else\r
+    {\r
+        GH3X2X_INFO_LOG("[%s]ready code reg is error !!! \r\n", __FUNCTION__);\r
+        while(1);\r
+    }\r
+\r
+    GH3X2X_INFO_LOG("[%s]Comunication confirm ok. \r\n", __FUNCTION__);\r
+        \r
+   \r
+    \r
+\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+/*********************************************** init function*******************************************/\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_Init(void)\r
+ *\r
+ * @brief  init GH3X2X_AFE chip\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  None\r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_Init(void)\r
+{\r
+    /* Step 1: init communicate interface. */\r
+    #if(GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_SPI)\r
+    hal_gh3x2x_afe_spi_init();\r
+    #else\r
+    hal_gh3x2x_afe_i2c_init();\r
+    #endif\r
+\r
+    /* Step 2: init interupt pin  */\r
+    #if(GH3X2X_AFE_PRO_TYPE == GH3X2X_AFE_PRO_BY_INT)\r
+    hal_gh3x2x_afe_int_init();\r
+    #endif\r
+    \r
+\r
+    /* Step 3: Reset GH3X2X_AFE chip */\r
+    #if(GH3X2X_AFE_RESET_TYPE == GH3X2X_AFE_RESET_HARDWARE)\r
+    hal_gh3x2x_afe_reset_pin_init();\r
+    #endif\r
+    GH3X2X_AFE_Reset();\r
+\r
+    /* Step 4: Check conmunication and chip id is ok or not */\r
+    GH3X2X_AFE_CommunicateConfirm();\r
+       GH3X2X_AFE_CheckChipId();\r
+       GH3X2X_AFE_CheckEfuseCrc();\r
+\r
+\r
+    /* Step 5: Init GH3X2X_AFE chip */\r
+    GH3X2X_AFE_SendRegPackage(GH3X2X_AFE_reg_list, GH3X2X_AFE_reg_list_len);\r
+\r
+    /* Step 6: agc module reset and set parm*/\r
+    GH3X2X_LedAgcReset();\r
+    GH3X2X_DemoLedAgcPramConfig();\r
+    //GH3X2X_LedAgcPramWrite();\r
+               \r
+    /* Step 7: enter low power mode */\r
+    GH3X2X_AFE_EnterLowPowerMode();\r
+\r
+}\r
+\r
+/*********************************************** sample control handle function*******************************************/\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_StartSampling(GU8 SlotCfgEnable)\r
+ *\r
+ * @brief  start sample\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  SlotCfgEnable slot enable bit  bit0 control slot0, bit1 control slot1, bit2 control slot2...\r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_StartSampling(GU8 SlotCfgEnable)\r
+{\r
+    GH3X2X_AFE_ExitLowPowerMode();\r
+\r
+    //agc init\r
+    GH3X2X_LedAgcInit(g_pstGh3x2xAgcInfo);\r
+    \r
+    //write slot enable\r
+    GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_EN_ADDR, (GU16)SlotCfgEnable);\r
+    //start sample\r
+    GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,1);\r
+    \r
+    GH3X2X_AFE_EnterLowPowerMode();\r
+}\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_StopSampling(void)\r
+ *\r
+ * @brief  stop sample\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  None\r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_StopSampling(void)\r
+{\r
+    GH3X2X_AFE_ExitLowPowerMode();\r
+\r
+    //stop sample\r
+    GH3X2X_AFE_WriteRegBitField(GH3X2X_AFE_REG_START_ADDR,GH3X2X_AFE_REG_START_LSB,GH3X2X_AFE_REG_START_MSB,0);\r
+\r
+    GH3X2X_AFE_EnterLowPowerMode();\r
+}\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_SwitchSlot(GU8 SlotCfgEnable)\r
+ *\r
+ * @brief  switch sample slot.\r
+ *\r
+ * @attention   this function can only be used during sampling, after call GH3X2X_AFE_StartSampling\r
+ *\r
+ * @param[in]  SlotCfgEnable slot enable bit  bit0 control slot0, bit1 control slot1, bit2 control slot2...\r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_SwitchSlot(GU8 SlotCfgEnable)\r
+{\r
+    GH3X2X_AFE_ExitLowPowerMode();\r
+            \r
+    //write slot enable\r
+    GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_SLOT_EN_ADDR, (GU16)SlotCfgEnable);\r
+    \r
+    GH3X2X_AFE_EnterLowPowerMode();\r
+}\r
+\r
+/********************************* interrupt handle:fifo read and analysis ***************************/\r
+#define GH3X2X_AFE_READ_FIFO_BUF_LEN (800)\r
+GU32 GH3X2X_AFE_ReadFifoBuffer[(GU16)GH3X2X_AFE_READ_FIFO_BUF_LEN];\r
+\r
+/*\r
+    FIFO rawdata decode\r
+*/\r
+typedef struct\r
+{\r
+    GU32 uiAdcCode;                      //sampling rawdata of ADC\r
+    GU8  ubSlotNo;                       //slot number\r
+    GU8  ubAdcNo;                        //adc number\r
+    GU8  ubFlagLedAdjIsAgc_EcgRecover;   //adj flag of ppg data or fast recover flag of ecg data\r
+    GU8  ubFlagLedAdjAgcUp;            //adj up flag of ppg data\r
+}StFifoDataInformation;\r
+\r
+/**\r
+ * @fn     GU32 EndienRev32(GU32 luiTempData)\r
+ *\r
+ * @brief  reverse data endien\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  luiTempData input data\r
+ * @param[out] None\r
+ *\r
+ * @return  output data\r
+ */\r
+static GU32 EndienRev32(GU32 luiTempData)\r
+{\r
+    GU8 *lpubIn;\r
+    GU8 *lpubOut;\r
+    \r
+    GU32 luiOutData;\r
+    \r
+    lpubIn = (GU8 *)(&luiTempData);\r
+    lpubOut = (GU8 *)(&luiOutData);\r
+    \r
+    for(GU8 i = 0; i < 4; i ++)\r
+    {\r
+        lpubOut[i] = lpubIn[3 - i];\r
+    }\r
+    \r
+    return luiOutData;\r
+}\r
+\r
+void GH3X2X_UpdateAgcInfo(void)\r
+{\r
+    GH3X2X_Memcpy(g_pstGh3x2xAgcInfo->uchTiaGainRecord, g_pstGh3x2xAgcInfo->uchTiaGainAfterSoftAgc, sizeof(g_pstGh3x2xAgcInfo->uchTiaGainRecord));\r
+               GH3X2X_Memcpy(g_pstGh3x2xAgcInfo->uchDrvCurrentRecord, g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc, sizeof(g_pstGh3x2xAgcInfo->uchDrvCurrentRecord));\r
+       \r
+       \r
+}\r
+\r
+void GH3X2X_RecordAgcInfo(void)\r
+{\r
+    GU16 usDrv0CurRegData = 0;\r
+    GU16 usDrv0CurRegAddr = 0;    \r
+    GU16 usDrv1CurRegData = 0;\r
+    GU16 usDrv1CurRegAddr = 0;\r
+               GU16 uchTIAData = 0;\r
+\r
+               // record TIA\r
+               for (GU8 uchSlotIndex = 0; uchSlotIndex < 8; uchSlotIndex++)\r
+               {\r
+        uchTIAData = GH3X2X_AFE_READ_REG(0x0112 + (uchSlotIndex * 0x001C));\r
+                       \r
+                               for (GU8 nAdcCnt = 0; nAdcCnt < 4; nAdcCnt++)\r
+                               {\r
+                                               uchTIAData = (GU8)(((uchTIAData) >> (4 * nAdcCnt)) & 0x000F);\r
+                                               g_pstGh3x2xAgcInfo->uchTiaGainAfterSoftAgc[uchSlotIndex*4 + nAdcCnt] = uchTIAData;\r
+                               }       \r
+               }\r
+               \r
+                               //Record Drv            \r
+        usDrv0CurRegAddr = 0x011E;\r
+        usDrv1CurRegAddr = 0x0120;\r
+        for (GU8 uchSlotIndexCnt = 0; uchSlotIndexCnt < 8; uchSlotIndexCnt++)\r
+        {\r
+                                       usDrv0CurRegData = (GH3X2X_AFE_READ_REG(usDrv0CurRegAddr + (uchSlotIndexCnt * 0x001C)) & 0xFF);\r
+                                       usDrv1CurRegData = (GH3X2X_AFE_READ_REG(usDrv1CurRegAddr + (uchSlotIndexCnt * 0x001C)) & 0xFF);\r
+                                       g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc[uchSlotIndexCnt] =  (GU16)(usDrv0CurRegData << 0x0);\r
+                                       g_pstGh3x2xAgcInfo->uchDrvCurrentAfterSoftAgc[uchSlotIndexCnt] |= (GU16)(usDrv1CurRegData << 0x0);\r
+        }\r
+}\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_FifoDataAnalysis(GU16 luwFifoDataCnt)\r
+ *\r
+ * @brief  analysis fifo data\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  luwFifoDataCnt    the number of rawdata \r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_FifoDataAnalysis(GU16 luwFifoDataCnt)\r
+{\r
+    StFifoDataInformation stTempFifoInfo = {0};\r
+    GU16 luwFifoCnt = 0;\r
+    \r
+    GU32 luiTempFifoData = 0;\r
+\r
+    GH3X2X_INFO_LOG("Received rawdata sample num = %d \r\n", (int)luwFifoDataCnt);\r
+    \r
+    for(luwFifoCnt = 0; luwFifoCnt < luwFifoDataCnt; luwFifoCnt++)\r
+    {\r
+        luiTempFifoData = EndienRev32(GH3X2X_AFE_ReadFifoBuffer[luwFifoCnt]);  //big endien -> little endien\r
+        \r
+        stTempFifoInfo.uiAdcCode = ((luiTempFifoData >> 0) & 0x00FFFFFF);\r
+        stTempFifoInfo.ubSlotNo =  ((luiTempFifoData >> 29) & 0x00000007);\r
+        stTempFifoInfo.ubAdcNo = ((luiTempFifoData >> 27) & 0x00000003);\r
+        stTempFifoInfo.ubFlagLedAdjIsAgc_EcgRecover = ((luiTempFifoData >> 26) & 0x00000001);\r
+        stTempFifoInfo.ubFlagLedAdjAgcUp = ((luiTempFifoData >> 25) & 0x00000001);\r
+        #if GH3X2X_ADT_FUNC_ENABLE\r
+        if(stTempFifoInfo.ubSlotNo == GH3X2X_ADT_SLOT_NUM && stTempFifoInfo.ubAdcNo == GH3X2X_ADT_ADC_NUM)\r
+        {\r
+            EMWearStatus emWearStatus;\r
+            GH3x2xAdtAlgoExe(&stTempFifoInfo.uiAdcCode,&emWearStatus);\r
+        }\r
+        #endif\r
+        GH3X2X_INFO_LOG("Received rawdata:slot:%d,adc:%d,data:%d\r\n", stTempFifoInfo.ubSlotNo, stTempFifoInfo.ubAdcNo,stTempFifoInfo.uiAdcCode);\r
+                               //GH3X2X_INFO_LOG("drv = %d, g0 = %d,g1 = %d,g2 = %d,g0 = %d\r\n",(int)g_pstGh3x2xAgcInfo->uchDrvCurrentRecord[0],(int)g_pstGh3x2xAgcInfo->uchTiaGainRecord[0],(int)g_pstGh3x2xAgcInfo->uchTiaGainRecord[1],g_pstGh3x2xAgcInfo->uchTiaGainRecord[2],g_pstGh3x2xAgcInfo->uchTiaGainRecord[3]);\r
+               \r
+\r
+        \r
+        /******************************** add your fifo date process code******************************/\r
+        //you can combine frame rawdata according to stTempFifoInfo\r
+        //and then excute algorithm calculate\r
+        \r
+        \r
+    }\r
+}\r
+\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_ChipPro(void)\r
+ *\r
+ * @brief  interrupt handle function\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  None\r
+ * @param[out] None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_ChipPro(void)\r
+{\r
+    GU16 luwGH3X2X_AFEFifoLen = 0;\r
+        GU16 luwGotEvent = 0;\r
+\r
+\r
+#if (GH3X2X_AFE_PRO_TYPE == GH3X2X_AFE_PRO_BY_INT)\r
+    if(0 == g_uchGh3x2xAfeIntCallBackIsCalled)\r
+    {\r
+        GH3X2X_INFO_LOG("InterruptProcess:invalid call, do not process.\r\n");\r
+        return;\r
+    }\r
+    g_uchGh3x2xAfeIntCallBackIsCalled = 0;  \r
+        \r
+#endif\r
+\r
+     if (GH3X2X_AFE_GetNeedWakeUpGh3x2xFlag())\r
+    {\r
+        GH3X2X_AFE_ExitLowPowerMode();\r
+    }\r
+\r
+\r
+    luwGH3X2X_AFEFifoLen = 0;\r
+\r
+    //read event\r
+    luwGotEvent = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_INT_EVENT_ADDR);  \r
+    GH3X2X_INFO_LOG("Received irq = %d \r\n", (int)luwGotEvent);\r
+    //clear event\r
+    GH3X2X_AFE_WRITE_REG(GH3X2X_AFE_REG_INT_EVENT_ADDR,luwGotEvent);  //clear event\r
+\r
+    //read fifo use\r
+    luwGH3X2X_AFEFifoLen = GH3X2X_AFE_READ_REG(GH3X2X_AFE_REG_FIFO_USE_ADDR);\r
+    if(luwGH3X2X_AFEFifoLen > GH3X2X_AFE_READ_FIFO_BUF_LEN)\r
+    {\r
+        luwGH3X2X_AFEFifoLen = GH3X2X_AFE_READ_FIFO_BUF_LEN;\r
+    }\r
+\r
+    // read fifo data\r
+    if(0 != luwGH3X2X_AFEFifoLen)\r
+    {\r
+        GH3X2X_AFE_READ_FIFO((GU8 *)GH3X2X_AFE_ReadFifoBuffer,luwGH3X2X_AFEFifoLen * 4);\r
+    } \r
+    \r
+    \r
+    //ECG_LEAD OFF DET & resample\r
+    #if GH3X2X_ECG_FUNC_ENABLE\r
+\r
+    GU16 luwGH3X2X_AFEFifoByteLen = luwGH3X2X_AFEFifoLen * 4;\r
+    luwGotEvent &= (~GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_OFF));\r
+    \r
+    GU8 lubRet = GH3X2X_LeadOffDetect((GU8 *)GH3X2X_AFE_ReadFifoBuffer, &luwGH3X2X_AFEFifoByteLen, 0);\r
+     if(lubRet != 0)\r
+    {\r
+        luwGotEvent |= (GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_OFF));\r
+    }\r
+    \r
+    GH3X2X_INFO_LOG("before Rs luwGH3X2X_AFEFifoLen = %d\r\n",luwGH3X2X_AFEFifoLen);\r
+    GH3X2X_AFE_EcgRsHandle((GU8 *)GH3X2X_AFE_ReadFifoBuffer, &luwGH3X2X_AFEFifoByteLen,0,GH3X2X_ECG_DOWN_FS);\r
+    luwGH3X2X_AFEFifoLen = luwGH3X2X_AFEFifoByteLen/4;\r
+    GH3X2X_INFO_LOG("after Rs luwGH3X2X_AFEFifoLen = %d\r\n",luwGH3X2X_AFEFifoLen);\r
+    #endif\r
+    \r
+    if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_WEAR_ON)))\r
+    {\r
+        GH3X2X_INFO_LOG("Received wear on event\r\n");\r
+    }\r
+\r
+    if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_WEAR_OFF)))\r
+    {\r
+        GH3X2X_INFO_LOG("Received wear off event\r\n");\r
+    }\r
+\r
+    if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_ON)))\r
+    {\r
+        GH3X2X_INFO_LOG("Received lead on event\r\n");\r
+        GH3X2X_AFE_Leadon_hook();\r
+    }\r
+\r
+    if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LEAD_OFF)))\r
+    {\r
+        GH3X2X_INFO_LOG("Received lead off event\r\n");\r
+        GH3X2X_AFE_Leadoff_hook();\r
+\r
+    }\r
+\r
+    if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LED_TUNE_FAIL)))\r
+    {\r
+        GH3X2X_INFO_LOG("Received tune fail event\r\n");\r
+    }\r
+\r
+    if(0 != (luwGotEvent & GH3X2X_AFE_EVENT_BIT(GH3X2X_AFE_EVENT_LED_TUNE_DONE)))\r
+    {\r
+        GH3X2X_INFO_LOG("Received tune done event\r\n");\r
+    }\r
+\r
+\r
+    //you can add some code to adjust ppg sample parameter, such as led drv current    GU16 usTempDrvCurrent;\r
+    \r
+    //GH3x2xSetPpgCtrlReg(GH3X2X_AFE_PPG_CTRL_REG_AGC_EN,1,0);\r
+    //GH3x2xSetPpgCtrlReg(GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV0,1,60);\r
+    //GH3X2X_INFO_LOG("change slot0 drv0 current.\r\n");\r
+    //GH3X2X_INFO_LOG("Get slot0 drv0 current = %d.\r\n",(int)GH3x2xGetPpgCtrlReg(GH3X2X_AFE_PPG_CTRL_REG_LED_CURRENT_DRV0,0));\r
+\r
+               GH3X2X_LedAgcProcess((GU8 *)GH3X2X_AFE_ReadFifoBuffer, luwGH3X2X_AFEFifoLen * 4, g_pstGh3x2xAgcInfo);\r
+    \r
+    GH3X2X_AFE_EnterLowPowerMode();\r
+    \r
+\r
+    if(0 != luwGH3X2X_AFEFifoLen)\r
+    {\r
+        GH3X2X_AFE_FifoDataAnalysis(luwGH3X2X_AFEFifoLen);\r
+    }                \r
+}\r
+\r
+const GU16 g_usGH3x2xTiaGainR[] = \r
+{\r
+    10,\r
+    25,\r
+    50,\r
+    75,\r
+    100,\r
+    250,\r
+    500,\r
+    750,\r
+    1000,\r
+    1250,\r
+    1500,\r
+    1750,\r
+    2000,\r
+};\r
+\r
+const GU16 g_usGH3x2xSlotRegBase[8] = \r
+{\r
+    0x0100,\r
+    0x011C,\r
+    0x0138,\r
+    0x0154,\r
+    0x0170,\r
+    0x018C,\r
+    0x01A8,\r
+    0x01C4,\r
+};\r
+\r
+\r
+const STGh3x2xAgcReg g_pstGH3x2xAgcReg[] = \r
+{\r
+    {0x10, 9, 8},              //0: agc en\r
+    {0x22, 7, 0},              //1: led current up limit\r
+    {0x22, 15, 8},               //2: led current down limit\r
+    {0x1E, 7, 0},               //3: led current drv0\r
+    {0x20, 7, 0},               //4: led current drv1\r
+    {0x12, 3, 0},               //5: rx0 tia gain\r
+    {0x12, 7, 4},               //6: rx1 tia gain\r
+    {0x12, 11, 8},               //7: rx2 tia gain\r
+    {0x12, 15, 12},               //8: rx3 tia gain\r
+    {0x10, 7,6},               //9: agc src\r
+    {0x1A, 1,0},               //10: rx0 bg cancel\r
+    {0x1A, 3,2},               //11: rx1 bg cancel    \r
+    {0x1A, 5,4},               //12: rx2 bg cancel\r
+    {0x1A, 7,6},               //13: rx2 bg cancel\r
+    {0x0A, 15,8},               //14: sr mulipliper\r
+    {0x0A, 5,1},               //15: ecg en& rx0~rx1 en\r
+};\r
+\r
+void GH3x2x_AFESetAgcReg(GU8 uchAgcReg,  GU8 uchSlot, GU16 usValue)\r
+{\r
+    GH3X2X_AFE_WriteRegBitField(g_usGH3x2xSlotRegBase[uchSlot] + g_pstGH3x2xAgcReg[uchAgcReg].uchAddrOffset, g_pstGH3x2xAgcReg[uchAgcReg].uchLsb, g_pstGH3x2xAgcReg[uchAgcReg].uchMsb, usValue);\r
+}\r
+\r
+GU16 GH3x2x_AFEGetAgcReg(GU8 uchAgcReg,  GU8 uchSlot)\r
+{\r
+    return GH3X2X_AFE_ReadRegBitField(g_usGH3x2xSlotRegBase[uchSlot] + g_pstGH3x2xAgcReg[uchAgcReg].uchAddrOffset, g_pstGH3x2xAgcReg[uchAgcReg].uchLsb, g_pstGH3x2xAgcReg[uchAgcReg].uchMsb);\r
+}\r
+\r
+/**\r
+ * @fn  void GH3X2X_AFE_GetEfuseCode(GS8* pchLedDrvEcode,GS8* pchTiaEcode,GS8* pchEcgEcode)\r
+ *\r
+ * @brief: Get Efuse Code\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]    \r
+ * @param[out]  pchLedDrvEcode\r
+ *              pchTiaEcode\r
+ *              pchEcgEcode\r
+ * @return  :  none\r
+ */\r
+void GH3X2X_AFE_GetEfuseCode(GS8* pchLedDrvEcode,GS8* pchTiaEcode,GS8* pchEcgEcode)\r
+{\r
+    GU16 usRegVal;\r
+    GH3X2X_AFE_WRITE_REG(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,0x0020);\r
+    GH3X2X_AFE_WRITE_REG(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,0x0030);\r
+\r
+    while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0));\r
+    usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_1_REG_ADDR);\r
+    *pchLedDrvEcode = (GS8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal);\r
+    *pchTiaEcode    = (GS8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal);\r
+    *pchEcgEcode    = (GS8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_2_REG_ADDR));\r
+}\r
+\r
+\r
+/**\r
+ * @fn  GU16 GH3X2X_AFE_SetLedDrvCurrent(GU8 uchCurrent_mA,GU8 uchDrvNum, GS8 chECODE)\r
+ *\r
+ * @brief: led drv calibration\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]   GU8 uchCurrent_mA:led drv current, unit: mA\r
+                GU8 uchDrvNum    :led Drv num,0 or 1\r
+                GS8 chECODE      :Led Drv Ecode from efuse\r
+ * @param[out] None\r
+ *\r
+ * @return  :  Drv code\r
+ */\r
+GU16 GH3X2X_AFE_SetLedDrvCurrent(GU8 uchCurrent_mA, GU8 uchDrvNum, GS8 chECODE)\r
+{\r
+    GF32 fEr;\r
+    GF32 fY;\r
+    GU8  uchN;\r
+    GU16 usDrvCode;\r
+    GU16 usDrvScale;\r
+    \r
+    if(uchDrvNum == 0)\r
+    {\r
+        fY = 0.1;\r
+        usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV0_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV0_FULL_SCAL_CURRENT_MSB);\r
+    }\r
+    else\r
+    {\r
+        fY = 0.01;\r
+        usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV1_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV1_FULL_SCAL_CURRENT_MSB);\r
+        \r
+    }\r
+    uchN = 1 << (3 - usDrvScale);    \r
+    \r
+    fEr = (GF32)((GF32)chECODE/256) + 1.0f;\r
+    usDrvCode = (GU16)(0.5f+((GF32)fEr*255*(GF32)uchN)/(0.225f/((GF32)uchCurrent_mA/1000) - fY));\r
+    \r
+    return usDrvCode;\r
+}\r
+\r
+\r
+/**\r
+ * @fn  GF32 GH3X2X_AFE_GetLedDrvCurrent(GU16 usDrvCode, GU8 uchDrvNum, GS8 chECODE)\r
+ *\r
+ * @brief: get led drv calibration current\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  GU16 usDrvCode   :led drv code\r
+                GU8 uchDrvNum    :led Drv num,0 or 1\r
+                GS8 chECODE      :Led Drv Ecode from efuse\r
+ * @param[out] None\r
+ *\r
+ * @return  :  calibration current\r
+ */\r
+\r
+GF32 GH3X2X_AFE_GetLedDrvCurrent(GU16 usDrvCode, GU8 uchDrvNum, GS8 chECODE)\r
+{\r
+    GF32 fEr;\r
+    GF32 fY;\r
+    GU8  uchN;\r
+    GF32 fDrvCurrent;\r
+    GU16 usDrvScale;\r
+       \r
+    if(uchDrvNum == 0)\r
+    {\r
+        fY = 0.1;\r
+        usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV0_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV0_FULL_SCAL_CURRENT_MSB);\r
+    }\r
+    else\r
+    {\r
+        fY = 0.01;\r
+        usDrvScale = GH3X2X_AFE_ReadRegBitField(GH3X2X_LED_DRV_AD_REG_REG_ADDR,GH3X2X_DRV1_FULL_SCAL_CURRENT_LSB,GH3X2X_DRV1_FULL_SCAL_CURRENT_MSB);\r
+    }\r
+    uchN = 1 << (3 - usDrvScale);    \r
+    fEr = (GF32)((GF32)chECODE/256) + 1;\r
+    fDrvCurrent = 0.225f/(fEr*255*(GF32)uchN/(GF32)usDrvCode + fY);\r
+    return fDrvCurrent*1000;\r
+\r
+}\r
+\r
+/**\r
+ * @fn   GF32 GH3X2X_AFE_GetTiaCalCode(GS8 chECODE)\r
+ \r
+ *\r
+ * @brief:  Get Tia Calibration Code\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  GS8 chECODE      :Tia Ecode from efuse\r
+ * @param[out] None\r
+ *\r
+ * @return  :  calibration Code\r
+ */\r
+GF32 GH3X2X_AFE_GetTiaCalCode(GS8 chECODE)\r
+{\r
+    GF32 fEr;\r
+    fEr = (GF32)((GF32)chECODE/512) + 1;\r
+    return fEr;\r
+}\r
+\r
+/**\r
+ * @fn   GF32 GH3X2X_AFE_GetEcgCalCode(GS8 chECODE)\r
+ \r
+ *\r
+ * @brief:  Get ECG Calibration Code\r
+ *\r
+ * @attention   \r
+ *\r
+ * @param[in]  GS8 chECODE      :ECG Ecode from efuse\r
+ * @param[out] None\r
+ *\r
+ * @return  :  calibration Code\r
+ */\r
+GF32 GH3X2X_AFE_GetEcgCalCode(GS8 chECODE)\r
+{\r
+    GF32 fEr;\r
+    fEr = (GF32)((GF32)chECODE/1024) + 1;\r
+    return fEr;\r
+}\r
+\r
+\r
+/**\r
+ * @fn     GCHAR *GH3X2X_GetAfeLibVersion(void)\r
+ *\r
+ * @brief  Get afe driver version\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  library version string\r
+ */\r
+GCHAR *GH3X2X_GetAfeLibVersion(void)\r
+{\r
+    return (GCHAR *)GH3X2X_VERSION_STRING;\r
+}\r
+\r
+\r
+GU8 GH3X2X_AFE_GetChipId(void)\r
+{\r
+       return (GU8)GH3X2X_AFE_ReadRegBitField(GH3X2X_WHO_AM_I_REG_ADDR,GH3X2X_WHO_AM_I_LSB,GH3X2X_WHO_AM_I_MSB);\r
+}\r
+\r
+GS8 GH3X2X_AFE_CheckChipId(void)\r
+{\r
+    GS8 chRet = GH3X2X_AFE_RET_OK;\r
+    GS8 chipd_id = GH3X2X_AFE_GetChipId();\r
+       if(GH3X2X_CHIP_ID != chipd_id)\r
+       {\r
+               GH3X2X_INFO_LOG("wrong chip id!!\r\n");\r
+               chRet = GH3X2X_AFE_RET_GENERIC_ERROR;\r
+       }\r
+    else\r
+    {\r
+        GH3X2X_INFO_LOG("check chip id success!!  0x%x\r\n",chipd_id);\r
+    }\r
+    return chRet;\r
+}\r
+\r
+/**\r
+ * @fn     void *GH3X2X_Memcpy(void *pDest, const void *pSrc, GU32 unByteSize)\r
+ *\r
+ * @brief  memcpy() Re-implementation\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   pSrc        pointer to source buffer\r
+ * @param[in]   unByteSize  source buffer byte size\r
+ * @param[out]  pDest       pointer to destination buffer\r
+ *\r
+ * @return  pointer to destination buffer\r
+ */\r
+void *GH3X2X_Memcpy(void *pDest, const void *pSrc, GU32 unByteSize)\r
+{\r
+    GU8 *puchSrc = (GU8 *)pSrc;\r
+    GU8 *puchDest = (GU8 *)pDest;\r
+    GU32 unAlign = ((GU32)puchDest | (GU32)puchSrc) << 30;\r
+\r
+    if ((pDest == GH3X2X_PTR_NULL) || (pSrc == GH3X2X_PTR_NULL) || (0 == unByteSize))\r
+    {\r
+        return GH3X2X_PTR_NULL;\r
+    }\r
+    if (unAlign == 0) // if align 4\r
+    {\r
+        while (unByteSize >= 4)\r
+        {\r
+            *(GU32 *)puchDest = *(GU32 *)puchSrc;\r
+            puchSrc += 4;\r
+            puchDest += 4;\r
+            unByteSize -= 4;\r
+        }\r
+    }\r
+    while (unByteSize) // bytes\r
+    {\r
+        *(GU8 *)puchDest = *(GU8 *)puchSrc;\r
+        puchSrc++;\r
+        puchDest++;\r
+        unByteSize--;\r
+    }\r
+    return pDest;\r
+}\r
+\r
+/**\r
+ * @fn     void *GH3X2X_Memset(void* pDest, GCHAR chVal, GU32 unByteSize)\r
+ *\r
+ * @brief  memset() Re-implementation\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   chVal       char val for set\r
+ * @param[in]   unByteSize       source buffer len\r
+ * @param[out]  pDest       pointer to destination buffer\r
+ *\r
+ * @return  pointer to destination buffer\r
+ */\r
+void *GH3X2X_Memset(void* pDest, GCHAR chVal, GU32 unByteSize)\r
+{\r
+    GU8 *puchDest = (GU8 *)pDest;\r
+    GU32 unAlign = ((GU32)puchDest) << 30;\r
+    GU32 unWordVal = GH3X2X_AFE_MAKEUP_DWORD(chVal, chVal, chVal, chVal);\r
+\r
+    if (pDest == GH3X2X_PTR_NULL)\r
+    {\r
+        return GH3X2X_PTR_NULL;\r
+    }\r
+    if (unAlign == 0) // if align 4\r
+    {\r
+        while (unByteSize >= 4)\r
+        {\r
+            *(GU32 *)puchDest = unWordVal;\r
+            puchDest += 4;\r
+            unByteSize -= 4;\r
+        }\r
+    }\r
+    while (unByteSize) // bytes\r
+    {\r
+        *(GU8 *)puchDest = (GU8)chVal;\r
+        puchDest++;\r
+        unByteSize--;\r
+    }\r
+    return pDest;\r
+}\r
+\r
+GU8 _crc8(GU8 *ptr,GS32 len)\r
+{\r
+  GS32 i;\r
+  GU8 crc = 0x00;\r
+  while(len--)\r
+  {\r
+    crc ^= *ptr++;\r
+    for(i=8;i>0;--i)\r
+    {\r
+      if(crc&0x80)\r
+      {\r
+        crc = (crc<<1)^0x31;\r
+      }\r
+      else\r
+      {\r
+        crc = (crc<<1);\r
+      }\r
+      crc = crc & 0xff;\r
+    }\r
+  }\r
+  return (GU8)(crc);\r
+}\r
+\r
+void GH3X2X_AFE_LoadEfuse(GU8* puchEfuseBuffer,GU16 EfuseByteLen)\r
+{\r
+       if(EfuseByteLen < 24)\r
+       {\r
+               GH3X2X_INFO_LOG("EfuseByteLen is too short!!\r\n");\r
+               return;\r
+       }\r
+       \r
+    GU16 usRegVal;\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_MODE_LSB,GH3X2X_EFUSE_MODE_MSB,0);\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CHOOSE_LSB,GH3X2X_EFUSE_CHOOSE_MSB,0);\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CLK_EN_LSB,GH3X2X_EFUSE_CLK_EN_MSB,1);\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_START_LSB,GH3X2X_EFUSE_START_MSB,1);\r
+       while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0));\r
+       for(GU8 i = 0; i < 4; i++)\r
+       {\r
+          usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR + 2 * i);\r
+          puchEfuseBuffer[2*i]         = (GU8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal);\r
+          puchEfuseBuffer[2*i + 1] = (GU8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal);\r
+       }\r
+\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CHOOSE_LSB,GH3X2X_EFUSE_CHOOSE_MSB,1);\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_START_LSB,GH3X2X_EFUSE_START_MSB,1);\r
+       while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0));\r
+       for(GU8 i = 0; i < 4; i++)\r
+       {\r
+          usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR + 2 * i);\r
+          puchEfuseBuffer[8 + 2*i]     = (GU8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal);\r
+          puchEfuseBuffer[8 + 2*i + 1] = (GU8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal);\r
+       }\r
+\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_CHOOSE_LSB,GH3X2X_EFUSE_CHOOSE_MSB,2);\r
+       GH3X2X_AFE_WriteRegBitField(GH3X2X_EFUSE_CTRL_CMD_REG_ADDR,GH3X2X_EFUSE_START_LSB,GH3X2X_EFUSE_START_MSB,1);\r
+       while(0 == GH3X2X_AFE_ReadRegBitField(GH3X2X_EFUSE_CTRL_STATUS_REG_ADDR,0,0));\r
+       for(GU8 i = 0; i < 4; i++)\r
+       {\r
+          usRegVal = GH3X2X_AFE_READ_REG(GH3X2X_EFUSE_CTRL_RDATA_0_REG_ADDR + 2 * i);\r
+          puchEfuseBuffer[16 + 2*i]     = (GU8)GH3X2X_AFE_GET_LOW_BYTE_FROM_WORD(usRegVal);\r
+          puchEfuseBuffer[16 + 2*i + 1] = (GU8)GH3X2X_AFE_GET_HIGH_BYTE_FROM_WORD(usRegVal);\r
+       }\r
+\r
+       \r
+}\r
+\r
+GS8 GH3X2X_AFE_CheckEfuseCrc(void)\r
+{\r
+    GS8 chRet = GH3X2X_AFE_RET_OK;\r
+       GU8  uchEfuseBuffArr[24];\r
+    GH3X2X_AFE_LoadEfuse(uchEfuseBuffArr,24);\r
+       GU8 uchCrcArr[3];\r
+       uchCrcArr[0] = _crc8(uchEfuseBuffArr,7);\r
+       uchCrcArr[1] = _crc8((uchEfuseBuffArr + 8),3);\r
+       uchCrcArr[2] = _crc8((uchEfuseBuffArr + 12),10);\r
+       if(uchCrcArr[0] != uchEfuseBuffArr[7] || uchCrcArr[1] != uchEfuseBuffArr[11] ||uchCrcArr[2] != uchEfuseBuffArr[22])\r
+       {\r
+               GH3X2X_INFO_LOG("Efuse crc error!!\r\n");\r
+               chRet = GH3X2X_AFE_RET_GENERIC_ERROR;\r
+       }\r
+    return chRet;\r
+}\r
+\r
+ \r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_lead_off.c
new file mode 100644 (file)
index 0000000..b1e628a
--- /dev/null
@@ -0,0 +1,748 @@
+#include "gh3x2x_afe_ecg.h"\r
+#include "gh3x2x_afe_demo.h"\r
+\r
+#define RESAMPLE_800HZ_TO_500HZ 0\r
+#define RESAMPLE_800HZ_TO_250HZ 0\r
+#define RESAMPLE_320HZ_TO_250HZ 1 \r
+#define RESAMPLE_256HZ_TO_250HZ 0 \r
+\r
+\r
+#if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+#define RESAMPLE_400HZ_TO_250HZ 1 \r
+#else\r
+#define RESAMPLE_400HZ_TO_250HZ 0 \r
+#endif\r
+\r
+#define GH3X2X_PPG_START_SLOT    1\r
+#define GH3X2X_ECG_START_SLOT    0\r
+\r
+#define   GH3X2X_AFE_GET_ECG_CHANNEL_MAP(slotNum)                     (((slotNum << 5) | (3 <<3)) &0xF8)\r
+#define   GH3X2X_AFE_GET_PPG_CHANNEL_MAP(slotNum)                     (((slotNum << 5) | (0 <<3)) &0xF8)\r
+\r
+STGh3x2xSoftLeadOffDetInfo  g_pstGh3x2xSoftLeadOffDetInfoEntity[1];\r
+STGh3x2xRsInfo  g_pstGh3x2xEcgRsInfoEntity[1];\r
+const GU8 g_uchGh3x2xEcgChnlNumLimit = 1;\r
+STGh3x2xSoftLeadOffDetInfo * const g_pstGh3x2xSoftLeadOffDetInfo = g_pstGh3x2xSoftLeadOffDetInfoEntity;\r
+STGh3x2xRsInfo * const g_pstGh3x2xEcgRsInfo = g_pstGh3x2xEcgRsInfoEntity;\r
+\r
+\r
+#if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+#define GH3X2X_PPG_DOWNSAMP_CHNL_NUM 1\r
+const GU32 g_uchPPGDownSampleChnlNumLimit = GH3X2X_PPG_DOWNSAMP_CHNL_NUM;\r
+STGh3x2xRsInfo  g_pstGh3x2xPPGRsInfoEntity[GH3X2X_PPG_DOWNSAMP_CHNL_NUM];\r
+STGh3x2xRsInfo * const g_pstGh3x2xPPGRsInfo = g_pstGh3x2xPPGRsInfoEntity;\r
+#endif\r
+\r
+//Ecg sample rate from hardware\r
+static GU16 g_usEcgInputFs = GH3X2X_ECG_FS; // ecg sample rate 800/320/256\r
+static GU16 g_usEcgOutputFs = GH3X2X_ECG_DOWN_FS; // ecg down sample rate 500/250\r
+\r
+/// down sample lead module(ECG PPG)\r
+static GU8 g_uchDownSampleModule = DOWNSAMPLE_ECG;\r
+\r
+#define ADCREF 1800   \r
+#define ADC_OFFSET (1<<23)\r
+#define PI 3.14159265\r
+#define  ABS(x) ( (x)>0?(x):(-(x)) ) \r
+#define AMP_NUM 5  \r
+#define IQ_NUM 48  \r
+\r
+const int winCoef[IQ_NUM / 2] = { 0, 9580474, 38150933, 85201535, 149892663, 231069901, 327284639, 436819923, 557721094, 687830666, 824826833, 966264894, 1109620882, 1252336609, 1391865307, 1525717084, 1651503351, 1766979451, 1870084709, 1958979209, 2032076627, 2088072537, 2125967693, 2145085852};\r
+#define winAmpCoef  4082 \r
+//unsigned char gscFlagFrPrev = 0; \r
+GU32 g_nLeadOffDetIqAmpThr = 1500;//unit: uv\r
+long long g_lLeadOffDetIqAmp;\r
+long long  g_lLeadOffDetIqAmpThrRaw;\r
+long long  g_lLeadOffDetIqAmpFrThrRaw;\r
+\r
+GU32 g_nLeadOffDetIqAmpDiffThr = 1000;//unit: uv\r
+long long g_lLeadOffDetIqAmpDiff;\r
+long long g_lLeadOffDetIqAmpDiffThrRaw;\r
+long long g_lLeadOffDetIqAmpDiffFrThrRaw;\r
+\r
+int COND_VAL_VALID_TIME = 1; \r
+GU32 g_nLeadOffDetValThr = 80;//unit: mv\r
+int g_LeadOffDetValThrRaw;\r
+\r
+#define SHIFTBITS 30\r
+\r
+#if RESAMPLE_800HZ_TO_500HZ\r
+       const int rsFirCoef_800_500hz[] = { 58200, 102435, 156130, 215460, 274735, 326585, 362380, 372790, 348645, 281870, 166550, 0, -216285, -475850, -766815, -1071825, -1368460, -1630170, -1827760, -1931325, -1912605,\r
+                                -1747635, -1419445, -920670, -255820, 557070, 1485515, 2482735, 3488860, 4433375, 5238695, 5824850, 6114965, 6041350, 5551740, 4615280, 3227790, 1415785, -761100, -3209770, -5805610, -8396875, -10811545, -12866385,\r
+                                -14377925, -15174745, -15110485, -14076620, -12014295, -8924190, -4873605, 0, 5489625, 11323885, 17176845, 22682405, 27452740, 31100030, 33260510, 33619540, 31936265, 28066360, 21981325, 13782945, 3711580, -7852615,\r
+                                -20396185, -33286830, -45795550, -57125820, -66448630, -72941905, -75832375, -74437800, -68207360, -56757870, -39903755, -17678885, 9651270, 41588185, 77410100, 116192965, 156841955, 198132190, 238757000, 277381455, 312698655, 343486005, 368658785, 387318230, 398791740, 402663190 };\r
+#endif\r
+#if RESAMPLE_800HZ_TO_250HZ    \r
+       const int rsFirCoef_800_250hz[] = { -74905, -95385, -116975, -138740, -159540, -178080, -192900, -202440, -205060, -199120, -183040, -155365, -114830, -60455, 8370, 91845, 189655, 300920, 424150, 557225, 697345, 841065, 984315, 1122440, 1250290, 1362325,\r
+                                1452720, 1515555, 1544935, 1535220, 1481220, 1378385, 1223050, 1012615, 745780, 422705, 45175, -383265, -857210, -1369370, -1910565, -2469770, -3034240, -3589685, -4120510, -4610090, -5041145, -5396125, -5657660, -5809045, -5834740, -5720895, -5455890,\r
+                                -5030825, -4440010, -3681420, -2757070, -1673325, -441140, 923805, 2401100, 3965690, 5588100, 7234765, 8868540, 10449275, 11934545, 13280495, 14442770, 15377525, 16042520, 16398240, 16409055, 16044325, 15279560, 14097430, 12488725, 10453225, 8000385,\r
+                                5149865, 1931900, -1612575, -5431990, -9464450, -13638290, -17872830, -22079425, -26162660, -30021820, -33552510, -36648435, -39203325, -41112955, -42277200, -42602135, -42002095, -40401670, -37737600, -33960495, -29036370, -22947970, -15695790,\r
+                                -7298825, 2204995, 12758710, 24286615, 36694830, 49872305, 63692080, 78012930, 92681285, 107533410, 122397830, 137097950, 151454790, 165289835, 178427925, 190700125, 201946505, 212018845, 220783110, 228121755, 233935695, 238146055, 240695490, 241549195 };\r
+#endif\r
+\r
+#if RESAMPLE_400HZ_TO_250HZ    \r
+//const int rsFirCoef_250hz1[] = { 0,-24495,-56710,-95045,-136775,-178125,-214440,-240490,-250920,-240760,-205965,-144050,-54555,60475,196250,345190,497105,639650,759070,841160,872410,841285,739500,563245,314150,0,-365010,-760510,-1160685,-1535620,-1853070,-2080745,-2188790,-2152475,-1954770,-1588670,-1058960,-383360,407260,1269625,2149850,2986210,3712890,4264415,4580525,4611280,4321835,3696680,2742865,1491895,0,-1653335,-3368750,-5032125,-6521320,-7714135,-8497040,-8774130,-8475685,-7565610,-6047220,-3966715,-1413955,1479820,4547350,7593800,10407850,12774895,14491705,15381495,15308470,14190830,12011055,8822720,4752940,0,-5174080,-10455925,-15497715,-19937805,-23423930,-25637735,-26318950,-25287690,-22463185,-17877445,-11682610,-4150955,4332910,13287805,22159230,30349170,37251070,42288110,44952645,44844420,41705155,35447110,26173540,14189250,0,-15699840,-32051440,-48066690,-62673020,-74765800,-83265770,-87178475,-85652480,-78033065,-63908265,-43144325,-15908305,17323970,55775495,98391360,143876925,190749335,237400000,282164985,323399855,359555130,389248460,411329760,424935830,429531605};\r
+const int rsFirCoef_250hz2[] = {-20165,29190,117750,248970,420650,623445,839855,1044105,1203060,1278285,1229350,1018175,614220,0,-823490,-1832200,-2975865,-4177020,-5332555,-6318335,-6996880,-7227970,-6881615,-5852620,-4075600,-1539030,1703020,5523035,9717440,14010255,18063685,21495860,23905235,24900525,24134595,21339975,16363405,9196555,0,-10882185,-22919440,-35404830,-47478995,-58167535,-66430495,-71221570,-71553685,-66566985,-55594615,-38221750,-14333265,15853795,51776230,92531020,136902815,183411755,230379530,276010140,318480795,356037520,387089565,410296710,424643805,429497860,};\r
+#endif\r
+               \r
+#if RESAMPLE_320HZ_TO_250HZ    \r
+       const int rsFirCoef_320_250hz[] = {79095,936340,341760,-2712470,-2547785,4817105,8099190,-5170865,-17933790,0,30974265,15517780,-42765395,-45670380,44706790,92106715,-24021395,-152053275,-36768905,217784250,166596045,-277901355,-451953470,320248390,1667310365,2147483647,};\r
+#endif\r
+#if RESAMPLE_256HZ_TO_250HZ            \r
+       const int rsFirCoef_256_250hz[]={194000,77770,-331070,-632290,-254280,769680,1439880,622640,-1454740,-2779600,-1303600,2436730,4847325,2461115,-3753755,-7872475,-4310105,5424840,12120690,7126740,-7444180,-17902495,-11265025,9777230,25594875,17187555,-12359260,-35689230,-25526795,15096890,48893725,37213545,-17872685,-66356185,-53763065,20552645,90184745,77974330,-22995885,-124828195,-115908245,25065740,181561700,183974820,-26641130,-299102515,-347934030,27626950,749679370,1463910805,1761638120,};\r
+#endif\r
+\r
+GS32* rsFirCoef;\r
+GS32* rsFirCoef1;\r
+               \r
+STGh3x2xDownSampleCalParamInfo pstECGDownSampCalParamInfo[1];\r
+#if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+STGh3x2xDownSampleCalParamInfo pstPPGDownSampCalParamInfo[1];\r
+#endif\r
+\r
+void GH3X2X_DownSampleMarcoIni(GU16 usEcgSampleRate)\r
+{\r
+       switch (g_usEcgInputFs)\r
+       {\r
+       case 800:\r
+        if( usEcgSampleRate == 500)\r
+        {\r
+            pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_800HZ_TO_500HZ;\r
+        }\r
+        else\r
+        {\r
+            pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_800HZ_TO_250HZ;\r
+        }\r
+        break;\r
+       case 320:\r
+        if( usEcgSampleRate == 250)\r
+        {\r
+            pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_320HZ_TO_250HZ;\r
+        }\r
+        break;\r
+       case 256:\r
+        if( usEcgSampleRate == 250)\r
+        {\r
+            pstECGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_256HZ_TO_250HZ;\r
+        }\r
+        break;\r
+       default: // do nothing\r
+        break;\r
+       }\r
+\r
+       // ppg downsample ini\r
+       #if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+               pstPPGDownSampCalParamInfo->uchDownSampleType = DOWNSAMPLE_400HZ_TO_250HZ;\r
+       #endif\r
+}\r
+\r
+void RsFirResetSingle(GU8 uchChipIndex, GU8 uchMode)\r
+{\r
+    STGh3x2xRsInfo * pstRsInfo;\r
+    GU8 uchChnNum = 0;\r
+    #if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+    if(DOWNSAMPLE_PPG == uchMode)\r
+    {\r
+        pstRsInfo = g_pstGh3x2xPPGRsInfo;\r
+        uchChnNum = g_uchPPGDownSampleChnlNumLimit;\r
+    }\r
+    #endif\r
+\r
+    if(DOWNSAMPLE_ECG == uchMode)\r
+    {\r
+        pstRsInfo = g_pstGh3x2xEcgRsInfo;\r
+        uchChnNum = uchChipIndex+1;\r
+    }\r
+\r
+    for( GU8 i=0; i<uchChnNum;i++)\r
+    {\r
+        pstRsInfo[i].snBufHead = -1;\r
+        pstRsInfo[i].snRsFirState = 0;\r
+        pstRsInfo[i].nRsIcounter = 0;\r
+        pstRsInfo[i].nRrsDcounter = 0;\r
+        pstRsInfo[i].uchFlagFrPrev = 1;\r
+        pstRsInfo[i].nRsLastRaw = 0;\r
+        pstRsInfo[i].fDownStep = 0;\r
+        pstRsInfo[i].uchLinearInterState = 0;\r
+        pstRsInfo[i].uchLinearDataUpdate = 0;\r
+    }\r
+}\r
+\r
+void RsFirReset(GU8 uchMode)\r
+{\r
+    RsFirResetSingle(0,uchMode);\r
+}\r
+\r
+void GH3X2X_ECGResampleConfig(GU16 usEcgSampleRate)\r
+{\r
+    RsFirReset(DOWNSAMPLE_ECG);\r
+    GH3X2X_DownSampleMarcoIni(usEcgSampleRate);\r
+    if(usEcgSampleRate == 500)\r
+    {\r
+        #if RESAMPLE_800HZ_TO_500HZ\r
+        if(DOWNSAMPLE_800HZ_TO_500HZ == pstECGDownSampCalParamInfo->uchDownSampleType)\r
+        {\r
+            pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_800_500hz;\r
+            pstECGDownSampCalParamInfo->uchRsFirOrder = 182;\r
+            pstECGDownSampCalParamInfo->uchRsI = 5;\r
+            pstECGDownSampCalParamInfo->uchRsD = 8;\r
+            pstECGDownSampCalParamInfo->uchRsEnable = 1;\r
+        }\r
+        #endif\r
+    }\r
+    else if(usEcgSampleRate == 250)\r
+    {\r
+        #if RESAMPLE_800HZ_TO_250HZ\r
+        if(DOWNSAMPLE_800HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)\r
+        {\r
+            pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_800_250hz;\r
+            pstECGDownSampCalParamInfo->uchRsFirOrder = 250;\r
+            pstECGDownSampCalParamInfo->uchRsI = 5;\r
+            pstECGDownSampCalParamInfo->uchRsD = 16;\r
+            pstECGDownSampCalParamInfo->uchRsEnable = 1;\r
+        }\r
+        #endif\r
+\r
+        #if RESAMPLE_320HZ_TO_250HZ\r
+        if(DOWNSAMPLE_320HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)\r
+        {\r
+            pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_320_250hz;\r
+            pstECGDownSampCalParamInfo->uchRsFirOrder = 50;\r
+            pstECGDownSampCalParamInfo->uchRsI = 1;\r
+            pstECGDownSampCalParamInfo->uchRsD = 1;\r
+            pstECGDownSampCalParamInfo->uchRsEnable = 1;\r
+            pstECGDownSampCalParamInfo->ufStep = 128;\r
+        }\r
+        #endif\r
+\r
+        #if RESAMPLE_256HZ_TO_250HZ\r
+        if(DOWNSAMPLE_256HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)\r
+        {\r
+            pstECGDownSampCalParamInfo->rsFirCoef= (GS32*)rsFirCoef_256_250hz;\r
+            pstECGDownSampCalParamInfo->uchRsFirOrder = 100;\r
+            pstECGDownSampCalParamInfo->uchRsI = 1;\r
+            pstECGDownSampCalParamInfo->uchRsD = 1;\r
+            pstECGDownSampCalParamInfo->uchRsEnable = 1;\r
+            pstECGDownSampCalParamInfo->ufStep = 1024;\r
+        }\r
+        #endif\r
+    }\r
+    else\r
+    {\r
+        pstECGDownSampCalParamInfo->uchRsEnable = 0;\r
+        return;\r
+    }\r
+\r
+    if(pstECGDownSampCalParamInfo->uchRsFirOrder % 2)\r
+    {\r
+        pstECGDownSampCalParamInfo->uchRsFirCoefNum = ((pstECGDownSampCalParamInfo->uchRsFirOrder+1)/2) ;\r
+    }\r
+    else\r
+    {\r
+        pstECGDownSampCalParamInfo->uchRsFirCoefNum = ((pstECGDownSampCalParamInfo->uchRsFirOrder+2)/2);\r
+    }\r
+    pstECGDownSampCalParamInfo->uchRsBufSize = (pstECGDownSampCalParamInfo->uchRsFirOrder / pstECGDownSampCalParamInfo->uchRsI + 1);\r
+}\r
+\r
+#if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+void GH3X2X_PPGResampleConfig(GU16 usPPGSampleRate)\r
+{\r
+    RsFirReset(DOWNSAMPLE_PPG);\r
+               GH3X2X_DownSampleMarcoIni(usPPGSampleRate);\r
+    if(usPPGSampleRate == 250)\r
+    {\r
+        #if RESAMPLE_400HZ_TO_250HZ\r
+        pstPPGDownSampCalParamInfo->rsFirCoef = (GS32*)rsFirCoef_250hz2;\r
+        pstPPGDownSampCalParamInfo->uchRsFirOrder = 126;\r
+        pstPPGDownSampCalParamInfo->uchRsI = 5;\r
+        pstPPGDownSampCalParamInfo->uchRsD = 8;\r
+        pstPPGDownSampCalParamInfo->uchRsEnable = 1;\r
+        #else\r
+        pstPPGDownSampCalParamInfo->uchRsEnable = 0;\r
+        #endif\r
+    }\r
+    else\r
+    {\r
+        pstPPGDownSampCalParamInfo->uchRsEnable = 0;\r
+        return;\r
+    }\r
+\r
+    if(pstPPGDownSampCalParamInfo->uchRsFirOrder % 2)\r
+    {\r
+        pstPPGDownSampCalParamInfo->uchRsFirCoefNum = ((pstPPGDownSampCalParamInfo->uchRsFirOrder+1)/2) ;\r
+    }\r
+    else\r
+    {\r
+        pstPPGDownSampCalParamInfo->uchRsFirCoefNum = ((pstPPGDownSampCalParamInfo->uchRsFirOrder+2)/2);\r
+    }\r
+    pstPPGDownSampCalParamInfo->uchRsBufSize = (pstPPGDownSampCalParamInfo->uchRsFirOrder / pstPPGDownSampCalParamInfo->uchRsI + 1);\r
+}\r
+#else\r
+void GH3X2X_PPGResampleConfig(GU16 usPPGSampleRate)\r
+{\r
+    return;\r
+}\r
+#endif\r
+\r
+void GH3X2X_LeadOffDetectResetSingleChip(GU8 uchChipIndex)\r
+{\r
+    int i;\r
+    STGh3x2xSoftLeadOffDetInfo * pstSoftLeadOffDetInfo = g_pstGh3x2xSoftLeadOffDetInfo + uchChipIndex;\r
+    pstSoftLeadOffDetInfo -> snCounter = 0;\r
+    pstSoftLeadOffDetInfo -> sniqCounter = 0;\r
+    pstSoftLeadOffDetInfo -> snniVal = 0;\r
+    pstSoftLeadOffDetInfo -> snnqVal = 0;\r
+    pstSoftLeadOffDetInfo -> uchFastRecoryHistory = 0;\r
+    for (i = 0; i < AMP_NUM; i++)\r
+        pstSoftLeadOffDetInfo -> snniqAmp[i] = 0;\r
+}\r
+\r
+void GH3X2X_LeadOffDetectReset(void)\r
+{\r
+    GH3X2X_LeadOffDetectResetSingleChip(0);\r
+}\r
+\r
+void GH3X2X_ConfigLeadOffThr(GU32 uIQAmpThr, GU32 uIQAmpDiffThr,GU32 uValThr)\r
+{\r
+    g_nLeadOffDetIqAmpThr = uIQAmpThr;\r
+    g_lLeadOffDetIqAmp = ((long long)g_nLeadOffDetIqAmpThr * 20 * ADC_OFFSET / ADCREF/1000*IQ_NUM*1000/winAmpCoef);\r
+    g_lLeadOffDetIqAmpThrRaw = (g_lLeadOffDetIqAmp*g_lLeadOffDetIqAmp);\r
+    g_lLeadOffDetIqAmpFrThrRaw = (g_lLeadOffDetIqAmp*g_lLeadOffDetIqAmp / 20 / 20); \r
+\r
+    g_nLeadOffDetIqAmpDiffThr = uIQAmpDiffThr;\r
+    g_lLeadOffDetIqAmpDiff = ((long long)g_nLeadOffDetIqAmpDiffThr * 20 * ADC_OFFSET / ADCREF/1000*IQ_NUM*1000/winAmpCoef);\r
+    g_lLeadOffDetIqAmpDiffThrRaw = (g_lLeadOffDetIqAmpDiff*g_lLeadOffDetIqAmpDiff);\r
+    g_lLeadOffDetIqAmpDiffFrThrRaw = (g_lLeadOffDetIqAmpDiff*g_lLeadOffDetIqAmpDiff / 20 / 20); \r
+\r
+    g_nLeadOffDetValThr = uValThr;\r
+    g_LeadOffDetValThrRaw = (g_nLeadOffDetValThr * (20 * ADC_OFFSET / ADCREF)); \r
+}\r
+\r
+GS32 GH3X2X_LeadOffDetectInit(void)\r
+{\r
+    GH3X2X_ECGResampleConfig(g_usEcgOutputFs);\r
+       \r
+               #if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+    GH3X2X_PPGResampleConfig(GH3X2X_PPG_DOWN_FS);        \r
+               #endif\r
+       \r
+    GH3X2X_ConfigLeadOffThr(g_nLeadOffDetIqAmpThr,  g_nLeadOffDetIqAmpDiffThr, g_nLeadOffDetValThr);\r
+    GH3X2X_LeadOffDetectReset();\r
+    return 0;\r
+}\r
+\r
+/**\r
+ * @fn     GU8 GH3X2X_LeadOffDetect(GU8* puchFifoBuffer, GU16 usFifoBufferLen)\r
+ *\r
+ * @brief  Lead off Detection, suppose the increment of  normal ECG value in LEADOFF_DET_POINT_NUM+1 samples point \r
+ *         not exceed   LEADOFF_DET_THR_mV\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   puchFifoBuffer           pointer to read fifo data buffer\r
+ * @param[in]   usFifoBufferLen          read fifo buffer len\r
+ * @param[out]  None\r
+ *\r
+ * @return  lead off status output \r
+ * @retval  #0          not detect lead off\r
+ * @retval  bit0=1      AdcValue larger than thresh\r
+ * @retval  bit1=1      IQ Value larger than thresh\r
+ */\r
+\r
+GU8 GH3X2X_LeadOffDetectSingleChip(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 unChipIndex, GU8 uchEcgSlotNum)\r
+{\r
+    GU16 usByteIndexTmp = 0;\r
+    GS32 j;\r
+    GU8 uchRet = 0;\r
+    GU32 fifoVal;\r
+    GS32 adcVal;\r
+    GU8  flagFastRecovery;\r
+    GS32 absAdcVal; //ABS of adcVal\r
+    GS64 temp;\r
+\r
+    STGh3x2xSoftLeadOffDetInfo * pstSoftLeadOffDetInfo = g_pstGh3x2xSoftLeadOffDetInfo + unChipIndex;\r
+\r
+    for (usByteIndexTmp = 0; usByteIndexTmp < *pusFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE)\r
+    {\r
+        if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == GH3X2X_AFE_GET_ECG_CHANNEL_MAP(uchEcgSlotNum))\r
+        {\r
+            fifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchFifoBuffer[usByteIndexTmp], puchFifoBuffer[usByteIndexTmp + 1],puchFifoBuffer[usByteIndexTmp + 2], puchFifoBuffer[usByteIndexTmp + 3]);\r
+            adcVal = (GS32)((fifoVal & 0x00FFFFFF)) - ADC_OFFSET; \r
+            flagFastRecovery = (fifoVal >> 26) & 0x01;\r
+            if(flagFastRecovery)\r
+            {\r
+                pstSoftLeadOffDetInfo->uchFastRecoryHistory = 1;\r
+                                       //GH3X2X_INFO_LOG("has fast recovery!!!!\r\n");\r
+            }\r
+            if(0 == pstSoftLeadOffDetInfo->uchFastRecoryHistory)\r
+            {\r
+                                       //GH3X2X_INFO_LOG("Warning: No fast recovery!!!!\r\n");\r
+                continue;\r
+            }\r
+            if (pstSoftLeadOffDetInfo-> uchFlagFrPrev != flagFastRecovery)\r
+            {\r
+                GH3X2X_LeadOffDetectReset();\r
+                pstSoftLeadOffDetInfo->uchFastRecoryHistory = 1;\r
+            }\r
+            pstSoftLeadOffDetInfo-> uchFlagFrPrev = flagFastRecovery;\r
+\r
+            //sample counter\r
+            if (pstSoftLeadOffDetInfo -> snCounter < 20000)\r
+                pstSoftLeadOffDetInfo -> snCounter++;\r
+            \r
+            if (flagFastRecovery == 0 && pstSoftLeadOffDetInfo -> snCounter>COND_VAL_VALID_TIME)\r
+            {\r
+                absAdcVal = ABS(adcVal);\r
+                if (absAdcVal > g_LeadOffDetValThrRaw)\r
+                    uchRet |= 0x01;\r
+            }\r
+            if (pstSoftLeadOffDetInfo -> sniqCounter < IQ_NUM / 2)\r
+            {\r
+                temp = (GS64)adcVal*winCoef[pstSoftLeadOffDetInfo -> sniqCounter];\r
+            }\r
+            else\r
+            {\r
+                temp = (GS64)adcVal*winCoef[IQ_NUM-1 - pstSoftLeadOffDetInfo -> sniqCounter];\r
+            }\r
+            switch (pstSoftLeadOffDetInfo -> sniqCounter%4)\r
+            {\r
+            case 0:\r
+                pstSoftLeadOffDetInfo -> snniVal += temp;\r
+                break;\r
+            case 1:\r
+                pstSoftLeadOffDetInfo -> snnqVal += temp;\r
+                break;\r
+            case 2:\r
+                pstSoftLeadOffDetInfo -> snniVal -= temp;\r
+                break;\r
+            case 3:\r
+                pstSoftLeadOffDetInfo -> snnqVal -= temp;\r
+                break;\r
+            default:\r
+                break;\r
+            }\r
+            if (pstSoftLeadOffDetInfo -> sniqCounter == (IQ_NUM - 1))\r
+            {\r
+                for (j = AMP_NUM-1; j >0; j--)\r
+                {\r
+                    pstSoftLeadOffDetInfo -> snniqAmp[j] = pstSoftLeadOffDetInfo -> snniqAmp[j - 1];\r
+                }\r
+                pstSoftLeadOffDetInfo -> snniVal = pstSoftLeadOffDetInfo -> snniVal >> 31;\r
+                pstSoftLeadOffDetInfo -> snnqVal = pstSoftLeadOffDetInfo -> snnqVal >> 31;\r
+                pstSoftLeadOffDetInfo -> snniqAmp[0] = pstSoftLeadOffDetInfo -> snniVal*(int)pstSoftLeadOffDetInfo -> snniVal + pstSoftLeadOffDetInfo -> snnqVal*(int)pstSoftLeadOffDetInfo -> snnqVal;\r
+                pstSoftLeadOffDetInfo -> snniVal = 0;\r
+                pstSoftLeadOffDetInfo -> snnqVal = 0;\r
+    \r
+                if (flagFastRecovery == 0)\r
+                {\r
+                    if (pstSoftLeadOffDetInfo -> snniqAmp[0] > g_lLeadOffDetIqAmpThrRaw && pstSoftLeadOffDetInfo -> snniqAmp[1] > g_lLeadOffDetIqAmpThrRaw)\r
+                        uchRet |= 0x02;\r
+\r
+                    if ((pstSoftLeadOffDetInfo -> snniqAmp[0] - pstSoftLeadOffDetInfo -> snniqAmp[2]) > g_lLeadOffDetIqAmpDiffThrRaw && (pstSoftLeadOffDetInfo -> snniqAmp[1] - pstSoftLeadOffDetInfo -> snniqAmp[2]) > g_lLeadOffDetIqAmpDiffThrRaw)\r
+                    {\r
+                        if(pstSoftLeadOffDetInfo ->snCounter > 2 * IQ_NUM)\r
+                        {\r
+                            uchRet |= 0x04;\r
+                        }\r
+                    }\r
+                }\r
+                else\r
+                {\r
+                    if (pstSoftLeadOffDetInfo -> snniqAmp[0] > g_lLeadOffDetIqAmpFrThrRaw && pstSoftLeadOffDetInfo -> snniqAmp[1] > g_lLeadOffDetIqAmpFrThrRaw)\r
+                        uchRet |= 0x08;\r
+                }\r
+            }\r
+            pstSoftLeadOffDetInfo -> sniqCounter++;\r
+            pstSoftLeadOffDetInfo -> sniqCounter = pstSoftLeadOffDetInfo -> sniqCounter%(IQ_NUM);\r
+        } // end of if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == g_uchEcgLeadChannelMap)\r
+    } // end of for (usByteIndexTmp = 0; usByteIndexTmp < usFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE)\r
+\r
+    return uchRet;\r
+}\r
+\r
+\r
+\r
+void GH3x2xSetEcgOutputFs(GU16 usEcgOutputFs)\r
+{\r
+    g_usEcgOutputFs = usEcgOutputFs;\r
+}\r
+\r
+GU8 GH3X2X_LeadOffDetect(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum)\r
+{\r
+    GU8 uchRet = 0;\r
+    uchRet |= GH3X2X_LeadOffDetectSingleChip(puchFifoBuffer, pusFifoBufferLen, 0, uchEcgSlotNum);\r
+    if(g_uchGh3x2xEcgChnlNumLimit > 1)\r
+    {\r
+        uchRet |= GH3X2X_LeadOffDetectSingleChip(puchFifoBuffer, pusFifoBufferLen, 1, uchEcgSlotNum);\r
+    }\r
+        return uchRet;\r
+}\r
+\r
+void GH3X2X_DownSampleCal( GU8 *puchFifoBuffer, GU16 usByteIndexTmp, GU16 *usRawdataBufIdx, GU16 usSampleRate, STGh3x2xRsInfo * pstRsInfo ,STGh3x2xDownSampleCalParamInfo * pstDownSampCalParamInfo)\r
+{\r
+    GU32 fifoVal;\r
+    GS32 adcVal;\r
+    GU8 chNo;\r
+    GU8  flagFastRecovery;\r
+    GS32 j;\r
+\r
+    fifoVal = GH3X2X_AFE_MAKEUP_DWORD(puchFifoBuffer[usByteIndexTmp], puchFifoBuffer[usByteIndexTmp + 1], puchFifoBuffer[usByteIndexTmp + 2], puchFifoBuffer[usByteIndexTmp + 3]);\r
+    chNo = (fifoVal >> 27); \r
+    adcVal = (GS32)((fifoVal & 0x00FFFFFF)) - ADC_OFFSET; \r
+       \r
+    if(g_uchDownSampleModule == DOWNSAMPLE_ECG)\r
+    {\r
+        flagFastRecovery = (fifoVal >> 26) & 0x01;\r
+        if (pstRsInfo ->uchFlagFrPrev != flagFastRecovery)\r
+        {\r
+            GH3X2X_ECGResampleConfig(usSampleRate);\r
+        }\r
+        pstRsInfo ->uchFlagFrPrev = flagFastRecovery;\r
+    }\r
+\r
+    #if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+    else if(g_uchDownSampleModule == DOWNSAMPLE_PPG)\r
+    {\r
+        flagFastRecovery = (fifoVal >> 26) & 0x01;\r
+        if (pstRsInfo ->uchFlagFrPrev != 1)\r
+        {\r
+            if(usSampleRate)\r
+            {\r
+                GH3X2X_PPGResampleConfig(usSampleRate);\r
+            }\r
+        }\r
+        pstRsInfo ->uchFlagFrPrev = 1;\r
+    }\r
+    #endif\r
+               \r
+    // ECG downsample\r
+    #if RESAMPLE_320HZ_TO_250HZ || RESAMPLE_256HZ_TO_250HZ\r
+    if((DOWNSAMPLE_320HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType) || (DOWNSAMPLE_256HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType))\r
+    {  \r
+        GS32 LinerAdcVal;\r
+        if(pstDownSampCalParamInfo->uchRsEnable)\r
+        {\r
+            GS32 k;\r
+            GS64 y;\r
+\r
+            //??\r
+            if (pstRsInfo ->snRsFirState > 0)\r
+            {\r
+                pstRsInfo ->snBufHead = pstRsInfo ->snBufHead - 1;\r
+                pstRsInfo ->snBufHead = pstRsInfo ->snBufHead < 0 ? (pstDownSampCalParamInfo->uchRsBufSize - 1) : pstRsInfo ->snBufHead;\r
+                pstRsInfo ->snRsXbuf[pstRsInfo ->snBufHead] = adcVal;\r
+            }\r
+            else\r
+            {\r
+                for (j = 0; j < pstDownSampCalParamInfo->uchRsFirOrder / pstDownSampCalParamInfo->uchRsI + 1; j++)\r
+                        pstRsInfo ->snRsXbuf[j] = adcVal;\r
+                pstRsInfo ->snBufHead = pstDownSampCalParamInfo->uchRsBufSize - 1;\r
+            }\r
+                              \r
+            k = pstRsInfo ->snBufHead;\r
+            y = 0;\r
+            for (j = 1; j < pstDownSampCalParamInfo->uchRsFirCoefNum; j = j + 1) //\r
+            {\r
+                y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[j]);\r
+                k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize;\r
+            }\r
+            for (; j <(pstDownSampCalParamInfo->uchRsFirOrder+1); j = j + 1) //\r
+            {\r
+                y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[pstDownSampCalParamInfo->uchRsFirOrder - j]);\r
+                k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize;\r
+            }\r
+\r
+            y = y >> SHIFTBITS;\r
+            k = (GS32)y + ADC_OFFSET; //\r
+            if (k < 0)\r
+                k = 0;\r
+            else if (k>=(ADC_OFFSET * 2))\r
+                k = (ADC_OFFSET * 2-1);\r
+\r
+            // ???????\r
+            if(pstRsInfo->uchLinearInterState >0)\r
+            {\r
+                #if RESAMPLE_320HZ_TO_250HZ\r
+                if(DOWNSAMPLE_320HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)\r
+                {\r
+                    if(pstRsInfo->fDownStep <=100)\r
+                    {\r
+                        LinerAdcVal = ((GU32)k*pstRsInfo->fDownStep + (100-pstRsInfo->fDownStep)*pstRsInfo->nRsLastRaw)/100;\r
+                        pstRsInfo->nRsLastRaw = (GU32)k;\r
+                        pstRsInfo->fDownStep = pstRsInfo->fDownStep + pstDownSampCalParamInfo->ufStep - 100;\r
+                        pstRsInfo->uchLinearDataUpdate = 1;\r
+                    }\r
+                    else\r
+                    {\r
+                        pstRsInfo->nRsLastRaw = (GU32)k;\r
+                        pstRsInfo->fDownStep = pstRsInfo->fDownStep - 100;\r
+                        pstRsInfo->uchLinearDataUpdate = 0;\r
+                    }\r
+                }\r
+                #endif\r
+\r
+                #if RESAMPLE_256HZ_TO_250HZ\r
+                if(DOWNSAMPLE_256HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)\r
+                {\r
+                    if(pstRsInfo->fDownStep <=1000)\r
+                    {\r
+                        LinerAdcVal = (GU32)(((GS64)(k)*(GS64)(pstRsInfo->fDownStep) + (GS64)((1000-pstRsInfo->fDownStep)*(GS64)(pstRsInfo->nRsLastRaw)))/1000);\r
+                        pstRsInfo->nRsLastRaw = (GU32)k;\r
+                        pstRsInfo->fDownStep = pstRsInfo->fDownStep + pstDownSampCalParamInfo->ufStep - 1000;\r
+                        pstRsInfo->uchLinearDataUpdate = 1;\r
+                    }\r
+                    else\r
+                    {\r
+                        pstRsInfo->nRsLastRaw = (GU32)k;\r
+                        pstRsInfo->fDownStep = pstRsInfo->fDownStep - 1000;\r
+                        pstRsInfo->uchLinearDataUpdate = 0;\r
+                    }\r
+                }\r
+                #endif\r
+            }\r
+            else\r
+            {\r
+                LinerAdcVal = (GU32)k;\r
+                pstRsInfo->nRsLastRaw = (GU32)k;\r
+                pstRsInfo->fDownStep = pstRsInfo->fDownStep + pstDownSampCalParamInfo->ufStep;\r
+                pstRsInfo->uchLinearInterState =1;\r
+                pstRsInfo->uchLinearDataUpdate = 1;\r
+            }\r
+\r
+            if(pstRsInfo->uchLinearDataUpdate == 1)\r
+            {\r
+                fifoVal = (((GU8)chNo)<<27) + (((GU8)flagFastRecovery)<<26) + ((GU32)LinerAdcVal/5);\r
+                puchFifoBuffer[*usRawdataBufIdx]     = GH3X2X_AFE_GET_BYTE3_FROM_DWORD(fifoVal);\r
+                puchFifoBuffer[*usRawdataBufIdx + 1] = GH3X2X_AFE_GET_BYTE2_FROM_DWORD(fifoVal);\r
+                puchFifoBuffer[*usRawdataBufIdx + 2] = GH3X2X_AFE_GET_BYTE1_FROM_DWORD(fifoVal);\r
+                puchFifoBuffer[*usRawdataBufIdx + 3] = GH3X2X_AFE_GET_BYTE0_FROM_DWORD(fifoVal);\r
+\r
+                *usRawdataBufIdx += GH3X2X_AFE_FIFO_RAWDATA_SIZE;\r
+            }\r
+        }\r
+    }\r
+    #endif\r
+\r
+    #if  RESAMPLE_800HZ_TO_500HZ ||RESAMPLE_800HZ_TO_250HZ || (RESAMPLE_400HZ_TO_250HZ & (__SUPPORT_ECG_PPG_DOWNSAMP__))\r
+    if((DOWNSAMPLE_800HZ_TO_500HZ == pstECGDownSampCalParamInfo->uchDownSampleType)||(DOWNSAMPLE_800HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType)||(DOWNSAMPLE_400HZ_TO_250HZ == pstECGDownSampCalParamInfo->uchDownSampleType))\r
+    {\r
+        if(pstDownSampCalParamInfo->uchRsEnable)\r
+        {\r
+            GS32 k;\r
+            GS64 y;\r
+            GS32 delta;\r
+            if (pstRsInfo ->snRsFirState > 0)\r
+            {\r
+                pstRsInfo ->snBufHead = pstRsInfo ->snBufHead - 1;\r
+                pstRsInfo ->snBufHead = pstRsInfo ->snBufHead < 0 ? (pstDownSampCalParamInfo->uchRsBufSize - 1) : pstRsInfo ->snBufHead;\r
+                pstRsInfo ->snRsXbuf[pstRsInfo ->snBufHead] = adcVal;\r
+                pstRsInfo ->nRsIcounter += pstDownSampCalParamInfo->uchRsI;\r
+            }\r
+            else\r
+            {\r
+                for (j = 0; j < pstDownSampCalParamInfo->uchRsFirOrder / pstDownSampCalParamInfo->uchRsI + 1; j++)\r
+                        pstRsInfo ->snRsXbuf[j] = adcVal;\r
+                pstRsInfo ->nRsIcounter = 0;\r
+                pstRsInfo ->snRsFirState = 1;\r
+                pstRsInfo ->snBufHead = pstDownSampCalParamInfo->uchRsBufSize - 1;\r
+            }\r
+\r
+            if (pstRsInfo ->nRrsDcounter >= pstRsInfo ->nRsIcounter && pstRsInfo ->nRrsDcounter < (pstRsInfo ->nRsIcounter + pstDownSampCalParamInfo->uchRsI))\r
+            {\r
+                delta = pstRsInfo ->nRrsDcounter - pstRsInfo ->nRsIcounter;\r
+                k = pstRsInfo ->snBufHead;\r
+                y = 0;\r
+                for (j = delta; j < pstDownSampCalParamInfo->uchRsFirCoefNum; j = j + pstDownSampCalParamInfo->uchRsI)\r
+                {\r
+                        y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[j]);\r
+                        k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize;\r
+                }\r
+                for (j = j; j <(pstDownSampCalParamInfo->uchRsFirOrder+1); j = j + pstDownSampCalParamInfo->uchRsI)\r
+                {\r
+                        y += ((GS64)pstRsInfo ->snRsXbuf[k] * pstDownSampCalParamInfo->rsFirCoef[pstDownSampCalParamInfo->uchRsFirOrder - j]);\r
+                        k = (k + 1) % pstDownSampCalParamInfo->uchRsBufSize;\r
+                }\r
+                pstRsInfo ->nRrsDcounter += pstDownSampCalParamInfo->uchRsD;\r
+\r
+                y = y >> SHIFTBITS;\r
+                k = (GS32)y + ADC_OFFSET;\r
+                if (k < 0)\r
+                        k = 0;\r
+                else if (k>=(ADC_OFFSET * 2))\r
+                        k = (ADC_OFFSET * 2-1); \r
+                fifoVal = (((GU8)chNo)<<27) + (((GU8)flagFastRecovery)<<26) + ((GU32)k);\r
+                puchFifoBuffer[*usRawdataBufIdx]     = GH3X2X_AFE_GET_BYTE3_FROM_DWORD(fifoVal);\r
+                puchFifoBuffer[*usRawdataBufIdx + 1] = GH3X2X_AFE_GET_BYTE2_FROM_DWORD(fifoVal);\r
+                puchFifoBuffer[*usRawdataBufIdx + 2] = GH3X2X_AFE_GET_BYTE1_FROM_DWORD(fifoVal);\r
+                puchFifoBuffer[*usRawdataBufIdx + 3] = GH3X2X_AFE_GET_BYTE0_FROM_DWORD(fifoVal);\r
+                *usRawdataBufIdx += GH3X2X_AFE_FIFO_RAWDATA_SIZE;\r
+            }\r
+        }\r
+    }\r
+#endif\r
+}\r
+\r
+void GH3X2X_EcgPPGRsHandleSingleChip(GU8 *puchFifoBuffer, GU16 *pusFifoBufferLen, GU8 uchChipIndex, GU8 uchEcgSlotNum ,GU16 usSampleRate)\r
+{\r
+    GU16 usByteIndexTmp = 0;\r
+    GU16 usRawdataBufIdx = 0;\r
+    GU8  usCheckDataType = 0; // 1:ECG 2:PPG 0:other\r
+\r
+    for (usByteIndexTmp = 0; usByteIndexTmp < *pusFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE)\r
+    {  \r
+        if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == GH3X2X_AFE_GET_ECG_CHANNEL_MAP((GU8)(GH3X2X_ECG_START_SLOT + uchEcgSlotNum)))\r
+        {\r
+            STGh3x2xRsInfo * pstRsInfo_ECG = g_pstGh3x2xEcgRsInfo + uchChipIndex;\r
+            g_uchDownSampleModule = DOWNSAMPLE_ECG;\r
+            GH3X2X_DownSampleCal( puchFifoBuffer, usByteIndexTmp, &usRawdataBufIdx, usSampleRate,pstRsInfo_ECG,pstECGDownSampCalParamInfo);\r
+            usCheckDataType =1;\r
+        }\r
+                                       \r
+        #if __SUPPORT_ECG_PPG_DOWNSAMP__\r
+        if(g_uchPPGDownSampleChnlNumLimit && pstPPGDownSampCalParamInfo->uchRsEnable==1)\r
+        {\r
+            for(GU8 uchPPGSlotNumTmp = 0; uchPPGSlotNumTmp < g_uchPPGDownSampleChnlNumLimit; uchPPGSlotNumTmp++)\r
+            {\r
+                if (GH3X2X_AFE_CHANNEL_MAP_GET(puchFifoBuffer[usByteIndexTmp]) == GH3X2X_AFE_GET_PPG_CHANNEL_MAP((GU8)(GH3X2X_PPG_START_SLOT + uchPPGSlotNumTmp)))\r
+                {\r
+                    STGh3x2xRsInfo * pstRsInfo_PPG = g_pstGh3x2xPPGRsInfo + uchPPGSlotNumTmp;\r
+                    g_uchDownSampleModule = DOWNSAMPLE_PPG;\r
+                    GH3X2X_DownSampleCal(puchFifoBuffer, usByteIndexTmp, &usRawdataBufIdx, usSampleRate,pstRsInfo_PPG,pstPPGDownSampCalParamInfo);\r
+                    usCheckDataType =2;\r
+                }\r
+            }\r
+        }\r
+        #endif\r
+        if(!usCheckDataType)\r
+        {\r
+            if(pstECGDownSampCalParamInfo->uchRsEnable)\r
+            {\r
+                //this rawdata is not ECG data\r
+                puchFifoBuffer[usRawdataBufIdx]     = puchFifoBuffer[usByteIndexTmp];\r
+                puchFifoBuffer[usRawdataBufIdx + 1] = puchFifoBuffer[usByteIndexTmp + 1];\r
+                puchFifoBuffer[usRawdataBufIdx + 2] = puchFifoBuffer[usByteIndexTmp + 2];\r
+                puchFifoBuffer[usRawdataBufIdx + 3] = puchFifoBuffer[usByteIndexTmp + 3];\r
+                usRawdataBufIdx += GH3X2X_AFE_FIFO_RAWDATA_SIZE;\r
+            }\r
+        }\r
+        usCheckDataType = 0;\r
+    } // end of for (usByteIndexTmp = 0; usByteIndexTmp < usFifoBufferLen; usByteIndexTmp += GH3X2X_AFE_FIFO_RAWDATA_SIZE)\r
+    *pusFifoBufferLen = usRawdataBufIdx;\r
+}\r
+\r
+GU8 GH3X2X_AFE_EcgRsHandle(GU8* puchFifoBuffer, GU16* pusFifoBufferLen, GU8 uchEcgSlotNum, GU16 usEcgSampleRate)\r
+{\r
+    if(pstECGDownSampCalParamInfo->uchRsEnable == 1)\r
+    {\r
+        GH3X2X_EcgPPGRsHandleSingleChip(puchFifoBuffer, pusFifoBufferLen, 0,uchEcgSlotNum,usEcgSampleRate);\r
+        return 1;\r
+    }\r
+    else\r
+    {\r
+        return 0;\r
+    }\r
+}\r
+\r
+/********END OF FILE********* Copyright (c) 2003 - 2022, Goodix Co., Ltd. ********/\r
+\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_afe_user.c
new file mode 100644 (file)
index 0000000..8190fed
--- /dev/null
@@ -0,0 +1,484 @@
+#include "gh3x2x_afe_user.h"\r
+#include "gh3x2x_afe_drv.h"\r
+#include "pinctrl_porting.h"\r
+#include "hal_gpio.h"\r
+#include "i2c.h"\r
+#include "pm_definition.h"\r
+#if GH3X2X_AFE_MP_MODE\r
+// #include "gh3x2x_mp_common.h"\r
+#endif\r
+\r
+#include "los_tick.h"\r
+#include "debug_print.h"\r
+\r
+#ifdef GOODIX_DEMO_PLATFORM\r
+#include "gh3x2x_demo_goodix_PLATFORM.h"\r
+#else\r
+\r
+#include "spi.h"\r
+\r
+#define GOODIX_PLATFORM_SPI_WRITE_ENTITY(write_buffer, length)\r
+#define GOODIX_PLATFORM_SPI_READ_ENTITY()\r
+#define GOODIX_PLATFORM_SPI_CS_CTRL_ENTITY()\r
+#define GOODIX_PLATFORM_SPI_RESET_PIN_ENTITY()\r
+#define GOODIX_PLATFORM_INT_HANDLER_CALL_BACK_ENTITY()\r
+#define GOODIX_PLATFORM_LOG_ENTITY()      \r
+#define GOODIX_PLATFORM_DELAY_US_ENTITY()\r
+#define GOODIX_PLATFORM_DELAY_MS_ENTITY()\r
+#define GOODIX_PLATFORM_DELAY_MS_ENTITY()\r
+#define GOODIX_PLATFORM_INT_INIT_ENTITY()\r
+#define GOODIX_PLATFORM_RESET_PIN_INIT_ENTITY()\r
+#define GOODIX_PLATFORM_SPI_INIT_ENTITY()\r
+#define GOODIX_PLATFORM_I2C_WRITE_ENTITY(device_id, write_buffer,length)\r
+#define GOODIX_PLATFORM_I2C_INIT_ENTITY()\r
+#define GOODIX_PLATFORM_I2C_READ_ENTITY(device_id, write_buffer, write_length, read_buffer, read_length)\r
+#endif\r
+\r
+#define GH3X2X_CS   S_MGPIO3\r
+#define GH3X2X_CLK  S_MGPIO2\r
+#define GH3X2X_MOSI S_MGPIO1\r
+#define GH3X2X_MISO S_MGPIO0\r
+\r
+#define GH3X2X_SPI_BUS SPI_BUS_0\r
+#define GH3X2X_I2C_BUS I2C_BUS_2\r
+\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_DelayUs(GU16 usUsec)\r
+ * \r
+ * @brief  Delay in us,user should register this function into driver lib\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+void hal_gh3x2x_afe_DelayUs(GU16 usUsec)\r
+{\r
+    // GH3X2X_AFE_UNUSED_VAR(usUsec);\r
+    // GOODIX_PLATFORM_DELAY_US_ENTITY();\r
+    LOS_Udelay(usUsec);\r
+\r
+}\r
+\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_BspDelayMs(GU16 usMsec)\r
+ * \r
+ * @brief  Delay in ms\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void hal_gh3x2x_afe_DelayMs(GU16 usMsec)\r
+{\r
+    // GH3X2X_AFE_UNUSED_VAR(usMsec);\r
+    // GOODIX_PLATFORM_DELAY_MS_ENTITY();\r
+    LOS_Mdelay(usMsec);\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+#if ( GH3X2X_AFE_COM_INTERFACE_TYPE == GH3X2X_AFE_COM_INTERFACE_I2C )\r
+\r
+/* i2c interface */\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_i2c_init(void)\r
+ * \r
+ * @brief  hal i2c init for gh3x2x_afe\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void hal_gh3x2x_afe_i2c_init(void)\r
+{\r
+\r
+    /* code implement by user */\r
+    GOODIX_PLATFORM_I2C_INIT_ENTITY();\r
+\r
+}\r
+\r
+/**\r
+ * @fn     uint8_t hal_gh3x2x_afe_i2c_write(uint8_t device_id, const uint8_t write_buffer[], uint16_t length)\r
+ * \r
+ * @brief  hal i2c write for gh3x2x_afe\r
+ *\r
+ * @attention   device_id is 8bits, if platform i2c use 7bits addr, should use (device_id >> 1)\r
+ *\r
+ * @param[in]   device_id       device addr\r
+ * @param[in]   write_buffer    write data buffer\r
+ * @param[in]   length          write data len\r
+ * @param[out]  None\r
+ *\r
+ * @return  status\r
+ * @retval  #1      return successfully\r
+ * @retval  #0      return error\r
+ */\r
+GU8 hal_gh3x2x_afe_i2c_write(GU8 device_id, const GU8 write_buffer[], GU16 length)\r
+{\r
+    uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART);\r
+    if (cnt == 0) \r
+    {\r
+        uapi_pm_add_sleep_veto(PM_ID_HEART);\r
+    }\r
+    uint8_t ret = 1;\r
+\r
+    /* code implement by user */\r
+\r
+    // GOODIX_PLATFORM_I2C_WRITE_ENTITY(device_id, write_buffer,length);\r
+    i2c_data_t i2c_data;\r
+       i2c_data.send_buf = write_buffer;\r
+    i2c_data.send_len = length;\r
+    i2c_data.receive_buf = NULL;\r
+    i2c_data.receive_len = 0;\r
+       // custom_i2c_write_reg(BN02_I2C_ADDR, 0x00, 1, &data, 1, BN02_I2C_BUS);\r
+       errcode_t result = uapi_i2c_master_write(GH3X2X_I2C_BUS, device_id, &i2c_data);\r
+       if (result != ERRCODE_SUCC) \r
+        printf("i2c write data fail! ret=0x%x\n", result);\r
+    // custom_i2c_read_regs(device_id, reg_addr, 1 , pBuffer, buf_size, VC9202_I2C_BUS);\r
+\r
+    cnt = pm_veto_get_id_cnt(PM_ID_HEART);\r
+    if (cnt == 1) \r
+    {\r
+        uapi_pm_remove_sleep_veto(PM_ID_HEART);\r
+    }\r
+\r
+\r
+    return ret;\r
+}\r
+\r
+/**\r
+ * @fn     uint8_t hal_gh3x2x_afe_i2c_read(uint8_t device_id, const uint8_t write_buffer[], uint16_t write_length,\r
+ *                            uint8_t read_buffer[], uint16_t read_length)\r
+ * \r
+ * @brief  hal i2c read for gh3x2x_afe\r
+ *\r
+ * @attention   device_id is 8bits, if platform i2c use 7bits addr, should use (device_id >> 1)\r
+ *\r
+ * @param[in]   device_id       device addr\r
+ * @param[in]   write_buffer    write data buffer\r
+ * @param[in]   write_length    write data len\r
+ * @param[in]   read_length     read data len\r
+ * @param[out]  read_buffer     pointer to read buffer\r
+ *\r
+ * @return  status\r
+ * @retval  #1      return successfully\r
+ * @retval  #0      return error\r
+ */\r
+GU8 hal_gh3x2x_afe_i2c_read(GU8 device_id, const GU8 write_buffer[], GU16 write_length, GU8 read_buffer[], GU16 read_length)\r
+{\r
+    uint8_t cnt = pm_veto_get_id_cnt(PM_ID_HEART);\r
+    if (cnt == 0) \r
+    {\r
+        uapi_pm_add_sleep_veto(PM_ID_HEART);\r
+    }\r
+    uint8_t ret = 1;\r
+\r
+    /* code implement by user */\r
+\r
+    // GOODIX_PLATFORM_I2C_READ_ENTITY(device_id, write_buffer, write_length, read_buffer, read_length);\r
+\r
+    i2c_data_t i2c_data;\r
+       i2c_data.send_buf = write_buffer;\r
+    i2c_data.send_len = write_length;\r
+    i2c_data.receive_buf = read_buffer;\r
+    i2c_data.receive_len = read_length;\r
+\r
+       errcode_t result = uapi_i2c_master_writeread(GH3X2X_I2C_BUS, device_id, &i2c_data);\r
+       if (result != ERRCODE_SUCC) \r
+        printf("i2c read data fail! ret=0x%x\n", result);\r
+    // custom_i2c_read_regs(device_id, reg_addr, 1 , pBuffer, buf_size, VC9202_I2C_BUS);\r
+\r
+    cnt = pm_veto_get_id_cnt(PM_ID_HEART);\r
+    if (cnt == 1) \r
+    {\r
+        uapi_pm_remove_sleep_veto(PM_ID_HEART);\r
+    }\r
+\r
+    return ret;\r
+}\r
+\r
+#else \r
+\r
+/* spi interface */\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_spi_init(void)\r
+ * \r
+ * @brief  hal spi init for gh3x2x_afe\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+void hal_gh3x2x_afe_spi_init(void)\r
+{\r
+    /* init spi and cs pin */\r
+    // GOODIX_PLATFORM_SPI_INIT_ENTITY();\r
+    spi_bus_t bus;\r
+    spi_attr_t attr;\r
+    bus = SPI_BUS_0;\r
+    attr.is_slave = false;\r
+    attr.slave_num = 1;\r
+    attr.bus_clk = 40000000;\r
+    attr.freq_mhz = 10;\r
+    attr.clk_polarity = (uint32_t)SPI_CFG_CLK_CPOL_1;\r
+    attr.clk_phase = (uint32_t)SPI_CFG_CLK_CPHA_1;\r
+    attr.frame_format = SPI_CFG_FRAME_FORMAT_MOTOROLA_SPI;\r
+    attr.spi_frame_format = (uint32_t)HAL_SPI_FRAME_FORMAT_STANDARD;\r
+    attr.frame_size = (uint32_t)HAL_SPI_FRAME_SIZE_8;\r
+    attr.tmod = HAL_SPI_TRANS_MODE_TXRX;\r
+    attr.sste = SPI_CFG_SSTE_DISABLE;\r
+    attr.ndf = 1;\r
+\r
+    uapi_spi_init(bus,&attr,NULL);\r
+}\r
+\r
+/**\r
+ * @fn     GU8 hal_gh3x2x_afe_spi_write(GU8 write_buffer[], GU16 length)\r
+ * \r
+ * @brief  hal spi write for gh3x2x_afe\r
+ *\r
+ * @attention   if __gh3x2x_afe_SPI_TYPE__ == __gh3x2x_afe_SPI_TYPE_SOFTWARE_CS__  , user need generate timming: write_buf[0](W) + write_buf[1](W) + ...\r
+ * @attention   if __gh3x2x_afe_SPI_TYPE__ == __gh3x2x_afe_SPI_TYPE_HARDWARE_CS__  , user need generate timming: CS LOW  + write_buf[0](W) + write_buf[1](W) + ... + CS HIGH\r
+ *\r
+ * @param[in]   write_buffer    write data buffer\r
+ * @param[in]   length          write data len\r
+ * @param[out]  None\r
+ *\r
+ * @return  status\r
+ * @retval  #1      return successfully\r
+ * @retval  #0      return error\r
+ */\r
+GU8 hal_gh3x2x_afe_spi_write(GU8 write_buffer[], GU16 length)\r
+{\r
+    GU8 ret = 1;\r
+\r
+    \r
+    //   GOODIX_PLATFORM_SPI_WRITE_ENTITY(write_buffer, length);\r
+    spi_xfer_data_t sdata ={0} ;\r
+       sdata.tx_buff = write_buffer;\r
+       sdata.tx_bytes = length;\r
+       sdata.rx_buff = NULL;\r
+       sdata.rx_bytes = 0;\r
+\r
+    ret = uapi_spi_master_write(GH3X2X_SPI_BUS, &sdata, 0x100);\r
+\r
+\r
+    return ret;\r
+}\r
+\r
+\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) \r
+/**\r
+ * @fn     GU8 hal_gh3x2x_afe_spi_read(GU8 read_buffer[], GU16 length)\r
+ * \r
+ * @brief  hal spi read for gh3x2x_afe\r
+ *\r
+ * @attention   user need generate timming: read_buf[0](R) + write_buf[1](R) + ... \r
+ *\r
+ * @param[in]   read_length     read data len\r
+ * @param[out]  read_buffer     pointer to read buffer\r
+ *\r
+ * @return  status\r
+ * @retval  #1      return successfully\r
+ * @retval  #0      return error\r
+ */\r
+GU8 hal_gh3x2x_afe_spi_read(GU8 read_buffer[], GU16 length)\r
+{\r
+    GU8 ret = 1;\r
+    // GH3X2X_AFE_UNUSED_VAR(read_buffer);\r
+    // GH3X2X_AFE_UNUSED_VAR(length);\r
+    // GOODIX_PLATFORM_SPI_READ_ENTITY();\r
+\r
+    spi_xfer_data_t sdata ={0} ;\r
+       sdata.tx_buff = NULL;\r
+       sdata.tx_bytes = 0;\r
+       sdata.rx_buff = read_buffer;\r
+       sdata.rx_bytes = length;\r
+\r
+    ret = uapi_spi_master_read(GH3X2X_SPI_BUS, &sdata, 0x100);\r
+\r
+    return ret;\r
+}\r
+#elif (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_HARDWEAR_CS)\r
+/**\r
+ * @fn     GU8 hal_gh3x2x_afe_spi_write_F1_and_read(GU8 read_buffer[], GU16 length)\r
+ * \r
+ * @brief  hal spi write F1 and read for gh3x2x_afe\r
+ *\r
+ * @attention    user need generate timming: CS LOW + F1(W) + read_buf[0](R) + read_buf[1](R) + ... + CS HIGH\r
+ *\r
+ * @param[in]   write_buf     write data\r
+ * @param[in]   length     write data len\r
+ *\r
+ * @return  status\r
+ * @retval  #1      return successfully\r
+ * @retval  #0      return error\r
+ */\r
+GU8 hal_gh3x2x_afe_spi_write_F1_and_read(GU8 read_buffer[], GU16 length)\r
+{\r
+    GU8 ret = 1;\r
+    GH3X2X_AFE_UNUSED_VAR(read_buffer);\r
+    GH3X2X_AFE_UNUSED_VAR(length);\r
+    GOODIX_PLATFORM_SPI_READ_ENTITY();\r
+    \r
+    return ret;\r
+}\r
+#endif\r
+\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_spi_cs_ctrl(GU8 cs_pin_level)\r
+ * \r
+ * @brief  hal spi cs pin ctrl for gh3x2x_afe\r
+ *\r
+ * @attention   pin level set 1 [high level] or 0 [low level]\r
+ *\r
+ * @param[in]   cs_pin_level     spi cs pin level\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+\r
+\r
+#if (GH3X2X_AFE_SPI_TYPE == GH3X2X_AFE_SPI_SOFTWARE_CS) \r
+void hal_gh3x2x_afe_spi_cs_ctrl(GU8 cs_pin_level)\r
+{\r
+    // GH3X2X_AFE_UNUSED_VAR(cs_pin_level);\r
+    // GOODIX_PLATFORM_SPI_CS_CTRL_ENTITY();\r
+\r
+    uapi_pin_set_mode(GH3X2X_CS, (pin_mode_t)HAL_PIO_FUNC_GPIO);\r
+    uapi_gpio_set_dir(GH3X2X_CS, GPIO_DIRECTION_OUTPUT);\r
+    uapi_gpio_set_val(GH3X2X_CS, cs_pin_level);\r
+\r
+}\r
+#endif\r
+\r
+#endif\r
+\r
+#if (GH3X2X_AFE_RESET_TYPE == GH3X2X_AFE_RESET_HARDWARE)\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_int_init(void)\r
+ * \r
+ * @brief  gh3x2x_afe int init\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+\r
+\r
+void hal_gh3x2x_afe_reset_pin_init(void)\r
+{\r
+    GOODIX_PLATFORM_RESET_PIN_INIT_ENTITY();\r
+}\r
+\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_reset_pin_ctrl(GU8 pin_level)\r
+ * \r
+ * @brief  hal reset pin ctrl for gh3x2x_afe\r
+ *\r
+ * @attention   pin level set 1 [high level] or 0 [low level]\r
+ *\r
+ * @param[in]   pin_level     reset pin level\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+void hal_gh3x2x_afe_reset_pin_ctrl(GU8 pin_level)\r
+{\r
+    GH3X2X_AFE_UNUSED_VAR(pin_level);\r
+    GOODIX_PLATFORM_SPI_RESET_PIN_ENTITY();\r
+}\r
+\r
+#endif\r
+\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_int_init(void)\r
+ * \r
+ * @brief  gh3x2x_afe int init\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+\r
+\r
+void hal_gh3x2x_afe_int_init(void)\r
+{\r
+    GOODIX_PLATFORM_INT_INIT_ENTITY();\r
+}\r
+\r
+#if (GH3X2X_AFE_PRO_BY_INT == GH3X2X_AFE_PRO_TYPE)\r
+/**\r
+ * @fn     void hal_gh3x2x_afe_int_handler_call_back(void)\r
+ * \r
+ * @brief  call back of gh3x2x_afe int handler\r
+ *\r
+ * @attention   None\r
+ *\r
+ * @param[in]   None\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void hal_gh3x2x_afe_int_handler_call_back(void)\r
+{\r
+/****************** DO NOT MODITY ****************************************************************/\r
+       GH3X2X_AFE_SetNeedWakeUpGh3x2xFlag(0);  //not need wake up gh3x2x_afe when process int event\r
+       g_uchGh3x2xAfeIntCallBackIsCalled = 1;\r
+#if GH3X2X_AFE_MP_MODE\r
+       GH3X2X_MP_SET_INT_FLAG();  //gh3x2x mp test must call it\r
+#endif\r
+/****************** DO NOT MODITY ****************************************************************/\r
+    \r
+    \r
+    \r
+    GOODIX_PLATFORM_INT_HANDLER_CALL_BACK_ENTITY();\r
+}\r
+\r
+#endif\r
+\r
+/**\r
+ * @fn     void GH3X2X_AFE_Log(char *log_string)\r
+ * \r
+ * @brief  for debug version, log\r
+ *\r
+ * @attention   this function must define that use debug version lib\r
+ *\r
+ * @param[in]   log_string      pointer to log string\r
+ * @param[out]  None\r
+ *\r
+ * @return  None\r
+ */\r
+void GH3X2X_AFE_Log(GCHAR *log_string)\r
+{\r
+    // GH3X2X_AFE_UNUSED_VAR(log_string);\r
+    // GOODIX_PLATFORM_LOG_ENTITY();\r
+    PRINT("%s", log_string);\r
+}\r
+\r
diff --git a/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c b/code/sdk/zhihui/drivers/ppg/gh3x2x/src/gh3x2x_hal.c
new file mode 100644 (file)
index 0000000..d1eea6e
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * @Author: penglei 1624952103@qq.com
+ * @Date: 2024-03-13 15:08:38
+ * @LastEditors: penglei 1624952103@qq.com
+ * @LastEditTime: 2025-01-17 17:57:09
+ * @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 "pinctrl_porting.h"
+#include "hal_gpio.h"
+
+// 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(S_AGPIO_L24, (pin_mode_t)HAL_PIO_FUNC_GPIO);
+    uapi_gpio_set_dir(S_AGPIO_L24, GPIO_DIRECTION_OUTPUT);
+    uapi_gpio_set_val(S_AGPIO_L24, GPIO_LEVEL_LOW);
+    LOS_Mdelay(1);
+    uapi_pin_set_mode(S_MGPIO0, (pin_mode_t)HAL_PIO_FUNC_GPIO);
+    uapi_gpio_set_dir(S_MGPIO0, GPIO_DIRECTION_OUTPUT);
+    uapi_gpio_set_val(S_MGPIO0, GPIO_LEVEL_LOW);
+    LOS_Mdelay(1);
+    uapi_pin_set_mode(GPIO_PIN_PRG_LED_ON, (pin_mode_t)HAL_PIO_FUNC_GPIO);
+    uapi_gpio_set_dir(GPIO_PIN_PRG_LED_ON, GPIO_DIRECTION_OUTPUT);
+    uapi_gpio_set_val(GPIO_PIN_PRG_LED_ON, GPIO_LEVEL_HIGH);
+    LOS_Mdelay(1);
+    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);
+   
+    LOS_Mdelay(50);
+    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(50);
+    return 0;
+}
+
+void ppg_send_cmd_to_gh3x2x_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
index 40f29c8..7644bda 100644 (file)
@@ -52,6 +52,9 @@ extern "C" {
 #elif  defined(PPG_VC921X)
 #include "vc921x_hal.h"
 #include "vc921x_user_app.h"
+#elif  defined(PPG_GH3X2X)
+#include "gh3x2x_hal.h"
+#include "gh3x2x_afe_drv.h"
 #else
 #include "hx3695_hal.h"
 #include "hx3695.h"
@@ -464,6 +467,14 @@ errcode_t uapi_ppg_service_init(void)
         tyhx_poweroff();
         return ERRCODE_FAIL;
     }
+#elif defined(PPG_GH3X2X)
+    if (GH3X2X_AFE_CheckChipId() != 0)
+    {
+        //TODO 没找到3695,退出线程
+        PRINT("PPG_GH3X2X not exist!\r\n");
+        tyhx_poweroff();
+        return ERRCODE_FAIL;
+    }
 #endif
 
     tyhx_poweroff();
index cc4bc6c..c9c3ad8 100644 (file)
@@ -89,8 +89,10 @@ bool uapi_cat1_get_power_stat(void)
 {
 #if defined(BOARD_FD230)
    return (  GPIO_LEVEL_HIGH == uapi_gpio_get_output_val(S_AGPIO_L23));
-#elif defined(BOARD_L22) || defined(BOARD_W9)
+#elif defined(BOARD_L22)
    return (  GPIO_LEVEL_HIGH == uapi_gpio_get_output_val(S_AGPIO_L14));
+#elif defined(BOARD_W9)
+   return (  GPIO_LEVEL_HIGH == uapi_gpio_get_output_val(S_AGPIO_L17));
 #endif
 
 }
index 7b27669..2ca706f 100644 (file)
@@ -750,7 +750,7 @@ bool batteryservice_get_voltage_by_channel(float *voltage, uint8_t channel)
 #define GPIO_PIN_CHARGE_STAT S_AGPIO_L29
 void disable_charge(void)
 {
-#ifdef BOARD_FD230
+#if defined(BOARD_FD230) || defined(BOARD_W9)
     // PRINT("disable_charge\r\n");
     uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE, (pin_mode_t)HAL_PIO_FUNC_GPIO);
     uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE, GPIO_DIRECTION_OUTPUT);
@@ -763,7 +763,7 @@ void disable_charge(void)
 
 void enable_charge(void)
 {
-#ifdef BOARD_FD230
+#if defined(BOARD_FD230) || defined(BOARD_W9)
     // PRINT("enable_charge\r\n");
     uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE, (pin_mode_t)HAL_PIO_FUNC_GPIO);
     uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE, GPIO_DIRECTION_OUTPUT);
@@ -777,7 +777,7 @@ void enable_charge(void)
 
 void enable_02c(void)
 {
-#ifdef BOARD_FD230
+#if defined(BOARD_FD230) || defined(BOARD_W9)
     // PRINT("enable_charge_02c\r\n");
     uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE_0_2C, (pin_mode_t)HAL_PIO_FUNC_GPIO);
     uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE_0_2C, GPIO_DIRECTION_OUTPUT);
@@ -797,7 +797,7 @@ uint8_t get_02c_value(void)
 }
 void disable_02c(void)
 {
-#ifdef BOARD_FD230
+#if defined(BOARD_FD230) || defined(BOARD_W9)
     // PRINT("disable_charge_02c\r\n");
     uapi_pin_set_mode(GPIO_PIN_ENABLE_CHARGE_0_2C, (pin_mode_t)HAL_PIO_FUNC_GPIO);
     uapi_gpio_set_dir(GPIO_PIN_ENABLE_CHARGE_0_2C, GPIO_DIRECTION_OUTPUT);
index a590391..e12969e 100644 (file)
@@ -2,7 +2,7 @@
  * @Author: penglei 1624952103@qq.com\r
  * @Date: 2024-06-17 14:31:08\r
  * @LastEditors: penglei 1624952103@qq.com\r
- * @LastEditTime: 2025-01-09 16:57:54\r
+ * @LastEditTime: 2025-01-16 10:01:35\r
  * @FilePath: /FD230/code/sdk/application/wearable/service/factorytest_service/factorytest_protocol.c\r
  * @Description: \r
  * \r
 #ifdef ENABLE_HP4507\r
 #include "hp4570.h"\r
 #endif\r
-\r
+#ifdef PPG_VC9202\r
+#include "vc9202_user.h"\r
+#endif\r
+#ifdef SUPPORT_GNSS\r
+#include "gnss_ctl.h"\r
+#include "NMEA0183.h"\r
+static gps_data_t send_gps_data = {0};\r
+#endif\r
 #pragma pack(1)\r
 typedef struct factorytest_cmd_header_t\r
 {\r
@@ -1753,7 +1760,29 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint
                 1);\r
                 LOS_Mdelay(100);\r
                 uapi_poweroff_device();\r
+            } else if(testitem == 0x06)\r
+            {\r
+                //切换vbus供电测电流\r
+                uint8_t send_data = 0x00;\r
+#ifdef ENABLE_HP4507\r
+                hp45xxx_init(HP4570C9);\r
+                hp45xxx_set_batfet_dis(true);\r
+                // hp45xxx_set_ceb_en(true);\r
+                hp45xxx_set_hiz_en(false);\r
+                LOS_Mdelay(50);\r
+                if (hp45xxx_read_status_vbus_pg()) \r
+                    PRINT("VBUS is in Power Good state\n");\r
+                else \r
+                    PRINT("VBUS is not in Power Good state\n");\r
+            \r
+#endif\r
+                factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
+                BLE_TEST_CMD_SOFT_TEST_SUB_MODE_PM,\r
+                0x06,\r
+                &send_data,\r
+                1);\r
             }\r
+            \r
 \r
             break;\r
 \r
@@ -2210,6 +2239,87 @@ void factorytest_protocol_soft_test_decode(uint8_t submode,uint8_t testitem,uint
 \r
             break;\r
 \r
+        case BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS:\r
+\r
+            if (testitem == 0x01)\r
+            {\r
+                //定位\r
+                uint8_t send_data = 0;\r
+                bool flag = 0;\r
+                char tmp[1024]={0};\r
+                char time[10]={0};\r
+#ifdef SUPPORT_GNSS\r
+                gnss_start();\r
+                LOS_Msleep(100);\r
+                do{\r
+                    gps_data_t *gps_data = getGPSGlobaldata();\r
+                    if(gps_data == NULL)\r
+                    {\r
+                        PRINT("gps_data == NULL \n");\r
+                        return;\r
+                    }\r
+                    if (gps_data->last_gps_time_ms > 0)\r
+                    {\r
+                        memcpy_s(&send_gps_data,sizeof(gps_data_t),gps_data,sizeof(gps_data_t));\r
+                    }\r
+                    if(send_gps_data.status > 1)\r
+                    {\r
+                        flag = 1;\r
+                    }\r
+                    else\r
+                    {\r
+                        LOS_Msleep(1000);\r
+                        send_data++;\r
+                    }\r
+                    memset_s(tmp,sizeof(tmp),0,sizeof(tmp));        \r
+                    dump_location_data_to_factory(&send_gps_data,tmp,sizeof(tmp));\r
+                    memset_s(time,sizeof(time),0,sizeof(time));  \r
+                    sprintf_s(time,sizeof(time),"%d",send_data);\r
+                    strcat_s(tmp,sizeof(tmp),time);\r
+                    // PRINT("send_gps_data.status : %d time : %d\n",send_gps_data.status,send_data);\r
+                    // PRINT("tmp : %s size : %d\n",tmp,strlen(tmp));\r
+                    factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
+                        BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS,\r
+                        0x01,\r
+                        (uint8_t*)tmp,\r
+                        strlen(tmp));\r
+                }while(send_data <= 2 * 60 && !flag);\r
+                // PRINT("定位超时 关闭GPS\n");\r
+                gnss_stop();\r
+#endif\r
+\r
+            } else if(testitem == 0x02)\r
+            {\r
+                //获取可见星 有效星 信号增益 定位精度\r
+                uint8_t send_data[7] = {0};\r
+#ifdef SUPPORT_GNSS\r
+                // if(send_gps_data)\r
+                {\r
+                    send_data[0] = send_gps_data.num_sats;\r
+                    send_data[1] = send_gps_data.th001_valid_star_count;\r
+                    send_data[2] = send_gps_data.th000_signal_vga;\r
+                    send_data[3] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0xFF000000) >> 24);\r
+                    send_data[4] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0x00FF0000) >> 16);\r
+                    send_data[5] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0x0000FF00) >> 8);\r
+                    send_data[6] = (uint8_t)(((uint32_t)send_gps_data.th001_quality & 0x000000FF) >> 0);\r
+\r
+                    // PRINT("gps_data->num_sats : %d,gps_data->th001_valid_star_count : %d,gps_data->th000_signal_vga : %d,gps_data->th001_quality : %f\n",\r
+                    // send_gps_data.num_sats,send_gps_data.th001_valid_star_count,\r
+                    // send_gps_data.th000_signal_vga,send_gps_data.th001_quality\r
+                    // );\r
+                    // PRINT("%2X %2X %2X\r\n",send_data[0],send_data[1],send_data[2]);\r
+                    // PRINT("%2X %2X %2X %2X \r\n",send_data[3],send_data[4],send_data[5],send_data[6]);\r
+                }\r
+#endif\r
+                factorytest_protocol_replymsg(BLE_TEST_CMD_MODE_SOFT_TEST,\r
+                        BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS,\r
+                        0x02,\r
+                        send_data,\r
+                        sizeof(send_data));\r
+            }\r
+\r
+            break;\r
+\r
         default:\r
             printf("");\r
             break;\r
@@ -2247,7 +2357,7 @@ errcode_t factorytest_protocol_decode(uint8_t *buf, uint16_t event_size)
                 \r
             printf("crc16 0x%04X vs 0x%04X\n",crc16,crc16_2);\r
 \r
-            // if( crc16 == crc16_2) //校验通过,开始正式解析\r
+            if( crc16 == crc16_2) //校验通过,开始正式解析\r
             {\r
                 if(factorytest_mode_flag == 0 && header.submod != BLE_TEST_CMD_COMMON_SUB_MODE_SWITCH_MODE)\r
                     return ERRCODE_FAIL;\r
index b8198b4..d238728 100644 (file)
@@ -95,6 +95,9 @@ extern "C" {
 #define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_SPEAKER  0x1B
 //软件测试 子模式ID  气压计
 #define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_LQBP  0x1C
+//软件测试 子模式ID  GPS
+#define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_GPS  0x1D
+
 //软件测试 子模式ID  通讯录
 #define BLE_TEST_CMD_SOFT_TEST_SUB_MODE_CONTACTS  0x30
 //软件测试 子模式ID  支付宝
index 32c18e3..ba7690c 100644 (file)
@@ -259,6 +259,8 @@ void dump_location_data(gps_data_t *locationdata);
 void dump_location_data_to_buf(gps_data_t *locationdata,char* buf,int max_buflen);\r
 gps_data_t * getGPSGlobaldata(void);\r
 \r
+void dump_location_data_to_factory(gps_data_t *locationdata,char* buf,int max_buflen);\r
+\r
 #ifdef __cplusplus\r
 }\r
 #endif /* __cplusplus */\r
index 7dbf6fd..bf27cbe 100644 (file)
@@ -1194,6 +1194,225 @@ void dump_location_data_to_buf(gps_data_t *locationdata,char* buf,int max_buflen
 #endif\r
        free(tmpbuf);\r
 }\r
+\r
+void dump_location_data_to_factory(gps_data_t *locationdata,char* buf,int max_buflen)\r
+{\r
+       \r
+       char *tmpbuf=(char*)malloc(DUMP_BUF_SIZE);\r
+       if (tmpbuf == NULL) return;\r
+#ifndef NOUTILS\r
+\r
+       // memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+       // sprintf_s(tmpbuf,DUMP_BUF_SIZE,"xx卫星[卫星数](strid,snr):\n");\r
+\r
+       if (locationdata->starcountP>0)\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"G,%d",\r
+               locationdata->starcountP);\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+               for(int i=0;i<5;i++)\r
+               {\r
+                       // printf("i : %d locationdata->startsP[i].starID : %d \n",i,locationdata->startsP[i].starID);\r
+                       if (i< locationdata->startsP[i].starID>0)\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d",\r
+                                       locationdata->startsP[i].starID,\r
+                                       locationdata->startsP[i].snr);\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+                       else\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0");\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"G,0,0,0,0,0,0,0,0,0,0,0");\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+       }\r
+\r
+       strcat_s(buf,max_buflen,";");\r
+\r
+\r
+       if (locationdata->starcountB>0)\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"B,%d",\r
+               locationdata->starcountB);\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+               for(int i=0;i<5;i++)\r
+               {\r
+                       // printf("i : %d locationdata->startsB[i].starID : %d \n",i,locationdata->startsB[i].starID);\r
+                       if (i< locationdata->startsB[i].starID>0)\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d",\r
+                                       locationdata->startsB[i].starID,\r
+                                       locationdata->startsB[i].snr);\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+                       else\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0");\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"B,0,0,0,0,0,0,0,0,0,0,0");\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+       }\r
+       \r
+       strcat_s(buf,max_buflen,";");\r
+\r
+       if (locationdata->starcountN>0)\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,";N,%d",\r
+               locationdata->starcountN);\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+               for(int i=0;i<5;i++)\r
+               {\r
+                       // printf("i : %d locationdata->startsN[i].starID : %d \n",i,locationdata->startsN[i].starID);\r
+                       if (i< locationdata->startsN[i].starID>0)\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d",\r
+                                       locationdata->startsN[i].starID,\r
+                                       locationdata->startsN[i].snr);\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+                       else\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0");\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"N,0,0,0,0,0,0,0,0,0,0,0");\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+       }\r
+\r
+       strcat_s(buf,max_buflen,";");\r
+\r
+       if (locationdata->starcountL>0)\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"L,%d",\r
+               locationdata->starcountL);\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+               for(int i=0;i<5;i++)\r
+               {\r
+                       // printf("i : %d locationdata->startsL[i].starID : %d \n",i,locationdata->startsL[i].starID);\r
+                       if (i< locationdata->startsL[i].starID>0)\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d",\r
+                                       locationdata->startsL[i].starID,\r
+                                       locationdata->startsL[i].snr);\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+                       else\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0");\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"L,0,0,0,0,0,0,0,0,0,0,0");\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+       }\r
+\r
+       strcat_s(buf,max_buflen,";");\r
+\r
+       if (locationdata->starcountQ>0)\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"Q,%d",\r
+               locationdata->starcountQ);\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+               for(int i=0;i<5;i++)\r
+               {\r
+                       // printf("i : %d locationdata->startsQ[i].starID : %d \n",i,locationdata->startsQ[i].starID);\r
+                       if (i< locationdata->startsQ[i].starID>0)\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d",\r
+                                       locationdata->startsQ[i].starID,\r
+                                       locationdata->startsQ[i].snr);\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+                       else\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0");\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"Q,0,0,0,0,0,0,0,0,0,0,0");\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+       }\r
+\r
+       strcat_s(buf,max_buflen,";");\r
+       \r
+       if (locationdata->starcountA>0)\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"A,%d",\r
+               locationdata->starcountA);\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+               for(int i=0;i<5;i++)\r
+               {\r
+                       // printf("i : %d locationdata->startsA[i].starID : %d \n",i,locationdata->startsA[i].starID);\r
+                       if (i< locationdata->startsA[i].starID>0)\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",%d,%d",\r
+                                       locationdata->startsA[i].starID,\r
+                                       locationdata->startsA[i].snr);\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+                       else\r
+                       {\r
+                               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+                               sprintf_s(tmpbuf,DUMP_BUF_SIZE,",0,0");\r
+                               strcat_s(buf,max_buflen,tmpbuf);\r
+                       }\r
+               }\r
+       }\r
+       else\r
+       {\r
+               memset_s(tmpbuf,DUMP_BUF_SIZE,0,DUMP_BUF_SIZE);\r
+               sprintf_s(tmpbuf,DUMP_BUF_SIZE,"A,0,0,0,0,0,0,0,0,0,0,0");\r
+               strcat_s(buf,max_buflen,tmpbuf);\r
+       }\r
+       strcat_s(buf,max_buflen,";");\r
+#endif\r
+       free(tmpbuf);\r
+}\r
+\r
+\r
 #define MSGBUF_LEN 1024\r
 void dump_location_data(gps_data_t*locationdata)\r
 {\r
index 5d81c5c..77d8df9 100644 (file)
@@ -2712,11 +2712,17 @@ error:
 uint32_t custom_i2c_suspend(void)
 {
     i2c_save_reg(I2C_BUS_2);
+#ifdef ENABLE_BN02
+    i2c_save_reg(I2C_BUS_0);
+#endif
     return 0;
 }
 uint32_t custom_i2c_resume(void)
 {
     i2c_recovery_reg(I2C_BUS_2);
+#ifdef ENABLE_BN02
+    i2c_recovery_reg(I2C_BUS_0);
+#endif
     return 0;
 }
 
index 0f1f7af..97b4f1f 100644 (file)
@@ -431,7 +431,7 @@ static uint32_t custom_at_message_test(uint8_t *para, uint32_t paraLen, char *st
     return ERRCODE_SUCC;
 }
 #include "cywee_hal.h"
-#include "hx3695_hrs_agc.h"
+
 static uint32_t custom_gsensor_getdata(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
 {
     // gsenson_t *t;