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