ReadyMedic - CS Course Webpages

advertisement
ReadyMedic
A Health Information Appliance
Final Report
5-8-00
Keith Kirkendall
Jeremy Pearce
Steven Saunders
Lanny Schrib
Kerri Smith
Table of Contents
1. ABSTRACT ...................................................................................................................3
2. FEATURES ...................................................................................................................4
3. BASIC MODULE OVERVIEW ..................................................................................5
4. DETAILED MODULE DESCRIPTION ....................................................................8
5. TEST REPORTS AND RESULTS ...........................................................................34
BETA TESTING .................................................................................................................34
COMPONENT TESTING .....................................................................................................34
TOP-DOWN TESTING ........................................................................................................34
6. CONCLUSION ...........................................................................................................36
7. ACKNOWLEDGEMENTS .......................................................................................37
8. REFERENCES ............................................................................................................38
2
ABSTRACT
The ReadyMedic aims to empower the user with greater control of their health care by providing
the patient with health information and communication with their personal physician without
requiring previous technical knowledge. It provides access to personal medical records,
prescription scheduling, automatic health information gathering, emergency medical contact, and
connections to modern medical devices to aid in home health care. Additionally, all information
is maintained in a web-based database that will provide the doctor or surgeon with a convenient
means of monitoring and storing patient information.
The ReadyMedic project is composed of two deliverables. First is the handheld health
information appliance, based on an NEC MobilePro 800, which uses a Global Positioning System
and Ethernet connection to help connect the user to the world. Second is the web-server, which
facilitates communication between the ReadyMedic device and the online medical history records
and automatic information gathering, as well as giving physicians means of easily storing patient
information. This server also provides the doctor with a powerful means to monitor and update
patients.
This report details the results of the ReadyMedic design team in developing the first prototype of
the ReadyMedic health information appliance and its extended accessories.
3
FEATURES
The ReadyMedic is designed to provide an easily understood user interface while still providing
powerful features. It requires minimal user input and programmatically provides the maximum
amount of information. This facilitates use by both less technically inclined people as well as
people with busy lifestyles that do not want to spend the time learning yet another technical
device. Part of the ReadyMedic’s power lies in its centralization of data, enabling multiple
doctors to easily access and monitor the same patient via the provided online interface.

Scheduler—A scheduler keeps track of multiple medicine dosage times and gives the
ReadyMedic user notification of the need to take medication.

Medical History—An online database containing medical records is accessible (for readonly) to the patient via the ReadyMedic. Medical records are updated by the physician(s)
treating the patient through the ReadyMedic Web Service to facilitate the localization of
data and easy access in emergency situations.

Health Information Queries—By taking advantage of the wealth of medical knowledge
stored online, the ReadyMedic is able to provide the user with the latest information on
areas of medical interest such as disease, medication or health practices from the
American Medical Association website. This searching capability is abstracted from the
user such that they simply enter the desired information and they are notified when it
becomes available.

Ask a Doctor—The ReadyMedic allows the user to enter questions via the keyboard and
automatically forwards them to the patient’s personal physician. After the physician has
responded to the question, the answer is provided to the user via the ReadyMedic device.

Emergency Locator—The ReadyMedic is equipped with a Global Positioning System,
which allows a ReadyMedic operator to be notified of the user’s location during an
emergency that requires immediate professional medical attention. The operator is able
to access the user’s medical and contact information. Protection from accidental
invocation of the service is provided with a countdown timer allowing cancellation of the
function.

Medical Device Interface—An interface is provided for connecting supplemental medical
devices to the ReadyMedic. This greatly facilitates home care of the patient allowing the
user to monitor their blood pressure, blood sugar, pulse, and temperature. Currently, these
devices are simulated with LabVIEW software.

