TEST
Dependencies: max32630fthr Adafruit_FeatherOLED USBDevice
Interfaces/DeviceStudio/DSInterface.cpp
- Committer:
- gmehmet
- Date:
- 2019-04-10
- Revision:
- 1:f60eafbf009a
File content as of revision 1:f60eafbf009a:
/*************************************************************************** * 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 <ctype.h> #include <string.h> #include "DSInterface.h" #include "../../Utilities/mxm_assert.h" #include "../version.h" #include "Peripherals.h" #include "utils.h" #include "Thread.h" #include "BLE_ICARUS.h" #define HR_ENABLED 1 << 0 #define SPO2_ENABLED 1 << 1 #define BPT_ENABLED 1 << 2 #define WHRM_ENABLED 1 << 3 #define WSPO2_ENABLED 1 << 4 #define AEC_ENABLED 1 << 5 #define SCD_ENABLED 1 << 6 #define AGC_ENABLED 1 << 7 typedef struct { uint8_t fwVersion[3]; uint16_t enAlgoDescBitField; char me11ProductID; }fw_type_t; const static fw_type_t HUB_FW_TABLE[] = { {{1,8,3}, HR_ENABLED | SPO2_ENABLED | AGC_ENABLED , 'A' }, {{20,1,1}, WHRM_ENABLED | SCD_ENABLED | AEC_ENABLED , 'B' }, {{30,1,1}, WHRM_ENABLED | WSPO2_ENABLED | AGC_ENABLED | SCD_ENABLED | AEC_ENABLED , 'C' }, {{40,0,4}, BPT_ENABLED | SPO2_ENABLED | AGC_ENABLED , 'D' } }; static const char* ActivAlgoInfo[32] = { [0] = "hr,", [1] = "spo2,", [2] = "bpt,", [3] = "whrm,", [4] = "wspo2,", [5] = "aec,", [6] = "scd,", [7] = "agc,", }; static const char *glbl_cmds[] = { "stop", "get_device_info", "silent_mode 0", "silent_mode 1", "pause 0", "pause 1", "enable console", "disable console", "set_cfg lcd time", "set_cfg flash log", "set_cfg stream ascii", // set streaming mode to ascii "set_cfg stream bin", // set streaming mode to binary "set_cfg report 1", //set report mode to 1 (brief) "set_cfg report 2" // set report mode to 2 (long) }; typedef enum { stop=0, get_device_info, silent0_mode, silent1_mode, pause0_mode, pause1_mode, enable_console, disable_console, set_lcd_time, set_flash_log, enable_ascii_mode, enable_bin_mode, set_cfg_report_1, set_cfg_report_2, NUM_CMDS, } glbl_cmd_state; DSInterface::DSInterface(USBSerial* USB) :flash_thread_(osPriorityNormal, 2 * 1024) { cmd_idx = 0; silent_mode = false; pause_mode = false; memset(sensor_list, 0, DS_MAX_NUM_SENSORCOMMS * sizeof(SensorComm*)); num_sensors = 0; m_USB = USB; ds_console_interface_exists_ = false; recordingStarted = false; ds_queue_flash_ = &ds_queue_one_; ds_queue_fill_ = &ds_queue_two_; queue_init(ds_queue_flash_, buffer_one_, FLASH_MESSAGE_SIZE, sizeof(buffer_one_)); queue_init(ds_queue_fill_, buffer_two_, FLASH_MESSAGE_SIZE, sizeof(buffer_two_)); flash_thread_.start(callback(&event_queue_, &EventQueue::dispatch_forever)); } DSInterface::~DSInterface() { } void DSInterface::add_sensor_comm(SensorComm *s) { mxm_assert_msg(num_sensors < DS_MAX_NUM_SENSORCOMMS, "Too many sensors added to DSInterface. Increase DS_MAX_NUM_SENSORCOMMS."); sensor_list[num_sensors++] = s; } void DSInterface::enable_console_interface() { ds_console_interface_exists_ = true; } void DSInterface::ds_set_ble_status(bool en){ SensorComm *p_sensor; ds_ble_interface_exists_ = en; for(int sensor_num = 0; sensor_num < num_sensors; ++sensor_num) { p_sensor = sensor_list[sensor_num]; p_sensor->SensorComm_Set_Ble_Status(ds_ble_interface_exists_); } } void DSInterface::ds_set_flash_rec_status(bool en) { SensorComm *p_sensor; recordingStarted = en; for(int sensor_num = 0; sensor_num < num_sensors; ++sensor_num) { p_sensor = sensor_list[sensor_num]; p_sensor->SensorComm_Set_Flash_Status(en); } } void DSInterface::build_command(char ch) { if (!this->silent_mode) /* BUG: POTENTIAL BUG, what uart port to echo, not only console */ m_USB->printf("%c", ch); if (ch == 0x00) { pr_err("Ignored char 0x00"); return; } if ((ch == '\n') || (ch == '\r')) { if (cmd_idx < (int)CONSOLE_STR_BUF_SZ) cmd_str[cmd_idx++] = '\0'; m_USB->printf("\r\n"); parse_command(); //Clear cmd_str while (cmd_idx > 0) /* BUG: POTENTIAL BUG for multiple port access */ cmd_str[--cmd_idx] = '\0'; } else if ((ch == 0x08 || ch == 0x7F) && cmd_idx > 0) { //Backspace character if (cmd_idx > 0) cmd_str[--cmd_idx] = '\0'; } else { /* BUG: POTENTIAL BUG for multiple port access */ if (cmd_idx < (int)CONSOLE_STR_BUF_SZ) cmd_str[cmd_idx++] = ch; } } void DSInterface::stopcommand() { for (int i = 0; i < num_sensors; i++) { sensor_list[i]->stop(); } ds_set_flash_rec_status(false); } void DSInterface::parse_command_str(const char* cmd ) { strncpy(cmd_str, cmd , strlen(cmd) + 1); parse_command(); } void DSInterface::write_to_flash_thread_funct() { //static Timer mytimer; //mytimer.reset(); //mytimer.start(); fwrite((uint8_t*)ds_queue_flash_->base, 1, ds_queue_flash_->item_size * ds_queue_flash_->num_item, flashFileHandle); queue_reset(ds_queue_flash_); //mytimer.stop(); //printf("%f seconds\n", mytimer.read()); } void DSInterface::parse_command() { int i; glbl_cmd_state cmd; char charbuf[512]; char tempbuf[32]; int data_len = 0; int data_len_log=0; int ret; bool parsed_cmd = true; printf("%s \n",cmd_str ); //If top level command, then handle it for (i = 0; i < NUM_CMDS; i++) { if (starts_with(&cmd_str[0], glbl_cmds[i])) { cmd = (glbl_cmd_state)i; switch (cmd) { case (enable_ascii_mode): { sensor_list[0]->AsciiEn = true; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (enable_bin_mode): { sensor_list[0]->AsciiEn = false; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (stop): { for (int i = 0; i < num_sensors; i++) { sensor_list[i]->stop(); } ds_set_flash_rec_status(false); data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (get_device_info): { data_len = snprintf(charbuf, sizeof(charbuf), "\r\n%s platform=%s firmware_ver=%s sensors=", cmd_str, platform_name, FIRMWARE_VERSION); //Add list of sensors for (int i = 0; i < num_sensors; i++) { if (sensor_list[i]->is_visible()) { data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, "%s", sensor_list[i]->get_type()); if (i < (num_sensors - 1)) data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, ","); } } for (int i = 0; i < num_sensors; i++) { SensorComm *s = sensor_list[i]; if (!s->is_visible()) continue; //Add algo_ver data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, " algo_ver_%s=%s", s->get_type(), s->get_algo_ver()); //Add part name data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, " part_name_%s=%s", s->get_type(), s->get_part_name()); uint8_t part_id, part_rev; ret = s->get_part_info(&part_id, &part_rev); if (ret == 0) { //Add part id data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, " part_id_%s=%d", s->get_type(), part_id); //Add rev id data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, " part_rev_%s=%d", s->get_type(), part_rev); } } if(firmware_version){ data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, " hub_firm_ver=%s", firmware_version); if(algo_desc_strsz > 0) data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, "%s", algo_desc_string); } data_len += snprintf(charbuf + data_len, sizeof(charbuf) - data_len, " err=0\r\n"); } break; case (silent0_mode): { silent_mode = false; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (silent1_mode): { silent_mode = true; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (pause0_mode): { pause_mode = false; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (pause1_mode): { pause_mode = true; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (enable_console): { ds_console_interface_exists_ = true; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (disable_console): { ds_console_interface_exists_ = false; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (set_lcd_time): { while(1) { if(cmd_str[17+lcd_time_count] == '\0') { lcd_time_str[lcd_time_count] = '\0'; break; } lcd_time_str[lcd_time_count] = cmd_str[17+lcd_time_count]; lcd_time_count++; } sscanf(lcd_time_str,"%d",&lcd_time_val); set_time(lcd_time_val); lcd_time_count=0; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (set_flash_log): { if(cmd_str[18] == '1' ) { time_t seconds; seconds = time(NULL); strftime(tempbuf, 32, "/fs/log-%I-%M-%S.maximlog", localtime(&seconds)); flashFileHandle = fopen(tempbuf, "w+"); if ( flashFileHandle != NULL ) { fprintf(flashFileHandle,"mxim"); //1 byte to indicate the version of the log unsigned char vers = 0; //4 bytes to indicate the number of bytes used to write the format unsigned int NumByteBLE = 764; unsigned int NumByteNoBLE = 659; fwrite(&vers,sizeof(unsigned char),1,flashFileHandle); if(BLE::Instance().gap().getState().connected){ fwrite(&NumByteBLE,sizeof(unsigned int),1,flashFileHandle); } else fwrite(&NumByteNoBLE,sizeof(unsigned int),1,flashFileHandle); ds_set_flash_rec_status(true); //Write the formats data_len_log += snprintf(logbuf+data_len_log, sizeof(logbuf) - data_len_log- 1,"ppg 0 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}\n" "ppg 1 cs=1 format={smpleCnt,8},{irCnt,20},{redCnt,20},{accelX,14,3}," "{accelY,14,3},{accelZ,14,3},{r,12,1},{wspo2conf,8}," "{spo2,11,1},{wspo2percentcomplete,8},{wspo2lowSNR,1},{wspo2motion,1},{status,8}\n" "bpt 0 cs=1 format={status,4},{irCnt,19},{hr,9}," "{prog,9},{sys_bp,9},{dia_bp,9}\n" "bpt 1 cs=1 format={status,4},{irCnt,19},{hr,9}," "{prog,9},{sys_bp,9},{dia_bp,9}\n"); if(BLE::Instance().gap().getState().connected){ data_len_log += snprintf(logbuf+data_len_log, sizeof(logbuf) -data_len_log- 1,"ecg 1 cs=1 format={smpleCnt,8},{rtor,14},{rtorbpm,8}," "{pTag.0,3},{eTag.0,3},{ecg.0,18},{pTag.1,3},{eTag.1,3},{ecg.1,18}," "{pTag.2,3},{eTag.2,3},{ecg.2,18},{pTag.3,3},{eTag.3,3},{ecg.3,18}\n"); }else{ data_len_log += snprintf(logbuf+data_len_log, sizeof(logbuf) -data_len_log- 1,"ecg 1 cs=1 format={smpleCnt,8},{pTag,3},{eTag,3}," "{ecg,18},{rtor,14},{rtorbpm,8}\n"); } data_len_log += snprintf(logbuf+data_len_log, sizeof(logbuf)-data_len_log - 1,"ecg 2 cs=1 format={smplCnt,8},{rtor,15}\n"); data_len_log += snprintf(logbuf+data_len_log, sizeof(logbuf) -data_len_log-1,"temp 0 cs=1 format={smpleCnt,8},{temp,16,2}\n"); fprintf(flashFileHandle,logbuf,data_len_log); } else { ds_set_flash_rec_status(false); } data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } else if (cmd_str[18] == '0'){ ds_set_flash_rec_status(false); handle_file_close(); data_len += snprintf(charbuf, sizeof(charbuf) - 1,"\r\n%s err=0\r\n", cmd_str); } else{ //print cmd not recognized string data_len += snprintf(charbuf, sizeof(charbuf) - 1,"\r\n%s err=-255\r\n", cmd_str); } } break; case (set_cfg_report_1): { //m_USB->printf("\r\n MODE 1\r\n"); algo_report_mode = 1; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; case (set_cfg_report_2): { //m_USB->printf("\r\n MODE 2\r\n"); algo_report_mode = 2; data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=0\r\n", cmd_str); } break; default: parsed_cmd = false; break; } if (parsed_cmd) { m_USB->printf(charbuf); if (BLE::Instance().gap().getState().connected) { BLE_Icarus_AddtoQueue((uint8_t *)charbuf, (int32_t)sizeof(charbuf), data_len); } } return; } } //Set the stream type to check the data streaming type later if(starts_with(&cmd_str[0],"read ppg 0")){ stream_type=0x00; } else if(starts_with(&cmd_str[0],"read ppg 1")){ stream_type=0x01; } else if(starts_with(&cmd_str[0],"read bpt 0")){ stream_type=0x02; } else if(starts_with(&cmd_str[0],"read bpt 1")){ stream_type=0x03; } else if(starts_with(&cmd_str[0],"read ecg 1")){ stream_type=0x04; } else if(starts_with(&cmd_str[0],"read ecg 2")){ stream_type=0x05; } else if(starts_with(&cmd_str[0],"read temp 0")){ stream_type=0x06; } //Loop through each sensor in sensorList //If sensor.get_type() is contained in cmd_str, pass cmd_str to that sensor's parser for (int i = 0; i < num_sensors; i++) { if (strstr(&cmd_str[0], sensor_list[i]->get_type())) { if (sensor_list[i]->parse_command(cmd_str)) return; break; } } //If we still haven't found a way to parse the command, //send it to every sensor until one handles it for (int i = 0; i < num_sensors; i++) { if (sensor_list[i]->parse_command(cmd_str)) return; } //No one could handle the command, print cmd not recognized string data_len += snprintf(charbuf, sizeof(charbuf) - 1, "\r\n%s err=-255\r\n", cmd_str); m_USB->printf(charbuf); if (BLE::Instance().gap().getState().connected) { BLE_Icarus_AddtoQueue((uint8_t *)charbuf, (int32_t)sizeof(charbuf), data_len); } } void DSInterface::swap_queues() { if(flash_thread_.get_state() != Thread::WaitingEventFlag){ printf("overflow happened state %d\r\n", flash_thread_.get_state()); return; } queue_t * temp_queue = ds_queue_flash_; ds_queue_flash_ = ds_queue_fill_; ds_queue_fill_ = temp_queue; event_queue_.call(Callback<void()>(this, &DSInterface::write_to_flash_thread_funct)); } void DSInterface::handle_file_close() { //if recording is enabled do not close the file if(recordingStarted) { return; } if(flashFileHandle != NULL) { if(flash_thread_.get_state() != Thread::WaitingEventFlag) return; if(ds_queue_fill_->num_item){ swap_queues(); return; } printf("closing file\r\n"); fclose(flashFileHandle); flashFileHandle = NULL; } } void DSInterface::force_file_close() { if(flashFileHandle != NULL) { while(flash_thread_.get_state() != Thread::WaitingEventFlag) { wait_ms(1); } if(ds_queue_fill_->num_item){ swap_queues(); } while(flash_thread_.get_state() != Thread::WaitingEventFlag) { wait_ms(1); } //printf("closing file\r\n"); fclose(flashFileHandle); flashFileHandle = NULL; } } #define ECGSENSOR_ID 0x02 //TODO:FIX THESE #define ECGSENSOR_DATA_REPORT_MODE 0x04 //TODO:FIX THESE void DSInterface::data_report_execute() { char buffer[256]; int data_len = 0; buffer[0] = '\0'; int ret; bool all_sensors_disabled = true; for (int i = 0; i < num_sensors; i++) { //if ((*it)->is_enabled()) { if(!recordingStarted) data_len = sensor_list[i]->data_report_execute(buffer, sizeof(buffer)); else data_len = sensor_list[i]->data_report_execute(buffer + FLASH_MESSAGE_OFFSET , sizeof(buffer) - FLASH_MESSAGE_OFFSET); if (!this->pause_mode && (data_len > 0)) { all_sensors_disabled = false; if ((flashFileHandle != NULL) && (recordingStarted)) { if(data_len + FLASH_MESSAGE_OFFSET != ds_queue_flash_->item_size) { printf("Reinit item size: %d\r\n", data_len); queue_update_items_size(ds_queue_flash_, (data_len+ FLASH_MESSAGE_OFFSET)); queue_update_items_size(ds_queue_fill_, (data_len+ FLASH_MESSAGE_OFFSET)); } //set stream type buffer[0] = stream_type; // enqueue data ret = enqueue(ds_queue_fill_, buffer); if(ret != 0) { printf("enqueue has failed %d\r\n", ds_queue_fill_->num_item); } if(queue_is_full(ds_queue_fill_)) { swap_queues(); } } if (BLE::Instance().gap().getState().connected & !recordingStarted) { ds_console_interface_exists_ = false; BLE_Icarus_AddtoQueue((uint8_t *)buffer, (int32_t)sizeof(buffer), data_len); } if (ds_console_interface_exists_ & !recordingStarted){ if(sensor_list[0]->AsciiEn){ m_USB->printf(buffer); } else{ m_USB->writeBlock((uint8_t*)buffer, data_len); } } data_len = 0; } } if(all_sensors_disabled) handle_file_close(); } void DSInterface::set_fw_version(const char* version) { if (version && *version){ firmware_version = version; algo_desc_strsz = get_fw_algorithms(); } } int DSInterface::get_fw_algorithms( void ) { int i, fwToReport; char *start, *end; uint8_t fwIdx[3]; start = (char*) firmware_version; /*MYG: no need to optimize ,lib function call, just called once at start of execution*/ fwIdx[0] = (uint8_t) strtol(start,&end, 10) ; start = end; fwIdx[1] = (uint8_t) strtol(start+1,&end, 10); start = end; fwIdx[2] = (uint8_t) strtol(start+1,&end, 10); fwToReport = -1; for( i = 0 ; i < sizeof(HUB_FW_TABLE)/ sizeof(fw_type_t); i++ ){ if( HUB_FW_TABLE[i].fwVersion[0] == fwIdx[0]/* & HUB_FW_TABLE[i].fwVersion[1] == fwIdx[1] & HUB_FW_TABLE[i].fwVersion[2] == fwIdx[2] */) { fwToReport = i; break; } } if(fwToReport == -1){ return -1; } i = ((fwToReport == -1)? 0:1) * ( /*32 bit*/ 32 - __builtin_clz(HUB_FW_TABLE[fwToReport].enAlgoDescBitField)); strcpy(&algo_desc_string[0], " fw_algos="); int tail = strlen(" fw_algos="); int descStrSz = sizeof(algo_desc_string); while(--i && tail < descStrSz) { if( (HUB_FW_TABLE[fwToReport].enAlgoDescBitField >> i) & 0x0001) { strcpy( &algo_desc_string[tail], ActivAlgoInfo[i]); tail += strlen(ActivAlgoInfo[i]); } } strcpy( &algo_desc_string[tail-1]," "); return tail; //m_USB->printf("%d %s \r\n", tail , algo_desc_string); } void DSInterface::set_fw_platform(const char* platform) { if (platform && *platform) platform_name = platform; }