编辑 | blame | 历史 | 原始文档

Gambro Artis 协议规范(ORU^R31)

  • 文件来源:artis_protocol_oru_r31.md
  • 适用场景:实时监视治疗参数
  • 最后更新:2023-10-27

目录

1. 连接与通信基础

配置项 值/说明
端口 3021(TCP Server)
编码 UTF-16(Unicode)
触发机制 治疗开始后,机器每 60 秒自动推送
ACK 策略 不需要客户端回复(MSH-15/16 = NE)

⚠️ 重要警告:客户端接收数据后**不要发送任何 ACK 消息**,否则可能导致机器断开连接或报错。

2. 消息流程

  1. 连接建立:客户端连接 Artis 机器的 3021 端口。
  2. 数据推送:机器在治疗状态下,每隔 60 秒主动发送一条 ORU^R31 消息。
  3. 数据处理:客户端接收并解析数据。
  4. 静默接收:保持连接,不回复确认帧。

3. 消息结构(XML)

根节点为 <ORU_R31>,消息通常包含 MSH、(可选)PID/ORC/OBR、以及若干个 ORU_R31.OBSERVATION 数据块。

3.1 MSH(消息头)

字段 关键值/说明
MSH-9 ORU^R31
MSH-8 CRC 校验码(4 位十六进制)。计算时需先置空,算出后填入。
MSH-15/16 NE(Never Expect ACK)- 明确指示不需要确认。
MSH-18 UNICODE

3.2 OBX(观察结果,核心数据)

每条消息包含多个 <ORU_R31.OBSERVATION> 块,每个块包含一个 <OBX> 段,代表一个临床参数。

