C#

C#で医療用検査機器とシリアル通信 – パート1

普段お世話になっているクライアント様から医療用の検査機器との通信をするアプリケーションを組むお話をいただきました。
RS-232Cでのシリアル通信なのですが、10年以上前に少し触れた程度だったため、医療機器となるともちろん不具合があっては行けないでしょうし不安を抱えながらも受けさせていただきました。

基本的にはASTMプロトコルの規格で検査機器とやり取りを行う、LIS(ラボ情報システム)サーバーの役割をするアプリケーションを組むことになります。
サーバーとはいっても、検査機器と被験者情報の入ったデータベースサーバーとの橋渡しをする感じです。

このような検査機器に普段から携わっていらっしゃる技術者さんでしたら、何てことはない作業かもしれませんが、どこから手をつけたら良いのか検討がつきませんでしたよ。
なにせ、シリアル通信自体忘れていますし、その時点では検査機器自体が現場に無いのですから・・・
だから想像力(?)に頼るしかありませんでした。

とは言っても、さすがに参考になるものが無いと進められませんよね。
まずはどんな情報(文字列)がやり取りされるのかといった情報は、当該検査機器のメーカーさんからいただきました。
こんな感じです。

試験オーダー要求
H|\^&|||DEVICE_NAME|||||LISHost||P|1
Q|1|^SAMPLE01||ALL||||||||O
Q|2|^SAMPLE02||ALL||||||||O
L|1|N
結果エクスポート
H|\^&|||DEVICE_NAME|||||LISHost|||1|19941115202738
P|1|PatID01|||Meria^Anna||19741001|F|||||MARTINEZ
O|1|SAMPLE01|C35B802B-B4F9-400A-9409-1FAB9D736C8D^1234|^^^CT/GC|R|20100506123145|||||||||||||||||||F
R|1|^^^CT/GC^CTResult|CT neg|||||F||||20100506123145|
R|2|^^^CT/GC^GCResult|GC Equiv|||||F||||20100506123145|
P|2|PatID01|||Meria^Anna||19741001|F|||||MARTINEZ
O|1|subject_name|C35B802B-B4F9-400A-9409-1FAB9D736C8D^1234|^^^CT/GC|R|20100506123145|||||||||||||||||||F
R|1|^^^CT/GC^CTResult|CT neg|||||F||||20100506123145|
R|2|^^^CT/GC^GCResult|GC Equiv|||||F||||20100506123145|
C|1|I|^RDFS - failure when dispensing sample\^CLT - Clot detedted|I
L|1|N

検査機器からは、検査の対象となる試験管毎に貼られたバーコードを読み取って、「このバーコードの検体は何の試験をするの?」とLISサーバーに聞いてきます(試験オーダー要求)。それに対してLISサーバーが「この検査をしてね。」と検査内容を返して上げることになります。
それに沿って検査機器で数時間かけて自動で試験を行い、結果が出たら結果情報(結果エクスポート)をLISサーバーに送信してきます。

それぞれのレコードの意味は省きますが、僕にとって問題なのは、恥ずかしながら通信処理をほぼ忘れてしまっているということです。
その昔たずさわった仕事のかすかな記憶では、シリアル通信ならポートを開けて、その送信(書込)メソッドで文字列を渡してあげて、相手からの応答を待って・・・なんてことがあったはずです。
反対に受信でも最後まで受けきってから、こちらから応答(返信)してあげるってのがありましたよね。
そこには決まり事があったような気がするなぁと。。。
シリアル通信の参考になる情報はGoogleで調べれば色々と出てきますが、電文のやり取りそのものの説明はあんまり出てないんですよね(泣)

で、もっと情報が無いかメーカーの担当者さんに問い合わせたところ、資料をいただけました。実際にやり取りする電文はこんな感じでした。

<ENQ>
<ACK>
<STX>1H|\^&|||DEVICE_NAME|||||HOST||P|1|<CR><ETX>77<CR><LF>
<ACK>
<STX>2Q|1|^PNL-A-000001||ALL||||||||O<CR><ETX>57<CR><LF>
<ACK>
<STX>3Q|2|^PNL-B-000002||ALL||||||||O<CR><ETX>58<CR><LF>
<ACK>
<STX>4Q|3|^PNL-C-000003||ALL||||||||O<CR><ETX>5B<CR><LF>
<ACK>
<STX>5Q|4|^PNL-D-000004||ALL||||||||O<CR><ETX>6A<CR><LF>
<ACK>
<STX>6Q|5|^PNL-E-000005||ALL||||||||O<CR><ETX>67<CR><LF>
<ACK>
<STX>7L|1|N<CR><ETX>0A<CR><LF>
<ACK>
<EOT>

そうそう!これが欲しかったんですよ!

やり取りの中で1レコード受け取ったら「受け取りましたよ」と返してあげるってことですね。
送信側と受信側で文字列を投げ合うということなのですが、[ENQ]でこれから情報投げるよで、[ACK]でOKだよと返信し、[STX]で本番のデータが渡され、最後に[EOT]で終了という流れです。

「結果エクスポート」では、検査結果の情報を一通り受け取ったら検査機器に返す情報は特にありませんが、「試験オーダー要求」では、受け取った文字列を元にして、それぞれの検体(バーコード)に対してどの検査を行うかを返さなければなりません。何の検査をするのか分からないのでストップしたままとなってしまいますもんね。

つまり、「試験オーダー要求」の電文が来ている最中は、受け取った検体分のバーコード文字列をどこかに保持しておきながら電文をすべて受け切るという処理が必要となります。その後、検体の検査情報をデータベースから引っ張り出して検査内容の情報を生成し、検査機器へ「この検査をして下さい」と個々に1検体ずつ送信するということのようです。

何となく流れはつかめました。長くなってしまったので、続きは後日に。。。