ECG Monitor – Software Revision, Hardware Revision, Firmware Revision and Mechanical Design Revision

 
 
 
 
 

Software Revision

ECG Monitor – Software Revision, Hardware Revision, Firmware Revision and Mechanical Design Revision / Research & Development

//=========================================================
// Format of Status
// S0000, S0001, S0010, S0011
// Last TWO bits are the status of LOD+ and LOD-
//=========================================================
// Data Capture
// Comment: Try to save data in HEXDEC format. It is not easy to read.
// Final : Using double precision format to save the data.
//=========================================================
// Modified: 31 Aug 2016 8:35:00 AM
// (Description 1.0.0.2)
// Put All the bluetooth module to uChatManager.pas and create two threads
// (TReadThread and TWriteThread) for handling the Read/Write process during
// communication between Android host and ECG client.
// =============================
// Bluetooth Module Modification
// =============================
// Create uChatManager.pas unit with following:-
// 1) TChatManager
// 2) TReadThread
// 3) TWriteThread
//
// Comment:
// Using the System.Bluetooth unit, there is I/O exception,
// There is an error when the android try to connect with the bluetooth
// HC-06. The socket is closed or timeout.
// “java.io.ioexception read failed socket might closed or timeout read ret -1”
//
// LServerSocket.Accept(60000);
// LReadSocket.Connect;
// LWriteSocket.Connect;
//
// The above socket DOES NOT work. Bugggggy!!!!
//
// Solution:
// Using the AndroidApi instead. See below.
//=========================================================
// Modified: 20 Oct 2016 3:00:00 PM
// (Description 1.0.0.3)
// ECGBTMain v26a working.rar <<< This apps is working but bug!!!!
//
// Read Thread has error to read automatically.
// Read Thread has error to read automatically.
//
// Using uAndroidChatManager.pas and create two threads
// (TReadThread and TWriteThread) for handling the Read/Write process during
// communication between Android host and ECG client.
// =============================
// Bluetooth Module Modification
// =============================
// Create uAndroidChatManager.pas unit with following:-
// 1) TAndroidChatManager
// 2) TReadThread
// 3) TWriteThread
// Comment: uChatManager cannot communicate between Android and BlueTooth Module.
// Create uAndroidChatManager to do the job. The unit is using
// AndroidApi to call BlueTooth module.
//=========================================================
// Modified: 26 Oct 2016 10:00:00 AM
// (Description 1.0.0.4)
//
// Using uAndroidChatManager.pas and create one timer to read the receiving text
// to communicate between Android host and ECG client.
// =============================
// Bluetooth Module Modification
// =============================
// Create uAndroidChatManager.pas unit with following:-
// 1) TAndroidChatManager
// 2) receiveThd : TReceiveThread;
// Comment: uAndroidChatManager can communicate between Android and BlueTooth Module.
// Using receiveThd: TReceiveThread to receive the incoming text automatically.
//=========================================================
// Modified: 3 Dec 2016 10:43:00 AM
// (Description 1.0.0.5)
//
// Using BluetoothLE unit to communicate with Bluetooth 4.0 version
// Using uBT4ChatManager.pas and create to read the receiving text
// to communicate between Android, MAC OSX & iOS, host and ECG client.
// =============================
// Bluetooth Module Modification
// =============================
// Create uBT4ChatManager.pas unit with following:-
// 1) TBT4ChatClass
// 2) fbGetServiceAndCharacteristics
// 3) fbBTCharacteristicWrite
// 4) fbBTCharacteristicRead
// Comment: uBT4ChatManager can communicate between Android, MAC OSX & iOS and BlueTooth 4.0 module.
//
// ===========================
// ===========================
// ===========================
//
// Result: Testing Bluetooth 4 version 3.0.6
// *****************************************
// Procedure
// {$Define BT4} Change in ECGctrl.inc
// The module of BT4 is working but very very slow.
// The BT4 need to transmitted the Characteristic String each time together with the data variable.
// It will take a significant amount of time to transmit “Characteristic String” and “Data Variable”.
// Further Development
// *******************
// Baud rate is increased to certain amount to deduce the Characteristic String. It will have this improvement.
// ===========================
// ===========================
// ===========================
//
//=========================================================
// 32-bit Windows and 64-bit Windows are using for DEBUG only.
// They don’t have Bluetooth wireless enable!
//=========================================================
// Comment:
// There is a problem at the pcrParserBytes to calculate the heartTimer.Interval.
// pcrParserBytes is a thread. There is a conflict between timer and pcrParserBytes thread.
// Set heartTimer.Interval here is more stable sound pulse than that
// at the pcrParserBytes
//
// It is the best location to put the fbBeepSound and reset timer.
// Reset heartTimer after each of the fbBeepSound when the interval is changed.
//
// Create: TTimeThread.pas
// This unit is used a thread to control the time interval (eRate).
// The time interval is more precise than that of the system timer.
//=========================================================
// Capture data in HexDec format at pcrParserBytes here
// OR
// Capture data in float point format at fbSetUpOneBTData
//=========================================================
// Modified: 20 Dec 2016 11:43:00 PM
// (Description 1.0.0.6)
// Extra Function:
// 1) Auto Phone Dialer – Monitor ecg If too high or too low, it will call the preset phone number.
// 2) eMail information – email ecg information, location to the preset email address
// 3) Current Location – get the current location from GPS
// 4) SMS – send ecg information, location to the preset SMS number
//=========================================================
// Research Paper – “InTech-A_mobile_device_based_ecg_analysis_system.pdf”
// School of Electrical and Computer Engineering, RMIT University of Australia
//
// Description of “Procedure pcrMonitor”
// The following code is to calculate the
// 1)First Derivative
// 2)Second Derivative
// 3)Check or Monitor FDBT
// 4)Check or Monitor SDBT
//
// Parameters:
// eFrequency (pulse per second) is used to calculate SDBT
//=========================================================
// Research Paper – “Dynamic Time Warp Visualizer by Aleksei Loos”
// Research Paper – “Dynamic Time Warping by Quim Llimona Torras / Jounal Club 2011. MTG-UPF”
//
// Description
// In time series analysis, dynamic time warping (DTW) is
// an algorithm for measuring similarity between two temporal sequences
// which may vary in speed. For instance, similarities in walking
// could be detected using DTW, even if one person was walking
// faster than the other, or if there were accelerations and decelerations
// during the course of an observation.
// DTW has been applied to temporal sequences of video, audio, and graphics data
// — indeed, any data which can be turned into a linear sequence can be
// analyzed with DTW.
// A well known application has been automatic speech recognition,
// to cope with different speaking speeds.
// Other applications include speaker recognition and online signature recognition.
// Also it is seen that it can be used in partial shape matching application.
//
//=========================================================
// Usage: function TPlotClass.fbCalculateDistance(aObsChartValues: TChartValues; //obs
// aExpChartValues: TChartValues; //exp or Standard
// var dDisDataSet: dMultiArray): boolean;
// fbCalculateDistance is used to calculate the Dynamic Time Warping(DTW).
// Input : There are two dataset of ChartValues (aObsChartValues & aExpChartValues).
// Output: dDisDataSet will be generated by the function.
//=========================================================
// Usage: function TPlotClass.fbCalculatePath(dDisDataSet: dMultiArray;
// var dPathDataSet: dArray): boolean;
// fbCalculatePath is used to calculate the shortest distance.
// Constant: giDTWConstant & gdDTWcoefficient
// Adjust two constants, the output will generate the result changing accordingly.
// Output: dPathDataSet will be generated by the fbCalculatePath.
//=========================================================
// Measure fbCalculateDistance < // Measure fbCalculatePath < // Measure The Maximum Amplitude < // Measure The RR-Interval between two pulse < // Measure first derivative of ecg < // Measure second derivative of ecg < // Monitor FDBT < // Monitor SDBT < // Reading the measurements and send email, auto dialer, current location and SMS
//=========================================================
// Further Development
// Discrete Frechet Distance
// For person identification, Dynamic Time Warping (DTW) and
// Fisher’s Linear Discriminant Analysis (FLDA)
// with K-Nearest Neighbor Classifier (NNC) as single stage classification
// yielded a recognition accuracy of 96% and 97% respectively.
// To further improve the performance of the system, two stage classification techniques
// have been adapted.
// In two stage classifications FLDA is used with k-NNC at the first stage followed by
// DTW classifier at the second stage which yielded 100% recognition accuracy.
//=========================================================
//=========================================================
// Special Feature #001
// ecg Frequency Function
// Description: If the capture Amplitude is too low to be detected Threshold,
// it is better to make the frequency to ZERO and then pulse/sec and pulse/min to zero.
// if (epuAmplitude < gdAmplitudeThreshold) then // eFrequency := 0; // // Apply the Special Feature #001 at the below functions // 1) TfrmECG.pcrParserBytes // 2) TTimeThread.DoProgress; // 3) TPlotClass.pcrMonitor // //========================================================= // Special Feature #002 // ecg Frequency Function // Description: If the capture Frequency is too high to be detected Threshold, // it is better to make the frequency to ZERO and then pulse/sec and pulse/min to zero. // if (eFrequency > gdFrequencyThreshold) then
// eFrequency := 0;
//=========================================================
// Special Feature #003
// ecg Frequency Function
// Description: If the capture Frequency is too low to be detected Threshold,
// it is better to make the frequency to ZERO and then pulse/sec and pulse/min to zero.
// if (eFrequency < gdFrequencyThresholdMin) then // eFrequency := 0; //========================================================= // Special Feature #004 // Function: fdOptimizeFrequency // Method I : Average Frequency is calculated by mean of the dFreq. // Method II: Get the best frequency from the conditions logic. // // Comment: Method II will give a more stable frequency. // dFreq1 and dFreq2 are smaller than 1. The Result will be smaller as is. // dFreq1 and dFreq2 are greater than 2. The Result will be greater as is. //========================================================= // Modified 2 Feb 2017 11:37:00 PM // (Description 1.0.0.7) // 1) Theme – Adding different color theme // 2) INIfile – Adding IniTools, ecgReadIni & ecgWriteIni to access the Inifile parameters. // 3) Extended to double – Change the casting from extended type to double. // 4) Chi-Square – The function of Chi-Square is to compare two curve. It is too slow to // carry out the calculation. // 5) DTW – Adding Dynamic Time Warping or similar (frechet distance) to compare two curve. // Expected Curve (Standard ecg curve or pulse) compare with Observed Curve. // fbCalculatePath is used to calculate the shortest distance. // The shortest distance is greater than a HI limit or lower than a LO limit. // There will be an error of the Expected Curve. // 6) Capture File Name – Introduce NOW TDateTime function to the file name of the captured file. // Add file folder to system ‘download/ecgCaptureData’ directory for the ecg captured files. // Temporarily remove the output of ‘ecgInput.txt’, ‘ecgSaved.txt’ and ‘ecgData.txt’. // 7) Capture Save & Load- Capture data will be loaded from ‘File…’ input page and saved as ecgCaptureXXXXXXXX.txt // When the capture data is loaded, the header information will be neglected. // ‘Start’ to run with the captured data // When the capture data is saved, the header information will be saved. // ‘Pause’ to save the captured data with the header file. // 8) Capture information- Capture information is added to the header file // This the client current location // Resolution/sps // Latitude // Longitude // AdminArea // CountryCode // CountryName // FeatureName // Locality // PostalCode // SubAdminArea // SubLocality // SubThoroughfare // Thoroughfare // 9) File>Load Header Resolution/sps <<< It will load the resolution ONCE the capture data file is selected. // Default Resolution/sps = 384sps // 10) Add tmrAbout To display the about page LOGO for 4s. // Disable this tmrAbout.Enabled := False; // You can enable tmrAbout.Enabled := True; // 11) BT2 transmission distance: 100ft // 12) Modify Table Sin(), Exp(), Sqr() are replaced by Math Function instead of wave table. // 13) email Add Header with client location and ecg information. // 14) email + attachment Add Attachment – ecg Captured File List to the attachment. // 15) email option Choose (Header only) or (Header + Attachment) // 16) Cardiac mode 3 Leads cardiac monitor // Heart mode Monitor place next to the heart // Hand mode HEART RATE MEASUREMENT AT HANDS (Trial Version) // 17) Sleep mode Let MCU Sleep right away //========================================================= // 16) Capture Data To Minimize the Capture Data size // Format in ‘HEXDEC’ or ‘6 Significant figure with 5 decimal places’ // Comment: For ONE sps is approx 10 byte in ‘6 Significant figure with 5 decimal places’ // ONE hour data capture // 128sps approx 1280×3600 = 4608 kbytes/hr // 256sps approx 2560×3600 = 9216 kbytes/hr // 384sps approx 3840×3600 = 13824 kbytes/hr // 512sps approx 5120×3600 = 18432 kbytes/hr // 640sps approx 6400×3600 = 23040 kbytes/hr // 768sps approx 7680×3600 = 27648 kbytes/hr // 896sps approx 8960×3600 = 32256 kbytes/hr // 1024sps approx 10240×3600 = 36864 kbytes/hr // 1152sps approx 11520×3600 = 41472 kbytes/hr // 17) Syntax Optimization in ecgMain.pas // 18) Remove some global variable in FFTfcn.pas and modularize all function and procedure. // 19) The global variable calling in FFTThread.pas cannot be removed. This are problems of the thread characteristic. //========================================================= // 20) Check the Alert Condition // procedure pcrMonitorTrigger // Description: Check the Alert Condition // bprAlertDTW, bprAlertAmp, bprAlertbpm, bprAlertFDBT, bprAlertSDBT // // if Alert Condition is TRUE, call the AutoDialer, AutoSMS and AutoEmail // tbi – Comment: After calling AutoDialer, AutoSMS and AutoEmail these functions, // // NEED to reset the AutoDialer, AutoSMS and AutoEmail. // NEED to reset the AutoDialer, AutoSMS and AutoEmail. // OR NEED to recall the AutoDialer, AutoSMS and AutoEmail with “certain period of time” !!! // OR NEED to recall the AutoDialer, AutoSMS and AutoEmail with “certain period of time” !!! //========================================================= // 21) Check abnormal ECG either by // bprAlertDTW, bprAlertAmp, bprAlertbpm, bprAlertFDBT, bprAlertSDBT // If the clients want to capture abnormal ECG, they can select either one or more option to capture // the ecg data. If ecg wave is abnormal and will be captured automatically. // The file ecgdataXXXX.txt will be saved automatically. // Capture Period is default in 5 minutes. User can change the period to more in INIFile. //========================================================= // 22) Adding function to check LO+ and LO- (IN+ and IN-) status // Show LA and RA – On/Off on the screen for the connection status. //========================================================= // AD8232/(AC/~DC)/Pin 14/IO-PD4 Always PULL-Low /Default = DC Lead off mode !!! // AD8232/(AC/~DC)/Pin 14/IO-PD4 Always PULL-Low /Default = DC Lead off mode !!! // AD8232/(AC/~DC)/Pin 14/IO-PD4 Always PULL-Low /Default = DC Lead off mode !!! // AD8232/(AC/~DC)/Pin 14/IO-PD4 Always PULL-Low /Default = DC Lead off mode !!! //========================================================= // 23) Adding Heart Mode // There are two electrode underneath the equipment. User can place the equipment next to your heart // to carry out the ecg monitor function. // BUT there is NO detection of two electrodes which is connected or disconnected with the user body of the heart. // // Comparison with Cardiac Mode. // There is a detection of two electrodes which is connected or disconnected with the user body of the heart. // There will have an indications of the connection with the user body. //========================================================= //========================================================= //========================================================= // Comment: Cardiac Mode & Heart Mode // There is NO significant difference between Cardiac Mode & Heart Mode in hardware. // Two units of MAX4626 switches are deleted. Now, the firmware of Cardiac Mode & Heart Mode are the same. // Even though the instruction CMD command ?a and ?b is to change the PD3 and PD7 logic. Actually, there // is NO change of the hardware of AD8232. It only config as Cardiac Mode with gain = 1100. // // LO+ and LO- are connected to CPU port PD5 and PD6. Software detection algorithm is used to detect the LO+ and LO-. // In Cardiac Mode, it will detect the connectivity of LA and RA electrodes to the body. // In Heart Mode, LO+ and LO- are disable by software. The two electrodes are directly connected to the body // next to the heart. //========================================================= //========================================================= //========================================================= // 24) Display ECGxxxxxxxx.txt label when select Rd ECG at the cbxMenu //========================================================= // function fbZeroCrossFreq // Description: The function is to find the R-S complex. // continuously to find the next R-S complex. // Calculate the difference between the time of TWO R-S complex. // Successfully to calculate iRRInterval := iTrs0 + iTss – iTrs1 // // Comment: Code is tested OK!!! dd 18 May 2017 //========================================================= // 25) Selectable Frequency Transformation // by ZeroCross Method – fbZeroCrossFreq // by FFT – fbmakeSpectrum //========================================================= // Sudden Cardiac Death – SCD is a death from causes // attributable to the heart, preceded by a sudden loss of // consciousness, which takes place shortly (less than one // hour) after appearance of acute symptoms in patients with // heart disease. // // http://pe.org.pl/articles/2013/2a/13.pdf // Project of open-source software platform for sudden cardiac // death (SCD) risk stratification and advanced ECG analysis // // For SCD risk stratification authors will use a set of four markers based on // ECG signal: TWA, HRT, HRV and DC/AC. //========================================================= // 25) HRV Heart Rate Variability // Heart rate variability (HRV) is the physiological phenomenon of variation // in the time interval between heartbeats. // It is measured by the variation in the beat-to-beat interval. // Function: fbRMSSD is used to calculate the Root Mean Square of the difference of RR-Interval //========================================================= // 26) HRT Heart Rate Turbulence // For SCD risk stratification authors will use a set of four markers // Heart rate turbulence (HRT) is the return to equilibrium of heart rate after a premature // ventricular contraction (PVC). It consists of a brief speed-up in heart rate, followed by // a slow decrease back to the baseline rate. // Function: fbHRT is used to calculate the Heart Rate Turbulence //========================================================= // 27) ST Segment Analysis // The detection of arrhythmia and continuous ST segment monitoring to detect ST // changes which may be ischemic episodes. Ischemia detection has always been an important // component in identifying
and managing patients with coronary artery disease. // Function: fbSTAnalysis is used to calculate the ST Segment Analysis //========================================================= // 28) T-Wave Alternans (TWA) // T wave alternans (TWA) is a periodic beat-to-beat variation in the amplitude or shape of // the T wave in an ECG. // Function: fbTAnalysis is used to compute the TWA // // Methodology: // (1) Calculate iTt time frame for T-Wave segment. // (2) Using A0 and B0 as a reference beat. // (3) Align An with A0 and algin Bn with B0 accordingly. // (4) Fill in aTAChartValues when iTIndex is odd // (5) Fill in aTBChartValues when iTIndex is odd // (6) If iTt = T-Segment width, set bTSegment = False // (7) After finish to fill up aTAChartValues and aTBChartValues, we can calculate each of Average T-Wave // (8) We can have TWO aTAvgA and aTAvgB ChartValues to compare the difference of TWA // (9) Once Average T-Wave of TA and TB are calculated, we can call DTW to calculate the distance path //========================================================= // 29) Deceleration Capacity (DC) / Acceleration Capacity (AC) // function: fbDCAC // Description: During Deceleration capacity (DC) and corresponding // acceleration capacity (AC) provide a quantitative // assessment of heart rhythm capacity to decelerate and // accelerate respectively. Parameter values are calculated // using phase-rectified signal averaging (PRSA) method, // after synchronization of all periodic oscillations of RR // intervals excluding all non-periodic distortions (artifacts, // noise, etc.) // Methodology: // (1) Definition of anchors // (2) Definition of segments (S1, S2, S3,…Sn) // (3) Phase rectification // (4) Signal averaging // (5) Quantification of DC or AC //========================================================= // 30) Detect Inverted T-Wave // Function: fbInvertTWave // Description: Detect Inverted T-Wave // If there exist a Positive T-Wave, there also exist an Inverted T-wave. // bInvertedT = False // If there is NO Positive T-Wave, there ONLY exist an Inverted T-wave. // bInvertedT = True // // Methodology // (1) Looking for Positive T-Wave (-ve local maxima) in between S-Complex and dInvTStart. It must be above zero. // (2) If there is NO positive Local Maxima which above 0.06 // (3) Looking for Inverted T-Wave (-ve local minima) in between dInvTStart and dInvTWidth. // (4) Timeout then reset iTInvT timer counter to -1, bPositiveT and bInvertedT to False //========================================================= // 31) Procedure pcrSetLabelsCoordinate // Description: There is an error to display the labels for 10″, 7″, 5″ and 4″ in Android screen. // especially, in huawei 1080 x 1920 pixels (~423 ppi pixel density). // Solution: Calculate ALL labels by frmECG.Width/960 and frmECG.Height/640 // It will take care of all the width and font.size for difference size of Android screen. // The previous version 10″, 7″, 5″ and 4″ in Android screen using hard code to put labels // on to the form. Procedure pcrSetLabelsCoordinate is using ratio dXRate = frmECG.Width/960 // to calculate and re-draw ALL labels. //========================================================= // 32) function fbBTCharacteristicRead is modified. It can transmit three bytes ‘S0002$0003$0004$00005’ // without CRLF. The TXD and RXD speed without CRLF is acceptable. //========================================================= // 33) Important Note!!! Reference to Apple Developer Guide – ‘xCode Simulate Bluetooth’ // Testing Bluetooth LE applications will require access to a real iOS device going forward. // As you discovered, bluetooth is not supported in the simulator. // That support was removed some time ago (around 2013 if I recall correctly). // You need to use a real device with the simulator if you want to test with bluetooth. //========================================================= // 34) tbi pnlWaiting.Visible := False; // Disable pnlWaiting and make visibility to False //========================================================= // 35) OSX (Must be worked with external bluetoothLE!!!) // Otherwise, it does not work with internal bluetooth!!! // // Testing Bluetooth LE applications will require access to a real iOS device going forward. // As you discovered, bluetooth is not supported in the simulator. That support was removed // some time ago (around 2013 if I recall correctly). // You need to use a real device with the simulator if you want to test with bluetooth. // // 36) IOS (It works with real device with the simulator if you want to test with bluetooth.) // Setup with IOS “Provisioning an iOS Application” // Reference: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Provisioning_an_iOS_Application // Read “iOS Mobile Application Development” // Reference: http://docwiki.embarcadero.com/RADStudio/Tokyo/en/IOS_Mobile_Application_Development // xCode and simulator: KeyChain to select My Certificate/IOS Developer/Access Control – // “Allow all applications to access this item” // xCode and simulator: Create a project “Bundle Identifier: ecgMonitor” // Deployment Target : iPhone OS – example 10.3 same as physical iPhone. // Device : iPhone // Left ICON: Select iPhone with “same name” as physical iPhone // Signing Certificate with Apple Developer and Team //========================================================= // 37) Customizing Your info.plist File // http://docwiki.embarcadero.com/RADStudio/Tokyo/en/Customizing_Your_info.plist_File //========================================================= // 38) Apple Developer Data Path // ‘/Users/domko/Library/Developer/CoreSimulator/Devices/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/data/Containers/Data/Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents/ecgCaptureData/ECG18021232924-256.txt’ //========================================================= // 39) Add Beep Sound to IOS //========================================================= // 40) Fix Screen Orientation // Simulation Test: // iPad AIR 10.3.1 OK // iPad 7+ 10.3.1 OK // iPad Air 10.2 OK // iPhone 6+ 9.3 OK // iPhone SE 10.2 OK // iPad 2 10.3 OK // iPad Pro 10.3 Fail // iPhone 6 9.3 OK // iPhone 6s+ 10.2 OK // iPad Retina 9.3 OK // iPhone SE 10.3.1 OK // iPad Air 2 9.3 OK // iPhone 5s 10.2 OK // iPad 2 9.3 OK // iPhone 6s 9.3 OK // iPhone 5 10.2 OK // iPhone 7 10.3 Fail // // Android Test: // Nexus7 // Samsung //========================================================= // 41) Change pnlWaiting to rectWaiting // Change pnlBT4Waiting to rectBT4Waiting //========================================================= // 42) Add large file capture control // Setup>Capture Limited Data
//=========================================================
// 43) Add LogAppErr on fbSetUpOneBTData and fbZeroCrossFreq
//
//=========================================================
// 44) Add FLAG_KEEP_SCREEN_ON to keep the screen awake
//
//=========================================================
// 45) Initialization
// TFastLineSeries(ecgChart[0]).DrawAllPoints := False;
// TFastLineSeries(ecgChart[0]).FastPen := True;
// ecgChart.Axes.FastCalc := True;
// ecgFastLine.AutoRepaint := False;
// ecgChart.AutoRepaint := False;
//=========================================================
// The HM-10 abstracts and packs a Bluetooth Low Energy
// connection in a serial connection.
// The original out-of-the-box firmware of the module exposes
// a BLE peripheral with a proprietary connectivity service
//
// (Service UUID: 0000ffe0-0000-1000-8000-00805f9b34fb) that
// enables bidirectional communication between the module and
// any other central device that connects to it.
// The service defines a single characteristic
//
// (Characteristic UUID: 0000ffe1-0000-1000-8000-00805f9b34fb) that
// stores 20 bytes of unformatted data:
//
// When the central device wants to send data to the module,
// it WRITES the characteristic with the desired content.
// When the module wants to send data, it sends a NOTIFICATION
// to the central device.
//=========================================================
// Modified: 2 Jul 2018 11:53:00 PM
// (Description: 1.0.0.12)
// 46) Change giDefaultFreq and giDefaultAmp to value of 10.
// Sound of the beep when there is invalid frequency will be 600 pulse per sec.
// It more make sense of invalid frequency on bpm or bps.
// The lblPulseMin will be ‘888 bpm’ or ’88 bpm’.
// lblPulseSec will be ‘8.88 bps’.
//
// Verify the fbDCAC and fbHRT functions.
// fbDCAC and fbHRT are depending on eFrequency.
// It is OK to use ‘ZeroCross discrete frequency’ to get the frequency whenever
// there is a valid frequency available from fbZeroCrossFreq.
//=========================================================
// Modified: 5 Jul 2018 07:13:00 AM
// (Description: 1.0.0.15)
// 47) Add Directive at ECGctrl.inc
//
// For IOS Device – 32 bit, there is no problems on AnsiChar.
// For IOS Device – 64 bit, there is an exception on
// ‘No mapping for the Unicode character exists in the target multi-byte code page’
//
// Change the following code.
// {$HIGHCHARUNICODE ON}
// {$EXCESSPRECISION OFF}
// sValue := ACharacteristic.GetValueAsString(0, True);
//=========================================================
// Modified: 23 Jul 2018 09:26:00 PM
// (Description: 1.0.0.19)
// 48) Low Battery Operation:
// If the battery is operated below 3.3v, the wave form will have a BIG distortion.
// There will be a 0.2Hz-0.5Hz wave superimposed on the ECG wave,
// It should be re-charged the battery again!!!
//
// The BLE also received better signal when the battery is enough.
//
//=========================================================
// Modified: 26 Aug 2018 12:00:00 PM
// (See Description 1.0.0.24)
// Reinstallation on Delphi 10.2.3
// Recompile the project on Delphi 10.2.3
//=========================================================
// Modified: 27 Aug 2018 08:38:00 AM
// (See Description 1.0.0.25)
//
// There is NO change on the code of ecgMain.
//
// 1) Samsung S9 Issue
// Samsung can be seen by the Delphi. Still it cannot be link with debugger.
// The issue is same as 10.2.1 and 10.2.3.
// The debugger cannot link with Delphi. The problem is coming from the Google side.
// The OS Android Oreo is tested on Nexus. This problem will be solved.
// Samsung S9 is waiting for the update…
//
// 2) IOS Simulator – OS 11 or Later.
// For OS 11 or later, the simulator also cannot be compiled.
// Delphi said the new version of 10.3 will have 64-bit os. The problem will be solved.
// The current simulator on 10.2.3 is still working on 32-bit os.
// The simulator is waiting for the update…
//
// 3) Samsung Galaxy Note Edge
// The apps is running un-stable in 10.2.1.
// After about 1-day running, the apps will suddenly closed.
// The apps is running more stable in 10.2.3.
// After about 2-day running, the apps is still running without closed.
//
// 4) Nexus 7 in 10.2.3
// The apps is running with more fast respond. The is NO delay in real time capture.
// There is NO issue in iPhone and iPad.
//=========================================================
// Modified: 09 Sep 2018 10:20:00 PM
// (See Description 1.0.0.27)
// Add ‘D.P.F. Component IOS’ to the library. DPF Component is native IOS component.
//
// 1) This DPF Component IOS library has to major usage on ‘eMail and iMessage compose’.
// The component of dpfMailCompose and dpfMessageCompose are using in IOS to
// send email and iMessage to another mobile device.
//
// Before the apps is only enhanced for Android. With this DPF Component IOS,
// the app can be used for IOS device.
//
// 2) DPF Component is native IOS component. For user permission, it is easy to add
// the interfacing of TDPFUserDefaults. SetBooleanValue and GetBooleanValue to
// get and set the boolean value at IOS of iPhone and iPad at
// Settings > General > Application > (SMS, Email, Location and Phone Call)
//
// The DPF component is used to set and get the information in ‘root.PList’.
// Once the apps change the boolean value. It will change the value of ‘root.PList’.
// SMS, Email and Phone Call can be set in ‘root.PList’.
// Location Permission is in difference place of setting in
// Project > Options > Version Info > ‘NSLocationAlwaysUsageDescription & NSLocationWhenInUseUsageDescription’
//
// 3) rectUserPermission and rectMessageDlg dialogs are added for Android and IOS.
// At FIRST start, a dialog will ask the user permission for ‘SMS, Email, Phone Call and Location’.
// Once the user answer all permission with ‘Allow or Deny’.
// At Second start, a dialog will NOT popup again. It only can be changed at
// Settings > General > Application > (SMS, Email, Location and Phone Call).
//
// Comment: There is a ‘root.PList’ in XML format for IOS.
// This ‘root.PList’ is using to hold information:-
// – Application, Developer or version information
// – Preference/Boolean of SMS, Email, Location and Phone Call.
// Some library components are added to $(SDKROOT)/System/Library/Frameworks
//
//=========================================================
// Modified: 17 Sep 2018 03:30:00 PM
// (See Description 1.0.0.28)
// Add ‘KastriFree-master’ to the library. KastriFree-master is Android component
//
// 1) For user permission, it is easy to add the interfacing of TSystemHelper.
// shprSystemHelper.RequestPermissions is used to get and set the boolean value
// at Android at Settings > Apps > Application > Permission of (External Storage, SMS, Location and Phone Call)
//
// 2) rectUserPermission and rectMessageDlg dialogs are added for Android and IOS.
// At FIRST start, a dialog will ask the user permission for ‘External Storage, SMS, Phone Call and Location’.
// Once the user answer all permission with ‘Allow or Deny’.
// At Second start, a dialog will NOT popup again. It only can be changed at
// Settings > Apps > Application > Permission of (External Storage, SMS, Location and Phone Call)
//
// 3) Android Permission Library is added for ‘KastriFree-master’
// Library path is set to Android Permission Library/API,
// Android Permission Library/ComponentHelpers,
// Android Permission Library/Core
// Android Permission Library/Include
// Android Permission Library/Lib
//
// Comment: The User Permission only enable in OS 6.0.0 or Higher. Testing ON 4.4.2 or 5.0.1 is not working!!!
// ‘google-play-services-gcm-7.0.0.dex.jar’ is disabled to run the KastriFree-master.
// ‘dw-nativeactivity.jar’ is added to the library.
// AndroidManifest.template.xml is using KastriFree-master provided.
// Android and IOS are both shared ‘rectUserPermission and rectMessageDlg’ dialogs
// We don’t add the FULL ‘KastriFree-master’ library (just necessary part) to the Android Permission Library.
//
// Android Permission – (External Storage, SMS, Location and Phone Call)
// IOS Permission – (SMS, Location, Phone Call and Email)
//
//=========================================================
// Modified: 25 Sep 2018 01:10:00 AM
// (See Description 1.0.0.29)
// Using rectPageControl to replace the Delphi PageControl component.
// The graphic interface is look colourful than PageControl.
//
// We are using the following rectPageControl components.
// rectPageControl : TRectangle;
// rectPageAbout : TRectangle;
// rectPageBTChat : TRectangle;
// rectPageBT4Chat : TRectangle;
// rectPageECGMonitor : TRectangle;
// rectPageSetup : TRectangle;
// rectPageFiles : TRectangle;
// rectPageTheme : TRectangle;
// rectPageMemo : TRectangle;
// rectPageLocation : TRectangle;
//
// Comments:
// 1) pcrUpdateKBBounds is removed from FormFocusChanged.
// 2) There is a bug in pcrSetLabelsCoordinate of ecgChart.Height.
// ecgChart.Height is changing and cannot be validated before calling pcrSetLabelsCoordinate
//=========================================================
// Modified: 29 Sep 2018 10:00:00 PM
// (See Description 1.0.0.31)
// Remove public variable in TPlotClass. Modularize the procedure and function call.
//=========================================================
// Modified: 04 Oct 2018 10:00:00 PM
// (See Description 1.0.0.32)
// Function: fbPeakBin, fbQuadratic & fbStirling are used to estimate the PeakBin Frequency and Amplitude.
// Function: fbLogPeakBin, fbExpQuadratic is used to estimate the PeakBin Frequency and Amplitude.
//
// Comment: -dResolution <= dp <= dResolution, Where dResolution = half of the interval of VFreq
// Result almost the same: (fbLogPeakBin & fbExpQuadratic) and (fbPeakBin & fbQuadratic)!!!
// Result almost the same: (fbLogPeakBin & fbExpQuadratic) and (fbPeakBin & fbQuadratic)!!!
// Result almost the same: (fbLogPeakBin & fbExpQuadratic) and (fbPeakBin & fbQuadratic)!!!
//
// vFreqs[i] Frequency Resolution:-
// eFreq := i*iSampleRate/iNBRPoints/32;
// vFreqs[i] := eFreq*iTimeBase/iTimeBaseConstant;
// vFreqs[i] := i*iSampleRate/iNBRPoints/32 * iTimeBase/iTimeBaseConstant;
//
// vFreqs[i] Frequency Resolution is given by the above equation.
// example: eFreqs := 8192/2048/32 = 1/8;
// vFreqs[i] := 1/8 * 256 / 256 = 1/8;
// The resolution will be improved by using fbPeakBin & fbStirling.
// They are second and third order iteration.
// The result vFreqs[i] Frequency Resolution is improved a lot.
//
// dx[0] := 0.75;
// dx[1] := 0.875;
// dx[2] := 1;
// dx[3] := 1.125;
// dx[4] := 1.25;
// dfx[0] := 0;
// dfx[1] := 0.0;
// dfx[2] := 8.0;
// dfx[3] := 0.0000005; //<<< Here is the error term!!!
// dfx[4] := 0.0;
// //Freq original = 60 bpm
// //Freq estimated = 60.00000100 bpm //<<< Here is the estimation!!!
//
// fbPeakBin, fbQuadratic & fbStirling are tested!!!
//
//
// 1) fbPeakBin is converted
// applsci-06-00306.pdf
// www.mdpi.com/2076-3417/6/10/306/pdf
//
// 2) fbStirling is converted from C++ to pascal
// https://www.geeksforgeeks.org/program-stirling-interpolation-formula/
//
// We use PeakBin (fbPeakBin) and Stirling Interpolation (fbStirling) to
// calculate the frequency and amplitude.
// Stirling is third order iteration. PeakBin is second order iteration.
//
// 3) we use fbQuadratic to estimate Amplitude from PeakBin Frequency
// https://ccrma.stanford.edu/~jos/parshl/Peak_Detection_Steps_3.html
// y(x) app. = a (x – p) * (x – p) + b
//
// p = 0.25 * (alpha – gamma) / (alpha – 2beta + gamma)
// which is given by dResult of fbPeakBin
//
// y(p) = beta – 0.25 * (alpha – gamma) * p
//
// where:-
// alpha := dfx[1];
// beta := dfx[2];
// gamma := dfx[3];
// p := 0.25 * (alpha – gamma) / (alpha – 2beta + gamma)
//
// Comments:-
// fbStirling is more accurate but slower.
// fbQuadratic is less accurate but faster.
//=========================================================
// Modified: 04 Oct 2018 10:00:00 PM
// (See Description 1.0.0.32)
// 1) Array modified: ecgStd, ECG_Wave & ECGReal_wave
// 2) Re-define lbxGpHeader and lbxItem of lbxMultiView and re-define margin, Font, Size and Family
// 3) Add DSP Resolution switch to select Stirling or Quadratic Interpolation
// 4) Add color to buttons on rectPageSetup
//=========================================================
// Modified: 11 Oct 2018 10:50:00 PM
// (See Description 1.0.0.34)
// 1) Modifed: bt4ECGCharacteristicRead, bt4ECGDiscoverLEDevice & bt4ECGEndDiscoverDevices
// 2) Filter only for all ‘ecgMon’ devices and list on the drop down list.
// It will not show up other BLE devices without ‘ecgMon’ characters.
// 3) It will or will not start pcrBTEndDevice automatically after bt4ECGEndDiscoverDevices.
//=========================================================
// Modified: 13 Oct 2018 10:50:00 PM
// (See Description 1.0.0.35)
// First time installation, show ‘splash screen’ before user permission screen
// It works on Android. It does not work on IOS.
//=========================================================
// Modified: 16 Mar 2019 10:00:00 PM
// (See Description 1.0.0.37)
// Android version
// After certain time the apps will be killed by the OS of Android,
// if the user switch off the screen after certain time.
// Killing apps time is depending on setting arround 5-10 minutes.
//
// After Android OS 8 Oreo, Google adding Power Manager to Optimize the battery life.
//
// ================================================================================
// We want to keep the screen on by ‘FLAG_KEEP_SCREEN_ON’ when the apps is running.
// OR
// If press ‘Power Off’ button with screen and keyboard off,
// we still want to keep the CPU in running mode.
// ================================================================================
// BUT, after the user press the power button, Android will KILL the apps if the screen off
// at certain time.
//
// IOS version
// There is no such issue in IOS.
//
// Attention: The wake lock doesn’t work in debug mode.
// It only work in release mode.
//
// SOLUTION:-
// User Permission: WakeLock on and Androidapi.JNI.PowerManager to solve the issue.
// Keeping the Android CPU running in the background when screen and keyboard are OFF.
//
// ================================================================================
// Stable Version by Delphi-Emotiv-EPOC-master.zip of PowerViewer
//
// Mode: PARTIAL_WAKE_LOCK
// ScreenCtrl: True (Always Screen ON)
// Note: Including AndroidManifest.template.xml in the project!!!<<<<<<<<<<<
// Source Code: Delphi-Emotiv-EPOC-master.zip of PowerViewer
// Adding user permission ‘Access Wake Lock’
//
// TApplicationEvent are using the original event handler!!!
// TApplicationEvent.FinishedLaunching : fbAcquireWakeLock(jprWakeLock);
// TApplicationEvent.BecameActive : fbAcquireWakeLock(jprWakeLock);
// TApplicationEvent.WillBecomeInactive : pcrReleaseWakeLock(jprWakeLock);
// TApplicationEvent.EnteredBackground : pcrReleaseWakeLock(jprWakeLock);
// TApplicationEvent.WillBecomeForeground: fbAcquireWakeLock(jprWakeLock);
// TApplicationEvent.WillTerminate : pcrReleaseWakeLock(jprWakeLock);
//
// Comment: ScreenCtrl: Off (Always Screen Off) is not always working!!!
// ================================================================================
//
// Method: Adding user permission ‘Access Wake Lock’ interfacing to user permission popup.
// Adding corresponding code to functions and procedure to enable the ‘Access Wake Lock’.
//
// Reference: [How to prevent FireMonkey app / service stop working while in background?] // https://stackoverflow.com/questions/52504808/how-to-prevent-firemonkey-app-service-stop-working-while-in-background
//
// [Guide to background processing] // https://developer.android.com/guide/background#js
//
// [how to keep app running when screen off?] // https://stackoverflow.com/questions/44743265/how-to-keep-app-running-when-screen-off-or-open-another-app
//
// [Delphi XE5 Android. How to use PowerManager.WakeLock?] // https://stackoverflow.com/questions/19021647/delphi-xe5-android-how-to-use-powermanager-wakelock
//
// [How to keep an Activity running while screen off?] // https://stackoverflow.com/questions/11978742/how-to-keep-an-activity-running-while-screen-off
//
// [PowerManager] // https://developer.android.com/reference/android/os/PowerManager
//
// [GlassLevel example by Embarcardero] <<<< GlassLevel doesn’t work properly!!! // is using wake lock to keep the apps continue running in background. // // [PowerViewer] from Delphi-Emotiv-EPOC-Master/Demo/PowerViewer // is using wake lock to keep the apps continue running in background. // PowerViewer is modified with method ‘PARTIAL_WAKE_LOCK’ and worked properly!!! // // [Optimize for Doze and App Standby] // https://developer.android.com/training/monitoring-device-state/doze-standby // // Comment: // There are few solutions to solve this problems by ‘Background Processing’. // DownloadManager, sync adapter, JobScheduler, Firebase Cloud Messaging and Wake Lock. //========================================================= // Modified: 21 Mar 2019 12:30:00 PM // (See Description 1.0.0.38) // // Moving ‘FLAG_KEEP_SCREEN_ON’ to the Setting Page // Using a switch to control the screen. // Allow the Screen Auto OFF and Always ON // Battery Save Mode – Screen Auto OFF // Special Request – Screen Always ON // // Apply the switch procedure at swScreenCtrlClick //=============================== // //Prevent Android to sleep // {$IFDEF ANDROID} // Screen always ON // SharedActivity.getWindow.addFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_KEEP_SCREEN_ON); // {$ENDIF} // // //Prevent IOS to sleep // {$IFDEF IOS} // //UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication); // //UIApp.setIdleTimerDisabled(True); // {$ENDIF} //=============================== // //Allow Android to sleep for Battery Save Mode // {$IFDEF ANDROID} // Screen Auto OFF // SharedActivity.getWindow.clearFlags(TJWindowManager_LayoutParams.JavaClass.FLAG_KEEP_SCREEN_ON); // {$ENDIF} // // //Allow IOS to sleep for Battery Save Mode // {$IFDEF IOS} // //UIApp := TUIApplication.Wrap(TUIApplication.OCClass.sharedApplication); // //UIApp.setIdleTimerDisabled(False); // {$ENDIF} //=============================== //========================================================= // Modified: 01 Apr 2019 12:30:00 PM // (See Description 1.0.0.39) // // Rename: ecgBTMonitor to ecgMonitor // Comment: Prepare and Submit the app to Apple Store and Google Play Console // Modified: All Graphics are changed to ‘ecgMonitor’ // Apple Developer License is applied. // Google Developer License is applied. //========================================================= // Modified: 21 Apr 2019 07:15:00 PM // (See Description 1.0.0.40) // Solution: WORKED from Dave N, DelphiWorlds // Status: Bug Fixed // // Comment: // Screen Orientation is able to do Landscape and Inverted Landscape // rectPageAbout, rectPageBT4Chat, rectPageBTChat, rectTabECGMonitorClick & rectPageLocation // Screen Orientation is applied to ALL Orientation // rectPageSetup, rectPageFile & rectPageTheme //========================================================= // Modified: 27 Apr 2019 01:25:00 PM // (See Description 1.0.0.41) // Android: Version Info->Add API Key from Google Play Console
// Android: http://blong.com/Articles/AndroidPermissions/DelphiAppPermissions.htm
// Please play attention below.
// However at the end of 2017 Google announced that the rules were changing
// in 2018. In order to submit apps to the Google Play store they must now
// target API Level 26 (Android 8.0) or higher. Complying with this new
// requirement means that Delphi apps will now need to work with the runtime
// permissions model, something they could not do until Delphi 10.3 Rio.
//=========================================================
// Modified: 04 May 2019 05:00:00 AM
// (See Description 1.0.0.42)
// OLD Library U_FFT.pas and U_FFT2.pas is replaced by new U_FFT.pas.
// fbFourierTransform from fourier.pas – Don Cross <dcross@intersrv.com>
//
// Updated version of Kastri library from Delphiworld/Dave Nottage is using with DW.Android.Helpers.
// TAndroidHelperEx.RestartIfNotIgnoringBatteryOptimizations is to make sure the app
// is running in ‘IgnoringBatteryOptimization’ mode.
//
// In Android after 6.0, there is a ‘Doze’ and ‘Standby’ mode to optimize the battery usage.
// User Permission is required from the user at the startup screen to ask for the
// ‘IgnoringBatteryOptimization’ permission to keep the background running for CPU on and Screen off.
//
// In iPad and iPhone, there are no such issue to ‘Keep_Screen_ON’.
// Background runmning is OK in IOS.
//=========================================================
// Modified: 10 May 2019 10:00:00 PM
// (See Description 1.0.0.43)
//
// Introduce the below ‘Performance Mode’ for Android
// 1) High Performance – Screen On
// 2) Normal Mode – Screen Off/Background Mode
// 3) Low Battery Mode – Screen Off
//
// Description of ‘Performance Mode’
// 1) High Performance – Screen On is the mode that CPU is always running and Screen is always ON.
// The user can do any activities such as phone call, browsing, gaming,
// video and audio … etc together. The apps is ALWAYS working.
// The ‘High Performance Mode’ is that the battery will be drain for performance.
// 2) Low Battery Mode – Screen Off/Background mode is that CPU is always running in the background and
// Screen is auto off in doze mode.
// The user can do any activities such as phone call, browsing, gaming,
// video and audio … etc together. CPU can be kept running in the background
// for 1hr-8hrs. The apps will be killed by the system when the user has no
// activities.
//=========================================================
// App’s core function is ecg monitoring and maintaining a persistent connected via standard Bluetooth profiles.
//
// An app holding the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS permission can trigger a system dialog to let the user add the app to the whitelist directly, without going to settings. The app fires a ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Intent to trigger the dialog.
//
// “Google’s written approval of your use-case before asking for this permission in your app”!!!
// Try to get in touch with Google to avoid unexpected suspension.
//
//https://andrewrezk.com/how-i-restored-my-app-on-google-play-after-suspension/
//=========================================================
// Google Play Console:
//
// App name: ‘ecgMonitor’
//
// Build # v.1.0.0.6
//
// Description:
// ecgMonitor is a wearable device using to measure ECG next to the heart.
// The ecg data is captured by the monitor and send to Android phone or tablet
// and iPhone and iPad by ‘ecgMonitor’ app to carry out ‘REAL-Time’ Analysis
// via Bluetooth Profile.
//
// Ref: REQUEST_IGNORE_BATTERY_OPTIMIZATION and WAKE_LOCK
//
// App’s core function is ecg monitoring and maintaining a persistent connection via standard Bluetooth profiles.
//
// Since the app is need to maintain a persistent connection via Bluetooth profiles for monitor function, the app need to have ‘REQUEST_IGNORE_BATTERY_OPTIMIZATIONS’ and ‘WAKE_LOCK’ permission.
//
// I want to inquire how to do it right for the above TWO permissions.
//
// How to do it properly to to avoid unexpected suspension?
//
// Would you please also how to have the approval from Google to using TWO permissions in my apps?
//
// Thank you for your help and assistance.
//
// encl. Pls find an in-app dialog to ask for the user for the permission.
// Screenshot_Stop_Battery_Optimization_Settings.jpg
// Screenshot_User_Permission.jpg
//=========================================================
//
// ALPHA TEST with bug report
//
//=========================================================
//
//
//=========================================================
//
// Bug Report!!!
//
//=========================================================
// Bug#001
// Fixed
// Disable the function when the time is running(Start Event)
//
//=========================================================
// Bug#002 FIXED
// Fixed
// Here for giWaveType > giCaptureMode
// Do one more time of setup chart scale
// Change Axes Time Scale
// Code is removed.
//
//=========================================================
// Bug#003
// Fixed
// Only enable the function when the time is not running(Pause Event)
//
// Bug#004
// Fixed
// Only save the capture data when capture is enabled.
//
//=========================================================
// Bug#005
// Fixed
// Same as Bug#004. Only save the capture data when capture is enabled.
//
//=========================================================
// Bug#006
// Fixed
// Make sure CALLING the pcrMonitor after the first page. Try 5 Times!!!
// If there is no delay, it will araise access violation.
//
//=========================================================
// Bug#007
// Fixed
// This bug is due to the tmrECG thread still running in the background.
// fbCalculatePath is not finished the calculation and quit the exe.
// It will come out the Exception.
// Waiting 2s to end the fbCalculatePath calculation, Threads, Timers
//
//=========================================================
// Bug#008
// Fixed
// Quiting the Apps need to wait until the fbCalculatePath is finished!!!
// It cannot free the array or waiting these calculation to be finished.
// Checking the fbCalculatePath is still finished or not?
//
//=========================================================
// Bug#009
// Fixed
// while bpuMonStatus do
// begin
// Do something
// end;
//
// =============================================================================
// Bug#010
// Fixed. See Bug#022
// Android OS 4.4.2
// Comment: Different iResolution will give different NumBufPoints.
// This is because the phase and the capture data difference.
// Solution: Result := Trunc(iScbTrigger+iTimeBase*XXX) > 3072, it must be greater than 3072.
// =============================================================================
// iWaveType = giReadMode, different i Resolution will give different Bluepoints
// Pl see the description of the function disfigurements
// If the capture data size is NOT multiple of 256, it will appear
// the join of the graph during looping of playing record.
// Result := Trunk(outrigger+Sebastian*XXX) > 3072, it must be greater than 3072.
//
//=========================================================
// Bug#011
// Fixed
// Casting the format extended or double into single.
//
//=========================================================
// Bug#012
// Fixed
// Make sure CALLING the pcrMonitor after the first page (not bpu1stPlot)
//
//=========================================================
// Bug#013
// Here, length of vXReal & vXImag must be the same of two multiple
//
//=========================================================
// Bug#014
// Fixed
// Fill the original chart with NO Gain and NO Offset
// Save dy to the aOrgChartValues
// No need to have this statement here and comment it out
// aOrgChartValues[indexI] := dy; //<<<<< Comment it out!!!
//
//=========================================================
// Bug#015
// Fixed
// Fill the original chart with NO Gain and NO Offset
// Save dy to the aOrgChartValues
// No need to have this statement here and comment it out
// aOrgChartValues[indexI] := dy; //<<<<< Comment it out!!! // //========================================================= // Bug#016 // Fixed // Get TWO max frequency from the frequency domain. Find the minimum of TWO max frequency. // ie. eF := min(efMax1, efMax2); // //========================================================= // Bug#017 // Fixed // Most difficult Bug!!! // fbPrnFrame has access violation exception. This exception is not always being catch. // Sometime happened and sometime not. Adding iprTimerCount to delay one frame and to start // the printing frame, the result is not more access violation. // Wait ONE time then starting fbPrnFrame // if iprTimerCount > 0 then
//
//=========================================================
// Bug#018
// Android Version 4.4.2
// Issue: The apps will hang. Problem: Broken Thread!!!
// Description: When the apps is capturing through the bluetooth and pause.
// Switching to SIN, Sim Hm or … etc and then switch back.
// Re-capture the ecg again. Then the app will hang!!!
//
// If the apps is capturing through the bluetooth and pause.
// Switching back to ecg capture or switching the resolution,
// There is NO such issue.
// Android Version 6.0.1
// There is NO such issue of above.
//
//=========================================================
// Bug#019 FIXED by Bug#020
// Android Version 4.4.2
// Issue: The apps will hang. Problem: Demo Broken Time Thread!!!
// Description: When the apps is switching from Wave Type within 10s and repeat and repeat switching the Wave Type.
// Switching to SIN, Sim Hm or … etc and then switch back. Then the app will hang!!!
//
// Issue: 1) The Timer has the broken thread!!!
// 2) Out of Memory in 4.4.2
// 3) OS has bug!!!
// It cannot catch the exception in 4.4.2
// Fixed Solution: Adding Sleep, Application.Process will help. It cannot solve the problems
//
// There is NO such issue.
// Android Version 6.0.1
// There is NO such issue of above.
//=========================================================
// Bug#020
// Comment out the below statement
// Axes.Bottom.Increment := 256;
// FIXED Bug#019
// After comment out this code, there is no more Bug#019 on Android 4.4.2
//=========================================================
// Bug#021
// Fixed
// Check the valid $XXXX hexdec format before proceed
// PlotClass.fbValidateStr();
//=========================================================
// Bug#022
// Fixed
// Modified the TPlotClass.fiGetNumBufPoints();
// All timebase constant is multiple by 1.05 or 5% more for buffer.
//=========================================================
// Bug#023
// Fixed
// The below code is to save the slprECGSavedData until iprCount > giNumRecords
// It is use to prevent the slprECGSavedData being too big to be save at the final.
//=========================================================
// Bug#024
// Checking the Bluetooth is connected or not
// If bluetooth connection is broken, reconnect it again
//=========================================================
// Bug!!! Bug#025
// Fixed
// Comment out the pcrcbxResolution0to1
// Let the demo have the resolution 128sps
//=========================================================
// Bug!!! Bug#026
// Fixed Minor bug
// sSend := edtBT4NewText.Text;
// sSend := edtNewText.Text;
//=========================================================
// Bug!!! Bug#027
// Fixed Minor bug
// Comment out the below code. Focus something wrong with bottom screen
// pcrUpdateKBBounds;
//=========================================================
// Bug!!! Bug#028
// Fixed
// It is a MUST that (vFreqs[i] < iBPMHighLimit/60)!!! // It is a MUST that (vFreqs[i] > iBPMLowLimit/60)!!!
// If (vFreqs[i] <= iBPMHighLimit/60) and (vFreqs[i] > iBPMLowLimit/60) then
// to Keep track of the 2 highest amplitudes.
//=========================================================
// Bug!!! Bug#029
// if frmECG.epuFrequency = 0, the fbTimerOnTime is NOT working.
// We need to check the dFreqThreshold frequency.
//=========================================================
// Bug!!! Bug#030
// if frmECG.epuFrequency = 0, the fdOptimizeFrequency is NOT working.
// We need to check the dFreqThreshold frequency.
//=========================================================
// Bug!!! Bug#031
// Add the below code to optimize the frequency below 0.01 dAmplitudeThreshold
// if (eA < gdAmplitudeThreshold) then // ef := 0; //========================================================= // Bug!!! Bug#032 // Code optimization: We don’t use fbFIFOcvChart to swap the chart. // We just put the data directly. // eg. aYChartValues[iBufPoints -1 -iIndex] := dy-dOffset // aYChartValues[iIndex] := dy-dOffset; // // eg. aYChartValues[iBufPoints -1 -iIndex] := dy-dOffset // aYChartValues[iIndex] := dy-dOffset; // Comment: It only work on fbSetupDataOneFrame!!! // It doesn’t work on fbSetUpOneBTData!!! //========================================================= // Bug!!! Bug#033 // There is NO Sound effect on R2L enabled. // The issue is internal code required optimization. // Solution: See Bug#032 & Bug#022 // Review Solution: Result := Trunc(iScbTrigger*9 + iNumPoints); //========================================================= // Bug!!! Bug#034 // There is a bug loading the ecg files. // The ECG graph is reversed!!! // We change the code from L2R to R2L and fbAxesConversion // All the syntax LeftToRight is changed to RightToLeft //========================================================= // Bug!!! Bug#035 // function: fbMakeSpectrum // We don’t use method to find the max amplitude!!! // We don’t use method to optimize the frequency!!! // Locate the max power, then get the corresponding Frequency and Amplitude!!! // // Method I // We find the max frequency by max(iMax1 & iMax2). // // Method II // We find the max frequency by interpolation method from (iMax1 & iMax2). // // Method III // Function: fdOptimizeFrequency // It works as a filter to filter out some unwanted frequency. // Select the best frequency instead of max power of spectrum. // Max power of frequency will give a too high or too low frequency than expected!!! // // By Method II // After testing, Method II and Method III together give the better result frequency. // // Comment: // Using method II to calculate the eFrequency. // If the eFrequency >= 2, we will use fdOptimizeFrequency to get the better frequency instead.
// If the eFrequency >= 2, we will use fdOptimizeFrequency to get the better frequency instead.
//
// If efMax1 and efMax2 are BOTH >= 2, the eFrequency will be greater than 2!!!
// The client will have the abnormal bpm!!!
//=========================================================
// Bug!!! Bug#036
// Freq = 786, 1152
// Adjust the eFrequency for giWavetype = giReadMode
// Comment: Because there is NO time clock to run the reading signal.
// Base on the cpu clock, the reading of ECG graph is running with cpu clock.
// It will variate will the system clock.
// Solution: By Bug#037, reading (TimeBase number of data per second by fbPrnFrame.
// The FFT calculation is more more stable and accurate.
//=========================================================
// Bug!!! Bug#037
// Before the method is just reading any data per second and to calculate FFT.
// The result is very very unstable and inaccurate.
//
// Fixed.
// Now is reading (TimeBase) number of data per second by fbPrnFrame.
// This fbPrnFrame is tmeECG operated per second.
// When tmeECG time on time, it will come to here to prepare a frame.
// Let say the iTimeBase = 384. It will read 384 number of data per second
// to prepare a chart for printing.
//=========================================================
// Bug!!! Bug#038
// fbMakeSpectrum add this condition(iWaveType <> iCaptureMode)
//=========================================================
// Bug!!! Bug#039
// Adding EOF a file ending number ‘1,’ and ‘-1’ to slData.
//=========================================================
// Bug!!! Bug#040
// Don’t put fbDoConnection into the applog
// LogAppErr(‘TAndroidChatManager.fbDoConnection: ‘ + E.classname, ‘general’, E.message);
//=========================================================
// Bug!!! Bug#041
// Comment: Num Point is using 16384 instead of 2048
// More accuracy and precise of Frequency and Amplitude!!!
// More accuracy and precise of Frequency and Amplitude!!!
// More accuracy and precise of Frequency and Amplitude!!!
// bpm is more precise and accuracy.
// giNumPoints : integer = 16384; //Instead of 2048, Number of Point of Chart Value
// giObsNumPoints : integer = 8192; //Instead of 1024, Half Number of Point of Chart Value
// giNumBufPoints : integer = 16384; //Instead of 3072, Is to define the Plot Graph Width.
//=========================================================
// Bug!!! Bug#042
// giNumPoints : integer = 8192;
// Number of Point of Chart Value. Default = 8192. [min 1024, 2048, 4096, 8192, 16384 max] // If using 16384 for giNumPoints, sound pitch output will have the distortion
//=========================================================
// Bug!!! Bug#043
// Check Android version below 4.4.x
// Set giNumPoints = 2048
// If Android version on or after 5.0
// Set giNumPoints = 4096
// If you want to set giNumPoints = 8192 or 16384, the sound frequency will have the distortion!!!
// If you want to set giNumPoints = 8192 or 16384, the sound frequency will have the distortion!!!
// If you want to set giNumPoints = 8192 or 16384, the sound frequency will have the distortion!!!
//=========================================================
// Bug!!! Bug#044
// Add 1 to iSTBufPoints for buffer. There is an exception for 4.4.2
//=========================================================
// Bug!!! Bug#045
// Need to add below code to control the lblTWA Visible at fbTAnalysis
// frmECG.lblTWA.Visible := frmECG.cbxZeroCross.IsChecked and frmECG.cbxMonitor.IsChecked;
//=========================================================
// Bug!!! Bug#046
// Comment:
// Now, put the dAllowLtd at the if condition check for Local Maxima R-Complex!!!
// dAllowance:= abs(dMaxima1 – dMaxima2)*dAllowLtd;
// dAllowLtd = 1.5 is good for QT Analysis
// dAllowLtd = 0.5 is good for RR Interval
//
// There is no significant difference to increase the value dAllowLtd2 = 1.5 to 3.
//
// These TWO if conditions is applied.
// The output RR-Interval and QT-Complex calculation are More More accurate!!!
// The output RR-Interval and QT-Complex calculation are More More accurate!!!
// The results are under expectation.
//
// There are TWO if conditions for Local Maxima
// (1) if (dDY0 <> 0) and (dDY1 <> 0) and (dDY2 <> 0) and (dMaxima1 <> 0) and (dMinima2 <> 0) and (not bMaxima) and
// (dDY0 < dDY1) and (dDY1 > dDY2) and (dDY1 > dMaxima1 – dAllowance*dAllowLtd1)
// (2) if (dDY0 <> 0) and (dDY1 <> 0) and (dDY2 <> 0) and (dMaxima1 <> 0) and (dMinima2 <> 0) and (not bMaxima) and
// (dDY0 < dDY1) and (dDY1 > dDY2) and (dDY1 > dMaxima1 – dAllowance*dAllowLtd2) then
//
// There are TWO if conditions for Local Mimima
// (1) if (dDY0 <> 0) and (dDY1 <> 0) and (dDY2 <> 0) and bMaxima and (dDY0 > dDY1) and (dDY1 < dDY2) and
// (iTrs1 < iTimeBase * dRTimeWidth) and //(iTimeBase * dRTimeWidth / 2 < iTrs1) and
// (dDY1 < dMaxima1 – dAmp + dAllowance*dAllowLtd2) and (dMaxima1 – dAmp – dAllowance*dAllowLtd2 < dDY1) then
// (2) if (dDY0 <> 0) and (dDY1 <> 0) and (dDY2 <> 0) and bMaxima and (dDY0 > dDY1) and (dDY1 < dDY2) and
// (iTrs1 < iTimeBase * dRTimeWidth) and //(iTimeBase * dRTimeWidth / 2 < iTrs1) and
// (dDY1 < dMaxima1 – dAmp + dAllowance*dAllowLtd1) and (dMaxima1 – dAmp – dAllowance*dAllowLtd1 < dDY1) then
//=========================================================
// Bug!!! Bug#047
// Need to re-test these two statements!!!
// Comment out these two lines. The Plot will run faster!!!
// ecgFastLine.Repaint;
// ecgChart.Invalidate;
//=========================================================
// Bug!!! Bug#048 Done
// Fixed FormVirtualKeyboardShown
// Keyboard is hiding the edit.text in Android
//
// Hard code. We don’t have better solution to get the virtual keyboard size Height and Width.
// Once we have the virtual keyboard size, we can relocate the select text or focus.
// Now, we just use screen size to recalculate the keyboard size.
//=========================================================
// Bug!!! Bug#049
// ‘Pause’ click
// We cannot stop the ecgMonitor to right away.
// We send a stop command to ecgMonitor. The internal thread is keep on running.
// ecgMonitor need to pause to process the stop command. This action not working properly!!!
//
// //Using fbBTCharacteristicWrite to send gsCMD to ECG Client
// if not BT4ChatClass.fbBTCharacteristicWrite(btLowEnergy,
// btDevice,
// sCMD,
// slLine,
// btGattCharacteristic,
// sErrMsg) then
// begin
// slLine.Add(sErrMsg);
// {$IFDEF ctrlBT_Log}
// LogAppErr(‘fbBTCharacteristicWrite’, ‘general’, sErrMsg+’ Error-1026′); //<— This exception
// is raised. The ecgMonitor client side cannot be stopped right away!!!
// The thread of the ecgMonitor client is still running!!!
// {$ENDIF}
// exit;
// end;
//
//=========================================================
// Bug!!! Bug#050
// We don’t use notification
// We use read characteristic and fbReceiveTimerEnabled again
//
// BluetoothLE notification cannot stop external by host.
// We cannot stop the ecgMonitor to right away. See Bug#049
//
// Using read characteristic and fbReceiveTimerEnabled, it can stop the the ecgMonitor client.
//=========================================================
// Bug!!! Bug#051
// Put the Application.ProcessMessages inside the cbxMonitor.
// The app will run faster in IOS!!!
//=========================================================
// Bug!!! Bug#052
// IOS is too slow if giObsNumPoints = 1024
// giObsNumPoints : integer = 1024; //Half Number of Point of Chart Value
// IOS is better if giObsNumPoints = 512
// giObsNumPoints : integer = 512; //Half Number of Point of Chart Value
//=========================================================
// Bug!!! Bug#053
// Set lblDTW.Text
// Show dDTW is outside the fbMonitor.
// If put dDTW inside the fbMonitor, there is some delay of the loop
//=========================================================
// Bug!!! Bug#054
// There is a bug TWebBrowser with TTabControl
// Setting the TWebBrowser.visible := true, the components in TTabControl in
// another page will lose control.
// Using TMSFMXWebBrowser, the bug is removed.
//
// Bug!!! Bug#088
// Now, we don’t use TTabControl to select a page. By using rectPageControl,
// there is no such Bug#054. TMSFMXWebBrowser will have another bug exception on OS 8.0.0 Samsung SM-G960W.
// When the user reconnect the charging cable, user will ask permission for data access.
// TMSFMXwebBrowser will popup at the same time as the permission request.
// This is a bug generated by the OS 8.0.0. It will popup the unwanted TMSFMXWebBrowser.
//
// Comment: We try to use TWebBrowser with rectPageControl. The page control is OK without problems.
// The is NO such popup webbrowser at another page When the user reconnect the charging cable,
// user will ask permission for data access.
//
// The TMSFMXWebBrowser library is removed from the project!!!
//=========================================================
// Bug!!! Bug#055 Version:1.0.9v167A107
// procedure TfrmECG.pcrUpdateKBBounds;
// procedure TfrmECG.FormVirtualKeyboardShown
// Fixed virtual keyboard of screen orientation in Android and IOS
//=========================================================
// Bug!!! Bug#056
//
// Beep frequency is right on FFT. Fixed.
// Beep frequency is wrong on ZeroCrossing. Fixed.
// fbSetLabel inside pcrPrnParameters is removed.
//
// HRV does not work on FFT. Fixed.
// HRV only work on ZeroCrossing Fixed.
// fbSetLabel inside pcrPrnParameters is removed.
//
// fbMakeSpectrum and fbZeroCrossFreq is re-write
// fbOptimizeFrequencyZERO is used to select the efrequency from fbMakeSpectrum and fbZeroCrossFreq
//=========================================================
// Bug!!! Bug#057
// Use printThd: TPrintThread to print ALL labels before in the main thread.
// Move all Label.text to fbPrintTimerOnTime
// Comment:
// Little bit smooth to redraw at the ecgChart with Monitor ON in Android.
//=========================================================
// Bug!!! Bug#058
// There are bug in epufrequency and epuAmplitude = 0;
// We need to use giDefaultFreq and giDefaultAmp when epufrequency and epuAmplitude = 0
// fbTimerOnTime <– Cannot bypass this code. // Finally, epufrequency = giDefaultFreq and epuAmplitude = giDefaultAmp // // Comment: // It will be running smooth to redraw at the ecgChart with Monitor ON in Android. // Minor bug fix on AlertAMP and AlertBMP //========================================================= // Bug!!! Bug#059 // For large ecg capture data, there will be missing the Capture Header. // We need to add the Capture Header to ecg Capture txt. //========================================================= // Bug!!! Bug#060 // Important!!! // BT4, there is a bug at tmrCHKStatusTimer gsCMDRDLeadStatus in Android // BluetoothLE, we cannot send command to client. // We cannot stop the ecgMonitor to right away. See Bug#049 //========================================================= // Bug!!! Bug#061 // There is a bug in fiGetNumBufPoints. // Firstly, read the ecg file. Secondly, start the capture. // There is a bug to define fiGetNumBufPoints. // It will raise an exception. //========================================================= // Bug!!! Bug#062 // There is a distortion of the wave form. // Cause: BT4 transmission limitation. // Solution: Increase the baud rate of the transmission from 115200 to 230400 baud. // Available and usable rate without distortion: 128, 256, 384, 512 sps // There is a distortion of the wave form. 640, 768, 896, 1024 and 1152 sps //========================================================= // Bug!!! Bug#063 // Enable ctrlDisplayCapture will raise exception during data capture. // Normal running, it MUST be disable ctrlDisplayCapture //========================================================= // Bug!!! Bug#064 // Minor bug fix at fiGetNumBufPoints // Adjustment of Author, Version and Copyright position // Detect iPad Mini 2. bpuiPad status to check for iPad4,4 //========================================================= // Bug!!! Bug#065 // iPhone Application Icon 180×180 use for first screen loading in iPad Mini 2 // The loading PNG is abnormally stretched!!! from 180×180 to 2048×1536. //========================================================= // Bug!!! Bug#066 // Fixed. Set UIDeviceFamily to iPad and iPhone. The black frame problem is solved. // There is black colour frame on iPad Mini 2. // Screen resolution is 1X Retina display. // We cannot stretch to maximize the screen size of the device. // Test run on iPad Air. There is NO such problems of black color frame on iPad Mini 2. //========================================================= // Bug!!! Bug#067 // There is an exception error on fbLinearLeastSquares divided by zero. // Introduce eM = 9.99 and eB = 9.99 constant to handle exception error. // HRT-Invalid, TO = 9.99 and TS = 9.99 will be displayed when there is an invalid data found. // // There is an exception error on fbSTAnalysis when eM = Infinity from fbLinearLeastSquares // Introduce eM = 9.99 constant to handle exception error. // We don’t tell outside that we have found the eSTSlope and bSTAboveZero. ie. bValidST = False //========================================================= // Bug!!! Bug#068 // Re-define fiGetNumBufPoints // Re-define iBufPoints // Stabilitiy Problem??? //========================================================= // Bug!!! Bug#069 // Fix missing LogAppErr in all functions and procedures // Check and fix the function which has a dividend by ZERO. // sprLoadFileName to load an ExtractFileName of Capture Data File //========================================================= // Bug!!! Bug#070 // If the last session is not closed properly, the apps will raise exception error // to start another session of BT4 data transmission. // We try to stop another session and force the user to close the apps and restart again. //========================================================= // Bug!!! Bug#071 // Minor bug fix on WiFi connection on LocationService, SMS and eMail. // There is an exception on fbLocationSensor1LocationChanged. This function is try to // connect with WiFi. We need to check the WiFi is whether connected or not before calling // fbLocationSensor1LocationChanged. // fbCheckWiFi is the function to check the WiFi connection via IdTCPClient. //========================================================= // Bug!!! Bug#072 // ‘No mapping for the Unicode character exists in the target multi-byte code page’ // Try to detect non unicode character by fbTestAnsiCompatible //========================================================= // Bug!!! Bug#073 // Add a phase change constant making the wave form moving forward. //========================================================= // Bug!!! Bug#074 // Set ecgChart.AutoRepaint = False will not repaint ecgChart //========================================================= // Bug!!! Bug#075 // Output efrequency of fbZeroCrossFreq is a discrete function. // Output efrequency is like a pulse. Once fbZeroCrossFreq determined a frequency, // it will output result frequency. Otherwise it will back to zero frequency. // // Whereas, FFT is a continuous function. The output frequency is a continuous function. //========================================================= // Bug!!! Bug#076 // (Description: 1.0.0.16) // Minor bug fix at pcrSetBT4HeartMode //========================================================= // Bug!!! Bug#077 // (Description: 1.0.0.17) // Minor bug fix at pcrParserBytes / bpu1stPlot //========================================================= // Bug!!! Bug#078 // (Description: 1.0.0.18) // Fix invalid flowing point operation error at fbLinearLeastSquares //========================================================= // Bug!!! Bug#079 // (Description: 1.0.0.19) // 1) Minor bug fix if Inverted T-Wave Found // 2) Change the priority of ‘File’ and ‘Setup’ at tctlDevices // 3) Add guide after scanning of bt4ECGEndDiscoverDevices //========================================================= // Bug!!! Bug#080 // (See Description 1.0.0.20) // 1) Minor bug fix in Android with small screen resolution 640×335 // The size of ‘Location’ rectTabLocation is misalignment. //========================================================= // Bug!!! Bug#081 // (See Description 1.0.0.21) // 1) TPrintThread, the Thread Interval is less than giPRNInterval, // the apps will use or waste more cpu time on thread. // 2) Set iBufPoints := 0 and rectWaiting.Visible:= False. // Old Android CPU will use less CPU time to load the BT data at start // 3) Check valid bpm in which iprIndexZC > (PlotClass.fiECGTimeBase(gsCMD) * giValidBPMTime)
// If iprIndexZC greater than certain time (PlotClass.fiECGTimeBase(gsCMD) * giValidBPMTime),
// there is NO new eFrequency found.
// This means no new updated eFrequency and eFrequency is below < gdFreqThreshold. // // The longer is giValidBPMTime. The longer is the waiting time // to have another valid BPM frequency found. // Drawback! The time of BPM appeared when there have NOT found another new frequency. // // Using giValidBPMTime_Freq and giValidBPMTime_ZC to check the ValidBPMTime interval // will have a better delay and respond time of BPS. // // After (giValidBPMTime_Freq) 3s with NO new frequency found, it will trigger to use giDefaultFreq // After (giValidBPMTime_ZC) 10s with NO new frequency found, it will trigger to reset iprIndexZC := 0; // 4) If the frequency BPS is greater than (eRate > giBPMLowLimit/60),
// check eRate is higher than giFreqInterval.
// 5) ProgressBar has a bug in 4.XX. It does not working properly in loading data!!!
// Solution:
// Check Android with OS 4.XX. There is NO beep sound when there Zero BPS or 888 BPS.
// Other OS. There will be a beep sound when there Zero BPS or 888 BPS.
//=========================================================
// Bug!!! Bug#082
// Resolution and Distortion
//
// Distortion Comment: BT4 / HM05 / HM10 ONLY
// ECG wave form distortion is due to the BT4 receiving error or limitation.
// This BT4 limitation is coming from the hardware properties of data transmission
// of notification event. The notification (receiving) event is handled by the
// hardware of BT4. The Delphi has no control of the notification event.
//
// The ecg unit is sending the higher baud (512 sps or higher) of data to the
// host computer. The Delphi cannot entertain or manipulate the incoming data by
// the notification event.
//
// Android BT2 / HC06
// The incoming data is handled by the interval of TReceiveThread which is set at giReceiveInterval.
// Delphi can handle or control the interval of TReceiveThread. The higher baud rate receives the
// data, the lower giReceiveInterval to receive the data in ecg HOST computer.
//
// The ecgBT unit (Firmware) is tested with difference baud rate setting.
// The higher baud rate is working properly.
// The Delphi BT4 notification event cannot handle properly with higher baud rate.
//=========================================================
// Bug!!! Bug#083
// Android BT5 Test, Result and Solution
// (See Description 1.0.0.22)
//
// Android (BT5 HM10): Support 128, 256, 300 sps (No Distortion)
// (BT5 HM05): 128, 256, 384, 512 sps (No Distortion) in Samsung SW-G960W
// (BT5 HM05): 128, 256, 384 sps (No Distortion) in iPad and iPhone OS 9.3 to 11.4
// (BT5 HM05): 128, 256, 384 sps (Rare Distortion) in Android for slow machine.
//
// Test on HM10:
// Samsung S9, SM-G960W, OS 8.0.0, Octa-core (4×2.7 GHz Mongoose M3 & 4×1.8 GHz Cortex-A55) is tested.
// It is running on BT5. There is a distortion on 384 sps resolution. It has about 20% data lost on transmission.
// We add the resolution 100, 200 & 300 sps to the choice. 300 sps is the highest in BT5 without distortion.
//
// Test on HM05:
// There is NO such bug in HM05. (No Distortion) in Samsung SW-G960W.
// It is also No Distortion in Samsung SW-G960W at 512 sps!!!
//
// In the client side AD7680, the firmware are also added resolution 100, 200 & 300 sps.
//=========================================================
// Bug!!! Bug#084
// (See Description 1.0.0.23)
// Screen size and font adjustment on pnlStatus
// Set Android User Permission
//=========================================================
// Bug!!! Bug#085
// (See Description 1.0.0.26)
// Samsung Galaxy Note Edge show the invalid HRV.
// Add else to bValidFreq
// If the bValidFreq is invalid, eZCLastFreq and eZCLastAmp = 0
//=========================================================
// Bug!!! Bug#086
// (See Description 1.0.0.27)
// Add ; to OSX directive to DPF.iOS.Common
//=========================================================
// Bug!!! Bug#087
// (See Description 1.0.0.29)
// There is a bug after adding rectPageControl.
// Adding frmResize to btnStartClick activate this function call.
// echChart.Height will be validated again with frmResize call.
//=========================================================
// Bug!!! Bug#088
// Please refer to Bug#054
//=========================================================
// Bug!!! Bug#089
// There is a technical issue of HM05 and HM10 BLE module.
// There is a bug in HM10. The module will have a big distortion on the wave form at 384sps or above.
// There is NO such bug in HM05. The module can run at the steady speed to 512sps in Samsung SW-G960W.
// It is also No Distortion in Samsung SW-G960W at 512 sps!!!
// In IOS, there is NO difference of the speed. The module can run at the steady speed to 384sps.
//=========================================================
// Bug!!! Bug#090
// There is a bug in Nexus 7 (Only my developer Android Tablet). It is CRASH and CORRUPT FILES!!!
// The package name = ‘com.pqrst.ca’,
// The files error is in the system directory > Android > Data > com.pqrst.ca > files > ‘app.log and ecgFile.ini’.
// ‘app.log and ecgFile.ini’ cannot be removed!!!
//
// We can try to change the ‘app.log and ecgFile.ini’ to ‘apps.log and ecgFile.ini’
// We can use ‘com.pqrst.$(ModuleName)’ or other name ‘com.PQRST.ca’ (Case Sensitive). The problem will be solved.
// Android debug version package name = ‘com.pqrst.$(ModuleName).debug’ or ‘com.PQRST.ca’ …
// Android release version package name = ‘com.pqrst.$(ModuleName)’ or ‘com.pqrst.ca’ …
//=========================================================
// Bug!!! Bug#091
// Minor Bug fix at swZeroCrossClick. Add pcrSetupHRMonitor to event click.
//=========================================================
// Bug!!! Bug#092
// IOS Cannot start the BT connection automatically!!!
// Abdroid start BT connection – OK.
// It is better let the user to activate from drop down list!!!
//=========================================================
// Bug!!! Bug#093
// BT5 cannot search Bluetooth device if the location have too many Bluetooth transmitter source.
//=========================================================
// Bug!!! Bug#094
// For RIO1030:-
// ecgWebBrowser/TWebBrowser will raise up exception with TForm.
// frmECG.BorderStyle := TFmxFormBorderStyle.None will crash with the TForm!!!
// Solution: frmECG.BorderStyle := TFmxFormBorderStyle.Sizeable; <<< This one must be worked in MSWINDOWS!!!
// Solution: frmECG.BorderStyle := TFmxFormBorderStyle.NONE; <<< This one must be worked for OTHER OS!!!
// For Toyko1023:-
// Solution: frmECG.BorderStyle := TFmxFormBorderStyle.NONE; <<< This one must be worked for ALL OS!!!
//=========================================================
// Bug!!! Bug#095
// 1023-v1-AndroidSDK25.2.5_32bit.sdk is working sdk in delphi 1023!!!
// C:\Users\Public\Documents\Embarcadero\Studio\20.0\PlatformSDKs\android-sdk-windows where 20.0 is working!!!
// C:\Users\Public\Documents\Embarcadero\Studio\17.0\PlatformSDKs\android-ndk-r9c where 17.0 is working!!!
// C:\Program Files\Java\jdk1.7.0_71\bin\keytool.exe is working!!!
//
// Comment: C:\Users\Public\Documents\Embarcadero\Studio\20.0\PlatformSDKs\android-ndk-r17b is NOT working!!!
// It only works in Delphi 10.3!!! It does NOT working in 10.2.3!!!
//
// 1030-AndroidSDK25.2.5_32bit.sdk is working sdk in delphi 1030!!!
// C:\Users\Public\Documents\Embarcadero\Studio\20.0\PlatformSDKs\android-sdk-windows where 20.0 is working!!!
// C:\Users\Public\Documents\Embarcadero\Studio\20.0\PlatformSDKs\android-ndk-r17b where 20.0 is working!!!
// C:\Program Files\Java\jdk1.7.0_71\bin\keytool.exe is working!!!
//=========================================================
// Bug!!! Bug#096
// TWebBrowser has a bug!!!
// Status: Bug Fixed
// RIO1030 uLocation.pas/TWebBrowser/ecgWebBrowser does NOT work in RIO1030!!!
// Toyko1023 uLocation.pas/TWebBrowser/ecgWebBrowser WORK in Toyko1023!!!
//
// https://quality.embarcadero.com/browse/RSP-21834
// Comment out the below statement. IOSSensor problem will be fixed on triggering OnLocationChanged event.
// [MethodName(‘locationManager:didUpdateLocations:’)] // The problem can be worked around by copying the unit to the project folder, and commenting out line 151
// (the MethodName attribute for locationManagerDidUpdateLocations)
// Just copy the file from C:\Program Files (x86)\Embarcadero\Studio\20.0\source\rtl\common\System.iOS.Sensors.pas,
// to the folder your project is in.
//=========================================================
// Bug!!! Bug#097
// Solution: WORKED from Dave N, DelphiWorlds
// Status: Bug Fixed
//
// TWebBrowser has a bug in RIO1030!!!
// There is no problems in Tokyo1023!!!
// Align: Client in Samsung S9 NOT work after minimize!!!
//
// Comment: Detect on Samsung S8 & S9 making Align: FitLeft
//=========================================================
// Bug!!! Bug#098
// Android version
// After certain time the apps will be killed by the OS of Android,
// if the user switch off the screen after certain time.
// Killing apps time is depending on setting arround 5-10 minutes.
// =============================
// Attention: PARTIAL_WAKE_LOCK
// It doesn’t work!!! with any combination with IgnoringBatteryOptimization.
// Android will kill the background apps after API 26.
// We only use JavaClass.FLAG_KEEP_SCREEN_ON to enable the CPU and Screen on.
// =============================
//
// IOS Version
// There is no such issue the apps will be killed by the IOS.
//
// User Permission: WakeLock on and Androidapi.JNI.PowerManager to solve the issue.
// Keeping the Android CPU running in the background when screen is OFF.
// Android: pcrIgnoringBatteryOptimization is added to prevent ‘Battery Optimization / Doze Mode’
// https://developer.zebra.com/community/home/blog/2018/10/26/keeping-your-application-running-when-the-device-wants-to-sleep
//
// Mode: PARTIAL_WAKE_LOCK
//
// Reference: [How to prevent FireMonkey app / service stop working while in background?] // https://stackoverflow.com/questions/52504808/how-to-prevent-firemonkey-app-service-stop-working-while-in-background
//
// [Guide to background processing] // https://developer.android.com/guide/background#js
//
// [how to keep app running when screen off?] // https://stackoverflow.com/questions/44743265/how-to-keep-app-running-when-screen-off-or-open-another-app
//
// [Delphi XE5 Android. How to use PowerManager.WakeLock?] // https://stackoverflow.com/questions/19021647/delphi-xe5-android-how-to-use-powermanager-wakelock
//
// [How to keep an Activity running while screen off?] // https://stackoverflow.com/questions/11978742/how-to-keep-an-activity-running-while-screen-off
//
// [PowerManager] // https://developer.android.com/reference/android/os/PowerManager
//
// [GlassLevel example by Embarcardero] // is using wake lock to keep the apps continue running in background
//
// [Optimize for Doze and App Standby] // https://developer.android.com/training/monitoring-device-state/doze-standby
//
// Comment:
// There are few solutions to solve this problems by ‘Background Processing’.
// DownloadManager, sync adapter, JobScheduler, Firebase Cloud Messaging and Wake Lock.
// Please See ‘Modified: 16 Mar 2019 10:00:00 PM’
//=========================================================
// Bug!!! Bug#099
// Android version
// There is a bug when the Wake Lock acquire at the frmCreate.
// Once the user wake up the system, it will go through below statement and release the wake lock.
// TApplicationEvent.WillBecomeInactive : pcrRelease_WakeLock(jprWakeLock);
// If the user keep on/off the power button, the apps will pass through WillBecomeInactive.
// Release_WakeLock will be release.
//
// Therefore, the apps sometime work and sometime NOT work of the wake lock particularly
// at the long sleeping!!! The apps will be killed by the system when background running.
//
// Comment: We try to remove the pcrRelease_WakeLock when the app is still running
// for long time and wake up by user by press power button.
// Solution: Finally, it is working!!! Testing about 5hr long sleeping, it is working!!!
//=========================================================
// Bug!!! Bug#100
// IOS for iPhone
// There is a bug “Cannot begin rendering scene for ‘TContextIOS'”.
// When the TForm change the exception will be raised.
//
// Comment:
// 1) Try to include FMX.Context.GLES.IOS.pas in the project.
// 2) rectPageAbout, rectPageBT4Chat, rectPageBTChat, rectTabECGMonitorClick & rectPageLocation
// there will be pcrSetLandscapeOrientation with NO pcrSetALLOrientation.
// 3) rectPageSetup, rectPageFile & rectPageTheme
// there will be pcrSetALLOrientation instead.
//=========================================================
// Bug!!! Bug#101
// Solution: WORKED from Dave N, DelphiWorlds
// Status: Bug Fixed
//
// For Samsung S9, Change Orientation is not work on Location Page!!!
// For Android, All Orientation is work. But Landscape and Inverted Landscape are not worked.
// Bug!!! Bug#097
//
// TWebBrowser has a bug in RIO1030!!!
// There is no problems in Tokyo1023!!!
//
// Solution: WORKED from Dave N, DelphiWorlds
//=============================
// Tokyo1023
// FMX.FORMS is NOT added.
// RIO1030
// FMX.FORMS is added to the project folder ‘ECG Bluetooth App’.
// Rename ‘1030FMX.Forms.pas’ to ‘FMX.Forms.pas’ when project compiled in RIO1030.
//=============================
//
// Comment:
// 1) Try to include FMX.Context.GLES.IOS.pas in the project.
// 2) rectPageAbout, rectPageBT4Chat, rectPageBTChat, rectTabECGMonitorClick & rectPageLocation
// there will be pcrSetLandscapeOrientation with NO pcrSetALLOrientation.
// 3) rectPageSetup, rectPageFile & rectPageTheme
// there will be pcrSetALLOrientation instead.
//=========================================================
// Bug!!! Bug#102
// OLD library of U_FFT.pas from Pascal has error on REALFFT2.
// It will crash with ‘Doze’ mode in Android 8.0 or above.
// It must be Keep_Screen_ON to let the apps run.
// Issue: The client let Android to sleep or go to ‘Doze’ mode,
// sleeping for long time without activities, the app will crach when switch on again.
// The bug is at the REALFFT2 library.
//
// Solution: Using fbFourierTransform from fourier.pas – Don Cross <dcross@intersrv.com>
// http://www.intersrv.com/~dcross/fft.html#pascal
// or
// https://github.com/neurolabusc/MRIcron
//
// Function fbFourierTransform is rewriten to replace the REALFFT2.
// There is an error of calculate the daAmps[i] amplitude array after using fbFourierTransform.
// daAmps[i] := eAmplitude/sqrt(iNBRPoints); //<<<< After using fbFourierTransform, here need to divide sqrt(iNBRPoints);
//=========================================================
// Bug!!! Bug#103
// lblBatOpt.Text:= FormatDateTime(‘hh:nn:ss’, tmrBatOpt.Tag / SecsPerDay);
//=========================================================
// Important Notes:-
// To reinstall the apps with the newer version:-
// 1) Goto storage to clear the data and/or clear the cached data.
//
// 2) For ‘Release Version’
// All system folder: Android,
// IOSDevice32,
// IOSDevice64,
// IOSSimulator,
// OSX32,
// Win32,
// Win64
// We need to delete all the above folders and rebuild a clean apps!!!
// We need to delete all the above folders and rebuild a clean apps!!!
// We need to delete all the above folders and rebuild a clean apps!!!
//
// Comment: iPad Mini 2 test run: This machine does not support ‘UIBackgroundModes’.
// When the iPad switch off and the system will kill all the apps running
// in the background. The apps will restart after coming back.
//=========================================================
// Alpha Test
// Comment: All TApplicationEvent are Original. PARTIAL_WAKE_LOCK and Default Screen ON
//
// v1.0.0.A – Apply DelphiWorld RestartIfNotIgnoringBatteryOptimizations.
// Optimize the code in fbMakeSpectrum and fbQuadratic
// v1.0.0.F – FFT Don Cross – Fast Fourier Transformation / Fourier.pas
// MUST RESET Android!!!
// v1.0.0.2 – kastri updated library, move to H:\Project\ECG Bluetooth Project\ECG Bluetooth App\AndroidManifest.template.xml
// v1.0.0.3 – Delete and cleanup unnecessary files in project folder.
// Verify Kastri library
// AndroidManifest.template.xml //
//
//
// v1.0.0.4 – AndroidManifest.template.xml //
// android:allowTaskReparenting=”true”
// android:launchMode=”standard”
// v1.0.0.5 – Apply Band Pass Filter after (Fast Fourier Transformation) fbFourierTransform to make the iteration faster.
// Apply Band Pass Filter for frequency = 0.5Hz to 360Hz = 30 bpm to 360 bpm
// AndroidManifest.template.xml //
// android:allowTaskReparenting=”true” //Remove this statement
// android:launchMode=”standard” //Change this statement back to “singleTask”
// The Doze mode bug may be here below!!!
// There is unnecessary to check this statement here. For loop is a band pass filter!!!
// if ((daFreqs[i] <= iBPMHighLimit*cdDiv60) and (daFreqs[i] >= iBPMLowLimit*cdDiv60)) then
// v1.0.0.6 – Remove READ_PHONE_STATUS in AndroidManifest.Template.xml
// Modified Label lblScreenCtrl for gsHighPerformanceMode, gsLowBatteryMode1 & gsLowBatteryMode2
// v1.0.0.7 – Modified: 17 May 2019 01:00:00 AM
// Disable below functions: for Android and IOS!!!
// They are not the MAJOR functions. Otherwise, Google and Apple will ban or not allow to publish the app.
// 1) READ_SMS and SEND_SMS
// 2) CALL_PHONE
// 3) Email
// 4) REQUEST_IGNORE_BATTERY_OPTIMIZATIONS and WAKE_LOCK
// Google Play will not approve the above function. They will ban or subspend the account!!!
// Change the Splash Screen accordingly.
// Permission ‘ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION’ must declare!!!
// https://developer.android.com/guide/topics/connectivity/bluetooth
//
// For Android, (Permission – External Storage, Bluetooth and Access_Coarse_Location)
// We don’t ask for user permission in AndroidManifest.template.xml make it easier to approve by Google!!!
// They are not the major function of the app. Google will challenge why the app need these permission.
// Google is very stict on Doze and Standby Mode and dangerous permissions.
//
//
//
//
//
//
//
// For IOS, (Permission – Bluetooth)
// Just ask for user permission on ‘Bluetooth’. ‘External Storage and ACCESS_FINE_LOCATION’ are not necessary.
//
// SMS, Call Phone, Location, Doze and Standby Mode functions are removed!!!
// For the privacy concern, Google and Apple will not easily approve the permissions!!!
//
// For Android, Screen Ctrl – Keep Screen On/Allow to do any activities until press ‘Power’ button.
// – Keep Screen Off/Single App/Can last for more than 4 hrs
// For IOS, Screen Ctrl – Keep Screen On/Allow to do any activities/No such issue!!!
// – Keep Screen Off/Allow to do any activities/No such issue!!!
// Default: KEEP_SCREEN_OFF. Keep Screen On will draw so many battery!
// v1.0.7.1 – Modified: 07 Jun 2019 07:00:00 AM
// Minor bug fix on lblBatOpt format hh:nn:ss
//=========================================================
// Testing: Apps ecgMonitor v1.0.0.5.apk
//
// Model Options Doze Mode/Sleep Resolution Result Status
// Samsung S9 FFT+ZeroCross+ScreenON Always WakeUP 256sps Any Activity OK
//
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 1Hr+NO Activity 256sps ?
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 2Hr+NO Activity 256sps ?
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 3Hr+NO Activity 256sps ?
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 4Hr+NO Activity+NO Power 256sps XXX
//
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 1Hr+NO Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 2Hr+With Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 3Hr+with Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 4Hr+with Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 5Hr+with Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 6Hr+with Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 7Hr+with Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 8Hr+with Activity+NO Power 128sps OK
// Samsung S9 FFT+ZeroCross+ScreenAutoOFF 9Hr+with Activity+NO Power 128sps OK
//
// Comment:
// with Activity = background with two or more games, wifi phone calling, browsing, camera photo activities…etc.
// NO Power = usb power cable is unplug.
//=========================================================

 
 
 
 
 

