SYSTEM AND METHOD FOR GENERATING AND TRANSFERRING DATA
BACKGROUND OF THE INVENTION This invention relates generally to systems and methods for generating and transferring medical and other data. A specific implementation includes a remote heart monitoring method.
Many industries use real-time information, but the medical field is one in which such information is particularly critical. In hospitals, for example, patients may have their biological functions or conditions continuously monitored so that any significant change can be immediately detected and addressed by appropriate personnel. Such monitoring includes generating the information and transferring it to where it is to be used.
United States Patent No. 5,481,255 to Albert et al. discloses transmitting medical data, for example, through a paging network to a pager receiver connected to a computer, such as a palmtop computer held by a physician. In one example, a patient is connected to an electrocardiogram (ECG) machine to generate ECG information that is processed and transmitted through the paging network to the receiver and attached computer.
United States Patent No. 5,735,285 to Albert et al. discloses another communication system for conveying ECG data or other biomedical waveform data between a patient and an attending physician's location. The patient employs a HEART CARD™ device from Instromedix, Inc., or the like, which converts the patient's ECG signal into a frequency modulated audio signal that may then be analyzed by audio inputting via a telephone system to a selected hand-held computer device with integrated microphone and audio system. The computer device functions to digitize, record and demodulate the frequency modulated signal for presentation and viewing on the hand-held computer. The audio signal can also be input directly into a personal computer (PC) via a standard personal computer microphone. The audio signal can be input directly into a PC through a phone line connection via a standard "voice-capable" modem, for example. The stored ECG audio signal can be retransmitted via telephone, either wireline or wireless. At a receiving end, a programmed hand-held computer can be used to receive the audio FM biomedical signal for digitization, recording and demodulation for viewing. Such computer can be one with integrated microphone, audio analog to digital converter, digital to analog converter, speaker, and central processing unit with memory for performing various computational, data storage and signal processing tasks.
Despite previously disclosed or implemented systems, there is still the need for a novel and improved system and method for generating and transferring medical (or other) data, especially a system and method which enable a patient to communicate with a medical care provider in real time virtually from anywhere. Preferably such a system and method should be able to communicate globally, such as via the Internet. Such a system and method should be inexpensive, simple, and easy-to-use. This includes use of a computer without having to purchase or manually install a specialized computer application program or any special hardware. Such system and method should be relatively inexpensive both for the patient or other input user and the medical care provider or other recipient to use (e.g., minimal equipment requirements, no long distance telephone tolls). Such system and method should quickly (ideally, in real time) provide accurate data from the input user to the recipient.
SUMMARY OF THE INVENTION The present invention meets the aforementioned needs by providing a novel and improved system and method for generating and transferring medical and other data. For example, the system and method permit the monitoring of biological functions and conditions of a plurality of patients and the reporting of the resulting data to respective medical care providers. In a particular implementation, the present invention provides for remote heart monitoring. In a preferred embodiment, a device that can be manipulated by a patient senses some function or condition of the patient. One example is a small, inexpensive, hand-held heart monitor that a patient can hold against his or her chest; when used, the device outputs an audible signal responsive to the beating of the heart, such as the electrocardiogram. A computer that can be operated by the patient runs a program that processes an electric signal generated in response to the audible signal as received through a microphone connected to the computer. The computer can send resulting data signals over a computer communication network and preferably over a global communication network such as the Internet. Using a plurality of the foregoing components, any number of patients that can access the computer communication network can quickly, easily, inexpensively, and accurately provide real-time information about their personal medical condition to their personal medical care providers. The real-time information can also be used locally such as by the individual during exercise or simply while trying to monitor or modulate the sensed condition (e.g., to lower heart rate, blood pressure, or stress).
One definition of the system for generating and transferring medical data of the present invention comprises: means for sensing a biological function or condition; and means, communicating with the means for sensing, for transferring a response to the sensed biological function or condition over the Internet. In accordance with another definition of the present invention, the system comprises a sensor used by a human user to sense a function or condition of the user's body. It also comprises a personal computer located with the sensor. The personal computer has a microphone connector and analog to digital conversion means which are communicated with the sensor such that a digital processing circuit of the personal computer receives from the analog to digital conversion means a digital electric signal derived from an analog electric signal received through the microphone connector in response to the user's body function or condition sensed by the sensor. The personal computer is programmed to transfer data representative of the received digital electric signal over a computer communication network contemporaneously with the sensor sensing the user's body function or condition. This system can further comprise a recipient computer located at a medical facility and connected to communicate with the computer communication network, wherein the recipient computer is programmed to receive the data transferred over the computer communication network and to provide a visible representation of the sensed body function or condition and to store the data in a searchable database. The system can comprise a recipient computer located at a data communication service provider facility and connected to communicate with the computer communication network, wherein the recipient computer is programmed to receive the data transferred over the computer communication network and to transmit in response thereto another signal to an end user. Still another definition of the present invention for a system for generating and transferring medical data comprises: a sensor to provide an acoustical signal in simultaneous response to a biological function or condition; a microphone, located with the sensor, to receive the acoustical signal as the acoustical signal is provided from the sensor; and a computer connected to the microphone and adapted to transfer over the Internet, in real-time response to the microphone receiving the acoustical signal, electric signals representative of the received acoustical signal. In one embodiment the computer includes a personal computer programmed with a web browser and a medical data
acquisition and transmission program. The medical data acquisition and transmission program can be downloaded from an Internet site accessed using the web browser.
The system of the present invention can also be defined without limitation as to type of data, such as to comprise: a plurality of initial user sites, each of the initial user sites having a data generating source and a computer connected to receive signals from the data generating source and to access the Internet; and an Internet site addressable from each of the plurality of initial user sites such that each initial user site can access a data acquisition and transmission program through the Internet site to enable the respective computer to process received signals from the respective data generating source and transmit responsive signals over the Internet. Each initial user site preferably can transmit simultaneously over the Internet to one or more recipient sites. Also, the receiving computer at a recipient site can receive and display in real time the signals from one or a multiple number of initial user sites.
A method of generating and transferring medical data in accordance with an aspect of the present invention comprises: transducing directly from a patient a human body function or condition into a first signal; converting at the site of the patient the first signal into a second signal adapted for transmission over the Internet; and transmitting the second signal over the Internet to a recipient. In one implementation the method further comprises performing the transducing, converting, and transmitting contemporaneously; and contemporaneously therewith generating at the recipient a display in response to the transmitted second signal, wherein the display is a real-time representation of the transduced human body function or condition.
A method of generating and transferring data in accordance with the present invention comprises: accessing an Internet site from a computer where a data generating source is located; downloading to the computer from the accessed Internet site a data acquisition and transmission program; and operating the computer with the downloaded data acquisition and transmission program such that the computer receives signals from the data generating source, processes the received signals, and transmits data signals onto the Internet in response thereto. In particular implementations, the downloaded program may or may not operate unless the computer is connected to the specific web site on the Internet from which the program was obtained.
A method of the present invention for generating medical data representative of a biological function or condition of an individual comprises:
(a) accessing an Internet site with a personal computer located with the individual, wherein the personal computer is programmed with a conventional operating program;
(b) downloading from the accessed Internet site to the personal computer a medical data acquisition program automatically operable with the conventional operating program;
(c) generating an acoustical signal in response to the biological function or condition of the individual;
(d) receiving the acoustical signal in a microphone near the individual and converting with the microphone the received acoustical signal into an analog electric signal;
(e) communicating the analog electric signal from the microphone to an analog to digital conversion circuit of the personal computer and converting thereby the analog electric signal to a digital electric signal;
(f) processing the digital electric signal in the personal computer under control of the medical data acquisition program; and
(g) displaying to the individual, through the personal computer, a representation of the individual's biological function or condition in response to which the acoustical signal was generated.
As a step (h), responsive data can be transmitted over the Internet to other sites for storage and review. From such other site or sites, for example, data can then be transmitted over a paging or other wireless network to a physician, for example. In a preferred embodiment, at least steps (c) through (h) are performed together in real time. Still another definition of a method of monitoring biological functions and conditions of a plurality of patients in accordance with the present invention comprises: distributing to each patient at least one sensor to detect at least one biological function or condition of the patient; and maintaining a medical data acquisition and transmission program at an Internet site accessible by the patients such that the patients can use, from computers at the locations of the patients, the medical data acquisition and transmission program to control their respective computers to receive and process signals from the patients' respective sensors and to transmit medical data onto the Internet in response thereto. This method can further comprise distributing to a plurality of physicians
receivers (with or without transmitting capability) for receiving at least portions of the medical data transmitted over the Internet. It can still further comprise providing a combination Internet receiving and paging or other wireless communication network transmitting site to receive the medical data transmitted on the Internet and to transmit received medical data to at least one respective physician's receiver through the wireless network. The method can also comprise marking each sensor with indicia defining the address of the Internet site.
Therefore, from the foregoing, it is a general object of the present invention to provide a novel and improved system and method for generating and transferring medical and other data. Other and further objects, features and advantages of the present invention will be readily apparent to those skilled in the art when the following description of the preferred embodiments is read in conjunction with the accompanying drawings. BRIEF DESCRIPTION OF THE DRAWINGS FIG. 1 is a block diagram illustrating one configuration of a system of the present invention.
FIG. 2 is a block diagram illustrating one variation of the FIG. 1 configuration wherein a patient site accesses a log-on site to acquire a software program necessary to provide medical data to a recipient site.
FIG. 3 is a block diagram illustrating one implementation of the system depicted in FIG. 2.
FIG. 4 is a block diagram illustrating another implementation of the system depicted in FIG 2.
FIG. 5 illustrates one implementation for a patient site.
FIG. 6 is a general flow diagram for the use and operation of the implementations of FIGS. 2-5.
FIG. 7 is a more detailed block diagram of the patient site depicted in FIG. 5. FIG. 8 illustrates a particular implementation of a system of the present invention including at least one patient site of the type shown in FIG. 7.
FIG. 9 is a flow diagram for a medical data acquisition and transmission program for the FIG. 8 system.
FIG. 10 is a flow diagram for displaying data at a recipient Internet site remote from the patient's site of the FIG. 8 system.
DETAILED DESCRIPTION OF THE INVENTION A general representation of the system of the present invention as applied to one example of medical data acquisition and transmission is illustrated in FIG. 1. The present invention also can be used for generating and transferring other data that can be processed in the manner described below.
Although only one patient site need be present, typically there will be a plurality of patient sites 2a-2n (the term "patient" as used herein is not limited to someone who is ill or who is necessarily under a medical provider's care; it simply refers to an individual using the present invention in the medical context). These sites are wherever the patient (or, more broadly, initial user or simply some data generating source) is and has access to a computer and communication network, which is specifically illustrated as including the Internet 4 in the drawings and in the remainder of the following description of the present invention (the term "Internet" as used herein encompasses the global computer network commonly known by that name, any functional part of it suitable for use in the present invention (e.g., the World Wide Web), and any other suitable global computer network capable of providing the communication link of the present invention). Also connected to the Internet 4 is at least one remote site 6 with which the patient sites 2a-2n can communicate.
The remote Internet site(s) 6 can be embodied in various manners; however, two particular types of the preferred embodiment are represented in FIG. 2. One or more logon sites 6a are addressed by a patient at his or her site entering the log-on site's address. Such a log-on site 6a is the only site a patient need explicitly address from the respective patient site 2.
Although the foregoing is the only explicit address a patient need enter, other remote sites can be accessed, such as illustrated by recipient sites 6b in FIG. 2. In preferred embodiments, such sites are automatically addressed when data is to be sent from a patient site 2 to an end user. This can occur through a log-on site 6a, but in the illustrated embodiment of FIG. 2 there are physically and functionally distinct recipient Internet sites. A further overview of the foregoing will be described with reference to FIGS. 3-6.
A more detailed explanation will then be given with reference to FIGS. 7-10.
Referring to FIG. 3, a patient site 2 includes means for sensing a biological function or condition (more broadly, a data generating source; for example, a device that
responds to some ambient parameter by generating a signal adaptable for use by a computer as described herein). It also includes means, communicating with the means for sensing, for transferring a response to the sensed biological function or condition over the Internet. The means for sensing includes at least one sensor 8 suitable for sensing a function or condition of the body of the respective patient. The means for transferring includes a computer 10 connected to receive signals from the one or more sensors 8 and to access the Internet 4.
In a particular implementation, the sensor 8 includes a hand-held device that is inexpensive and simple to use. As illustrated in FIG. 5, the sensor 8 includes a heart monitor that provides an audible output signal in response to the sensed biological function or condition, which in this example is the patient's heart activity. The patient can hold this device against his or her chest by hand, this can be done by another person, or the device can be attached to the chest or held by an elastic strap (for example). The sensor 8 of this implementation in FIG. 5 includes a hand-held transducer that converts energy from an adjacent beating heart of a patient 12 into an acoustical signal. The acoustical signal can be detected by a microphone 14 connected to the conventional microphone jack of a personal computer 16 implementing the computer 10. The term "personal computer" as used in this specification and claims encompasses all types of computers conventionally referred to by that name regardless of size designation (e.g., desktop, laptop, notebook, hand-held, palmtop, etc.). Non-limiting examples of sensors are those capable of providing outputs responsive to (1) changes of electrical potential occurring during the heartbeat to provide ECG data, or (2) brain waves to provide EEG data, or (3) variations in the size of an organ or limb and in the amount of blood present or passing through it to provide plethysmograph data, or (4) galvanic skin resistance. It is to be noted that any particular sensor 8 merely needs to provide some signal suitable for inputting to the computer 10 (thus "data" of the present invention includes anything represented by such signal). The microphone 14 is used in the embodiment of FIG. 5 to convert the acoustical signal of this embodiment into a corresponding analog electric signal used by the personal computer 16. The sensor 8 can be a type that provides an electric signal output directly to the personal computer 16, for example.
The personal computer 16 in the FIG. 5 implementation is connected to the microphone 14 and includes circuits and programs to access the Internet 4 and to transfer a representation of the sensor's output signal over the Internet 4 to a selected Internet site in
response to input to the personal computer 16 from the microphone 14. That is, the personal computer 16 transfers over the Internet 4 data representative of the electric signal received either from the microphone or other device, such as the sensor 8 itself, into the personal computer 16. The personal computer 16 need be programmed initially only with conventional programs sufficient to enable the patient or other user at the patient site to access the Internet 4 through the personal computer 16. This programming can include a conventional web browser. At some point in the use of the personal computer 16, it is also programmed with a medical data (or other specific type of data as used for other embodiments) acquisition and transmission program (in broader terms, simply a data acquisition and transmission program). In the preferred embodiment, this program is downloaded into the personal computer 16 from the log-on site 6a using the web browser. The program can be in any suitable form, such as in the form of an application "plug-in," a "Java applet," or in a preferred particular implementation an "ActiveX control." The personal computer 16 connects to the Internet 4 by any suitable communication link (e.g., telephone line, television cable).
The circuitry and programming of the personal computer 16 also ultimately are sufficient to provide it with the capability to read the input port receiving the signal from the microphone 14 or other input device, to process the input signal, to access the recipient
Internet site to which data is to be transferred, and to send the data to the recipient site over the Internet.
Referring to FIG. 3 again, the log-on site 6a in this embodiment includes a computer 18 having the medical data acquisition and transmission program stored for downloading to a patient site 2. That is, the log-on site 6 of this implementation is an Internet site addressable from each of the plurality of patient sites such that each patient site can access the medical data acquisition and transmission program through the Internet site to enable the respective computer 10 (e.g., personal computer 16) at the respective patient site to process received signals from a patient sensor connected to it and to transmit responsive signals over the Internet 4.
The log-on site 6 can be implemented in any suitable manner. For example, it can be provided by an existing Internet service provider which the computer at a patient site accesses when the patient initially logs onto the Internet.
Still referring to FIG. 3, the recipient site 6b includes a computer 20 programmed to receive data and display it through a display 22 (e.g., a monitor or printer). In the
implementation of FIG. 3, the computer 20 receives the transferred response over the Internet and directly communicates the information via the display 22. For example, the computer 20 can be located at a medical facility and connected to communicate with the Internet. Such computer is programmed to receive the response transferred over the Internet and to provide a visible representation of the sensed biological function or condition.
Another implementation of a recipient site 6b is illustrated in FIG. 4. In this implementation, the recipient site 6b functions as an intermediary between a patient site and an end user of the data. As shown in FIG. 4, the recipient site 6b still includes the computer 20, but which is additionally programmed to transfer the data to something other than the display 22. In FIG. 4, the computer 20 is programmed to communicate the data to a wireless network 24 (but other communication techniques can be used in other embodiments) that sends the data through its system to a wireless data receiver and computer combination 26. The wireless system is one that can provide data transmission (e.g., digital phone systems, such as GSM or CDMA which provide data transmission; two-way paging systems; one-way paging systems). This type of transfer can occur in accordance with the known technology described in the patents cited in the background explanation set forth above, which are incorporated herein by reference. In this implementation, the recipient computer 20 can be located at a data communication service provider facility. This computer 20 is connected to communicate with the Internet 4, and it is programmed to receive at least part of the responsive signals transmitted over the Internet and to transmit in response thereto end user signals from the recipient computer 20 to an end user. The end user signals are a representation of the human body function or condition (or other data) as initially sensed by the sensor 8. As mentioned above, the log-on site 6a and the recipient site 6b can be combined such that a single site provides both the medical data acquisition and transmission program to be downloaded to the patient site and also the programming necessary to receive data and directly display it or transfer it by other means to an end user. This is illustrated in FIG. 8 which is described below. The method of the present invention for the foregoing embodiments is now described with reference to FIG. 6. Using the computer 10 (e.g., personal computer 16) where the patient is located, the Internet site having the medical data acquisition and transmission program is accessed from the respective patient's site. Access occurs by the
computer 10 at the patient site 2 running its web browser or otherwise gaining access to the Internet 4. Once Internet access has been gained, the computer 10 accesses the known log-on site where the medical data acquisition and transmission program is located. This can be the site through which Internet access is gained, or the site containing the medical data acquisition and transmission program can be different from the Internet portal.
When the appropriate site has been accessed, identification information (e.g., name, password) is entered (e.g., manually by the patient or automatically by preprogramming the patient's computer 10) to enable the computer 10 at the patient site 2 to select and download the medical data acquisition and transmission program. When the appropriate information has been given to the log-on site 6a in the illustrated embodiments of FIGS. 3 and 4, the medical data acquisition and transmission program downloads to, or otherwise becomes accessible for use by, the computer 10 at the patient site 2.
The medical data acquisition and transmission program preferably downloads in active mode so that it is ready to perform the functions at the patient site 2 without the patient having to perform functions other than manipulating the sensor to sense the biological function or condition to be transmitted to the computer 10 at the patient site. In the implementation of FIG. 5, the patient 12 holds the heart monitor 8 against his or her chest. The heart monitor 8 responds to the beating heart by generating corresponding acoustical signals transmitted to the microphone 14. The microphone 14 converts the signals to analog electric signals communicated to the personal computer 16 programmed with the downloaded medical data acquisition and transmission program. In using the medical data acquisition and transmission program, the personal computer 16 receives the signals, processes the received signals, and transmits medical data signals onto the Internet 4 in response. Transmitting over the Internet 4 to a recipient site 6b includes accessing a second
Internet site from the computer 10 and transmitting patient data over the Internet to the accessed second Internet site 6b, both under control of the medical data acquisition and transmission program used by the computer 10.
In addition to the foregoing which is illustrated in FIG. 6, the method of the present invention can further comprise receiving, over the Internet, the transmitted medical data signals at a recipient site. As explained above, this can be any suitable site, such as a medical facility or a data communication service provider facility. The former would typically be an end user of the data whereas the latter would typically be an
intermediary that transfers the data onto an end user. As explained above with reference to FIG. 4, such could include transmitting, from the data communication server provider facility to an end user, end user signals responsive to the received medical data signals. In FIG. 4, this includes transmitting the medical data signals through the wireless data network 24.
When the data is received by the end user, a display is generated in response to a received signal. The display is a representation of the transduced human body function or condition. In the example of a heart monitor implementing the sensor 8, the display can be a waveform corresponding to the detected heart beat energy. This display can be by way of a computer monitor or printer or other display device.
The method of the present invention can also be defined as comprising distributing by any suitable means (e.g., through direct mail, at physicians' offices) at least one sensor to each patient. For example, this includes distributing to a plurality of patients respective portable heart monitoring devices that the respective patients can hold against their chests without assistance. Each sensor can be marked with indicia defining the address of the Internet site of the log-on site 6a. In the preferred embodiments of FIGS. 3 and 4, this can include the World Wide Web address for the respective log-on site 6a that one or more of the patients is to access to download the medical data acquisition and transmission program. The method further comprises maintaining the medical data acquisition and transmission program at the Internet site which is accessible by the patients such that the patients can use the medical data acquisition and transmission program to control their respective computers to receive and process signals from the patients' respective sensors and to transmit medical data onto the Internet in response. Use of the program is made by accessing the Internet site using a web browser program or other suitable programming loaded on the computer at the location of the patient.
Maintaining the medical data acquisition and transmission program includes storing the program in a computer at the Internet site 6a for FIGS. 3 and 4. The method can further comprise storing in the computer at the Internet site a database of potential recipients of the medical data, wherein the database is also accessible by each patient such that each patient can identify from the potential recipients at least one selected recipient to receive the medical data for that patient.
One way of getting the information to the end users is to distribute to a plurality of physicians receivers for receiving at least portions of the medical data transmitted over the
Internet. The receivers (which may also have transmitting capability can include pagers connected to palmtop computers such as referred to in the patents mentioned in the background portion of this specification and incorporated herein by reference.
A more detailed explanation of the foregoing will next be given with reference to FIGS. 7-10.
FIG. 7 shows a particular implementation of the components generally identified in FIG. 5. This includes the sensor 8, the microphone 14 and the personal computer 16. The sensor 8 provides an acoustical signal in simultaneous response to a biological function or condition, namely a beating heart in the illustrated implementation. The microphone 14 is located with the sensor 8 to receive the acoustical signal as the signal is provided from the sensor 8. The personal computer 16 is connected to the microphone and is adapted to transfer over the Internet, in real-time response to the microphone receiving the acoustical signal, electric signals representative of the received acoustical signal.
The sensor 8 of the FIG. 7 implementation includes a device 30 that converts the beating heart energy into electric signals. This can be by conventional electrocardiogram (ECG) electrodes as represented in FIG. 7 or other suitable device (e.g., a suitable piezoelectric device). The electric signals generated by the device 30 are amplified through an amplifier 32. The output of the amplifier 32 is processed through a voltage to frequency converter 34 to provide an alternating current signal that drives a speaker 36 to emit the acoustical signal directed toward the microphone 14.
The microphone 14 converts the acoustical signal into an analog electric signal conducted through a connected microphone jack 38 of the personal computer 16. The microphone jack 38 connects to the input of an analog to digital converter circuit 40 in the personal computer 16. The circuit 40 interfaces the microphone to the computer by converting the analog signal from the microphone 14 to a digital signal that can be used by a microprocessor circuit 42. The microprocessor circuit 42 is connected to a mouse 44, a keyboard 46, and a display 48. The microprocessor circuit 42 also communicates with an Internet connection 50, such as a coupling to a telephone line (e.g., a modem).
The analog to digital converter circuit 40 preferably provides at least eight-bit resolution and samples at 8,000 or more samples per second; this can be implemented with conventional technology, one example of which is a SOUND BLASTER brand
sound card from Creative Labs. The microprocessor circuit 42 is also conventional, but preferably has a microprocessor nominally rated at least 20 megahertz. It also includes suitable memory for program storage and processing functions (e.g., typically both read only memory and random access memory). The programming of such memory is also conventional prior to loading the medical data acquisition and transmission program referred to above. This conventional programming can include, for example, a Windows operating system and a compatible web browser, such as Microsoft's INTERNET EXPLORER program or Netscape's NAVIGATOR program. Thus, the foregoing, and the other components illustrated in FIG. 7, can be implemented with conventional devices. With the equipment of FIG. 7, shown in simplified blocks in FIG. 8, a patient at the site of the sensor 8, microphone 14 and personal computer 16 uses the web browser stored in the personal computer 16 to log onto the Internet. Typically this occurs through whatever Internet service provider the patient uses. Non-limiting examples include America On-Line and AT&T Worldnet. Once logged onto the Internet through his or her Internet service provider, the patient types in the address of the Internet site containing the medical data acquisition and transmission program if it is not available at the Internet service provider site. For example, for the illustration in FIG. 8, the patient enters the address "http//www.datacritical.com". The home page of datacritical.com appears on the display 48 of the personal computer 16. Through this home page, the patient downloads or otherwise accesses the medical data acquisition and transmission program. In one example, the datacritical.com home page contains a link that the patient selects to go to a page from which the program is downloaded. This linked page includes patient identification entry spaces, such as calling for the patient's unique password, to enable only a registered patient to download the program if such registry is desired to permit someone to download the program.
An example of a medical data acquisition and transmission program that is downloaded to the patient's computer 16 is appended at the end of this specification. The program can be of any suitable language and type to enable the implementation of the present invention; however, non-limiting examples include a program in ActiveX or Java, or a plug-in module. Preferably the program is downloaded in an active mode so that the patient does not need to do anything to actuate the program to receive the medical data and to process it for display locally or transmission onto the Internet.
With the downloaded program running, an acoustical signal is generated at the patient site in response to the biological function or condition of the individual being monitored. This includes the heart monitor for the illustration of FIGS. 7 and 8. The acoustical signal is received in the microphone 14 near the individual. The microphone 14 converts the acoustical signal into an analog electric signal. The analog electric signal is communicated from the microphone 14 to the analog to digital conversion circuit 40 where it is converted to a digital electric signal. The digital electric signal is processed in the microprocessor circuit 42 of the personal computer 16 under control of the medical data acquisition and transmission program that has been downloaded and is actively running. The program can then display to the individual, through the display 48 of the personal computer 16, a representation of the individual's biological function or condition in response to which the acoustical signal was generated. The medical data acquisition and transmission program can also transmit the data onto the Internet. In the illustration of FIG. 8, the data is transmitted to datacritical.com where it can be stored in a searchable database and transmitted to an end user. Preferably the transmission to the end user occurs contemporaneously with the foregoing steps so that there is real-time transmission of the data from the time the biological function or condition of the individual was sensed to the time it is received by the end user. Thus, once the program has been downloaded into the personal computer 16, preferably the subsequent steps from sensing the condition through display to the individual at the patient's site or transmission to an end user are performed together in real time. The data downloaded to the end user can also be stored in the end user's computer for later retrieval. Thus, the medical information derived from the sensing activity can be useful both for clinical purposes by an end user medical care provider as well as for providing self-knowledge benefits for the patient, such as in monitoring his or her own biological functions or conditions.
A flow diagram of a preferred embodiment of the medical data acquisition and transmission program downloaded to the personal computer 16 is illustrated in FIG. 9, and the source code is listed at the end of this specification before the claims. The program is an ActiveX control in combination with an HTML page which collects, filters and displays a user's ECG waveform and heart rate. When the control is embedded in a web page (e.g., at datacritical.com in the FIG. 8 illustration), it is downloaded to the user's personal computer 16 and configured to record ECG data from the microphone 14 connected to the personal computer 16 and to display the ECG waveform in the browser
window of the personal computer 16. Configuration of the control is achieved via HTML "Param" tags. The control is embedded in an HTML page via the "Object" tag — this tells the browser to load the control. After the "Object" tag, and the name of the control, come the "Param" tags which provide values for named parameters of the control. For example, in the appended program listing there is a parameter called "Microphone_Not_Server," and the Param statement looks like:
<PARAM NAME = "Microphone_Not_Server" VALUE = "1"> This statement initializes the control to listen for data at the microphone. The browser-loaded control can also stream, across the Internet, demodulated ECG data to a redisplay server at a recipient site if one is available. The redisplay server also contains a control program (see FIG. 10 and program listing) that processes the forwarded ECG data.
When the program of FIG. 9 operates in the personal computer 16 at a patient's site, the data source in this implementation referring to FIGS. 7-10 is an 8 kilohertz pulse code modulated (PCM) ECG signal received from the analog to digital converter circuit 40 in response to the acoustical signal sensed by the microphone 14. When the control is contained in a redisplay server, the data source is demodulated ECG data that has been sent from the personal computer 16 over the Internet to the redisplay server (or from the personal computer to datacritical.com and then to the redisplay server via the Internet or a paging network, for example).
In the flow diagram of FIG. 9, once the control has been downloaded to the user's personal computer, it is configured via an HTML "Param" tag to collect data from the microphone as input through the analog to digital converter circuit 40 as explained above. The control may also be configured to connect to a redisplay server via another "Param" tag in the manner described above. The control then receives a "draw yourself event from Windows. The first time this event is received, the control starts listening for data on the microphone.
Upon receiving data from the microphone, the control demodulates the data from 8 kilohertz pulse code modulated to 200 hertz ECG samples. If a redisplay server is specified, the control streams the new, demodulated samples to the server over the Internet.
Once the ECG data has been demodulated, it is filtered based upon the filtering level set in a "Param" tag on the web page. Filtering levels are as listed in FIG. 9 (low pass filter, high pass filter, derivative filter, square filter).
The most recent two seconds worth of filtered data is then scanned for QRS complexes to determine the user's heart rate in beats per minute. The software fires a
Windows "my view has changed" event, which causes Windows to call the control's
"OnDraw" routine such that "OnDraw" updates the screen 48 of the personal computer 16 with the latest ECG waveform and heart rate.
Referring to FIG. 10, in a redisplay server, the program enables the server to listen at a known port for incoming demodulated ECG samples from a remote site. When samples are received, the server passes them to the control's filtering routine as described above. The same chain of events then occurs: the samples are filtered, QRS detection is executed, and the waveform is updated to the remote server's window.
Thus, the present invention is well adapted to carry out the objects and attain the ends and advantages mentioned above as well as those inherent therein. While preferred embodiments of the invention have been described for the purpose of this disclosure, changes in the construction and arrangement of parts and the performance of steps can be made by those skilled in the art, which changes are encompassed within the spirit of this invention as defined by the appended claims.
if( mCurreπtAverage >= mAverageCount ) mCurrentAverage = 0;
} else
++mCumuSamps ;
for( i = 0; i < mAverageCount; i++ ) total += *(mpBPMs + i); mAvgBPM = total / mAverageCount; if( !mAvgBPM ) mAvgBPM = mCurBPM;
-H-m urrent amp ; if( mCurrentSamp >= mNumSamples ) CurrentSamp = 0; mPreviousPoint - newpoiπt; return mCurBPM; // end of update
// webEcg . h : Declarati on of the CWebEcg
#i fndef _WEBECG_H_ #defi ne _WEBECG_H_
#i ncl ude " resource . h" // main symbol s #i ncl ude "network. h" #i ncl ude "BPMDetector . h" #i ncl ude "ri ngbuf. h"
const unsigned long SAMPLE_FREQ = 8000; const unsigned l ong DECIMATION = 40 ; // 40 to 1 decimati on const unsi gned long ECG_FREQ = (SAMPLE_FREQ / DECIMATION) ; const unsi gned l ong FRAMES_PER_SEC = 20; const unsigned l ong WORK_BUFFER_SIZE = (SAMPLE_FREQ / FRAMES_PER_SEC) ; //#defi ne DISPLAY.SECONDS 5
/////////////////////////////////////////////////////////////////////////////
// cwebεcg class ATL_NO_VTABLE CWebEcg : publ i c CComOb ectRootEx<CComSi ngleThreadModel> , public CComCoClass<CwebEcg, &CLSID_WebEcg> , public CComCoπtrol<CwebEcg>, public CStockPropi pl-cCwebEcg, IWebEcg, &IID_IWebEcg , &LlBID_WEBECGCONTROLLi b>, public IProvideCl sslnfo2lmpl<&CLSID_webEcg, NULL, &LIBID_WEBECGCONTROLLib>, publ c IPers stPropertyBaglmpl<CwebEcg> , publ i c IPersi ststreamln tl p1<cwebEcg>, publ i c IPersi ststoragelmpl <CWebEcg> , publ c iQuickActivatelmpl<CwebEcg> , public IθleControlImpl<CwebEcg>, publ c Iθleθbjectlmpl<CWebEcg>, publ c IOlelnplaceActiveobjectlmpl<cwebEcg> , public iv ewObiectExlmpl<CWebEcg>, publ i c IOlelnPlaceobjectwi ndo lesslmpl <CwebEcg> , public IDataObjectlmpl <CwebEcg>, public ISupportErrorlnfo, publi c IConnectionPoi ntContainerlmpl<CWebEcg> , publ c IPropertyNotifyS nkCP<CwebEcg>, public ISpecifyPropertyPagesImpl<cwebEcg>
{ public:
CWebEcgO
: mBPMC 200, // samps per sec 4, // maxQRSPerSec 2, // sees to buffer 3, // sees to average
40.0 )// detect thresh"
// MessageBoxC'webECG Starting", "informational message.. MB_OK) ; m_bMicrophoneNotserver = false; mbDra ECG = false; " m_bFrozen = false; m_bw ndo only = TRUE; m_nVolumeThreshold = 8; m_nBPMFontSize = 36; m_dDetectPercent = 50.0;
• _nBPM = m_nAvgBPM ■ 0; Age = 30; mMaxHR = 220 - mAge; m_nForewidth = 2; ιτu.clrForeColor = RGB(0, 0,255) ; π clrβackColor = RGB (0,0,0); n clrGridColor = RGB (0,192,0) ; m_dwCardioGramLength = ECG_FREQ*2; m_pCardioGram = new (signed char[m_dwCardioGramLength]) ; m_pCardioGramPoints = new(POINT[m_dwCardioGramLength]) ; m_pverticalBar = new (unsigned char[m_dwCardioGramLength]) ; for (unsigned long i = 0; i<m_d CardioGramLength; I- -) m_pCardioGram[i] = 0; m_pverticalBar[i] = 0; } m_dwStartDrawi ng = 0; m_dwStopDrawi ng = 0; m_bRecording = false; mBPMSamplecount = 0; πtSampsPerBPMPt = ECG_FREQ / 4; mCumSamps = 0; for( i = 0; i < 4; i++ ) m_pwaveHdr[i] = new(WAVEHDR) ; m_pwavBuf[i] = NULL;
m_dMaxmV = 2.0 m_dMiπmV = -2.0 m_dstepmv = 0.5 m_hbmpworkBitmap = NULL; m_hdcworkDC = NULL; wsAStartupCOxOlOl, &m_ sawSAData) ; // 0x0101 means winsock 1.1 m_bConnectedToServer = false; mMaxPoints = 0 Pointwidth = 4 mMinPointwidth = 4 mspacewidth = 2 mCur oint = 0 mPointsRead = 0 mPointsPerCyc = 0 mDrawingwid = 0 mxscale 0.0; mYscale 0.0; mxoffset 0.0; mYoffset 0.0; mHeight 0; mwidth 0; prevwidth -l; mYmax 0; mMaxHrY 0; mMinHrY 0;
} // end constructor
-CwebEcgO
{ int ι ; avelnReset(m_hwaveln) ; wavelnClose(m_hwaveln) ;
// Sleep(C1.0/SAMPLE_FREQ)*C2*WORK_BUFFER_SIZE)*1000); // Give system time to shut down whatever. .> ,, .
// sleepC(1000/SAMPLE_FREQ)*C2*wθR _BUFFER_SlZE)); // Give system time to s hut down whatever.
// sleep((1000*2*WORK_BUFFER_SIZE)/SAMPLE_FREQ); // Give system time to s hut down whatever.
Sleep((2000*wθRK_BUFFER_SIZE)/SAMPLE_FREQ); // Give system time to shut down whatever. for (i=0; i<4; i++) wavelnuπprepareHeader(m_hWaveln , m_pwaveHdr[i ] , si zeof (WAVEHDR)) ; delete m_pwaveHdr[i ] ; i f( m_pwavBuf [i] ) del ete m_pwavBu [i] ;
} delete π pverticalBar; delete π pCardioGramPoiπts; delete m_pCardioGram; if (m_hbmpworkBitmap)
DeleteObiectCmJib pWorkBitmap) ; if (m_hdcworkDC)
DeleteObject(m_hdcworkDC) ;
shutdown(m_sckLocalSocket , 1) ; closesocket(π sckLocalSocket) ; wSACleanupC); // MessageBox("webECG Stopping", "informational message...", MB_OK) ;
DECLARE_REGISTRY_RESOURCEID(IDR_WEBECG)
BEGIN_COM_MAP(CWebEcg)
COM_INTERFACE_ENTRY(IWβbEcg)
COM_INTERFACE_ENTRY(IDi Spatch)
COM_INTERFACE_ENTRY_IMPL(IVl ewθbjectEx)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IVi ewObject2 , IVi ewObjectEx)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IVl ewObject , IVi ewObjectEx)
COM_INTERFACE_ENTRY_IMPL(IOl einPl aceObjectwi ndowless)
COM_lNTERFACE_ENTRY_lMPL_HD(llD_lθlelnPlaceθbject, lOlelnPl aceObjectwi ndowl ess)
COM_INTERFACE_ENTRY_IMPL_IID(IID_IθleWindow, lOlelnPlaceObjectwi πdowless)
COM_INTERFACE_ENTRY_IMPL(lθl einPl aceAct veObject)
COM_INTERFACE_ENTRY_IMPL(IθleControl )
COM_INTERFACE_ENTRY_IMPL(IOl eObject)
COM_INTERFACE_ENTRY_IMPL(lQu CkACtl vate)
COM_INTERFACE_ENTRY_IMPL(IPersιstPropertyBag)
COM_INTERFACE_ENTRY_IMP (IPers ststorage)
COM_INTERFACE_ENTRY_IMPL(IPers ststreamlnit)
COM_INTERFACE_ENTRY_IMPL(ISpecifyPropertyPages)
COM_INTERFACE_ENTRY_IMPL(IDataObjeCt) COM_INTERFACE_ENTRY(IProvideclasslπfo) COM_INTERFACE_ENTRY(IProvi decl asslnfo2) COM_INTERFACE_ENTRY(ISupportErrorInfo) COM_INTERFACE_ENTRY_IMPL(IConnectionPoiπtContainer) END_COM_MAP()
BEGIN_PROPERTY_MAP(CWβbEcg)
// Exampl e entri es
// PROP_ENTRY("Property Descri pti on di spid, clsi d)
PROP_ENTRY("Fore_Color' DISPID_FORECOLOR, CLSlD_StockCol orPage) PROP_ENTRY("Back_Col or" , DISPID_BACKCOLOR, CLSiD_stockCol orPage) PROP_ENTRY("Gri d_Col or " , di spi dGri dCol or , CLSlD_webEcgPPG) PROP_ENTRY("Gri d_Styl e" , di spi dGri dStyl e , CLSiD_webEcgPPG) PROP_ENTRY(" ax_mV" , di sp dMaxmV, CLSiD_webεcgPPG) PROP_ENTRYC"Mi n_mv" , di spi dMi nmV , CLSiD_webεcgPPG) PROP_ENTRY("Step_mV" , di spi dstepmv , CLSID_webEcgPPG) PROP_ENTRY("Fore_Wi dth" , di spi dForewi dth , CLSID_webEcgPPG) PROP_ENTRY("Di spl ay_Seconds" , di spi dDi spl aySeconds , CLSID_WebEcgPPG) PROP_ENTRY("Vol ume_Threshol d" , di spi dvol umeThreshol d , CLSID_WebEcgPPG) PROP_ENTRY("Fi lteri ng" , di spi dFi lteri ng , CLSID_WebEcgPPG) PROP_ENTRYC"BPM_Foπt_Si ze" , di spi dBPMFontSi ze , CLSID_WebEcgPPG) PROP_ENTRY("Detect_Perceπt" , di spi dDetectPercent , CLSID_webEcgPPG) PROP_ENTRY("Server_Address" , di spi dServerAddress , CLSiD_webEcgPPG)
PROP_ENTRY("Mi crophone_Not_Server" , di spi dMi crophoneNotServer , CLSID_webEcgP
PG)
PROP_ENTRY("AddNewPθi nt" , di spi dAddNewPoi nt , CLSiD_webEcgppG) PROP_ENTRY("Age" , dispidAge, CLSID_WebEcgPPG) PROP_ENTRY("Average_Count" , di spi dAverageCount , CLSID_WebEcgPPG) PROP_ENTRYC"Vi ewECG" , dispidviewECG, CLSID_WebEcgPPG) END_PROPERTY_MAPθ
BEGIN_CONNECTION_POINT_MAP(CWebEcg)
CONNECTION_POINT_ENTRY(IID_IPropertyNoti fySi nk) END_CONNECTION_POINT_MAP()
BEGIN_MSG_MAP(CWβbECg)
MESSAGE_HANDLER(WM. .PAINT , Onpaint)
MESSAGE_HANDLER(WM..SETFOCUS , OnSetFocus)
MESSAGE_HANDLER(WM.. ILLFOCUS , Onκi 11 Focus)
MESSAGE_HANDLER(MM..WIM_OPEN , OnwimOpen)
MESSAGE_HANDLER(MM..WIM_DATA , OnwimData)
MESSAGE_HANDLER(MM..WIM_CLOSE , OπwimClose)
MESSAGE_HANDLER(MM..WOM_OPEN , OnwomOpeπ)
MESSAGE_HANDLE (MM. WOM_DONE , OnwomDone)
MESSAGE_HANDLER(MM_ WOM_CLOSE , OnwomClose)
MESSAGE_HANDLER (WM..LBUTTONDOW , OnLButtonDown) END_MSG_MAPO
// ISupportsErrorlnfo
STDMETHOOClnterfaceSupportsErrorlnfo) (REFIID ri i d) ;
// ivi ewobjectEx
STDMETHθD(GetviewStatus) (DWORD* pdwStatus) {
ATLTRACE(_T("lvi ewobjectExImpl : :GetviewStatus\n")) ;
*pdwStatUS = VIEWSTATUS_SOLIDBKGND | VIEWSTATUS_OPAQUE; return S_OK; }
// iwebEcg
P" STDMETHOD(get_viewECG)(/*[out, retval]*/ BOOL *pval); STDMETHOD(put_viewECG)(/* [in]*/ BOOL newval); STDMETHOD(get_Average_Count)(/*[out, retval]*/ long *pval); STDMETHOD(put_Average_Count)(/*[in]*/ long newval); STDMETHOD(get_Age)(/*[out, retval]*/ short *pval); STDMETHOD(put_Age)(/*[in]*/ short newval); STDMETHOD(get_AddNewPoint)(/*[out, retval]*/ short *pval); STDMETHOD(put_AddNewPo nt)(/*[in]*/ short newval); STDMETHOD(get_MicrophoneNotServer)(/*[out, retval]*/ short *pval); STDMETHOD(put_MicrophoneNotServer)(/*[in]*/ short newval); STDMETHOD(get_ServerAddress)(/*[out, retval]*/ BSTR *pval); STDMETHOD(put_ServerAddress)(/*[in]*/ BSTR newval); STDMETHOD(get_DetectPercent)(/*[out, retval]*/ double *pval); STDMETHOD(put_DetectPerceπt)(/*[in]*/ double newval); STDMETHOD(get_BPMFontSize)(/*[out, retval]*/ short *pval); STDMETHOD(put_BPMFontSize)(/*[in]*/ short newval); STDMETHOD(get_Filtering)(/*[out, retval]*/ short *pval); STDMETHOD(put_Filtering)(/*[in]*/ short newval); STDMETHθD(get_volumeτhreshold)(/*[out, retval]*/ short *pval); STDMETHOD(put_VolumeThreshold)(/*[in]*/ short newval); STDMETHOD(get_DisplaySecoπds)(/*[out, retval]*/ short *pval); STDMETHOD(put_DisplaySecoπds)(/*[in]*/ short newval); STDMETHOD(get_Forewidth)(/*[out, retval]*/ long *pval); STDMETHOD(put_Forewidth)(/*[in]*/ long newval); STDMETHOD(get_Stepmv)(/*[out, retval]*/ double *pval); STDMETHOD(put_StepmV)(/*[in]*/ double newval); STDMETHOD(get_Maxmv)(/*[out, retval]*/ double *pval); STDMETHOD(put_Maxmv)(/*[in]*/ double newval); STDMETHOD(get_Minmv)(/*[out, retval]*/ double *pval); STDMETHOD(put_Minmv)(/*[in]*/ double newval); STDMETHOD(get_GridStyle)(/*[out, retval]*/ long *pval); STDMETHOD(put_GridStyle) /*[in]*/ long newval); STDMETHOD(get_GridColor)(/*[out, retval]*/ OLE_COLOR *pval); STDMETHOD(put_GridColor)(/*[in]*/ OLE_COLOR newval); HRESULT FireViewChangeO; HRESULT OπDraw(ATL_DRAWINFθ& di); HRESULT drawECG( ATL_DRAWINFO& di ) ; HRESULT drawBPMPointsC ATL_DRAWINFO& di );
HRESULT Onw mθpen(UINT uMsg, WPARAM wParam, LPARAM 1 Param, BOOL& bHandled); HRESULT OnwimDataCuiNT uMsg, WPARAM wParam, LPARAM lparam, BOOL& bHandled); HRESULT Onwimclose(UlNT uMsg, WPARAM wParam, LPARAM 1 Param, BOOL& bHandled); HRESULT OnwomOpenCuiNT uMsg, WPARAM wParam, LPARAM 1 Param, BOOL& bHandled); HRESULT OnwomDoneCuiNT uMsg, WPARAM wParam, LPARAM lparam, BOOL& bHandled); HRESULT OnwomClose(uiNT UMsg, WPARAM wParam, LPARAM lparam, BOOL& bHandled); LRESULT OnLButtonDown(uiNT uMsg, WPARAM wParam, LPARAM 1 Param, BOOL& bHandle d) ;
CComPtr<IPi ctureDi sp> m_pMouselcon ;
OLE_COLOR m_clrBackColor;
OLE_COLOR m_clrBorderColor;
OLE_COLOR m_clrForeColor;
OLE_COLOR it clrGridColor;
BOOL m_bBordervisible; long m_nBorderStyle; long m_nBorderw dth; long m_nForewidth; long m_nGridstyle; long m_nMousePointer; short m_nvolumeτhreshold; short m_nFilter ng; short m_nBPMFoπtSιze;
CComBSTR π bstrFi leName; CComBSTR π bstrServerAddress ; bool m_bConnectedToServer; double m_dMi nmv; double ir dMaxmv; double m_dstepmv; double m_dDetectPercent;
// shouldn ' t be publi c, but I don ' t care about ni ce now as // much as getti ng somethi ng worki
BOOL m_bMi crophoneNotSe rve r ; signed char * m_pCardioGram; unsigned char ' m_pverti cal Bar;
POINT * m_pcardi oGramPoi nts ; unsigned long π dwCardi oGramLength ; bool m_bRecordi ng ; unsigned char * m_pwavBuf [4J ; unsigned char * m_pFullwav; unsigned long m_dwFul 1wavLength ;
HWAVEIN m_hwavelπ ;
PWAVEHDR m_pwaveHdr[4] ; unsigned short m_nBPM; unsigned short m_nAvgBPM; unsigned long m_dwStartDrawi ng ; unsigned long m_dwStopDrawi ng ;
HBΓTMAP m_hbmpworkBi tmap;
HDC m_hdcworkDC; bool m_bFrozeπ;
RECT m_rctFreezeButton ;
SOCKET m_sckLocalSocket; sockaddr_in m_sckadrRemoteSocketAddress ;
WSADATA m_wsawSAData;
priv 'aattee:: void NewRawData(signed short * RawData, unsigned long NumData); voi d ConnectToServer() ; void drawPointsC HDC &dc, RECT &rc, int dataStart, int xStart, int xEnd, int numBars ); void upArrowC POINT *pPoints, int x, int y, int wid ); void downArrowC POINT *pPoints, int x, int y, int wid );
CBPMDetector mBPM; bool mbDrawECG; short mAge; short mMaxHR; short mBPMSampleCount; ringbuf < int > mBPMData; short mSampsPerBPMPt; short mCumSamps;
// Members for drawing poin int mMaxPoints; // # points which can be drawn int mPoi πtwi dth ; // point width int mMinPointwidth; // minimum point width int mSpaceWidth; // width of space between points int mCurPoint; // current point # int mPointsRead; // total points read in int mPointsPerCyc; // total points to read before wrap
int mDrawingwid; // width of actual drawing area
// General drawing vars double mxscale; double mYscale; doub e mYscale_mv; double mYscale_Cπts; double mxoffset; double mYoffset; int mHeight; int wi dth ; int mPrevwi dth ; int mY ax ; ong mMaxHrY; long mMinHrY;
}; // end of class CWebEcg
#endif //_WEBECG_H_
// webEcg.cpp : Implementation of CWebEcg
#include "stdafx.h1
#i ncl ude "webEcgCoπtrol . "
♦include "webEcg.h"
#i ncl ude "stdio.h" #i ncl ude "DemodECG.h" #i ncl ude "QRS.h"
const COLORREF cnYello = RGB( 255, 255, const COLORREF cnRed = RGB( 255, 0, const COLORREF cnGreen = RGB( 0, 255, const COLORREF cnPurp = RGB( 200, 0, 200 ) const COLORREF cnBlue = RGB( 0, 0, 255 ) const COLORREF cnLtBlu = RGB( 50, 100, 255 ) const COLORREF cnBlack = RGB( 0, 0, 0 )
HRESULT CWebEcg: :Firev ewChangeO if Cm_bInPlaceActιve) {
// Active if Cπ hWndCD != NULL) return C: :InvalidateRectCm_hwndCD, NULL, FALSE)) ? S OK : E_FAIL- // window based ^ A1Ll "
if (m_splnPlaceSite != NULL) . return m_splnPlaceSιte->InvalιdateRectCNULL, FALSE); // wi ndowl ess
}
// inactive
SendOnvi ewChange CDVASPECT_C0NTENT) ; return S_OK; }
LRESULT cwebEcg: :OnLButtonDowπCuiNT uMsg, PARAM wParam, LPARAM lparam, BOOL & b Handled)
POINTS clickPos;
ClickPos = MAKEPOINTSCl Param); if C CClickPos.y >= m_rctFreezeButton.top) && CClickPos.y <= m_rctFreezeButt on. bottom) &&
CClickPos.x >= m_rctFreezeButton.left) && CClickPos.x <= m_rctFreezeButt on. right) )
{ π bFrozen = !m_bFrozeπ;
// Fire_ClickC);
Firevi ewChange ); } return 0;
}
HRESULT cwebEcg: :OnDra C ATL_DRAWINFO& di ) ifC bDrawECG ) return drawECGC di ); else return drawBPMPointsC di );
} // end of OnDraw
HRESULT cwebEcg: :drawECGC ATL_DRAWINFO& di ) unsigned long i; double y; long ypos; long xPos; long StartXPos[2] ; long StopXPos[2] ; long LeftEdge; static long NextStartPos=0; bool wrapped; char buf[80] ;
HRESULT Result; doub e WorkMin; doub e workMax; doub e Overshoot; static SIZE BPMsize; static ATL_DRAWINFO PreVDI;
/*
// Handy little trick for very simple debugging output.
// writes whatever you want directly to the screen
HDC ScreenDC;
ScreenDC = ::GetDCC0); sprintfCbuf,"%d - %d ".π dwStartDrawing, m_dwStopDra
g) ;
SetBkModeCscreenDC, OPAQUE);
TextOutCScreenDC,0,0,_τCbuf),strlenCbuf));
ReleaseDCCScreenDC) ;
V if CC!m_bRecording) && CmJiwndCD) && Cm_bMicrophoneNotServer)) π bRecording = true;
WAVEFORMATEX waveformat;
// set up wave recording. waveformat. wFormatTag = WAVE_FORMAT_PC ; waveformat. n hannels = 1; waveformat. nSamplesPerSec = SAMPLE_FREQ; waveformat. nAvgBytesPerSec = SAMPLE_FREQ; waveformat. nβlockAlign = 1; waveformat.wBitsPerSample = 8; waveformat. cbsize = 0;
Result = wavelnOpen C&m_hwaveln , WAVE_MAPPER, &waveformat, CDWORD) m_hwndCD, 0, CALLBACK_WINDOW) ; } if Cm_dMaxmV > m_dMinmv) workMax = π dMaxmv; workM n = m_dMinmv; else if Cm_dMaxmV = π dMiπ V) workMax = m_dMaxmv + 0.5; workM n = πudMaxmv - 0.5;
} else
{ workMax = m_dMinmv; workMin = m_dMaxmV; } Overshoot = CworkMax - workMin)/20.0;
RECT& re = *CRECT*)di.prcBouπds; if Cπ pCardioGramPoiπts = NULL) m_pCardioGramPoints = newCPOINT[m_dwCardioGramLength]) ; mPrevwidth = -1; // Force following check to reload x positions
if CmWidth != mPrevw dth) mHeight = re. bottom - re. top + 1;
// Make room for Freeze/Unfreeze button mHeight -= FREEZE_HEIGHT; mwidth = re. right - re. left + 1;
// Multiply original value by these mxscale = Cdouble)mwidth/Cdouble)m_dwCardioGramLength; mγscale_mv = -CmHe ght)/CworkMax - workMin + C2*OverShoot)) ; // +/- 2mV
// Set mYscale_Cnts to counts, not mv mYscale_Cnts = mγscale_mv / 40.0;
// Add these to the result xoffset = re. left;
//mvoffset = re. top + mHeight/2; , • • .. η u
// Algebraically derived. Don t ask me to explain it... In my logbook
1-29-1999
// CActually, I have "T + .2*Scale" there, but since scale is negative, we have to . , ..,
// subtract instead of add) mYoffset = Crc.top - CθverShoot*mYscale_mv)) - workMax * C-Crc. bottom - re. top + l)/(workMax - WorkMin + C2*θverShoot))) ;
// Recalculate X positions of all of the Cardiogram points, for Ci=0; i<m_dwCardioGramLength; i++) π pCardi oGra Poi nts [i ] . x = CI oπg) Ci *mxscal e+mxof set) ; } mPrevwidth = mwidth;
HDC workDC; HBΓΓMAP workBitmap; HBITMAP origworkBitmap;
// Hold onto Cand re-use) workDC and WorkBitmap if we can, but rebuild them
// if anything in the Drawlnfo changes. if CmemcmpCCvoid *)&di , Cvoid *)&PrevDI, sizeof PrevDI) != 0)
Deleteobject(m_hdcworkDC) ; DeleteObιect0n_hbmpworkBitmap) ; m_hdcwor DC = CreateCompatibleDCCdi .hdcDraw); m_hbmpworkBitmap = CreateCompatibleBitmapCdi .hdcDraw, mwidth, mHeight); // Something weird has happened - redraw the entire screen. m_dwStartDrawing = m_dwStopDrawi ng + 1; if Cm_dwStartDrawing == m_dwCardioGramLength) m_dwStartDrawing = 0; workDC = m_hdcworkDC;
WorkBitmap = m_hbmpworkBitmap; memcpyCCvoid *)&PrevDI, Cvoid *)&di , sizeof PrevDI) ;
OrigworkBitmap = CHBlTMAP)SelectObjectCworkDC, WorkBitmap);
SetBkColorCworkDC, m_clrBackColor) ; SetTextColorCworkDC, m_clrGridColor) ;
HPEN OrigPen;
HBRUSH OrigBrush;
LOGBRUSH BrushDesc; BrushDesc.lbStyle = PS_SOLID; BrushDesc. IbColor = m_clrBackColor;
OrigBrush « CHBRUSH)SelectObjectCworkDC, CreateBrushlnd rectC&BrushDesc)) ; OrigPen = CHPEN)SelectObjectCworkDC, CreatePenCPS_SOLID | PS_INSIDEFRAME, 0, BrushDesc. IbColor)) ;
// StopXPos[0] is the most recent point's position if Cm_dwStopDrawing > m_dwStartDrawing)
{ wrapped = false;
StartXPos[0] = NextStartPos;
Stopχpos[0] = Clong)Cm_dwStopDrawing * mXscale + mxoffset);
Rectangle CworkDC, Startχpos[0]-1, re. top,
StopXPos[0]+l, re. bottom - FREEZE_HEIGHT) ; . . . // GraD tne last vertical line of the previous section so we can merαe w ith it. 3
LeftEdge = Cstartχpos[0]?StartXPos[0]-l:0) ;
BitBltCworkDC, LeftEdge, re.top, 1, mHeight, di. hdcDraw, LeftEdge, re.top, SRCCOPY) ;
} else
{ wrapped = true;
StartXPos[0] = re. left;
StopXPos[0] = Cloπg)Cm_dwStopDrawιng * mxscale + mxoff set) ;
StartXPos[l] = NextStartPos;
StopXPos[l] = re. right;
RectaπgleCworkDC, StartXPos[0]-5, re. top,
StopXPos[0]+5, re. bottom - FREEZE_HEIGHT) ; RectangleCworkDC, StartXPos[l]-5, re. top,
StopxPos[l]+5, re. bottom - FREEZE_HEIGHT) ; // Grab the last vertical line of the previous section so we can merge w ith it. „ . ,., _ «
LeftEdge = CStartχpos[l]?StartXPos[l]-l:0) ; BitBltCworkDC, LeftEdge, re. top, 1, mHeight, di. hdcDraw, LeftEdge, re. top,
SRCCOPY) ;
DeleteObjectCSelectObjectCworkDC, OrigBrush)) ;
// Now draw the grid in GridColor double LowAxis; double HighAxis;
LowAxis = WorkMin;
HighAx s = workMax; while CCLowAxis - m_dstepmv) >= CworkMin - Overshoot))
LowAxis -= m_dstepmv; while CCHighAxis + m_dstepmv) <= CworkMax + Overshoot))
HighAxis += m_dstepmv;
DeleteObjectCSelectobjectCworkDC, CreatePenCm_nGridStyle, 0, m_clrGridColor)
)); if Cwrapped)
// oκ, now draw the Cardiogram in ForeColor for Ci=Cm_dwStartDrawing?m_dwStartDrawing-l:0); I < m_dwCardιoGramLength
; i++) m_pCardioGramPoiπts[i].y = (long)Cm_pCardioGram[i] * mYscale_Cπts + m_pCardioGramPoiπts[i] .x = OongXi * mxscale + mxoffset); m_pCardioGramPo πts[m_dwCardioGramLength-l] .x = re. right; DeleteObject SelectObjectCworkDC, CreatePenCPS_SOLID, m_nForewidth, m_cl
PolylineCworkDC, &Cm_pCardioGramPoints[m_dwStartDrawing]) , m_dwCardioGra mLength - m_dwStartDrawing); .
// OK, now draw the Cardiogram in ForeColor for the wrapped section for Ci=0; i <= m_dwStopDrawing; i++) m_pCardioGramPoints[i] .y = Clong)Cm_pCardioGram[i] * mYscale_Cπts + m_pCardioGramPoints[i] .x = Clong)Ci * mxscale + mxoffset); m_pCardioGramPoints[m_dwStopDrawiπg] .x = Stopχpos[0]; PolylineCworkDC, m_pCardioGramPoints, m_dwStopDrawing + 1);
} else
// Horizontal lines for Cy=LowAxis; y<=HighAxis; y+=m_dstepmv) yPos = Clong)Cy*mYscale_mV+mYoffset);
DrawLineCworkDC, StartXPos[0] , yPos, StopXPos[0]+l, yPos) ;
// vertical lines for Ci=m_dwStartDrawing; i <= m_dwStopDraw πg; i++) i Cm_pverticalBar[i] & 1) xPos = OongXi * mxscale + mxof set);
DrawLineCworkDC, xPos, re. top, xPos, re. bottom - FREEZE_HEIGHT) ;
}
// OK, now draw the Cardiogram in ForeColor for Ci=Cm_dwStartDrawing?m_dwStartDrawing-l:0) ; i <= m_dwStopDrawing; i+ +)
{ m_pCardioGramPoints[i] .y = Clong) Cm_pcard oGram[i] * mYscale_Cnts + mYoff set) ; m_pCardioGramPoints[i] .x = Clong) Ci * mxscale + mxoffset); m_pCardioGramPoints[Cm_dwStartDrawing?m_dwStartDrawιng-l:0)] .x = StartXP os[0]-l; m_pCardioGramPoints[m_dwStopDrawing] .x = StopXPos[0];
DeleteObjectCSelectObjectCworkDC, CreatePenCPS_SOLID, m_nForewidth, m_cl rForeColor))) ;
Polyl neCworkDC, &Cm_pCardi oGra Poi πts [ Cm_dwStartDrawi ng?m_dwStartDrawi n g-l:0)]), m_dwStopDrawing - Cm_dwStartDrawing?m_dwStartDrawing-l:0) + 1);
// SetPixelvCworkDC, m_pCardioGramPoints[m_dwStopDraw ng] .x,m_pCard i oGramPoi nts[m_dwStopDrawing] .y,m_cl rForeColor) ;
// Now draw the grid labels, outlined in BackColor SetTextAlign CworkDC, TA_LEFT); SetBkModeCworkDC, TRANSPARENT); SetTextColorCworkDC, m_clrBackColor) ; for (y=LowAxis; y<=HighAxis; y+=m_dstepmv) yPos - Clong)Cy*mYscale_mv+mYof set); sprintfCbuf, "%5.2fmv",y);
TextOutCworkDC, rc.left+9, yPos, _TCbuf) .strlenCbuf)) ;
TextOutCworkDC, rc.left+11, yPos , _TCbuf) , strlenCbuf)) ;
TextOutCworkDC, rc.left+10, yPos-1, _TCbuf) .strlenCbuf)) ;
TextOutCworkDC, rc.left+10, yPos+1, _TCbuf) .strlenCbuf)) ;
SetBkModeCworkDC, TRANSPARENT);
SetTextColorCworkDC, m_clrGridColor) ; for Cy=LowAxis; y<=HighAxis; y+=m_dstepmv) yPos = Clong)Cy*πιYscale_mv+mYoffset) ; sprintfCbuf,"%5.2fmv",y);
TextOutCworkDC, rc.left+10, yPos, _TCbuf) .strlenCbuf)) ; }
// Copy the newly created regionCs) to the screen, if Cwrapped)
BitBltCdi. hdcDraw, re. left, re. top, stopχpos[0] - re. left + 1, Height, workD C , re .1 ef t , re . top , SRCCOPY) ;
BitBltCdi. hdcDraw, StartxPos[l], re. top, re. right - StartXPos[l] + l.mHeigh t , workDC , StartXPos [1] , re . top , SRCCOPY) ; else
LeftEdge = CstartXPos[0]?StartXPos[0]-l:0) ;
BitBltCdi .hdcDraw, LeftEdge, re. top, StopXPos[0] - LeftEdge + 1, mHeight workDC, LeftEdge, re. top,
SRCCOPY) ;
}
// Draw BPM in upper right HFONT OrigFont;
OrigFont = CHFONT)SelectObjectCworkDC, CreateFontC-MulDivCm nBPMFontSize.Get Devi ceCaps CworkDC, LOGPIXELSY) , 72) ,
O mWidth*/,
0/*escapement*/,
0/*ori eπtati on*/ ,
FW_NORMAL/*wei ght*/ ,
FALSE ltalic*/,
FALSE/*Underline*/,
FALSE/*Strikeθut*/,
DEFAULT_CHARSET,
OUT_TT_ONLY_PRECIS/*OutputPreci si on*/ ,
CLIP_DEFAULT_PRECIS , DEFAULT_QUALΓΓΎ, DEFAULT_PΓΓCH | FF_ROMAN, "Times New Roman"
)); sprintfCbuf " %d BPM" , m_nAvgBPM) ;
// sprintfCbuf, %d %ά BPM", m_nBPM, m_nAvgBPM );
SetBkModeCworkDC, OPAQUE); SetTextAl gnCworkDC, TA_RIGHT) ;
SetTextColorCworkDC, m_clrBackcolor);
SetBkColorCworkDC, m_cl rGridColor) ;
TextOutCworkDC, re. right, re. top, _TCbuf) , strlenCbuf));
// Fiαure out how big the biggest reading we will ever take is.
GetTextExteπtPoiπt32 CworkDC, _TC"999 BPMn) , strlenC"999 BPM"), &BPMsize); // GetTextExtentPoiπt32 ( orkDC, _TC"999 999 BPM"), strlenC"999 999 BPM"), & BPMsize);
Del eteobj ect CSelectobj ect CworkDC, OrigFont)); SetBkModeCdi . hdcDraw, TRANSPARENT) ;
Del eteob ect CSelectobj ect CworkDC, OrigPen)) ;
BitBltCdi .hdcDraw, re. right - BPMsize.ex + 1, re. top, BPMsize.ex, BPMsize.cy workDC, re. right - BPMsize.ex + 1, re. top,
SRCCOPY) ;
// Draw the sweep ng line
OrigPen = (HPEN)SelectObjectCdι .hdcDraw, CreatePenCPS_SOLlD, 2, RGBC255.255,
DrawLineCdi.hdcDraw, stopχpos[0]+3, re. top, StopXPos[0]+3, re. bottom - FREEZ E_HEIGHT) ;
Del eteobj ect CSelectob ect Cdi .hdcDraw, OrigPen)) ;
// Do not delete the returned Bitmap, since it is tracked as a member of thi s object.
Sel ectob j ect CworkDC , Ori gWorkBi tmap) ;
// Del eteobj ect CworkBi tmap); // HACKHACKHACK - Deleted elsewhere
// Del eteDC CworkDC); // HACKHACKHACK - Deleted elsewhere
/*
// Hack for drawing BPM numbers next to detection point.
// Probably needs to be removed for final version.
SetTextAl i gn Cdi . hdcDraw , TA_RIGHT) ;
SetBkMode Cdi . hdcDraw , TRANSPARENT) ; for Ci=π dwStartDraw ng; i <= m_dwStopDrawing; i++) if Cm_pverticalBar[i] & 254)
{ xPos = Clong) i * mxscale + mxoffset); yPos = Clong)Cm_pCardioGram[i] * mYscale_Cnts + mYoffset) ; sprintfCbuf ,"%d BPM", Cm_pvert calBar[i]»l) & 0x7F) ;
SetTextColorCdi .hdcDraw, _cl rBackColor) ;
Textout Cd .hdcDraw, xPos+1, yPos, _TCbuf) .strlenCbuf)) ;
Textout Cd .hdcDraw, χpos-1, yPos, _TCbuf) .strlenCbuf)) ;
TextOut Cdi .hdcDraw, xPos, yPos+1, _TCbuf) .strlenCbuf)) ;
Textout Cdi. hdcDraw, xPos, yPos-1, _TCbuf) .strlenCbuf)) ;
SetTextColorCdi .hdcDraw, m_cl rGr dColor) ;
TextOutCd .hdcDraw, XPOS, yPos, _τCbuf) .strlenCbuf)) ;
} V if Cm_bFrozen) strcpyCbuf, "unfreeze Display"); else
strcpyCbuf, "Freeze Display"); BrushDesc. IbStyle = PS_SOLID; BrushDesc. IbColor = π clrBackColor; OrigBrush = CHBRUSH)SelectObjectCd .hdcDraw, CreateBrushlndi rectC&BrushDesc)
) ;
OrigPen = CHPEN)SelectObjectCdi .hdcDraw, CreatePenCPS_SOLID I PS_INSIDEFRAME , 2, m_cl rGridColor)); m_rctFreezeButton.left = re. left; m_rctFreezeButtoπ. right = re. right; m_rctFreezeButton.top = re. bottom - FREEZE_HEIGHT; m_rctFreezeButton. bottom = re. bottom;
RectangleCdi .hdcDraw, m_rctFreezeButton.left, m_rctFreezeButton.top, m_rctFreezeButton . ri ght, m_rctFreezeButton . bottom) ;
SetTextColorCdi .hdcoraw, m_cl rGridColor) ;
DraWTextCdi .hdcDraw, _τCbuf) , strlenCbuf), &m_rctFreezeButtoπ, DT_CENTER I D T VCENTER I DT_SINGLELINE) ;
DeleteObjectCselectObjectCdi .hdcDraw, OrigPen)) ;
Deleteob ec CSelectobject(di .hdcDraw, OrigBrush));
m_dwStartDrawing = m_dwStopDrawing+l; if Cm_dwStartDrawing >= m_dwCardioGramLength) m_dwStartDrawing = 0; NextstartPos = re. left;
} else
NextstartPos = Stopχpos[0] + 1; } return S_OK; } // end of drawECG
HRESULT cwebEcg: :drawBPMPointsC ATL_DRAWINFO &di ) char buf [80] ;
HRESULT Result; stati c SIZE BPMsi ze ; static ATL_DRAWINFO PrevDI; stati c long maxTextwi dth = 0 ;
//-- -
// Turn on the microphone input if necess ifC C!m_bRecording) && Cπ hwndCD) && Cm_bMicrophoneNotServer) ) m_bRecording = true;
WAVEFORMATEX waveformat;
// Set up wave recording. waveformat.wFormatTag = WAVE_FORMAT_PCM; waveformat. nChannels = 1; waveformat. nSamplesPersec = SAMPLE_FREQ; waveformat. nAvgBytesPerSec = SAMPLE_FREQ; waveformat. nBlockAl gn = 1; waveformat.wBitsPerSa ple = 8; waveformat. cbsize = 0;
Result = wavelnOpenC &m_hwaveln, WAVE_MAPPER, &waveformat,
CDWORD) m_hwndCD, 0, CALLBACK_WIND0W) ;
} // end if to turn on wave recorder
// If no data yet, return
// "" if mBPMData . empty () ) return S_OK;
RECT & re = *CRECT*)di . prcBounds ;
// Recalculate dimensions, offsets if // width changes bool widthchanged = false; ifC mwidth != mPrevwidth ) widthchanged = true; mHeight = re. bottom - re. top; mwidth = re. right - re. left; mxoffset = re. left + 66.0; mYoffset = 0.0; mDrawingWid = mwidth - mxoffset; mPointwidth = mDrawingWid / CmBPMSampleCount +
CmBPMSampleCount - 1) * mSpacewidth); mPointwidth = max mMinPointwidth, mPointwidth ); mMaxPoints = mDrawingWid / CmPoiπtwidth + mSpacewidth); mPo ntsPerCyc = mBPMSampleCouπt * mMaxPoints; ifC mPointsRead >= mPointsPerCyc ) mPoiπtsRead = 0;
// Scale original values with these mxscale = Cdouble) CmPointwidth + mSpacew dth); mYseale = (double) (mHeight - mYoffset) / Cdouble) mMaxHR; mYmax = re. bottom; mMaxHrY = Clong) C CCdoubleXmMaxHR - mMaxHR * .85) * mYseale) + mYoffset ) ; mMi nHrY = Clong) C CCdoubl eXmMaxHR - mMaxHR * .65) * mYseal e) + mYoffset ) ;
} // end i f mwi dths don ' t match mPrevwi dth = mwi dth;
HBΓΓMAP workBi tmap ; HBITMAP ori gworkBi tmap ; HFONT ori qFoπt; HFONT I Sml Font ; HFONT lMedFont; HFONT 1 Bi Font; HDC workDC;
HPEN origPen; HBRUSH origBrush; LOGBRUSH brushoesc; brushoesc.lbstyle = PS_S0LID; brushDesc. IbColor = m_clrBackColor;
// Hold onto Cand re-use) workDC and // workBitmap if we can, but rebuild // them if anything in the Drawlnfo // changes. bool // — dcChanged— = fals~e; " ifC memcmpC Cvoid *) &di , Cvoid *) &PrevDI, sizeof PrevDI ) != 0 )
Del eteobj ec C mJidcworkDC );
DeleteObiectC m_hbmpworkBitmap ); mJidcworkDC = CreateCompatibleDCC di. hdcDraw ); m_hbmpworkBitmap = CreateCompatibleBitmapC di. hdcDraw, mwidth, mHeight )
dcChanged = true;
} // end if prev DC not = this workDC = m_hdcworkDC; workBitmap = mJibmpworkBitmap; memcpyC Cvoid *)&PrevDI, Cvoid *)&di , sizeof PrevDI ); origBrush = CHBRUSH) SelectObjeetC workDC, CreateBrushlndi rectC &brushθesc )
); origPen = CHPEN) SelectObjeetC workDC, CreatePenCPS_SOLID | PS_INSIDEFRAME
0, brushDesc. IbColor) ); origworkBitmap = CHBITMAP) SelectObjeetC workDC, workBitmap );
SetBkColorC workDC, m_clrBackColor );
axPoints ) );
datastart = 0; numPoi nts = mBPMData. cur Pos ) ;
} el se datastart = mBPMData. lastReadC) ; numPoints = m nC mMaxPoints, numPoints );
}
// numPoints will normally be < mPointsRead ifC numPoints < mPointsRead ) screenstart = CmPointsRead - numPoints) % mMaxPoints; else
screenstart = CmPointsPerCyc + CmPointsRead - numPoints)) % mMaxPoints;
} // end else numPoints > mPointsRead
rt * mxscale);
le; drawPointsC workDC, re, datastart, xStart, xEnd, numPoints );
// -
// But the new area to the screen
// int xwidth = numPoints * mxscale;
BitBltC di. hdcDraw, xStart, re. top, xwidth, mHeight, workDC, xStart, re. top, SRCCOPY );
} // end if not wrapped else
{
//
// Calculate bounding rectangles of both
// regions int xStart [2]; int xEnd [2]; int dataPoιnts[2]; dataPoiπts[0] = mMaxPoints - screenstart; dataPoints[l] = numPoints - dataPoints[0] ; xStart [0] = mxoffset + Cint) CscreenStart * mxscale); xEnd[0] = xStart [0] + dataPoiπts[0] * mxscale; xStart [1] = mxoffset; xEnd[l] = xStart [1] + dataPoιnts[l] * mxscale; int datstart2 = datastart; mBPMData. incrC datstart2, dataPoiπts[0] );
[0], dataPoiπts[0] ); drawPointsC workDC, re, datstart2, xstart[l], xEnd[l], dataPoints[l] );
// - —" -
// But the new areas to the screen int xwidth [2]; xwidth[0] = dataPoints[0] * mxscale; xwidth[l] = dataPointsϊl] * mxscale;
BitBltC di. hdcDraw, xStart[0], re. top, xwidth[0], mHeight, workDC, xstart[0], re. top, SRCCOPY );
BitBltC di. hdcDraw, xStart[l], re. top, xwidth[l], mHeight, workDC, xstartil], re. top, SRCCOPY );
} // end else wrapped
lMedFont = CreateFontC -MulDivC 10,
GetDeviceCapsC workDC, LOGPIXELSY ), 72 ) ,
0 Λmwidth*/,
0 Λescapemeπt*/,
0 orientation*/,
FW_NORMAL/*wei ght*/ ,
FALSE /*Italic*/,
FALSE Λunderline*/,
FALSE /*StrikeOut*/,
DEFAULT_CHARSET,
OUT_TT_ONLY_PRECIS ΛoutputPreci si on*/,
CLIP_DEFAULT_PRECIS , DEFAULT.QUALΓΓY, DEFAULT_PΓΓCH | FF_ROMAN, //"Times New Roman" "Arial"
); lBigFont = CreateFontC -MulDivC m_nBPMFoπtSize,
GetDeviceCapsC workDC, LOGPIXELSY ), 72 ) ,
0 Λmwidth*/,
0 Λescapemeπt*/,
0 Λorientation*/,
FW_NORMAL/*wei ght*/ ,
FALSE Λltalic*/,
FALSE Λunderline*/,
FALSE ΛstrikeOut*/,
DEFAULT_CHARSET,
OUT_TT_ONLY_PRECIS /*OutputPreci si on*/ ,
CLIP_DEFAULT_PRECIS ,
DEFAULT-QUALITY,
DEFAULT_PΓΓCH I FF_ROMAN, //"Times New Roman" "Arial"
); origFont = CHFONT) SelectObjeetC workDC, lBigFont ); SetTextAlignC workDC, TA^RIGHT );
("999 BPM"), &BPMsize ); maxTextwidth = maxC BPMsize.cy, maxTextwidth );
SetBkModeC workDC, OPAQUE );
// -
// Max HR at top left
//
DrawStringC workDC, ISmlFont, TA_LEFT, cnRed, rc.left+2, re. top, " AX" ); sprintfC buf, "%d", mMaxHR );
DrawStringC workDC, lMedFont, TA_RIGHT, cnRed, mxoffset-2, re. top, buf );
//
// 85 % of max
//— long hr = Clong) CCdouble) mMaxHR * 0.85);
DrawStringC workDC, ISmlFont, TA_LEFT, cnLtBlu, rc.left+2, mMaxHrY, "85%" ); sprintfC buf, "%d" , hr ) ;
DrawStringC workDC, IMedFont, TA_RIGHT, cnLtBlu, mxoffset-2, MaxHrY, buf );
DrawStringC workDC, ISmlFont, TA_LEFT, cnLtBlu, rc.left+2, mMinHrY, "65%" ); c r* L* -P "<^^" hr* ^ *
DrawStringC orkocl IMedFont, TA^RIGHT, cnLtBlu, mxoffset-2, mMinHrY, buf );
SetBkColorC workDC, m_cl rGridColor );
DrawStringC workDC, lBigFont, TA_RIGHT, m_clrBackColor, mxoffset - 2, re. bottom - BPMsize.cy, buf );
SetBkModeC di. hdcDraw, TRANSPARENT );
// Left border line DeleteObjectC SelectObjeetC workDC, CreatePenC m_nGridStyle, 1, cnBlue ) ) )
DrawLiπeC workDC, mxoffset-1, re. top, mxoffset-l, re. bottom );
SelectObjeetC workDC, origFont ); SelectObjeetC workDC, origPen ); SelectObjeetC workDC, origBrush );
DeleteObjectC ISmlFont ) DeleteObjectC IMedFont ) DeleteObjectC lBigFont )
// -
// But new area to screen /
BitBltC di. hdcDraw, re. left, re. top, mxoffset, re. bottom, workDC, re. left, re. top, SRCCOPY ); return S_OK;
} // end of drawBPMPoiπts
void CWebEcg: : drawPointsC HDC &dc,
RECT &rc, int datastart, int xStart, int xεnd, int numPoints ) {
HPEN blackPen = CreatePenC PS_SOLID | PS_INSIDEFRAME, 0, cnBlack )• HPEN redPen = CreatePenC PS_SOLID | PS_INSIDEFRAME, 0, cnRed );
HPEN gridPen * CreatePenC PS_SOLID I PS_INSIDEFRAME , 0 , cnLtBlu ) ;
HPEN greenPen = CreatePenC PS_SOLID I PS_INSIDEFRAME , 0, cnGreen ) ;
HPEN purppen = CreatePenC PS_S0LID I PS.INSIDEFRAME, 0, cnPurp ) ;
HPEN origPen;
HBRUSH bkβrush = CreateSolidBrushC m_cl rBackColor ) ;
HBRUSH greenβrush = CreateSolidBrushC cnGreen ) ;
HBRUSH redBrush = CreateSolidBrushC cnRed ) ;
HBRUSH purpβrush = CreateSol dBrushC cnPurp ) ;
HBRUSH origBrush;
POINT points [3] ; origBrush = CHBRUSH) SelectObjeetC dc, bkBrush ) ; origPen = CHPEN) SelectObjeetC dc, blackPen ) ;
RectangleC dc, xStart, re. top, xEnd, re. bottom );
SelectObjeetC dc, gridPen ); int linestart = xStart - mSpacewidth; linestart = max mxoffset, linestart );
DrawLineC dc, linestart, mMaxHrY, xEnd, mMaxHrY ); DrawLineC dc, linestart, mMinHrY, xEnd, mMinHrY );
int dataStop = datastart; mBPMData. incrC dataStop, numPoints );
// - —
// Draw new points
// - — int x; int y; forC int i = datastart, xl = 0; i != dataStop; mBPMData. incrC i ), xl++ ) x = xStart + Cint) Cxi * mxscale); y = mYmax - Cint) CmBPMData[i] * mYseale + mYoffset); if( y < 0 || y >= mYmax ) continue;
else if y < mMaxHrY ) // HR too high
SelectObjeetC dc, redBrush ); SelectObjeetC dc, redPen ); downArrowC points, x, y, mPointwidth ); PolygonC dc, points, 3 ); lse // HR just right
SelectObjeetC dc, greenBrush );
SelectObjeetC dc, greenPen );
RectangleC dc, x, y, x + mPointwidth, y + mPointwidth );
/ end for thru bars
// update ring buffer index to indicate
// we've read numPoints
//- mBPMData.updateeyC numPoints );
//--- "
// Clean up
SelectObjeetC dc, origBrush ); SelectObjeetC dc, origPen );
Deleteobject bkBrush ); DeleteobjectC redBrush ); DeleteobjectC greenBrush ); DeleteobjectC purpBrush );
DeleteobjectC gridPen ); DeleteobjectC blackPen ) ; DeleteobjectC redPen ); Del eteobjectC greenPen ); DeleteobjectC purpPen );
} // end of drawPoints
void CWebEcg: :upArrowC POINT *pPoints, int x, int y, int wid ) pPoints .x x; pPoiπts • y y + wid; pPoints[i; .X x + wid / 2; ppointsϊl" • y y; pPoints .X X + wid; pPoints • y y + wid;
} // end of upArrow
void CWebEcg: -.downArrowC POINT *pPoints, int x, int y, int wid )
bEcg: :0nwim0penCuiNT uMsg, WPARAM wParam, LPARAM iParam, BOOL& bHandl
// Should have LOTS of memory checking error handling all through here... m_pFullwav = NULL; for Ci=0; i<4; i++) m_pwavBuf[i] = newCunsigned char[WORK_BUFFER_SIZE]) ; m_pwaveHdr[i ->lpData = Cchar *)m_pwavBuf[i] ; m_pWaveHdr[i ->dwBufferLength = WORK_BUFFER_SIZE; m_pwaveHdr[i ->dwBytesRecorded = 0; m_pwaveHdr[i >dwuser = 0; m_pwaveHdr[i ]->dwFlags = 0; m_pwaveHd 'rr[_ij-> ►cdwLoops = 1; m_p rwaveHdr[_ii]->lpNext = NULL; m_pwaveHdr[i]->reserved = 0; wavelnPrepareHeader Cm_hwaveln, m_pwaveHdr[i] , sizeof CWAVEHDR)); wavelnAddBuffer C _hwaveln, m_pwaveHdr[i] , sizeof CWAVEHDR));
}
// Start sampling m_dwFullwavLength = 0;
MMRESULT mmResult = waveInStartCm_hWavein) ; return S_OK;
}
HRESULT cwebEcg: :OnwimDataCuiNT uMsg, WPARAM wParam, LPARAM iParam, BOOL& bHandl ed) const unsigned int OverlapPts = 4; const unsigned int DiscardPts = 4; static int sampleCount; static signed char wavedata[wθRK_BUFFER_SIZE+OverlapPts*DECIMATlON] ; static short lpDataout[woRK_BUFFER_siZE/DEClMATION + OverlapPts]; int iDataOutS ze; unsigned long i ; bool bSo ethingThere; bool initPass = true; bSomethingThere = false; if Clπ bFrozen) { for Ci=0; I'<CCPWAVEHDR) 1 Param) ->dwBytesRecorded; i++)
, , J f C CCunsigned char)CCCPWAVEHDR) 1 param) ->lpData[i]) <= 128-m n olu meThreshold) | |
,. ,_,. , CCunsigned char)CC(PWAVEHDR) 1 Param) ->lpData[i]) >= 128+m_nVolum eThreshold) )
{ bSomethingThere = true;
break; } }
} if (bSomethingThere) if( initPass )
// Do first time initialization here initPass = false;
// Only do this the first time we get something past the volume thre shold.
// Setting m_dwStopDrawi ng to -1 will work properly as long as the f ol 1 owi ng
// code moves m_dwStopDrawi ng forward by filling in the new data. I f you do
// not have any new data and let OnDraw try to work with m_dwStopora w ng=-l,
// you get a crash.
// A so, -1 is an odd value to push into an UNSIGNED long. Fortunat ely. it
// has a value of all l's, and adding one to that will roll it over to all O's,
// so it has the essential -l'ness that we need. m_dwStopDrawi ng = -1;
for Ci=0; i<WORK_BUFFER_SIZE; i++) signed char p = Csigned char) CCPWAVEHDR) 1 param) ->1 pData [i ] ; signed char q = (signed char) (p - 128); signed char r; wavedata[i+overlapPts*DECiMAT ON] = (signed char) C CCPWAVEHDR) iParam )->lpData[i] - 128); r = wavedata[i+OverlapPts*DECIMATION] ; }
DemodECG O pDataOut , &i DataoutSi ze ,
Cchar *)wavedata, W0RK_BUFFER_SIZE + OverlapPts*DECIMATlON,
80,
1520) ;
// we are done with this buffer. Return it to the system as soon as
// possible. wavelnAddBuffer C _hwaveln, CPWAVEHDR) iParam, sizeof CWAVEHDR));
// First several ECG points are garbage.
// Save the last several ECG points worth of samples to prepend to the
// next buffer. That way the first several ECG points of this new buffe r
// are garbage and discarded COK, since they are the last several return ed
// this time), if COverlapPts)
// OK, some explanation here...
// we want to move the LAST OverlapPts worth of samples to the front
// of wavedata. The end of wavedata is at:
// Cremember - each ECG point is equivalent to DECIMATION samples)
45
// wavedata+WORK_BUFFER_SIZE+ verlapPts*DECIMAT ON
// Cactually, that is the address of the first byte after the end of // wavedata, but if you wanted to see the last 1 byte of wavedata, y ou
// would go to that address-1, and if you wanted to see the last 10 bytes
// you would go to that address-10, etc. This makes sense when you read
// the following)
// But we want to start OverlapPts worth of samples before that, so:
// wavedata+WORK_BUFFER_SIZE+OverlapPts*DECIMATION-θverlapPts*DECIMA
TION
//
// whi ch simpl ifies to:
//
// wavedata+WORK_BUFFER_SIZE
MoveMemoryCwavedata, wavedata+W0RK_BUFFER_SIZE, Overl apPts*DECIMATIO
N) ;
}
// Fi rst several returned points are garbage. . . if CDi scardPts) iDataoutSize -= Di scardPts ;
MoveMemory I pDataOut , &0 pDataOut [Di scardPts] ) , i DataoutSi ze * si zeof ( lpDataθut[0])) ;
> if Cπ bconnectedToServer) sendCm_sckLocalSocket, Cconst char *)lpDataθut, iDataoutSize*2, 0); }
NewRawDataCIpDataOut, iDataoutSize) ;
} else
{ wavelnAddBuffer Cπ hwaveln , CPWAVEHDR) l param, si zeof CWAVEHDR)) ; return S_OK;
}
HRESULT CWebEcg: :OnwimClose(UINT uMsg, WPARAM wParam, LPARAM iParam, BOOL& bHand led)
{
// Never gets called in time if wavelnclose is called from -CwebEcg...
//MessageBoxC"Onwimclose","NOTE",MB_OK);
// wavelnunprepareHeaderCm_hwaveln, π pwaveHdrl, sizeofCWAVEHDR)) ;
// waveInunprepareHeaderCm_hwaveIn, m_pwaveHdr2, sizeofCWAVEHDR)) ;
// delete m_pwaveHdrl;
// delete m_pwaveHdr2;
// delete n pwavBuf[0] ;
// delete m_pwavBuf[l] ; return S_OK;
HRESULT cwebEcg: :OnwomθpeπCUINT uMsg, WPARAM wParam, LPARAM iParam, BOOL& bHandl ed)
{ return S_OK;
HRESULT cwebEcg: :OnwomDoneCuiNT uMsg, WPARAM wParam, LPARAM 1 aram, BOOL& bHandl ed)
{ return S_OK;
HRESULT cwebEcg: :OnWomCloseCuiNT UMsg, WPARAM wParam, LPARAM lparam, BOOL& bHand led)
{ return S_OK; }
STDMETHODIMP CWebEcg : : get_Gri dColorCOLE_COLOR * pVal)
// TODO: Add your implementation code here *pval = m_cl rGridColor; return S_OK; }
STDMETHODIMP CWebEcg: : put_GridColor CθLE_COLOR newVal) // TODO: Add your implementation code here if CFireOnRequestEditCdispidGridColor) = S_FALSE)
{ return S_FALSE;
} m_cl rGridColor = newval; setDirtyCTRUE);
Fireonc :hnιangedCdispidGridcolor) ; Fi revi ewChangeO ; return S_OK;
}
STDMETHODIMP CWebEcg: :get_GridStyleClong * pval)
// TODO: Add your implementation code here *pval = m_nGridStyle; return S_OK; }
STDMETHODIMP CWebEcg: :put_GridStyle Clong newval)
// TODO: Add your implementation code here if CFireOnRequestEditCdispidGridStyle) == S_FALSE) return S_FALSE;
m_nGridStyle = newval; SetDirtyCTRUE);
Fi reOnChangedCdi spidGridstyle) ; Fire i ewChangeO; return S_OK; }
STDMETHODIMP cwebEcg: :get_Mi nmv Cdouble * pval)
// TODO: Add your i plementation code here *pval = m_dMi πmv; return S_OK; }
STDMETHODIMP CwebEcg : : ut_Mi nmv Cdoubl e newval) if CFi reOnRequestEditCdi spi dMi nmV) = S_FALSE)
{ return S_FALSE;
} m_dMi nmv = newval ;
SetDi rtyCTRUE) ;
Fi reOnc :hhangedCdi spi dMi nmv) ; Fi reviewChangeC) ; return S_OK;
}
STDMETHODIMP cwebEcg: : get_MaxmvCdouble * pval)
// TODO: Add your implementation code here *pval = πudMaxmv; return S_OK; }
STDMETHODIMP CWebEcg: : put_Maxm Cdouble newval) if CFireonRequestEditCdispidMaxmV) = s_FALSE) return S_FALSE; } m_dMaxmv = newval ;
SetDi rtyCTRUE) ;
Fi reOnc :hhangedCdi spidMaxmv) ; Fi revi ewChangeO ; return S_OK;
}
STDMETHODIMP CWebEcg: :get_StepmvCdouble * pval)
// TODO: Add your implementation code here *pval = m_dstepmv; return S_OK;
STDMETHODIMP CWebEcg: :put_stepm Cdouble newval) if CFireonRequestEditCdispidStepmv) == S_FALSE)
ια_pCardioGram[i] « 0; m_pVerticalBar[i] « 0;
} mBPMSampleCount = newval * 4; // 4 samples per sec mPointsPerCyc = mBPMSampleCount * mMaxPoints; i !mPointsPerCyc ) mPointsPerCyc = mBPMSampleCount; mBPMData. resize mBPMSampleCount );
SetDirtyCTRUE); , _, ^ Fi reOnChangedCdi spidDispiaySeconds) ; Fi revi ewChangeO; return S_OK;
} // end of put_Di spi aySeconds
STDMETHODIMP CWebEcg: : get_volumeThreshol dCshort * pval)
// TODO: Add your i plementation code here *pval = m_nvolumeThreshold; return s_oκ; }
STDMETHODIMP CWebEcg: : put_volumeThreshol dCshort newval)
// TODO: Add your implementation code here if (FireonRequestEditCdispidvolumeThreshold) = S_FALSE)
{ return s_FALSE;
} m_nvolumeThreshold = newval;
SetDirtyCTRUE);
Fi reOnchangedCdi spi dvol u eThreshol d) ;
Fi reviewChangeO ; return S_OK;
}
STDMETHODIMP CWebEcg: :get_Fi lteri ngCshort * pval)
// TODO: Add your implementation code here *pval = m_nF ltering; return S_OK;
STDMETHODIMP CWebEcg: : put_Fi lteri ngCshort newval)
// TODO: Add your implementat on code here if CFireOnRequestEdit Cdi spi dFi ltering) == S_FALSE) return s_FALSE; } m_nFi ltering = newval;
SetDirtyCTRUE);
Fi reθ;ιChanged Cdi spi dFi 1 teri ng) ; Fi revi ewChange O ; return S_OK; }
STDMETHODIMP CwebEcg: : get_BPMFoπtSizeCshort * pval)
// TODO: Add your impl ementation code here *pval « m_nBPMFontSize; return S_OK; }
STDMETHODIMP CWebEcg : : put_BPMFontSizeCshort newval)
// TODO: Add your implementation code here if CFi reOnRequestEditCdi spidBPMFontSize) = S_FALSE) return S_FALSE; } m_nBPMFontSize = newval ;
SetDirtyCTRUE);
Fi reOnchangedCdi spidBPMFontSize) ;
Fi reviewChangeC); return S_OK; }
STDMETHODIMP CWebEcg: :get_DetectPercentCdouble * pval)
// TODO: Add your implementation code here *pval = m_dDetectPercent; return S_OK;
}
STDMETHODIMP CwebEcg: :put_DetectPercentCdouble newval)
// TODO: Add your impl ementati on code here i f CFi reOnRequestEditCd spi dDetectPercent) == S_FALSE) return S_FALSE ; } m_dDetectPercent = newval ; mBPM.DetectPercentC newval );
SetDirtyCTRUE);
Fi reOnc:hhSangedCdi spidDetectPercent) ; Fi rev ewChangeO ; return S_OK;
}
STDMETHODIMP cwebEcg: :get_ServerAddressCBSTR * pval)
// TODO: Add your i plementat on code here *pval = m_bstrServerAddress. CopyO; return S_OK;
STDMETHODIMP cwebEcg: :put_serverAddressC BSTR newval )
// TODO: Add your implementation code here
USES_CONVERSION ; // Seems necessary for a call to W2A later to work. ifC Fi reOnRequestEditCdispidServerAddress) = S_FALSE ) return S.FALSE; } m_bstrServerAddress = newval ; if m_bConnectedToServer ) shutdown C nusckLocal Socket , 1 ) ; cl osesocketC nusckLocal Socket ) ; m_bConnectedτoServer = fal se;
} if m_bstrServerAddress. LengthO < 7 ) return S_OK; if m_bMi crophoneNotServer ) ConnectToServerC) ; setDi rtyC TRUE ) ;
Fi reOnchanged di sp dServerAddress ) ;
Fi revi ewChange C) ; return S_OK;
}
STDMETHODIMP CWebEcg: :get_MicrophoneNotServerCshort * pval)
// TODO: Add your implementation code here *pval = π bMicrophoneNotServer; return S_OK; }
STDMETHODIMP CWebEcg: :put_MicrophoneNotServerCshort newval)
// TODO: Add your implementation code here if CFireOnRequestEditCdispidMicrophoneNotServer) = S_FALSE) return S_FALSE; } if Cπ bMicrophoneNotServer && newval)
// Both true — no change -- don't care } else if C ! Cm_bMicrophoneNotServer || newval))
// Neither true — no change — don't care el se {
// State changed - adjust as necessary . if C _bMi cropnoneNotServer)
{
// was running from microphone, now from net // must shut down microphone int i ;
wavelnResetCπuhwaveIn) ; wavelnCloseCπuhwaveln) ;
// sleepCC1.0/SAMPLE_FREQ)*(2*WORK_BUFFER_SIZE)*1000); // Give ς stem time to shut down whatever. y // sleepCC1000/SAMPLE_FREQ)*C2*wθRK_BUFFER_SiZE)); // Give syst em time to shut down whatever.
// SleepCC1000*2*WORK_BUFFER_SIZE)/SAMPLE_FREQ); // Give syst em time to shut down whatever.
SleepCC2000*WORK_BUFFER_SIZE)/SAMPLE_FREQ); // Give system time to s hut down whatever. for Ci=0; i<4; i++) wavelnunprepareHeaderCπuhwaveln , m_pwaveHdr[i ] , sizeof CWAVEHDR)) delete m_pwaveHdr[i] ; del ete πupwavβuf [i ] ; } } el se
// was runni ng from net, now from mi crophone ifC πubstrServerAddress . Length O >= 7 )
ConnectToServerC) ; πubRecordi ng = false; } πubMi crophoneNotServer « newval ;
SetDi rtyCTRUE) ;
Fi reOnchanged Cdi spi dMi crophoneNotServer) ;
Fi revi ewChange C) ;
} return S_OK;
} void CWebEcg: :NewRawDataC signed short * RawData, unsigned long NumData ) static int SampleCount; unsigned long i ; short CurrFilteredPoint; static unsigned long SamplesSinceQRS; static bool InitPass = true; static short Last2SecsFiltered[ECG_FREQ*2] ; static short PrevBPM;
// nudwStopDrawing should always point to the // most recently inserted CardioGram Point, signed char workReading;
forC i=0; i < Cunsigned long)NumData; i++ )
// CharFilter is #defined macro in QRS.h that converts input into // SIGNED character, and pegs value at 127 or -128 boundaries. workReading = CharFilterC RawData[i] );
// The following set of filters is in the QRS files, and is // taken from a routine in a book on biomedical signal processing. // As we played with the signal, certain parts were changed and/or // removed.
CurrFilteredPoint - LowPassFil erC WorkReading ); ifC πunFiltering = 1 ) workReading = CharFilterC CurrFilteredPoint );
CurrFilteredPoint = HighPassFilterC CurrFilteredPo nt ); if πunFiltering = 2 ) . workReading = CharFilterC CurrFilteredPoint ); workReading += 55;
CurrFilteredPoint = DerivativeC CurrFilteredPoint ); ifC πunFiltering == 3 ) . . . workReading = CharFilterC CurrFilteredPoint );
CurrFilteredPoint = Square C CurrFilteredPoint ); ifC πunFiltering = 4 ) workReading = CharFilterC CurrFilteredPoint );
// CurrFilteredPoint = MoviπgwindowIntegralCCurrFilteredPoint) ; if CπunFiltering >= 5) WorkReading = CharFilterCCurrFilteredPoint);
// Store the reading in the CardioGram
// πudwStopDrawiπg should always point to the most recently inserted Car dioGram Point. ifC mbDrawECG ) πudwStopDrawi ng++; if CπudwStopDrawi ng >= πudwCardioGramLength) πudwStopDrawing = 0; m_pCardioGram[m_dwStopDrawing] = WorkReading;
// Flag the axis, if necessary if CSa pleCount == 0) πupvertical Bar [πudwStopDrawing] = 1; else πupvertical Bar [πudwStopDrawing] = 0;
SampleCount++; if CSampleCount >= ECG_FREQ) SampleCount = 0;
} // end if mbDrawECG
// Detect QRS complexes
// If this seems overly simplified, set Filtering property to 5 and
// take a look at the fully filtered data.
// First, find max value in last 2 seconds of data. ΠUΠBPM = mBPM.updateC CurrFilteredPoint ); πunAvgBPM = mBPM.AvgBPMO ;
} // end for thru data
ifC !mbDrawECG )
mCumS mps NumData; ifC mCumSamps >= mSampsPerBPMPt ) int minHr = minC πunAvgBPM, mMaxHR ) ; mBPMData. push_backC minHr ) ; mCumSamps = 0;
// mPointsRead tells us where to put // the point on the screen when the // number of screen points is less // than the number of data points ++mPointsRead; ifC mPointsRead >= mPointsPerCyc ) mPointsRead = 0;
Fi revi ewChange );
} // end if time to draw again
} // end if ! drawECG else
Fi reviewChangeO;
} // end of NewRawData voi d cwebEcg : : ConnectToServerC)
USES.CONVERSiON; πubConnectedToServer = true; nusckLocal Socket = socketCPF_INET, SOCK_STREAM, 0) ; rrusckadrRemoteSocketAddress . s n_family = PF_INET; πusckadrRemoteSocketAddress . s n_port = htonsC4321); πusckadrRemoteSocketAddress . s n_addr.s_addr = GetAddrCw2ACm_bstrServerAddres s)); πusckadrRemoteSocketAddress. si n_zero[0] = 0 πusckadrRemoteSocketAddress. sin_zero[l] = 0 πusckadrRemoteSocketAddress. sin_zero[2] = 0 πusckadrRemoteSocketAddress. si n_zero[3] = 0 πusckadrRemoteSocketAddress. sin_zero[4] = 0 rrusckadrRemoteSocketAddress. sin_zero[5] = 0 πusckadrRemoteSocketAddress. sin_zero[6] = 0 πusckadrRemoteSocketAddress. s n_zero[7] = 0 if CconnectCπusckLocalSocket,
Csockaddr *)C&m_sckadrRemoteSocketAddress) , sizeofCπusckadrRemoteSocketAddress)))
{
// Some kind of problem...
// 05/02 - No window here char buff[200]; sprintfC buff, "Connect: Could not attach to host: %s", m_bstrServerAddress.m_str ); MessageBoxC buff, "DR DAVE", MB_OK) ; πubConnectedToServer = false;
STDMETHODIMP cwebEcg : :get_AddNewPointCshort * pval)
// TODO: Add your implementation code here *pval « 0; return S_OK;
}
STDMETHODIMP CWebEcg: : put_AddNewPoiπtCshort newval)
// TODO: Add your implementation code here if CFi reOnRequestEditCdispidDetectPercent) — S.FALSE)
{ return S_FALSE;
}
NewRawDataC&newval , 1) ;
SetDirtyCTRUE);
Fi reOnchangedCdi spi dDetectPercent) ; return S_OK; }
STDMETHODIMP CwebEcg: :get_AgeC short *pval )
{
*pval = mAge; return S_θκ; }
STDMETHODIMP cwebEcg: : put_AgeC short newval ) mAge = newval ; return S_OK; }
STDMETHODIMP CWebEcg: : get_Average_Count long *pval)
*pval = mBPM.AverageCount ) ; return S_OK;
}
STDMETHODIMP CWebEcg : :put_Average_CountClong newval) mBPM.AverageCountC newval ); return S_OK; }
STDMETHODIMP C ebEcg: :get_viewECGCBOOL *pval) ifC mbDrawECG )
*pval = TRUE; else
*pval = FALSE; return S_OK; }
STDMETHODIMP cwebEcg: :put_viewECGCBOOL newval) ifC newval == TRUE ) mbDrawECG = true;
else mbDrawECG = false; return S_OK;
} inline void DrawLineCHDC hdc, long xl, long yl, long x2, long y2)
MoveToExChdc, xl, yl, NULL); LineTo Chdc, x2, y2); } void DrawStringC HDC dc,
HFONT font,
UINT align, COLORREF col, int 1eft , int top, char *str )
{
SelectObjeetC dc, font ); SetTextAlignC dc, align ); setTextcolorC dc, col );
TextOutC dc, left, top, _TCstr), strlenCstr) );
// end of Drawstring
# nclude <olectl.h>
// webEcgControl.idl : IDL source for webEcgControl.dll
//
// This file will be processed by the MIDL tool to
// produce the type library CwebEcgControl .tlb) and marshalling code. import "oaidl.idl"; import "ocidl. dl"; typedef enu propertydispids dispi GridColor = 2, d spidGridStyle = 3, dispidMaxmv = 4, d spidMinmV » 5, disp dStepmv = 6, dispidForewidth = 7, dispi DispiaySeconds = 8, dispidvolumeThreshold = 9, dispidFiltering = 10, dispidBPMFontSize = 11, dispi DetectPerceπt = 12, dispidServerAddress = 13, dispidMicrophoneNotServer = 14, dispidNewPointβytel = 15, dispidNewPointβyte2 = 16, dispidAddNewPoint = 17, }PROPERTYDISPIDS;
[ object, uuιd(E254A2Cl-B470-llD2-8455-00104B05249C) , dual , helpstringC'lwebEcg Interface") , poi nter_def aul t Cum que) i nterface IWebEcg : IDi spatch
[propput, idCDISPID_BACKCOLOR)]
HRESULT BackColor([in]OLE_COLOR clr);
[propget, id DiSPlD_BACKCOLOR)]
HRESULT BackCol or([out, retval ]OLE_COLOR* pclr);
[propput, idCDISPID_BORDERCOLOR)]
HRESULT BorderColorC[in]OLE_COLOR clr);
[propget, idCDlSPlD_BORDERCOLOR)]
HRESULT BorderColorC[out, retval]! OLE_COLOR* pel r) ;
[propput, id DISPID.BORDERSTYLE)'
HRESULT BorderStyleC[in]long st e) ;
[propget, idCDISPID_BORDERSTYLE)'
HRESULT BorderStyleC[out, retval" long* pstyle) ;
[propput, idCDISPID_BORDERWIDTH)'
HRESULT BorderwidthC[in]long width);
[propget , idCDISPIDuBORDERWIDTH)]
HRESULT BorderwidthC[out, retval ] long* width) ;
[propput, idCDISPID_FORECOLOR)]
HRESULT ForeColorC[i n]OLE_COLOR cl r) ;
[propget, i dCDISPID.FORECOLOR)]
HRESULT ForeColorC[out , retval]OLE_cOLOR* pcl r) ;
[propput , i dCDISPID_BORDERVISIBLE) ]
HRESULT Bordervi sibleC[i n]VARIANT_BOOL vbool ) ;
[propget , i d CDISPID_BORDERVISIBLE) ]
HRESULT Bordervi si bl e [out , retval ] VARIANT_BOOL* pbool ) ;
[propput, idCDISPID_MOUSEPOINTER)]
HRESULT MousePointerC[in]long pointer);
[propget, idCDISPID.MOUSEPOINTER)]
HRESULT MousePointerC[out, retvalllong* ppoiπter);
[propput ref, idCDISPID.MOUSEICON)]
HRESULT MouselconC[in]IPictureDisp* pMouselcon) ;
[propput, idCDISPID.MOUSEICON)]
HRESULT Mouselcon([in]lPictureDisp* pMouselcon);
[propget, idCDiSPiD_MOUS EICON)]
HRESULT MouselconC[out, retval JIPictureDisp** ppMouselcon) ;
[propget, idCdispidGridColor) , helpstringC property GndColor )] HRESULT GridcolorCrout, retval] OLE_COLOR *pval); , „^,
Gr [Jrop it. idCdispidGridColor), helpstringC'property Gridcolor")] HRESULT
GridColor [in] OLE_COLOR newval); .
[propget, idCdispidGridStyle) , helpstringC property Gπdstyle")] HRESULT GridStyleC[out, retval] long *pval);
[propput, idCdispidGridStyle), helpstringC'property Gridstyle")] HRESULT
GridStyleC[ nJ long newval);
[propget, ldCdispidMiπmv) , helpstringC property Mi nmv )] HRESULT Mi nmvC[o ut, retval] double *pval); .
[propput, idCdispidMinmv), helpstringC property Minmv )] HRESULT Minmv([ι n] double newval);
[propget, idCdispidMaxmv) , helpstringC'property Maxmv")] HRESULT MaxmV([o ut, retval] double *pval);
[propput, idCdispidMaxmv), helpstringC'property Maxmv")] HRESULT Maxmv([i ή] double newval);
[propget, idCdispidStepmv) , helpstringC property Stepmv")] HRESULT Stepmv C[out, retval] double *pval);
[propput, idCdispidStepmv), helpstringC'property stepmv")] HRESULT Stepmv C[in] double newval);
[propget, id dispidForewidth) , helpstringC'property Forewidth")] HRESULT Forew dthC[out, retval] long *pval);
[propput, idCdispidForewidth), helpstringC'property Forewidth")] HRESULT ForewidthC[in] long newval);
[propget, I d Cdi spi dDi spi aySeconds) , helpstringC'property Di spi aySeconds") ] HRESULT Di spi aySeconds C [out, retval] short *pval);
[propput, idCdispidDisplaySeconds), helpstringC'property Di spi aySeconds") ] HRESULT Di spi aySeconds C [in] short newval);
[propget, idCdispidVolumeThreshold), helpstringC'property volumeThreshold ")] HRESULT volumeThreshold C [out, retval] short *pval);
[propput, idCdispidVolumeThreshold), helpstringC'property volumeThreshold ")] HRESULT volumeThresholdC[in] short newval);
[propget, idCdispidFiltering), helpstringC'property Filtering")] HRESULT F 1 teri ngC [out, retval] short *pval);
{propput, idCdispidFiltering), helpstringC'property Filtering")] HRESULT FilteringC[in] short newval);
[propget, idCdispidBPMFontSize), helpstringC'property BPMFontSize")] HRES ULT BPMFontSizeCtout, retval] short *pval);
[propput, idCdispidBPMFontSize), helpstringC'property BPMFontSize")] HRES ULT BPMFontSizeC[in] short newval);
[propget, idCdispidDetectPerceπt) , helpstringC'property DetectPercent")] HRESULT DetectPercentCfout, retval] double *pval);
[propput, idCdispidDetectPercent), helpstringC'property DetectPercent")] HRESULT DetectPercent C [in] double newval);
[propget, idCdispidServerAddress), helpstringC'property ServerAddress")] HRESULT ServerAddress C [out, retval] BSTR *pval);
[propput, idCdispidServerAddress), helpstringC'property ServerAddress")] HRESULT ServerAddress n] BSTR newval);
[propget, idCdispidMicrophoneNotServer), helpstringC'property MierophoneN otserver")] HRESULT MicrophoneNotServerC[out, retval] short *pval) ;
[propput, idCdispidMicrophoneNotServer), helpstringC'property MierophoneN otserver")] HRESULT MicrophoneNotServerC[in] short newval);
[propget, idCdispidAddNewPoiπt), helpstringC'property AddNewPoint")] HRES
ULT AddNewPoint ([out, retval] short *pval);
[propput, id(dispidAddNewPoint), helpstringC'property AddNewPoint")] HRES ULT AddNewPoint ([in] short newval);
}; uuidCE254A2B4-B470-llD2-8455-00104B05249C), versionCl.O) , helpstringC'webEcgControl 1.0 Type Library") library WEBECGCONTROLLib importlib("stdole32.tlb") ; importlib("stdole2.tlb");
uuid(E254A2C2-B470-llD2-8455-00104B05249C), helpstringC'webEcg Class") coclass webEcg
[default] interface IWebEcg; };
[ uuidC3D002C02-B9E0-llD2-8455-00104B05249C), helpstringC'webEcgPPG Class") coclass webEcgPPG { interface IUnknown;
};
};
// webEcgControl . cpp : Implementation of DLL Exports .
// Note: Proxy/Stub information
// To bui ld a separate proxy/stub DLL,
// run nmake -f webEcgCoπtrol ps .mk i n the project di rectory .
#i ncl ude "stdafx . h" # ncl ude " resource. h #i ncl ude "initguid. h" #incl ude "webEcgControl . h
#incl ude "webEcgControl_i . c" #i ncl ude "webEcg . h" #i ncl ude "webEcgPPG. h
CComModule _Module;
BEGIN_OB ECT.MAP(Ob βCtMap)
OB3ECT_ENTRY(CLSiD_webEcg, cwebEcg)
OBJECT_ENTRYCCLSID_WebEcgPPG, cwebEcgPPG) END_OB3ECT_MAPC)
BOOL WINAPI DllMainCHlNSTANCE hlnstance, DWORD dwReason, LPVOID /*lpReserved*/) if (dwReason == DLL_PROCESS_ATTACH)
.Module. iπitCobiectMap, hlnstance) ; Di sableThreadLi braryCal 1 s Chlnstance) ; else if CdwReason « DLL_PROCESS_DETACH)
_Module.τermC); return TRUE; // ok }
///////////////////////////////////////////////////////////////////////////// // used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanunloadNowCvoid) { return C_Module.GetLockCountC)==0) ? S_OK : S_FALSE;
///////////////////////////////////////////////////////////////////////////// // Returns a class factory to create an object of the requested type
STDAPI DllGetClassObjectCREFCLSID rclsid, REFIID riid, LPVOID* ppv) return _Module.GetClassObjectCrcl si d, riid, ppv);
///////////////////////////////////////////////////////////////////////////// // DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServerCvoid)
// registers object, typelib and all interfaces in typelib return .Module. Reg sterserverCTRUE) ;
///////////////////////////////////////////////////////////////////////////// // DllunregisterServer - Removes entries from the system registry
STDAPI DllunregisterServerCvoid)
.Module. UnregisterServerO; return S.OK; }
// resource. h
//{{NO.DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// used by webEcgControl . re
//
#define IDS.PROJNAME 100
#define IDR.WEBECG 101
#define iDS.TTTLEWebEcgPPG 102
#define lDS_HELPFlLEWebEcgPPG 103
#define lDS_DOCSTRlNGwebEcgPPG 104
#define IDR.WEBECGPPG 105
#define IDD.WEBECGPPG 106
#define IDC.FORE.WIDTH 201
#define IDCFILENAME 202
#define IDC_EDIT2 203
#define IDC_GRID_STYLE 204
#define IDC.MAX.MV 205
#define IDCMIN.MV 206
#define IDC_STEP_MV 207
#define IDCDISPLAY.SECONDS 208
#define IDC_VOLUME_THRESHOLD 209
// Next default values for new objects //
#ifdef APSTUDIO.INVOKED
#i fndef APSTUDIO.READONLY.SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 201
#define _APS_NEXT_COMMAND_ ALUE 32768
#define _APS_NEXT_CONTROL_VALUE 210
#define .APS.NEXT.SYMED.VALUE 107
#endif
#endif
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently
#if !definedCAFX_STDAFX_H_E254A2B8_B470_llD2_8455_00104B05249C_INCLUDED_) #define AFX_STDAFX_H_E254A2B8_B470_11D2_8455_00104B05249C INCLUDED.
#if .MSC.VER >= 1000
#pragma once
#endιf // .MSCVER >= 1000
#define STRICT
#define _WIN32_WINNT 0x0400 #def i ne _ATL_APARTMENT_THREADED
# ncl ude <atlbase.h>
//You may derive a class from CComModule and use it if you want to override
//something, but do not change the name of .Module extern CComModule .Module;
#i ncl ude <atlcom.h>
#i ncl ude <atlctl.h>
# ncl ude <ocidl.h> // Added by Classview
//{{AFX.INSERT.LOCATION}}
// Microsoft Developer studio will insert additional declarations immediately bef ore the previous line.
#endif // !definedCAFX_STDAFX_H_E254A2B8_B470_llD2_8455_00104Bθ5249C INCLUDED)
// stdafx.cpp : source file that includes just the standard includes
// stdafx.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
#i f def _ATL_STATIC_REGISTRY
#i ncl ude <statreg.h> #include <statreg.cpp> #endif
#include <atlimpl . cpp> #i ncl ude <atl ctl . cpp> #i ncl ude <atlwin.cpp>