关键字段路径:

  • 参数 ID:OBX-3.CE.1(例如:7
  • 参数名:OBX-3.CE.2(例如:Temperature
  • 数值:OBX-5.FN.1(例如:37.500000
  • 单位:OBX-6.CE.1(例如:cel
  • 状态:OBX-11(通常为 F - Final)

4. 常用临床参数列表

解析时请根据 OBX-3 中的 ID 区分数据:

ID 参数名(EN) 中文含义 单位示例 典型值示例

| 0 | Operating Phase | 治疗阶段 | - | PRE TRT, HD-DN |
| 1 | Remaining Time | 剩余时间 | s | 14400.000000 |
| 2 | UF Volume | 超滤量 | L | 1.500000 |
| 3 | UF Rate | 超滤率 | L/hr | 0.500000 |
| 4 | Conductivity | 电导率 | mS/cm | 14.000000 |
| 6 | Blood Flow | 血流速 | ml/min | 300.000000 |
| 7 | Temperature | 温度 | cel | 37.500000 |
| 8 | Dialysis Fluid Flow | 透析液流速 | ml/min | 500.000000 |
| 12 | TMP Actual | 跨膜压 | mmHg | 120.000000 |
| 13 | Venous Pressure | 静脉压 | mmHg | 80.000000 |
| 14 | Arterial Pressure | 动脉压 | mmHg | -150.000000 |
| 32 | Set Blood Flow | 设定血流速 | ml/min | 300.000000 |

💡 注意:如果某个参数在当前治疗模式下不适用,该 OBX 段的值可能为空或为 0

5. 完整消息示例

<?xml version="1.0" encoding="UTF-8"?>
<ORU_R31>
  <MSH>
    <MSH.1>|</MSH.1>
    <MSH.2>^~\&amp;</MSH.2>
    <MSH.3><HD.1>Gambro_171</HD.1></MSH.3>
    <MSH.4><HD.1>SW_8.52_SN_12345</HD.1></MSH.4>
    <MSH.5><HD.1>Client_PC</HD.1></MSH.5>
    <MSH.6><HD.1>HIS</HD.1></MSH.6>
    <MSH.7><TS.1>20231027103000</TS.1></MSH.7>
    <MSH.8>A1B2</MSH.8> <!-- CRC 校验码 -->
    <MSH.9>
      <MSG.1>ORU</MSG.1>
      <MSG.2>R31</MSG.2>
    </MSH.9>
    <MSH.10>MSG_00123</MSH.10>
    <MSH.11>P</MSH.11>
    <MSH.12>2.5</MSH.12>
    <MSH.15>NE</MSH.15>
    <MSH.16>NE</MSH.16>
    <MSH.18>UNICODE</MSH.18>
  </MSH>

  <!-- 省略 PID, ORC, OBR 段 -->

  <!-- 数据块:温度 (ID 7) -->
  <ORU_R31.OBSERVATION>
    <OBX>
      <OBX.3><CE.1>7</CE.1><CE.2>Temperature</CE.2></OBX.3>
      <OBX.5><FN.1>37.500000</FN.1></OBX.5>
      <OBX.6><CE.1>cel</CE.1></OBX.6>
      <OBX.11>F</OBX.11>
    </OBX>
  </ORU_R31.OBSERVATION>
</ORU_R31>

6. 开发实现要点

在 VS Code 中开发时,可参考以下实现逻辑:

TCP 接收与粘包处理

  • 使用 Node.js net 模块监听逻辑。
  • 维护 Buffer,直到检测到 </ORU_R31> 结尾才进行解析。

UTF-16 解码与 XML 解析

  • 接收到的 Buffer 是 UTF-16 编码,需先转换为字符串。
  • 使用 xml2js 库解析。
  • 提取所有 ORU_R31.OBSERVATION 节点,根据 OBX.3.CE.1 的 ID 整理为 JSON 对象。

特定参数监控

  • 编写监控函数:若 Temperature(ID 7)> 42 或 < 35,或 Venous Pressure(ID 13)> 250,打印红色警告日志。

CRC 校验(可选)

  • 调试阶段可跳过 MSH-8 的 CRC 验证,直接解析消息体。

附录 A:文档中出现的示例代码片段

说明:以下片段在原文中出现在“消息结构(XML)”段落中间,疑似为示例工程脚手架/客户端代码(且内容不完整)。为避免干扰协议说明,已移至附录;内容本身未做语义补全。

// init-project.js
const fs = require('fs');
const path = require('path');

const projectStructure = {
  'config.js': `module.exports = {
  ARTIS: {
    host: '192.168.1.100',
    port: 3021,
    reconnectInterval: 5000,
  },
  MONITOR: {
    temperature: { min: 35, max: 42 },
    venousPressure: { max: 250 },
    arterialPressure: { min: -200, max: 0 },
  },
  LOG: {
    enable: true,
    level: 'info',
  },
};`,

  'src/artisClient.js': `const net = require('net');
const EventEmitter = require('events');
const MessageParser = require('./messageParser');
const DataMonitor = require('./dataMonitor');
const config = require('../config');

class ArtisClient extends EventEmitter {
  constructor() {
    super();
    this.host = config.ARTIS.host;
    this.port = config.ARTIS.port;
    this.socket = null;
    this.buffer = Buffer.alloc(0);
    this.parser = new MessageParser();
    this.monitor = new DataMonitor();
    this.isConnected = false;
    this.reconnectTimer = null;
  }

  connect() {
    return new Promise((resolve, reject) => {
      console.log(\`[Client] 正在连接 \${this.host}:\${this.port}...\`);
      this.socket = net.createConnection({ host: this.host, port: this.port });

      this.socket.on('connect', () => {
        this.isConnected = true;
        console.log('\\x1b[32m%s\\x1b[0m', '[Client] 连接成功!');
        this.emit('connected');
        resolve();
      });

      this.socket.on('data', (data) => this.handleData(data));
      this.socket.on('error', (error) => {
        console.error('[Client] 连接错误:', error.message);
        this.isConnected = false;
        this.emit('error', error);
        reject(error);
      });
      this.socket.on('close', () => {
        console.log('[Client] 连接已关闭');
        this.isConnected = false;
        this.emit('disconnected');
        this.scheduleReconnect();
      });
    });
  }

  handleData(data) {
    this.buffer = Buffer