Hardware Revision

//=========================================================
// Hardware Revision
//=========================================================
// 1st prototype of ECG Monitor
// ADS8866 ADC converter is deleted.
// BT2 is used for communication with Android.
//=========================================================
// 2nd prototype of ECG Monitor
// BT2 is used for communication with Android.
// 50Hz/60Hz Notch Filter are added to filter out the noise from AC.
// MAX4624 is used for control and is deleted.
//=========================================================
// 3rd prototype of ECG Monitor
// BT4 is used for communication with Android.
//=========================================================
// 4th prototype of ECG Monitor
// BT4 is used for communication with Android and iPhone
// Add USB power charging unit.
// Re-design the hardware layout.
//=========================================================
// 5th prototype of ECG Monitor
// Re-design the hardware layout and minimize the size of the case.
// Use 0.6mm pcb for the manufacturing.
// Checking the layout for the Surface Mount Technology.
//=========================================================

 
 
 
 
 

Firmware Revision

//=========================================================
// THREE modes of  Heart Rate Monitor
//=========================================================
// Description:
// There are three modes of Heart Rate Monitor.
//
// Function:
// Mode 1: ECG Waveform Monitoring
// Mode 2: Heart Rate Measurement Next to Heart
// Mode 3: HEART RATE MEASUREMENT AT HANDS (Trial Mode)
//
//=========================================================
// Mode 1: ECG Waveform Monitoring
//=========================================================
// This configuration is designed for monitoring the shape
// of the ECG waveform. It assumes that the patient remains
// relatively still during the measurement, and therefore,
// motion artifacts are less of an issue.
//
// To obtain an ECG waveform with minimal distortion, the
// AD8232 is configured with a 0.5 Hz two-pole high-pass
// filter followed by a two-pole, 40 Hz, low-pass filter.
// A third electrode is driven for optimum common-mode
// rejection.
//
// In addition to 40 Hz filtering, the op amp stage
// is configured for a gain of 11, resulting in a
// total system gain of 1100.
//=========================================================
// Mode 2: HEART RATE MEASUREMENT NEXT TO THE HEART
//=========================================================
// For wearable exercise devices, the AD8232 is typically
// placed in a pod near the heart. The two sense electrodes
// are placed under-neath the pectoral muscles; no driven
// electrode is used. Because the distance from the heart
// to the AD8232 is small, the heart signal is strong and
// there is less muscle artifact interference.
//
// To obtain an ECG waveform with minimal distortion, the
// AD8232 is configured with a 0.5 Hz two-pole high-pass
// filter followed by a two-pole, 40 Hz, low-pass filter.
// No gain is used on the output op amp.
// Total system gain is 100.
//=========================================================
// Mode 3: HEART RATE MEASUREMENT AT HANDS (Trial Mode)
//=========================================================
// The heart rate signal is measured at the hands with
// stainless steel electrodes. The user’s arm and upper body
// movement create large motion artifacts and the long lead
// length makes the system susceptible to common-mode
// interference.
//
// To obtain an ECG waveform with minimal distortion, the
// AD8232 is configured with a 0.5 Hz two-pole high-pass
// filter followed by a two-pole, 40 Hz, low-pass filter.
//
// In addition to 40 Hz filtering, the op amp stage
// is configured for a gain of 11, resulting in a
// total system gain of 1100.
//=========================================================
//=========================================================
// Heart Mode
// There are two electrode underneath the equipment. User can place the equipment next to your heart
// to carry out the ecg monitor function.
// BUT there is NO detection of two electrodes which is connected or disconnected with the user body of the heart.
//
// Comparsion with Cardiac Mode.
// There is a detection of two electrodes which is connected or disconnected with the user body of the heart.
// There will have an indications of the connection with the user body.
//=========================================================
//=========================================================
//=========================================================
// COMMENT: Cardiac Mode & Heart Mode
// There is NO significant difference between Cardiac Mode & Heart Mode in hardware.
// Two units of MAX4626 switches are deleted. Now, the firmware of Cardiac Mode & Heart Mode are the same.
// Even though the instruction CMD command ?a and ?b is to change the PD3 and PD7 logic. Actually, there
// is NO change of the hardware of AD8232. It only config as Cardiac Mode with gain = 1100.
//
// LO+ and LO- are connected to CPU port PD5 and PD6. Software detection algorithm is used to detect the LO+ and LO-.
// In Cardiac Mode, it will detect the connectivity of LA and RA electrodes to the body.
// In Heart Mode, LO+ and LO- are disable by software. The two electrodes are directly connected to the body
// next to the heart.
//=========================================================

 
 
 
 
 

