![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
This is the latest working repository used in our demo video for the Maxim to display temperature readings on Bluetooth
hspguisourcev301/HspGuiSourceV301/HSPGui/ECGChannel.cs
- Committer:
- darienf
- Date:
- 2021-04-10
- Revision:
- 3:36de8b9e4b1a
File content as of revision 3:36de8b9e4b1a:
/******************************************************************************* * 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; namespace HealthSensorPlatform { // Code for ECG Configuration Tab public partial class HspForm { List<RegisterField> ecgChannelField = new List<RegisterField>(); List<RegisterField> ecgGlobalField = new List<RegisterField>(); List<RegisterField> rToRField = new List<RegisterField>(); List<RegisterField> channelEnableField = new List<RegisterField>(); // Needed for dynamic changing of options RegisterField ecgSampleRateField; RegisterField ecgDlpfField; string[][] ecgSampleRateOptions = new string[][] { new string[] { "512 sps", "256 sps", "128 sps*" }, new string[] { "500 sps", "250 sps", "125 sps*" }, new string[] { "N/A", "N/A", "200 sps*" }, new string[] { "N/A", "N/A", "199.8 sps*" } }; double[][] ecgSampleRates = new double[][] { new double[] {512, 256, 128, 128}, new double[] {500, 250, 125, 125}, new double[] {200, 200, 200, 200}, new double[] {199.8, 199.8, 199.8, 199.8} // using 200, the error is 0.1% }; string[][][] ecgDlpfOptions; void initalizeECGConfigFields() { ecgDlpfOptions = new string[4][][]; for (int i = 0; i < 4; i++) { ecgDlpfOptions[i] = new string[4][]; } // 32768 Hz ecgDlpfOptions[0][0] = new string[] {"Bypass (00)", "40.96 Hz (01)*", "102.4 Hz (10)", "153.6 Hz (11)"}; ecgDlpfOptions[0][1] = new string[] {"Bypass (00)", "40.96 Hz (01)*", "102.4 Hz (10)"};//, "40.96 Hz (11)"}; ecgDlpfOptions[0][2] = new string[] {"Bypass (00)", "40.96 Hz (01)*"}; //, "40.96 Hz (10)", "40.96 Hz (11)"}; ecgDlpfOptions[0][3] = new string[] {"Bypass (00)", "40.96 Hz (01)*"}; //, "40.96 Hz (10)", "40.96 Hz (11)"}; // 32000 Hz ecgDlpfOptions[1][0] = new string[] { "Bypass (00)", "40.00 Hz (01)*", "100.0 Hz (10)", "150.0 Hz (11)"}; ecgDlpfOptions[1][1] = new string[] {"Bypass (00)", "40.00 Hz (01)*", "100.0 Hz (10)"}; //, "40.00 Hz (11)"}; ecgDlpfOptions[1][2] = new string[] {"Bypass (00)", "40.00 Hz (01)*"}; //, "40.00 Hz (10)", "40.00 Hz (11)"}; ecgDlpfOptions[1][3] = new string[] {"Bypass (00)", "40.00 Hz (01)*"}; //, "40.00 Hz (10)", "40.00 Hz (11)"}; //32000 Hz ecgDlpfOptions[2][0] = new string[] { "Bypass", "40.00 Hz"}; //, "40.00 Hz", "40.00 Hz" }; ecgDlpfOptions[2][1] = new string[] { "Bypass", "40.00 Hz"}; //, "40.00 Hz", "40.00 Hz" }; ecgDlpfOptions[2][2] = new string[] { "Bypass", "40.00 Hz"}; //, "40.00 Hz", "40.00 Hz" }; ecgDlpfOptions[2][3] = new string[] { "Bypass", "40.00 Hz"}; //, "40.00 Hz", "40.00 Hz" }; // 31968 Hz ecgDlpfOptions[3][0] = new string[] { "Bypass (00)", "39.96 Hz (01)" }; //, "39.96 Hz (10)", "39.96 Hz (11)" }; ecgDlpfOptions[3][1] = new string[] { "Bypass", "39.96 Hz"}; //, "39.96 Hz", "39.96 Hz" }; ecgDlpfOptions[3][2] = new string[] { "Bypass", "39.96 Hz"};//, "39.96 Hz", "39.96 Hz" }; ecgDlpfOptions[3][3] = new string[] { "Bypass", "39.96 Hz"};//, "39.96 Hz", "39.96 Hz" }; string[] fastOptions = { "Normal*", "Manual Fast Recovery", "Automatic Fast Recovery" }; string[] fastThOptions = new string[64]; for (int i = 0; i < 64; i++) { fastThOptions[i] = i.ToString() + " * 2048 LSB"; } fastThOptions[0x3F] += "*"; // Default option string[] channelGainOptions = { "20 V/V*", "40 V/V", "80 V/V", "160 V/V" }; //string[] sampleRateOptions = { "512 sps", "256 sps", "128 sps*"}; // Assume FMSTR = 32768 Hz string[] dlpfOptions = { "Bypass", "40.96 Hz*", "102.4 Hz", "153.6 Hz" }; string[] dhpfOptions = { "Bypass", "0.50 Hz*" }; RegisterField fastField = new RegisterField { Name = "FAST", Register = 5, Index = 22, Width = 2, Descriptions = fastOptions, Label = lblFast, Control = cboFast, Device = max30001}; RegisterField fastThField = new RegisterField { Name = "FAST_TH", Register = 5, Index = 16, Width = 6, Descriptions = fastThOptions, Label = lblFastTh, Control = cboFastTh, Device = max30001}; ecgChannelField.Add(fastField); ecgChannelField.Add(fastThField); RegisterField channelGainField = new RegisterField { Name = "ECG_GAIN", Register = 0x15, Index = 16, Width = 2, Descriptions = channelGainOptions, Label = lblChannelGain, Control = cboChannelGain, Device = max30001}; ecgChannelField.Add(channelGainField); ecgSampleRateField = new RegisterField { Name = "ECG_RATE", Register = 0x15, Index = 22, Width = 2, Descriptions = ecgSampleRateOptions[0], Label = lblSampleRate, Control = cboSampleRate, Device = max30001}; ecgChannelField.Add(ecgSampleRateField); ecgDlpfField = new RegisterField { Name = "ECG_DLPF", Register = 0x15, Index = 12, Width = 2, Descriptions = dlpfOptions, Label = lblDlpf, Control = cboDlpf, Device = max30001}; RegisterField dhpfField = new RegisterField { Name = "ECG_DHPF", Register = 0x15, Index = 14, Width = 1, Descriptions = dhpfOptions, Label = lblDhpf, Control = cboDhpf, Device = max30001}; ecgChannelField.Add(ecgDlpfField); ecgChannelField.Add(dhpfField); } void initalizeECGGlobalControls() { string[] fmstrDescription = { "32768 Hz (00)*", "32000 Hz (01)", "32000 Hz (10)", "31968 Hz (11)" }; string[] enECGDescription = { "Disabled*", "Enabled" }; RegisterField fmstrField = new RegisterField { Name = "FMSTR", Register = 0x10, Index = 20, Width = 2, Descriptions = fmstrDescription, Control = cboMasterClock, Device = max30001}; ecgGlobalField.Add(fmstrField); //RegisterField enECGField = new RegisterField { Name = "EN_ECG", Register = 0x10, Index = 19, Width = 1, Descriptions = enECGDescription, Label = lblECGChannelEnable }; //enECGField.Control = cboECGChannelEnable; //ecgGlobalField.Add(enECGField); RegisterField enECGField = new RegisterField { Name = "EN_ECG", Register = 0x10, Index = 19, Width = 1, Control = chkEnECG, Device = max30001}; RegisterField enBioZField = new RegisterField { Name = "EN_BIOZ", Register = 0x10, Index = 18, Width = 1, Control = chkEnBioZ, Device = max30001}; RegisterField enPaceField = new RegisterField { Name = "EN_PACE", Register = 0x10, Index = 17, Width = 1, Control = chkEnPace, Device = max30001}; RegisterField enRtorField = new RegisterField { Name = "EN_RTOR", Register = 0x1d, Index = 15, Width = 1, Control = chkEnRtor, Device = max30001}; channelEnableField.Add(enECGField); channelEnableField.Add(enBioZField); channelEnableField.Add(enPaceField); channelEnableField.Add(enRtorField); } void initalizeRToRFields() { string[] wndwOptions = {"6 * 8ms", "8 * 8ms", "10 * 8ms", "12 * 8ms*", "14 * 8ms", "16 * 8ms", "18 * 8ms", "20 * 8ms", "22 * 8ms", "24 * 8ms", "26 * 8ms", "28 * 8ms"}; string[] gainOptions = { "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192", "16384", "Auto-Scale*" }; string[] enableOptions = { "Disable*", "Enable" }; string[] pavgOptions = { "2", "4", "8*", "16" }; string[] ptsfOptions = { "1/16", "2/16", "3/16", "4/16*", "5/16", "6/16", "7/16", "8/16", "9/16", "10/16", "11/16", "12/16", "13/16", "14/16", "15/16", "16/16"}; string[] hoffOptions = new string[64]; for(int i = 0; i < 64; i ++) { hoffOptions[i] = i.ToString(); if (i == 32) hoffOptions[i] += "*"; } string[] ravgOptions = { "2", "4", "8*", "16" }; string[] rhsfOptions = { "0/8", "1/8", "2/8", "3/8", "4/8*", "5/8", "6/8", "7/8" }; RegisterField wndwField = new RegisterField { Name = "RTOR_WNDW", Register = 0x1d, Index = 20, Width = 4, Descriptions = wndwOptions, Control = cboRRWndw, Label = lblRRWndw, Device = max30001 }; RegisterField gainField = new RegisterField { Name = "RTOR_GAIN", Register = 0x1d, Index = 16, Width = 4, Descriptions = gainOptions, Control = cboRRGain, Label = lblRRGain, Device = max30001 }; RegisterField enableField = new RegisterField { Name = "EN_RTOR", Register = 0x1d, Index = 15, Width = 1, Descriptions = enableOptions, Control = cboEnRToR, Label = lblEnRToR, Device = max30001 }; RegisterField pavgField = new RegisterField { Name = "RTOR_PAVG", Register = 0x1d, Index = 12, Width = 2, Descriptions = pavgOptions, Control = cboRRPavg, Label = lblRRPavg, Device = max30001 }; RegisterField ptsfField = new RegisterField { Name = "RTOR_PTSF", Register = 0x1d, Index = 8, Width = 4, Descriptions = ptsfOptions, Control = cboRRPtsf, Label = lblRRPtsf, Device = max30001}; RegisterField hoffField = new RegisterField { Name = "RTOR_HOFF", Register = 0x1e, Index = 16, Width = 6, Descriptions = hoffOptions, Control = cboRRHoff, Label = lblRRHoff, Device = max30001 }; RegisterField ravgField = new RegisterField { Name = "RTOR_RAVG", Register = 0x1e, Index = 12, Width = 2, Descriptions = ravgOptions, Control = cboRRRavg, Label = lblRRRavg, Device = max30001 }; RegisterField rhsfField = new RegisterField { Name = "RTOR_RHSF", Register = 0x1e, Index = 8, Width = 3, Descriptions = rhsfOptions, Control = cboRRRhsf, Label = lblRRRhsf, Device = max30001 }; rToRField.Add(wndwField); rToRField.Add(gainField); rToRField.Add(enableField); rToRField.Add(pavgField); rToRField.Add(ptsfField); rToRField.Add(hoffField); rToRField.Add(ravgField); rToRField.Add(rhsfField); } /// <summary> /// Read register values and update GUI accordingly /// </summary> void ECGChannelUpdateRegisters() { internalUpdate = true; ReadComboBoxesRegisters(ecgChannelField); ReadComboBoxesRegisters(rToRField); internalUpdate = false; } /// <summary> /// Read and update all the MAX30001 global GUI settings (enable bits and clock) /// </summary> void ECGGlobalUpdateRegisters() { internalUpdate = true; ReadComboBoxesRegisters(ecgGlobalField); ReadCheckBoxRegisters(channelEnableField); channelEnableMask(chkEnECG); internalUpdate = false; // Update EcgView to maintain consistent state ecgView1.EnableBioZ = chkEnBioZ.Checked; ecgView1.EnableECG = chkEnECG.Checked; ecgView1.EnablePace = chkEnPace.Checked; ecgView1.EnableRToR = chkEnRtor.Checked; } /// <summary> /// Mask enable bits for features which depend on EN_ECG = 1 and EN_BIOZ = 1 /// </summary> /// <param name="enEcg">Checkbox representing EN_ECG bit</param> void channelEnableMask(MaximStyle.MaximCheckBox enEcg) { if (enEcg.Checked == false) { chkEnRtor.Enabled = false; chkEnPace.Enabled = false; } else { chkEnRtor.Enabled = true; if (max30001Model.PartID == Model.MAX30001Model.Part.MAX30001) chkEnPace.Enabled = true; } /*if (chkEnBioZ.Checked == false) { chkEnPace.Enabled = false; } else { chkEnPace.Enabled = true; }*/ } void ReadComboBoxesRegisters(List<RegisterField> fields) { int bitValue; MaximStyle.MaximComboBox cbox; foreach (RegisterField rf in fields) { cbox = (MaximStyle.MaximComboBox)rf.Control; if (rf.AutoUpdate == true) { //for (int i = 0; i < 3; i++) //{ // try // { bitValue = rf.ReadField(); if (bitValue < cbox.Items.Count && cbox.Items.Count != 0) // Bit setting matches combobox setting { cbox.SelectedItem = rf.Descriptions[bitValue]; } else // Bit setting value outside of combobox item range { cbox.Text = "0b" + Convert.ToString(bitValue, 2); } // } // catch (System.TimeoutException) // { // if (i == 2) // throw; // } //} } } } void ReadComboBoxesRegister(RegisterField rf) { int bitValue; MaximStyle.MaximComboBox cbox; cbox = (MaximStyle.MaximComboBox)rf.Control; if (rf.AutoUpdate == true) { bitValue = rf.ReadField(); if (bitValue < cbox.Items.Count && cbox.Items.Count != 0) // Bit setting matches combobox setting { cbox.SelectedItem = rf.Descriptions[bitValue]; } else // Bit setting value outside of combobox item range { cbox.Text = "0b" + Convert.ToString(bitValue, 2); } } } void ReadCheckBoxRegisters(List<RegisterField> fields) { int bitValue; MaximStyle.MaximCheckBox chk; foreach (RegisterField rf in fields) { chk = (MaximStyle.MaximCheckBox)rf.Control; if (rf.AutoUpdate == true) { bitValue = rf.ReadField(); if (bitValue == 0) chk.Checked = false; else chk.Checked = true; } } } /// <summary> /// Get bit value from register /// </summary> /// <param name="field"></param> /// <returns></returns> /*int BitValue(RegisterField field) { int registerData; registerData = max30001.ReadReg((byte)field.Register); return (registerData >> field.Index) & ((1 << field.Width) - 1); }*/ /// <summary> /// Add tool tips to combo boxes and event to write registers /// </summary> /// <param name="list"></param> void initalizeToolTipEvents(List<RegisterField> list) { MaximStyle.MaximComboBox cbox; Label lbl; StringBuilder strBuilder = new StringBuilder(); foreach (RegisterField field in list) { cbox = (MaximStyle.MaximComboBox)field.Control; lbl = field.Label; // Tool Tip String strBuilder.Append("Bit "); strBuilder.Append(field.Name.Replace("\n", String.Empty)); strBuilder.Append(" in Register 0x"); strBuilder.Append(field.Register.ToString("X2")); toolTip1.SetToolTip(cbox, strBuilder.ToString()); if (lbl != null) toolTip1.SetToolTip(lbl, strBuilder.ToString()); strBuilder.Clear(); // Event to Write Registers if (cbox != cboMasterClock && cbox != cboSampleRate && cbox != cboBioZSampleRate) // cboMasterClock has a special handler to support repopulation of comboboxes cbox.SelectedIndexChanged += new System.EventHandler(cboECGChannel_SelectedIndexChanged); } } /// <summary> /// Write corresponding register of cbox /// </summary> /// <param name="cbox"></param> void writeComboBox(MaximStyle.MaximComboBox cbox) { List<RegisterField>[] fieldLists = { ecgChannelField, ecgInputMuxField, ecgGlobalField, rToRField, bioZChannelField, bioZInputMuxField, bioZLoadField, paceChannelField}; RegisterField field = null; //int val; foreach (List<RegisterField> list in fieldLists) { foreach (RegisterField f in list) { if (f.Control == cbox) { field = f; break; } } if (field != null) break; } field.WriteField((((MaximStyle.MaximComboBox)field.Control).SelectedIndex)); } void writeCheckBox(MaximStyle.MaximCheckBox chk) { List<RegisterField>[] fieldLists = { channelEnableField }; RegisterField field = null; //int val; foreach (List<RegisterField> list in fieldLists) { foreach (RegisterField f in list) { if (f.Control == chk) { field = f; break; } } if (field != null) break; } field.WriteField(((MaximStyle.MaximCheckBox)field.Control).Checked == true ? 1 : 0); } /// <summary> /// Event to handle when a new item is selected in the comboboxes for ECG Channel tabs /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cboECGChannel_SelectedIndexChanged(object sender, EventArgs e) { MaximStyle.MaximComboBox cbox = (MaximStyle.MaximComboBox)sender; if (connected && !internalUpdate) writeComboBox(cbox); } /// <summary> /// Update sample rate for ECG View /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cboSampleRate_SelectedIndexChanged(object sender, EventArgs e) { MaximStyle.MaximComboBox cbox = (MaximStyle.MaximComboBox)sender; if (connected && !internalUpdate) writeComboBox(cbox); if (cboMasterClock.SelectedIndex > -1) { // Set sample rate based on clock ecgView1.SampleRateEcg = ecgSampleRates[cboMasterClock.SelectedIndex][cbox.SelectedIndex]; // Set digital low pass filter cboDlpf.Items.Clear(); ecgDlpfField.Descriptions = ecgDlpfOptions[cboMasterClock.SelectedIndex][cboSampleRate.SelectedIndex]; ecgDlpfField.Control = cboDlpf; // Trigger updating of descriptions //internalUpdate = true; if (connected) cboDlpf.SelectedIndex = ecgDlpfField.ReadField(); //internalUpdate = false; //ReadComboBoxesRegisters(cboDlpf); } } private void cboChannelGain_SelectedIndexChanged(object sender, EventArgs e) { MaximStyle.MaximComboBox cbox = (MaximStyle.MaximComboBox)sender; switch (cbox.SelectedIndex) { case 0: ecgView1.GainECG = 20; break; case 1: ecgView1.GainECG = 40; break; case 2: ecgView1.GainECG = 80; break; case 3: ecgView1.GainECG = 160; break; } } private void chkChannelEnable_CheckedChanged(object sender, EventArgs e) { MaximStyle.MaximCheckBox chk = (MaximStyle.MaximCheckBox)sender; // Write bit if (connected && !internalUpdate) { writeCheckBox(chk); // Do not allow user to change masked enable bits channelEnableMask(chkEnECG); // Tell ECG View the status if (chk == chkEnECG) { ecgView1.EnableECG = chk.Checked; } else if (chk == chkEnBioZ) { ecgView1.EnableBioZ = chk.Checked; } else if (chk == chkEnPace) { ecgView1.EnablePace = chk.Checked; } else if (chk == chkEnRtor) { ecgView1.EnableRToR = chk.Checked; } // Read all enable bits internalUpdate = true; ReadCheckBoxRegisters(channelEnableField); internalUpdate = false; } } private void cboMasterClock_SelectedIndexChanged(object sender, EventArgs e) { MaximStyle.MaximComboBox cbo = (MaximStyle.MaximComboBox)sender; int[] clock = { 32768, 32000, 32000, 31968 }; if (connected && !internalUpdate) writeComboBox(cbo); ecgView1.FrequencyMasterField = cbo.SelectedIndex; //ecgView1.TimeResolution = 1.0/(2*clock[cbo.SelectedIndex]); ecgSampleRateField.Descriptions = ecgSampleRateOptions[cbo.SelectedIndex]; ecgSampleRateField.Control = cboSampleRate; // Trigger updating of descriptions cboBioZSampleRate.Items.Clear(); bioZSampleRateField.Descriptions = bioZSampleRateOptions[cbo.SelectedIndex]; bioZSampleRateField.Control = cboBioZSampleRate; // Trigger updating of descriptions // Trigger update of current selection to new description internalUpdate = true; if (connected) { cboSampleRate.SelectedIndex = ecgSampleRateField.ReadField(); cboDlpf.SelectedIndex = ecgDlpfField.ReadField(); cboBioZSampleRate.SelectedIndex = bioZSampleRateField.ReadField(); cboBioZDigitalLpf.SelectedIndex = bioZDlpfField.ReadField(); } internalUpdate = false; } private void cboRRWndw_SelectedIndexChanged(object sender, EventArgs e) { MaximStyle.MaximComboBox cbo = (MaximStyle.MaximComboBox)sender; ecgView1.RToRWindowField = cbo.SelectedIndex; } private CustomControls.InitArgs.RToRInitStart getRToRArgs() { CustomControls.InitArgs.RToRInitStart initArgs = new CustomControls.InitArgs.RToRInitStart(); initArgs.Wndw = cboRRWndw.SelectedIndex; initArgs.Gain = cboRRGain.SelectedIndex; initArgs.En_rtor = chkEnRtor.Checked == true ? 1 : 0; initArgs.Pavg = cboRRPavg.SelectedIndex; initArgs.Ptsf = cboRRPtsf.SelectedIndex; initArgs.Hoff = cboRRHoff.SelectedIndex; initArgs.Ravg = cboRRRavg.SelectedIndex; initArgs.Rhsf = cboRRRhsf.SelectedIndex; initArgs.Clr_rrint = 1; // Default from Jerry's GUI return initArgs; } private void setRToRArgs(CustomControls.InitArgs.RToRInitStart initArgs) { cboRRWndw.SelectedIndex = initArgs.Wndw; cboRRGain.SelectedIndex = initArgs.Gain; //initArgs.En_rtor = chkEnRtor.Checked == true ? 1 : 0; //cboEnRToR.SelectedIndex; cboRRPavg.SelectedIndex = initArgs.Pavg; cboRRPtsf.SelectedIndex = initArgs.Ptsf; cboRRHoff.SelectedIndex = initArgs.Hoff; cboRRRavg.SelectedIndex = initArgs.Ravg; cboRRRhsf.SelectedIndex = initArgs.Rhsf; //initArgs.Clr_rrint = 2; // Default from Jerry's GUI } } }