Mithilfe des Toolkits DCMTK lässt sich ein einfacher DICOM Worklist Server realisieren. Hierbei wird der in dem Toolkit enthaltene wlmscpfs Server verwendet. Für jeden Worklisteintrag muss dazu in einem konfigurierbaren Verzeichnis eine binäre DICOM-Datei vorhanden sein. Mittels des ebenfalls in dem Toolkit enthaltenden Programms dump2dcm lassen sich diese aus einer Textrepräsentation des DICOM-Datensatzs erstellen:
(0008,0050) SH ${AN} # 0, 0 AccessionNumber (0010,0010) PN ${PN} # 16, 1 PatientsName (0010,0020) LO ${PID} # 6, 1 PatientID (0010,0030) DA ${GEBDAT} # 8, 1 PatientsBirthDate (0010,0040) CS ${SEX} # 2, 1 PatientsSex (0040,0100) SQ # 118, 1 ScheduledProcedureStepSequence (fffe,e000) - # 110, 1 Item (0008,0060) CS [US] # 2, 1 Modality (fffe,e00d) - # 0, 0 ItemDelimitationItem (fffe,e0dd) -
Eine Erzeugung direkt aus Mirth Connect ist nicht möglich. Allerdings kann man den Mirth Connect verwenden, um obiges Text-Template mit Inhalt aus HL7-Nachrichten zu befüllen.
In einem Transformer werden die enstprechenden Variablen-Templates mit Inhalten gefüllt.
Die exportierten Textdateien werden dann über einen cron-Job periodisch in die DICOM-Binärdateien umgewandelt:
#!/bin/bash # # DICOM Worklist generierern HISWEBWL=/var/opt/hisweb/dicom/HNOUSMWL DUMPFILES=`ls -1 $HISWEBWL/*.txt 2>/dev/null` if [ -n $DUMPFILRS ] then rm -f $HISWEBWL/lockfile for FILE in $DUMPFILES do BASENAME=`basename $FILE .txt` dump2dcm $FILE $HISWEBWL/$BASENAME.wl >/dev/null 2>/dev/null rm -f $FILE done touch $HISWEBWL/lockfile fi
Die Worklist kann man sich auch aus ADT-Nachrichten fingieren: Für jede A04-Nachricht mit Bewegungsdatum des aktuellen Tages wird eine Auftragsdatei mit O am Dateinamensanfang folgender der Fallnummer als Dateiname erstellt. Bei Nachrichten zu stationären Patienten erzeugt man eine Datei mit I am Dateinamensanfang und dann folgend der Fallnummer. Der entsprechende Filter sieht dann so aus:
// Filter für Ultraschall Modality Worklist // // $Id$ // Eventtypen, die kommuniziert werden sollen var valid_Events = new RegExp("A01|A02|A04|A06|A07|A12|A13"); var todayTs = new Date(); var eventDate = new Date(); var process = false; if (valid_Events.test(msg['EVN']['EVN.1']['EVN.1.1'].toString())) { eventDate.hl7parse(msg['ZBE']['ZBE.2']['ZBE.2.1'].toString()); if ( todayTs.toGermanDateString() == eventDate.toGermanDateString() ) { process = true; } } return process;
Hier in diesem Beispiel kommen Prototyphilfsfunktionen zum Einsatz.
Über einen weiteren cron-Job, der täglich um 20:00 Uhr ausgeführt wird, werden dann die nicht mehr benötigten Worklisteinträge gelöscht:
#!/bin/bash # # alte DICOM Worklist Einträge löschen HISWEBWL=/var/opt/hisweb/dicom/HNOUSMWL NDAYS=15 rm -f $HISWEBWL/lockfile rm -f $HISWEBWL/O*.wl $HISWEBWL/AO*.wl FILES=`find $HISWEBWL -name "I*.wl" -type f -mtime +$NDAYS -print` for FILE in $FILES do rm -f $FILE >/dev/null 2>/dev/null done touch $HISWEBWL/lockfile
Zum Starten des wlmscpfs-Servers wird folgendes runlevel-skript in /etc/init.d verwendet:
#! /bin/sh ### BEGIN INIT INFO # Provides: wlmscpfs # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: DICOM Basic Worklist Management SCP # Description: DICOM Basic Worklist Management SCP ### END INIT INFO # Author: Stefan Langenberg # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="DICOM Basic Worklist Management SCP" NAME=wlmscpfs DAEMON=/usr/bin/$NAME DATAPATH=/var/opt/hisweb/dicom LOG=/var/log/wlmscpfs.log DAEMON_ARGS="+ac -v --disable-file-reject -dfp $DATAPATH 16999" PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.2-14) to ensure that this file is present # and status_of_proc is working. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started #start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \ # || return 1 start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \ $DAEMON_ARGS >$LOG 2>$LOG & return 0 # Add code here, if necessary, that waits for the process to be ready # to handle requests from services started subsequently which depend # on this one. As a last resort, sleep for some time. } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 # Wait for children to finish too if this is a daemon that forks # and if the daemon is only ever run from this initscript. # If the above conditions are not satisfied then add some other code # that waits for the process to drop all resources that could be # needed by services started subsequently. A last resort is to # sleep for some time. start-stop-daemon --stop --quiet --oknodo --retry=0/1/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } # # Function that sends a SIGHUP to the daemon/service # do_reload() { # # If the daemon can reload its configuration without # restarting (for example, when it is sent a SIGHUP), # then implement that here. # start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME return 0 } case "$1" in start) log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; stop) log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) log_end_msg 0 ;; 2) log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; #reload|force-reload) # # If do_reload() is not implemented then leave this commented out # and leave 'force-reload' as an alias for 'restart'. # #log_daemon_msg "Reloading $DESC" "$NAME" #do_reload #log_end_msg $? #;; restart|force-reload) # # If the "reload" option is implemented then remove the # 'force-reload' alias # log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2 echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac :
Du muss angemeldet sein, um einen Kommentar zu veröffentlichen.