This is Info file appman.info, produced by Makeinfo-1.64 from the input file appman.texi. This text describes the concepts, operation, and maintenance of the ProtoGen/HL7 interface to HP's clinical information system CareVue as well as the ASTM to HL7 converter for the acid base laboratory Radiometer ABL 500 and 600 series. Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies. Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one. Permission is granted to copy and distribute translations of this manual into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by the Free Software Foundation. Copyright (C) 1996 Gunther Schadow  File: appman.info, Node: cvgateway, Next: idb_direct, Prev: CLI, Up: CareVue Interface The HL7 to CareVue Gateway Program ================================== Synopsis ........ cvgateway [-x] SERVICE FSI_SERVICE FSI_HOST FACILITY Description ........... This is a HL7 server application that acts as a gateway for the HP CareVue 9000 Clinical Information System. CareVue comes with a limited HL7 interface, that requires transformation of messages, addtion of a non-standard ZDM segment, removal of other (standard) segments, decomposition of some messages, and change of field contents etc. See *Note CareVue Interface:: for more. The `cvgateway' process accepts ILLP driven TCP connections (see *Note ILLP::) on the port SERVICE. Messages are forwarded to CareVue via ILLP/TCP connections made to FSI_HOST at port FSI_SERVICE. The FACILITY name used by the `cvgateway' application its the same as the receiving facility for carevue and specified by the last argument. The following messages are accepted, if allowed for the requesting connection tag, host, facility and application (see *Note ILLP:: and *Note hl7hosts::). The contents of the message is interpreted and changed as explained in *Note ADT:: and *Note CLI::. The messages are then handled as follows: `ADT^A01 (admit patient)' The CareVue census is examined and the following cases are distinguished: *patient is unknown* Forward the message to the ADT application, patient will be admitted. *bed is occupied by other patient* Forward the message to the ADT application, but clear the assigned patient location. The patient will be admitted without bed to the waiting list. *patient is known already* Derive an A08 message to update the patient data. `ADT^A02 (transfer patient)' The CareVue census is examined and the following cases are distinguished: *patient is unknown* Try an admission (A01) with the data that is supplied in the message if the assigned location is within the scope of the CareVue census. If transfer is out of care-unit, an AE is reported. *patient known, new bed occupied by same patient* The patient was transferred already, do nothing. *patient known, new bed occupied by other patient* The transfer action cannot be completed, AE is reported. *patient known, new bed is free* Forward the message to the ADT application, patient will be transfered. `ADT^A03 (discharge patient)' The CareVue census is examined and the following cases are distinguished: *patient is unknown* Return an application error (AE). *patient is known* Forward message to ADT application, patient will be discharged. `ADT^A08 (update patient information)' The CareVue census is examined and the following cases are distinguished: *patient is unknown* Try an admission (A01) with the available data. *patient is known already* Forward the message to the ADT application, the patient information will be updated. `ADT^A11 (cancel admit)' `ADT^A12 (cancel transfer)' `ADT^A13 (cancel discharge)' Forward the request to the ADT application. The effect of these messages is *not* controlled. See the CareVue documentation (if you have some more of it than I do). `ADT^A17 (swap patients)' The CareVue census is examined. Since there are two patients there are many cases to distinguish. *some patient is unknown* Do *not* try an admission *one patient is known* Try to transfer (A02) the known patient *both patients are known* Forward the request to the ADT application, the patients will be transfered to their new locations if these are free or mutually occupied, otherwise the census will be unchanged (CareVue will report AA anyway). The actions that CareVue takes are *not* controlled in any detail. `ORU (report results)' Forward the message to the CLI application. `NMD (network data)' If the RECEIVING APPLICATION is the application name of the `cvgateway' program (`CVGATEWAY'), the reply is generated. Otherwise the message is forwarded to CareVue. If the type of a message is changed, the handling procedure is repeated as if the original request message was of the new type. For instance, if the request message was A08, and the patient is unknown the type is changed to A01. The A01 message handler then tests the census again and checks for an occupied bed, etc. Options ....... `-x' Use exact match semantics for interpretation of the access control list (see *Note hl7hosts::). Examples ........ The `cvgateway' program is typically started by init(8) using the `/etc/ttys' or `/etc/inittab'. `/etc/ttys' cvgateway -x carevuehl7 carevuefsi localhost 060_IOP Environment ........... `PG_CODELIB' The location of the external code databases for LOINC, LabEventInfo and units. This is rarely used, since everyone uses the names compiled into the programs. Files ..... `/usr/hl7/var/log/CVGATEWAY/060_IOP/REQ####' The `cvgateway' program writes a copy of each HL7 message as a file to a directory whose name is composed of the APPLICATION and FACILITY names. The filename is composed of the string `REQ' and the process id (PID) of the cvgateway process attached to it. `/usr/hl7/var/log/CVGATEWAY/060_IOP/ACK####' Likewise the acknowledgment HL7 message is written into the same directory with the same PID number attached to the prefix `ACK'. `/tmp/cvgateway.log' The run log file, if syslog(3) is not used instead. Bugs .... The process id is certainly a bad choice for numbering files, because process ids will repeat and thus do not reflect the order in time of the messages. See Also ........ *Note ADT::, *Note CLI::, *Note idb_direct::, *Note ILLP::, *Note hl7tocv::.  File: appman.info, Node: idb_direct, Next: LabEventInfo, Prev: cvgateway, Up: CareVue Interface Direct Access to CareVue's Database =================================== Synopsis ........ idb_direct -e EVENT -r RECNO -l BED [-s RECNO2] [-m BED2] [-n NBED] [-c] [-H HEIGHT] [-W WEIGHT] [-S BSA] idb_direct -e 1|8 -r RECNO -l BED [-c] [-H HEIGHT] [-W WEIGHT] [-S BSA] idb_direct -e 2 -r RECNO -l OLD_BED -n NEW_BED idb_direct -e 3 -r RECNO -l BED idb_direct -e 17 -r RECNO1 -l BED1 -s RECNO2 -m BED2 Description ........... CareVue does only accept medical record numbers (RECNO) for patient reference. CareVue's own HL7 interface fails to report many application error conditions, such as admitting a patient into an occupied bed. This script takes the medical record number(s) and bed identifier(s) of a patient (or a pair of patients) and tests 1. whether the bed is free or occupied, 2. whether the patient is known or unknown (by his/her record number), and 3. whether the given (known) patient is assigned to the given (occupied) bed or else the bed is occupied by a different patient. Currently, however, there is no way to report the identity of the other patient back to the calling program. For the HL7 EVENTs A01 (admission), A03 (discharge), and A08 (update pat. info.), only the first bed/patient is tested. For A02 (transfer) the second RECNO is set equal to the first while the first BED is the source BED and the second BED is the destination bed. Thus one can test, whether the patient was already transfered to the new bed (i.e. if the second bed is occupied by the given known patient). *NOTE* All patient locations are assumed to be within one and the same careunit. If observations (WEIGHT, HEIGHT, and BSA) are supplied and the commit flag (`-c') is also given, these values are written into the patient record. If the relevant entities (`AdmitWt', etc.) do not yet exist, they are inserted and linked to the patient record before. Any write access to the database requires the patient record to be known to the patient manager in order to avoid severe database havoc. Therefore the `ptMgrSup' program is repeatedly polled until the patient is found. This can be most efficiently handled by waiting for the admitted patient to appear in the census (`ptMgrSup -c') only during the commit phase (`-c') of the admission (`-e 1') transaction. Thus any successive transaction can be quite sure that it won't get into conflict with a pending admission. The idb part requires the script `new_wt_ht_bsa' to be accessible within the standard path in the CHARTING domain. This bourne shell script calls `dbload' in order to insert new entities in the ADT observation classes. Return Value ............ The return value is to be interpreted as a bit-set, where the least significant triple denotes the first (or only) given BED/RECNO and the more significant triple denotes the second BED/RECNO. The most significant bit is the error flag. The following table defines the meaning of each bit in a triple: Bitset Value Meaning ------- ------- ------------------------------------------------ 001 1 bed is occupied (by whoever) 010 2 patient is known (assigned to whatever location) 111 7 bed is occupied, patient is known, and given patient is assigned to the given bed The `idb_direct' script issues CareVue system messages if a patient that is to be admitted will be put on the waiting list because the assigned patient location is occupied (see *Note cvgateway::). The actions being taken by this script highly depend on local considerations. They can be programmed differently. Shell scripts provide an easy way of prototyping changes regarding it's use in other circumstances. It is only required not to change the interface of this script, i.e. the argument list format, and the results presentation to the calling program. Options ....... `-e EVENT' The ADT EVENT number out of 1, 2, 3, 8, and 17. `-c' Commit flag, tells that the CareVue database is to be updated. Without the commit flag the database will not be changed. `-l BED' The patient location, a valid term for `name' of `BedConfig'. `-m BED2' The patient location for the second patient for the EVENT number 17 (swap). A valid term for `name' of `BedConfig'. `-n NEW_BED' The new patient location in a A02 (transfer) transaction. A valid term for `name' of `BedConfig'. `-r RECNO' The medical record number (`medRecNum'). `-s RECNO2' The medical record number (`medRecNum') of the second patient in a swap transaction (EVENT == 2). `-H HEIGHT' The HEIGHT for the admit height (`ht'). `-W WEIGHT' The WEIGHT for the admit weight (`admitWt'). `-S BSA' The surface area value for the body surface area (`BSA'). Examples ........ The `idb_direct' program is normally only called from a `cvgateway' process. Test for admission of patient 12345 into bed 601-1: /usr/hl7/etc/idb_direct -e 1 -r 12345 -l 601-1 Test for transfer of patient 12345 from bed 601-1 into 604-7: /usr/hl7/etc/idb_direct -e 2 -r 12345 -l 601-1 -n 604-7 Test for update of patient 12345 in 601-1. Update the admission observations if the patient does exist in the census: /usr/hl7/etc/idb_direct -e 8 -r 12345 -l 601-1 -c -H 182 -W 75 -S 2.7 Test for swapping patients 12345 into 601-1 and 54321 into 604-7: /usr/hl7/etc/idb_direct -e 17 -r 12345 -l 601-1 -s 54321 -m 604-7 Environment ........... `ADMIN' The e-mail address of a system administrator who gets error and warning messages mailed. This variable need not exist, it is better to let the system look for its value in the file `/usr/hl7/etc/admin' `CAREVUE' The rcp address (`LOGIN@HOST') of the carevue system in order for rcp or rsh to execute CareVue `idb', `dbload' and `ptMgrSup' commands. The user and host who runs `idb_direct' must have an `.rhosts' entry in this account. This variable need not exist, it is better to let the system look for its value in the file `/usr/hl7/etc/carevue'. Files ..... `/usr/hl7/etc/admin' The e-mail address of a system administrator who gets error and warning messages mailed. `/usr/hl7/etc/carevue' The rcp address (`LOGIN@HOST') of the carevue system in order for rcp or rsh to execute CareVue `idb', `dbload' and `ptMgrSup' commands. The user and host who runs `idb_direct' must have an `.rhosts' entry in this account. `CVUSER@CVHOST:new_wt_ht_bsa' This file must reside in the login account for carevue command execution. It is needed to run `dbload' on it in order to create new admission weight, height, and BSA entries. See Also ........ `sh(1)', `rcp(1)', `rsh(1)', `idb(1)', `dbload(1)', `ptMgrSup(1)', *Note cvgateway::.  File: appman.info, Node: LabEventInfo, Next: hl7tocv, Prev: idb_direct, Up: CareVue Interface Configuring Results Mapping =========================== * Menu: * LabEventInfo.tab:: The LabEventInfo Table * LabEventInfoMgr:: Managing the Results Mapping  File: appman.info, Node: LabEventInfo.tab, Next: LabEventInfoMgr, Prev: LabEventInfo, Up: LabEventInfo The LabEventInfo Table ---------------------- Description ........... The `cvgateway' program needs information about CareVue `LabEvent's, in order to bring observation results into the right unit needed for carevue and to adjust the format and precision of the measurement value. The `LabEventInfo' table has the following attributes: `loinc_num' LOINC code number (or some other observation identifier). `labEventClass' CareVue's `LabEventClass' `property' CareVue's `property' of the `LabEventClass', usually `value1' `msmt' CareVue's `MsmtClass' `unit' unit of measure in which the measurement is expressed in CareVue `constUnit' unit of a constant that can be used to convert between two related units. Typically specifies molar masses for conversion between substance concentration and mass concentration `constValue' value of the conversion constant `minVal' minimal allowed value for the measure in CareVue `lowAlert' low alarm boundary `lowNormal' low boundary of reference value `highNormal' high boundary of reference value `highAlert' high alarm boundary `maxVal' maximal allowed value for the measure in CareVue `increment' increment configured in CareVue (e.g. `0.001') `precision' precision configured in CareVue (e.g. `3'). Functionally dependent with `increment'. This database exists in two forms: the tabular (`source code') form is used by humans to edit the table, while the compiled, hashed form is used for fast access by the `cvgateway' program. The tabular form simply specifies one tuple (row) per line and separates the columns by colons (`:'). Commentary lines are allowed to start with a number sign (`#') as the first character of the line. An empty numeric field is treated as zero and an empty string field is treated as NULL. The checking of boundaries is turned off by setting the boundary equal to the high boundary (preferably both to zero). Specialities of `cvgateway' ........................... The `cvgateway' program has some special interpretations to the entries of the `LabEventInfo' database. Since the laboratory result are currently received only from the ABL,(1) and since our CareVue configuration distinguishes between venous and artherial ABL results in order to perform calculations with the two. Some measurements, like hemoglobin, had to be doubled in the LOINC code to provide for the additional knowledge about the exact specimen source. On the other hand, the LOINC specimen source code lacks exact differentiation of venous blood between peripheral venous, central venous and mixed venous. There is an implied entry in the LabEventInfo database defining the `BGATYPA' and `BGATYPV' parameter. The values that are currently transmitted to CareVue for these "observations" are from and ad-hoc code table, that does neither respect any standard, nor is it good for international use (german abbreviated word `unbek.' for "unknown"). However, this is an ad-hoc solution that was quickly programmed and can be changed in the `cvgateway' sourcecode(2). *soapbox* This shows the enormous interoperability problems evolving when coding systems are not complete. Every work around this problem is essentially a hack, the interim solution can be to facilitate coding systems mapping (which is not trivial) but this will *never be* a final solution. A successful EDI standard must provide a consistent and complete set of coding systems for use among all implementation in order to grant interoperability. *end soapbox* If the `property' value is set to `*BGATEMP*' the `cvgateway' will look up the observation identifiers `BGATEMPA' or `BGATEMPV' depending on the specimen source being arterial or venous respectively. The freedom to define additional `LOINC+' codes is stressed too much if we defined artherial and venous temperatures. Examples ........ Some example lines for this database are: # Admit weight, height and BSA # "3138-5":"":"":"H":"cm":"":0:0.5:0:0:0:0:300.0:1.0:1 "3142-7":"":"":"W":"kg":"":0:0.20:0:0:0:0:250.00:1.0:2 "3140-1":"":"":"S":"m2":"":0:0.5:0:0:0:0:300.0:0.01:2 # # type of blood specimen # "BGATYPA":"Ursprung_art__CFG":"value1":"UrsprArtBGAMsmt":::::::::::: "BGATYPV":"Ursprung_venĪ_CFG":"value1":"UrsprungVBGACode":::::::::::: # # temperature (map 9984-6/"BODY TEMPERATURE" to BGATEMPA or BGATEMPV) # "9984-6":"":"*BGATEMP*":"cel":"":::::::::::: "BGATEMPA":"a__BGA_Temp_CFG":"value1":"cel":""::25:0:0:0:0:45:0.1:1 "BGATEMPV":"v__BGA_Temp_CFG":"value1":"cel":""::25:0:0:0:0:45:0.1:1 # # PO2 # "2703-7":"PaO2_CFG":"value1":"O2Msmt":"kPal":"":0:0:0:0:0:0:40:0.1:1 "2704-5":"PaO2_CFG":"value1":"O2Msmt":"kPal":"":0:0:0:0:0:0:40:0.1:1 "2705-2":"PVO2_CFG":"value1":"O2Msmt":"kPal":"":0:2:0:0:0:0:40:0.01:2 # # Hb. HbO2. HbCO. metHb # "9948-1":"t_Hb_CFG":"value1":"t_HbMsmt":"g/dl":"kg/mol":16.113439:0:0:0:0:0:30:0.1:1 "9947-3":"t_Hb_CFG":"value1":"t_HbMsmt":"g/dl":"kg/mol":16.113439:0:0:0:0:0:30:0.1:1 "2714-4":"art__HBO2_CFG":"value1":"ArtHBO2Msmt":"%":"":0:-20:0:0:0:0:100:0.1:1 "2715-1":"art__HBO2_CFG":"value1":"ArtHBO2Msmt":"%":"":0:-20:0:0:0:0:100:0.1:1 # # K+, Na+, Ca++, Cl-, Glucose # "6298-4":"Kalium_i_S__m_CFG":"value1":"KMsmt":"mmol/l":"g/mol":39.0983:0:0:0:0:0:8:0.1:1 "2947-0":"Natrium_i_S___CFG":"value1":"NaMsmt":"mmol/l":"g/mol":22.9898:0:0:0:0:0:500:1:0 "1994-3":"Calcium_i_S___CFG":"value1":"CaMsmt":"mmol/l":"g/mol":40.078:0.5:0:0:0:0:25:0.1:1 "2069-3":"Chlorid_i_S___CFG":"value1":"ClMsmt":"mmol/l":"g/mol":35.4527:1:0:0:0:0:150:0.1:1 "2339-0":"Glukose_i_S___CFG":"value1":"GlcMsmt":"mmol/l":"g/mol":180.16:0:0:0:0:0:100:0.1:1 Files ..... `/usr/hl7/etc/LabEventInfo.tab' the tabular source version `/usr/hl7/lib/codes/LabEventInfo.db' the compiled, hashed file See Also ........ `odbm(3)', `gdbm(3)', *Note LabEventInfoMgr::. ---------- Footnotes ---------- (1) not because we don't want to receive results from the laboratory dept., we would like to if only they were available electronically (2) file `report_results.cc'  File: appman.info, Node: LabEventInfoMgr, Prev: LabEventInfo.tab, Up: LabEventInfo Managing the Results Mapping ---------------------------- Synopsis ........ LabEventInfoMgr [-cru] FILES ... LabEventInfoMgr [-DM] Description ........... The `LabEventInfoMgr' program is the "manager" for the `LabEventInfo' database. It is used to create the compiled, hashed form of the database from the tabular form or to dump the contents of the compiled form into the tabular form. An `idb' script can be generated from the database that when run creates a `LabEventMap' that is thus always consistent with the `LabEventInfo' database. Options ....... `-c FILES ...' create the database `-r FILES ...' update the database (update) `-u FILES ...' update database (insert) `-D' dump database into the tabular form `-M' create idb script for LabEventMap Examples ........ After updating the file `LabEventInfo.tab' use: LabEventInfoMgr -c LabEventInfo.tab to rebuild the compiled database, and then LabEventInfoMgr -M > LabEventMap.idb to build an `idb' script. Environment ........... `PG_CODELIB' The location of the external code databases for LOINC, LabEventInfo and units. This is rarely used, since everyone uses the names compiled into the programs. Files ..... `/usr/hl7/etc/LabEventInfo.tab' the tabular source version `/usr/hl7/lib/codes/LabEventInfo.db' the compiled, hashed file `labEventInfo.log' the run log file used if syslog(3) is not used. Bugs .... Writing errors to the logfile is not useful, since it is a program that is normally invoked manually by an operator. The table parser is a bit itchy about end of lines The generated idb script misses the following three opening lines: SET ColumnMode; CLEAR FROM LabEventMap WHERE objectId != NULL; SELECT objectId INTO OID FROM CISCareUnitCfg WHERE name="060_IOP"; The generated idb script tries to insert the admit observations as `LabEvent's which will cause idb to exit with an error. Those `INSERT' statements where `mappedPtEvent = ""' must be manually deleted from the script. Diagnostics ........... See `labEventInfo.log', the run log file, if you experience problems. See Also ........ *Note LabEventInfo.tab::  File: appman.info, Node: hl7tocv, Next: llpdrv, Prev: LabEventInfo, Up: CareVue Interface The `hl7tocv' Program ===================== Synopsis ........ hl7tocv hl7tocv batch ablhl7tocv ablhl7tocv batch Description ........... The `hl7tocv' program is used in order to process a spool directory of queued HL7 messages waiting to be forwarded to the `cvgateway'. It can be invoked in two modes, the batch mode and the operator mode. Batch mode is used when this program is called on a regular basis by cron(8), while operator mode is used in order to fix problems and to let an operator watch and intervene to the processing of the message queues. HL7 message files found in the spool directory that do not have a corresponding lock are forwarded to the `cvgateway'. If in batch mode the message gets a negative acknowledgment an error report is mailed to the system administrator. In interactive mode, the message delivery is retried after some time of waiting. During this waiting time, the operator can press the interrupt key (usually ^C) in order to get into a menu. This menu allows choosing between the following actions by pressing the respective key: v View the request and response messages. e Edit the request message. l view the CareVue Log file `ml.cis'. r write a problem report into a report file. d Delete message from queue as if it was successful. s Skip this message, but leave it in the queue. c Continue retrying to send this message. x eXit the `hl7tocv' program. If there are more severe errors occuring in batch mode, the program sends a CareVue system message telling that the HL7 system is down and mails any report to the administrator. Moreover an error mark file is written into the spool directory telling any subsequent `hl7tocv' process that the queue is blocked. The error mark is deleted when the administrator invokes `hl7tocv' in interactive mode in order to diagnose the problem. All system messaging and mailing is turned off in interactive mode. Each time the `hl7tocv' program starts up it tests for a run lock file in the spool directory. If there is no such lock file, the process itself generates one such that no two `hl7tocv' processes run concurrently on the same message queue. In interactive mode if there is a run lock file detected, the process waits until the lock file vanishes. The operator can forcefully remove the old lock file by pressing the interrupt key in the wait cycle. Examples ........ The cron(8) daemon can call `hl7tocv' every minute: */1 * * * * hl7tocv batch Environment ........... `ADMIN' The e-mail address of a system administrator who gets error and warning messages mailed. This variable need not exist, it is better to let the system look for its value in the file `/usr/hl7/etc/admin' `CAREVUE' The rcp address (`LOGIN@HOST') of the carevue system in order for rcp or rsh to execute CareVue `idb', `dbload' and `ptMgrSup' commands. The user and host who runs `idb_direct' must have an `.rhosts' entry in this account. This variable need not exist, it is better to let the system look for its value in the file `/usr/hl7/etc/carevue'. Files ..... `/usr/hl7/var/spool' the area of spool directories `/usr/hl7/var/log' the area of log directories, where transactions are logged `/usr/hl7/var/spool/ABL/060_IOP' the spool directory for `ablhl7tocv' `/usr/hl7/var/log/ABL/060_IOP' the log directory, where transactions are logged for `ablhl7tocv' `/usr/hl7/var/log/ABL/060_IOP/REPORT' the report file for error reports for `ablhl7tocv' `/usr/hl7/var/spool/ANAE_IOP' the spool directory for `hl7tocv' `/usr/hl7/var/log/ANAE_IOP' the log directory, where transactions are logged for `hl7tocv' `/usr/hl7/var/log/ANAE_IOP/REPORT' the report file for error reports for `ablhl7tocv' `/usr/hl7/etc/admin' The e-mail address of a system administrator who gets error and warning messages mailed. `/usr/hl7/etc/carevue' The rcp address (`LOGIN@HOST') of the carevue system in order for rcp or rsh to execute CareVue `idb', `dbload' and `ptMgrSup' commands. The user and host who runs `idb_direct' must have an `.rhosts' entry in this account. `/var/tmp/hl7tocv.log' the run log file where all stdout and stderror output is written to `CVUSER@CVHOST:/usr/M1215A/carevue/data/logs/ml.cis' The CareVue log file Bugs .... The two programs `ablhl7tocv' and `hl7tocv' should be merged into one program which can work multiple message queues whose spool and log areas can be configured dynamically. The CareVue log file `CVUSER@CVHOST:/usr/M1215A/carevue/data/logs/ml.cis' is expected to occur at this place. Should be configureable. The run log file should not be `/var/tmp/hl7tocv.log' Diagnostics ........... Read the administrator's mail and see the run log and report files. See Also ........ *Note cvgateway::  File: appman.info, Node: llpdrv, Prev: hl7tocv, Up: CareVue Interface The LLP Driver Program ====================== Synopsis ........ llpdrv [-dyY] [-a|-h|-m] [[-i|-u|-p|-t] FROM] [-i TO] [-i DIST] Description ........... Background The LLP support that is currently provided with ProtoGen is somehow a hack. Driven by the urgent need for an implementation of ANSI X3.28 protocol, I decided to write an LLP translator that transforms ANSI X3.28 sessions to a simpler LLP. For the latter, I chose what I called "Internal LLP" (ILLP) (see *Note ILLP::) later, since it was designed for the communication among HL7 applications built upon ProtoGen/HL7. The ILLP is a very simple LLP designed for the use with C++ IOstream classes. Basically it signals the end of a message by an end-of-file token. Thus, reading a HL7 message from a communication channel becomes just the same as reading it from a file (one message per file). No need to track end-of-message delimiter characters as when using the MLLP or HLLP or more. This can easily be done with BSD sockets (i.e. TCP/IP or UNIX-Stream sockets): The a stream socket, which is a full-duplex communication channel, can, once it is connected, be shut down on just one half. I.e. you can close just your writable half of the channel and still receive data on the readable half. The peer will recognize that you have closed your writable half by receiving and end-of-file token (i.e. read() returns 0). Now the peer can send it's reply data through the still open half that you are reading on. Thus, the ILLP favors a specific view on a (HL7) communication session which is outlined in the figure below. A request message is sent from the client to the server after which the client closes it's write-half of the connection signaling end of message to the server. Now the server interprets the request message, performs the service and sends the reply message (typically ACK) via it's still usable write-half of the connection (which is the read-half for the client). This is now closed as well, which signals end of message to the client. By now, the connection became unusable, because either party has closed it's write-half. Since this is so, the socket is deleted and the session is finished. C S L -------- REQUEST -----------> E ----+ I R PERFORM E V SERVICE N <------- REPLY -------------- E <---+ T R The LLP Driver Rather than being linked into the program that needs to use the LLP, the LLP driver is a separate program, called `llpdrv'. It translates the session and transport protocol mechanisms of the ANSI X3.28, the "hybrid lower layer protocol" (HLLP), or the "minimal lower layer protocol" (MLLP), which are described in `HL7 v2.1, Appendix B' or the `HL7 Implementation Guide', to the ILLP. Programs that need to communicate in either of these LLPs do only need to implement the simple ILLP and communicate to sites that require the other LLPs via an `llpdrv' process. The `llpdrv' process is started once for each communication channel that should be driven by one of the supported LLP. For example: consider you have a serial line `/dev/cua00', which is connected to a HL7 application `CaVe' that requires ANSI X3.28 LLP. Your application, called `MyApp' can communicate via ILLP/TCP. You would start the LLP driver once as follows: llpdrv -a -t /dev/cua00 -i mahl7%myhost -i cvhl7 This starts an LLP-driver process that listens on the channel `/dev/cua00' (referred to as "the line") for any ANSI X3.28 communication to start (e.g. ENQ). When this happens, it connects your application on the host `myhost' and TCP service/port `mahl7' via ILLP/TCP. MyApp will receive the message that was sent by CaVe but packed into ILLP instead of ANSI X3.28 LLP. MyApp will reply to the message just received in the same thread. So far we have only shown how the LLP driver is used if the CaVe System is the client and the MyApp is the server. If the two need to change roles, the client (MyApp) can connect the server (CaVe) via the TCP service/port `cvhl7' on the host where the `llpdrv' process is running. An ILLP session is now directed to the CaVe System via ANSI X3.28. An `llpdrv' process is thus two servers in one: The server that serves the port `cvhl7' is called the distal server, while the server that serves "the line" is called the proximal server. The proximal client is the first process to contact the LLP driver. The destination server is the second process that the LLP driver gets contact with and, third, multiple distal clients can connect subsequently to the distal server. ................................. (1) . . (2) PROXIMAL--->>---PROXIMAL---LLPDRV----------->>---DESTINATION CLIENT . SERVER | . SERVER . | . . +---DISTAL---<<---DISTAL . SERVER . CLIENT . . (3-n) ...........LLP DRIVER............ Roles and Processes It is important to identify four different "roles" that the LLP driver processes can assume: Startup process, proximal server process, proximal serv*ing* process and distal server process. First of all, there is the "startup process", which is the one that is usually called by execve(2) from a shell. The setup process exits as soon as it has: * initialized some variables using the command line option arguments * bound a socket that can later accept connections * invoked the "server process" by fork * printing the server process' id to the standard output There is nothing else printed to the standard output, thus the server process' id can be stored easily for an eventual shutdown of the LLP driver at a later point in time. The "server process" is the process that accepts connections by a client. However, it does not serve the client itself but invokes a "serving process" that does the real work, before it loops back to accept more connections. This is because the Berkeley sockets are capable of handling multiple client-server connections that rendez-vous at the same socket in parallel (actually, rendez-vous is sequential but interaction is parallel). Since the tty(or pty)-socket abstraction is not a real Berkeley socket, multiple interactions are not possible with tty-sockets. Anyway, the server process stays resident throughout the lifetime of a running LLP driver. Thus the proximal server process is the main process which has to be sent a termination signal in order to shut down the whole LLP driver. * | setup | bind | fork------+ | | exit disassociate ==== from terminal . | +--------do | +-------do | | | | | accept | | | | | connection | | | If socket is a tty don't fork but act like a child. | | fork--------------+ From here on we must decide if | | | | we exit or continue on error | | close allocate conditions depending on if we | | connection semaphore... did fork or not. | | | | : | +-------+ fork--------------+ A distal server is | . . | : | always established | . . proximal : distal except if we only | . . server...mutex...server want a single trans- | . . | | action. | . . kill distal | reopen tty . server ......... exit | . . | ==== +------------------- proximal > proximal > distal process server serving server (and serving) process process process transient resident transient transient The "serving process" is the process that actually serves the proximal client. The proximal connection is regarded as a full duplex serial line. This line is connected to another server, which is the destination of any transaction that is initiated from the proximal client. The destination server is connected by an INET socket and communication to it is driven by the so called "internal protocol" (see *Note ILLP::). The protocol used at the proximal connection can be either a kind of ANSI X3.28, the HLLP, or the MLLP. The capability of the proximal client to act as a server is propagated by the LLP driver by means of the "distal server" which is a child process of the proximal serving process. The distal server binds an INET socket which can however serve only one transaction at a time (non-multiplexed). The distal connection is driven by the "internal protocol" since the "line" is regarded as a non-multiplexed line. Because the proximal and distal clients use the line concurrently, there is a need for a mutual exclusion mechanism that guarantees that *either* the proximal serving process *or* the distal serving process may use the line. The process that has permissions is said to "have the line", while the other process is blocked in a wait state. Security Only processes on the localhost may connect to the distal server of the LLP driver. Options ....... LLP to use at the proximal connection (the line): `-a' ANSI X3.28 `-h' Hybrid LLP (HLLP) `-m' Minimal LLP (MLLP) The medium of the line: `-i' TCP/IP address specified as `SERVICE%HOST' `-u' a UNIX stream socket `-p' a pseudo terminal (PTY) `-t' a terminal/serial line (TTY) The destination address (TO), always ILLP driven using TCP: `-i SERVICE%HOST' TCP/IP SERVICE and HOSTname to connect in order to forward proximal requests The distal server (DIST), always ILLP driven using TCP: `-i SERVICE' TCP/IP SERVICEname where the distal server can be connected Miscellaneous options `-I' If a TTY (`-t') or PTY (`-p') is used as the line, don't wait for the proximal client to do something but immediately establish the distal service. Otherwise the LLP driver listens on the line for an outgoing message (like NMD) before the distal service is established. `-1' One shot mode. Disconnect from the line after each transaction. No distal server is established. `-y' Don't fork the proximal server process off the startup process. `-Y' Don't fork the proximal server process off the startup process and don't disassociate from the controlling terminal. The `-Y' and `-y' options are useful for debugging purpose or when started by init(8) via `/etc/ttys'or `/etc/inittab'. Normally the `llpdrv' forks directly into the background, disassociates from the controlling terminal and establishes a new process group to which any of it's sub-processes belong. Examples ........ `/etc/ttys' ttyd0 llpdrv -YIa -t /dev/ttyd0 -i discard%localhost -i carevuefsi Bugs .... The ANSI X3.28 protocol implementation has difficulties with very hasty peers, i.e. those whose timeout timer values are small. 1 s is safe. The ANSI X3.28 protocol options are only adjustable at compile time. The HLLP protocol is not actually implemented but only it's empty "slot" is provided. The MLLP protocol was lat tested long ago, it might be broken in the meantime. The LLP driver is more complex than necessary. The LLP driver is less complex than necessary. The LLP driver introduces too much overhead involving the ILLP communication. The LLP driver will be replaced by a library approach which is more comprehensive and flexible. Thus the LLP driver itself is not supported on the long run. See Also ........ `hosts(5)', `services(5)', *Note ILLP::.  File: appman.info, Node: Databases, Prev: CareVue Interface, Up: Top Common Files and Databases ************************** * Menu: * LOINC:: The LOINC Code * Units:: The Code for Units of Measure * Hosts:: Users and Hosts  File: appman.info, Node: LOINC, Next: Units, Prev: Databases, Up: Databases The LOINC Code ============== * Menu: * LOINC.tab:: The `LOINC.tab' and `LOINC+.tab' Databases * loincmgr:: Managing the LOINC Code Database  File: appman.info, Node: LOINC.tab, Next: loincmgr, Prev: LOINC, Up: LOINC The `LOINC.tab' and `LOINC+.tab' Databases ------------------------------------------ Description ........... The Regenstrief Institute of Indianapolis compiled the "Laboratory Observations Names and Codes" (LOINC) code in order to have a unique set of identifiers for observations for use with HL7. The advantage of this code is that (1) it is freely available, (2) it is planned to extend the code beyond laboratory observations in order to map also clinical terms, and (3) it tries to refer to other coding systems (ASTM and IUPAC) where applicable. Even though the LOINC code is not perfect, neither in its concepts, nor in it's degree of reaching it's own aims, it seems feasible to use it as an integral part of ProtoGen/HL7 applications for observation identifiers. The LOINC code is sizeable (over 6000 entries) so that it deserves to be used only as a compiled, hashed and indexed database for quickly referencing its entries. A textual version is used for editing and extending the database. The "manager" program, `loincmgr', is used to convert between the two representations of the LOINC database. The following attributes are defined, of which only the most important are explained here. Please refer to the LOINC manual for more. `loinc_num (key)' LOINC number with check digit separated by a `-', e.g. `5914-7' `measure (indexed)' a string, e.g. `GLUCOSE' `property' the dimension, e.g. `SCNC' for substance concentration. `timing' `specimen' the specimen, e.g. `BLD' for blood `precision' `method' `relat_nms (indexed for each entry)' a semicolon separated list of (probably non-unique) alias names `mclass (indexed)' `source (indexed)' `euclide_cd (indexed)' `astm_cd (indexed)' `iupac_cd (indexed)' references to other code systems (most of which are still void) `dt_last_ch' `comments' `answerlist' `status' `scope' `snomed_cd' `va_cd' `metpath_code (indexed)' `hcfa_code' references to other code systems (most of which are still void) `norm_range' normal range, about all are still void `units' functional dependent to property, still left void `map_to' Since the LOINC coding scheme tries to map measure x dimension x specimen x other specifiers to one loinc number, the list is likely to be incomplete regarding other specimen or dimensions for the same measure. Moreover the list is incomplete even regarding measures, e.g. those needed for acid base analysis. The LOINC thus requires extension if it is to be usefully applied. Modifications to the original LOINC database are not allowed, but additions are still possible if assigned loinc numbers that do not interfere with existing ones. This can be achieved by numbering the additions from 9999 backwards. The additions that are defined for this Interfacing project are bundled in the file `LOINC+.tab' while the original LOINC code is found in `LOINC.tab'. The `.tab' file format for the LOINC code is optionally quoted (`"') strings separated by tabs one line per row. Comments are not allowed. Care should be taken that the table contains only valid lines and no empty ones. Examples ........ "9984" "BODY TEMPERATURE" "TEMP" "PT" "PAT" "QN" "MEASURED" "" "CLIN" "GUSW" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "9999" "OXYGEN^^SATURATION ADJUSTED TO 0.5" "PRES" "PT" "BLDA" "QN" "" "PO2(50);P50" "CHEM" "GUSW" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "9998" "OXYGEN^^SATURATION ADJUSTED TO 0.5" "PRES" "PT" "BLDC" "QN" "" "PO2(50);P50" "CHEM" "GUSW" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "9997" "OXYGEN^^SATURATION ADJUSTED TO 0.5" "PRES" "PT" "BLDV" "QN" "" "PO2(50);P50" "CHEM" "GUSW" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" Files ..... `/usr/hl7/etc/LOINC.tab' the original LOINC code table `/usr/hl7/etc/LOINC+.tab' the table of extensions `/usr/hl7/lib/codes/LOINC.db' the compiled, hashed and indexed database See Also ........ *Note loincmgr:: *Note LabEventInfo::  File: appman.info, Node: loincmgr, Prev: LOINC.tab, Up: LOINC Managing the LOINC Code Database -------------------------------- Synopsis ........ loincmgr -[crux] FILES ... loincmgr -[dq] FIELD == VALUE [FIELD OP VALUE] ... loincmgr -D [FIELD == VALUE [FIELD OP VALUE] ...] loincmgr -R Description ........... The `loincmgr' program is the "manager" of the LOINC code database. It is used to convert between tabular and compiled, hashed form of the database. Moreover it offers shell level access to the querying feature of the underlying ODBM object database management facility. The first form is used in order to create (`-c') the compiled, hashed and indexed database, add (`-u'), replace (`-r'), or delete (`-x') objects from the database. The tuples are submitted as files in the tabular format (see *Note LOINC.tab::). The second form is used to query or delete objects from the database. The query is specified by a clause asking for the key or an indexed FIELD to be equal to some string VALUE; followed by other clauses further testing the operator OP on other FIELDs and VALUEs. The operator OP can be `==' (equal) or `!=' (not equal). The clauses are linked by logical and. The FIELD can be specified either by a number or by the LOINC standard name for the field: `LOINC_NUM', `MEASURE', `PROPERTY', `TIMING', `SPECIMEN', `PRECISION', `METHOD', `RELAT_NMS', `CLASS', `SOURCE', `EUCLIDE_CD', `ASTM_CD', `IUPAC_CD', `DT_LAST_CH', `COMMENTS', `ANSWERLIST', `STATUS', `SCOPE', `SNOMED_CD', `VA_CD', `METPATH_CODE', `HCFA_CODE', `NORM_RANGE', `UNITS', and `MAP_TO'. The third form is used to regain the tabular source form of the database from the compiled form. It is possible, but not required, to use a query clause as described above in order to limit the amount of data that is printed to the standard output. The last form is used to reorganize the database, i.e. to delete all indices that have doubled or became void because of data being replaced or removed from the database. Options ....... `-c FILES ...' create database `-r FILES ...' update database (update) `-u FILES ...' update database (insert) `-x FILES ...' exclude from database `-q FIELD == VALUE [FIELD OP VALUE] ...' query database `-d FIELD == VALUE [FIELD OP VALUE] ...' delete tuples from database `-D [FIELD == VALUE [FIELD OP VALUE] ...]' dump tuples in database to tabular format `-R' reorganize database Environment ........... `PG_CODELIB' The location of the external code databases for LOINC, LabEventInfo and units. This is rarely used, since everyone uses the names compiled into the programs. Files ..... `/usr/hl7/etc/LOINC.tab' the original LOINC code table `/usr/hl7/etc/LOINC+.tab' the table of extensions `/usr/hl7/lib/codes/LOINC.db' the compiled, hashed and indexed database `./loinc.log' the run log file Bugs .... Writing errors to the logfile is not useful since this is a program that is normally invoked manually by an operator. The table parser is a bit itchy about end of lines. The `-r' option is not yet implemented The `-R' option is not implemented yet. It can be emulated by loincmgr -D > /tmp/loinc.tmp loincmgr -c /tmp/loinc.tmp Diagnostics ........... See the file `./loinc.log' to make sure that no error has occurred. See Also ........ `odbm(3)', `gdbm(3)', *Note LOINC.tab::, *Note LabEventInfo.tab::.