repo time

Dependencies:   mbed MAX14720 MAX30205 USBDevice

Revision:
20:6d2af70c92ab
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HspGuiSourceV301/HSPGui/Presenter/RawFileLogPresenter.cs	Tue Apr 06 06:41:40 2021 +0000
@@ -0,0 +1,477 @@
+/*******************************************************************************
+* 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);
+        }
+    }
+}