mirror of
https://github.com/ltian059/Graduation-Project.git
synced 2025-02-05 11:28:06 +00:00
432 lines
12 KiB
C
432 lines
12 KiB
C
/*******************************************************************************
|
|
* Copyright (C) 2018 Maxim Integrated Products, Inc., All rights Reserved.
|
|
*
|
|
* This software is protected by copyright laws of the United States and
|
|
* of foreign countries. This material may also be protected by patent laws
|
|
* and technology transfer regulations of the United States and of foreign
|
|
* countries. This software is furnished under a license agreement and/or a
|
|
* nondisclosure agreement and may only be used or reproduced in accordance
|
|
* with the terms of those agreements. Dissemination of this information to
|
|
* any party or parties not specified in the license agreement and/or
|
|
* nondisclosure agreement is expressly prohibited.
|
|
*
|
|
* The above copyright notice and this permission notice shall be included
|
|
* in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
* IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
|
|
* OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*
|
|
* Except as contained in this notice, the name of Maxim Integrated
|
|
* Products, Inc. shall not be used except as stated in the Maxim Integrated
|
|
* Products, Inc. Branding Policy.
|
|
*
|
|
* The mere transfer of this software does not imply any licenses
|
|
* of trade secrets, proprietary technology, copyrights, patents,
|
|
* trademarks, maskwork rights, or any other form of intellectual
|
|
* property whatsoever. Maxim Integrated Products, Inc. retains all
|
|
* ownership rights.
|
|
*******************************************************************************
|
|
*/
|
|
|
|
|
|
#include "sensorhub_api.h"
|
|
|
|
|
|
#include <string.h>
|
|
|
|
#include "sh_comm.h"
|
|
#include "defs.h"
|
|
|
|
/* Maxim Integrated Low Power SDK */
|
|
#include "mxc_errors.h"
|
|
|
|
#define SS_PACKET_COUNTERSIZE 1
|
|
|
|
/* 3 Slots Measurement 2 PD */
|
|
#define SSMAX86176_MODE1_DATASIZE 18
|
|
|
|
/* 3 Axis */
|
|
#define SSACCEL_MODE1_DATASIZE 6
|
|
|
|
/* Sensorhub reporting mode 1 */
|
|
#define SSWHRM_WSPO2_SUITE_MODE1_DATASIZE 20
|
|
|
|
/* Sensorhub reporting mode 2 */
|
|
#define SSWHRM_WSPO2_SUITE_MODE2_DATASIZE 58
|
|
|
|
#define MAX_NUMBER_OF_TRANSACTION_IN_BYTE (255)
|
|
|
|
typedef void (*parser) (void * , uint8_t *);
|
|
|
|
typedef enum{
|
|
TIMESTAMP_DATA = 0,
|
|
MAX86176_MODE1_DATA,
|
|
WHRM_SPO2_SUITE_MODE1,
|
|
WHRM_SPO2_SUTITE_MODE2,
|
|
ACCEL_MODE1_DATA
|
|
} data_format_t;
|
|
|
|
typedef union {
|
|
struct {
|
|
uint8_t max86176_enabled:1;
|
|
uint8_t accel_enabled :1;
|
|
uint8_t whrm_wspo2_suite_enabled_mode1 :1;
|
|
uint8_t whrm_wspo2_suite_enabled_mode2 :1;
|
|
uint8_t timestamp_enabled:1;
|
|
|
|
uint8_t reserved:3;
|
|
};
|
|
uint8_t status_vals;
|
|
} algo_sensor_status_t;
|
|
|
|
typedef struct{
|
|
data_format_t data_type;
|
|
int data_size;
|
|
parser fp_parse;
|
|
} ss_instance_parser_t;
|
|
|
|
/* Data parser functions */
|
|
static void data_time_stamper(void * p_time_stamp, uint8_t* data_ptr);
|
|
static void accel_data_rx(void * p_accel_data, uint8_t* data_ptr);
|
|
static void max86176_data_rx(void * p_ppg_data, uint8_t* data_ptr);
|
|
static void whrm_wspo2_suite_data_rx_mode1(void * p_algo_data_mode1, uint8_t* data_ptr);
|
|
static void whrm_wspo2_suite_data_rx_mode2(void * p_algo_data_mode2, uint8_t* data_ptr);
|
|
|
|
static algo_sensor_status_t g_algo_sensor_stat;
|
|
|
|
static ss_instance_parser_t parsers[SH_NUM_CURRENT_ALGOS] =
|
|
{
|
|
{TIMESTAMP_DATA, 0, data_time_stamper },
|
|
{MAX86176_MODE1_DATA, SSMAX86176_MODE1_DATASIZE, max86176_data_rx },
|
|
{WHRM_SPO2_SUITE_MODE1, SSWHRM_WSPO2_SUITE_MODE1_DATASIZE, whrm_wspo2_suite_data_rx_mode1 },
|
|
{WHRM_SPO2_SUTITE_MODE2, SSWHRM_WSPO2_SUITE_MODE2_DATASIZE, whrm_wspo2_suite_data_rx_mode2 },
|
|
{ACCEL_MODE1_DATA, SSACCEL_MODE1_DATASIZE, accel_data_rx},
|
|
};
|
|
|
|
int sensorhub_interface_init()
|
|
{
|
|
int ret = 0;
|
|
|
|
sh_init_hwcomm_interface();
|
|
|
|
mxc_delay(MXC_DELAY_SEC(1));
|
|
|
|
ret = sh_set_data_type(SS_DATATYPE_BOTH, true);
|
|
|
|
if(0 == ret){
|
|
ret = sh_set_fifo_thresh(1);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_enable_sensors()
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = sh_sensor_enable_(SH_SENSORIDX_ACCEL, 1, SH_INPUT_DATA_DIRECT_SENSOR);
|
|
g_algo_sensor_stat.accel_enabled = 1;
|
|
pr_info("SENSOR_ENABLED_ACCEL Ret %d \n", ret);
|
|
|
|
if(0 == ret){
|
|
/* Enabling OS6X with host supplies data */
|
|
ret = sh_sensor_enable_(SH_SENSORIDX_MAX86176, 1, SH_INPUT_DATA_DIRECT_SENSOR);
|
|
g_algo_sensor_stat.max86176_enabled =1;
|
|
pr_info("SENSOR_ENABLED_OS64 Ret %d \n", ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_disable_sensor()
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = sh_sensor_disable(SH_SENSORIDX_ACCEL);
|
|
g_algo_sensor_stat.accel_enabled = 0;
|
|
pr_info("SENSOR_DISABLED_ACCEL Ret %d \n", ret);
|
|
|
|
if(0 == ret){
|
|
/* Enabling OS6X with host supplies data */
|
|
ret = sh_sensor_disable(SH_SENSORIDX_MAX86176);
|
|
g_algo_sensor_stat.max86176_enabled = 0;
|
|
pr_info("SENSOR_DISABLED_OS64 Ret %d \n", ret);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_enable_algo(sensorhub_report_mode_t mode)
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = sh_enable_algo_(SS_ALGOIDX_WHRM_WSPO2_SUITE_OS6X , (int) mode);
|
|
|
|
if(SENSORHUB_MODE_BASIC == mode){
|
|
g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode1 = 1;
|
|
}
|
|
else{
|
|
g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode2 = 1;
|
|
}
|
|
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_disable_algo()
|
|
{
|
|
int ret = 0;
|
|
|
|
ret = sh_disable_algo(SS_ALGOIDX_WHRM_WSPO2_SUITE_OS6X);
|
|
|
|
g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode1 = 0;
|
|
g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode2 = 0;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_get_output_sample_number(int * p_number_of_sample)
|
|
{
|
|
int ret = 0;
|
|
|
|
if(NULL == p_number_of_sample)
|
|
{
|
|
ret = E_BAD_PARAM;
|
|
}
|
|
|
|
if(E_NO_ERROR == ret)
|
|
{
|
|
ret = sh_num_avail_samples(p_number_of_sample);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_get_result(sensorhub_output * p_result)
|
|
{
|
|
int ret = 0;
|
|
int num_bytes_to_read = 0;
|
|
uint8_t hubStatus = 0;
|
|
uint8_t databuf[150];
|
|
uint8_t *ptr;
|
|
|
|
if(NULL == p_result)
|
|
{
|
|
ret = E_BAD_PARAM;
|
|
}
|
|
|
|
if(E_NO_ERROR == ret)
|
|
{
|
|
ret = sh_get_sensorhub_status(&hubStatus);
|
|
pr_info("sh_get_sensorhub_status ret %d \n", ret);
|
|
}
|
|
|
|
if(hubStatus & SS_MASK_STATUS_DATA_RDY){
|
|
pr_info("SS_MASK_STATUS_DATA_RDY\n");
|
|
}
|
|
else{
|
|
ret = E_NONE_AVAIL;
|
|
}
|
|
|
|
if(hubStatus & SS_MASK_STATUS_FIFO_OUT_OVR){
|
|
pr_info("SS_MASK_STATUS_FIFO_OUT_OVR\n");
|
|
}
|
|
|
|
if(0 == ret){
|
|
|
|
memset(p_result, 0, sizeof(sensorhub_output));
|
|
memset(databuf, 0, sizeof(databuf));
|
|
|
|
num_bytes_to_read += SS_PACKET_COUNTERSIZE;
|
|
|
|
if(g_algo_sensor_stat.max86176_enabled)
|
|
num_bytes_to_read += SSMAX86176_MODE1_DATASIZE;
|
|
|
|
if(g_algo_sensor_stat.accel_enabled)
|
|
num_bytes_to_read += SSACCEL_MODE1_DATASIZE;
|
|
|
|
if(g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode1)
|
|
num_bytes_to_read += SSWHRM_WSPO2_SUITE_MODE1_DATASIZE;
|
|
|
|
if(g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode2)
|
|
num_bytes_to_read += SSWHRM_WSPO2_SUITE_MODE2_DATASIZE;
|
|
|
|
ptr = &databuf[2];
|
|
|
|
WAIT_MS(5);
|
|
|
|
ret = sh_read_fifo_data(1, num_bytes_to_read, databuf, sizeof(databuf));
|
|
|
|
if(g_algo_sensor_stat.accel_enabled){
|
|
parsers[ACCEL_MODE1_DATA].fp_parse(&p_result->acc_data, ptr);
|
|
ptr += parsers[ACCEL_MODE1_DATA].data_size;
|
|
}
|
|
|
|
if(g_algo_sensor_stat.max86176_enabled){
|
|
parsers[MAX86176_MODE1_DATA].fp_parse(&p_result->ppg_data, ptr);
|
|
ptr += parsers[MAX86176_MODE1_DATA].data_size;
|
|
}
|
|
|
|
if(g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode1){
|
|
parsers[WHRM_SPO2_SUITE_MODE1].fp_parse(&p_result->algo_data, ptr);
|
|
ptr += parsers[WHRM_SPO2_SUITE_MODE1].data_size;
|
|
}
|
|
|
|
if(g_algo_sensor_stat.whrm_wspo2_suite_enabled_mode2){
|
|
parsers[WHRM_SPO2_SUTITE_MODE2].fp_parse(&p_result->algo_data, ptr);
|
|
ptr += parsers[WHRM_SPO2_SUTITE_MODE2].data_size;
|
|
}
|
|
}
|
|
else{
|
|
ret = E_NONE_AVAIL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_get_version(uint8_t algoVersion[3])
|
|
{
|
|
int ret = 0;
|
|
ret = sh_get_algo_version(algoVersion);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int sensorhub_reset_sensor_configuration()
|
|
{
|
|
int ret = 0;
|
|
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x10, 0x01, 1);
|
|
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x10, (0x01 << 1), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x15, (0x1E), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x18, (0x80), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x19, (0x9F), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x1A, (0x3F), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x1C, (0x1 << 5), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x1D, (0x05), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x1E, (0x1F), 1);
|
|
ret |= sh_set_reg(SH_SENSORIDX_MAX86176, 0x86, (0x01 << 6), 1);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
static void data_time_stamper(void * p_time_stamp, uint8_t* data_ptr)
|
|
{
|
|
|
|
}
|
|
|
|
static void accel_data_rx(void * p_accel_data, uint8_t* data_ptr)
|
|
{
|
|
accel_data * sample = (accel_data *)p_accel_data;
|
|
|
|
sample->x = (data_ptr[0] << 8) | data_ptr[1];
|
|
sample->y = (data_ptr[2] << 8) | data_ptr[3];
|
|
sample->z = (data_ptr[4] << 8) | data_ptr[5];
|
|
}
|
|
|
|
static void max86176_data_rx(void * p_ppg_data, uint8_t* data_ptr)
|
|
{
|
|
max86176_data * sample = (max86176_data *)p_ppg_data;
|
|
|
|
sample->led1 = (data_ptr[0] << 16) | (data_ptr[1] << 8) | data_ptr[2]; // LED1, PD1
|
|
sample->led2 = (data_ptr[3] << 16) | (data_ptr[4] << 8) | data_ptr[5];
|
|
sample->led3 = (data_ptr[6] << 16) | (data_ptr[7] << 8) | data_ptr[8]; // LED3, PD1
|
|
sample->led4 = (data_ptr[9] << 16) | (data_ptr[10] << 8) | data_ptr[11]; // LED1, PD2
|
|
sample->led5 = (data_ptr[12] << 16) | (data_ptr[13] << 8) | data_ptr[14];
|
|
sample->led6 = (data_ptr[15] << 16) | (data_ptr[16] << 8) | data_ptr[17]; // LED3, PD2
|
|
}
|
|
|
|
static void whrm_wspo2_suite_data_rx_mode1(void * p_algo_data_mode1, uint8_t* data_ptr)
|
|
{
|
|
whrm_wspo2_suite_sensorhub_data *sample = (whrm_wspo2_suite_sensorhub_data *) p_algo_data_mode1;
|
|
|
|
sample->current_operating_mode = data_ptr[0];
|
|
|
|
/* WHRM Data */
|
|
sample->hr = (data_ptr[1] << 8) | data_ptr[2];
|
|
sample->hr_conf = data_ptr[3];
|
|
sample->rr = (data_ptr[4] << 8) | data_ptr[5];
|
|
sample->rr_conf = data_ptr[6];
|
|
sample->activity_class = data_ptr[7];
|
|
|
|
/* WSPO2 Data */
|
|
sample->r = (data_ptr[8] << 8) | data_ptr[9];
|
|
sample->spo2_conf = data_ptr[10];
|
|
sample->spo2 = (data_ptr[11] << 8) | data_ptr[12]; // already x10;
|
|
sample->percentComplete = data_ptr[13];
|
|
sample->lowSignalQualityFlag = data_ptr[14];
|
|
sample->motionFlag = data_ptr[15];
|
|
sample->lowPiFlag = data_ptr[16];
|
|
sample->unreliableRFlag = data_ptr[17];
|
|
sample->spo2State = data_ptr[18];
|
|
sample->scd_contact_state = data_ptr[19];
|
|
|
|
}
|
|
|
|
static void whrm_wspo2_suite_data_rx_mode2(void * p_algo_data_mode2, uint8_t* data_ptr)
|
|
{
|
|
whrm_wspo2_suite_sensorhub_data *sample = (whrm_wspo2_suite_sensorhub_data *) p_algo_data_mode2;
|
|
|
|
sample->current_operating_mode = data_ptr[0];
|
|
|
|
/* WHRM Data */
|
|
sample->hr = (data_ptr[1] << 8) | data_ptr[2];
|
|
sample->hr_conf = data_ptr[3];
|
|
sample->rr = (data_ptr[4] << 8) | data_ptr[5];
|
|
sample->rr_conf = data_ptr[6];
|
|
sample->activity_class = data_ptr[7];
|
|
|
|
/* WSPO2 Data */
|
|
sample->r = (data_ptr[8] << 8) | data_ptr[9];
|
|
sample->spo2_conf = data_ptr[10];
|
|
sample->spo2 = (data_ptr[11] << 8) | data_ptr[12]; // already x10;
|
|
sample->percentComplete = data_ptr[13];
|
|
sample->lowSignalQualityFlag = data_ptr[14];
|
|
sample->motionFlag = data_ptr[15];
|
|
sample->lowPiFlag = data_ptr[16];
|
|
sample->unreliableRFlag = data_ptr[17];
|
|
sample->spo2State = data_ptr[18];
|
|
sample->scd_contact_state = data_ptr[19];
|
|
|
|
/* Extended report */
|
|
sample->walk_steps = (data_ptr[20] << 24) | (data_ptr[21] << 16) | (data_ptr[22] << 8) | data_ptr[23];
|
|
sample->run_steps = (data_ptr[24] << 24) | (data_ptr[25] << 16) | (data_ptr[26] << 8) | data_ptr[27];
|
|
sample->kcal = (data_ptr[28] << 24) | (data_ptr[29] << 16) | (data_ptr[30] << 8) | data_ptr[31];
|
|
sample->totalActEnergy = (data_ptr[32] << 24) | (data_ptr[33] << 16) | (data_ptr[34] << 8) | data_ptr[35];
|
|
|
|
int ind = SH_PPG_SIGNAL_GREEN0;
|
|
int idx = 35;
|
|
for(ind = SH_PPG_SIGNAL_GREEN0; ind < SH_PPG_SIGNAL_MAX; ++ind)
|
|
{
|
|
uint16_t curr = (data_ptr[idx+1] << 8) | data_ptr[idx+2];
|
|
uint8_t int_time = data_ptr[idx+3];
|
|
uint8_t avg = data_ptr[idx+4];
|
|
uint8_t dac_off = data_ptr[idx+5];
|
|
|
|
sample->afe_requests[ind].led_curr.is_led_curr_update_requested = (curr >> 15);
|
|
sample->afe_requests[ind].led_curr.requested_led_curr = (curr & 0x7FFF);
|
|
|
|
sample->afe_requests[ind].int_time.is_int_time_update_requested = (int_time >> 7);
|
|
sample->afe_requests[ind].int_time.requested_int_time = (int_time & 0x7F);
|
|
|
|
sample->afe_requests[ind].sample_averaging.is_averaging_update_requested = (avg >> 7);
|
|
sample->afe_requests[ind].sample_averaging.requested_avg = (avg & 0x7F);
|
|
|
|
sample->afe_requests[ind].dac_offset.is_dac_offset_update_requested = (dac_off >> 7);
|
|
sample->afe_requests[ind].dac_offset.dac_offset = (dac_off & 0x7F);
|
|
|
|
idx += 5;
|
|
}
|
|
|
|
|
|
sample->hrm_afe_state = data_ptr[56];
|
|
sample->is_high_motion = data_ptr[57];
|
|
}
|