HSP Platform firmware evaluating ECG data and hearth rate over PPG data.
Dependencies: max32630fthr Adafruit_FeatherOLED USBDevice
Diff: Interfaces/SensorComm/SmartSensorComm/SSMAX8614X/SSMAX8614XComm.cpp
- Revision:
- 1:f60eafbf009a
diff -r 07d28b5db986 -r f60eafbf009a Interfaces/SensorComm/SmartSensorComm/SSMAX8614X/SSMAX8614XComm.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/Interfaces/SensorComm/SmartSensorComm/SSMAX8614X/SSMAX8614XComm.cpp Wed Apr 10 14:56:25 2019 +0300
@@ -0,0 +1,1428 @@
+/*******************************************************************************
+ * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * 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 "DSInterface.h"
+#include "SSMAX8614XComm.h"
+
+#include "../../../../Utilities/mxm_assert.h"
+#include "flc.h"
+#include "flc_regs.h"
+#include "Peripherals.h"
+#include "utils.h"
+#include "CRC8.h"
+
+
+#include "BLE_ICARUS.h"
+
+
+
+
+// By default, host accel is enabled
+
+//#define FORCE_RESET_WHEN_FAILED
+
+#define MAX_NUM_WR_ACC_SAMPLES 5
+#define BMI160_SAMPLE_RATE 25
+
+static const char* const cmd_tbl[] = {
+ "get_format ppg 0",
+ "read ppg 0", // moved here to match parser index "3"
+ "get_reg ppg",
+ "set_reg ppg",
+ "dump_reg ppg",
+ "set_cfg ppg agc 0",
+ "set_cfg ppg agc 1",
+ "self_test ppg os58",
+ "self_test ppg acc",
+ "set_cfg whrmaecscd aecenable",
+ "get_cfg whrmaecscd aecenable",
+ "set_cfg whrmaecscd scdenable",
+ "get_cfg whrmaecscd scdenable",
+ "set_cfg whrmaecscd adjpdperiod",
+ "get_cfg whrmaecscd adjpdperiod",
+ "set_cfg whrmaecscd debouncewin",
+ "get_cfg whrmaecscd debouncewin",
+ "set_cfg whrmaecscd motionthreshold",
+ "get_cfg whrmaecscd motionthreshold",
+ "set_cfg whrmaecscd minpdcurrent",
+ "get_cfg whrmaecscd minpdcurrent",
+ "set_cfg whrmaecscd pdconfig",
+ "get_cfg whrmaecscd pdconfig",
+ "set_cfg whrmaecscd ledconfig",
+ "get_cfg whrmaecscd ledconfig",
+ "send_raw", // write raw data to I2C (Slave address will be perpended)
+ "set_cfg accel_sh 0", // disables sensorhub accel, host accel is used
+ "set_cfg accel_sh 1", // enables sensorhub accel, host accel is not used
+ "set_cfg whrm conf_level", //sets the conf level coming from the GUI inside the internal flash
+ "set_cfg whrm hr_expiration", ////sets the expiration dfuration coming from the GUI inside the internal flash
+
+};
+
+SSMAX8614XComm::SSMAX8614XComm(USBSerial *USB, SSInterface* ssInterface, DSInterface* dsInterface)
+ :SensorComm("ppg", true), m_USB(USB), ss_int(ssInterface), ds_int(dsInterface), agc_enabled(true)
+{
+ max8614x_mode1_data_req.data_size = SSMAX8614X_MODE1_DATASIZE;
+ max8614x_mode1_data_req.callback = callback(this, &SSMAX8614XComm::max8614x_data_rx);
+
+ whrm_mode1_data_req.data_size = SSWHRM_MODE1_DATASIZE;
+ whrm_mode1_data_req.callback = callback(this, &SSMAX8614XComm::whrm_data_rx_mode1);
+
+ whrm_mode2_data_req.data_size = SSWHRM_MODEX_DATASIZE;
+ whrm_mode2_data_req.callback = callback(this, &SSMAX8614XComm::whrm_data_rx_mode2);
+
+ accel_mode1_data_req.data_size = SSACCEL_MODE1_DATASIZE;
+ accel_mode1_data_req.callback = callback(this, &SSMAX8614XComm::accel_data_rx);
+
+ agc_mode1_data_req.data_size = SSAGC_MODE1_DATASIZE;
+ agc_mode1_data_req.callback = callback(this, &SSMAX8614XComm::agc_data_rx);
+
+ queue_init(&max8614x_queue, max8614x_queue_buf, sizeof(max8614x_mode1_data), sizeof(max8614x_queue_buf));
+ queue_init(&whrm_queue, whrm_queue_buf, sizeof(whrm_modeX_data), sizeof(whrm_queue_buf));
+
+ queue_init(&accel_output_queue, accel_output_queue_buf, sizeof(accel_mode1_data), sizeof(accel_output_queue_buf));
+ queue_init(&accel_input_queue, accel_input_queue_buf, sizeof(accel_mode1_data), sizeof(accel_input_queue_buf));
+
+
+ sensor_algo_en_dis_.sensorhub_accel = 1; // enable sensor hub accel by default
+
+ m_bmi160 = 0;
+
+ input_fifo_size = 0;
+ sensor_data_from_host = false;
+}
+
+void SSMAX8614XComm::stop()
+{
+ status_algo_sensors_st sensor_algo_en_dis_temp;
+ comm_mutex.lock();
+ ss_int->disable_irq();
+ data_report_mode = 0;
+ sample_count = 0;
+
+ if (sensor_algo_en_dis_.max8614x_enabled) {
+ ss_int->disable_sensor(SS_SENSORIDX_MAX86140);
+ queue_reset(&max8614x_queue);
+ }
+
+ if (sensor_algo_en_dis_.accel_enabled) {
+ ss_int->disable_sensor(SS_SENSORIDX_ACCEL);
+ queue_reset(&accel_output_queue);
+ }
+
+ if (sensor_algo_en_dis_.whrm_enabled) {
+ ss_int->disable_algo(SS_ALGOIDX_WHRM);
+ queue_reset(&whrm_queue);
+ }
+
+ // store a copy of settings
+ sensor_algo_en_dis_temp.status_vals = sensor_algo_en_dis_.status_vals;
+ // clear all settings
+ sensor_algo_en_dis_.status_vals = 0;
+ //recover settings that need to be maintained
+ sensor_algo_en_dis_.sensorhub_accel = sensor_algo_en_dis_temp.sensorhub_accel;
+ ss_int->ss_clear_interrupt_flag();
+ ss_int->enable_irq();
+
+ if(sensor_algo_en_dis_.sensorhub_accel==0){
+ m_bmi160->reset();
+ queue_reset(&accel_input_queue);
+ }
+
+
+ comm_mutex.unlock();
+ input_fifo_size = 0;
+ sensor_data_from_host = false;
+}
+
+int SSMAX8614XComm::parse_cal_str(const char *ptr_ch, const char *cmd, uint8_t *cal_data, int cal_data_sz)
+{
+ char ascii_byte[] = { 0, 0, 0 };
+ const char* sptr = ptr_ch + strlen(cmd);
+ int found = 0;
+ int ssfound;
+ unsigned int val32;
+
+ //Eat spaces after cmd
+ while (*sptr != ' ' && *sptr != '\0') { sptr++; }
+ if (*sptr == '\0')
+ return -1;
+ sptr++;
+
+ while (found < cal_data_sz) {
+ if (*sptr == '\0')
+ break;
+ ascii_byte[0] = *sptr++;
+ ascii_byte[1] = *sptr++;
+ ssfound = sscanf(ascii_byte, "%x", &val32);
+ if (ssfound != 1)
+ break;
+ *(cal_data + found) = (uint8_t)val32;
+ //pr_err("cal_data[%d]=%d\r\n", found, val32);
+ found++;
+ }
+
+ //pr_err("total found: %d\r\n", found);
+ if (found < cal_data_sz)
+ return -1;
+ return 0;
+}
+
+int SSMAX8614XComm::parse_str(const char *ptr_ch, const char *cmd, uint8_t *data, int data_sz)
+{
+ char ascii_byte[] = { 0, 0, 0 };
+ const char* sptr = ptr_ch + strlen(cmd);
+ int found = 0;
+ int ssfound;
+ unsigned int val32;
+
+ //Eat spaces after cmd
+ while (*sptr != ' ' && *sptr != '\0') { sptr++; }
+ if (*sptr == '\0')
+ return -1;
+ sptr++;
+
+ while (found < data_sz) {
+ if (*sptr == '\0')
+ break;
+ ascii_byte[0] = *sptr++;
+ ascii_byte[1] = *sptr++;
+ ssfound = sscanf(ascii_byte, "%x", &val32);
+ if (ssfound != 1)
+ return -1;
+ *(data + found) = (uint8_t)val32;
+ pr_err("cal_data[%d]=%d\r\n", found, val32);
+ found++;
+ }
+
+ pr_err("total found: %d\r\n", found);
+ return found;
+}
+
+
+void SSMAX8614XComm::setBMI160(BMI160_I2C *pbmi160)
+{
+ if (pbmi160) {
+ m_bmi160 = pbmi160;
+ m_bmi160->reset();
+ }
+}
+
+
+int SSMAX8614XComm::get_sensor_xyz(accel_data_t &accel_data) {
+ int ret = 0;
+if(sensor_algo_en_dis_.sensorhub_accel==0){
+ BMI160::SensorData stacc_data = {0};
+ if (m_bmi160) {
+ ret = m_bmi160->getSensorXYZ(stacc_data, BMI160::SENS_2G);
+ if (ret < 0)
+ return ret;
+ }
+
+ accel_data.x = stacc_data.xAxis.scaled;
+ accel_data.y = stacc_data.yAxis.scaled;
+ accel_data.z = stacc_data.zAxis.scaled;
+
+ accel_data.x_raw = stacc_data.xAxis.raw;
+ accel_data.y_raw = stacc_data.yAxis.raw;
+ accel_data.z_raw = stacc_data.zAxis.raw;
+
+}
+
+ return ret;
+}
+
+bool SSMAX8614XComm::parse_command(const char* cmd)
+{
+ int ret;
+ SS_STATUS status;
+ bool recognizedCmd = false;
+ int data_len = 0;
+ char charbuf[768];
+ addr_val_pair reg_vals[64];
+
+ if (!ss_int) {
+ pr_err("No SmartSensor Interface defined!");
+ return false;
+ }
+ if (!ds_int) {
+ pr_err("No DeviceStudio Interface defined!");
+ return false;
+ }
+
+ for (int i = 0; i < NUM_CMDS; i++) {
+ if (starts_with(cmd, cmd_tbl[i])) {
+ cmd_state_t user_cmd = (cmd_state_t)i;
+ recognizedCmd = true;
+
+ switch (user_cmd) {
+ case set_cfg_accel_sh_dis:
+ {
+ sensor_algo_en_dis_.sensorhub_accel = 0;
+ m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+
+ } break;
+ case set_cfg_accel_sh_en:
+ {
+ sensor_algo_en_dis_.sensorhub_accel = 1;
+ m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+
+ } break;
+ case set_cfg_ppg_conf_level:
+ {
+ int j=24;
+ char temp_buf[4];
+ uint32_t PpgConfLevel[2];
+ while(cmd[j]!='\0'){
+ temp_buf[j-24] = cmd[j];
+ j++;
+ }
+ temp_buf[j-24]='\0';
+ sscanf(temp_buf,"%u",&PpgConfLevel[0]);
+
+ PpgConfLevel[1] = (*(uint32_t *)PPG_EXPIRE_DURATION_FLASH_ADDRESS);
+
+ if(FLC_Init()!=0){
+ m_USB->printf("\r\n%s err=Initializing flash\r\n", cmd);
+ break;
+ }
+ if( FLC_PageErase(PPG_CONF_LEVEL_FLASH_ADDRESS, MXC_V_FLC_ERASE_CODE_PAGE_ERASE, MXC_V_FLC_FLSH_UNLOCK_KEY)!=0 ){
+ m_USB->printf("\r\n%s err=Erasing page\r\n", cmd);
+ break;
+ }
+ if(FLC_Write(PPG_CONF_LEVEL_FLASH_ADDRESS,PpgConfLevel,sizeof(PpgConfLevel),MXC_V_FLC_FLSH_UNLOCK_KEY)!=0){
+ m_USB->printf("\r\n%s err=Writing flash\r\n", cmd);
+ break;
+ }
+ m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+
+ } break;
+ case set_cfg_ppg_expire_duration:
+ {
+ int j=27;
+ char temp_buf[4];
+ uint32_t PpgExpireDuration[2];
+ while(cmd[j]!='\0'){
+ temp_buf[j-27] = cmd[j];
+ j++;
+ }
+ temp_buf[j-27]='\0';
+ sscanf(temp_buf,"%u",&PpgExpireDuration[1]);
+
+ PpgExpireDuration[0] = (*(uint32_t *)PPG_CONF_LEVEL_FLASH_ADDRESS);
+
+ if(FLC_Init()!=0){
+ m_USB->printf("\r\n%s err=Initializing flash\r\n", cmd);
+ break;
+ }
+ if( FLC_PageErase(PPG_EXPIRE_DURATION_FLASH_ADDRESS, MXC_V_FLC_ERASE_CODE_PAGE_ERASE, MXC_V_FLC_FLSH_UNLOCK_KEY)!=0 ){
+ m_USB->printf("\r\n%s err=Erasing page\r\n", cmd);
+ break;
+ }
+ if(FLC_Write(PPG_CONF_LEVEL_FLASH_ADDRESS,PpgExpireDuration,sizeof(PpgExpireDuration),MXC_V_FLC_FLSH_UNLOCK_KEY)!=0){
+ m_USB->printf("\r\n%s err=Writing flash\r\n", cmd);
+ break;
+ }
+ m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+
+ } break;
+ case get_format_ppg_0:
+ {
+ if(AsciiEn)
+ {
+ if (ds_int->algo_report_mode == 1){
+ m_USB->printf("\r\n%s format=smpleCnt,grnCnt,led2,led3,grn2Cnt,led5,led6,"
+ "accelX,accelY,accelZ,hr,hrconf,r,activity err=0\r\n", cmd);
+ }
+ else { // report mode 2
+ m_USB->printf("\r\n%s format=smpleCnt,grnCnt,led2,led3,grn2Cnt,led5,led6,"
+ "accelX,accelY,accelZ,hr,hrconf,r,rconf,activity,walkSteps,runSteps,"
+ "energyKcal,stepCadence,isLedCurrentAdj,adjLedCurrent,isTAdj,adjT,isFAdj,"
+ "adjF,aecSmpAve,aecState,isAECMotion,scdStatus err=0\r\n", cmd);
+ }
+ }
+ else{
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s enc=bin cs=1 format={smpleCnt,16},"
+ "{grnCnt,20},{grn2Cnt,20},{accelX,14,3},{accelY,14,3},"
+ "{accelZ,14,3},{hr,12},{hrconf,8},{r,11,1},{activity,8} err=0\r\n", cmd);
+ m_USB->printf(charbuf);
+ }
+ } break;
+
+ case read_ppg_0:
+ {
+ sample_count = 0;
+
+ status = ss_int->get_input_fifo_size(&input_fifo_size);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d\n", __LINE__);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ status = ss_int->set_data_type(SS_DATATYPE_BOTH, false);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d, set DATA_TYPE\n, ", __LINE__);
+#ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+#endif
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ status = ss_int->set_fifo_thresh(5);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d, set thresh\n", __LINE__);
+#ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+#endif
+ m_USB->printf(charbuf);
+ break;
+ }
+
+
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d - agc_enabled: %d\n", __LINE__, agc_enabled);
+ ss_int->enable_irq();
+
+#ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+#endif
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ ss_int->disable_irq();
+
+ status = ss_int->enable_sensor(SS_SENSORIDX_MAX86140, 1, &max8614x_mode1_data_req);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d, enable max86140\n", __LINE__);
+ ss_int->enable_irq();
+ #ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+ #endif
+ m_USB->printf(charbuf);
+ break;
+ }
+ sensor_algo_en_dis_.max8614x_enabled = 1;
+
+
+
+ if (sensor_algo_en_dis_.sensorhub_accel) {
+ status = ss_int->enable_sensor(SS_SENSORIDX_ACCEL, 1, &accel_mode1_data_req, SH_INPUT_DATA_DIRECT_SENSOR);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d\n", __LINE__);
+ ss_int->enable_irq();
+ #ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+ #endif
+ m_USB->printf(charbuf);
+ break;
+ }
+ sensor_algo_en_dis_.accel_enabled = 1;
+ }
+ else {
+ m_bmi160->BMI160_DefaultInitalize();
+ if (m_bmi160->setSampleRate(BMI160_SAMPLE_RATE) != 0) {
+ pr_err("Unable to set BMI160's sample rate\n");
+ data_len = snprintf(charbuf , sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d\n", __LINE__);
+ ss_int->enable_irq();
+ #ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+ #endif
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ ret = m_bmi160->enable_data_ready_interrupt();
+ if(ret != E_SUCCESS){
+ pr_err("Unable to enable BMI160 Interrupt, ret: %d\n", ret);
+ break;
+ }
+
+
+
+ status = ss_int->enable_sensor(SS_SENSORIDX_ACCEL, 1, &accel_mode1_data_req, SH_INPUT_DATA_FROM_HOST);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d\n", __LINE__);
+ ss_int->enable_irq();
+ #ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+ #endif
+ m_USB->printf(charbuf);
+ break;
+ }
+ sensor_data_from_host = true;
+ sensor_algo_en_dis_.accel_enabled = 1;
+ }
+
+
+ if (ds_int->algo_report_mode == 2)
+ status = ss_int->enable_algo(SS_ALGOIDX_WHRM, 2, &whrm_mode2_data_req);
+ else // default is mode 1
+ status = ss_int->enable_algo(SS_ALGOIDX_WHRM, 1, &whrm_mode1_data_req);
+ if (status != SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "FAILED at line %d, enable whrm\n", __LINE__);
+ ss_int->enable_irq();
+ #ifdef FORCE_RESET_WHEN_FAILED
+ ret = ss_int->reset();
+ data_len += snprintf(charbuf+data_len, sizeof(charbuf)- data_len - 1,
+ "\r\nReset!\r\n");
+ #endif
+ m_USB->printf(charbuf);
+ break;
+ }
+ sensor_algo_en_dis_.whrm_enabled = 1;
+
+
+ comm_mutex.lock();
+ data_report_mode = read_ppg_0;
+ comm_mutex.unlock();
+ data_len = snprintf(charbuf, sizeof(charbuf) - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ ss_int->enable_irq();
+ } break;
+
+ case get_reg_ppg:
+ {
+ uint8_t addr;
+ uint32_t val;
+
+ ret = parse_get_reg_cmd(cmd, sensor_type, &addr);
+ if (!ret) {
+ status = ss_int->get_reg(SS_SENSORIDX_MAX86140, addr, &val);
+ if (status == SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s reg_val=%02X err=%d\r\n", cmd, (uint8_t)val, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ } else {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+ } else {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case set_reg_ppg:
+ {
+ uint8_t addr;
+ uint8_t val;
+
+ ret = parse_set_reg_cmd(cmd, sensor_type, &addr, &val);
+ if (!ret) {
+ status = ss_int->set_reg(SS_SENSORIDX_MAX86140, addr, val, SSMAX8614X_REG_SIZE);
+ if (status == SS_SUCCESS) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ } else {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+ } else {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case dump_reg_ppg:
+ {
+ int num_regs;
+ status = ss_int->dump_reg(SS_SENSORIDX_MAX86140, ®_vals[0], ARRAY_SIZE(reg_vals), &num_regs);
+ if (status == SS_SUCCESS) {
+ bool comma = false;
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1, "\r\n%s reg_val=", cmd);
+ for (int reg = 0; reg < num_regs; reg++) {
+ if (comma) {
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1, ",");
+ }
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1,
+ "{%X,%lX}", reg_vals[reg].addr, reg_vals[reg].val);
+ comma = true;
+ }
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1, " err=%d\r\n", COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } else {
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1,
+ "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case set_agc_en:
+ {
+ agc_enabled = true;
+ status = ss_int->enable_algo(SS_ALGOIDX_AGC, 1, &agc_mode1_data_req);
+ sensor_algo_en_dis_.agc_enabled = 1;
+ m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ } break;
+
+ case set_agc_dis:
+ {
+ agc_enabled = false;
+ status = ss_int->disable_algo(SS_ALGOIDX_AGC);
+ sensor_algo_en_dis_.agc_enabled = 0;
+ m_USB->printf("\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ } break;
+
+ case self_test_ppg_os58:
+ {
+ ret = selftest_max8614x();
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1,
+ "%s selftest_max8614x: err=<%d>\r\n", cmd, ret);
+ m_USB->printf(charbuf);
+ } break;
+
+ case self_test_ppg_acc:
+ {
+ ret = selftest_accelerometer();
+ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len - 1,
+ "%s selftest_accelerometer: err=<%d>\r\n", cmd, ret);
+ m_USB->printf(charbuf);
+ } break;
+
+ //--------- WHRM_AEC_SCD AEC ENABLE
+ case set_cfg_whrmaecscd_aecenable:
+ {
+ uint8_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[1] = { (uint8_t)(val[0]) };
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_AEC_ENABLE, &Temp[0], 1);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_aecenable:
+ {
+ uint8_t rxBuff[1+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_AEC_ENABLE, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD SCD ENABLE
+ case set_cfg_whrmaecscd_scdenable:
+ {
+ uint8_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[1] = { (uint8_t)(val[0]) };
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_SCD_ENABLE, &Temp[0], 1);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_scdenable:
+ {
+ uint8_t rxBuff[1+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_SCD_ENABLE, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD ADJ TARGET PD PERIOD
+ case set_cfg_whrmaecscd_adjpdperiod:
+ {
+ uint16_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[2] = { (uint8_t)((val[0] >> (1*8)) & 0xFF), (uint8_t)((val[0] >> (0*8)) & 0xFF)};
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_ADJ_TARGET_PD_CURRENT_PERIOD, &Temp[0], 2);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_adjpdperiod:
+ {
+ uint8_t rxBuff[2+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_ADJ_TARGET_PD_CURRENT_PERIOD, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD DEBOUNCE WINDOW
+ case set_cfg_whrmaecscd_debouncewin:
+ {
+ uint16_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[2] = { (uint8_t)((val[0] >> (1*8)) & 0xFF), (uint8_t)((val[0] >> (0*8)) & 0xFF)};
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_SCD_DEBOUNCE_WINDOW, &Temp[0], 2);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_debouncewin:
+ {
+ uint8_t rxBuff[2+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_SCD_DEBOUNCE_WINDOW, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD MOTION MAG THRESHOLD
+ case set_cfg_whrmaecscd_motionthreshold:
+ {
+ uint16_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[2] = { (uint8_t)((val[0] >> (1*8)) & 0xFF), (uint8_t)((val[0] >> (0*8)) & 0xFF)};
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_MOTION_MAG_THRESHOLD, &Temp[0], 2);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_motionthreshold:
+ {
+ uint8_t rxBuff[2+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_MOTION_MAG_THRESHOLD, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD MIN PD CURRENT
+ case set_cfg_whrmaecscd_minpdcurrent:
+ {
+ uint16_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[2] = { (uint8_t)((val[0] >> (1*8)) & 0xFF), (uint8_t)((val[0] >> (0*8)) & 0xFF)};
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_MIN_PD_CURRENT, &Temp[0], 2);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_minpdcurrent:
+ {
+ uint8_t rxBuff[2+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_MIN_PD_CURRENT, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD PD CONFIG
+ case set_cfg_whrmaecscd_pdconfig:
+ {
+ uint8_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[1] = { (uint8_t)(val[0]) };
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_PD_CONFIG, &Temp[0], 1);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_pdconfig:
+ {
+ uint8_t rxBuff[1+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_PD_CONFIG, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- WHRM_AEC_SCD LED CONFIG
+ case set_cfg_whrmaecscd_ledconfig:
+ {
+ uint8_t val[1];
+ ret = (parse_cmd_data(cmd, cmd_tbl[i], &val[0], 1, true) != 1);
+ if (ret) {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_INVALID_PARAM);
+ m_USB->printf(charbuf);
+ break;
+ }
+
+ uint8_t Temp[1] = { (uint8_t)(val[0]) };
+
+ status = ss_int->set_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_LED_CONFIG, &Temp[0], 1);
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+
+ case get_cfg_whrmaecscd_ledconfig:
+ {
+ uint8_t rxBuff[1+1]; // first byte is status
+ char outstr[2*sizeof(rxBuff)];
+ int str_idx = 0;
+ uint8_t *Temp = &rxBuff[1];
+ uint8_t val[1];
+
+ status = ss_int->get_algo_cfg(SS_ALGOIDX_WHRM, SS_CFGIDX_WHRM_LED_CONFIG, &rxBuff[0], sizeof(rxBuff));
+ for (int i = 0; i < sizeof(rxBuff)-1; i++)
+ str_idx += snprintf(outstr + str_idx, sizeof(outstr) - str_idx - 1, "%02X", Temp[i]);
+
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s value=%s err=%d\r\n", cmd, outstr, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+
+ } break;
+
+ //--------- SEND RAW
+ case send_raw:
+ {
+ int size=0;
+ uint8_t data[256]; // max size of command
+
+ size = parse_str(cmd, cmd_tbl[i], data, sizeof(data));
+ status = ss_int->send_raw(data, size);
+
+ if (status == SS_SUCCESS)
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_SUCCESS);
+ m_USB->printf(charbuf);
+ }
+ else
+ {
+ data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s err=%d\r\n", cmd, COMM_GENERAL_ERROR);
+ m_USB->printf(charbuf);
+ }
+
+ } break;
+ //--------------------------------------------------------
+
+ default:
+ {
+ mxm_assert_msg(false, "Invalid switch case!");
+ } break;
+
+ }
+
+
+ if (BLE::Instance().gap().getState().connected) {
+ BLE_Icarus_AddtoQueue((uint8_t *)charbuf, (int32_t)sizeof(charbuf), data_len);
+ }
+
+
+ break;
+
+ }
+ }
+
+ return recognizedCmd;
+}
+
+void SSMAX8614XComm::max8614x_data_rx(uint8_t* data_ptr)
+{
+ max8614x_mode1_data sample;
+ sample.led1 = (data_ptr[0] << 16) | (data_ptr[1] << 8) | data_ptr[2];
+ 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];
+ sample.led4 = (data_ptr[9] << 16) | (data_ptr[10] << 8) | data_ptr[11];
+ 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];
+
+ pr_info("led1=%.6X led2=%.6X led3=%.6X led4=%.6X led5=%.6X led6=%.6X\r\n",
+ sample.led1, sample.led2, sample.led3, sample.led4, sample.led5, sample.led6);
+
+ enqueue(&max8614x_queue, &sample);
+}
+
+void SSMAX8614XComm::whrm_data_rx_mode1(uint8_t* data_ptr)
+{
+ whrm_modeX_data sample;
+
+ sample.hr = (data_ptr[0] << 8) | data_ptr[1];
+ sample.hr_conf = data_ptr[2];
+ sample.rr = (data_ptr[3] << 8) | data_ptr[4];
+ sample.activity_class = data_ptr[5];
+ //m_USB->printf("\r\n Md1- hr:%d conf:%d rr:%d act:%d\r\n", sample.hr,sample.hr_conf,sample.rr,sample.activity_class );
+ enqueue(&whrm_queue, &sample);
+ pr_info("hr=%.1f conf=%d rr=%.1f rr_conf=%d status=%d\r\n", (float)sample.hr / 10.0, sample.hr_conf, (float)sample.rr/10, sample.rr_conf,sample.activity_class);
+}
+
+void SSMAX8614XComm::whrm_data_rx_mode2(uint8_t* data_ptr)
+{
+ whrm_modeX_data sample;
+
+ sample.hr = (data_ptr[0] << 8) | data_ptr[1];
+ sample.hr_conf = data_ptr[2];
+ sample.rr = (data_ptr[3] << 8) | data_ptr[4];
+ sample.activity_class = data_ptr[5];
+ sample.rr_conf = data_ptr[6];
+ sample.walk_steps = (data_ptr[7] << 24) | (data_ptr[8] << 16) |(data_ptr[9] << 8) | data_ptr[10];
+ sample.run_steps = (data_ptr[11] << 24) | (data_ptr[12] << 16) |(data_ptr[13] << 8) | data_ptr[14];
+ sample.kcal = (data_ptr[15] << 24) | (data_ptr[16] << 16) |(data_ptr[17] << 8) | data_ptr[18];
+ sample.cadence = (data_ptr[19] << 24) | (data_ptr[20] << 16) |(data_ptr[21] << 8) | data_ptr[22];
+ sample.is_led_cur_adj = data_ptr[23];
+ sample.adj_led_cur = (data_ptr[24] << 8) | data_ptr[25];
+ sample.is_t_int_cur_adj = data_ptr[26];
+ sample.adj_t_int_cur = (data_ptr[27] << 8) | data_ptr[28];
+ sample.is_f_smp_adj = data_ptr[29];
+ sample.adj_f_smp = data_ptr[30];
+ sample.smp_ave = data_ptr[31];
+ sample.state = data_ptr[32];
+ sample.is_high_motion = data_ptr[33];
+ sample.status = data_ptr[34];
+
+ //m_USB->printf("\r\nMd2- hr:%d conf:%d rr:%d act:%d\r\n", sample.hr,sample.hr_conf,sample.rr,sample.activity_class );
+ enqueue(&whrm_queue, &sample);
+ pr_info("hr=%.1f conf=%d rr=%.1f rr_conf=%d status=%d\r\n", (float)sample.hr / 10.0, sample.hr_conf, (float)sample.rr/10, sample.rr_conf,sample.activity_class);
+}
+
+
+void SSMAX8614XComm::accel_data_rx(uint8_t* data_ptr)
+{
+ //See API doc for data format
+ accel_mode1_data sample;
+ 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];
+
+ enqueue(&accel_input_queue, &sample);
+}
+
+void SSMAX8614XComm::agc_data_rx(uint8_t* data_ptr)
+{
+ //NOP: AGC does not collect data
+}
+
+int SSMAX8614XComm::data_report_execute(char* buf, int size)
+{
+ uint8_t tmp_report_mode;
+ max8614x_mode1_data max8614x_sample = { 0 };
+ whrm_modeX_data whrm_sample_modeX = { 0 };
+ //wspo2_modeX_data wspo2_sample_modeX = { 0 };
+ accel_mode1_data accel_sample = { 0 };
+
+
+ accel_data_t accel_data = {0};
+
+ int16_t data_len = 0;
+
+ static uint8_t isReportEnabled = 0;
+
+ if (size <= 0)
+ {
+ m_USB->printf("\r\nError: RepSize = %d\r\n", size);
+ return 0;
+ }
+
+ if (isReportEnabled != is_enabled())
+ {
+ isReportEnabled = is_enabled();
+ m_USB->printf("\r\nRep Enable = %d \r\n",isReportEnabled);
+ }
+
+ if (!is_enabled())
+ {
+ return 0;
+ }
+
+ ss_int->ss_execute_once();
+
+ comm_mutex.lock();
+ tmp_report_mode = data_report_mode;
+ comm_mutex.unlock();
+
+
+ while (sensor_data_from_host) {
+ accel_data_t accel_data = {0};
+
+ int ret;
+ ret = get_sensor_xyz(accel_data);
+ if (ret < 0)
+ break;
+
+ accel_mode1_data acc_sample;
+ acc_sample.x = (int16_t)(accel_data.x*1000);
+ acc_sample.y = (int16_t)(accel_data.y*1000);
+ acc_sample.z = (int16_t)(accel_data.z*1000);
+
+ if (enqueue(&accel_output_queue, &acc_sample) < 0)
+ pr_err("Thrown an accel sample\n");
+
+ if (queue_len(&accel_output_queue) < MAX_NUM_WR_ACC_SAMPLES)
+ break;
+
+ int num_bytes = 0;
+ SS_STATUS status = ss_int->get_num_bytes_in_input_fifo(&num_bytes);
+ if (status != SS_SUCCESS) {
+ pr_err("Unable to read num bytes in input fifo\r\n");
+ break;
+ }
+
+ int num_tx = input_fifo_size - num_bytes;
+ mxm_assert_msg((num_tx >= 0), "num_tx can't be negative");
+ if (num_tx <= 0)
+ break;
+
+ int num_samples = num_tx / sizeof(accel_mode1_data);
+ num_samples = min(num_samples, MAX_NUM_WR_ACC_SAMPLES);
+ num_tx = num_samples * sizeof(accel_mode1_data);
+
+ if (num_samples == 0) {
+ pr_err("Input FIFO is Full\n");
+ break;
+ }
+
+ accel_mode1_data peek_buf[num_samples];
+ ret = queue_front_n(&accel_output_queue, peek_buf, num_samples, num_samples * sizeof(accel_mode1_data));
+ if (ret < 0)
+ mxm_assert_msg((num_tx >= 0), "Unable to peek samples from accel queue. Something is wrong.");
+
+ uint8_t tx_buf[2 + num_tx]; /* 2 bytes were allocated for commands */
+ for (int i = 2, j = 0; j < num_samples; i+= sizeof(accel_mode1_data), j++) {
+ acc_sample = peek_buf[j];
+
+ tx_buf[i] = acc_sample.x;
+ tx_buf[i + 1] = acc_sample.x >> 8;
+
+ tx_buf[i + 2] = acc_sample.y;
+ tx_buf[i + 3] = acc_sample.y >> 8;
+
+ tx_buf[i + 4] = acc_sample.z;
+ tx_buf[i + 5] = acc_sample.z >> 8;
+
+ }
+
+ int num_wr_bytes = 0;
+ int nb_expected = num_tx;
+ status = ss_int->feed_to_input_fifo(tx_buf, num_tx + 2, &num_wr_bytes);
+ if (status != SS_SUCCESS) {
+ pr_err("Unable to write accel data. num_tx: %d. status: %d\r\n", num_tx, status);
+ break;
+ }
+
+ int num_written_samples = num_wr_bytes / sizeof(accel_mode1_data);
+ if (num_written_samples == 0)
+ break;
+
+ ret = queue_pop_n(&accel_output_queue, num_written_samples);
+ if (ret < 0)
+ mxm_assert_msg((num_tx >= 0), "Unable to popped samples out from accel queue. Something is wrong.");
+
+ break;
+ }
+
+
+ switch (tmp_report_mode) {
+ case read_ppg_0:
+ {
+ if (1
+
+
+ && (queue_len(&max8614x_queue) > 0 && sensor_algo_en_dis_.max8614x_enabled)
+
+
+
+ && (queue_len(&accel_input_queue) > 0 && sensor_algo_en_dis_.accel_enabled)
+
+
+
+ && (queue_len(&whrm_queue) > 0 && sensor_algo_en_dis_.whrm_enabled)
+
+ )
+ {
+
+ if(sensor_algo_en_dis_.max8614x_enabled)
+ dequeue(&max8614x_queue, &max8614x_sample);
+
+
+
+ if(sensor_algo_en_dis_.accel_enabled)
+ dequeue(&accel_input_queue, &accel_sample);
+
+
+
+ if(sensor_algo_en_dis_.whrm_enabled){
+ dequeue(&whrm_queue, &whrm_sample_modeX);
+ instant_hr = whrm_sample_modeX.hr * 0.1;
+ instant_hr_conf = whrm_sample_modeX.hr_conf;
+ instant_hr_activityClass = whrm_sample_modeX.activity_class;
+ }
+
+
+ if (AsciiEn) {
+ // mode 2 only for ASCII
+ if (ds_int->algo_report_mode == 2){
+ data_len = snprintf(buf, size - 1,
+ "%u,%lu,%lu,%lu,%lu,%lu,%lu,%.3f,%.3f,%.3f,%.1f,%d,%.1f,%d,%d,%lu,%lu,%lu,%lu,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
+ sample_count++,
+ max8614x_sample.led1,max8614x_sample.led2,max8614x_sample.led3,max8614x_sample.led4,max8614x_sample.led5,max8614x_sample.led6,
+ accel_sample.x * 0.001,accel_sample.y * 0.001,accel_sample.z * 0.001,
+ whrm_sample_modeX.hr * 0.1, whrm_sample_modeX.hr_conf, whrm_sample_modeX.rr * 0.1,whrm_sample_modeX.rr_conf,whrm_sample_modeX.activity_class,
+ whrm_sample_modeX.walk_steps, whrm_sample_modeX.run_steps, whrm_sample_modeX.kcal, whrm_sample_modeX.cadence,
+ whrm_sample_modeX.is_led_cur_adj, whrm_sample_modeX.adj_led_cur, whrm_sample_modeX.is_t_int_cur_adj, whrm_sample_modeX.adj_t_int_cur,
+ whrm_sample_modeX.is_f_smp_adj, whrm_sample_modeX.adj_f_smp,
+ whrm_sample_modeX.smp_ave, whrm_sample_modeX.state, whrm_sample_modeX.is_high_motion, whrm_sample_modeX.status);
+ }
+ else {
+ data_len = snprintf(buf, size - 1, "%u,%lu,%lu,%lu,%lu,%lu,%lu,%.3f,%.3f,%.3f,%.1f,%d,%.1f,%d\r\n",
+ sample_count++,
+ max8614x_sample.led1,
+ max8614x_sample.led2,
+ max8614x_sample.led3,
+ max8614x_sample.led4,
+ max8614x_sample.led5,
+ max8614x_sample.led6,
+ accel_sample.x * 0.001,
+ accel_sample.y * 0.001,
+ accel_sample.z * 0.001,
+ whrm_sample_modeX.hr * 0.1,
+ whrm_sample_modeX.hr_conf,
+ whrm_sample_modeX.rr * 0.1,
+ whrm_sample_modeX.activity_class);
+ }
+ }
+ else { // bin report
+
+
+ mxm_assert_msg(((uint32_t)size > sizeof(ds_pkt_data_mode2_compact)), "data_report_execute buffer too small");
+ ds_pkt_data_mode2_compact* data_packet = (ds_pkt_data_mode2_compact*)buf;
+ data_packet->start_byte = DS_BINARY_PACKET_START_BYTE;
+ data_packet->sample_cnt = sample_count++;
+ data_packet->grnCnt = max8614x_sample.led1;
+ data_packet->grn2Cnt = max8614x_sample.led4;
+ data_packet->hr = (whrm_sample_modeX.hr * 0.1);
+ data_packet->x = (int16_t)(accel_sample.x);
+ data_packet->y = (int16_t)(accel_sample.y);
+ data_packet->z = (int16_t)(accel_sample.z);
+ data_packet->hr_confidence = whrm_sample_modeX.hr_conf;
+ data_packet->rr = whrm_sample_modeX.rr;
+ data_packet->status = whrm_sample_modeX.activity_class;
+ data_packet->crc8 = crc8((uint8_t*)data_packet, sizeof(*data_packet) - sizeof(uint8_t));
+ data_len = sizeof(*data_packet);
+ }
+ }
+ else
+ {
+ //m_USB->printf("\r\nError Printing: max8614x_q:%d, max8614x_enabled:%d, \r\n",queue_len(&max8614x_queue), sensor_algo_en_dis_.max8614x_enabled );
+ //m_USB->printf("\r\n accel_q:%d, accel_enabled:%d, \r\n",queue_len(&accel_input_queue), sensor_algo_en_dis_.accel_enabled);
+ //m_USB->printf("\r\n whrm_queue:%d,whrm_enabled:%d, \r\n",queue_len(&whrm_queue) , sensor_algo_en_dis_.whrm_enabled);
+
+ }
+ } break;
+
+ default:
+ {
+ m_USB->printf("\r\nError tmp_report_mode=%d\r\n", tmp_report_mode);
+ return 0;
+ }
+ }
+
+ if (data_len < 0) {
+ pr_err("snprintf console_tx_buf failed");
+ } else if (data_len > size) {
+ pr_err("buffer is insufficient to hold data");
+ }
+
+ return data_len;
+}
+
+// TODO: convert this to PPG sensor test
+int SSMAX8614XComm::selftest_max8614x(){
+ int ret;
+ uint8_t test_result;
+ bool test_failed = false;
+ m_USB->printf("starting selftest_max8614x\r\n");
+ // configure mfio pin for self test
+ ss_int->mfio_selftest();
+ ret = ss_int->self_test(SS_SENSORIDX_MAX86140, &test_result, 1000);
+ if(ret != SS_SUCCESS){
+ m_USB->printf("ss_int->self_test(SS_SENSORIDX_MAX86140, &test_result) has failed err<-1>\r\n");
+ test_failed = true;
+ }
+ // reset mfio pin to old state
+ if(!ss_int->reset_mfio_irq()){
+ m_USB->printf("smart sensor reset_mfio_irq has failed err<-1>\r\n");
+ test_failed = true;
+ }
+ // reset the sensor to turn off the LED
+ ret = ss_int->reset();
+ if(test_failed | !self_test_result_evaluate("selftest_max8614x", test_result)){
+ return -1;
+ }else{
+ return SS_SUCCESS;
+ }
+}
+
+int SSMAX8614XComm::selftest_accelerometer(){
+ int ret;
+ uint8_t test_result;
+ bool test_failed = false;
+ m_USB->printf("starting selftest_accelerometer\r\n");
+ ret = ss_int->self_test(SS_SENSORIDX_ACCEL, &test_result, 1000);
+ if(ret != SS_SUCCESS){
+ m_USB->printf("ss_int->self_test(SS_SENSORIDX_ACCEL, &test_result) has failed err<-1>\r\n");
+ test_failed = true;
+ }
+ // reset the sensor to turn off the LED
+ ret = ss_int->reset();
+ if(ret != SS_SUCCESS){
+ m_USB->printf("smart sensor reset has failed err<-1>\r\n");
+ test_failed = true;
+ }
+ if(test_failed | !self_test_result_evaluate("selftest_accelerometer", test_result)){
+ return -1;
+ }else{
+ return SS_SUCCESS;
+ }
+}
+
+bool SSMAX8614XComm::self_test_result_evaluate(const char *message, uint8_t result){
+ // check i2c response status
+ if(result != 0x00){
+ m_USB->printf("%s has failed % 02X err<-1>\r\n", message, result);
+ if((result & FAILURE_COMM))
+ m_USB->printf("%s communication has failed err<-1>\r\n", message);
+ if(result & FAILURE_INTERRUPT)
+ m_USB->printf("%s interrupt pin check has failed err<-1>\r\n", message);
+ return false;
+ }
+ return true;
+}
+
+unsigned char SSMAX8614XComm::get_sensor_id() {
+ return SENSOR_ID_SSMAX8614X; //TODO: assign the correct number
+}