![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
repo time
Dependencies: mbed MAX14720 MAX30205 USBDevice
HspGuiSourceV301/HSPGui/Presenter/DataLogPresenter.cs
- Committer:
- darienf
- Date:
- 2021-04-06
- Revision:
- 20:6d2af70c92ab
File content as of revision 20:6d2af70c92ab:
/******************************************************************************* * Copyright (C) 2016 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. ******************************************************************************* */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using RPCSupport.Streaming; using HealthSensorPlatform.Model; using HealthSensorPlatform.View; using HealthSensorPlatform.CustomControls; namespace HealthSensorPlatform.Presenter { class DataLogPresenter { IDataLogModel model; DataLoggingView view; IRawFileLogView temperatureLog1; IRawFileLogView temperatureLog2; IRawFileLogView pressureLog; IRawFileLogView accelerometerLog; IRawFileLogView opticalLog; IRawFileLogView ecgLog; IRawFileLogView bioZLog; IRawFileLogView paceLog; IRawFileLogView rToRLog; IFormView formView; StatusForm statusForm; EcgView ecgView; // Needed to obtain some state information, should be decoupled later and use from data log model OpticalView opticalView; int count = 0; int bioZCount = 0; int ppgCount = 0; int accelCount = 0; PaceData paceData; RToRCalculator rToRCalculator; bool rToRFirst = true; string logFileDirectory = null; View.FileLogView.FileLogHeader fileLogHeader = new View.FileLogView.FileLogHeader(); public DataLogPresenter(IFormView formView, EcgView ecgView, OpticalView opticalView, IDataLogModel model, DataLoggingView view, IRawFileLogView temperatureLog1, IRawFileLogView temperatureLog2, IRawFileLogView pressureLog, IRawFileLogView accelerometerLog, IRawFileLogView opticalLog, IRawFileLogView ecgLog, IRawFileLogView bioZLog, IRawFileLogView paceLog, IRawFileLogView rToRLog) { this.model = model; this.view = view; this.formView = formView; this.ecgView = ecgView; this.opticalView = opticalView; this.temperatureLog1 = temperatureLog1; this.temperatureLog2 = temperatureLog2; this.pressureLog = pressureLog; this.accelerometerLog = accelerometerLog; this.opticalLog = opticalLog; this.ecgLog = ecgLog; this.bioZLog = bioZLog; this.paceLog = paceLog; this.rToRLog = rToRLog; view.LogDownloadStart += new EventHandler<EventArgs>(OnLogDownloadStart); view.MissionWrite += new EventHandler<EventArgs>(OnMissionWrite); view.MissionRead += new EventHandler<EventArgs>(OnMissionRead); view.MissionErase += new EventHandler<EventArgs>(OnMissionErase); model.LogData += new EventHandler<PartialArrayIntAvailableEventArgs>(OnLogData); } public void ProcessTemperature1(int[] data) { double[] calcTemp; calcTemp = CalculateTemperature(data); temperatureLog1.DisplayTemperature(data, calcTemp); } public void ProcessTemperature2(int[] data) { double[] calcTemp; calcTemp = CalculateTemperature(data); temperatureLog2.DisplayTemperature(data, calcTemp); } public double[] CalculateTemperature(int[] data) { double[] calcTemp = new double[data.Length]; int rawCode; for (int i = 0; i < data.Length; i++ ) { rawCode = data[i]; if (rawCode > 0x7fff) rawCode -= 0x10000; calcTemp[i] = rawCode / Math.Pow(2, 8); } return calcTemp; } public void ProcessPressure(int[] data) { int[] rawTemp = new int[data.Length/2]; int[] rawPress = new int[data.Length/2]; double[] calcTemp, calcPress; for (int i = 0, j = 0; i < data.Length; i = i + 2, j++) { rawTemp[j] = data[i]; rawPress[j] = data[i + 1]; } var result = CalculatePressure(rawTemp, rawPress); calcTemp = result.Item1; calcPress = result.Item2; pressureLog.DisplayPressure(rawTemp, calcTemp, rawPress, calcPress); } public Tuple<double[], double[]> CalculatePressure(int[] temperature, int[] pressure) { double[] calcTemp = new double[temperature.Length]; double[] calcPress = new double[pressure.Length]; for (int i = 0; i < temperature.Length; i++ ) { calcTemp[i] = temperature[i] / 10.0; } for (int i = 0; i < pressure.Length; i++ ) { calcPress[i] = pressure[i] / 10; } return new Tuple<double[],double[]>(calcTemp, calcPress); } private void OnLogDownloadStart(object sender, EventArgs e) { if (view.Connected) { count = 0; bioZCount = 0; ppgCount = 0; accelCount = 0; missionRead(); if (model.MissionSettings.Enable) { if (selectFile()) { string missionString; StringBuilder sb = new StringBuilder(); foreach (string str in model.MissionString()) { sb.Append("% "); sb.Append(str); sb.Append(Environment.NewLine); } missionString = sb.ToString().Trim(Environment.NewLine.ToCharArray()); if (temperatureLog1 != null && temperatureLog1.Enable) { temperatureLog1.WriteLine(missionString); temperatureLog1.WriteLine(fileLogHeader.Temperature1); } if (temperatureLog2 != null && temperatureLog2.Enable) { temperatureLog2.WriteLine(missionString); temperatureLog2.WriteLine(fileLogHeader.Temperature2); } if (pressureLog != null && pressureLog.Enable) { pressureLog.WriteLine(missionString); pressureLog.WriteLine(fileLogHeader.Pressure); } if (accelerometerLog != null && accelerometerLog.Enable) { accelerometerLog.WriteLine(missionString); accelerometerLog.WriteLine(fileLogHeader.Accelerometer); } if (opticalLog != null && opticalLog.Enable) { opticalLog.WriteLine(missionString); opticalLog.WriteLine(fileLogHeader.Optical); } if (ecgLog != null && ecgLog.Enable) { ecgLog.WriteLine(missionString); ecgLog.WriteLine(fileLogHeader.Ecg); } if (bioZLog != null && bioZLog.Enable) { bioZLog.WriteLine(missionString); bioZLog.WriteLine(fileLogHeader.BioZ); } if (rToRLog != null && rToRLog.Enable && ecgLog.Enable) { rToRLog.WriteLine(missionString); rToRCalculator = new RToRCalculator(ecgView.MasterClockField, view.EcgArgs.Rate, view.EcgArgs.Dlpf, view.RToRArgs.Wndw); rToRLog.WriteLine(fileLogHeader.RToR); } else if (rToRLog != null && rToRLog.Enable) { rToRLog.WriteLine(missionString); rToRCalculator = null; rToRLog.WriteLine(fileLogHeader.RToR); } if (paceLog != null && paceLog.Enable) { paceLog.WriteLine(missionString); paceLog.WriteLine(fileLogHeader.Pace); } statusForm = new StatusForm(); statusForm.Text = "Flash Download"; statusForm.Message = "Please wait while your data is saved to your file."; statusForm.Show(); model.Start(); } } } } private void LogDownloadStop() { if (temperatureLog1 != null && temperatureLog1.Enable) temperatureLog1.Enable = false; if (temperatureLog2 != null && temperatureLog2.Enable) temperatureLog2.Enable = false; if (pressureLog != null && pressureLog.Enable) pressureLog.Enable = false; if (accelerometerLog != null && accelerometerLog.Enable) accelerometerLog.Enable = false; if (opticalLog != null && opticalLog.Enable) opticalLog.Enable = false; if (ecgLog != null && ecgLog.Enable) ecgLog.Enable = false; if (bioZLog != null && bioZLog.Enable) bioZLog.Enable = false; if (rToRLog != null && rToRLog.Enable) rToRLog.Enable = false; if (paceLog != null && paceLog.Enable) paceLog.Enable = false; formView.MessageInfo("File save complete"); statusForm.Hide(); } private void OnLogData(object sender, PartialArrayIntAvailableEventArgs e) { switch(e.reportID) { case PartialArrayIntAvailableEventArgs.PACKET_BMP280_PRESSURE: if (pressureLog != null && pressureLog.Enable) ProcessPressure(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX31725_TEMP1: if (temperatureLog1 != null && temperatureLog1.Enable) ProcessTemperature1(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX31725_TEMP2: if (temperatureLog2 != null && temperatureLog2.Enable) ProcessTemperature2(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_ECG: if (ecgLog != null && ecgLog.Enable) ProcessEcg(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_BIOZ: if (bioZLog != null && bioZLog.Enable) ProcessBioZ(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_PACE: if (paceLog != null && paceLog.Enable) paceData = new PaceData(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_RTOR: if (rToRLog != null && rToRLog.Enable) ProcessRToR(e.array1[0]); break; case PartialArrayIntAvailableEventArgs.PACKET_LIS2DH: case PartialArrayIntAvailableEventArgs.PACKET_LSM6DS3_ACCEL: if (accelerometerLog != null && accelerometerLog.Enable) ProcessAccelerometer(e.array1, e.array2, e.array3); break; case PartialArrayIntAvailableEventArgs.PACKET_END_OF_STREAM: LogDownloadStop(); break; } if ((e.reportID & 0xF0) == PartialArrayIntAvailableEventArgs.PACKET_MAX30101) { if (opticalLog != null && opticalLog.Enable) ProcessOptical(e.array1, e.array2, e.array3); } } private void OnMissionWrite(object sender, EventArgs e) { if (view.Connected) { if (view.EnableAccelerometer || view.EnableBioz || view.EnableEcg || view.EnableOpticalHR || view.EnableOpticalMulti || view.EnableOpticalSpO2 || view.EnablePace || view.EnablePressure || view.EnableRToR || view.EnableTemperature1 || view.EnableTemperature2) { if (view.ValidateGuiElements()) { statusForm = new StatusForm(); statusForm.Message = "Please wait while your flash log is cleared and new parameters are written. Do not unplug the USB connection or press start button on the board until write is complete."; statusForm.Show(); formView.MessageInfo("Writing in progress..."); model.MissionErase(); model.EraseWrittenSectors(); model.MissionStartDefinition(); view.ProcessGuiElements(); //rpcClient.DataLogging.Test(); model.MissionWrite(); statusForm.Hide(); formView.MessageInfo("Write parameters complete"); } else formView.MessageInfo("Incorrect logging parameters"); } else { formView.MessageInfo("No devices selected"); } } } private void OnMissionRead(object sender, EventArgs e) { if (view.Connected) { missionRead(); } } private void OnMissionErase(object sender, EventArgs e) { if (view.Connected) { model.MissionErase(); formView.MessageInfo("Erase parameters complete"); } } private void OnLogFileEnable(object sender, EnableEventArgs e) { // Not used } private bool selectFile() { bool result = false; Mission settings = model.MissionSettings; if (settings.EnableEcg) result |= selectLogFileName(ecgLog, "hsp-log-ecg"); if (settings.EnablePace) result |= selectLogFileName(paceLog, "hsp-log-pace"); if (settings.EnableBioZ) result |= selectLogFileName(bioZLog, "hsp-log-bioz"); if (settings.EnableRToR) result |= selectLogFileName(rToRLog, "hsp-log-rtor"); if (settings.EnableOpticalHR || settings.EnableOpticalMulti || settings.EnableOpticalSpO2) result |= selectLogFileName(opticalLog, "hsp-log-optical"); if (settings.EnableTemperature1) result |= selectLogFileName(temperatureLog1, "hsp-log-temperature1"); if (settings.EnableTemperature2) result |= selectLogFileName(temperatureLog2, "hsp-log-temperature2"); if (settings.EnablePressure) result |= selectLogFileName(pressureLog, "hsp-log-barometer"); if (settings.EnableAccelerometer) result |= selectLogFileName(accelerometerLog, "hsp-log-accelerometer"); return result; } bool selectLogFileName(IRawFileLogView log, string name) { bool result; if (logFileDirectory != null) log.FileDirectory = logFileDirectory; result = log.SelectCSVFile(name); log.Enable = result; if (result) logFileDirectory = log.FileDirectory; return result; } private void missionRead() { model.MissionRead(); view.UpdateGuiElements(model.MissionSettings); if (model.MissionSettings.Enable) formView.MessageInfo("Read complete"); else formView.MessageInfo("No parameters defined"); } void ProcessBioZ(int[] rawData) { BioZFifo[] bioZFifo; double[] time = new double[rawData.Length]; double sampleRate = ecgView.SampleRateBioZ; bioZFifo = ConvertBioZ(rawData); for (int i = 0; i < time.Length; i++ ) { time[i] = bioZCount / (double)sampleRate; bioZCount++; } bioZLog.DisplayBioZ(time, bioZFifo); } public BioZFifo[] ConvertBioZ(int[] data) { BioZFifo[] impedance = new BioZFifo[data.Length]; //EcgView.ChartInfo chartInfo = BioZInfo(); EcgView.ChartInfo chartInfo = ecgView.BioZInfo; int dataShift; for (int i = 0; i < data.Length; i++) { dataShift = data[i] >> chartInfo.Shift; // Two's Complement Conversions if (dataShift > chartInfo.Threshold) { dataShift -= chartInfo.Offset; } // 1.9734 = 1/2^19 * 1e-6 impedance[i].Data = dataShift * 1.9073486328125 / (chartInfo.Gain * ((chartInfo.CurrentGenerator == 0) ? 1 : chartInfo.CurrentGenerator)); impedance[i].Code = data[i]; impedance[i].BioZData = dataShift; impedance[i].BTag = data[i] & 0x07; } return impedance; } public EcgView.ChartInfo BioZInfo() { EcgView.ChartInfo info = new EcgView.ChartInfo(); int[] currentGen = new int[] {1, 8, 16, 32, 48, 64, 80, 96}; int[] gain = new int[] {20, 40, 80, 160}; info.Shift = 4; info.Offset = 0x100000; info.Threshold = 0x100000; info.Gain = gain[model.MissionSettings.BioZArgs[10]]; info.CurrentGenerator = currentGen[model.MissionSettings.BioZArgs[15]]; return info; } void ProcessEcg(int[] rawData) { EcgFifo[] ecgFifo; double[] ecgVoltage = new double[rawData.Length]; double[] timeSecond = new double[rawData.Length]; double ecgRate = ecgView.SampleRateEcg; ecgFifo = ConvertEcg(rawData); for (int i = 0; i < ecgFifo.Length; i++) { timeSecond[i] = count / ecgRate; // Look for Pace Events if (paceLog.Enable) { //for (int j = 0; j < ecgFifo.Length; j++) //{ if (ecgFifo[i].PTag != 7) { PaceData.PaceRegister paceRegister = paceData.PaceGroup(ecgFifo[i].PTag); List<double> timeMillsecondPace = new List<double>(); List<PaceData.PaceEdge> paceEdges = new List<PaceData.PaceEdge>(); for (int k = 0; k < 6; k++) { PaceData.PaceEdge edge = paceRegister.Edge[k]; timeMillsecondPace.Add(count / ecgRate + ConvertPace(edge.Data)); paceEdges.Add(edge); if (edge.Last == true) break; } paceLog.DisplayPace(timeMillsecondPace.ToArray(), paceEdges.ToArray()); System.Diagnostics.Debug.Print("ECG PTag = " + ecgFifo[i].PTag); } //} } count++; } ecgLog.DisplayEcg(timeSecond, ecgFifo); } public EcgFifo[] ConvertEcg(int[] data) { EcgFifo[] voltage = new EcgFifo[data.Length]; //EcgView.ChartInfo chartInfo = EcgInfo(); EcgView.ChartInfo chartInfo = ecgView.EcgInfo; int dataShift; for (int i = 0; i < data.Length; i++) { dataShift = data[i] >> chartInfo.Shift; // Two's Complement Conversions if (dataShift > chartInfo.Threshold) { dataShift -= chartInfo.Offset; } voltage[i].Data = 1000 * 7.62939453125e-6 * dataShift / chartInfo.Gain; voltage[i].EcgData = dataShift; voltage[i].Code = data[i]; voltage[i].PTag = data[i] & 0x07; voltage[i].ETag = (data[i] >> 3) & 0x07; } return voltage; } public EcgView.ChartInfo EcgInfo() { EcgView.ChartInfo info = new EcgView.ChartInfo(); int[] gain = new int[] {20, 40, 80, 160}; info.Shift = 6; info.Threshold = 0x1ffff; info.Offset = 0x40000; info.Gain = gain[model.MissionSettings.EcgArgs[10]]; return info; } public double ConvertRToR(int data) { return ecgView.TimeResolution * 1000 * data * 512; } public double ConvertPace(int data) { return data * ecgView.TimeResolution; } public string PaceRegisterGroupToString(PaceData.PaceRegister paceRegister) { StringBuilder paceRegisterLogBuilder = new StringBuilder(); for (int j = 0; j < 6; j++) { paceRegisterLogBuilder.Append(paceRegister.Edge[j].Data / (2 * ecgView.MasterClockFrequency)); paceRegisterLogBuilder.Append(", "); paceRegisterLogBuilder.Append(paceRegister.Edge[j].Polarity ? 'R' : 'F'); paceRegisterLogBuilder.Append(", "); paceRegisterLogBuilder.Append(paceRegister.Edge[j].Last ? 'Y' : 'N'); paceRegisterLogBuilder.Append(", "); } return paceRegisterLogBuilder.ToString(); } void ProcessRToR(int data) { if (rToRCalculator != null) { if (rToRFirst) { rToRLog.DisplayRToR(data, rToRCalculator.Corrected(data, true) / 1000); rToRFirst = false; } else rToRLog.DisplayRToR(data, rToRCalculator.Corrected(data, false) / 1000); } else { rToRLog.DisplayRToR(data, 0); } } public void ProcessOptical(int[] red, int[] ir, int[] green) { int sampleRate = opticalView.OpticalSampleRate; double[] time = new double[red.Length]; for (int i = 0; i < time.Length; i++ ) { time[i] = ppgCount / (double)sampleRate; ppgCount++; } opticalLog.DisplayPpg(time, new int[][] { red, ir, green }); } public void ProcessAccelerometer(int[] x, int[] y, int[] z) { int sampleRate = view.AccelSampleRate; double[] time = new double[x.Length]; for (int i = 0; i < time.Length; i++) { time[i] = accelCount / (double)sampleRate; accelCount++; } accelerometerLog.DisplayXYZ(time, new int[][] { x, y, z }); } } }