This is the latest working repository used in our demo video for the Maxim to display temperature readings on Bluetooth

Dependencies:   USBDevice

Revision:
3:36de8b9e4b1a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hspguisourcev301/HspGuiSourceV301/HSPGui/Form1.cs	Sat Apr 10 03:05:42 2021 +0000
@@ -0,0 +1,1902 @@
+/*******************************************************************************
+* 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.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+
+using System.Windows.Forms;
+using Microsoft.Win32;
+using Microsoft.Win32.SafeHandles;
+using System.Globalization;
+using System.Threading;
+using System.Management;
+using System.Diagnostics;
+using System.IO;
+using System.Collections.Specialized;
+
+using HealthSensorPlatform.DeviceDescriptions;
+using HealthSensorPlatform.CustomControls;
+using HealthSensorPlatform.View;
+using HealthSensorPlatform.Presenter;
+using HealthSensorPlatform.Model;
+
+using MAX30205EVKit.Presenter;
+
+using Maxim.MAX30101GUI;
+using Maxim.Utility;
+
+using MaximStyle;
+
+namespace HealthSensorPlatform
+{
+
+    public partial class HspForm : Form, IFormView, IHspSetting
+    {
+        /* Constants */
+        //Software Version
+        internal const int MAJORVERSION = 3;
+        internal const int MINORVERSION = 0;
+        internal const int PATCHVERSION = 1;
+        const string VersionSuffix = "";
+
+        const string PartNumber = "MAXREFDES100";
+
+        const string readVersionCommand = "/System/ReadVer\r\n";
+        const string readFlashIDCommand = "/S25FS512/ReadId\r\n";
+        const string firmwareKey = "HSP FW Version"; 
+
+        /* Fields */
+        SplashScreen splashScreen = new SplashScreen();
+        FormConnection connectionDialog = new FormConnection();
+        string port;
+        bool connected = false;
+        bool internalUpdate = false; // Used to prevent events from triggering
+        bool streaming = false; // Disable GUI features while streaming is enabled
+
+        static ManagementEventWatcher watcher; 
+
+        /* // TODO: Do not remember what this is for, can remove
+        MaximStyle.MaximNumericUpDown[] ud_cmd = new MaximStyle.MaximNumericUpDown[3];
+        MaximStyle.MaximNumericUpDown[] ud_data = new MaximStyle.MaximNumericUpDown[8];
+        Panel[] p_cmd = new Panel[3];
+        Panel[] p_data = new Panel[8];
+        */
+
+        IDeviceView[] deviceViews;
+        Maxim.CustomControls.RegisterView[] registerViews;
+        TabPage[] max30001TabPages;
+
+        RPCSupport.RPCClient rpcClient;
+        RPCSupport.Devices.I2cDevice i2cDevice;
+        RPCSupport.Devices.SpiDevice spiDevice;
+        RPCSupport.Devices.MAX30101 max30101;
+        RPCSupport.Devices.MAX30205 max30205;
+        RPCSupport.Devices.LIS2HD lis2hd;
+        RPCSupport.Devices.MAX30001 max30001;
+        RPCSupport.DataLogging.DataLogging logging;
+
+        ListDictionary registerViewDict;
+
+        //FileLogPresenter fileLogPresenter;
+        RawFileLogPresenter rawFileLogPresenter;
+        OpticalFileLogPresenter opticalFileLogPresenter;
+        TemperaturePresenter temperaturePresenter;
+
+        Model.MAX30001Model max30001Model;
+
+        public event EventHandler<EnableEventArgs> FileLogEnable;
+        public event EventHandler<EnableEventArgs> OpticalFileLogEnable;
+        public event EventHandler<EventArgs> RegisterExport;
+        public event EventHandler<EventArgs> RegisterImport;
+
+        public event EventHandler<EventArgs> Connected;
+
+        /* Constructor */
+        /// <summary>
+        /// 
+        /// </summary>
+        public HspForm()
+        {
+            InitializeComponent();
+
+            InitSplashScreen();
+
+            //initialize text in status bar
+            ss_Status.Items[0].Text = "";
+            ss_Status.Items[1].Text = "";
+
+            deviceViews = new IDeviceView[] { 
+                opticalView1, 
+                temperatureView1,
+                ecgView1,
+                dataLoggingView1,
+                rvLIS2HD,
+                rvMAX14720,
+                rvMAX30001,
+                rvMAX30101,
+                rvMAX30205,
+                rvMAX30205_U18
+            };
+
+            registerViews = new Maxim.CustomControls.RegisterView[] {
+                rvMAX30101,
+                rvMAX30205,
+                rvMAX30205_U18,
+                rvLIS2HD,
+                rvMAX30001,
+                rvMAX14720
+            };
+
+            max30001TabPages = new TabPage[] { tpMAX30001BioZInputMux, tpBioZChannel, tpMAX30001BioZLoad, tpMAX30001Pace };
+
+            registerViewDict = new ListDictionary();
+
+            InitRpcClient();
+
+            InitRpcDevices();
+            PrimitivesViewInit();
+            RegistersTabInit();
+            LoggingViewInit();
+            TemperatureViewInit();
+            OpticalViewInit();
+
+            BlockDiagramsInit();
+            ECGPlotsViewInit();
+
+            InitalizeUSBDetection();
+
+            FileLoggingInit();
+
+            RegisterExportInit();
+
+            SetupSwitchPictureBoxes();
+        }
+
+        private void SetupSwitchPictureBoxes()
+        {
+            //ECGMux Tab
+            picECGLeadConfig.Controls.Add(picSw1);
+            picSw1.Controls.Add(picSw2);
+            picSw2.Controls.Add(picSw3);
+            picSw3.Controls.Add(picSw4);
+            picSw4.Controls.Add(picSw5);
+            picSw5.Controls.Add(picSw6);
+            picSw6.Controls.Add(picSw7);
+            picSw7.Controls.Add(picSw8);
+            picSw8.Controls.Add(picSw9);
+            picSw9.Controls.Add(picSw10);
+            picSw10.Controls.Add(picSw11);
+            picSw11.Controls.Add(picSw12);
+            picSw12.Controls.Add(picSw13);
+            picSw13.Controls.Add(picSw14);
+
+            //BioZMux Tab
+            pictureBox2.Controls.Add(picLoff1);
+            picLoff1.Controls.Add(picLoff2);
+            picLoff2.Controls.Add(picLeadOn);
+            picLeadOn.Controls.Add(picBioZsw1);
+            picBioZsw1.Controls.Add(picBioZsw2);
+            picBioZsw2.Controls.Add(picLeadBias1);
+            picLeadBias1.Controls.Add(picLeadBias2);
+            picLeadBias2.Controls.Add(picBioZCal1);
+            picBioZCal1.Controls.Add(picBioZCal2);
+
+            //BioZLoad Tab
+            picBioZLoad.Controls.Add(picBioZLresload); 
+            picBioZLresload.Controls.Add(picBioZLloff1);
+            picBioZLloff1.Controls.Add(picBioZLloff2);
+            picBioZLloff2.Controls.Add(picBioZLlon);
+            picBioZLlon.Controls.Add(picBioZLsw1);
+            picBioZLsw1.Controls.Add(picBioZLsw2);
+            picBioZLsw2.Controls.Add(picBioZLlb1);
+            picBioZLlb1.Controls.Add(picBioZLlb2);
+            picBioZLlb2.Controls.Add(picBioZLcal1);
+            picBioZLcal1.Controls.Add(picBioZLcal2);
+
+
+        }
+
+        /* Delegates */
+        delegate void guiDisconnectedCallBack();
+
+        public void MessageInfo(string message)
+        {
+            ss_Status.MessagesLabel.Text = message;
+        }
+
+        public void MessageBoxShow(string message)
+        {
+            MessageBox.Show(message);
+        }
+
+        public void MessageBoxShow(string message, string title)
+        {
+            MessageBox.Show(message, title);
+        }
+
+
+        /// <summary>
+        /// http://stackoverflow.com/questions/286184/how-to-capture-a-serial-port-that-disappears-because-the-usb-cable-gets-unplugge
+        /// </summary>
+        private void InitalizeUSBDetection()
+        {
+            WqlEventQuery query;
+            ManagementScope scope;
+
+            scope = new ManagementScope("root\\CIMV2");
+            scope.Options.EnablePrivileges = true;
+
+            query = new WqlEventQuery();
+            query.EventClassName = "__InstanceDeletionEvent"; // "__InstanceCreationEvent" can be used for insertion
+            query.WithinInterval = new TimeSpan(0, 0, 3);
+            query.Condition = @"TargetInstance ISA 'Win32_USBControllerdevice'";
+            watcher = new ManagementEventWatcher(scope, query);
+            watcher.EventArrived += new EventArrivedEventHandler(USBRemovedHandler);
+            watcher.Start();
+        }
+        
+        /// <summary>
+        /// http://stackoverflow.com/questions/286184/how-to-capture-a-serial-port-that-disappears-because-the-usb-cable-gets-unplugge
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void USBRemovedHandler(object sender, EventArrivedEventArgs e)
+        {
+            PropertyData targetInstanceData = e.NewEvent.Properties["TargetInstance"];
+
+            if (targetInstanceData != null)
+            {
+                ManagementBaseObject targetInstanceObject = (ManagementBaseObject)targetInstanceData.Value;
+                if (targetInstanceData != null)
+                {
+                    string dependent = targetInstanceObject.Properties["Dependent"].Value.ToString();
+                    string deviceId = dependent.Substring(dependent.IndexOf("DeviceID=") + 10);
+
+                    if (deviceId.StartsWith("USB\\\\VID_0B6A&PID_003C")  // FW 1.5
+                        || deviceId.StartsWith("USB\\\\VID_1F00&PID_2012\\\\0123456789")
+                        || deviceId.StartsWith("USB\\\\VID_0B6A&PID_0100")) // FW 2.0 mbed
+                    {
+                        // device is disconnected
+                        guiDisconnected();
+                        try
+                        {
+                            rpcClient.Disconnect();
+                        }
+                        catch (System.IO.IOException)
+                        {
+
+                        }
+                        catch (NullReferenceException)
+                        {
+                            // Disconnecting when it doesn't exist
+                            // Occurs when you pull the USB while on the com port selection window
+                        }
+                    }
+                }
+
+            }
+            
+        }
+
+        private void InitSplashScreen()
+        {
+            splashScreen.maximSplashScreen1.CopyrightString = "©2016 Maxim Integrated Products, Inc.";
+            splashScreen.maximSplashScreen1.VersionString = "Version " + MAJORVERSION.ToString() + "." + MINORVERSION.ToString() + "." + PATCHVERSION.ToString() + VersionSuffix;
+            splashScreen.maximSplashScreen1.ApplicationName = this.Text;
+            //splashScreen.maximSplashScreen1.Checked = Properties.Settings.Default.DisableSplash;
+        }
+
+        void comPortConnect()
+        {
+            bool tryPreviousComPort = true;
+
+            connectionDialog.Reset();
+            connectionDialog.ScanPorts();
+
+            while (true)
+            {
+                // Try to connect to the previous port, if we have not tried before 
+                // and it the port string is not an empty string ("")
+                if (tryPreviousComPort == true
+                    && String.Compare(Properties.Settings.Default.ComPort, "") != 0)
+                {
+                    tryPreviousComPort = false;
+                }
+                else
+                {
+                    connectionDialog.ShowDialog();
+                }
+
+                // Break out of loop if user canceled
+                if (connectionDialog.Canceled == true)
+                {
+                    guiDisconnected();
+                    break;
+                }
+
+                // Get the port from the dialog form, returns default property
+                // for first use
+                port = connectionDialog.Port;
+                if (String.Compare(port, "") == 0)
+                    continue;
+
+
+                // Connect to port
+                try
+                {
+                    rpcClient.Connect(port);
+                    if (rpcClient.IsConnected() == true)
+                    {
+                        guiConnected();
+                        break;
+                    }
+                    else // Connected to COM port, but cannot query STM32_HV
+                    {
+                        MessageBox.Show("Device not found on selected port", "Connection Issue");
+                        guiDisconnected();
+                    }
+                }
+                catch (TimeoutException)
+                {
+                    guiDisconnected();
+                    rpcClient.Disconnect();
+                    MessageBox.Show("Unable to communicate with device, communication timed out.\nVerified selected port is correct.",
+                        "Connection Issue");
+                }
+                catch (System.IO.IOException)
+                {
+                    guiDisconnected();
+                    MessageBox.Show("Select a valid COM port. Unable to connect with device.\n\nVerify the " + PartNumber + " board is plugged in and turned on. Turn on by pressing the button on the board for 3 seconds until the red LED starts blinking.",
+                        "Connection Issue");
+                }
+                catch (UnauthorizedAccessException)
+                {
+                    // Port does not exist
+                }
+            }
+        }
+
+        bool checkFirmware()
+        {
+            string reply;
+
+            reply = rpcClient.RawRpcCall(readVersionCommand, true);
+
+            return reply.StartsWith(firmwareKey);
+        }
+
+        void guiConnected()
+        {
+            ss_Status.Items[1].Text = rpcClient.Version();//rpcClient.RawRpcCall(readVersionCommand, true); // TODO this should be moved into the RPCSupport as a virtual system device
+            ss_Status.Items[2].Text = "Hardware Connected (" + port + ")";
+
+            connected = true;
+
+            //connectionToolStripMenuItem.Enabled = false;
+            //disconnectToolStripMenuItem.Enabled = true;
+
+            connectionToolStripMenuItem.Checked = true;
+            disconnectToolStripMenuItem.Checked = false;
+
+            // Enable Communication for each Device View
+            foreach (IDeviceView device in deviceViews)
+            {
+                device.Connected = true;
+            }
+
+            // TODO Ask F/W team if this is needed
+            rpcClient.MAX30001.WriteReg(0x02, 0x3);
+            rpcClient.MAX30001.WriteReg(0x03, 0x3);
+
+            max30001Model = new Model.MAX30001Model(max30001);
+            partIDInit();
+
+            dataLoggingView1.Enabled = checkFlashID();
+
+            // Read device registers
+            UpdateRegisters();
+
+            if (Connected != null)
+                Connected(this, new EventArgs());
+        }
+
+
+        void guiDisconnected()
+        {
+            if (this.ss_Status.InvokeRequired)
+            {
+                guiDisconnectedCallBack d = new guiDisconnectedCallBack(guiDisconnected);
+                this.Invoke(d);
+            }
+            else
+            {
+                ss_Status.Items[1].Text = "";
+                ss_Status.Items[2].Text = "Hardware Not Connected";
+                //UpdateConnection(null, false);;
+                connected = false;
+
+                //connectionToolStripMenuItem.Enabled = true;
+                //disconnectToolStripMenuItem.Enabled = false;
+
+                connectionToolStripMenuItem.Checked = false;
+                disconnectToolStripMenuItem.Checked = true;
+
+                foreach (IDeviceView device in deviceViews)
+                {
+                    device.Connected = false;
+                }
+            }
+        }
+
+        void InitRpcClient()
+        {
+            rpcClient = new RPCSupport.RPCClient(RPCSupport.RPCClient.ePipeline.eSerialWrap);
+            rpcClient.InitPipeline();
+        }
+
+        void InitRpcDevices()
+        {
+            i2cDevice = rpcClient.Init_I2cDevice();
+            spiDevice = rpcClient.Init_SpiDevice();
+            max30101 = rpcClient.Init_MAX30101(0xAE);
+            max30205 = rpcClient.Init_MAX30205(0x32);
+            lis2hd = rpcClient.Init_LIS2HD(0x50);
+            max30001 = rpcClient.Init_MAX30001();
+            logging = rpcClient.Init_Logging();
+        }
+
+        private void Form_Load(object sender, EventArgs e)
+        {
+          if (splashScreen.SplashDisabled() == false)
+                splashScreen.ShowDialog();
+            
+            while (splashScreen.Visible == true)
+                Thread.Sleep(100);
+
+            comPortConnect();
+        }
+
+        void PrimitivesViewInit()
+        {
+            primitivesView1.rpcClient = rpcClient;
+            primitivesView1.i2cDevice = i2cDevice;
+            primitivesView1.spiDevice = spiDevice;
+            primitivesView1.max30101 = max30101;
+            primitivesView1.max30205 = max30205;
+            primitivesView1.max30001 = max30001;
+            primitivesView1.lis2hd = lis2hd;
+
+            maximTabControl1.HideTab("tpPrimitives");
+        }
+
+        void OpticalViewInit()
+        {
+            opticalView1.RPCClient = rpcClient;
+            //opticalView1.StreamingStartStop += new OpticalView.StreamingStartStopEventHandler(opticalView_StreamingStartStop);
+            opticalView1.StreamingStartStop += new EventHandler<StreamingStartStopEventArgs>(opticalView_StreamingStartStop);
+            dataLoggingView1.LoggingParametersChanged += new DataLoggingView.LoggingParametersHandler(dataLoggingFlashReadEventHandler);
+
+            MaximSKAlgorithmClass algorithm = new MaximSKAlgorithmClass();
+            OpticalAlgorithmPresenter presenter = new OpticalAlgorithmPresenter(rpcClient, algorithm, opticalView1);
+        }
+
+        void ECGPlotsViewInit()
+        {
+            ecgView1.RPCClient = rpcClient;
+
+            //cboEnRToR.SelectedIndexChanged += new EventHandler(cboStreaming_SelectedIndexChanged);
+            //cboECGChannelEnable.SelectedIndexChanged += new EventHandler(cboStreaming_SelectedIndexChanged);
+
+            ecgView1.GetEcgInitArgsPointer = new CustomControls.EcgView.GetEcgInitArgs(getEcgArgs); 
+            ecgView1.GetRToRInitArgsPointer = new CustomControls.EcgView.GetRToRInitArgs(getRToRArgs);
+            ecgView1.GetBioZInitArgsPointer = new CustomControls.EcgView.GetBioZInitArgs(getBioZArgs);
+            ecgView1.GetPaceInitArgsPointer = new CustomControls.EcgView.GetPaceInitArgs(getPaceArgs);
+
+            ecgView1.StreamingStartStop += new EventHandler<StreamingStartStopEventArgs>(ecgView_StreamingStartStop);
+
+            ecgView1.HspSetting = this;
+
+            StreamPresenter streamPresenter = new StreamPresenter(rpcClient, ecgView1, this);
+        }
+
+        void LoggingViewInit()
+        {
+            dataLoggingView1.RPCClient = rpcClient;
+
+            dataLoggingView1.GetEcgInitArgsPointer = new CustomControls.DataLoggingView.GetEcgInitArgs(getEcgArgs);
+            dataLoggingView1.GetRToRInitArgsPointer = new CustomControls.DataLoggingView.GetRToRInitArgs(getRToRArgs);
+            dataLoggingView1.GetBioZInitArgsPointer = new CustomControls.DataLoggingView.GetBioZInitArgs(getBioZArgs);
+            dataLoggingView1.GetPaceInitArgsPointer = new CustomControls.DataLoggingView.GetPaceInitArgs(getPaceArgs);
+            dataLoggingView1.GetFMSTRInitArgsPointer = new CustomControls.DataLoggingView.GetFMSTRInitArgs(getFMSTRArgs);
+            dataLoggingView1.GetHRModeInitArgsPointer = new CustomControls.DataLoggingView.GetHRModeInitArgs(opticalView1.GetHRModeArgs);
+            dataLoggingView1.GetSpO2HRModeInitArgsPointer = new CustomControls.DataLoggingView.GetSpO2HRModeInitArgs(opticalView1.GetSpO2HRModeArgs);
+            dataLoggingView1.GetMultiModeInitArgsPointer = new CustomControls.DataLoggingView.GetMultiModeInitArgs(opticalView1.GetMultiModeArgs);
+
+            Model.DataLogModel dataLogModel = new Model.DataLogModel(rpcClient);
+            DataLogPresenter dataLogPresenter = new DataLogPresenter(this, ecgView1, opticalView1, dataLogModel, dataLoggingView1, new RawFileLogView(), new RawFileLogView(), new RawFileLogView(), 
+                new RawFileLogView(), new RawFileLogView(), new RawFileLogView(), new RawFileLogView(), new RawFileLogView(), new RawFileLogView());
+        }
+
+        void FileLoggingInit()
+        {
+            IRawFileLogView ecgFileLog = new RawFileLogView();
+            IRawFileLogView bioZFileLog = new RawFileLogView();
+
+            //fileLogPresenter = new FileLogPresenter(ecgFileLog, bioZFileLog, this, rpcClient, ecgView1);
+            //ecgView1.EcgLog = ecgFileLog;
+            //ecgView1.BioZLog = bioZFileLog;
+
+            IRawFileLogView ecgRawFileLog = new RawFileLogView();
+            IRawFileLogView paceRawFileLog = new RawFileLogView();
+            IRawFileLogView rToRFileLog = new RawFileLogView();
+            IRawFileLogView bioZRawFileLog = new RawFileLogView();
+            rawFileLogPresenter = new RawFileLogPresenter(ecgRawFileLog, bioZRawFileLog, rToRFileLog, paceRawFileLog, this, rpcClient, ecgView1, dataLoggingView1);
+
+            IRawFileLogView opticalFileLog = new RawFileLogView();
+            IRawFileLogView accelFileLog = new RawFileLogView();
+
+            opticalFileLogPresenter = new OpticalFileLogPresenter(rpcClient, this, opticalView1, opticalFileLog, accelFileLog);
+
+        }
+
+        void RegisterExportInit()
+        {
+            RegisterExportPresenter registerExportPresenter;
+            RegisterExportForm exportForm = new RegisterExportForm();
+            List<Maxim.CustomControls.RegisterView> registerViewList = new List<Maxim.CustomControls.RegisterView>(); 
+
+            registerViewList.AddRange(registerViews);
+
+            registerExportPresenter = new RegisterExportPresenter(this, exportForm, registerViewList);
+        }
+        
+        private void txt_Status_TextChanged(object sender, EventArgs e)
+        {
+            //Scroll to the bottom of the textbox when text is added
+            txt_Status.SelectionStart = txt_Status.Text.Length;
+            txt_Status.ScrollToCaret();
+            txt_Status.Refresh();
+        }
+
+        private void btn_Clear_Click(object sender, EventArgs e)
+        {
+            //clear the status box
+            txt_Status.Text = "";
+        }
+
+        private void rvLIS2HDInit()
+        {
+            Maxim.CustomControls.LIS2DHInfo lis2DHInfo = new Maxim.CustomControls.LIS2DHInfo();
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(lis2DHInfo);
+            controller.SetInterface(rpcClient);
+            rvLIS2HD.SetController(controller);
+            //rvLIS2HD.ReadAll();
+            rvLIS2HD.DisplayRegisters();
+            rvLIS2HD.DeviceName = "LIS2DH";
+
+
+            //registerInfoData[0] = lis2DHInfo.Info;
+        }
+
+        private void rvMAX30101Init()
+        {
+            Maxim.CustomControls.MAX30101Info max30101Info = new Maxim.CustomControls.MAX30101Info();
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(max30101Info);
+            controller.SetInterface(rpcClient);
+            rvMAX30101.SetController(controller);
+            //rvMAX30101.ReadAll();
+            rvMAX30101.DisplayRegisters();
+            rvMAX30101.DeviceName = "MAX30101";
+
+
+            //registerInfoData[1] = max30101Info.Info;
+        }
+
+        private void rvMAX30205Init()
+        {
+            Maxim.CustomControls.MAX30205Info max30205Info = new Maxim.CustomControls.MAX30205Info(0x92);
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(max30205Info);
+            controller.SetInterface(rpcClient);
+            rvMAX30205.SetController(controller);
+            //rvMAX30205.ReadAll();
+            rvMAX30205.DisplayRegisters();
+            rvMAX30205.DeviceName = "MAX30205 (Top)";
+
+
+            //registerInfoData[2] = max30205Info.Info;
+        }
+
+        private void rvMAX30205_U18Init()
+        {
+            Maxim.CustomControls.MAX30205Info max30205Info = new Maxim.CustomControls.MAX30205Info();
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(max30205Info);
+            controller.SetInterface(rpcClient);
+            rvMAX30205_U18.SetController(controller);
+            //rvMAX30205_U18.ReadAll();
+            rvMAX30205_U18.DisplayRegisters();
+            rvMAX30205_U18.DeviceName = "MAX30205 (Bottom)";
+
+
+            //registerInfoData[3] = max30205Info.Info;
+        }
+
+        private void rvMAX30001Init()
+        {
+            Maxim.CustomControls.MAX30001Info max30001Info = new Maxim.CustomControls.MAX30001Info();
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(max30001Info);
+            controller.SetInterface(rpcClient);
+            rvMAX30001.SetController(controller);
+            //rvMAX30001.ReadAll();
+            rvMAX30001.DisplayRegisters();
+            rvMAX30001.DeviceName = "MAX30001";
+
+
+            //registerInfoData[4] = max30001Info.Info;
+        }
+
+        private void rvMAX30003Init()
+        {
+            Maxim.CustomControls.MAX30003Info max30003Info = new Maxim.CustomControls.MAX30003Info();
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(max30003Info);
+            controller.SetInterface(rpcClient);
+            rvMAX30001.SetController(controller);
+            //rvMAX30001.ReadAll();
+            rvMAX30001.DisplayRegisters();
+            rvMAX30001.DeviceName = "MAX30003";
+        }
+
+        private void rvMAX14720Init()
+        {
+            Maxim.CustomControls.MAX14720Info max14720Info = new Maxim.CustomControls.MAX14720Info();
+            Maxim.CustomControls.DeviceController controller = new Maxim.CustomControls.DeviceController();
+            controller.SetRegisterInfo(max14720Info);
+            controller.SetInterface(rpcClient);
+            rvMAX14720.SetController(controller);
+            //rvMAX14720.ReadAll();
+            rvMAX14720.DisplayRegisters();
+            rvMAX14720.DeviceName = "MAX14720";
+
+            //registerInfoData[5] = max14720Info.Info;
+        }
+
+        private void partIDInit()
+        {
+            //rvMAX30001.Clear();
+            tabPageEnable(null, false);
+            switch (max30001Model.PartID)
+            {
+                case Model.MAX30001Model.Part.MAX30003:
+                    // General GUI
+                    bioZMilliohmScaleToolStripMenuItem.Enabled = false;
+                    registerNamesToolStripMenuItem.Text = "Show MAX30003 Register Names";
+                    paceFileLogToolStripMenuItem.Enabled = false;
+                    bioZFileLogToolStripMenuItem.Enabled = false;
+
+                    // Block Diagram
+                    picBlockDiagram.Image = global::HealthSensorPlatform.Properties.Resources.system_block_diagram_max30003;
+                    linkBioZChannel.Visible = false;
+                    linkBioZMux.Visible = false;
+                    linkBioZLoad.Visible = false;
+                    linkPaceChannel.Visible = false;
+                    linkLabelQuickBioimpedance.Visible = false;
+                    linkLabelQuickRespiration.Visible = false;
+
+                    // Global Panel
+                    chkEnBioZ.Enabled = false;
+                    chkEnPace.Enabled = false;
+                    grpGlobalControls.Text = "MAX30003 Global Controls";
+
+                    // Tabs - not working 
+                    tabPageEnable(null, true);
+
+                    // Plots
+                    ecgView1.BioZFunction(false);
+
+                    // Data Logging Tab
+                    dataLoggingView1.PaceFunction(false);
+                    dataLoggingView1.BioZFunction(false);
+
+                    //Register Tabs
+                    for(int i = 0; i < cboRegisterTabDevice.Items.Count; i++)
+                    {
+                        if ((string)cboRegisterTabDevice.Items[i] == "MAX30001")
+                        {
+                            cboRegisterTabDevice.Items[i] = "MAX30003";
+                        }
+
+                    }
+                    rvMAX30003Init();
+
+                    break;
+                case Model.MAX30001Model.Part.MAX30001:
+                    // Defaults
+                    // General GUI
+                    bioZMilliohmScaleToolStripMenuItem.Enabled = true;
+                    registerNamesToolStripMenuItem.Text = "Show MAX30001 Register Names";
+                    paceFileLogToolStripMenuItem.Enabled = true;
+                    bioZFileLogToolStripMenuItem.Enabled = true;
+
+                    // Block Diagram
+                    picBlockDiagram.Image = global::HealthSensorPlatform.Properties.Resources.system_block_diagram;
+                    linkBioZChannel.Visible = true;
+                    linkBioZMux.Visible = true;
+                    linkBioZLoad.Visible = true;
+                    linkPaceChannel.Visible = true;
+                    linkLabelQuickBioimpedance.Visible = true;
+                    linkLabelQuickRespiration.Visible = true;
+
+                    // Global Panel
+                    grpGlobalControls.Text = "MAX30001 Global Controls";
+                    chkEnBioZ.Enabled = true;
+                    chkEnECG.Enabled = true;
+                    chkEnPace.Enabled = true;
+                    chkEnRtor.Enabled = true;
+
+                    // Tabs - not working
+                    tabPageEnable(null, true);
+
+                    // Plots
+                    ecgView1.BioZFunction(true);
+
+                    // Data Logging Tab
+                    dataLoggingView1.PaceFunction(true);
+                    dataLoggingView1.BioZFunction(true);
+
+                    //Register Tabs
+                    for (int i = 0; i < cboRegisterTabDevice.Items.Count; i++)
+                    {
+                        if ((string)cboRegisterTabDevice.Items[i] == "MAX30003")
+                        {
+                            cboRegisterTabDevice.Items[i] = "MAX30001";
+                        }
+
+                    }
+                    rvMAX30001Init();
+                    break;
+            }
+        }
+
+        private bool checkFlashID()
+        {
+            string reply;
+
+            reply = rpcClient.RawRpcCall(readFlashIDCommand, true);
+
+            return (reply.StartsWith("00010219"));
+        }
+
+        private void tabPageEnable(TabPage exception, bool enable)
+        {
+            if (enable)
+            {
+                if (max30001Model.PartID == MAX30001Model.Part.MAX30003)
+                {
+                    foreach (TabPage tp in maximTabControl1.TabPages)
+                    {
+                        if (!max30001TabPages.Contains(tp))
+                            tp.Enabled = true;
+                    }
+                }
+                else
+                {
+                    foreach (TabPage tp in maximTabControl1.TabPages)
+                    {
+                        tp.Enabled = true;
+                    }
+                }
+            }
+            else
+            {
+                foreach (TabPage tp in maximTabControl1.TabPages)
+                {
+                    if (tp != exception)
+                        tp.Enabled = false;
+                }
+            }
+
+            maximTabControl1.Invalidate();
+        }
+
+        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            splashScreen = new SplashScreen(120);
+            InitSplashScreen();
+            splashScreen.Show();
+            splashScreen.ShowOKButton();
+        }
+
+        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            Application.Exit();
+        }
+
+        private void maximTabControl1_SelectedIndexChanged(object sender, EventArgs e)
+        {
+
+            temperatureView1.TimerState(false);
+            //ecgView1.Stream = false; // Disconnect plotting event for flash log data loading
+
+            if (maximTabControl1.SelectedTab == tpBlockDiagram)
+            {
+                updateBlockDiagramLayout();
+            }
+            else if (maximTabControl1.SelectedTab == tpTemperature)
+            {
+                if (connected)
+                {
+                    // TODO
+                    /*
+                    temperatureView1.TimerState(true);
+                    temperatureView1.UpdateRegisters();
+                    temperatureView1.ReadTemperature();
+                    */
+                    temperatureView1.TimerState(true);
+                    temperaturePresenter.OnReadAll(this, new EventArgs());
+                }
+            }
+            else if (maximTabControl1.SelectedTab == tpMAX30001EcgChannel)
+            {
+                if (connected)
+                { 
+                    ECGChannelUpdateRegisters(); // and R to R
+                    ECGGlobalUpdateRegisters();
+                }
+
+                pnlMAX30001Global.Parent = tpMAX30001EcgChannel;
+            }
+            else if (maximTabControl1.SelectedTab == tpMAX30001InputMux)
+            {
+                if (connected)
+                {
+                    ECGInputMuxUpdateRegisters();
+                    ECGGlobalUpdateRegisters();
+                }
+
+                pnlMAX30001Global.Parent = tpMAX30001InputMux;
+            }
+            else if (maximTabControl1.SelectedTab == tpMAX30001Plots)
+            {
+                pnlMAX30001Global.Parent = tpMAX30001Plots;
+                //ecgView1.Stream = true;
+                //pnlMAX30001Global.BringToFront();
+                if (connected)
+                {
+                    ECGGlobalUpdateRegisters();
+                }
+            }
+            else if (maximTabControl1.SelectedTab == tpBioZChannel)
+            {
+                if (connected)
+                {
+                    BioZChannelUpdateRegisters();
+                    ECGGlobalUpdateRegisters();
+                }
+                pnlMAX30001Global.Parent = tpBioZChannel;
+            }
+            else if (maximTabControl1.SelectedTab == tpMAX30001BioZInputMux)
+            {
+                if (connected)
+                {
+                    BioZInputMuxUpdateRegisters();
+                    ECGGlobalUpdateRegisters();
+                }
+                pnlMAX30001Global.Parent = tpMAX30001BioZInputMux;
+            }
+            else if (maximTabControl1.SelectedTab == tpMAX30001BioZLoad)
+            {
+                if (connected)
+                {
+                    BioZLoadUpdateRegisters();
+                    ECGGlobalUpdateRegisters();
+                }
+                UpdateBioZLoadSwitches(); 
+                pnlMAX30001Global.Parent = tpMAX30001BioZLoad;
+            }
+            else if (maximTabControl1.SelectedTab == tpMAX30001Pace)
+            {
+                if (connected)
+                {
+                    PaceChannelUpdateRegisters();
+                    ECGGlobalUpdateRegisters();
+                }
+                pnlMAX30001Global.Parent = tpMAX30001Pace;
+            }
+            else if (maximTabControl1.SelectedTab == tpFlashLog)
+            {
+                if (connected)
+                {
+                    dataLoggingView1.UpdateArgs();
+                }
+            }
+            else if (maximTabControl1.SelectedTab == tpRegisters)
+            {
+                if (connected)
+                {
+                    ((Maxim.CustomControls.RegisterView)registerViewDict[(string)(cboRegisterTabDevice.SelectedItem)]).ReadAll(); 
+                }
+            }
+
+            if (maximTabControl1.SelectedTab != null) // Support dynamic adding/removing of tabs
+                pnlMAX30001Global.Location = new Point(0, maximTabControl1.SelectedTab.Size.Height - pnlMAX30001Global.Size.Height);
+
+            ss_Status.MessagesLabel.Text = ""; // Clear any message from previous tabs
+        }
+
+        /// <summary>
+        /// Read all registers, used for first connect
+        /// </summary>
+        public void UpdateRegisters()
+        {
+            ECGChannelUpdateRegisters();
+            ECGInputMuxUpdateRegisters();
+            ECGGlobalUpdateRegisters();
+            BioZChannelUpdateRegisters();
+            BioZInputMuxUpdateRegisters();
+            BioZLoadUpdateRegisters();
+            PaceChannelUpdateRegisters();
+
+            //rvLIS2HD.ReadAll();
+            //rvMAX14720.ReadAll();
+            //rvMAX30001.ReadAll();
+            //rvMAX30101.ReadAll();
+            //rvMAX30205.ReadAll();
+            //rvMAX30205_U18.ReadAll();
+        }
+
+        #region Temperature Tab
+        private void TemperatureViewInit()
+        {
+            MAX30205Model max30205_1 = new MAX30205Model(rpcClient.I2cDevice, 0x92);
+            MAX30205Model max30205_2 = new MAX30205Model(rpcClient.I2cDevice, 0x90);
+
+            temperaturePresenter = new MAX30205EVKit.Presenter.TemperaturePresenter(new MAX30205Model[] { max30205_1, max30205_2 }, temperatureView1, temperatureView1);
+            //temperatureView1.max30205_1 = max30205;
+            //temperatureView1.i2cDevice = i2cDevice;
+        }
+        #endregion
+
+        #region Register Tab
+        private void RegistersTabInit()
+        {
+            pnlRegMAX30101.Visible = true;
+            pnlRegMAX30101.Visible = false;
+            pnlRegMAX30205.Visible = false;
+            pnlRegMAX14720.Visible = false;
+
+            rvLIS2HDInit();
+            rvMAX30001Init();
+            rvMAX30101Init();
+            rvMAX30205Init();
+            rvMAX30205_U18Init();
+            rvMAX14720Init();
+            registerViewDict.Add(rvLIS2HD.DeviceName, rvLIS2HD);
+            registerViewDict.Add(rvMAX30001.DeviceName, rvMAX30001);
+            registerViewDict.Add("MAX30003", rvMAX30001);
+            registerViewDict.Add(rvMAX30101.DeviceName, rvMAX30101);
+            registerViewDict.Add(rvMAX30205.DeviceName, rvMAX30205);
+            registerViewDict.Add(rvMAX30205_U18.DeviceName, rvMAX30205_U18);
+            registerViewDict.Add(rvMAX14720.DeviceName, rvMAX14720);
+
+            cboRegisterTabDevice.Items.Clear();
+            foreach (Maxim.CustomControls.RegisterView rv in registerViews)
+                cboRegisterTabDevice.Items.Add(rv.DeviceName);
+
+            cboRegisterTabDevice.SelectedIndex = 0;
+
+            // Update status message when write is complete. Clear status message when entering the register data cell
+            foreach (Maxim.CustomControls.RegisterView rv in registerViews)
+            {
+                rv.CellBeginEdit += new Maxim.CustomControls.RegisterView.CellBeginEditHandler(registerView_CellBeginEdit);
+                rv.RegisterWriteComplete += new Maxim.CustomControls.RegisterView.RegisterWriteCompleteHandler(registerView_WriteComplete);
+            }
+
+        }
+
+        private void cboRegisterTabDevice_SelectedIndexChanged(object sender, EventArgs e)
+        {
+            MaximStyle.MaximComboBox cbo = (MaximStyle.MaximComboBox)sender;
+
+            if (cbo.Text.CompareTo(rvMAX30001.DeviceName) == 0)
+            {
+                pnlRegMAX30001.Visible = true;
+                pnlRegMAX30101.Visible = false;
+                pnlRegMAX30205.Visible = false;
+                pnlRegMAX30205_U18.Visible = false;
+                pnlRegLIS2HD.Visible = false;
+                pnlRegMAX14720.Visible = false;
+                rvMAX30001.ReadAll();
+            }
+            else if (cbo.Text.CompareTo(rvMAX30101.DeviceName) == 0)
+            {
+                pnlRegMAX30001.Visible = false;
+                pnlRegMAX30101.Visible = true;
+                pnlRegMAX30205.Visible = false;
+                pnlRegMAX30205_U18.Visible = false;
+                pnlRegLIS2HD.Visible = false;
+                pnlRegMAX14720.Visible = false;
+                rvMAX30101.ReadAll();
+            }
+            else if (cbo.Text.CompareTo(rvMAX30205.DeviceName) == 0)
+            {
+                pnlRegMAX30001.Visible = false;
+                pnlRegMAX30101.Visible = false;
+                pnlRegMAX30205.Visible = true;
+                pnlRegMAX30205_U18.Visible = false;
+                pnlRegLIS2HD.Visible = false;
+                pnlRegMAX14720.Visible = false;
+                rvMAX30205.ReadAll();
+            }
+            else if (cbo.Text.CompareTo(rvMAX30205_U18.DeviceName) == 0)
+            {
+                pnlRegMAX30001.Visible = false;
+                pnlRegMAX30101.Visible = false;
+                pnlRegMAX30205.Visible = true;
+                pnlRegMAX30205_U18.Visible = true;
+                pnlRegLIS2HD.Visible = false;
+                pnlRegMAX14720.Visible = false;
+                rvMAX30205_U18.ReadAll();
+            }
+            else if (cbo.Text.CompareTo(rvLIS2HD.DeviceName) == 0)
+            {
+                pnlRegMAX30001.Visible = false;
+                pnlRegMAX30101.Visible = false;
+                pnlRegMAX30205.Visible = false;
+                pnlRegMAX30205_U18.Visible = false;
+                pnlRegLIS2HD.Visible = true;
+                pnlRegMAX14720.Visible = false;
+                rvLIS2HD.ReadAll();
+            }
+            else if (cbo.Text.CompareTo(rvMAX14720.DeviceName) == 0)
+            {
+                pnlRegMAX30001.Visible = false;
+                pnlRegMAX30101.Visible = false;
+                pnlRegMAX30205.Visible = false;
+                pnlRegMAX30205_U18.Visible = false;
+                pnlRegLIS2HD.Visible = false;
+                pnlRegMAX14720.Visible = true;
+                rvMAX14720.ReadAll();
+            }
+        }
+        #endregion
+
+        #region Optical Tab
+        private void opticalView_StreamingStartStop(object sender, StreamingStartStopEventArgs e)
+        {
+            /* Disable user selection to Tabs when Streaming is enabled */
+            streaming = e.state;
+            if (e.state == true)
+            {
+                tabPageEnable(tpOpticalSensor, false);
+            }
+            else
+            {
+                tabPageEnable(tpOpticalSensor, true);
+            }
+            maximTabControl1.Invalidate(); // Redraw the tabs
+        }
+        #endregion
+
+        #region Block Diagrams
+        private void BlockDiagramsInit()
+        {
+            initalizeECGConfigFields(); 
+            initalizeECGInputMuxFields();
+            initalizeRToRFields();
+            initalizeECGGlobalControls();
+            initalizeBioZConfigFields();
+            initalizeBioZInputMuxFields();
+            initalizeBioZLoadFields();
+            initalizePaceChannelFields();
+
+            // Set ECG Gain setting for chart Y-scale purposes
+            cboChannelGain.SelectedIndexChanged += new EventHandler(cboChannelGain_SelectedIndexChanged);
+
+            //cboECGChannelEnable.SelectedIndex = 0; // Default is disabled
+
+            initalizeToolTipEvents(ecgChannelField);
+            initalizeToolTipEvents(rToRField);
+            initalizeToolTipEvents(ecgInputMuxField);
+            initalizeToolTipEvents(ecgGlobalField);
+            initalizeToolTipEvents(bioZChannelField);
+            initalizeToolTipEvents(bioZInputMuxField);
+            initalizeToolTipEvents(bioZLoadField);
+            initalizeToolTipEvents(paceChannelField);
+
+            // Force panel load for location placement in case of window resize
+            // on a tab where the panel is not shown otherwise it will show in a strange location
+            pnlMAX30001Global.Parent = tpMAX30001EcgChannel;
+        }
+
+        #endregion
+
+        #region Streaming
+        private void ecgView_StreamingStartStop(object sender, StreamingStartStopEventArgs e)
+        {
+            streaming = e.state;
+            /* Disable user selection to Tabs when Streaming is enabled */
+            if (e.state == true)
+            {
+                tabPageEnable(tpMAX30001Plots, false);
+
+                grpChannelPlotEnable.Enabled = false;
+                grpGlobalControls.Enabled = false;
+                menuStrip1.Enabled = false;
+            }
+            else
+            {
+                if (connected)
+                {
+                    // Rewrite enable bits for global controls to allow GUI to maintain consistent state
+                    foreach (RegisterField field in channelEnableField)
+                    {
+                        MaximCheckBox chk = (MaximStyle.MaximCheckBox)field.Control;
+
+                        if (chk.Checked)
+                            writeCheckBox(chk);
+                    }
+
+                    if (cboEnRbias.SelectedIndex != 0)
+                        writeComboBox(cboEnRbias);
+                    else if (cboBioZEnRbias.SelectedIndex != 0)
+                        writeComboBox(cboBioZEnRbias);
+
+                    if (cboEnDcloff.SelectedIndex != 0)
+                        writeComboBox(cboEnDcloff);
+                    else if (cboBioZEnDcloff.SelectedIndex != 0)
+                        writeComboBox(cboBioZEnDcloff);
+
+                    if (cboBioZDigitalLeadOffDetectionEnable.SelectedIndex != 0)
+                        writeComboBox(cboBioZDigitalLeadOffDetectionEnable);
+
+                    if (cboEmuxEnUlpLon.SelectedIndex != 0)
+                        writeComboBox(cboEmuxEnUlpLon);
+                    else if (cboBmuxEnUlpLon.SelectedIndex != 0)
+                        writeComboBox(cboBmuxEnUlpLon);
+
+                }
+                
+                tabPageEnable(tpMAX30001Plots, true);
+
+                grpChannelPlotEnable.Enabled = true;
+                grpGlobalControls.Enabled = true;
+                menuStrip1.Enabled = true;
+            }
+
+            maximTabControl1.Invalidate(); // Redraw the tabs
+        }
+        #endregion
+
+        #region Data Logging
+        // When Data Logging reads the flash, update the values on the other tabs to match what is in the flash
+        // The data logging tab will generate an event and run this method
+        private void dataLoggingFlashReadEventHandler(object sender, EventArgs e)
+        {
+            DataLoggingView dlView = (DataLoggingView)sender;
+
+            if (dlView.EnableOpticalHR)
+            {
+                opticalView1.SetHRModeArgs(dlView.HRModeArgs);
+            }
+            else if (dlView.EnableOpticalSpO2)
+            {
+                opticalView1.SetSpO2HRModeArgs(dlView.SpO2HRModeArgs);
+            }
+            else if (dlView.EnableOpticalMulti)
+            {
+                opticalView1.SetMultiModeArgs(dlView.MultiModeArgs);
+            }
+
+            if (dlView.EnableEcg)
+            {
+                setEcgArgs(dlView.EcgArgs);
+            }
+
+            if (dlView.EnableBioz)
+            {
+                setBioZArgs(dlView.BioZArgs);
+            }
+
+            if (dlView.EnableRToR)
+            {
+                setRToRArgs(dlView.RToRArgs);
+            }
+
+            if (dlView.EnablePace)
+            {
+                setPaceArgs(dlView.PaceArgs);
+            }
+        }
+        #endregion
+
+        private void connectionToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (connectionToolStripMenuItem.Checked)
+            {
+                connectionToolStripMenuItem.Checked = true;
+                return;
+            }
+
+            if (!connected)
+            {
+                comPortConnect();
+            }
+        }
+
+        private void disconnectToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (disconnectToolStripMenuItem.Checked)
+            {
+                disconnectToolStripMenuItem.Checked = true;
+                return;
+            }
+
+            if (connected)
+            {
+                guiDisconnected();
+                rpcClient.Disconnect();
+            }
+        }
+
+        /// <summary>
+        /// Stop streaming before exiting HSP
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void HspForm_FormClosing(object sender, FormClosingEventArgs e)
+        {
+            try
+            {
+                if (connected)
+                {
+                    opticalView1.Close(); // Stop streaming
+                    ecgView1.Close();
+                }
+            }
+            catch (Exception)
+            {
+                // We are exiting the GUI, we can ignore all exceptions
+                // Adding this for the case where the user unplugs HSP and quickly tries to close
+                // before the operating system reports USB removed
+                // Occurs while streaming ECG because we re-write the interrupt registers on stream stop
+                return;
+            }
+        }
+
+        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001InputMux;
+        }
+
+        private void linkLabel2_Click(object sender, EventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001BioZInputMux;
+        }
+
+        private void linkLabelBioZLoad_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001BioZLoad;
+        }
+
+        private void linkLabelQuickOpticalSpO2_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            if (connected)
+            {
+                opticalView1.OpticalSensorDefaults();
+                maximTabControl1.SelectedTab = tpOpticalSensor;
+            }
+        }
+
+        private void linkLabelQuickTemperature_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            if (connected)
+            {
+                temperaturePresenter.WriteRegister(0, 1, 0);
+                temperaturePresenter.WriteRegister(1, 1, 0);
+                maximTabControl1.SelectedTab = tpTemperature;
+            }
+        }
+
+        private void linkLabelQuickEcg_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            if (connected)
+            {
+                // SW_RST
+                max30001Model.Write(0x08, 1);
+                max30001Model.Write(0x08, 0);
+                // CNFG_GEN
+                max30001Model.Write(0x10, 0x080017);
+                // CNFG_EMUX
+                max30001Model.Write(0x14, 0x000000);
+                // CNFG_RTOR1
+                max30001Model.Write(0x1d, 0x3FA300);
+
+                ECGChannelUpdateRegisters();
+                ECGInputMuxUpdateRegisters();
+
+                maximTabControl1.SelectedTab = tpMAX30001Plots;
+            }
+        }
+
+        private void linkLabelQuickBioimpedance_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            if (connected)
+            {
+                // SW_RST
+                max30001Model.Write(0x08, 1);
+                max30001Model.Write(0x08, 0);
+                // CNFG_GEN
+                max30001Model.Write(0x10, 0x040027);
+                // CNFG_BMUX
+                max30001Model.Write(0x17, 0x000040);
+                // CNFG_BIOZ
+                max30001Model.Write(0x18, 0x601430);
+
+                ECGChannelUpdateRegisters();
+                ECGInputMuxUpdateRegisters();
+                BioZChannelUpdateRegisters();
+                BioZInputMuxUpdateRegisters();
+
+                bioZMilliohmScaleToolStripMenuItem.Checked = false;
+                ecgView1.BioZMilliOhmRange = false;
+
+                maximTabControl1.SelectedTab = tpMAX30001Plots;
+            }
+        }
+
+        private void linkLabelQuickRespiration_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            if (connected)
+            {
+                // SW_RST
+                max30001Model.Write(0x08, 1);
+                max30001Model.Write(0x08, 0);
+                // CNFG_GEN
+                max30001Model.Write(0x10, 0x040027);
+                // CNFG_BMUX
+                max30001Model.Write(0x17, 0x000040);
+                // CNFG_BIOZ
+                max30001Model.Write(0x18, 0x201050);
+
+                ECGChannelUpdateRegisters();
+                ECGInputMuxUpdateRegisters();
+                BioZChannelUpdateRegisters();
+                BioZInputMuxUpdateRegisters();
+
+                bioZMilliohmScaleToolStripMenuItem.Checked = true;
+                ecgView1.BioZMilliOhmRange = true;
+
+                maximTabControl1.SelectedTab = tpMAX30001Plots;
+            }
+        }
+
+        private void btnSwRst_Click(object sender, EventArgs e)
+        {
+            if (!connected)
+                return;
+
+            max30001.WriteReg(0x08, 0x01);
+            max30001.WriteReg(0x08, 0x00);
+
+            UpdateRegisters();
+        }
+
+        private void btnSynch_Click(object sender, EventArgs e)
+        {
+            if (!connected)
+                return;
+
+            max30001.WriteReg(0x09, 0x01);
+            max30001.WriteReg(0x09, 0x00);
+        }
+
+        private void btnFifoRst_Click(object sender, EventArgs e)
+        {
+            if (!connected)
+                return;
+
+            max30001.WriteReg(0x0A, 0x01);
+            max30001.WriteReg(0x0A, 0x00);
+        }
+
+        private void registerNamesToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            List<RegisterField>[] fields = new List<RegisterField>[]{ ecgChannelField, ecgInputMuxField, ecgGlobalField, rToRField,  bioZChannelField, bioZInputMuxField, bioZLoadField, paceChannelField };
+            ToolStripMenuItem tsi = (ToolStripMenuItem)sender;
+
+            if (tsi.Checked == true)
+            {
+                // Combo Boxes
+                foreach (List<RegisterField> listRegisterField in fields)
+                {
+                    foreach(RegisterField rf in listRegisterField)
+                    {
+                        if (rf.Label != null)
+                            rf.Label.Text = rf.Name;
+                    }
+                }
+
+                // Check Boxes
+                foreach (RegisterField rf in channelEnableField)
+                {
+                    rf.LabelDescription = rf.Control.Text;
+                    rf.Control.Text = rf.Name;
+                }
+
+                string calHighRegName = "CAL_THIGH";
+                cboCalFifty.Items[0] = calHighRegName;
+                cboBioZCalFifty.Items[0] = calHighRegName;
+                if (cboCalFifty.SelectedIndex == 0)
+                {
+                    cboCalFifty.SelectedIndex = ecgCalFiftyField.ReadField();
+                    cboBioZCalFifty.SelectedIndex = biozCalFiftyField.ReadField();
+                }
+
+            }
+            else
+            {
+                // Combo Boxes
+                foreach (List<RegisterField> listRegisterField in fields)
+                {
+                    foreach (RegisterField rf in listRegisterField)
+                    {
+                        if (rf.Label != null)
+                            rf.Label.Text = rf.LabelDescription;
+                    }
+                }
+                
+                // Check Boxes
+                foreach (RegisterField rf in channelEnableField)
+                {
+                    rf.Control.Text = rf.LabelDescription;
+                }
+
+                string calHighRegName = "Time High";
+                cboCalFifty.Items[0] = calHighRegName;
+                cboBioZCalFifty.Items[0] = calHighRegName;
+                if (cboCalFifty.SelectedIndex == 0)
+                {
+                    cboCalFifty.SelectedIndex = ecgCalFiftyField.ReadField();
+                    cboBioZCalFifty.SelectedIndex = biozCalFiftyField.ReadField();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Prevent tab changes while streaming
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void maximTabControl1_Selecting(object sender, TabControlCancelEventArgs e)
+        {
+            if (streaming && connected)
+                e.Cancel = true;
+        }
+
+        private void showAdvancedTabToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (showAdvancedTabToolStripMenuItem.Checked)
+            {
+                maximTabControl1.UnhideTab("tpPrimitives");
+            }
+            else
+            {
+                maximTabControl1.HideTab("tpPrimitives");
+            }
+        }
+
+        private void registerView_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
+        {
+            ss_Status.MessagesLabel.Text = "";
+        }
+
+        private void registerView_WriteComplete(object sender, Maxim.CustomControls.RegisterView.RegisterArgs e)
+        {
+            ss_Status.MessagesLabel.Text = "Write Reg " + e.Register.ToString("X2") + "h Complete";
+        }
+
+        private void bioZMilliohmScaleToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            // Set the BioZ chart to be in units of milliohms or ohms
+            ecgView1.BioZMilliOhmRange = bioZMilliohmScaleToolStripMenuItem.Checked;
+        }
+
+        public void LogFileItem(StreamType stream, bool state)
+        {
+            switch(stream)
+            {
+                case StreamType.Ecg:
+                    eCGFileLogToolStripMenuItem.Checked = state;
+                    break;
+                case StreamType.RToR:
+                    rToRFileLogToolStripMenuItem.Checked = state;
+                    break;
+                case StreamType.Pace:
+                    paceFileLogToolStripMenuItem.Checked = state;
+                    break;
+                case StreamType.BioZ:
+                    bioZFileLogToolStripMenuItem.Checked = state;
+                    break;
+                case StreamType.Optical:
+                    opticalAccelerometerFileLogToolStripMenuItem.Checked = state;
+                    break;
+                
+                // TODO other stream types
+            }
+        }
+
+        public void OpticalLogFileItem(bool state)
+        {
+            opticalAccelerometerFileLogToolStripMenuItem.Checked = state;
+        }
+
+        public void EcgLogFileItem(bool state)
+        {
+            eCGFileLogToolStripMenuItem.Checked = state;
+        }
+
+        public void BioZLogFileItem(bool state)
+        {
+            bioZFileLogToolStripMenuItem.Checked = state;
+        }
+
+        public void RtoRLogFileItem(bool state)
+        {
+            rToRFileLogToolStripMenuItem.Checked = state;
+        }
+
+        public void PaceLogFileItem(bool state)
+        {
+            paceFileLogToolStripMenuItem.Checked = state;
+        }
+
+        private void eCGBioZFileLogToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (FileLogEnable != null)
+                FileLogEnable(this, new EnableEventArgs(StreamType.Ecg, !eCGBioZFileLogToolStripMenuItem.Checked));
+        }
+
+        private void eCGFileLogToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (FileLogEnable != null)
+                FileLogEnable(this, new EnableEventArgs(StreamType.Ecg, !eCGFileLogToolStripMenuItem.Checked));
+        }
+
+        private void rToRFileLogToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (FileLogEnable != null)
+                FileLogEnable(this, new EnableEventArgs(StreamType.RToR, !rToRFileLogToolStripMenuItem.Checked));
+        }
+
+        private void paceFileLogToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (FileLogEnable != null)
+                FileLogEnable(this, new EnableEventArgs(StreamType.Pace, !paceFileLogToolStripMenuItem.Checked));
+        }
+
+        private void bioZFileLogToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (FileLogEnable != null)
+                FileLogEnable(this, new EnableEventArgs(StreamType.BioZ, !bioZFileLogToolStripMenuItem.Checked));
+        }
+
+        private void opticalAccelerometerFileLogToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (OpticalFileLogEnable != null)
+                OpticalFileLogEnable(this, new EnableEventArgs(StreamType.Optical,!opticalAccelerometerFileLogToolStripMenuItem.Checked));
+        }
+
+        private void registerExportToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (RegisterExport != null)
+                RegisterExport(this, e);
+        }
+
+        private void loadAllRegisterSettingsToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            if (RegisterImport != null)
+                RegisterImport(this, e);
+        }
+
+
+        #region Home Tab
+        private void linkTempSensor_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpTemperature;
+        }
+
+        private void linkOpticalSensor_Click(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpOpticalSensor;
+        }
+
+        private void linkEcgChannel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001EcgChannel;
+        }
+
+        private void linkEcgMux_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001InputMux;
+        }
+
+        private void linkPaceChannel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001Pace;
+        }
+
+        private void linkBioZChannel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpBioZChannel;
+        }
+
+        private void linkBioZMux_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001BioZInputMux;
+        }
+
+        private void linkBioZLoad_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+        {
+            maximTabControl1.SelectedTab = tpMAX30001BioZLoad;
+        } 
+        #endregion
+
+        private void updateBlockDiagramLayout()
+        {
+            //Stopwatch stopWatch = new Stopwatch();
+            double scale;
+            int scaledWidth, scaledHeight;
+            int widthOffset;
+            int blockWidth = pnlBlockDiagram.Width;
+            int blockHeight = pnlBlockDiagram.Height;
+
+            int height = maximTabControl1.TabPages[0].Height;
+            int width = maximTabControl1.TabPages[0].Width;
+
+            //stopWatch.Start();
+
+            if (height < width)
+            {
+                scale = (double)height / blockHeight;
+            }
+            else
+            {
+                scale = (double)width / blockWidth;
+            }
+
+            scaledWidth = (int)(scale * blockWidth + 0.5);
+            scaledHeight = (int)(scale * blockHeight + 0.5);
+            widthOffset = (int)((width - scaledWidth + 0.5) / 2.0);
+
+            pnlBlockDiagram.Width = scaledWidth;
+            pnlBlockDiagram.Height = scaledHeight;
+            pnlBlockDiagram.Location = new Point(widthOffset, 0);
+
+            //System.Diagnostics.Debug.Print(" X: " + linkTempSensor.Location.X + " Y: " + linkTempSensor.Location.Y);
+            scaleControlCenter(linkTempSensor, scale);
+            scaleControlCenter(linkOpticalSensor, scale);
+            scaleControlCenter(linkEcgChannel, scale);
+            scaleControlCenter(linkEcgMux, scale);
+            scaleControlCenter(linkBioZChannel, scale);
+            scaleControlCenter(linkBioZMux, scale);
+            scaleControlCenter(linkBioZLoad, scale);
+            scaleControlCenter(linkPaceChannel, scale);
+
+            // Quick Start Location
+            tlbQuickStart.Location = new Point(pnlBlockDiagram.Location.X + pnlBlockDiagram.Size.Width + 5, pnlBlockDiagram.Location.Y + 50);
+            //System.Diagnostics.Debug.Print("Scale: " + scale + " X: " + linkTempSensor.Location.X + " Y: " + linkTempSensor.Location.Y);
+
+            if (maximTabControl1.SelectedTab.Name != "tpBlockDiagram")
+            {
+                maximTabControl1.Refresh();
+            }
+
+            //stopWatch.Stop();
+
+            //TimeSpan ts = stopWatch.Elapsed;
+
+            //string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
+            //System.Diagnostics.Debug.Print("Run time " + elapsedTime);
+        }
+
+        private void updateOT90DiagramLayout(Panel panel)
+        {
+            updateOT90DiagramLayout(panel, 0);
+        }
+
+        private void updateOT90DiagramLayout(Panel panel, int heightOffset)
+        {
+            Stopwatch stopWatch = new Stopwatch();
+            double scale, scaleWidth, scaleHeight;
+            int scaledWidth, scaledHeight;
+            int widthOffset;
+            int blockWidth = panel.Width;
+            int blockHeight = panel.Height;
+
+            int height = maximTabControl1.SelectedTab.Height - pnlMAX30001Global.Height - heightOffset;
+            int width = maximTabControl1.SelectedTab.Width;
+
+            stopWatch.Start();
+
+            // Scale to the smaller dimension, the smaller side dominates the scaling factor
+            scaleWidth = (double)(width - 40) / blockWidth;
+            scaleHeight = (double)height / blockHeight;
+            if (scaleWidth < scaleHeight)
+                scale = scaleWidth;
+            else
+                scale = scaleHeight;
+
+            scaledWidth = (int)(scale * blockWidth + 0.5);
+            scaledHeight = (int)(scale * blockHeight + 0.5);
+            widthOffset = (int)((width - scaledWidth + 0.5) / 2.0);
+
+            panel.Width = scaledWidth;
+            panel.Height = scaledHeight;
+            panel.Location = new Point(widthOffset, 10);
+
+            foreach (Control cntl in panel.Controls)
+            {
+                scaleControl(cntl, scale);
+            }
+
+            //maximTabControl1.Refresh();
+
+            stopWatch.Stop();
+
+            TimeSpan ts = stopWatch.Elapsed;
+
+            string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds / 10);
+            System.Diagnostics.Debug.Print("Run time " + elapsedTime);
+        }
+
+        void scaleControl(Control c, double scale)
+        {
+            int x = c.Location.X;
+            int y = c.Location.Y;
+
+            double newX, newY;
+
+            newX = ((x) * scale + 0.5);
+            newY = ((y + c.Size.Height / 2) * scale + 0.5) - c.Size.Height / 2;
+
+            c.Location = new Point((int)(newX), (int)(newY));
+        }
+
+        void scaleControlCenter(Control c, double scale)
+        {
+            int x = c.Location.X;
+            int y = c.Location.Y;
+
+            double newX, newY;
+
+            newX = ((x + c.Size.Width / 2) * scale + 0.5) - c.Size.Width / 2;
+            newY = ((y + c.Size.Height / 2) * scale + 0.5) - c.Size.Height / 2;
+
+            c.Location = new Point((int)newX, (int)newY);
+        }
+
+        void scaleControlRight(Control c, double scale)
+        {
+            double AlignX = 590.0/636;
+            int x = c.Location.X;
+            int y = c.Location.Y;
+
+            double newX, newY;
+
+            newX = ((x + c.Size.Width) * scale + 0.5) - c.Size.Width;
+            newY = ((y + c.Size.Height / 2) * scale + 0.5) - c.Size.Height / 2;
+
+            c.Location = new Point((int)(AlignX * picBlockDiagram.Width - c.Size.Width), (int)(newY));
+
+        }
+
+        private void updateAllBlockDiagrams()
+        {
+            //this.SuspendLayout();
+            updateBlockDiagramLayout();
+            updateOT90DiagramLayout(pnlEcgChannel, grpRToR.Height + 20);
+            updateOT90DiagramLayout(pnlEcgMux);
+            updateOT90DiagramLayout(pnlBioZChannel);
+            updateOT90DiagramLayout(pnlBioZMux);
+            updateOT90DiagramLayout(pnlBioZLoad);
+            updateOT90DiagramLayout(pnlPace);
+            //this.ResumeLayout();
+        }
+
+        private void HspForm_ResizeEnd(object sender, EventArgs e)
+        {
+            updateAllBlockDiagrams();
+        }
+
+        protected override void WndProc(ref Message m)
+        {
+            if (m.Msg == /*WM_SIZE*/ 0x0005)
+            {
+                if (this.WindowState == FormWindowState.Maximized || this.WindowState == FormWindowState.Normal)
+                {
+                    updateAllBlockDiagrams();
+                }
+            }
+
+            base.WndProc(ref m);
+        }
+
+        public class DebugTextWriter : StreamWriter
+        {
+            public DebugTextWriter()
+                : base(new DebugOutStream(), Encoding.Unicode, 1024)
+            {
+                this.AutoFlush = true;
+            }
+
+            class DebugOutStream : Stream
+            {
+                public override void Write(byte[] buffer, int offset, int count)
+                {
+                    Debug.Write(Encoding.Unicode.GetString(buffer, offset, count));
+                }
+
+                public override bool CanRead { get { return false; } }
+                public override bool CanSeek { get { return false; } }
+                public override bool CanWrite { get { return true; } }
+                public override void Flush() { Debug.Flush(); }
+                public override long Length { get { throw new InvalidOperationException(); } }
+                public override int Read(byte[] buffer, int offset, int count) { throw new InvalidOperationException(); }
+                public override long Seek(long offset, SeekOrigin origin) { throw new InvalidOperationException(); }
+                public override void SetLength(long value) { throw new InvalidOperationException(); }
+                public override long Position
+                {
+                    get { throw new InvalidOperationException(); }
+                    set { throw new InvalidOperationException(); }
+                }
+            };
+        }
+
+        private void onlineDocumentationToolStripMenuItem_Click(object sender, EventArgs e)
+        {
+            Process.Start("http://www.maximintegrated.com/MAXREFDES100");
+        }
+    }
+}