ReadyMedic Web Service—All information is stored in a database and is accessible to
doctors through the online web interface, to patients through the ReadyMedic device, and
to emergency operators through the operator software system.
4
BASIC MODULE DESCRIPTION
Basic Overview
The following section of the report will give a basic overview of how the components of the
ReadyMedic project are incorporated to provide all of the functionality. Figure F-1 gives a
graphical representation of the components of the project and how they interact.
Figure F-1
ReadyMedic Device Windows CE
User Interface
This is the entry point and control for the ReadyMedic device. This is what the user interacts with
to access all the features. The user has the option to: Ask a Doc, Medical Info, Scheduler,
Medical History, Emergency, and Medical Device. Ask a Doc allows the user to write questions
to their doctors and read the responses to them. Medical Info enables the user to search for the
latest and greatest information on medical topics. Scheduler allows the user to schedule multiple
medications and it reminds the patient when to take their medicine. Medical History enables the
user to view their medical information and history. Emergency gives the user the ability to
request immediate medical attention. Medical device allows the user to take different medical
measurements. The user interface controls the flow of the program and is the cornerstone of the
project.
5
Connect
This allows for communication between the User Interface and the ReadyMedic.dyndns.org
Linux server. It opens connections to the server to send and receive information. Ask a Doc,
Medical Info, and Medical History all use the connection to the database to retrieve and send
data.
ReadyMedic Linux Server
Server
This is the key component of the ReadyMedic Linux Server. It routes all the connections to the
appropriate modules and information gathering programs. All Medical Info requests are sent to
getHTML to search the web, whereas all Ask A Doc requests are sent to QueryClient to connect
to the database. The server stores all information for the ReadyMedic to later download at a
convenient time.
getHTML
The server uses this module for Medical Info requests. It takes the query entered by the user and
searches the web for news on a certain medical topic via the AMA Website.
QueryClient
Whenever there is a need to access the database, the library QueryClient is called to make
embedded C MySQL calls to the database. The information is then returned to the Server or the
Emergency Server.
Database
The database stores all the information used by the system and is accessed by virtually every
piece of the system. The Emergency Server requests operator login information and patient
information from it. Ask a Doc stores the questions to the doctors. The Medical History is
retrieved from there.
Web Pages
The web pages are mainly used for the doctor to add new information or update old information.
It connects to the database to retrieve information for the doctor or to store new information.
Additionally, the ReadyMedic device accesses various “hidden” pages to allow the user to view
Medical History.
Barbrady Windows NT Server
Emergency Server
This module handles all emergency requests from the ReadyMedic and the Operator. It also
connects to the ReadyMedic Linux Server to connect to the database and retrieve information
using QueryClient. It requires administrator privileges, and thus currently runs on the Barbrady
computer in the 483 lab.
6
PC Windows 98/NT
Operator
This can be on several PCs all over the world. It is used to
handle requests that come to the Emergency Server requesting
immediate medical attention. It also uses the Emergency
Server to query the database to view the person’s information.
7
DETAILED MODULE DESCRIPTION
The following section of the report will give a more detailed description of the components of the
ReadyMedic project and the technical details that were involved in development. Figure F-2
gives a graphical representation of the components that will be discussed in this section of the
report and is an expansion of Figure F-1.
Figure F-2
ReadyMedicUI
The entire ReadyMedic user interface has been developed using Microsoft Visual C with the
Windows CE SDK (software developer's kit). Currently, all modules are built using the "Palmsize PC 2.01" compiler. This compiler was found to generate much smaller code than the
"Handheld PC 2.00" compiler, and allowed some features which were not implemented in
2.00. All the currently compiled code was built was "Win32 (WCE MIPS) Release" code since
the NEC is a MIPS based processor.
User Interface design is initially very difficult in Windows CE. There are literally hundreds to
functions that can be used to accomplish various tasks. As such, it is often hard to determine
exactly which call to make in order to complete the necessary task. It is recommended that the
two Windows CE books mentioned in the references section be consulted to learn the basics.
Simple questions, such as which parameters a function takes, can be quickly found in the online
help with MSVC (Microsoft Visual C), or on www.msdn.microsoft.com. Be forewarned, various
8
examples were taken from Microsoft’s massive amounts of documentation, and many times they
would not work!
Those new to Windows programming should also be forewarned about two other areas of
confusion. Firstly, Windows examples are written using the Hungarian notation for naming
variables, which prefixes a name with certain characters giving clues to its type, such as “p” for
“pointer”. This quickly leads to long, hard to read names. Secondly, Unicode is used (which is a
two byte version of characters designed to accommodate other languages, like Japanese, that
ASCII neglects). Unicode, which is the only form of string (i.e. char*) processing in Windows
CE, did not produce readable files using the standard Windows CE FileWrite calls. This
frustrating problem required finding the proper functions to convert back and forth with ASCII.
These functions are provided in the Utility.cpp file. The TEXT macro, which is used throughout
the code, converts standard strings into Unicode. It is also useful to know that in many cases, a
string manipulation function, such as strcat (which concatenates strings), is replaced by wcscat
(which concatenates wide character strings (i.e. Unicode)).
MSVC allows for a great deal of automatic MFC (Microsoft Foundation Class) code generation,
and the base ReadyMedicUI app was initially created this way. Using this tool, one can draw the
basics of the user interface, then programmatically resize it as needed later on. The MainDlg
dialog was created this way, and its buttons mapped to function calls using the ClassWizard
(simply right-click on a button, and select the ClassWizard option. You then have choices about
what messages, such as single-click, to map to functions). MFC handles routing the flow of
program control to these user interfaces handling functions automatically. In the
ReadyMedicUI’s case, these functions load new windows to continue the user interface flow. For
example, clicking the Emergency button will instantiate a EmergencyClient dialog box class, run
it until it completes execution with the DoModal method, then delete the object and resume
waiting for the user to click another button. As another example, clicking the Medical History
button loads an entirely new process (the htmlView program) and waits for that process to
complete before again regaining control. Since the htmlView process was written using standard
Windows CE message passing (as opposed to MFC), it can take command line attributes, and in
this case it takes the name of the initial html file to display.
A black dialog box is used in the background to cover up all evidence of Windows CE existing,
completely forcing the user to use the device only as intended. This is very important in reaching
the average user, which does not want to be bothered with such additional complexity. The
background is simply painted black using standard drawing commands to make the screen appear
to be blank except for the dialog boxes that are displayed. This is useful because it allows the
dialog boxes to be small (so they could be easily ported to smaller devices than a MobilePro).
The htmlView program actually uses the maximum possible screen space, which is important
because it display more information than any other module. However, it interacts with Windows
CE to determine its size, and thus it also would not require changes if ported to a smaller device.
In using the ReadyMedic, one will notice that windows are stacked “in the Z axis” to ensure only
one is available at a time. Again, this was decided to ensure that the user did not have to worry
about multitasking, it occurs for them transparently. To the programmer however, it is important
that these windows are all the same size to ensure that accidentally clicking the edge of one
doesn’t bring up something out of order. This is done in the DlgSpecs.h file, which calculates the
dimensions and placement that every dialog box should have. All dialog boxes that are created
with MFC had the OnInitDialog function added (to handle the WM_INITDIALOG message from
the class wizard handled) as used the following function to ensure its specs:
SetWindowPos(NULL, DLG_IX, DLG_IY, DLG_DX, DLG_DY, SWP_SHOWWINDOW);
9
This stacking of windows is demonstrated in Figure F-3, which shows the flow of windows
associated with finding Medical Info slightly spread out to emphasize the stacking.
Figure F-3
Closing the ReadyMedic
Please note, the project has been set up such that a user could never “exit” the program and thus
return to Windows CE. However, for the developer, it is often nice to be able to exit cleanly
without resorting to resetting the machine or using CTRL-ALT-DEL to kill a process. If the main
screen is visible along with the toolbar at the bottom of the screen (which shows two processes
with no names corresponding to the background dialog box and the main dialog box), it is
possible to hold the ALT key and click the second process to close the program. Closing in this
manner will stop all scheduled activities and clean up any files that were written.
Doctor Questions and Finding Medical Info
MFC was used to create the flow of dialog boxes required to enter questions to the doctor or
medical info. The both use standard Windows CE functions to send and get text to/from the
objects on the window. This text is parsed and formatted into a query string usable with the
ReadyMedic server. Since sockets connectivity does not work currently, this string is displayed
in a MessageBox(), which allows the user to use other methods (such as rmClient as described in
10
the User Manual) to send the information along its way. The expected names of the resulting
queries are stored in the registry, and later used by the AutoDownload module (see this section
for more detail).
Standard functions have been created to let the developer quickly access the windows registry in
the HKEY_LOCAL_MACHINE\ReadyMedic\* keys. These keys contain information about the
above directories, as well as the patient’s ID and doctor’s name. At times the schedule also stores
information here. The MainDlg.cpp file of the ReadyMedicUI project initially sets values for the
registry items. They may be changed in this file to modify the starting default values of the
patient ID and doctor’s name (both of which are used in create the strings for transferring
information) The developer may view/edit the contents of the registry manually using the MSVC
Tools\Windows CE Tools menu option and selecting the Remote Registry Editor.
Reading the results when they are downloaded is a simple process of generating the list of
available replies/documents and placing them in an html file as links. This enables the htmlView
module to display them and let the user easily switch between the various responses. The
DisplayLinks() function was created (it resides in Utility.cpp) to generate this list in the html file.
Here the text written to the file was converted from Unicode to ASCII to prevent having
characters in the resulting file being separated by boxes (presumably representing the increased
data capacity of the Unicode). This module automatically calls the htmlView module to let the
user interact with the information.
HtmlView
The htmlView program was based on an example from Microsoft, which utilized the Html
Viewer Control API, provided with Windows CE. This example was written with the standard
Windows message loop style instead of MFC. Note, the complexity of the program was greatly
reduced and each of its features within the code are documented. The program accepts a
command line argument, which it expects to be a string listing of the file to display, and thus tries
to display that file. A file is displayed by first determining if it must be downloaded from the
Internet (which means it contains “http://” in its name) and using the DownloadPage module to
save the file to a specified location. Various paths are set, and the file is opened and loaded into
memory. The Html API actually takes care of interpreting and displaying the Html code. Every
file that is displayed is added to the end of a circular buffer, which is an easy implementation for
a BACK button. Whenever that button is pressed, the current location in the buffer is
decremented by one and the page name stored there is displayed. Since the buffer is circular, the
user may not be able to go back to all pages visited, but there will also never be a low memory
condition either. The API automatically generates messages whenever a hyperlink is clicked
(NM_HOTSPOT), and the link is then displayed as described above. The API does not directly
handle graphics, thus they also generate a message and are handled manually. This section of
code was commented out to prevent viewing of pictures. Although it works, pictures from the
Internet must be downloaded first, and this can become very difficult. During this revision of the
product, it was found that the AMA page could be used very nicely without graphics. This does
however demonstrate the major deficiency with the htmlView module, it must have the full path
of something to download. Since most WebPages only use relative paths, this is a problem that
will need to be resolved if future work is done. A filter has been considered that would always
replace relative links with the full name.
The user interface of the htmlView only displays the actual Viewer Control (which automatically
supplies a scroll bar), a close button and the back button. The two buttons were created using the
CommandBar control, which is created very similar to a new window and is handled with the
WM_CREATE message. The back button was drawn as a bitmap, registered with the program
11
and added at runtime. The close button was added as an “adornment” and is a more common
feature of Windows applications.
AutoDownload
Windows CE provides a very nice function for scheduling a program to run at a certain time:
CeRunAppAtTime(). This function will run the specified program at the specified time, even if it
must power up the machine from its low power state. This allows the ReadyMedic to remain
turned off to the user, thus conserving power, but activate automatically when some event needs
to take place. Both the AutoDownload and Scheduler modules make use of this feature. Both are
separate subprograms that get scheduled by the ReadyMedicUI program using
CeRunAppAtTime(). AutoDownload simply looks for files on the ReadyMedic server and
displays a message if it finds any. It then reschedules itself to look again at a later time. It should
be noted that this time is currently 1 minute, which facilitates a quick demo. It is easy to change
this time to be an hour or a day later to reduce the number of connections to the network.
Because of the Windows bugs with the Connectivity modules, a kludge was required to allow any
functionality. Currently, any time the user enters a question for the doctor or a request for
medical info, the remote and local names of that file which will be generated by the server are
stored in the registry. Thus AutoDownload simply reads these names and downloads only that
server file. The more correct way of doing this would be to use FTP functionality and download
all files that are associated with a given ID number.
Scheduler
The medicine scheduler is probably the most interesting component of the ReadyMedic user
interface. Like AutoDownload, it is a subprogram that may be scheduled to execute at a certain
time. Its basic algorithm is as follows:

ReadyMedicUI
 Append UI data as an entry in a text file
 SetSchedule() to initialize notification

Scheduler Subprocess
 Alert user during notification
 SetSchedule() to set next notification
As such, every medicine that is scheduled is added to a Unicode text file in the form:
MED: <medicine name>
END: <last date to take medicine>
-> <time>
END.
The information is pulled directly from the scheduler user interface and appended to the end of
the file each time. SetSchedule() uses the MED & END tokens to break up the list of medicines
into the individual medicines and parses the entries for the next time during that day. If there is
no future time for the current day, the time is set to the next day and again a time is attempted to
be set. If it is past the medicines end date, its entry is removed from the text file. Each medicine
entry is scanned and the nearest time is used as the next medicine to schedule. This medicine’s
name is added to the registry, and the scheduler subprocess is scheduled for its time. When the
scheduler subprocess is started, it reads the name out of the registry and notifies the user to take a
dose of it. It then again calls SetSchedule() to find the next time to schedule itself.
12
Connect
The Connect function provides communication between the WinCE user interface and the
ReadyMedic.dyndns.org Linux server. It opens connections to the server to receive information.
Ask a Doc, Medical Info, and Medical History all use the connection to the database to retrieve
data.
Originally, attempts were made to use sockets to provide connection between the systems using
the sockets with a client running on the ReadyMedic WinCE device. The ideal solution would
have been to open an socket connection between the client, WinCE device, and server, Linux
box, to allow upload of patient questions to their physicians and topics for information query and
allow the download of results from the previous functions as well as the patient’s medical
information. When this proved to be unfruitful, other solutions were sought.
Windows Networking has WinInet functions defined in the wininet.h header file that are stated to
be supported by WinCE. The Windows CE WinInet API ideally enables the use of HTTP
(Hypertext Transfer Protocol) and FTP (File Transfer Protocol). Function code is provided in
Chapter 7 of the Microsoft Windows CE Communication Guide to allow the function to be called
and submit an HTTP request for the default HTML document from the server and display the
code and the transaction headers. Ideally, these functions would have provided the appropriate
results for the functions with required modifications. However, it was discovered that there are
‘Known Microsoft Bugs’ that do not allow this functions to work properly. Upgrades to WinCE
2.12 and Internet Explorer 4.01 for WinCE were required to properly use these function calls.
The group received an upgrade, however, not wanting to risk loosing the functions of the project
that were performing properly, the upgrades were not installed on the WinCE ReadyMedic
device.
In the end, an example HTTP function was modified to allow any file to be programmatically
downloaded to the WinCE ReadyMedic device and provided half the functionality of the ‘Ask A
Doc’ and ‘Information Info’ functions and full functionality of the ‘Medical History’ function.
Code was developed on the Linux server to compensate for the lack of connection between the
two systems, yet showing the possibility for full functioning of the ReadyMedic device’s
functions provided either the appropriate upgrades are installed on the device or a work around
for the lack of FTP protocol is developed.
ReadyMedic Server
It was decided early on that an FTP server with incoming and outgoing folders would be the best
solution for processing information requests. Any time the user makes a request, the ReadyMedic
would Ftp the request to the inbox. This box serves as a queue and requests are handled in order.
When they are completed, the results are posted to the outgoing folder, which the device will scan
periodically (looking for its personal ID code). If it is a longstanding request (such as a request
for all new info on a certain medicine) the request is left in the queue, otherwise it is deleted.
This concept is demonstrated as follows:
Loop (forever) {
Open(fromInbox, withBlocking);
ProcessRequest(fromInbox);
If(fromInbox is a single request)
Delete fromInbox;
Else
Return fromInbox with updated date
}
13
However, it was discovered that no calls existing that would allow a program to block until a file
was created in a directory, as specified in the previous biweekly report. Based on input from
Robert, as well as detailed examples from online resources, a sockets server was created to
produce the required functionality. Sockets are a common tool, and were thought to work across
the Linux, Windows CE and Windows NT platforms, and they would still enable the server to not
waste CPU cycles polling for data. Although the server now works, it turns out that the Windows
CE sockets could never successfully connect to it because of Microsoft bugs. The component
diagram of the server and its various process that it communicates with is shown in Figure F-4.
rmServer
- receive incoming info & doctor queries
- save & signal rmQueryHandler
rmQueryHandler
- process and save queries
- getHtml() for info queries
- queryclient() for doctor queries
- store / delete daily info queries
rmRenewQuery
- resignal daily queries and sleep()…
rmCheckDocAnswer
- process doctor replies and sleep()…
Figure F-4
An example client-server program written in C for UNIX was used as the first baseline. He first
got it to compile and execute on both his Linux machine and across the Internet to the
ReadyMedic server. This baseline server uses standard sockets calls to configure a port to listen
for incoming requests. The 'accept' call blocks until a client connects on the designated port (in
this case, 7333 was selected), then negotiates a port for message passing. The server then uses
the 'fork' system call to create another process to handle the incoming request. The parent simply
closes the new port and waits for another connection. The child handles the incoming request on
the new port by displaying a message on the screen. The baseline client simple used standard
calls to attempt a socket connection at a specified web address. It sends a simple message, then a
message of length 0 to signify the end of the connection.
The server program, rmServer.c, underwent many changes from this baseline. When the server
forks a child process, the child's memory space is not cleaned up until the server explicitly
specifies it. The 'waitpid' system call was used to allow children to be cleaned up if they are
finished executing/processing, otherwise it continues. This reduces the number of cycles the
parent must waste waiting when it could be looking for another incoming socket connection.
'waitpid' will generally have one defunct child, since a child is usually done by the time a new
connection is requested. When a message is passed, the child process now loads it into a buffer,
reads the ID number, finds that ID number's previous requests, or creates a new list. The server’s
representation of a request is a file, which contains one request per line and is named after the ID.
This file is useful because it allows a different program than the server to parse it. Whenever a
new request is created (or an existing one has a request appended to the end of it), the server
issues a signal. A signal is an operating system interrupt. Another program that is blocking in the
background until it receives that signal wakes up and completes processing of the request(s).
14
This program, rmHandleQuery.c, reads each file in the in directory and processes each request
within the files. Requests are in the form
<id>: <num> <type>: <action>
for info queries and
<id>: <num> <type>: <doctor id> <action>
for doctor questions where <id> is the patient’s id number, <num> is 1 for execute request
forever and 0 for execute once, <type> is a I, D, or K for information query, doctor question, or
kill (delete) existing request, and <doctor id> is the doctor’s logon id. The <action> is the
information to search on or ask the doctor about. The requests are loaded into a linked list of
requests, and the kill type is run to remove requests. The rest are then processed in order, and if
the num is 1, they are saved for future use to the done directory. Due to lack of time, the actual
ReadyMedic device does not provide a method of sending the kill message to the server.
However, using the client mentioned below, this action can still be performed. Info queries use
the GetHtml module to search the web and return the appropriate html, which is stored in the out
directory. Doctor questions are routed to the doctor using the queryclient() module.
Another program, rmRenewQuery.c, restores requests at the end of the day from done to in. This
is performed by the ‘rename’ call, equivalent to moving from on location to another (mv).
RenewQuery then issues the appropriate signal to allow query handling. It uses the sleep system
call to be scheduled to run only once a day, thus reducing the number of wasted CPU cycles.
The rmCheckDocAnswers.c program is the most simple. It simply loops infinitely (with a certain
about of nonblocking sleep() time between each iteration to reduce polling) and uses the
queryclient() functionality to store a doctor’s reply to a question in the out directory.
The client program, rmClient.c was kept relatively unchanged from the initial example. It was
modified to allow the user to enter the string to transfer, surrounded by quotes, via the command
line. This module has the server to transfer (ReadyMedic.dyndns.org) hardcoded to facilitate easy
use. This may be modified if a new server is used.
Although the original code was written in C, much of it was converted to C++. C++ has strong
type checking, which always finds many errors in passing arguments. C++ also allowed the
creation of a message logging object. It allows calls such as:
rmLogger log("rmServer", "logFile");
// Declare this globally
log.logMessage("Connection on port %d!", portNum); // Use this anywhere!
This allows every module to use the same generic class to log its output to either the specified
file or to stdout (i.e. the screen). The log files note the time and place of message and are very
useful for finding errors that may occur.
Obviously, compiling and starting the server could be difficult given so many modules. This was
aided by creating a tcsh shell script to compile and start each module in the appropriate order. A
makefile was written to facilitate compiling as well as cleaning (make clean) of the directories.
QueryClient
Common
Common is a file that lists function definitions for all functions used in every query to any
MySQL database. It has an associated header file, common.h, which contains the function
15
prototypes. Please note the #include’s, which would obviously need to be changed such that the
correct libraries (especially MySQL API) can be found. The functions within the common.c file
are: do_connect(), print_error(), and do_disconnect(). The function do_connect() takes
parameters: hostname (char *), username (char *), password (char *), dbname (char *), portnum
(unsigned int), socketname (char *), and flags (unsigned int). Depending upon the version of
MySQL used, different parameters are used to connect. Once the connection is established it will
return a connection handler. The function print_error() basically prints the error received and
held in the connection handler construct. It implements other functions from the MySQL API to
do this upon receiving a connection handler and a user-defined message (char *). The function
do_disconnect() simply disconnects the connection when passed the connection handler.
QueryClient
Queryclient.c is a file that lists function definitions for the following functions: queryclient(),
ask_to_buff(), and buff_to_ask(). The associated header file containing the function prototypes
is named queryclient.h. Again, note the #include’s at the top of the file, as well as the #define’s.
Notice that the dbname as well as other vital information is hardcoded there and would possibly
need to be changed based on the MySQL set up. Also, a global variable conn, which is a MySQL
connection handler, has been set up. The queryclient function takes a query (char *), an option
(int), and an error (int *) and returns an array of strings containing the results of the query. First,
the module attempts to connect to the database. Then based upon the option argument it will
follow one of the following paths: a question is inserted into the database (whereas the query
argument should contain a patient id, a drlogin value, and a question, each of them separated by a
space and in that order), any answered questions will be retrieved from the database (where query
is an empty string), values will be checked against information in the database (where query will
contain operator login and operator password, each separated by a space in the proper order), and
patient information retrieved from the database (where query contains a patient id).
Following the first path, or option equals 0, the query is sent to the buf_to_ask function, which
basically inserts the values into an Askadoc struct (containing fields for drlogin, pid, question,
and answer). Note more information will be given on the buf_to_ask function later. The struct is
then passed to a function called qinsclient (discussed under the qinsclient section). If the
information is successfully installed the first string in the return array, buffer, is set to success;
else, the entire buffer is set to NULL and returned.
Following the second path, option equals 1, again the query is sent to buf_to_ask function. Then
the qselclient is used to retrieve the answers from the database, which returns an array of
Askadocs full of answered questions. Note more information on qselclient will be given in the
qselclient section. If any information is retrieved it will then be processed one struct at a time by
the ask_to_buf function (described later). Each struct in the array corresponds to a string in the
returned string array, buffer.
Following the third path, option equals 2, the query is passed to the qselcj1 module (explained
further in the qselcj1 section). This module returns 0 if no errors occurred (i.e., the information
was found in the database), and the first entry in the return array is set to “SUCCESS”.
Following the final path, option equals 3, the query is passed to the qselcj2 module (explained
further in the qselcj2 section). As opposed to returning an error, it returns the information already
in an array of strings to be returned.
After that the queryclient module will disconnect from the server and database, and return the
string array to the proper client.
16
The buf_to_ask function first declares an Askadoc struct as well as some pointers used in
traversing the query passed in. Each of the pointers in the struct is initialized to NULL, and the
other pointers are set appropriately (endptr—the end of the query, spcptr—the query). Then after
testing for a valid query string, a loop that ends when either spcptr equals endptr or if a stop flag
equals 0. Until one of these two things happen, I will search the query for a space, count the
number of characters from the beginning of the query, then copy from query (which is reset after
each copy) the number of characters counted into the appropriate field in the struct. The correct
field is known due to the order being known and an option, known as value, to keep track of what
attribute has been completed. To know how many characters are in the last string, a running total
of how many characters are left in the query is kept, in tot. The struct is then returned.
The buf_to_ask function takes the struct, as well as a char *, and uses sprintf to take the values
from the struct and insert them into the char *, of course being separated by spaces.
Qinsclient
The prototype for this function can be found in the file qinsclient.h. The qinsclient module is
passed a connection handler as well as an almost completed Askadoc structure. The first task to
be done is to build the two query strings. The first will make sure that the patient is in the
database and linked to the doctor who will receive the question. The second will actually insert
the question into the Askadoc table in the database. The database is then sent the first query
through the API call mysql_query(). Then, if the patient is present and there are no errors in the
retrieval process, a validation flag, verified, is set. Upon “verification”, the second query string is
built from the information held in the Askadoc structure. To get the date, the function strftime is
used. Again using the mysql_query() function, the information is stored into the database and
the memory allocated for the query strings is released.
Qselclient
The qselclient module is passed a connection handler, a completely empty Askadoc structure, and
a pointer to an integer. The pointer is used to set and receive error codes, which are described in
error.h. First, an array of Askadoc structures is set up as well as allocating memory for the two
query strings. The first query string is used to select any questions from the database that have
been answered (i.e., the answer field in the database is not null). The second query string is used
to delete all the questions that have been answered. The first query string is built, and sent to the
database using mysql_query(). Each answer is stored in an Askadoc structure in the array as
mentioned earlier. This is accomplished by using a while loop and the mysql_fetch_row()
function on the result of the query. This takes a tuple from the database and puts each field in an
entry in the “row” array, which can simply be indexed to get the result. The fields will come
back from the database in the order requested in query. Then each element of each Askadoc
struct in the array is set to NULL so that proper processing will take place in the queryclient
module. Then for each answered question, a second query string is built that, when sent to the
database, will delete the entry with a matching value for its answer. The memory allocated to the
query strings is then released and the array of Askadocs is returned.
Qselcj1
This module performs the login validation for operators in the emergency medic feature. The
function prototype can be found in the file qselcj1.h. The qselcj1 module is passed a connection
handler, and a query (char *) which contains an operator login and an operator password. First
using a somewhat similar method as buf_to_ask, the query that is passed in is parsed to get values
for the operator login and password. These values are then inserted into a query string. To do
17
this, the first space in query is found and then the number of characters prior to the space is
counted and stored in count. Then the first count characters are copied into a variable, oplogin,
and the remaining characters into oppswd. Then using sprintf, the query string is built. This
query string will be sent to the database via the mysql_query() function. If the values are present
in the database a zero is returned, else another value is returned.
Qselcj2
This module performs the patient contact information retrieval when an emergency occurs and
the patient uses the emergency medic feature. The function prototype can be found in qselcj2.h
and the error codes can be found in error.h. The module is passed a connection handler, a query
(char *) containing the patient id number, and an int *. Again, the integer pointer is used to set
and receive error codes. First, space is allocated to a query string and also to an array of strings.
The array of strings, ans, is used to store the results of the query and will be returned back to the
calling function. The query string then is built and is used to retrieve all the information
corresponding to the given patient id. Again, this is accomplished through the mysql_query()
function. Only certain fields were needed by the operator however. As in the qselclient, the
mysql_fetch_row() is used and each row is stored into an array (note, there should only be one
row corresponding to each patient id). Then a case statement is used to select the information that
is really required. Each field is then put into a separate space in the ans array. Also, note that
when the state field arrives from the database, it is a number (in string form). The function
StringToInt is used to change the string into the corresponding number. This number corresponds
to a state, and this state is inserted into ans via a large case statement. The memory is then
released and ans is returned.
getHTML
getHtml is a function written for the sole purpose of getting HTML code from a search engine.
The function is written using C Stream sockets. It posts a header to a search engine, and returns a
string that contains the HTML code returned by the search engine.
As the function is programmed now, it only looks at the AMA web site. This was done for a
multitude of reasons. It would not be hard, however, to manipulate the code to search multiple
engines, or to allow the user to select a search engine. This will be explored in more detail later.
The function is called getHtml. It is defined, in C, as:
char * getHtml(char *search);
The function succeeded if it returns a string, and failed if it returns a NULL pointer.
The function expects to be passed a string to work with. Here's the caveat: the function does no
parsing on the search string. If you want to search with multiple words (such as "colon cancer"
instead of "leukemia") then you must pre-format the string with a + in the middle... e.g., the string
would say "colon+cancer" when passed to the function. It must pass this string (notice no spaces)
followed by the obligatory /0 (the string end).
The buffer used to return the string is defined as:
#define bufSize 65536
char buffer[bufSize];
18
This is a limitation on the size of the HTML file that can be returned. If you are not getting the
full HTML file, then change bufSize to something larger, preferably a base-2 number. If you are
consistently getting files that are much smaller than this, and memory is a concern, then you can
shrink bufSize.
The function first formats the header it is going to pass to the search engine. It then opens a
Stream socket. If the socket fails to open, the function fails and returns a NULL pointer. After
the socket is open, the function converts the hostname to an IP address (with the port hardcoded
to 80) and opens a connection to the server socket. It then sends the command string, which was
preformatted, to the server. If this fails, then the function fails and returns a NULL pointer. It
then buffers the input from the server. If the receive fails at any time during buffering, then the
function fails and returns a NULL pointer. After the buffering is completed, it closes the socket
and returns the string.
To make this function capable of searching multiple engines (say, X search engines), you would
have to repeat this process X times. You would then concatenate all of the strings returned by the
search engines into one long string, and return it.
To make this function able to search multiple engines, but only one at a time by user preference
(e.g., the user wants to search Altavista instead of AMA), you would have to include another
parameter in the parameter list. It would be logical to use an int.
char * getHtml(char *search, int engine);
You would then use a switch statement on engine to control which search engine is used, and the
procedure would be identical to what happens in the function now, except for that one change.
There would be significant overlapping of code (the same code inside the switch, over and over),
but that is the price you pay. The function will run in the same amount of time as the original
function; the object and executable code will only be larger.
Database
The ReadyMedic MySQL database provides the backend to the functionality of the ReadyMedic
project, including the web pages, the PDA device, and the operator. ReadyMedic approved
physicians are able to easily maintain and access medical information regarding their patients,
users of the device are able to view their personal information, and emergency operators can view
vital information of those who request emergency services. The database is designed to provide
security from inappropriate personnel gaining access to the information of ReadyMedic patients
using verification tables.
Using the insight gained in the user interface design meetings and information gained from
medical personnel, a database was implemented in mySQL including the attributes and
relationships shown in the entity-relationship diagram in Figure F-5.
19
Figure F-5
To provide the organization of the project, a single database entitled ‘Medical’ was created in
mySQL using the command:
CREATE DATABASE <database name>;
The Medical database includes eleven tables to hold the information of pertinent to the operation
of the ReadyMedic services. Tables were added to the Medical database using the command:
CREATE TABLE <tablename> (column specifications);
The twelve tables encompass the medical database include the following: ‘patient’ table with
common information, ‘Allergies’ table with information regarding allergies, ‘FH’ (family history)
table with information about medical problems in the patient’s family, ‘SH’ (social history) with
information regarding smoking, alcohol and drug usage, ‘HPI’ (history of the present illness)
table which documents all doctor’s visits, ‘PMSI’ (past medical and surgical information) table
with information about patient’s procedures, treatments and diagnosis, ‘medication’ table with
information about the medicines a patient may be taking and the prescribing physician, a ‘doctor’
20
table with general information about the physicians, and a ‘drlogin’ (doctor login) table requiring
a physician to have appropriate verification to make changes and updates to the database, a
‘operator’ table for verification of operators login and password, a ‘verify’ table which places a
link between the patient and the physician, and a ‘askadoc’ table which stores questions and
answers until they are sent to the appropriate person.
Below are tables describing the attributes of the tables described above.
patient pfname pminit plname pssn pstreet pstate pzip phphone pwphone pinsco pinsno pbdate
pec1fname pec1lname pec1street pec1city pec1state pec1zip pec1hphone pec1wphone
pec2fname pec2lname pec2street pec2city pec2state pec2zip pec2hphone pec2wphone
Allergies pid phallmed pallcon phallanes
FH pid phill prelation
SH pid palcoamt psmokyr psmokamt pdrugname pdrugstdate pdrugenddate
HPI pid cistartdate cistartloc cisymptoms ciworse cibetter cibefore cidiagnosis citreat cidate cidrid
PMSI pid phyear phdiag phproc phcompl
medication pid pmedname pmeddose pmedfreq pmedstdate pmedenddate
doctor drfname drminit drlname drstreet drcity drstate drzip drwphone drspec drlogin
drlogin drlogin drpassword
operator oplogin oppassword
verify drlogin pid
askadoc pid question drlogin qdate answer
WebPages
The ReadyMedic Website makes use of HTML, PHP, and a MySQL database on the backend and
an Apache web server. HTML (HyperText Markup Language) is the de facto standard for
building a web page. It is very simple to learn and provides many basic display necessities. PHP
is simply a scripting language that is pre-processed by the web server and then displayed as
HTML. The web server will grab the file, and if it is a PHP file (denoted by extension .php3), the
file will be passed on to the pre-processing module. Then a pipe is opened between the module
and the web server, and the web server pushes out whatever comes out of the pipe. PHP code can
be used literally anywhere in HTML, because it is used just like a tag (i.e., <?php mycode here
?>). PHP is used to take information from the HTML forms to the MySQL database on the
backend through the many built in functions and the easy use of PHP variables. For instance, if
you named a form element (via the name attribute) mytextfield, the text typed into the field could
21
be referenced through $mytextfield in PHP code. PHP is also used to dynamically generate
HTML. In general (with exception to the dynamic HTML creation pages), a PHP file will have
the following structure in our project:
1. Establish database connection (via mysql_connect(), mysql_select_db())
2. Data Testing and Validation
3. Do Database task(s) (via mysql_query())
4. Re-direct User to Appropriate Location and Set Appropriate Cookies (via header("Location:
$URL") and setcookie())
The design model for the ReadyMedic Website takes on a "pathways" form and provides what are
called “pseudo-sessions”. Once a user has begun a “pseudo-session”, the user follows a “path”
to get to the information needed. The window flow is something of the following: a login screen,
a screen allowing the doctor to choose which "pathway" to follow (i.e., Add a patient, Update a
patient, View Information and possibly Delete a patient). The previous paths are comprised of
the following:
 Add--two pages of information on the patient, the first general information and the
second more specific medical history
 Update--a page to choose what to update (General information, History of Present Illness,
or the more specific medical history), then a page to do such changes
 View—a page to request what information to view, the information page.
Each of these will involve a PHP page, since there will be queries, and an HTML page for the
user to enter the information into via forms. However, some of the HTML is generated
dynamically from PHP. Each path will now be discussed further.
Add a Patient
The Add a Patient pathway requires two pages of information on the patient, the first general
information and the second more specific medical history. Each of these requires an HTML file
and then a PHP file to insert the data. The two PHP files follow all steps from the general
algorithm above. Specifically in step 3, the query string used as the argument is of the form
“INSERT INTO <tablename> VALUES (<phpvar1>…<phpvarN>)”.
View Patient Information
The View Information pathway requires an HTML page to obtain information from the user, a
PHP page to process the choices made and a PHP page to display the results of the query. The
user is able to enter both a first and last name, or a patient id to obtain information. The first and
last name presented the problem of multiple records. The solution was to use another
intermediate PHP page to display key information about each “John Doe” in the database and let
the doctor select one based on id, as given. Once the information is retrieved, it is delivered back
via the mysql_query() function and is stored in $result. Then the mysql_fetch_array() function is
used so that information can be identified by the corresponding attribute name in the database.
Update Patient Information
The Update Information pathway includes a page to allow the user to choose what to update
(HTML and a PHP file), followed by several dynamically created web pages via PHP. The
dynamically created web pages query the database, then use syntax such as
print(“<myHtmlTagHere>”). By setting the value attribute on the HTML form tags equal to the
variable received back from the database query, the information already in the database is
inserted into the forms to be changed. Upon submission, the code first deletes the old record via
22
“DELETE FROM <tablename> WHERE <columnname>=’value’ ” and then inserts the new
information.
Login and Registration
Additionally, a login screen (HTML & PHP), as well as a doctor registration screen (HTML &
PHP), has been created. The login screen allows access via a “SELECT” query and the
registration screen allows doctors to enter their information via an “INSERT” query.
Patient Message View
This “pathway” includes a PHP file that retrieves all the questions for that doctor and posts them
in tables to be answered. Again PHP is used to dynamically create tables. In each table entry
there is a textfield, to allow the doctor to answer, and a submit button. Each text field/Submit
button combination corresponds to an entry in an array within the PHP code. Upon submission,
another PHP file will decide which question has been answered (based on the submit value) and
places the question and answer back into the database. This was done through an UPDATE
query so as not to destroy the data integrity of the database.
The setcookie(CookieName, CookieValue, ExpirationDate) function was used in a very important
way, that is to create “pseudo-sessions”. Within a “pseudo-session”, the cookie allows us to
maintain information about the user, provide a certain amount of security, as well as minimize the
amount of data entry when possible. The cookies currently used are CurPatID—which holds the
current patient’s ID number and CurDrID—which holds the current Dr.’s Login ID. The
CookieValue, which is just a string, can be accessed anywhere once set using a PHP variable
$CookieName.
Also, it should be apparent that all spaces in any of the entries are replaced with underscores. The
print() command in PHP will only print up to the first space when the argument is a variable. The
solution to this is to use the echo() command.
Emergency Server
The EmergencyMedic feature allows for the user immediate medical attention if an emergency
occurs. For example, if a user were having a heart attack, the user would hit the designated
EmergencyMedic button. This would prompt the ReadyMedic to capture the GPS string and send
it along with the device ID to the server. The server would then dispatch the GPS string and
certain medical information associated with the device ID to an available operator. The operator
would then have the location of the user in the world and would be able to dispatch the
appropriate emergency medical services. The whole process can be summed up in this diagram
shown in Figure F-6:
23
User invokes the
EmergencyMedic button.
ReadyMedic captures the
GPS string from the GPS
receiver.
ReadyMedic sends the
GPS string and device ID
to server.
The server queries
database for certain
medical information.
User’s life is saved!
Operator uses location
and medical information
to dispatch emergency
medical services.
Server sends GPS string
and medical information
to available Operator
program.
Server searches for an
available operator
connected.
Figure F-6
The EmergencyMedic service is broken up into four distinct parts: the NT Server, the Linux
ReadyMedic Server/ Database, the Operator application, and the ReadyMedic device. Each of
these has more subsystems, which we will go into detail later. An overview of the system is
pictured below in Figure F-7.
Linux
Server/Database
NT Server
ReadyMedic
Device
Operator
Figure F-7
This shows how each of the components piece together. The central component, the NT Server,
is the key part of the system. It handles requests for both the Operator and the ReadyMedic
Device as well as connections to the Linux Server to query the database. When the user hits the
EmergencyMedic button on the ReadyMedic, the ReadyMedic should open a serial port
connection and read the GPS data off the serial port. This will be described more in detail later.
Once the GPS string has been verified as correct data, the ReadyMedic sends the GPS string a
long with the ID of the device to the NT Server. The NT Server, which keeps track of Operators
logged into the system, then opens a connection with the Linux Server and sends the ID. Then it
waits for the Linux Server to send back the person’s information. Then it closes the connection
with the Linux Server. After that, it looks for an available Operator logged in and makes a
connection with it. It then sends the GPS string along with the person’s information to the
24
Operator. The Operator is notified that there is an incoming call and the Operator user is able to
view the coordinates of the person who requested the help and who that person is.
The nice feature of this system is that the Operator will be able to locate where this person is and
who this person is. No matter where a ReadyMedic user is in the world, they will be able to
request emergency assistance. The GPS device, the Motorola Oncore VP, is a very useful piece
of this project. Not only is it easy to use it also gives the means to track down a user’s location.
NT ReadyMedic Emergency Server
This is the key part of this system; this binds the system together and handles communication
between each of the parts. It listens on three separate ports, and it opens up to three separate
connections. It uses a networking set of functions called sockets. Sockets are the endpoints for
communication which allows an application program to “plug in” to the network and send data
(i.e. streams or blocks of bytes) to any other program that is also plugged into the network.
Because this server was written for the Windows NT Operating System environment, we used the
Microsoft Foundation Class CSocket. There are six method associated with creating, opening,
and reading and writing sockets: create(), connect(), listen(), accept(), receive(), send(). With
these functions, it is simple to create an application as a server or a client. The NT Server acts as
both a server and a client because of the way it routes the information to different location. To
start, I will go into the steps of setting up a server socket.
BOOL Create( UINT nSocketPort, int nSocketType, LPCTSTR lpszSocketAddress);
This method is called regardless whether or not you set up a socket connection as a server or a
client. What determines the difference is the parameters you send to it. For a server, you want to
specify a port number for nSocketPort. For our project, we used 7003, 7004, and 7005 to specify
the ports to listen for ReadyMedic connections, Operator logins, and Operator logouts
respectively. The nSocketType is set to SOCK_STREAM which uses TCP protocol and is
defined in one of the Windows libraries. This can be set to DGRAM and support the User
Datagram Protocol, but these can be somewhat unstable so we went with the TCP protocol. The
lpszSocketAddress is the IP address that you want to connect to. Since this is a server, we are not
connecting to anything we are accepting connection so we set it to NULL.
BOOL Listen( int nConnectionBacklog );
This method is specifically used for server applications only. It makes the socket a listening
socket and sets the maximum number of pending connections in the queue. This number is
denoted by nConnectionBacklog and it can not be more than 5. We call this in each of the server
threads.
BOOL Accept( CAsyncSocket& rConnectedSocket);
This method blocks until a connection has come in. That is why we had to set up three threads to
listen for different connections, which I will go into more later. You pass it the address of a
socket that you want to use for reading and writing. This is denoted by the rConnectedSocket
argument. Basically, it checks the queue periodically to see if a connection has come in. If there
is an incoming connection, then it will stop blocking it and you can handle the connection.
int Receive( void* lpBuf, int nBufLen, int nFlags );
virtual int Send( const void* lpBuf, int nBufLen, int nFlags = 0 );
These methods are used after a connection has been established. Using the rConnectedSocket
that was specified in the Accept call, data can be sent and received using Receive() and Send().
25
Receive waits until data has been sent to it. It can be configured to time out, but for our purposes
we did not bother setting it up. lpBuf is the string that is to be sent or received. We used this to
pass data in between process running on different machines. nbufLen is the size of the string you
are sending or receiving.
For more information about the CSocket class check the documentation in the Microsoft
Developer Network Guide.
Going back to the NT Emergency Server, we had to have three different sockets opened for
listening. Because Accept() is a blocking call, we needed a way to listen to several ports without
locking up the system. That involved using threads.
Operator
Query
operator ID
and password
Linux
Server
Query patient
information
ReadyMedic
Main Program
Op2NTServer
OpDisconnect
NT2LinuxOp
Operator
Logins
Operator
Logouts
ReadyMedic
connections
ServerThread
NT Server
Figure F-8
Figure F-8 is a more detailed version of the diagram to display the threads and the communication
between them. As you can see, there are three threads started in the NT Emergency Server.
There is one thread to listen for operators to log in. Once an operator attempts to login, the server
connects to the Linux Server and then the Linux Server queries the database and tells them
whether or not the operator name and password is in the database. If the Linux Server returns
“TRUE”, then the NT Emergency Server adds the Operator’s IP address to a linked list. Then
both connections are closed. The Operator now starts the ServerThread to listen for incoming
connections from the NT Emergency Server. Now, the NT Emergency Server has an IP of an
Operator stored in the linked list. This will allow the NT Emergency Server to open a new
connection with the Operator once a request from the ReadyMedic is made. The NT Emergency
Server is also listening for Operator Logouts. Once an Operator disconnects from the system, the
26
NT Emergency Server removes that from the linked list. The third thread that is running on the
NT Emergency Server is NT2LinuxOP, which is the thread that listens for ReadyMedic
connections. Once a connection is made, the NT Emergency Server makes a new connection
with the Linux Server and sends the patient ID that it received from the ReadyMedic. The Linux
Server returns to the NT Emergency Server the patient’s medical information. The NT
Emergency Server takes the first element off the linked list and opens a new connection with the
Operator program. It then sends the GPS string and the patient information to the Operator
program.
This is a very complex system because of so many components communicating with each other.
You might be wondering why we did not just simply used the Linux Server instead of making
this separate NT Server. Well, the Linux Server is connected via a DSL connection and is not on
the TAMUNet network. Therefore, the firewall prevents it from making connections inside
TAMUNet. The NT Server runs on one of the machines in the lab and therefore can make
connections inside and outside of TAMUNet.
Operator
Figure F-9
Figure F-9 shows the User Interface of the Operator program. As you can see, it is very simple.
There is a button to connect to the NT Emergency Server. There is a button to disconnect from
the NT Emergency Server. The bottom portion of the application is used solely when an
emergency occurs. Once an emergency occurs, a message box pops up notifying the incoming
emergency. The Alert Mode status is changed and the Latitude and Longitude coordinates are
set. The View button becomes active. Once the View button is active, the Operator can click it
and view the patient’s information: name, address, home and work phone number, longitude,
latitude, and the emergency contact.
27
Connecting
To connect to the server, the Operator hits the connect button. This brings up a password for
logging into the system. When the user hits ‘Submit’, the Operator program opens a connection
to the server as a client. To do this, we used the same class CSocket as we did above in the NT
Emergency Server. However, this time the Operator is a client instead of a server. We still call
create(), but this time we do not specify the port number.
BOOL Connect( LPCTSTR lpszHostAddress, UINT nHostPort );
Instead of calling Listen and Accept, we call a method named Connect. We need to specify the
address of the computer we are connecting to. The NT Emergency Server is located on
“barbrady.cs.tamu.edu”. The type of socket is still SOCK_STREAM. For our project, the port
number for Operator connections is specified as 7000.
If no errors have occurred, we can read/ write to the socket all we want. We send it the Operator
name and password and the NT Emergency Server returns whether the name and password is
valid. It is valid, the Operator is now logged in. It starts its own thread, ServerThread, to listen
for incoming connections. Starting a thread in Windows is simple using the Microsoft
Foundation Classes. You create a thread in this format:
UINT ServerThread (LPVOID pVoid)
pVoid is a void pointer and the function must return an unsigned integer, which represents the
exit code. If it returns a negative one, then the thread has been closed by some other means than a
normal exit. To start the thread, we call AfxBeginThread(ServerThread) and it starts running. In
our implementation, we call Accept, which is a blocking call. To be able to close this thread
outside the thread, we have to call CancelBlockingCall on the socket it has opened. This exits the
Accept function and then exits the thread.
Server Thread
The ServerThread opens a socket for listening. It waits for a connection from the NT Emergency
Server. Once a connection has been made, it reads the GPS string and information from the NT
Emergency Server and notifies the Operator user that of the incoming connection. It parses the
GPS string into the longitude and latitude coordinates and displays all the information into the
appropriate windows.
Parsing the GPS string is simple; we simply look for commas as breaks of the data. Here is the
break down of the GPS string:
$GPGGA,[1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12] *hh[CR][LF]
[1] – UTC time of position fix, hhmmss format.
[2] – Latitude, ddmm.mmmm format.
[3] – Latitude hemisphere, N or S.
[4] – Longitude, ddmm.mmmm format.
[5] – Longitude hemisphere, E or W.
[6] – GPS quality indication. 0 – no GPS, 1 – GPS acquired.
[7] – Number of satellites to use.
[8] – Horizontal dilution of precision, 1.0 to 99.9.
[9] – Antenna height above/below mean sea level.
[10] – Geoidal height.
[11] – Differential GPS (RTCM-SC104) date age.
[12] – Differential Reference Station ID,0000 to 1023
*hh – Checksum value in hex.
28
For our purposes, we parse the [2], [3], [4], and [5] elements of the string.
Disconnecting
Disconnecting from the NT Emergency Server is basically the same as connecting to it. It simply
opens a connection to “barbrady” on port 7005 instead of port 7000. It sends a disconnect
message to the NT Emergency Server and the NT Emergency Server removes the Operator’s IP
from its list.
This application consists of using the ReadyMedic of three parts. One to start a thread to count
down to ten. Another to communicate with the serial port to obtain the GPS string from the
Motorola Oncore VP. The last to connect to the NT Emergency Server. To handle the serial
communications between the GPS device and the Mobile Pro, the serial port needed to be
configured. A class called CComm was created, which opened the serial port, closed the serial
port, read the serial port, and verified the data sent.
Count Down Thread
The CountDown thread was made to help deter mistakenly making calls to the NT Emergency
Server. Basically it launches a thread to Count down for ten seconds. In that time the user can hit
the “Abort” button to cancel making the call. If it does not cancel the call, it will open the serial
port and read the GPS string off the serial port. It checks to see if the data is valid and then sends
it to the NT Emergency Server.
Opening the Serial Port
The opening the serial port method is the most important step in configuring the serial port. In
order to open the serial port, the function CreateFile is called to initialize the serial port to be
read. The COM port is specified as COM1: and opened for GENERAL_READ and
GENERAL_WRITE. There is a struct type called DCB, which is used to set up the serial port’s
properties. Here is the current setup:
PortDCB.BaudRate = CBR_4800;
PortDCB.fBinary = TRUE;
PortDCB.fParity = TRUE;
PortDCB.fOutxCtsFlow = FALSE;
PortDCB.fOutxDsrFlow = FALSE;
PortDCB.fDtrControl = DTR_CONTROL_ENABLE;
PortDCB.fDsrSensitivity = FALSE;
PortDCB.fTXContinueOnXoff = TRUE;
PortDCB.fOutX = FALSE;
PortDCB.fInX = FALSE;
PortDCB.fErrorChar = FALSE;
PortDCB.fNull = FALSE;
PortDCB.fRtsControl = RTS_CONTROL_ENABLE;
PortDCB.fAbortOnError = FALSE;
PortDCB.ByteSize = 8;
PortDCB.Parity = NOPARITY;
PortDCB.StopBits = ONESTOPBIT;
PortDCB.EvtChar = '$';
29
The baud rate is set for 4800, which is the speed that it needs to be to capture the GPS string from
the Oncore VP. Notice the event character being set as a ‘$’. This character signals the program
to start reading the characters into a buffer. Next, the SetCommState is called with the DCD
struct to set up the COM port with these settings. The GetCommTimeouts and
SetCommTimeouts are called to configure timeouts. These are not important because there are
no timeouts set. The last function called is SetCommMask with the EV_RXFLAG parameter.
This sets the serial port to watch for the event character.
Reading the Serial Port
Reading the serial port is fairly simple. WaitCommEvent is called to wait for the event set up by
the SetCommMask. For the GPS string, it waits until it sees a ‘$’ pass through the serial port.
ReadFile is called to read one byte in from the serial point. The character is checked to see if it is
a valid character and then it is stored in the buffer. It keeps reading until a newline character is
read in.
Closing the Serial Port
Closing the serial port is very simple. CloseHandle is called to close the serial port. The serial
port is now available to be opened by another program.
Verifying the Data
The Motorola Oncore VP, basically sends data in this format:
$GPGGA,[Location and Time],*[Checksum]
There is also a ‘\r’ and a ‘\n’ at the end of the string. A simple way to view this would be to open
a HyperTerminal Window with a 4800 baud connection. You would see that the Motorola
Oncore VP simply repeatedly writes this to the serial port. There is no message passing or
anything like that. Sometimes, the information received off the serial port is corrected and needs
to be checked. That is why the Oncore sends a checksum to the serial port. The checksum is
equivalent to each byte XOR’ed together from the character after the ‘$’ up to and including the
‘*’ character. Our algorithm simply scans through the characters and XORs them together. It
then converts the calculated checksum to a string and compares it to the checksum received from
the Oncore VP.
Connecting to the NT Emergency Server
This is one area which we were not able to complete due to a bug in the Windows CE build that
we have. There is a corresponding class to Windows CSocket for Windows CE. It is called
CCeSocket. It is suppose to have the exact same functionality just implemented slightly
differently. However, when we attempted the same connections using the CCeSocket class as we
did for the CSocket class it failed. We made a program to emulate the functionality of this
connection in Windows NT called testclient. Basically, it sends a hard coded GPS string and
patient ID to the server. For this, we make a client connection using the port number 7003. It
then sends the GPS string and the patient ID to the server and closes the connection.
Linux Server and Database
This part of the system is used to query the database on the ReadyMedic server
“ReadyMedic.dyndns.org”. This allows the NT Emergency Server to verify the operator login
and obtain the patient information. This piece is broken up into two separate processes:
emergency1 and emergency2. Emergency1 handles all the requests from the NT Emergency
Server dealing with operator logins. It uses a library called queryclient to determine if the
operator name and password is in the database. If it is determined that the operator is in the
database, then it sends back “TRUE”, otherwise it sends back “FALSE”. Emergency2 handles all
30
the requests from the NT Emergency Server dealing with patient information. It reads in the
patient ID and queries the database. It then sends all the information back to the NT Emergency
Server.
Both of these processes are very similar and use the same principles of sockets. Since this is on a
Linux server, they use Berkeley Sockets and not Windows sockets. Berkeley sockets are very
similar, but require more function calls than the Windows sockets. The processes are set up to
listen on two separate ports for incoming requests from the NT Emergency Server.
LabVIEW Medical Devices & MedDevice Program
The purpose of this document is to explain the design and workings of the medical device
interface for the ReadyMedic. The LabVIEW simulation will first be discussed, and then the
workings of the MedDevice program will be considered.
Figure F-10 – Medical Device Simulation Control Panel
31
The medical device attachment is made up of two parts. First, there is the medical device
simulation. This was implemented using LabVIEW. The control panel of the interface is shown
in Figure F-10. This simulation simply sends a string, along with some control characters, down
a serial port. The serial port can be set. As default, the serial port is COM2 and the baud rate is
9600.
To use the simulation, all you have to do is choose which device you want to simulate. There are
four devices.
1.
2.
3.
4.
Thermometer
Blood pressure
Pulse
Blood sugar
You simply set the value that you want on the device you wish to model, choose which cluster to
send using the knob at the bottom right, and then press the red arrow on the top left of the screen.
To stop the simulation, you press the green Program State button on the bottom right.
Figure F-11 – MedDevice User Interface
The second part of the medical device attachment is the MedDevice executable, which runs on
the ReadyMedic. The user interface for MedDevice is shown in Figure F-11. To use this
program, all you need to do is press “RUN”. After that, it will read in data from the serial port
(from the LabVIEW simulation) and display the data in the proper text box. The other three
instruments that are not being simulated will show “N/A”. The data is then logged to a text file
called “meddevices.txt” that is in the same directory as the executable. In order to ensure data
integrity between the simulation and the ReadyMedic, the MedDevice executable should be
started (i.e., you should press run) before the LabVIEW simulation has begun.
The LabVIEW module is fairly simple. The schematic diagram is shown in Figure F-12.
32
Figure F-12 – LabVIEW simulation schematic diagram
To change the port number, you simply change the integer constant next to the loop. 0=COM1,
1=COM2, and so on. The baud rate is set at 9600. You may need to change the port number
based on which serial port you hook the ReadyMedic up to on your PC. The rest of the diagram
is self-explanatory. It would not take much work to add more devices. You would also have to
edit the MedDevice executable, however, to deal with these new devices.
The MedDevice executable is fairly simple. Each button has an action associated with it. When
RUN is pressed, the program initializes the serial port, opens it, and begins reading from it. It
waits for a ‘$’ before accepting any characters. It stops reading when it receives a ‘\n’, or
newline character.
To modify MedDevice, you need Microsoft Visual C++ 6.0. If you wish to add a device, you use
the Class Wizard to edit the existing class, and add fields as you see fit. You then go to
MedDeviceDlg.cpp and edit the source code to deal with the extra text box. You need to edit the
methods:
1.
2.
3.
4.
void CMedDeviceDlg::ShowReceivedMessage(LPARAM message, int type);
int CMedDeviceDlg::StringType(TCHAR *text);
TCHAR * CMedDeviceDlg::StringParser(TCHAR *text);
void CMedDeviceDlg::FileWriter(TCHAR *text, int type);
The method, ShowRecievedMessage, simply prints the parsed string out in the correct text box.
Method StringType returns an int, and differentiates between the types of strings for the other
functions; 1 is temperature, 2 is blood pressure, 3 is pulse, and 4 is blood sugar. Method
StringParser simply returns the string, minus the character that identifies which type it is. Method
FileWriter writes the data to a file, based on what type it is and the data associated with it.
33
TEST REPORT AND RESULTS
Beta Testing
The web component of the ReadyMedic project was involved in Beta testing using medical
personnel. Three individuals who are third year medical students at Baylor College of Medicine
were given tasks to accomplish using the website www.ReadyMedic.dyndns.org with given login
ids and passwords. The tasks included adding a new patient, updating information on a current
patient using the history of the present illness form and viewing the information that they had
inserted. One of the persons was observed using the website and areas of difficulty and
frustration were observed. The following items were mentioned and observed by these persons
and were corrected to improve the project.



Alignment of the secondary emergency contact information.
Lack of acceptance of the last name of emergency contact persons.
Inadequate information accepted and returned from the Social History entry form.
The following items were mentioned by these persons, and due to the lack of time we were not
able to adequately make changes.




Physical Exam form on the site for input on History of the Present Illness would be
beneficial.
‘Submit All’ button when entering information in multiple categories of the adding a new
patient and updating patient web pages.
View all patient information on one screen as well as viewing each category separately.
Smaller input boxes for Family History input to account for the size of the entries in the
database.
Component Testing
As the project was assembled, each person tested individual components apart for the rest of the
project. For instance, a main module was created for QueryClient and it was thoroughly tested
before it was built as a library . Before it was known that Windows CE sockets calls would not
operate correctly, rmClient() was created to exercise the ReadyMedic Linux server. TestClient()
was created to exercise the emergency server. The MedDevice interface was able to be tested
apart from the rest of the ReadyMedic user interface, largely due to the fact that it is run as a
separate process. Thus, as each component was created, its component testing module was run
and the output was verified. Every module underwent this testing before being incorporated into
the large whole, and top down testing progressed.
Top Down Testing
Although it would have been ideal to have several typical users use the device for several days as
a part of the testing phase, this was not possible because of time constraints and the need for cord
connectivity for several of the features. However, the team spent a day participating in top down
testing of the medical device and web pages. Individuals of the team spent time using the
functions of the project that they were not directly involved in developing and looking for any
problems or inconsistencies. The following bugs were found:
34







In the Doctor Reply web page, the doctor may not enter an apostrophe. Although hitting
submit seems to work normally, the reply never seems to make it into the database.
In the Ask A Doc portion of the ReadyMedic user interface, the user may not type
punctuation (such as !,.?) to the doctor. Although it will transfer and be processed okay,
the resulting expected filename will expect to have that punctuation in it, which is illegal
for a Windows filename.
Cookies apparently do not work with the htmlView module.
When a scheduled medicine is completed and removed, it removes all other medicines,
and occasionally displays error messages. This error was fixed to perform normally.
Information was passed incorrectly from the queryClient module to the Operator module.
The systolic reading sent from LabVIEW to the ReadyMedic can only display 2 digits,
and thus values above 99 will only display the upper two digits.
htmlView does not handle the post method, however, it does accept the get method.
35
CONCLUSION
The ReadyMedic project collaborated many of the aspects of our college education and forced us
to use these components to provide useful deliverables. These topics incorporated Software
Engineering, Operating Systems, Networks, Databases, and Microprocessor Systems Design.
The following is a list of the topics, which were researched and used in the actual development,
and topics researched and then not even required in the implementation.
Development:
 Windows 98/NT/CE Programming
 Linux Programming
 Serial Prot, TCP & Client/Server Programming
 Multithreading
 Inter-Process Communication
 Linux System Administration
 MySQL Database Administration
 C API
 HTML
 PHP
 LabVIEW
Research Only:
 VPN
 Perl
 Sockets
 MedDevice Connection
Thus, this project has been good at integrating our entire education together. All members
were able to learn a great deal of new information and apply it successfully in the design of
the ReadyMedic.
36
ACKNOWLDEGEMENTS
The ReadyMedic project group would not have been able to successfully complete much
of this project without the insight and expert advice of the individuals listed below:

Cam Baker – University representative of Microsoft who aided us in obtaining
upgrades for WinCE 2.12 and Internet Explorer 4.01 for WinCE in our attempts
to work around Microsoft bugs.

Aaron King – Employee of National Instruments who gave insight into means of
modeling medical devices in LabVIEW for use with the ReadyMedic device.

Dr. Rabi Mahapatra – Course professor who helped us in all stages of
development of the ReadyMedic, especially with all the problems we faced.

Prof. Willis Marti – Networks professor who assisted us in troubleshooting
problems in connection with sockets.

Kamran Shah – Employee of National Instruments who gave insight into means
of modeling medical devices in LabVIEW for use with the ReadyMedic device.

Robert Tate – Robert never failed to always be in the right place at the right time
to give us valuable advice whenever we a problem would arise.
37
REFERENCES
Books
Boling, Douglas. Programming Microsoft Windows CE. Microsoft Press: 1998.
Burdick, Robert. Essential Windows CE Application Programming. Wiley Computer
Publishing: 1999.
Turner, Alice (Project Editor). Microsoft Windows CE: Communications Guide.
Microsoft Press: 1999.
Turner, Alice (Project Editor). Microsoft Windows CE: Programmer’s Guide. Microsoft
Press: 1999.
Turner, Alice (Project Editor). Microsoft Windows CE: User Interface Services Guide.
Microsoft Press: 1999.
WebSites
Apache – www.apache.org
GPS – www.mot.com/ies/GPS/products/prodvp.html
Last Semester’s GPS Team - http://www.cs.tamu.edu/courseinfo/cpsc483/common/99c/g2/g2.html
Linux administration - www.linux.org
Microsoft Developer’s Network – www.msdn.microsoft.com
MySQL – www.mysql.org
MySql Development - www.devshed.com/Server_Side/MySQL/Administration
PHP – www.php.net
Redhat Linux - www.redhat.com
USB Implementers Forum Homepage – www.usb.org
Webmonkey-The Web Developer’s Resource – www.webmonkey.com
Windows CE – www.microsoft.com/windowsce
38
Download