第四章 应用层协议详解:HL7 v2.x、DICOM与POCT1-A
应用层协议,说白了就是医疗设备之间“说人话”的规则。我做了十几年嵌入式医疗系统,见过太多设备因为协议解析不对,导致数据传过来全是乱码。这一章咱们就掰开揉碎,把三个最常用的协议讲透。
4.1 HL7 v2.x 消息结构——医院信息系统的“通用语”
HL7 v2.x 是目前医院信息系统(HIS)里用得最广的协议。它的消息结构其实不复杂,核心就是“段(Segment)+ 字段(Field)+ 组件(Component)”三层嵌套。
核心概念:HL7 消息 = 多个段(Segment)拼接而成,每个段以三个大写字母开头,比如 MSH(消息头)、PID(患者信息)、OBX(观测结果)。
4.1.1 消息结构解剖
我习惯把 HL7 消息比作一封信:
- MSH 段——信封,写明了发件人、收件人、消息类型、时间戳。
- PID 段——收件人信息,患者姓名、ID、出生日期。
- OBX 段——信的内容,具体的检验结果、生命体征数值。
来看一个实际的心电监护仪上报消息:
MSH|^~\&|监护仪|ICU_01|HIS|HOSP|202403151430||ORU^R01|MSG001|P|2.3
PID|||PAT001||张伟||19800515|M
OBX|1|NM|HR^心率||72|次/分|60-100|N||F
OBX|2|NM|SBP^收缩压||128|mmHg|90-140|N||F
注意看分隔符:| 是字段分隔符,^ 是组件分隔符。我在项目里遇到过最坑的事——有人把字段分隔符配成了 &,结果整个消息解析全乱套了。
我的经验:调试 HL7 消息时,先检查 MSH 段第 2 个字段(编码字符)。默认是 ^~\&,如果这里错了,后面所有解析都会偏移。我曾经花了一整天查一个“数据丢失”的 bug,最后发现是编码字符被意外修改了。
4.1.2 常见段类型速查表
| 段名 | 全称 | 用途 | 必选/可选 |
|---|---|---|---|
| MSH | Message Header | 消息头,定义消息类型、发送方、接收方 | 必选 |
| PID | Patient Identification | 患者身份信息 | 必选 |
| OBX | Observation Result | 观测结果,如心率、血压、血糖值 | 可选(但常用) |
| EVN | Event Type | 事件类型,记录触发消息的事件 | 可选 |
4.2 DICOM 文件格式解析——医学影像的“通用底片”
DICOM 不只是文件格式,它是一整套通信协议。但咱们做嵌入式系统,最常打交道的是 DICOM 文件——也就是设备生成的影像文件。
DICOM 文件的结构很有意思:它把患者信息、设备参数、图像数据全塞进一个文件里。说白了,就是“自描述”的。
4.2.1 文件结构四要素
- 文件头(Preamble)——前 128 字节,通常全零,后面紧跟 "DICM" 四个字符。
- 元信息(Meta Information)——传输语法、SOP Class UID 等。
- 数据集(Data Set)——一堆 Tag(标签),每个 Tag 对应一个属性,比如患者姓名、检查日期。
- 像素数据(Pixel Data)——真正的图像数据,可能是 JPEG 压缩或原始 RAW。
注意:DICOM 的 Tag 是 4 字节的(组号+元素号),比如 (0010,0010) 表示患者姓名。解析时一定要按小端序读取,我见过有人用大端序解析,结果患者名字变成了乱码。
4.2.2 关键 Tag 速查
| Tag (十六进制) | 含义 | VR (值表示法) | 说明 |
|---|---|---|---|
| (0008,0005) | Specific Character Set | CS | 字符集,常用 ISO_IR 100(拉丁语) |
| (0010,0010) | Patient Name | PN | 患者姓名,格式:姓^名 |
| (0028,0010) | Rows | US | 图像行数 |
| (0028,0011) | Columns | US | 图像列数 |
| (7FE0,0010) | Pixel Data | OW/OB | 像素数据本体 |
解析 DICOM 时,我建议先读 (0002,0010) 这个 Tag——它告诉你传输语法。如果是 1.2.840.10008.1.2(隐式 VR 小端序),那后面的 Tag 就没有 VR 字段,解析逻辑完全不同。
4.3 POCT1-A 协议——床旁检测的“现场指挥”
POCT1-A 是专门为床旁检测设备(血糖仪、血气分析仪、凝血仪)设计的协议。它跟 HL7 不一样,HL7 是“医院内部通用”,POCT1-A 是“床边专用”。
这个协议的核心思想是:设备要能即插即用,数据要能实时上传,而且必须保证患者身份准确无误。
4.3.1 协议分层与消息类型
POCT1-A 分为三层:
- 物理层——通常是 RS-232 串口或 USB 虚拟串口,波特率 9600 或 19200。
- 数据链路层——用帧头帧尾(STX/ETX)和校验和(Checksum)保证数据完整。
- 应用层——定义具体的操作命令,比如“上传结果”、“查询患者列表”。
消息类型主要有三种:
- 查询消息(Q)——设备向数据管理器请求信息。
- 响应消息(R)——数据管理器回复设备。
- 结果消息(R)——设备主动上传检测结果。
实际案例:我在一个血糖仪项目中,设备每次上传结果都要先发查询消息确认患者 ID 是否存在。如果数据管理器没响应,设备会重试 3 次,每次间隔 5 秒。这个机制避免了“测了血糖但找不到患者”的尴尬。
4.3.2 典型消息帧格式
STX | 长度 | 消息类型 | 设备ID | 数据 | 校验和 | ETX
02 | 0A | 51 | 01 02 | ... | XX | 03
- STX (0x02)——帧起始
- 长度——从消息类型到校验和的字节数
- 消息类型——0x51 表示结果上传
- 设备ID——2 字节,唯一标识设备
- 数据——具体内容,如血糖值 5.6 mmol/L
- 校验和——从长度到数据的累加和取低 8 位
- ETX (0x03)——帧结束
避坑指南:我曾经遇到一个设备,串口接收缓冲区只有 64 字节,但 POCT1-A 消息最长能到 128 字节。结果每次传长消息就丢帧。解决方案是:要么增大缓冲区,要么分帧传输。我建议直接上 256 字节环形缓冲区,一劳永逸。
4.4 三种协议对比与选型建议
| 维度 | HL7 v2.x | DICOM | POCT1-A |
|---|---|---|---|
| 主要用途 | 文本数据交换(检验、医嘱) | 医学影像传输与存储 | 床旁检测设备数据上传 |
| 数据格式 | 纯文本,分隔符结构 | 二进制 + Tag 结构 | 二进制帧结构 |
| 传输层 | TCP/IP(MLLP 协议) | TCP/IP(DICOM 上层协议) | 串口 / USB |
| 实时性 | 中等(秒级) | 低(影像传输较慢) | 高(毫秒级) |
| 嵌入式资源需求 | 低(文本解析简单) | 高(需要解压图像) | 极低(串口通信) |
选型时我的建议是:如果设备只传文本数据(血糖、血压),用 POCT1-A 最轻量;如果需要对接医院信息系统,HL7 v2.x 是标配;如果涉及影像(超声、X 光),DICOM 绕不开。
4.5 本章知识结构图
下面这张图把三种协议的核心关系画清楚了:
嗯,这张图把三种协议的关系和子节点都标清楚了。实际项目中,一个设备可能同时支持 HL7 和 POCT1-A——比如床旁监护仪既要上传波形数据(DICOM 格式),又要上传生命体征(HL7 格式),还要跟血糖仪通信(POCT1-A)。这时候就需要一个协议适配层,把不同协议的数据统一转换成内部数据结构。
我的习惯:在嵌入式系统里,我会用一个“协议工厂”模式——根据配置文件的协议类型,动态创建对应的解析器。这样加新协议时,只需要写一个新的解析器类,不用改主流程。
好了,这一章的内容就到这儿。三种协议各有各的脾气,但只要掌握了它们的核心结构——HL7 的段、DICOM 的 Tag、POCT1-A 的帧——剩下的就是多写代码、多调试了。