Darien Figueroa / Mbed 2 deprecated repo3

Dependencies:   mbed MAX14720 MAX30205 USBDevice

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers EcgView.cs Source File

EcgView.cs

00001 /*******************************************************************************
00002 * Copyright (C) 2016 Maxim Integrated Products, Inc., All rights Reserved.
00003 * 
00004 * This software is protected by copyright laws of the United States and
00005 * of foreign countries. This material may also be protected by patent laws
00006 * and technology transfer regulations of the United States and of foreign
00007 * countries. This software is furnished under a license agreement and/or a
00008 * nondisclosure agreement and may only be used or reproduced in accordance
00009 * with the terms of those agreements. Dissemination of this information to
00010 * any party or parties not specified in the license agreement and/or
00011 * nondisclosure agreement is expressly prohibited.
00012 *
00013 * The above copyright notice and this permission notice shall be included
00014 * in all copies or substantial portions of the Software.
00015 *
00016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
00017 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
00018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
00019 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
00020 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
00021 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
00022 * OTHER DEALINGS IN THE SOFTWARE.
00023 *
00024 * Except as contained in this notice, the name of Maxim Integrated
00025 * Products, Inc. shall not be used except as stated in the Maxim Integrated
00026 * Products, Inc. Branding Policy.
00027 *
00028 * The mere transfer of this software does not imply any licenses
00029 * of trade secrets, proprietary technology, copyrights, patents,
00030 * trademarks, maskwork rights, or any other form of intellectual
00031 * property whatsoever. Maxim Integrated Products, Inc. retains all
00032 * ownership rights.
00033 *******************************************************************************
00034 */
00035 
00036 //#define CES_DEMO
00037 //#define FILE_LOG
00038 
00039 using System;
00040 using System.Collections.Generic;
00041 using System.ComponentModel;
00042 using System.Drawing;
00043 using System.Data;
00044 using System.Linq;
00045 using System.Text;
00046 using System.Windows.Forms;
00047 using System.Windows.Forms.DataVisualization.Charting;
00048 using RPCSupport.Streaming;
00049 using RPCSupport.Devices;
00050 
00051 using HealthSensorPlatform.View;
00052 using HealthSensorPlatform.Presenter;
00053 using HealthSensorPlatform.Model;
00054 
00055 #if CES_DEMO
00056 using System.Collections;
00057 #endif
00058 
00059 // DEBUG
00060 using System.IO;
00061 
00062 
00063 namespace HealthSensorPlatform.CustomControls
00064 {
00065     public partial class EcgView : UserControl, IDeviceView, IEcgView
00066     {
00067         /* Constants */
00068         const int Rbias_FMSTR_Init = 0;
00069         const int CAL_init = 1;
00070         const int ECG_InitStart = 2;
00071         const int PACE_InitStart = 3;
00072         const int BIOZ_InitStart = 4;
00073         const int ECGFast_Init = 5;
00074         const int RtoR_InitStart = 6;
00075 
00076         const int RToRMaxValue = 0x3FFF;
00077 
00078 #if CES_DEMO
00079         const int[] averageOptions = new int[] { 1, 2, 4, 8, 10 };
00080 #endif
00081 
00082         /* Fields */
00083         public InitArgs.RbiasInit rbiasInit;
00084         public InitArgs.EcgInitStart ecgArgs;
00085         public InitArgs.EcgFastInit ecgFastArgs;
00086         public InitArgs.PACEInitStart paceArgs;
00087         public InitArgs.BIOZInitStart biozArgs;
00088         public InitArgs.RToRInitStart rtorArgs;
00089         public InitArgs.CalInitStart calArgs;
00090 
00091         public GetEcgInitArgs GetEcgInitArgsPointer;
00092         public GetRToRInitArgs GetRToRInitArgsPointer;
00093         public GetBioZInitArgs GetBioZInitArgsPointer;
00094         public GetPaceInitArgs GetPaceInitArgsPointer;
00095 
00096         /// <summary>
00097         /// Number of R To R points which need to be removed from the chart
00098         /// </summary>
00099         int rToRRemoveOffset;
00100 
00101         long lastRToRTime;
00102 
00103         double timeResolution = 0.00001525878; 
00104 
00105         double[] clockFreq = { 32768, 32000, 32000, 32768 * 640 / 656 }; // 31968.7804878 = 32768 * 640 / 656
00106 
00107         int frequencyMasterField = 0;
00108 
00109         public double masterClockFrequency = 32768;
00110 
00111 #if CES_DEMO
00112         public int AverageECG = 1;
00113 #endif
00114 
00115         private RPCSupport.RPCClient rpcClient;
00116         private bool connected = false;
00117         //private bool stream = true;
00118 
00119         /// <summary>
00120         /// Use to scale the bioZ chart data to milliohm range
00121         /// </summary>
00122         private int bioZRangeMultiplier = 1;
00123 
00124         bool startedCal = false;
00125         bool startedEcg = false;
00126         bool startedPace = false;
00127         bool startedBioz = false;
00128         bool startedRtoR = false;
00129 
00130         private bool enableECG = false;
00131         private bool enableRToR = false;
00132         private bool enableBioZ = false;
00133         private bool enablePace = false;
00134 
00135         int rToRInterval = -1;
00136 
00137         ChartInfo ecgInfo;
00138         ChartInfo rToRInfo;
00139         ChartInfo bioZInfo; 
00140         ChartInfo paceInfo;
00141 
00142         Queue<int> paceTag = new Queue<int>();
00143         public PaceData paceData; // TODO: public for testing only
00144         RToRCalculator rToRCalculator;
00145 
00146         List<double> heartRateList = new List<double>(10);
00147 
00148         /* CES DEMO average feature, normal operation average is 1 */
00149         //int averageEcgCount = 0;
00150         //int averageEcgSum = 0;
00151 
00152         StringBuilder fileLogData = new StringBuilder();
00153 
00154         int[, ,] ecgDecimationDelay = new int[,,] { {{650, 1034}, {2922, 3690}, {3370, 4906}, {3370, 4906}}, 
00155                                                     {{650, 1034}, {2922, 3690}, {3370, 4906}, {3370, 4906}},
00156                                                     {{1242, 2202}, {1242, 2202}, {1242, 2202}, {1242, 2202}},
00157                                                     {{1242, 2202}, {1242, 2202}, {1242, 2202}, {1242, 2202}}
00158                                                   };
00159 
00160         public int RToRWindowField = 0;
00161         
00162 #if CES_DEMO
00163         FirFilter hpf;
00164 #endif
00165 
00166 #if FILE_LOG
00167         // DEBUG
00168         StreamWriter file; //= new StreamWriter("hsp_ecg_output_data.csv");
00169 #endif
00170 
00171         /* Constructor */
00172         public EcgView()
00173         {
00174             InitializeComponent();
00175 
00176             //paceInfo = ecgInfo;
00177 
00178             /*foreach(int item in averageOptions)
00179             {
00180                 cboAverageEcg.Items.Add(item.ToString());
00181             }*/
00182             //cboAverageEcg.SelectedIndex = 0;
00183             //cboMaxScale.SelectedIndex = 1;
00184 
00185             chartRtoR.ChartAreas[0].AxisY.Maximum = 100;
00186 
00187             ecgInfo = new ChartInfo
00188             {
00189                 SampleRate = 128, // Power on defaults for ECG
00190                 Length = 10,
00191                 Average = 1,
00192                 Shift = 6,
00193                 Gain = 20,
00194                 // ECG is 18 bits, with MSB as sign bit
00195                 Threshold = 0x1ffff,
00196                 Offset = 0x40000,
00197                 Chart = chartECG,
00198                 SeriesName = "Series",
00199             };
00200             rToRInfo = new ChartInfo
00201             {
00202                 SampleRate = 128,
00203                 Length = 10,
00204                 Chart = chartECG,
00205                 SeriesName = "SeriesRToR",
00206             };
00207             bioZInfo = new ChartInfo
00208             {
00209                 SampleRate = 64,
00210                 Length = 10,
00211                 Shift = 4,
00212                 Gain = 20,
00213                 // BioZ is 20 bits, with MSB as sign bit
00214                 Threshold = 0x7ffff,
00215                 Offset = 0x100000,
00216                 Chart = chartBioz,
00217                 SeriesName = "Series",
00218             };
00219             paceInfo = new ChartInfo
00220             {
00221                 SampleRate = 65536 * ecgInfo.SampleRate, // 2 * fMSTR
00222                 Length = 10,
00223                 Average = 1,
00224                 Shift = 0, // Keep tag info
00225                 Chart = chartECG,
00226                 SeriesName = "SeriesPace",
00227             };
00228 
00229             NamedImage paceFalling = new NamedImage("PaceFallingImage", HealthSensorPlatform.Properties.Resources.pace_falling);
00230             chartECG.Images.Add(paceFalling);
00231             NamedImage paceRising = new NamedImage("PaceRisingImage", HealthSensorPlatform.Properties.Resources.pace_rising);
00232             chartECG.Images.Add(paceRising);
00233 #if CES_DEMO
00234             //grpAverage.Visible = true;
00235 
00236             hpf = new FirFilter();
00237             //cboEcgHpf.SelectedIndex = 0;
00238 #endif
00239         }
00240 
00241         /* Delegates */
00242         public delegate InitArgs.EcgInitStart GetEcgInitArgs();
00243         public delegate InitArgs.RToRInitStart GetRToRInitArgs();
00244         public delegate InitArgs.BIOZInitStart GetBioZInitArgs();
00245         public delegate InitArgs.PACEInitStart GetPaceInitArgs();
00246         //public delegate void StreamingStartStopEventHandler(StreamingStartStopEventArgs e);
00247 
00248         /* Events */
00249         /// <summary>
00250         /// Streaming event 
00251         /// </summary>
00252         public event EventHandler<StreamingStartStopEventArgs> StreamingStartStop;
00253 
00254         /* Enums */
00255         public enum StreamDataType
00256         {
00257             Ecg,
00258             RToR,
00259             Pace,
00260             BioZ
00261         };
00262 
00263         /* Properties */
00264         public RPCSupport.RPCClient RPCClient
00265         {
00266             set
00267             {
00268                 rpcClient = value;
00269                 //streamHandler = new EventHandler<PartialArrayIntAvailableEventArgs>(On_AppendChart);
00270                 //rpcClient.streaming.PartialArrayIntAvailable += streamHandler;
00271             }
00272         }
00273         /*
00274         public bool Stream
00275         {
00276             get
00277             {
00278                 return stream;
00279             }
00280             set
00281             {
00282                 stream = value;
00283                 if (stream == true)
00284                     rpcClient.streaming.PartialArrayIntAvailable += streamHandler;
00285                 else
00286                     rpcClient.streaming.PartialArrayIntAvailable -= streamHandler;
00287             }
00288         }
00289 */
00290         public bool Connected
00291         {
00292             get
00293             {
00294                 return connected;
00295             }
00296             set
00297             {
00298                 connected = value;
00299             }
00300         }
00301         public bool EnableECG
00302         {
00303             get
00304             {
00305                 return enableECG;
00306             }
00307             set
00308             {
00309                 enableECG = value;
00310                 chartECG.Enabled = value;
00311             }
00312         }
00313         public bool EnableRToR
00314         {
00315             get
00316             {
00317                 return enableRToR;
00318             }
00319             set
00320             {
00321                 enableRToR = value;
00322                 chartRtoR.Enabled = value;
00323                 grpBxHeartRate.Enabled = value;
00324             }
00325         }
00326         public bool EnableBioZ
00327         {
00328             get
00329             {
00330                 return enableBioZ;
00331             }
00332             set
00333             {
00334                 enableBioZ = value;
00335                 chartBioz.Enabled = value;
00336             }
00337         }
00338         public bool EnablePace
00339         {
00340             get
00341             {
00342                 return enablePace;
00343             }
00344             set
00345             {
00346                 enablePace = value;
00347                 chartPace.Enabled = value;
00348             }
00349         }
00350         public bool EnableDCLeadOff
00351         {
00352             get
00353             {
00354                 return grpBxDCLeadOff.Enabled;
00355             }
00356             set
00357             {
00358                 grpBxDCLeadOff.Enabled = value;
00359             }
00360 
00361         }
00362         public bool EnableEcgDCLeadOff { get; set; }
00363         public bool EnableBioZOverUnderRange
00364         {
00365             get
00366             {
00367                 return grpBxBioZOverUnderRange.Enabled;
00368             }
00369             set
00370             {
00371                 grpBxBioZOverUnderRange.Enabled = value;
00372             }
00373         }
00374 
00375         public bool BioZMilliOhmRange
00376         {
00377             get
00378             {
00379                 return (bioZRangeMultiplier == 1000);
00380             }
00381 
00382             set
00383             {
00384                 if (value)
00385                 {
00386                     bioZRangeMultiplier = 1000;
00387                     chartBioz.ChartAreas["ChartArea"].AxisY.Title = "Bioz (m‎Ω)";
00388                 }
00389                 else
00390                 {
00391                     bioZRangeMultiplier = 1;
00392                     chartBioz.ChartAreas["ChartArea"].AxisY.Title = "Bioz (‎Ω)";
00393                 }
00394             }
00395         }
00396 
00397         public double SampleRateEcg // Human readable sample rate
00398         {
00399             get
00400             {
00401                 return ecgInfo.SampleRate;
00402             }
00403             set
00404             {
00405                 ecgInfo.SampleRate = value;
00406                 //rToRInfo.SampleRate = value;
00407                 paceInfo.SampleRate = MasterClockFrequency * 2 * value;
00408             }
00409         }
00410         public double SampleRateBioZ // Human readable sample rate
00411         {
00412             get
00413             {
00414                 return bioZInfo.SampleRate;
00415             }
00416             set
00417             {
00418                 bioZInfo.SampleRate = value;
00419             }
00420         }
00421         public int GainECG // Human readable gain
00422         {
00423             get
00424             {
00425                 return ecgInfo.Gain;
00426             }
00427             set
00428             {
00429                 ecgInfo.Gain = value;
00430             }
00431         }
00432         public int GainBioZ // Human readable gain
00433         {
00434             get
00435             {
00436                 return bioZInfo.Gain;
00437             }
00438             set
00439             {
00440                 bioZInfo.Gain = value;
00441             }
00442         }
00443         public int CurrentBioZ // Human readable bioZ current generator magnitude
00444         {
00445             get
00446             {
00447                 return bioZInfo.CurrentGenerator;
00448             }
00449             set
00450             {
00451                 bioZInfo.CurrentGenerator = value;
00452             }
00453         }
00454         /// <summary>
00455         /// This value is t_RES = 1 / (2 * fMSTR) = 1 / (2 * 32768). For R-to-R the LSB time is 512*t_RES, while for
00456         /// PACE, the value is t_RES.
00457         /// </summary>
00458         public double TimeResolution
00459         {
00460             get
00461             {
00462                 return timeResolution;
00463             }
00464         }
00465 
00466         public ChartInfo EcgInfo { get { return ecgInfo; } }
00467         public ChartInfo RToRInfo { get { return rToRInfo; } }
00468         public ChartInfo BioZInfo { get { return bioZInfo; } }
00469         public ChartInfo PaceInfo { get { return paceInfo; } }
00470 
00471         public InitArgs.EcgInitStart EcgArgs { get { return ecgArgs; } }
00472         public InitArgs.RToRInitStart RToRArgs { get { return rtorArgs; } }
00473 
00474         public int MasterClockField { get { return frequencyMasterField; } }
00475         public int FrequencyMasterField
00476         {
00477             get
00478             {
00479                 return frequencyMasterField;
00480             }
00481 
00482             set
00483             {
00484                 frequencyMasterField = value;
00485                 masterClockFrequency = clockFreq[frequencyMasterField];
00486                 paceInfo.SampleRate = 2 * masterClockFrequency;
00487                 rToRInfo.SampleRate = masterClockFrequency / 256.0;
00488                 timeResolution = 1.0 / (2 * masterClockFrequency);
00489             }
00490         }
00491         public double MasterClockFrequency
00492         {
00493             get
00494             {
00495                 return masterClockFrequency;
00496             }
00497             /*
00498             set
00499             {
00500                 masterClockFrequency = value;
00501                 paceInfo.SampleRate = 2 * value;
00502                 TimeResolution = 1 / (2 * value);
00503             }*/
00504         }
00505 
00506         public int EcgDecimationDelay
00507         {
00508             get
00509             {
00510                 int fmstr = frequencyMasterField;
00511                 int ecgRate = ecgArgs.Rate;
00512                 int lpf = ecgArgs.Dlpf > 0 ? 1 : 0;
00513 
00514                 return ecgDecimationDelay[fmstr, ecgRate, lpf];
00515             }
00516         }
00517         public int RToRDelay
00518         {
00519             get
00520             {
00521 
00522                 return 5376 + 3370 + 256 * RToRWindowField;
00523             }
00524         }
00525 
00526         public Chart ChartECG { get { return chartECG; } } // Testing
00527         public IHspSetting HspSetting
00528         {
00529             get;
00530             set;
00531         }
00532 
00533         private void EcgView_Load(object sender, EventArgs e)
00534         {
00535             InitChart();
00536         }
00537 
00538         String ValueToBits(int value, int width)
00539         {
00540             String str = "";
00541             String val = "";
00542             int mask = 1;
00543             for (int i = 0; i < width; i++)
00544             {
00545                 if ((mask & value) == mask)
00546                 {
00547                     val = "1";
00548                 }
00549                 else
00550                 {
00551                     val = "0";
00552                 }
00553                 mask = mask << 1;
00554                 str = val + str;
00555             }
00556             return str;
00557         }
00558 
00559         String[] ValueToBitStringArray(int width)
00560         {
00561             List<String> stringList = new List<string>();
00562             for (int i = 0; i < Math.Pow(2, width); i++)
00563             {
00564                 stringList.Add(ValueToBits(i, width));
00565             }
00566             return stringList.ToArray();
00567         }
00568 
00569         private void InitChart()
00570         {
00571             // Reset Averaging
00572             //averageEcgSum = 0;
00573             //averageEcgCount = 0;
00574 
00575             //ecgInfo.Average = averageOptions[cboAverageEcg.SelectedIndex];
00576             ecgInfo.Average = 1; 
00577 
00578             // Rest Pace Tags
00579             paceTag.Clear();
00580 
00581             //UpdateChart(chartPace, new int[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
00582             //paceData = new PaceData(new int[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 });
00583             //UpdateChart(StreamDataType.Ecg, new int[] {1});
00584             DisplayEcg(new double[] { 0 }, null, null);
00585             //UpdateChart(chartECG, "SeriesRToR", new int[] {0});
00586             //UpdateChart(StreamDataType.BioZ, new int[] {0});
00587             DisplayBioZ(new double[] { 0 });
00588             UpdateChartAxis(chartECG);
00589             //UpdateChartAxis(chartRtoR);
00590             UpdateChartAxis(chartBioz);
00591             //UpdateChartAxis(chartPace);
00592 
00593             paceData = null;
00594             
00595             //chartRtoR.ChartAreas[0].AxisY.Maximum = 100;
00596         }
00597 
00598         private void ResetChart()
00599         {
00600             paceData = null;
00601         }
00602 
00603         private void UpdateChartAxis(System.Windows.Forms.DataVisualization.Charting.Chart chart)
00604         {
00605             ChartInfo chartInfo = new ChartInfo();
00606 
00607             if (chart.Name == "chartECG")
00608             {
00609                 chartInfo = ecgInfo;
00610             }
00611             else if (chart.Name == "chartBioz")
00612             {
00613                 chartInfo = bioZInfo;
00614             }
00615             else if (chart.Name == "chartPace")
00616             {
00617                 chartInfo = paceInfo;
00618             }
00619             else if (chart.Name == "chartRtoR")
00620             {
00621                 chartInfo = rToRInfo;
00622             }
00623 
00624             chart.SuspendLayout();
00625             chart.ChartAreas[0].AxisX.Minimum = 0;
00626             chart.ChartAreas[0].AxisX.Maximum = chartInfo.Points; 
00627             chart.ChartAreas[0].AxisX.Interval = (float)chartInfo.Points / chartInfo.Length;
00628 
00629             if (chart.Name != "chartRtoR")
00630             {
00631                 chart.ChartAreas[0].AxisX.CustomLabels.Clear();
00632                 // Set X-axis range in seconds
00633                 for (int i = 0; i < 11; i ++ )
00634                 {
00635                     chart.ChartAreas[0].AxisX.CustomLabels.Add(Math.Ceiling(((float)chartInfo.SampleRate / chartInfo.Average) * (2 * i - 1) / 2), 
00636                         Math.Floor(((float)chartInfo.SampleRate / chartInfo.Average) * (2 * i + 1) / 2), i.ToString());
00637                 }
00638             }
00639 
00640             chart.ResumeLayout();
00641         }
00642 
00643         public void DisplayEcg(double[] ecg, PacePoint[] pace, double[] rToR)
00644         {
00645             List<double> xList = new List<double>();
00646             List<double> yList = new List<double>();
00647             List<double> xListFalling = new List<double>();
00648             List<double> yListFalling = new List<double>();
00649 
00650             int offset = chartECG.Series["Series"].Points.Count; // Pace Offset
00651 
00652             chartECG.SuspendLayout();
00653 
00654             for(int i = 0; i < ecg.Length; i++ )
00655             {
00656                 chartECG.Series["Series"].Points.Add(ecg[i]);
00657             }
00658 
00659             if (pace != null)
00660             {
00661                 // Shift Old Points - Rising
00662                 for (int i = 0; i < chartECG.Series["SeriesPace"].Points.Count; i++)
00663                 {
00664                     double xValue = chartECG.Series["SeriesPace"].Points[i].XValue;
00665 
00666                     if (offset > ecgInfo.Points) // Do not shift until chart is full
00667                         xValue -= ecg.Length;
00668 
00669                     if (xValue >= 0)
00670                     {
00671                         xList.Add(xValue);
00672                         yList.Add(chartECG.Series["SeriesPace"].Points[i].YValues[0]);
00673                     }
00674                 }
00675                 // Shift Old Points - Falling
00676                 for (int i = 0; i < chartECG.Series["SeriesPaceFalling"].Points.Count; i++ )
00677                 {
00678                     double xValueFalling = chartECG.Series["SeriesPaceFalling"].Points[i].XValue;
00679 
00680                     if (offset > ecgInfo.Points)
00681                         xValueFalling -= ecg.Length;
00682 
00683                     if (xValueFalling >= 0)
00684                     {
00685                         xListFalling.Add(xValueFalling);
00686                         yListFalling.Add(chartECG.Series["SeriesPaceFalling"].Points[i].YValues[0]);
00687                     }
00688                 }
00689 
00690                 // Add New Points
00691                 for (int i = 0; i < pace.Length; i++)
00692                 {
00693                     if (pace[i].Polarity == true)
00694                     {
00695                         //xList.Add(pace[i].Time + offset);
00696                         //yList.Add(0.05);
00697                         chartECG.Series["SeriesPace"].Points.AddXY(pace[i].Time + offset, 0.05*(0+1));
00698                         //System.Diagnostics.Debug.Print("Rising: " + (pace[i].Time + offset));
00699                     }
00700                     else
00701                     {
00702                         //xListFalling.Add(pace[i].Time + offset);
00703                         //yListFalling.Add(-0.05);
00704                         chartECG.Series["SeriesPaceFalling"].Points.AddXY(pace[i].Time + offset, -0.08*(0+1));
00705                         //System.Diagnostics.Debug.Print("Falling: " + (pace[i].Time + offset));
00706                     }
00707                 }
00708 
00709                 // Bind data to chart
00710                 //chartECG.Series["SeriesPace"].Points.DataBindXY(xList, yList);
00711                 //chartECG.Series["SeriesPaceFalling"].Points.DataBindXY(xListFalling, yListFalling);
00712             }
00713 
00714             UpdateChartFormat(StreamDataType.Ecg, ecgInfo);
00715             //if (rToR != null) // Remove extra points
00716             //    UpdateChartFormat(StreamDataType.RToR, rToRInfo);
00717             if (pace != null) // Not needed anymore due to new plot style
00718                 UpdateChartFormat(StreamDataType.Pace, PaceInfo, offset + ecg.Length - ecgInfo.Points);
00719             chartECG.ResumeLayout();
00720         }
00721 
00722         public void DisplayBioZ(double[] bioZ)
00723         {
00724             chartBioz.SuspendLayout();
00725 
00726             for(int i = 0; i < bioZ.Length; i++)
00727             {
00728                 chartBioz.Series["Series"].Points.Add(bioZ[i] * bioZRangeMultiplier);
00729             }
00730 
00731             UpdateChartFormat(StreamDataType.BioZ, bioZInfo);
00732 
00733             chartBioz.ResumeLayout();
00734         }
00735 
00736         public double DisplayRToR(int rToR)
00737         {
00738             double rate;
00739             int rToREcg;
00740 
00741             long now = DateTime.Now.Ticks;
00742 
00743             if (rToR == RToRMaxValue) // Ignore the max value, counter overflow condition
00744                 return 0;
00745 
00746             rate = rToRCalculator.BeatsPerMinute(rToR); // RToRBeatsPerMinute(rToR);
00747 
00748             if (heartRateList.Count < 10)
00749                 heartRateList.Add(rate);
00750             else if (heartRateList.Count == 10)
00751             {
00752                 heartRateList.RemoveAt(0);
00753                 heartRateList.Add(rate);
00754 
00755                 double sum = 0;
00756                 foreach (double d in heartRateList)
00757                     sum += d;
00758 
00759                 lblHeartRateAverage10.Text = (sum / 10).ToString("F1");
00760 
00761             }
00762 
00763             lblHeartRateBeatToBeat.Text = rate.ToString("F1");
00764 
00765             if (heartRateList.Count != 1)
00766             {
00767                 rToREcg = rToRCalculator.EcgPoints(rToR, false); // RToREcgPoints(rToR, false);
00768             }
00769             else
00770             {
00771                 // First Point delay by Tdrtor_ecg
00772                 //rToREcg = RToREcgPoints(rToR, true) + 1; // DEBUG 3 extra 0x07 are sent from FW at start of stream, 1 extra point for GUI chart init
00773                 int rToRInEcg = rToRCalculator.EcgPoints(rToR, true);
00774                 rToREcg = rToRInEcg + 1;
00775             }
00776 
00777             if (lastRToRTime < 0)
00778                 lastRToRTime = now;
00779             else
00780             {
00781                 long diff = now - lastRToRTime;
00782                 TimeSpan elaspedTicks = new TimeSpan(diff);
00783 
00784                 int fullScaleTime = (int)(Math.Pow(2, 14) * 512 * TimeResolution + 0.5);
00785 
00786                 if (elaspedTicks.TotalSeconds > fullScaleTime)
00787                 {
00788                     int overflowCount = (int)(elaspedTicks.TotalSeconds / fullScaleTime);
00789 
00790                     for (int i = 0; i < overflowCount; i++ )
00791                         rToREcg += rToRCalculator.EcgPoints(EcgDelay.RToRMaxValue, false); //RToREcgPoints(0x3FFF, false);
00792                 }
00793 
00794                 lastRToRTime = now;
00795             }
00796 
00797             for (int i = 1; i < rToREcg - rToRRemoveOffset; i++ )
00798             {
00799                 chartECG.Series["SeriesRToR"].Points.Add(-5000);
00800             }
00801             int rToRCount = chartECG.Series["SeriesRToR"].Points.Count;
00802 
00803             if (rToRCount < chartECG.Series["Series"].Points.Count)
00804                 chartECG.Series["SeriesRToR"].Points.Add(chartECG.Series["Series"].Points[rToRCount].YValues[0]); // R to R comes in after ECG
00805             else
00806                 chartECG.Series["SeriesRToR"].Points.Add(0); // R to R comes in faster than ECG, add as 0 for now
00807 
00808             rToRRemoveOffset = 0;
00809 
00810             return rate;
00811         }
00812 
00813         public void BioZFunction(bool enable)
00814         {
00815             chartBioz.Visible = enable;
00816 
00817             if (enable == false)
00818             {
00819                 //tableLayoutPanelCharts.RowCount = 1;
00820                 tableLayoutPanelCharts.RowStyles[1] = new RowStyle(SizeType.Percent, 0);
00821                 tableLayoutPanelCharts.RowStyles[0] = new RowStyle(SizeType.Percent, 100);
00822             }
00823             else
00824             {
00825                 tableLayoutPanelCharts.RowStyles[0] = new RowStyle(SizeType.Percent, 50);
00826                 tableLayoutPanelCharts.RowStyles[1] = new RowStyle(SizeType.Percent, 50);
00827             }
00828 
00829         }
00830 
00831 
00832         /*
00833         public double RToRBeatsPerMinute(int rToRCode)
00834         {
00835             return 60 * 1000/ RToRMillisecond(rToRCode);
00836         }
00837 
00838         public double RToRMillisecond(int rToRCode)
00839         {
00840             return rToRCode * 512.0 * 1000 / (2 * MasterClockFrequency);
00841         }
00842 
00843         public int RToREcgPoints(int rToR, bool first)
00844         {
00845             double sampleRateRToR = MasterClockFrequency / 256;
00846             int rToRDifferentialDelay = RToRDelay - EcgDecimationDelay;
00847 
00848             double rToRInEcgSamples;
00849             int rToRInEcgSamplesInt;
00850 
00851             if (first)
00852             {
00853                 rToRInEcgSamples = (rToR - rToRDifferentialDelay / 256.0) * (SampleRateECG / sampleRateRToR);
00854                 rToRInEcgSamplesInt = (int)(rToRInEcgSamples + 0.5);
00855 
00856                 rToRInEcgSampleError = rToRInEcgSamplesInt - rToRInEcgSamples;
00857 
00858                 return rToRInEcgSamplesInt;
00859             }
00860             else
00861             {
00862                 rToRInEcgSamples = rToR * (SampleRateECG / sampleRateRToR) - rToRInEcgSampleError;
00863                 rToRInEcgSamplesInt = (int)(rToRInEcgSamples + 0.5);
00864 
00865                 rToRInEcgSampleError = rToRInEcgSamplesInt - rToRInEcgSamples;
00866 
00867                 return rToRInEcgSamplesInt;
00868 
00869             }
00870         }
00871         */
00872 
00873         private double[] UpdateChartFormat(StreamDataType dataType, ChartInfo chartInfo)
00874         {
00875             Chart chart = null;
00876             String series = "";
00877             double[] chartData;
00878             int minRound = 0, maxRound = 0;
00879             double min = Double.MaxValue, max = Double.MinValue;
00880             int count;
00881             
00882             switch (dataType)
00883             {
00884                 case StreamDataType.Ecg:
00885                     chart = chartECG;
00886                     series = "Series";
00887                     break;
00888                 case StreamDataType.BioZ:
00889                     chart = chartBioz;
00890                     series = "Series";
00891                     break;
00892                 case StreamDataType.RToR:
00893                     chart = chartECG;
00894                     series = "SeriesRToR";
00895                     break;
00896                 case StreamDataType.Pace:
00897                     chart = chartECG;
00898                     series = "SeriesPace";
00899                     break;
00900 
00901             }
00902             
00903             count = chart.Series[series].Points.Count;
00904 
00905             // Remove extra points
00906             while (count > chartInfo.Points)
00907             {
00908                 chart.Series[series].Points.RemoveAt(0);
00909                 if (dataType == StreamDataType.Ecg && EnableRToR) // Scroll R To R with ECG
00910                     if (chart.Series["SeriesRToR"].Points.Count > 0) // TODO
00911                         chart.Series["SeriesRToR"].Points.RemoveAt(0);
00912                     else
00913                         rToRRemoveOffset++;
00914 
00915                 count = chart.Series[series].Points.Count;
00916             }
00917 
00918             chartData = new double[chart.Series[series].Points.Count];
00919 
00920             // Copy data points and find min/max value
00921             for (int i = count / 2; i < count; i++) // Autoscale on last half of data only
00922             {
00923                 chartData[i] = chart.Series[series].Points[i].YValues[0];
00924 
00925                 if (chartData[i] < min)
00926                     min = chartData[i];
00927                 if (chartData[i] > max)
00928                     max = chartData[i];
00929             }
00930 
00931             if (min == max) // prevent any invalid ranges
00932                 max = max + 1;
00933 
00934             if (chartInfo == ecgInfo)
00935             {
00936                 // Round to 1mV for ECG
00937                 minRound = ((int)(min / 1) - 1) * 1;
00938                 maxRound = ((int)(max / 1) + 1) * 1;
00939 
00940                 if (minRound == -1 && maxRound == 1) // Manual control of auto interval
00941                     chart.ChartAreas[0].AxisY.Interval = 0.5;
00942                 else
00943                     chart.ChartAreas[0].AxisY.Interval = 0;
00944             }
00945             else if (chartInfo == bioZInfo)
00946             {
00947                 // Round to 100's for automatic axis scaling - for raw codes
00948                 minRound = (((int)min / 100 - 1) * 100);
00949                 maxRound = (((int)max / 100 + 1) * 100);
00950             }
00951             /*else if (chartInfo == rToRInfo)
00952             {
00953                 // Round to 100ms
00954                 minRound = 0; // R to R rate should never be negative;
00955                 maxRound = ((int)(max / 100) + 1) * 100;
00956             }
00957             else
00958             {
00959                 // Round to 100's for automatic axis scaling - for us of Pace length
00960                 minRound = (((int)min / 100 - 1) * 100);
00961                 maxRound = (((int)max / 100 + 1) * 100);
00962             }*/
00963 
00964             if (chartInfo == ecgInfo || chartInfo == bioZInfo)
00965             {
00966                 // Set full Y-axis range
00967                 chart.ChartAreas[0].AxisY.Minimum = minRound;
00968                 chart.ChartAreas[0].AxisY.Maximum = maxRound;
00969             }
00970 
00971             return chartData;
00972         }
00973 
00974         private double[] UpdateChartFormat(StreamDataType dataType, ChartInfo chartInfo, int shift)
00975         {
00976             List<double> xList = new List<double>();
00977             List<double> yList = new List<double>();
00978             List<double> xListFalling = new List<double>();
00979             List<double> yListFalling = new List<double>();
00980 
00981             int offset = chartECG.Series["Series"].Points.Count; // Pace Offset
00982 
00983             // Shift Old Points - Rising
00984             for (int i = 0; i < chartECG.Series["SeriesPace"].Points.Count; i++)
00985             {
00986                 double xValue = chartECG.Series["SeriesPace"].Points[i].XValue;
00987 
00988                 if (offset >= ecgInfo.Points) // Do not shift until chart is full
00989                     xValue -= shift;
00990 
00991                 if (xValue >= 0)
00992                 {
00993                     xList.Add(xValue);
00994                     yList.Add(chartECG.Series["SeriesPace"].Points[i].YValues[0]);
00995                 }
00996             }
00997             // Shift Old Points - Falling
00998             for (int i = 0; i < chartECG.Series["SeriesPaceFalling"].Points.Count; i++)
00999             {
01000                 double xValueFalling = chartECG.Series["SeriesPaceFalling"].Points[i].XValue;
01001 
01002                 if (offset >= ecgInfo.Points)
01003                     xValueFalling -= shift;
01004 
01005                 if (xValueFalling >= 0)
01006                 {
01007                     xListFalling.Add(xValueFalling);
01008                     yListFalling.Add(chartECG.Series["SeriesPaceFalling"].Points[i].YValues[0]);
01009                 }
01010             }
01011 
01012             chartECG.Series["SeriesPace"].Points.DataBindXY(xList, yList);
01013             chartECG.Series["SeriesPaceFalling"].Points.DataBindXY(xListFalling, yListFalling);
01014 
01015             return yList.ToArray();
01016         }
01017 
01018         /*
01019         public EcgFifo[] ConvertEcg(int[] data)
01020         {
01021             EcgFifo[] voltage = new EcgFifo[data.Length];
01022             ChartInfo chartInfo = ecgInfo;
01023             int dataShift;
01024 
01025             for (int i = 0; i < data.Length; i++ )
01026             {
01027                 dataShift = data[i] >> chartInfo.Shift;
01028 
01029                 // Two's Complement Conversions
01030                 if (dataShift > chartInfo.Threshold)
01031                 {
01032                     dataShift -= chartInfo.Offset;
01033                 }
01034 
01035                 voltage[i].Data = 1000 * 7.62939453125e-6 * dataShift / chartInfo.Gain;
01036                 voltage[i].PTag = data[i] & 0x07;
01037                 voltage[i].ETag = (data[i] >> 3) & 0x07;
01038             }
01039 
01040             return voltage;
01041         }
01042 
01043         public BioZFifo[] ConvertBioZ(int[] data)
01044         {
01045             BioZFifo[] impedence = new BioZFifo[data.Length];
01046             ChartInfo chartInfo = bioZInfo;
01047             int dataShift;
01048             int dataPoint;
01049 
01050             for (int i = 0; i < data.Length; i ++)
01051             {
01052                 dataShift = data[i] >> chartInfo.Shift;
01053 
01054                 // Two's Complement Conversions
01055                 if (dataShift > chartInfo.Threshold)
01056                 {
01057                     dataShift -= chartInfo.Offset;
01058                 }
01059 
01060                 // 1.9734 = 1/2^19 * 1e-6
01061                 impedence[i].Data = dataShift * bioZRangeMultiplier * 1.9073486328125 / 
01062                     (chartInfo.Gain * ((chartInfo.CurrentGenerator == 0) ? 1 : chartInfo.CurrentGenerator));
01063                 impedence[i].BTag = data[i] & 0x07;
01064             }
01065 
01066             return impedence;
01067         }
01068 
01069         public PaceData ConvertPace(int[] data)
01070         {
01071             paceData = new PaceData(data);
01072 
01073             return paceData;
01074         }
01075 
01076         public double ConvertRToR(int data)
01077         {
01078             rToRInterval = data;
01079 
01080             return rToRInterval;
01081         }
01082          */
01083 
01084         int[] ProcessRToR(int[] ecgData)
01085         {
01086             int[] rToRArray;
01087 
01088             rToRArray = new int[ecgData.Length];
01089             for (int i = 0; i < rToRArray.Length; i++)
01090                 rToRArray[i] = Int32.MinValue;
01091 
01092             if (rToRInterval > 0) // Valid R to R
01093             {
01094                 var ecgCode = EcgMaximumCode(ecgData);
01095                 rToRArray[ecgCode.Item1] = ecgCode.Item2;
01096             }
01097 
01098             return rToRArray;
01099         }
01100 
01101         public Tuple<int, int> EcgMaximumCode(int[] data)
01102         {
01103             int i;
01104             int max = Int32.MinValue;
01105             int maxCode = 0;
01106             int maxIndex = 0;
01107             int point;
01108 
01109             for (i = 0; i < data.Length; i++ )
01110             {
01111                 point = data[i] >> ecgInfo.Shift;
01112                 if (data[i] > ecgInfo.Threshold)
01113                     point -= ecgInfo.Offset;
01114 
01115                 if (point > max) // Two's complement offset
01116                 {
01117                     max = point;
01118                     maxCode = data[i];
01119                     maxIndex = i;
01120                 }
01121             }
01122 
01123             return new Tuple<int, int>(maxIndex, maxCode);
01124         }
01125 
01126         private bool LeadOffBit(int value, int bit)
01127         {
01128             int state;
01129             int mask = 1 << bit;
01130             state = ((value & mask) == mask) ? 1 : 0;
01131             return state == 1;
01132         }
01133 
01134         //public void On_AppendChart(object sender, PartialArrayIntAvailableEventArgs e)
01135         //{
01136             /*
01137             int leadOffState;
01138 
01139             if (e.array1.Length > 0) // Occurs with streaming from flash
01140             {
01141                 leadOffState = e.array1[0];
01142 
01143                 switch (e.reportID)
01144                 {
01145                     case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_LEADOFF_DC:
01146                         if (LeadOffBit(leadOffState, 8)) // check for ECG
01147                         {
01148                             UpdateLeadOffState(lblLdoffPh, LeadOffBit(leadOffState, 3));
01149                             UpdateLeadOffState(lblLdoffPl, LeadOffBit(leadOffState, 2));
01150                             UpdateLeadOffState(lblLdoffNh, LeadOffBit(leadOffState, 1));
01151                             UpdateLeadOffState(lblLdoffNl, LeadOffBit(leadOffState, 0));
01152                         }
01153                         if (LeadOffBit(leadOffState, 9)) // check for BIOZ
01154                         {
01155                             UpdateLeadOffState(lblLdoffPh, LeadOffBit(leadOffState, 3));
01156                             UpdateLeadOffState(lblLdoffPl, LeadOffBit(leadOffState, 2));
01157                             UpdateLeadOffState(lblLdoffNh, LeadOffBit(leadOffState, 1));
01158                             UpdateLeadOffState(lblLdoffNl, LeadOffBit(leadOffState, 0));
01159                         }
01160                         break;
01161                     case PartialArrayIntAvailableEventArgs.PACKET_MAX30001_LEADOFF_AC:
01162                         UpdateLeadOffState(lblBioZACOver, LeadOffBit(leadOffState, 0));
01163                         UpdateLeadOffState(lblBioZACUnder, LeadOffBit(leadOffState, 1));
01164                         break;
01165                 }
01166             }
01167             */
01168             /*
01169             StringBuilder outputData = new StringBuilder();
01170 
01171             if (e.reportID == PartialArrayIntAvailableEventArgs.PACKET_MAX30001_ECG)
01172             {
01173                 if (e.array1.Length != 0)
01174                 {
01175                     if (ecgBuffer != null)
01176                     { 
01177                         UpdateChart(StreamDataType.Ecg, ecgBuffer);
01178 
01179                         if (EnableRToR)
01180                         {
01181                             int[] rToRArray = ProcessRToR(ecgBuffer);
01182 
01183                             UpdateChart(StreamDataType.RToR, rToRArray);
01184                             rToRInterval = -1; // R to R processed reset value
01185                         }
01186                     }
01187 
01188                     ecgBuffer = ecgBuffer1;
01189                     ecgBuffer1 = e.array1; 
01190                     // DEBUG
01191                     foreach (int data in e.array1)
01192                     {
01193                         outputData.Append(data.ToString());
01194                         outputData.Append(Environment.NewLine);
01195                     }
01196 
01197                     file.Write(outputData.ToString());
01198 
01199                     ConvertEcg(e.array1);
01200                 }
01201             }
01202             if (e.reportID == PartialArrayIntAvailableEventArgs.PACKET_MAX30001_PACE)
01203             {
01204                 if (e.array1.Length != 0)
01205                 {
01206                     // Store Pace data for update with ECG PTAGs
01207                     ConvertPace(e.array1);
01208                 }
01209             }
01210             if (e.reportID == PartialArrayIntAvailableEventArgs.PACKET_MAX30001_RTOR)
01211             {
01212                 if (e.array1.Length != 0)
01213                 {
01214                     ConvertRToR(e.array1[0]);
01215                 }
01216             }
01217             if (e.reportID == PartialArrayIntAvailableEventArgs.PACKET_MAX30001_BIOZ)
01218             {
01219                 if (e.array1.Length != 0)
01220                 {
01221                     ConvertBioZ(e.array1);
01222                     //UpdateChart(StreamDataType.BioZ, e.array1);
01223                 }
01224             }*/
01225         //}
01226 
01227         private void Start()
01228         {
01229             //ParseRbiasArgs();
01230             /*rpcClient.MAX30001.Rbias_FMSTR_Init(
01231                 rbiasInit.En_rbias,
01232                 rbiasInit.Rbias,
01233                 rbiasInit.Rbiasp,
01234                 rbiasInit.Rbiasn,
01235                 rbiasInit.Fmstr
01236             );*/
01237 
01238 
01239             //if (ckbxCal.Checked)
01240             /*{
01241                 startedCal = true;
01242                 //ParseCalArgs();
01243                 calArgs.En_Vcal = 0;
01244                 calArgs.Vmode = 0;
01245                 calArgs.Vmag = 1;
01246                 calArgs.Fcal = 3;
01247                 calArgs.Thigh = 0x1F;
01248                 calArgs.Fifty = 0;
01249                 rpcClient.MAX30001.CAL_InitStart(
01250                     calArgs.En_Vcal,
01251                     calArgs.Vmode,
01252                     calArgs.Vmag,
01253                     calArgs.Fcal,
01254                     calArgs.Thigh,
01255                     calArgs.Fifty);
01256             }*/
01257 
01258             /*
01259             rpcClient.MAX30001.INT_assignment(MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_enint_loc,      en_eovf_loc,   en_fstint_loc,
01260                        MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_dcloffint_loc,  en_bint_loc,   en_bovf_loc,
01261                        MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_bover_loc,      en_bundr_loc,  en_bcgmon_loc,
01262                        MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_pint_loc,       en_povf_loc,   en_pedge_loc,
01263                        MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_lonint_loc,     en_rrint_loc,  en_samp_loc,
01264                        MAX30001.max30001_intrpt_type.MAX30001_INT_ODNR, MAX30001.max30001_intrpt_type.MAX30001_INT_ODNR);                //  intb_Type,         int2b_Type)
01265             */
01266             if (connected)
01267             {
01268                 rpcClient.MAX30001.WriteReg(0x02, 0x03); // Stop Interrupts
01269                 rpcClient.MAX30001.WriteReg(0x03, 0x03); // Stop Interrupts
01270             }
01271 
01272             if (enableECG)    
01273             {
01274                 startedEcg = true;
01275                 if (GetEcgInitArgsPointer != null)
01276                 {
01277                     ecgArgs = GetEcgInitArgsPointer();
01278                     rpcClient.MAX30001.ECG_InitStart(
01279                         ecgArgs.En_ecg,
01280                         ecgArgs.Openp,
01281                         ecgArgs.Openn,
01282                         ecgArgs.Pol,
01283                         ecgArgs.Calp_sel,
01284                         ecgArgs.Caln_sel,
01285                         ecgArgs.E_fit,
01286                         ecgArgs.Rate,
01287                         ecgArgs.Gain,
01288                         ecgArgs.Dhpf,
01289                         ecgArgs.Dlpf);
01290                 }
01291 
01292  /*               rpcClient.MAX30001.ECGFast_Init(
01293                     ecgFastArgs.Clr_Fast,
01294                     ecgFastArgs.Fast,
01295                     ecgFastArgs.Fast_Th);*/
01296             }
01297 
01298             if (enablePace)
01299             {
01300                 startedPace = true;
01301                 if (GetPaceInitArgsPointer != null)
01302                 {
01303                     paceArgs = GetPaceInitArgsPointer();
01304                     rpcClient.MAX30001.PACE_InitStart(
01305                         paceArgs.En_pace,
01306                         paceArgs.Clr_pedge,
01307                         paceArgs.Pol,
01308                         paceArgs.Gn_diff_off,
01309                         paceArgs.Gain,
01310                         paceArgs.Aout_lbw,
01311                         paceArgs.Aout,
01312                         paceArgs.Dacp,
01313                         paceArgs.Dacn);
01314                 }
01315             }
01316             if (enableBioZ)
01317             {
01318                 startedBioz = true;
01319                 if (GetBioZInitArgsPointer != null)
01320                 {
01321                     biozArgs = GetBioZInitArgsPointer();
01322                     rpcClient.MAX30001.BIOZ_InitStart(
01323                         biozArgs.En_bioz,
01324                         biozArgs.Openp,
01325                         biozArgs.Openn,
01326                         biozArgs.Calp_sel,
01327                         biozArgs.Caln_sel,
01328                         biozArgs.CG_mode,
01329                         biozArgs.B_fit,
01330                         biozArgs.Rate,
01331                         biozArgs.Ahpf,
01332                         biozArgs.Ext_rbias,
01333                         biozArgs.Gain,
01334                         biozArgs.Dhpf,
01335                         biozArgs.Dlpf,
01336                         biozArgs.Fcgen,
01337                         biozArgs.Cgmon,
01338                         biozArgs.Cgmag,
01339                         biozArgs.Phoff);
01340                 }
01341             }
01342             if (enableRToR)
01343             {
01344                 startedRtoR = true;
01345                 if (GetRToRInitArgsPointer != null)
01346                 {
01347                     rtorArgs = GetRToRInitArgsPointer();
01348                     rpcClient.MAX30001.RtoR_InitStart(
01349                         rtorArgs.En_rtor,
01350                         rtorArgs.Wndw,
01351                         rtorArgs.Gain,
01352                         rtorArgs.Pavg,
01353                         rtorArgs.Ptsf,
01354                         rtorArgs.Hoff,
01355                         rtorArgs.Ravg,
01356                         rtorArgs.Rhsf,
01357                         rtorArgs.Clr_rrint);
01358                 }
01359 
01360                 rToRCalculator = new RToRCalculator(frequencyMasterField, ecgArgs.Rate, ecgArgs.Dlpf, rtorArgs.Wndw);
01361             }
01362 
01363             /*rpcClient.MAX30001.Rbias_FMSTR_Init(
01364                 0,
01365                 0,
01366                 0,
01367                 0,
01368                 0);*/
01369 
01370             rpcClient.MAX30001.INT_assignment(MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_enint_loc,      en_eovf_loc,   en_fstint_loc,
01371                       MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_dcloffint_loc,  en_bint_loc,   en_bovf_loc,
01372                       MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_bover_loc,      en_bundr_loc,  en_bcgmon_loc,
01373                       MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_pint_loc,       en_povf_loc,   en_pedge_loc,
01374                       MAX30001.max30001_intrpt_Location.MAX30001_INT_2B, MAX30001.max30001_intrpt_Location.MAX30001_INT_B, MAX30001.max30001_intrpt_Location.MAX30001_NO_INT,  //  en_lonint_loc,     en_rrint_loc,  en_samp_loc,
01375                       MAX30001.max30001_intrpt_type.MAX30001_INT_ODNR, MAX30001.max30001_intrpt_type.MAX30001_INT_ODNR);                //  intb_Type,         int2b_Type)
01376 
01377             if (startedEcg | startedCal | startedPace | startedBioz | startedRtoR)
01378             {
01379                 rpcClient.MAX30001.StartStreaming();
01380             }
01381 
01382             // Clear Lead Off
01383             UpdateLeadOffState(lblLdoffPh, false);
01384             UpdateLeadOffState(lblLdoffPl, false);
01385             UpdateLeadOffState(lblLdoffNh, false);
01386             UpdateLeadOffState(lblLdoffNl, false);
01387             UpdateLeadOffState(lblBioZACOver, false);
01388             UpdateLeadOffState(lblBioZACUnder, false); 
01389 
01390             // Clear Charts 
01391             chartECG.Series["Series"].Points.Clear();
01392             chartECG.Series["SeriesRToR"].Points.Clear();
01393             chartECG.Series["SeriesPace"].Points.Clear();
01394             chartECG.Series["SeriesPaceFalling"].Points.Clear();
01395             //chartRtoR.Series["Series"].Points.Clear();
01396             chartBioz.Series["Series"].Points.Clear();
01397             //chartPace.Series["Series"].Points.Clear();
01398             InitChart();
01399             fileLogData.Clear(); // Clear initiation points
01400 
01401             // Reset R To R state
01402             rToRRemoveOffset = 0;
01403             lastRToRTime = -1;
01404 
01405             // Clear Heart Rate
01406             heartRateList = new List<double>(10);
01407             lblHeartRateAverage10.Text = "--";
01408             lblHeartRateBeatToBeat.Text = "--";
01409 
01410 #if CES_DEMO
01411             hpf.Reset();
01412 #endif
01413             btnMonitor.Text = "Stop Monitor";
01414             if (StreamingStartStop != null)
01415             {
01416                 StreamingStartStop(this, new StreamingStartStopEventArgs() { state = true });
01417             }
01418 #if FILE_LOG
01419             // Debug
01420             DateTime localDate = DateTime.Now;
01421 
01422             file = new StreamWriter("hsp_ecg_output_data.csv");
01423             file.WriteLine("# " + localDate.ToString() + ", Sample Rate Register Setting: " + ecgArgs.Rate);
01424             file.WriteLine(@"# ECG (μV)     Raw Integer");
01425 #endif
01426 
01427             // DEBUG - simulate the "first" R To R value as a > 10 second value to see what happens
01428             //DisplayRToR(0x600);
01429         }
01430         private void btnMonitor_Click(object sender, EventArgs e)
01431         {
01432             if (btnMonitor.Text == "Start Monitor")
01433             {
01434                 if (Connected)
01435                 {
01436                     //if (ckbxEcg.Checked | ckbxPace.Checked | ckbxBioz.Checked | ckbxRtoR.Checked)
01437                     if (EnableECG | EnableBioZ)
01438                         Start();
01439                     else if (EnableRToR)
01440                         MessageBox.Show("Also enable ECG for R-to-R streaming", "Streaming");
01441                     else
01442                         MessageBox.Show("Enable ECG or BioZ before starting streaming", "Streaming");
01443                 }
01444             }
01445             else
01446             {
01447                 Stop();
01448             }
01449         }
01450 
01451         private void Stop()
01452         {
01453             if (startedEcg | startedCal | startedPace | startedBioz | startedRtoR)
01454             {
01455                 rpcClient.MAX30001.StopStreaming(connected);
01456 
01457                 //rpcClient.MAX30001.WriteReg(0x02, 0);
01458                 //rpcClient.MAX30001.WriteReg(0x03, 0);
01459             }
01460 
01461             startedCal = false;
01462             startedEcg = false;
01463             startedPace = false;
01464             startedBioz = false;
01465             startedRtoR = false;
01466 
01467             btnMonitor.Text = "Start Monitor";
01468             if (StreamingStartStop != null)
01469                 StreamingStartStop(this, new StreamingStartStopEventArgs() { state = false });
01470 
01471 #if FILE_LOG
01472             // Debug
01473             file.Close();
01474 #endif
01475         }
01476 
01477         // Clean up streaming 
01478         public void Close()
01479         {
01480             // Disable streaming if enabled
01481             if (StreamingStartStop != null && btnMonitor.Text == "Stop Monitor")
01482             {
01483                 StreamingStartStop(this, new StreamingStartStopEventArgs() { state = false });
01484                 Stop();
01485             }
01486         }
01487 
01488 
01489         private void chkbxCheckedChanged(object sender, EventArgs e)
01490         {
01491             /*
01492             EnableDisableControls(CAL_init, ckbxCal.Checked);
01493             EnableDisableControls(ECG_InitStart, ckbxEcg.Checked);
01494             EnableDisableControls(PACE_InitStart, ckbxPace.Checked);
01495             EnableDisableControls(BIOZ_InitStart, ckbxBioz.Checked);
01496             EnableDisableControls(ECGFast_Init, ckbxEcg.Checked);
01497             EnableDisableControls(RtoR_InitStart, ckbxRtoR.Checked);
01498             */
01499         }
01500 
01501         private void btnStartTest_Click(object sender, EventArgs e)
01502         {
01503             System.Windows.Forms.DataVisualization.Charting.Chart test = chartECG;
01504 
01505             double ymin = test.ChartAreas[0].AxisY.Minimum;  
01506             double ymax = test.ChartAreas[0].AxisY.Maximum;
01507             if (btnStartTest.Text == "Start Test")
01508             {
01509                 rpcClient.MAX30001.StartTest();
01510                 btnStartTest.Text = "Stop Test";
01511             }
01512             else
01513             {
01514                 Stop();
01515                 btnStartTest.Text = "Start Test";
01516             }
01517 
01518         }
01519 
01520         public void SetDCLeadOff(int leadOffState)
01521         {
01522             if (LeadOffBit(leadOffState, 8)) // check for ECG
01523             {
01524                 UpdateLeadOffState(lblLdoffPh, LeadOffBit(leadOffState, 3));
01525                 UpdateLeadOffState(lblLdoffPl, LeadOffBit(leadOffState, 2));
01526                 UpdateLeadOffState(lblLdoffNh, LeadOffBit(leadOffState, 1));
01527                 UpdateLeadOffState(lblLdoffNl, LeadOffBit(leadOffState, 0));
01528             }
01529             if (LeadOffBit(leadOffState, 9)) // check for BIOZ
01530             {
01531                 UpdateLeadOffState(lblLdoffPh, LeadOffBit(leadOffState, 3));
01532                 UpdateLeadOffState(lblLdoffPl, LeadOffBit(leadOffState, 2));
01533                 UpdateLeadOffState(lblLdoffNh, LeadOffBit(leadOffState, 1));
01534                 UpdateLeadOffState(lblLdoffNl, LeadOffBit(leadOffState, 0));
01535             }
01536         }
01537 
01538         public void SetACLeadOff(int leadOffState)
01539         {
01540             UpdateLeadOffState(lblBioZACOver, LeadOffBit(leadOffState, 0));
01541             UpdateLeadOffState(lblBioZACUnder, LeadOffBit(leadOffState, 1));
01542         }
01543 
01544         //
01545         // Update LeadOff GUI State
01546         //
01547         private void UpdateLeadOffState(TextBox tb, bool state)
01548         {
01549             tb.Text = (state == true) ? "1" : "0";
01550             if (state == true) tb.BackColor = Color.LightGreen;
01551             else tb.BackColor = Color.Yellow;
01552         }
01553 
01554         private void UpdateLeadOffState(Label lbl, bool state)
01555         {
01556             lbl.ForeColor = (state == true) ? MaximStyle.MaximColor.Red : MaximStyle.MaximColor.Green;
01557         }
01558 
01559         /* Inner Classes of EcgView */
01560 
01561 
01562 
01563         /// <summary>
01564         /// Information used to generate the X-axis of a chart
01565         /// </summary>
01566         public class ChartInfo
01567         {
01568             /// <summary>
01569             /// Sample Rate
01570             /// </summary>
01571             private double sampleRate = 0;
01572             public double SampleRate
01573             {
01574                 get
01575                 {
01576                     return sampleRate;
01577                 }
01578                 set
01579                 {
01580                     sampleRate = value;
01581                     points = Convert.ToInt32(length * sampleRate / average);
01582                 }
01583             }
01584 
01585             /// <summary>
01586             /// Length of chart in seconds
01587             /// </summary>
01588             private int length = 1;
01589             public int Length
01590             {
01591                 get
01592                 {
01593                     return length;
01594                 }
01595                 set
01596                 {
01597                     length = value;
01598                     points = Convert.ToInt32(length * sampleRate / average);
01599                 }
01600             }
01601 
01602             /// <summary>
01603             /// Number of total points in chart
01604             /// </summary>
01605             private int points = 1;
01606             public int Points
01607             {
01608                 get
01609                 {
01610                     return points;
01611                 }
01612             }
01613 
01614             public int Gain;
01615 
01616             private int average = 1;
01617             public int Average
01618             {
01619                 get
01620                 {
01621                     return average;
01622                 }
01623                 set
01624                 {
01625                     average = value;
01626                     points = Convert.ToInt32(length * sampleRate / average);
01627                 }
01628             }
01629 
01630             /// <summary>
01631             /// Value passed the threshold is negative
01632             /// </summary>
01633             private int threshold = Int32.MaxValue;
01634             public int Threshold
01635             {
01636                 get
01637                 {
01638                     return threshold;
01639                 }
01640                 set
01641                 {
01642                     threshold = value;
01643                 }
01644             }
01645 
01646             /// <summary>
01647             /// Amount to offset value by to convert to negative 
01648             /// </summary>
01649             private int offset = 0;
01650             public int Offset
01651             {
01652                 get
01653                 {
01654                     return offset;
01655                 }
01656                 set
01657                 {
01658                     offset = value;
01659                 }
01660             }
01661 
01662             /// <summary>
01663             /// Number of bits to shift raw data by
01664             /// </summary>
01665             public int Shift;
01666 
01667 
01668             /// <summary>
01669             /// Current generator for BioZ
01670             /// </summary>
01671             public int CurrentGenerator;
01672 
01673             public Chart Chart;
01674 
01675             public String SeriesName;
01676         }
01677 
01678         public class PacePoint
01679         {
01680             public double Time;
01681             public bool Polarity;
01682 
01683             public PacePoint(double time, bool polarity)
01684             {
01685                 this.Time = time;
01686                 this.Polarity = polarity;
01687             }
01688         }
01689 
01690         // DEBUG
01691         int offsetTest = 0;
01692         private void button1_Click(object sender, EventArgs e)
01693         {
01694             //timer1.Enabled = !timer1.Enabled;
01695             chartECG.Series["SeriesPace"].Points.AddXY(1.99354553222656 + offsetTest, 0.05 * (1));
01696             chartECG.Series["SeriesPaceFalling"].Points.AddXY(1.99455261230469 + offsetTest, -0.08 * (1));
01697 
01698             offsetTest += 100;
01699         }
01700 
01701         // DEBUG
01702         private void timer1_Tick(object sender, EventArgs e)
01703         {
01704             /*
01705             PartialArrayIntAvailableEventArgs ecg1 = new PartialArrayIntAvailableEventArgs();
01706             PartialArrayIntAvailableEventArgs ecg2 = new PartialArrayIntAvailableEventArgs();
01707             PartialArrayIntAvailableEventArgs rr1 = new PartialArrayIntAvailableEventArgs();
01708 
01709             ecg1.array1 = new int[] { 0x00, 0x00, 0x00, 0x00, 0xfffff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
01710             ecg2.array1 = new int[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
01711             rr1.array1 = new int[] { 0x88 };
01712 
01713             ecg1.reportID = PartialArrayIntAvailableEventArgs.PACKET_MAX30001_ECG;
01714             ecg2.reportID = PartialArrayIntAvailableEventArgs.PACKET_MAX30001_ECG;
01715             rr1.reportID = PartialArrayIntAvailableEventArgs.PACKET_MAX30001_RTOR;
01716 
01717             if (clicks % 15 == 0)
01718             {
01719                 On_AppendChart(this, ecg2);
01720             }
01721             else if (clicks % 5 == 0)
01722             {
01723                 On_AppendChart(this, ecg1);
01724                 On_AppendChart(this, rr1);
01725             }
01726             else
01727                 On_AppendChart(this, ecg2);
01728 
01729             clicks++;
01730             */
01731             DisplayEcg(new double[] { 0, 0, 0, 0, 1, 2, 3, 4, 5 }, null, new double[] {-10, -10, -10, -10, -10, -10, 4, -10, -10});
01732         }
01733     }
01734 }