![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
repo time
Dependencies: mbed MAX14720 MAX30205 USBDevice
HspGuiSourceV301/HSPGui/Presenter/RawFileLogPresenter.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 HealthSensorPlatform.View; using HealthSensorPlatform.Model; using HealthSensorPlatform.CustomControls; using RPCSupport; using RPCSupport.Streaming; namespace HealthSensorPlatform.Presenter { public class RawFileLogPresenter { IRawFileLogView ecgLog; IRawFileLogView bioZLog; IRawFileLogView rToRLog; IRawFileLogView paceLog; IFormView formView; IEcgView ecgView; bool fileLog = false; // user enabled file logging bool streaming = false; // streaming data or flash log data, only save data from streaming //bool flashLog = false; IDataLoggingView dataLogView; PaceData paceData; RToRCalculator rToRCalculator; bool rToRFirst = true; // received first RR value for offset correction //bool ecgLeadOff; // DC Lead off data for ECG or BioZ Channel DCLeadOff leadOff; // lead off status bits ACLeadOff acLeadOff; // bioz lead off status bits int count = 0; int bioZCount = 0; //int ppgCount = 0; //int accelCount = 0; string logFileDirectory = null; View.FileLogView.FileLogHeader fileLogHeader = new View.FileLogView.FileLogHeader(); public RawFileLogPresenter(IRawFileLogView ecg, IRawFileLogView bioZ, IRawFileLogView rToR, IRawFileLogView pace, IFormView formView, RPCClient rpcClient, IEcgView ecgView, IDataLoggingView dataLogView) { this.ecgLog = ecg; this.bioZLog = bioZ; this.rToRLog = rToR; this.paceLog = pace; this.formView = formView; this.ecgView = ecgView; this.dataLogView = dataLogView; formView.FileLogEnable += new EventHandler<EnableEventArgs>(OnLogFileEnable); ecgView.StreamingStartStop += new EventHandler<StreamingStartStopEventArgs>(OnStreamStart); //dataLogView.LogDownloadStart += new EventHandler<EventArgs>(OnLogDownloadStart); rpcClient.streaming.PartialArrayIntAvailable += new EventHandler<PartialArrayIntAvailableEventArgs>(OnStreamData); } public void OnLogFileEnable(object sender, EnableEventArgs e) { fileLog = e.Enable; if (e.Enable) { bool result = false; IRawFileLogView log = ecgLog; string filePrefixName = String.Empty; switch(e.Stream) { case StreamType.Ecg: log = ecgLog; filePrefixName = "hsp-ecg"; break; case StreamType.RToR: log = rToRLog; filePrefixName = "hsp-rtor"; break; case StreamType.Pace: log = paceLog; filePrefixName = "hsp-pace"; break; case StreamType.BioZ: log = bioZLog; filePrefixName = "hsp-bioz"; break; } if (logFileDirectory != null) // Set starting directory to be the same as the last log.FileDirectory = logFileDirectory; result = log.SelectCSVFile(filePrefixName); log.Enable = result; if (result) // Save directory if success logFileDirectory = log.FileDirectory; formView.LogFileItem(e.Stream, result); } else { switch (e.Stream) { case StreamType.Ecg: ecgLog.Enable = false; break; case StreamType.RToR: rToRLog.Enable = false; break; case StreamType.Pace: paceLog.Enable = false; break; case StreamType.BioZ: bioZLog.Enable = false; break; } formView.LogFileItem(e.Stream, false); } } public void OnStreamStart(object sender, StreamingStartStopEventArgs e) { streaming = e.state; count = 0; bioZCount = 0; if (e.state) { leadOff = new DCLeadOff { NegativeHigh = false, NegativeLow = false, PostiveHigh = false, PostiveLow = false }; acLeadOff = new ACLeadOff { BioZOverRange = false, BioZUnderRange = false }; if (ecgLog != null && ecgLog.Enable && ecgView.EnableECG) { //ecgLog.WriteLine("% " + ecgView.HspSetting.EcgSettingString()); // TODO: What is the requirement for headers ecgLog.WriteLine(fileLogHeader.Ecg); } if (bioZLog != null && bioZLog.Enable && ecgView.EnableBioZ) { //ecgLog.WriteLine("% " + ecgView.HspSetting.BioZSettingString()); bioZLog.WriteLine(fileLogHeader.BioZ); } if (rToRLog != null && rToRLog.Enable && ecgView.EnableRToR) { rToRLog.WriteLine(fileLogHeader.RToR); rToRCalculator = new RToRCalculator(ecgView.MasterClockField, ecgView.EcgArgs.Rate, ecgView.EcgArgs.Dlpf, ecgView.RToRArgs.Wndw); } if (paceLog != null && paceLog.Enable && ecgView.EnablePace) { paceLog.WriteLine(fileLogHeader.Pace); } } else { if (ecgLog != null) ecgLog.Enable = false; if (bioZLog != null) bioZLog.Enable = false; if (rToRLog != null) rToRLog.Enable = false; if (paceLog != null) paceLog.Enable = false; } } void fileLogStop() { fileLog = false; stop(); } void stop() { if (ecgLog != null && ecgLog.Enable) ecgLog.Enable = false; if (rToRLog != null && rToRLog.Enable) rToRLog.Enable = false; if (paceLog != null && paceLog.Enable) paceLog.Enable = false; if (bioZLog != null && bioZLog.Enable) bioZLog.Enable = false; formView.LogFileItem(StreamType.Ecg, false); formView.LogFileItem(StreamType.RToR, false); formView.LogFileItem(StreamType.Pace, false); formView.LogFileItem(StreamType.BioZ, false); } private void OnStreamData(object sender, PartialArrayIntAvailableEventArgs e) { if (streaming) { switch (e.reportID) { case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_ECG: if (ecgLog.Enable) ProcessEcg(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_BIOZ: if (bioZLog.Enable) ProcessBioZ(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_PACE: if (paceLog.Enable) paceData = new PaceData(e.array1); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_RTOR: if (rToRLog.Enable) ProcessRToR(e.array1[0]); break; case PartialArrayIntAvailableEventArgs.PACKET_END_OF_STREAM: fileLogStop(); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_LEADOFF_DC: ProcessLeadOff(e.array1[0]); break; case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_LEADOFF_AC: ProcessACLeadOff(e.array1[0]); break; } } } void ProcessBioZ(int[] rawData) { BioZFifo[] bioZFifo; double sampleRate = ecgView.SampleRateBioZ; double[] time = new double[rawData.Length]; bioZFifo = ConvertBioZ(rawData); for (int i = 0; i < time.Length; i++) { time[i] = bioZCount / sampleRate; bioZCount++; } if (ecgView.EnableDCLeadOff == false && ecgView.EnableBioZOverUnderRange == true) bioZLog.DisplayBioZ(time, bioZFifo, acLeadOff); else if (ecgView.EnableDCLeadOff == true && ecgView.EnableEcgDCLeadOff == false && ecgView.EnableBioZOverUnderRange == false) // && ecgLeadOff == false) bioZLog.DisplayBioZ(time, bioZFifo, leadOff); else if (ecgView.EnableDCLeadOff == true && ecgView.EnableEcgDCLeadOff == false && ecgView.EnableBioZOverUnderRange == true) bioZLog.DisplayBioZ(time, bioZFifo, leadOff, acLeadOff); else if ((ecgView.EnableDCLeadOff == false && ecgView.EnableBioZOverUnderRange == false) || ecgView.EnableEcgDCLeadOff == true && ecgView.EnableEcgDCLeadOff == true && ecgView.EnableBioZOverUnderRange == false) bioZLog.DisplayBioZ(time, bioZFifo); } public BioZFifo[] ConvertBioZ(int[] data) { BioZFifo[] impedance = new BioZFifo[data.Length]; 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; } void ProcessEcg(int[] rawData) { EcgFifo[] ecgFifo; double ecgRate = ecgView.SampleRateEcg; double[] ecgVoltage = new double[rawData.Length]; double[] timeSecond = new double[rawData.Length]; 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++; } if (ecgView.EnableDCLeadOff && ecgView.EnableEcgDCLeadOff) ecgLog.DisplayEcg(timeSecond, ecgFifo, leadOff); else ecgLog.DisplayEcg(timeSecond, ecgFifo); } public EcgFifo[] ConvertEcg(int[] data) { EcgFifo[] voltage = new EcgFifo[data.Length]; 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 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 ProcessLeadOff(int data) { /* if (bitShiftMask(data, 8)) // ECG lead off ecgLeadOff = true; else if (bitShiftMask(data, 9)) // BioZ lead off ecgLeadOff = false; */ leadOff = new DCLeadOff() { PostiveHigh = bitShiftMask(data, 3), PostiveLow = bitShiftMask(data, 2), NegativeHigh = bitShiftMask(data, 1), NegativeLow = bitShiftMask(data, 0) }; } void ProcessACLeadOff(int data) { acLeadOff = new ACLeadOff() { BioZUnderRange = bitShiftMask(data, 1), BioZOverRange = bitShiftMask(data, 0), }; } private static bool bitShiftMask(int data, int index) { int state; int mask = 1 << index; state = ((data & mask) == mask) ? 1 : 0; return state == 1; } void ProcessRToR(int data) { if (rToRFirst) { rToRLog.DisplayRToR(data, rToRCalculator.Corrected(data, true) / 1000); rToRFirst = false; } else rToRLog.DisplayRToR(data, rToRCalculator.Corrected(data, false) / 1000); } } }