Mechanical Design Revision

//=========================================================
// Mechanical Design Revision
//=========================================================
// Description: CAD design
//=========================================================
// 1st prototype of ECG Monitor
// Use 18650 6000mAh Li-ion 3.7v Battery.
// Use external usb power charging unit.
// Generate the STL file for 3D printing.
//=========================================================
// 2nd prototype of ECG Monitor
// Use PN523450 1000mAh Li-ion 3.7v Battery.
// Rebuild usb power charging unit.
// Generate the STL file for 3D printing.
//=========================================================
// 3rd prototype of ECG Monitor
// Re-design 0.6mm PCB for manufacturing.
// Build the firmware programmer for the ECG Monitor.
// Generate the STL file for 3D printing.
//=========================================================
// 4th prototype of ECG Monitor
// Re-design elastic belt and clip to hold the ECG Monitor.
// Re-design the ECG Monitor case.
// Generate the STL file for 3D printing.
//=========================================================
// 5th prototype of ECG Monitor
// Re-design elastic belt and clip to hold the ECG Monitor.
// Re-design the ECG Monitor case.
// Generate the STL file for 3D printing.
//=========================================================
// 6th prototype of ECG Monitor
// Re-design elastic belt and clip to hold the ECG Monitor.
// Re-design the ECG Monitor case.
// Generate the STL file for 3D printing.
//=========================================================