--- /dev/null
+#include "lv_drv_conf_CUSTOM.h"
+#if USE_WMM300
+#include "whale_algo.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+#include "../../board.h"
+#include "../../common/i2c.h"
+#include "../../../../product/craneg_modem/framework/inc/gpio_api.h"
+#include "lvgl/hal/hal.h"
+#include "../../../lv_watch/app_adaptor/app_sensor_task.h"
+
+/************************simware add start***********************************/
+static uint32_t wmm300_mfp_cfgs[] = {
+ MFP_REG(GPIO_32) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE,
+ MFP_REG(GPIO_18) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE,
+ MFP_REG(GPIO_81) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE,
+ MFP_REG(GPIO_84) | MFP_AF0 | MFP_DRIVE_MEDIUM | MFP_PULL_LOW | MFP_SLEEP_DIR | MFP_LPM_EDGE_NONE,
+ MFP_EOC
+};
+
+typedef void* OS_HISR;
+static OS_HISR wmm300_hisr_ref;
+static void * wmm300_process_timer = NULL;
+static void * wmm300_millisecond_timer = NULL;
+static whale_algo_plat_if_t plat_if;
+static unsigned char is_WMM300 = 0;//是否存在IC
+static unsigned char is_open_WMM300 = 0; //是否打开测试
+static unsigned char s_WMM300_heart_rate = 0x0;//心律
+static unsigned char s_WMM300_high_blood = 0x0;//血压/高压
+static unsigned char s_WMM300_low_blood = 0x0;//血压/低压
+static unsigned char s_WMM300_blood_oxygen = 0x0;//血氧
+static unsigned char s_WMM300_HRV = 0x0;//hrv
+unsigned char s_WMM300_wear_status = 1;//佩戴状态
+#define HEART_RATE_BUFF_LEN 10
+unsigned char s_WMM300_heart_rate_buff[HEART_RATE_BUFF_LEN]={0};
+unsigned short s_WMM300_heart_rate_buff_count = 0;
+uint32_t WMM300_run_mode = NULL_MODE;
+uint32_t WMM300_jobs_mode = NULL_MODE;
+int ir_wear = 0;//红外佩戴状态
+int cap_wear = 1;//电容佩戴状态
+char is_open_sar = 1;//是否打开sar检测
+activity_data_t act_data;
+static void acc_process(void);
+void WMM300_close(void);
+static void wmm300_en_gpio_init(void)
+{
+ gpio_set_direction(GPIO18, GPIO_OUT);
+ gpio_set_direction(GPIO81, GPIO_OUT);
+ gpio_set_direction(GPIO84, GPIO_OUT);
+}
+//Hsensor 电源、复位
+static void wmm300_en_gpio_enable(bool param)
+{
+ static flag = 0;
+ if(param)
+ flag++;
+ else
+ {
+ if(flag > 0)
+ flag --;
+ }
+
+ if(flag > 0) {
+ gpio_set_value(GPIO18, GPIO_HIGH);
+ gpio_set_value(GPIO81, GPIO_HIGH);
+ gpio_set_value(GPIO84, GPIO_HIGH);
+ } else {
+ gpio_set_value(GPIO18, GPIO_LOW);
+ gpio_set_value(GPIO81, GPIO_LOW);
+ // gpio_set_value(GPIO84, GPIO_LOW);
+ }
+}
+
+static void wmm300_hisr_callback(void)
+{
+ sensor_task_send_message(WMM300_ID,SENSOR_MSG_PROCESS_DATA);
+}
+
+static void wmm300_create_hisr(void)
+{
+ OS_Create_HISR(&wmm300_hisr_ref,"icm_hisr", wmm300_hisr_callback, HISR_PRIORITY_2);
+}
+
+
+
+/* Timer0_0 is configured to free run @1MHz from BootROM. */
+static void DelayInUs(unsigned int us)
+{
+ unsigned long startTime, endTime;
+ Timer0_Switch(1);
+ startTime = GetTimer0CNT();
+ do
+ {
+ endTime = GetTimer0CNT();
+ }
+ while(Timer0IntervalInMicro(startTime, endTime) < us);
+}
+void WMM300_test(uint32_t mode)
+{
+ s_WMM300_heart_rate = 0x0;
+ s_WMM300_heart_rate_buff_count = 0;
+ s_WMM300_high_blood = 0x0;
+ s_WMM300_low_blood = 0x0;
+ s_WMM300_HRV = 0;
+ //s_WMM300_wear_status = 0;
+ s_WMM300_blood_oxygen = 0x0;
+ WMM300_LOG("WMM300_test1:%d!!!!\n\n",mode);
+ if(mode <= close_MODE)
+ {
+ if(whale_algo_enable(mode) == WHALE_ALGO_OK)
+ {
+ is_open_WMM300 = 1;
+ WMM300_LOG("wmm300_init:ok!!!!\n\n");
+ // if(sensor_timer== 0)
+ // {
+ // sensor_timer = Helios_Timer_init( (void* )sensor_timerout_cb, NULL);
+ // }
+
+ // Helios_Timer_Start(sensor_timer, TIMER_TIME_MS, IS_CYCLICAL);
+ }else
+ WMM300_LOG("wmm300_init:error!!!!\n\n");
+ }else if(mode == 255)
+ {
+
+ }
+ WMM300_LOG("WMM300_test2:%d!!!!\n\n",mode);
+}
+static void wmm300_process_timer_callback(void)
+{
+ OS_Activate_HISR(&wmm300_hisr_ref);
+}
+extern unsigned int WMM300_millisecond;
+static void wmm300_millisecond_timer_callback(void)
+{
+ WMM300_millisecond+=50;
+ if(WMM300_millisecond > 0xffff0000)
+ WMM300_millisecond = 0;
+}
+static void wmm300_start(void)
+{
+ Timer0_Switch(1);
+ WMM300_LOG("wmm300_start:WMM300_run_mode:%d\n",WMM300_run_mode);
+ hal_wmm300_int_init();
+ WMM300_restart();
+ if(wmm300_process_timer == NULL )
+ uos_timer_create(&wmm300_process_timer);
+ //每500ms轮询一次数据
+ uos_timer_start(wmm300_process_timer, MS_TO_TICKS(500), MS_TO_TICKS(500), wmm300_process_timer_callback, NULL);
+ if(wmm300_millisecond_timer == NULL )
+ uos_timer_create(&wmm300_millisecond_timer);
+ //计时器
+ uos_timer_start(wmm300_millisecond_timer, MS_TO_TICKS(50), MS_TO_TICKS(50), wmm300_millisecond_timer_callback, NULL);
+ WMM300_millisecond = 0;
+
+
+ WMM300_test(WMM300_run_mode);
+ WMM300_jobs_mode = WMM300_run_mode;
+ WMM300_run_mode = NULL_MODE;
+
+ // hal_gh30x_int_init();
+ // wmm300_en_gpio_enable(false);
+ // DelayInUs(10*1000);
+ // wmm300_en_gpio_enable(true);
+ // DelayInUs(50*1000);
+ // int ret = gh30x_module_init();
+
+
+}
+
+static void wmm300_stop(void)
+{
+ WMM300_LOG("[%s][%d]: \n", __FUNCTION__, __LINE__);
+
+ //wmm300_en_gpio_enable(false);
+ WMM300_close();
+ //WMM300_LOG("WMM300_irq_cb: 1111111111111!!!!!!!!\r\n");
+ WMM300_run_mode = NULL_MODE;
+ WMM300_jobs_mode = NULL_MODE;
+ uos_timer_stop(wmm300_process_timer);
+ uos_timer_stop(wmm300_millisecond_timer);
+ Timer0_Switch(0);
+
+}
+void wmm300_process_data(uint32_t *process_data)
+{
+ Timer0_Switch(1);
+ acc_process();
+ unsigned char value = 0;
+ if (whale_algo_process()) {
+ if (get_activity_data(&act_data)) {
+ // 存储睡眠活动数据
+ }
+ }
+
+ if (whale_algo_get_result(WMM300_jobs_mode, &value) == WHALE_ALGO_UPDATED) {
+ //log_len = sprintf(str_buf, "value: %d\n", hr_result.rate);
+ //port_log(str_buf, log_len);
+ WMM300_LOG("WMM300_jobs_mode:%d value: %d\n",WMM300_jobs_mode,value);
+ switch (WMM300_jobs_mode)
+ {
+ case WHALE_ALGO_TYPE_HR_CONTINUS:
+ s_WMM300_heart_rate = value;
+ break;
+ case WHALE_ALGO_TYPE_SPO2:
+ s_WMM300_blood_oxygen = value;
+ break;
+ case WHALE_ALGO_TYPE_STRESS:
+ s_WMM300_low_blood = value;
+ break;
+ case WHALE_ALGO_TYPE_WEAR:
+ s_WMM300_wear_status = value;
+ break;
+ default:
+ break;
+ }
+ // s_WMM300_heart_rate = hr;
+ // s_WMM300_blood_oxygen = bo;
+ // s_WMM300_high_blood = bp_high ;
+ // s_WMM300_low_blood = bp_low ;
+ // WHALE_ALGO_TYPE_HR_CONTINUS, // 连续心率
+ // WHALE_ALGO_TYPE_SPO2, // 血氧
+ // WHALE_ALGO_TYPE_STRESS, // 压力
+ // WHALE_ALGO_TYPE_WRIST, // 转腕
+ // WHALE_ALGO_TYPE_WEAR, // 穿戴
+ // WHALE_ALGO_TYPE_PEDOMETER, // 计步
+ // WHALE_ALGO_TYPE_SLEEP, // 睡眠
+ }
+}
+void hal_wmm300_int_init(void)
+{
+ // code implement by user
+ // must register func hal_gh30x_int_handler as callback
+ Timer0_Switch(1);
+ mfp_config(wmm300_mfp_cfgs);
+ wmm300_en_gpio_init();
+ WMM300_LOG("WMM300 ID : %d\n",whale_check_chip());
+
+}
+void Wmm300_Init(void)
+{
+ Timer0_Switch(1);
+ static bool register_dev_flag = false;
+ if(!register_dev_flag)
+ {
+ register_dev_flag = true;
+ sensor_drv_t sensor_drv;
+ sensor_drv.sensor_name = "wmm300";
+ sensor_drv.sensor_start = wmm300_start;
+ sensor_drv.sensor_stop = wmm300_stop;
+ sensor_drv.sensor_process_data = wmm300_process_data;
+ sensor_drv_register(WMM300_ID,&sensor_drv);
+ }
+ wmm300_create_hisr();
+ hal_wmm300_int_init();
+ WMM300_restart();
+ memset(&plat_if, 0, sizeof(plat_if));
+
+ plat_if.sys.log = port_log; // 算法库日志输出函数(便于调试,可用空函数替换)
+ plat_if.sys.get_tick = port_get_millisecond; // 获取以毫秒为单位的系统时间戳函数
+ plat_if.sys.get_rtc_timestamp = port_get_rtc; // 获取以秒为单位的UNIX时间戳函数
+ plat_if.sys.delay_ms = port_delay_ms; // 以毫秒为单位的系统延迟函数
+ plat_if.sys.malloc = port_malloc; // malloc动态内存分配函数
+ plat_if.sys.free = port_free; // free动态内存释放函数
+ plat_if.sys.charge_state = port_charge_state; // 获取设备充电状态
+
+ plat_if.ppg_ctrl.i2c_read = port_afe_read; // 模组I2C通信读数据函数
+ plat_if.ppg_ctrl.i2c_write = port_afe_write; // 模组I2C通信写数据函数
+ plat_if.ppg_ctrl.pwr_1v8 = port_afe_pwr_lv8; // 模组1.8v电源控制函数
+ plat_if.ppg_ctrl.pwr_vled = port_afe_pwr_vled; // 模组vled电源控制函数
+
+ whale_algo_init(&plat_if);
+
+
+}
+
+
+static bool is_measuring_flag = false;
+void wmm300_measure_hr_start(void)
+{
+ sys_pm_wakeup_no_lcd();
+
+
+ WMM300_run_mode = WHALE_ALGO_TYPE_HR_CONTINUS;
+ WMM300_LOG("wmm300_measure_hr_start :WMM300_run_mode:%d!!!!!!!!\n",WMM300_run_mode);
+ sensor_task_send_message(WMM300_ID,SENSOR_MSG_START);
+}
+
+void wmm300_measure_bo_start(void)
+{
+ sys_pm_wakeup_no_lcd();
+
+
+ WMM300_run_mode = WHALE_ALGO_TYPE_SPO2 ;
+ WMM300_LOG("wmm300_measure_bo_start :WMM300_run_mode:%d!!!!!!!!\n",WMM300_run_mode);
+ sensor_task_send_message(WMM300_ID,SENSOR_MSG_START);
+}
+void WMM300_restart(void)
+{
+ wmm300_en_gpio_enable(false);
+ port_delay_ms(50);
+ wmm300_en_gpio_enable(true);
+ port_delay_ms(50);
+}
+void wmm300_measure_stop(void)
+{
+ WMM300_LOG("wmm300_measure_stop !!!!!!!!\n");
+ WMM300_run_mode = close_MODE;
+ sensor_task_send_message(WMM300_ID,SENSOR_MSG_STOP);
+}
+void WMM300_close(void)
+{
+ WMM300_LOG("WMM300_close !!!!!!!!\n");
+ watch_set_sleep_lcd_only(false);
+ is_measuring_flag = false;
+ //asl_hr_bp_bo_measure_finish_flag_set();
+ //wmm300_hrs_disable
+
+ whale_algo_disable(WMM300_jobs_mode);
+
+ WMM300_restart();
+
+}
+
+static void wmm300_hr_bp_bo_value_update(uint16_t hr, uint16_t bp_high, uint16_t bp_low, uint16_t bo)
+{
+ WMM300_LOG("[@CHENG_DEBUG][%s][%d]: %d,%d,%d,%d\n", __FUNCTION__, __LINE__, hr, bp_high, bp_low, bo);
+ s_WMM300_heart_rate = hr;
+ s_WMM300_blood_oxygen = bo;
+ s_WMM300_high_blood = bp_high ;
+ s_WMM300_low_blood = bp_low ;
+
+
+}
+unsigned char wmm300_result_get_wear_status(void)
+{
+
+ return s_WMM300_wear_status ;
+}
+uint16_t get_wmm300_hr_value(void)
+{
+ return s_WMM300_heart_rate;
+}
+
+uint16_t get_wmm300_b0_value(void)
+{
+ return s_WMM300_blood_oxygen;
+}
+
+void wmm300_hr_bp_bo_value_get(uint16_t *hr, uint16_t *bp_high, uint16_t *bp_low, uint16_t *bo)
+{
+ if(hr != NULL)
+ *hr = s_WMM300_heart_rate;
+ if(bp_high != NULL)
+ *bp_high = s_WMM300_high_blood;
+ if(bp_low != NULL)
+ *bp_low = s_WMM300_low_blood;
+ if(bo != NULL)
+ *bo = s_WMM300_blood_oxygen;
+}
+
+void wmm300_hr_bp_bo_value_clear(void)
+{
+ s_WMM300_heart_rate = 0x0;
+ s_WMM300_heart_rate_buff_count = 0;
+ s_WMM300_high_blood = 0x0;
+ s_WMM300_low_blood = 0x0;
+ s_WMM300_HRV = 0;
+ //s_WMM300_wear_status = 0;
+ s_WMM300_blood_oxygen = 0x0;
+ //memset(&wmm300_hr_bp_bo_value, 0, sizeof(wmm300_hr_bp_bo_value));
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/********************************************************************/
+/********************************************************************/
+
+
+
+
+
+static void acc_process(void)
+{
+
+
+ sensor_data_acc_t *acc_data = port_malloc(25 * sizeof(sensor_data_acc_t));
+
+ if (acc_data) {
+ for (uint16_t i=0; i<25; i++) {
+ acc_data[i].x = -3785;
+ acc_data[i].y = -1492;
+ acc_data[i].z = 901;
+ }
+
+ whale_algo_push_data(WHALE_DATA_TYPE_ACC, acc_data, 1);
+
+ port_free(acc_data);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+#endif
\ No newline at end of file
--- /dev/null
+
+#include "lv_drv_conf_CUSTOM.h"
+#if USE_WMM300
+#include "whale_algo.h"
+
+#include "../../../lvgl/hal/hal.h"
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "../../board.h"
+#include "../../common/i2c.h"
+#include "../../../../product/craneg_modem/framework/inc/gpio_api.h"
+#include "lvgl/hal/hal.h"
+#include "../../../lv_watch/app_adaptor/app_sensor_task.h"
+unsigned int WMM300_millisecond = 0;
+// 获取以毫秒为单位的系统时间戳函数
+uint32_t port_get_millisecond(void)
+{
+ return WMM300_millisecond; // 系统心跳频率为1000hz
+}
+
+// 获取以秒为单位的UNIX时间戳函数
+uint32_t port_get_rtc(void)
+{
+ unsigned int time= 0;
+ Hal_Rtc_Gettime_Count(&time);
+ return time;
+}
+
+// 以毫秒为单位的系统延迟函数
+extern void UOS_SleepMs (uint32_t ms);
+void port_delay_ms(uint32_t ms)
+{
+ UOS_SleepMs(1);
+}
+
+// malloc动态内存分配函数
+void *port_malloc(uint32_t size)
+{
+ if (size)
+ return malloc(size);
+ else
+ return NULL;
+}
+
+// free动态内存释放函数
+void port_free(void *ptr)
+{
+ free(ptr);
+}
+
+// 算法库日志输出函数(便于调试)
+void port_log(const char *log, uint32_t len)
+{
+#if WMM300_DEBUG
+ WMM300_LOG( "WMM300:%s",log);
+#endif
+ //HAL_UART_Transmit(&huart3, (uint8_t *)log, len, 1000); // 串口输出log
+}
+
+bool port_charge_state(void)
+{
+
+
+ // 返回设备充电状态:true - 在充电;false - 未在充电;
+ if(HAL_CHG_DISCONNECTED / HAL_CHG_CONNECTED == Hal_Charger_Get_Status())
+ return true;
+ else
+ return false;
+}
+
+#define AFE_ADDR (0x3A >>1)
+
+// 模组I2C通信读数据函数:先写寄存器 data[0],再读取 len 长度的数据到 &data[0];
+int port_afe_read(unsigned char *data, uint32_t len)
+{
+ // HAL_I2C_Master_Transmit(&hi2c3, AFE_ADDR, data[0], 1, 100);
+ // HAL_I2C_Master_Receive(&hi2c3, AFE_ADDR, data, len, 100);
+ // if(-1 == i2c_read_regs(I2C_MASTER_CI2C1, AFE_ADDR, (uint16_t)data[0],(void *)data,len,0))
+ // {
+ // cplog_printf("read-------->>>i2c receive failed! AFE_ADDR:%d\r\n",AFE_ADDR);
+ // return -1;
+ // }
+ if(-1 == i2c_write_bytes(I2C_MASTER_CI2C1, AFE_ADDR, (void *)data, (size_t)(1),0))
+ {
+ cplog_printf("read-------->>>i2c transmit failed! \r\n");
+ return -1;
+ }
+
+ if(-1 == i2c_read_bytes(I2C_MASTER_CI2C1, AFE_ADDR, (void *)data, (size_t)len,0))
+ {
+ cplog_printf("read-------->>>i2c receive failed! \r\n");
+ return -1;
+ }
+ return 0;
+}
+
+// 模组I2C通信写数据函数
+int port_afe_write(unsigned char *data, uint32_t len)
+{
+ //return HAL_I2C_Master_Transmit(&hi2c3, AFE_ADDR, data, len, 100) == HAL_OK;
+ if(-1 == i2c_write_regs(I2C_MASTER_CI2C1, AFE_ADDR, (uint16_t)data[0], (void *)&data,len,0))
+ {
+ cplog_printf("write-------->>>i2c transmit failed! \r\n");
+ return -1;
+ }
+ return 0;
+}
+
+// 模组1.8v电源控制函数
+void port_afe_pwr_lv8(bool en)
+{
+ //
+}
+
+// 模组vled电源控制函数
+void port_afe_pwr_vled(bool en)
+{
+ //
+}
+#endif
\ No newline at end of file
--- /dev/null
+
+#ifndef _WHALE_ALGO_H
+#define _WHALE_ALGO_H
+
+#include <stdint.h>
+#include <stdbool.h>
+#define WMM300_DEBUG 1
+#if WMM300_DEBUG
+#define WMM300_LOG(msg, ...) cplog_printf( msg, ##__VA_ARGS__)//printf( msg, ##__VA_ARGS__)//
+//#define WMM300_LOG(msg, ...) printf( msg, ##__VA_ARGS__)//printf( msg, ##__VA_ARGS__)//
+#else
+#define WMM300_LOG(msg, ...)
+
+#endif
+typedef struct {
+ void (*log)(const char *log, uint32_t len); // log输出
+ void* (*malloc)(uint32_t size); // 动态分配内存
+ void (*free)(void *ptr); // 释放内存
+ uint32_t (*get_tick)(void); // 获取ms级时间戳
+ uint32_t (*get_rtc_timestamp)(void); // 获取秒级时间戳
+ void (*delay_ms)(uint32_t ms); // ms级延时
+ bool (*charge_state)(void); // 获取设备充电状态(返回值:true - 在充电;false - 未在充电;)
+} whale_algo_system_t;
+
+typedef struct {
+ int (*i2c_read)(uint8_t *data, uint32_t len); // I2C读取接口
+ int (*i2c_write)(uint8_t *data, uint32_t len); // I2C写入接口
+ void (*pwr_1v8)(bool en); // ppg模组1.8v电源开关
+ void (*pwr_vled)(bool en); // ppg模组led电源开关
+} whale_algo_ppg_control_t;
+
+typedef struct
+{
+ whale_algo_system_t sys;
+ whale_algo_ppg_control_t ppg_ctrl;
+} whale_algo_plat_if_t;
+
+typedef enum {
+ WHALE_DATA_TYPE_ACC,
+} WHALE_DATA_TYPE_T;
+
+typedef struct {
+ int16_t x;
+ int16_t y;
+ int16_t z;
+} sensor_data_acc_t;
+
+typedef enum {
+ WHALE_ALGO_TYPE_HR_CONTINUS, // 连续心率
+ WHALE_ALGO_TYPE_SPO2, // 血氧
+ WHALE_ALGO_TYPE_STRESS, // 压力
+ WHALE_ALGO_TYPE_WRIST, // 转腕
+ WHALE_ALGO_TYPE_WEAR, // 穿戴
+ WHALE_ALGO_TYPE_PEDOMETER, // 计步
+ WHALE_ALGO_TYPE_SLEEP, // 睡眠
+ NULL_MODE,//空闲模式
+ close_MODE//关闭模式
+} WHALE_ALGO_TYPE_T;
+
+typedef enum {
+ WHALE_ALGO_OK = 0,
+ WHALE_ALGO_ERROR,
+
+ WHALE_ALGO_UPDATED = WHALE_ALGO_OK,
+ WHALE_ALGO_NOT_READY,
+} WHALE_ALGO_ERROR_T;
+
+// 手势检测定义
+typedef enum {
+ WRIST_DO_NOTHING = 0, // 未做手势
+ WRIST_UP_TRUE = 0x01, // 抬腕
+ WRIST_DOWN_TRUE = 0x02, // 落腕
+ WRIST_FLIP_TRUE = 0x04, // 转腕
+} WRIST_RESULT_T;
+
+// 性别定义
+#define MALE (1) // 男性
+#define FEMALE (0) // 女性
+
+// 睡眠模式定义
+typedef enum {
+ SLEEP_MODE_LIGHT = 4, // 浅睡
+ SLEEP_MODE_DEEP = 5, // 深睡
+ SLEEP_MODE_WAKE_UP = 7, // 清醒
+ SLEEP_MODE_REM = 8, // REM阶段
+} SLEEP_MODE_T;
+
+// 心率结果
+typedef struct {
+ uint8_t rate;
+} whale_algo_result_hr_t;
+
+// 血氧结果
+typedef struct {
+ uint8_t value;
+} whale_algo_result_spo2_t;
+
+// 压力结果
+typedef struct {
+ uint8_t value;
+} whale_algo_result_stress_t;
+
+// 手势检测
+typedef struct {
+ WRIST_RESULT_T state;
+} whale_algo_result_wrist_t;
+
+// 佩戴检测
+typedef struct {
+ bool is_wear;
+} whale_algo_result_wear_t;
+
+// 计步结果
+typedef struct {
+ uint32_t steps;
+} whale_algo_result_ped_t;
+
+// 用户信息,睡眠计算用
+typedef struct {
+ uint8_t gender; /* User gender, male:1, female:0 */
+ uint8_t height; /* User height, unit cm */
+ uint8_t weight; /* User weight, unit kg */
+ uint8_t age; /* User age */
+} person_info_t;
+
+// 活动数据,睡眠计算用
+typedef struct {
+ uint8_t data[8];
+} activity_data_t;
+
+// 睡眠阶段数据
+typedef struct {
+ int16_t start;
+ int16_t stop;
+ int16_t mode;
+} sleep_stage_t;
+
+// 睡眠结果数据
+typedef struct {
+ bool has_sleep; // 是否睡觉
+ int16_t sleep_start; // 起始睡眠时间
+ int16_t sleep_end; // 结束睡眠时间
+ int16_t deep_sleep_len; // 深睡时长(分钟)
+ int16_t light_sleep_len; // 浅睡时长(分钟)
+ int16_t wake_up_len; // 清醒时长(分钟)
+ int16_t rem_sleep_len; // REM(快速动眼)时长(分钟)
+ int16_t sleep_stage_count; // 睡眠分期个数
+ sleep_stage_t *stage_sleep; // 睡眠分期
+} whale_algo_result_sleep_t;
+
+void whale_algo_init(whale_algo_plat_if_t *_plat_if);
+// 500ms 轮询执行
+bool whale_algo_process(void);
+void whale_algo_push_data(WHALE_DATA_TYPE_T type, void *data, uint16_t sample_count);
+
+void get_sleep_result(person_info_t *info, activity_data_t *data, uint32_t length, whale_algo_result_sleep_t *result); // 离线计算
+bool get_activity_data(activity_data_t *data);
+
+WHALE_ALGO_ERROR_T whale_algo_enable(WHALE_ALGO_TYPE_T algo_type);
+void whale_algo_disable(WHALE_ALGO_TYPE_T algo_type);
+WHALE_ALGO_ERROR_T whale_algo_get_result(WHALE_ALGO_TYPE_T algo_type, void *result);
+char *whale_algo_get_fw_ver(void);
+
+// 计步清零
+void whale_steps_clear(void);
+
+// 读取佩戴检测原始数据
+void whale_read_wear(uint16_t *amb, uint16_t *ir);
+// 读取心率原始数据,采样率为25hz; 返回值:实际读取数据个数;
+uint8_t whale_read_ppg(uint16_t *ppg_data);
+// 读取血氧原始数据,采样率为50hz; 返回值:实际读取数据个数;
+uint8_t whale_read_spo2(int32_t *red_data, int32_t *ir_data, int32_t *green_data);
+
+/* 该接口仅用于测试硬件
+* index: 1 - TX1(绿灯); 2 - TX2(红外灯); 4 - TX4(红灯); 0 - 熄灭所有灯;
+* 返回:true - 成功; false - 失败;
+* 说明:1. 返回false,请检查通信总线;2. 返回true,灯不亮,请检查led接线;
+*/
+bool whale_test_ppg_led(uint8_t index);
+
+/* 读取模组Chip ID,并验证是否正确;
+* 返回:true - ID正确; false - ID错误;
+* 说明:返回false,请检查电源供电和通信总线,可通过逻辑分析仪抓取信号进行排查;
+* 模组I2C的7位地址是0x3A,chip ID的寄存器地址为0xF8,读出来的值为0x0008。
+*/
+bool whale_check_chip(void);
+
+uint32_t port_get_millisecond(void);
+uint32_t port_get_rtc(void);
+void port_delay_ms(uint32_t ms);
+void *port_malloc(uint32_t size);
+void port_free(void *ptr);
+void port_log(const char *log, uint32_t len);
+bool port_charge_state(void);
+int port_afe_read(uint8_t *data, uint32_t len);
+int port_afe_write(uint8_t *data, uint32_t len);
+void port_afe_pwr_lv8(bool en);
+void port_afe_pwr_vled(bool en);
+
+void Wmm300_Init(void);
+void wmm300_measure_hr_start(void);
+void wmm300_measure_bo_start(void);
+void WMM300_restart(void);
+void wmm300_measure_stop(void);
+void WMM300_close(void);
+static void wmm300_hr_bp_bo_value_update(uint16_t hr, uint16_t bp_high, uint16_t bp_low, uint16_t bo);
+uint16_t get_wmm300_hr_value(void);
+uint16_t get_wmm300_b0_value(void);
+void wmm300_hr_bp_bo_value_get(uint16_t *hr, uint16_t *bp_high, uint16_t *bp_low, uint16_t *bo);
+
+void wmm300_hr_bp_bo_value_clear(void);
+unsigned char wmm300_result_get_wear_status(void);
+#endif /* _WHALE_ALGO_H */