C#串口开发案例:迈瑞血球分析仪

 

分享一个去年做的迈瑞血球分析仪BC-5120的串口开发,如果感兴趣可以留言或者私信,我再继续写其他检验设备的接口开发。

设备BC-5000和BC-5150应该都是通用的协议。详细内容请看传输协议。协议使用HL7,内容超复杂自行百度学习,不懂也没关系。

下载:数据传输协议、采集的数据、报告单的照片以及说明书上对项目的定义

下载:源代码涉及的类库、方法(2020年7月29日新增)

2020年7月29日在文末新增完整解析源代码。

先看看报告单:

看一下用AccessPort串口工具接收的数据:

在程序中获取串口数据byte[] data,删除前后多余的02后,首先判断开始标记:0B,结束标记:1C 0D。然后将数据流转化成字符串,消息段用0D分隔,转换成数组。

data = TrimByte(data, 0x02);//消除前后多余的02字节
if (IsBegin(data, 0x0B) && IsEnd(dataBuffer[id].Data, new byte[] { 0x1C, 0x0D })
{
    string txt = Encoding.Default.GetString(data);//数据流转成字符串
    txt = txt.SubString(1,txt.Length-3);//消除前后标记
    string[] Segment = txt.Split((char)0x0D);//用分隔符0D对消息段分组
}

消息段:段内的字段之间用“|”分隔。

string[] Field = Segment[i].Split('|');

MSH消息段,需要的内容:字段[10]消息控制ID=13(用于发送成功消息),字段[14]类型=P样本,Q质控

MSH|^~\&|||||20191123121334||ORU^R01|13|P|2.3.1||||||UNICODE PID|1||^^^^MR PV1|1 OBR|1||12|00001^Automated Count^99MRC|||

messageID = Field[9];//消息控制ID
type = Field[10];//P样本,Q质控

OBR消息段,字段[4]样本号=12,字段[8]日期=20191123115806

OBR|1||12|00001^Automated Count^99MRC|||20191123115806|||||||||||||||||HM||||||||1

SampleNo =  Field[3];//样本号
DateTime = Field[7];//日期yyyyMMddHHmmss

OBX消息段,检验结果保存在这里,字段[4]项目名称,字段[6]结果。其他结果依次获取。

OBX|5|NM|6690-2^WBC^LN||12.36|10*9/L|4.00-10.00|H~N|||F

string itemName = Field[3].Split('^')[1];//只需要名称缩写
string itemValue = Field[5];//检验结果

获取WBC白细胞直方图数据:从“Base64^”开始是以字符串保存的图像Base64数据,需要转换成图像。红细胞和血小板直方图以及散点图类似。

OBX|31|ED|15008^WBC Histogram. BMP^99MRC||^Image^BMP^Base64^Qk1ObgAAAAAAAAYCAAAoAAAApQAAAKUAAAABAAgAAAAAAEh

bmp = Base64ToImage(itemValue.Substring("^Image^BMP^Base64^".Length));//获取直方图

完成后需要向仪器发送成功消息:

string ack = string.Format(@"MSH|^~\&|LIS||||{0}||ACK^R01|{1}|P|2.3.1||||||UNICODE
MSA|AA|{2}", Cvt.Date14(DateTime.Now), messageID, messageID);//messageID是前面获取的消息控制ID
args.SendData = Encoding.UTF8.GetBytes(ack);//发送串口数据

下面是完整的解析代码,因为是LIS系统的一部分,代码并不简洁,其中分类线等数据并没用上:

/// <summary>
/// 迈瑞BC-5000,5120,5150血球分析仪数据解析
/// </summary>
/// <param name="id">检验设备名称或者ID,用于缓冲区</param>
/// <param name="data">串口数据</param>
/// <returns>检验结果类</returns>
public static DataArgs MindrayBC5000(string id, byte[] data)
{
    if (data.Length == 1 && data[0] == 2)//过滤0x02
    {
        return null;
    }
    data = Comm.TrimByte(data, 0x02);//删除数据流前后的0x02
    if (Comm.IsBegin(data, 0x0B) && Comm.dataBuffer.ContainsKey(id))//数据流从0x0B开始
    {
        Comm.dataBuffer[id].Clear();//清空缓冲区
    }
    Comm.AddBuffer(id, data);//数据放入缓冲区,同一个患者的结果可能被分成几段传输
    if (Comm.IsEnd(Comm.dataBuffer[id].Data, new byte[] { 0x1C, 0x0D }) == false)//以0x1C, 0x0D结束,传输还没结束,继续等待数据
    {
        return null;
    }
    //完成接收数据,清除前后标记
    Comm.dataBuffer[id].Data.RemoveAt(0);//0x0B开始
    Comm.dataBuffer[id].Data.RemoveRange(Comm.dataBuffer[id].Data.Count - 3, 2);//0x1C, 0x0D结束
    data = Comm.dataBuffer[id].Data.ToArray();//把缓冲区内数据复制到data后清空缓冲区


    Comm.dataBuffer[id] = null;
    Comm.dataBuffer.Remove(id);

    if (data == null || data.Length < 100)
        return null;
    string messageID = "";
    string type = "";
    DataArgs args = new DataArgs();//保存检验结果的类
    args.Data = data;
    args.Type = 0;
    List<ItemArgs> itemList = new List<ItemArgs>();//保存检验项目
    string[] Segment = Comm.ByteToString(data).Split((char)0x0D);//数据流转字符串后,以0x0D作为分隔符变成数组
    Comm.Log("StartingDataSub");
    char splitChar = '|';// Segment[0][3];//用|分隔
    List<byte> WSepLine = new List<byte>();
    List<byte> RSepLine = new List<byte>();
    List<byte> PSepLine = new List<byte>();
    List<byte> RHisto = new List<byte>();
    List<byte> WHisto = new List<byte>();
    List<byte> PHisto = new List<byte>();
    List<byte> DHisto = new List<byte>();//散点图
    Dictionary<string, int> dictLength = new Dictionary<string, int>();//直方图数据长度

    //该设备会传输直方图的图片,无需通过数据自己画图
    List<Bitmap> bmpList = new List<Bitmap>();
    HistoBox histDIFF = new HistoBox();
    histDIFF.HistoType1 = HistoBox.HistoType.DIFF;
    for (int i = 0; i < Segment.Length; i++)
    {
        string[] Field = Segment[i].Split(splitChar);//每行记录再用“|”分隔符拆分获取字段
        switch (Field[0])
        {
            case "MSH":
                messageID = Field[9];//消息控制ID
                type = Field[10];//P样本,Q质控
                break;
            case "OBR":
                args.SampleNo = Cvt.ToInt(Field[3]);//样本号
                args.DateTime = Cvt.ToDateTime(Field[7], "yyyyMMddHHmmss", DateTime.Now);//检验时间
                break;
            case "OBX":
                string itemName = Field[3].Split('^')[1];//项目名称
                string itemValue = Field[5];//值
                switch (itemName)
                {
                    //  其他数据
                    case "Take Mode":    //	进样模式	IS	8001	99MRC	08001^Take Mode^99MRC	
                    case "Blood Mode":    //	血样模式	IS	8002	99MRC	08002^Blood Mode^99MRC	
                    case "Test Mode":    //	测量模式	IS	8003	99MRC	08003^Test Mode^99MRC	
                    case "Age":    //	年龄	NM	30525-0	LN	30525-0^Age^LN	
                    case "Remark":    //	备注	ST	1001	99MRC	01001^Remark^99MRC	
                    case "Ref Group":    //	参考组	IS	1002	99MRC	01002^Ref Group^99MRC	
                    case "Qc Level":    //	质控级别	IS	5001	99MRC	05001^Qc Level^99MRC	
                    case "Recheck flag":    //	复检标志	IS	1006	99MRC	01006^ Recheck flag^99MRC	
                        break;
                    //	检验结果数据项					
                    case "WBC":    //	WBC	NM	Feb-90	LN	6690-2^WBC^LN	
                    case "BAS#":    //	BAS	NM	704-7	LN	704-7^BAS#^LN	
                    case "BAS%":    //	BAS_PER	NM	706-2	LN	706-2^BAS%^LN	
                    case "NEU#":    //	NEU	NM	751-8	LN	751-8^NEU#^LN	
                    case "NEU%":    //	NEU_PER	NM	770-8	LN	770-8^NEU%^LN	
                    case "EOS#":    //	EOS	NM	711-2	LN	711-2^EOS#^LN	
                    case "EOS%":    //	EOS_PER	NM	713-8	LN	713-8^EOS%^LN	
                    case "LYM#":    //	LYM	NM	731-0	LN	731-0^LYM#^LN	
                    case "LYM%":    //	LYM_PER	NM	736-9	LN	736-9^LYM%^LN	
                    case "MON#":    //	MON	NM	742-7	LN	742-7^MON#^LN	
                    case "MON%":    //	MON_PER	NM	May-05	LN	5905-5^MON%^LN	
                    //	研究参数					
                    case "*ALY#":    //	ALY	NM	26477-0	LN	26477-0^*ALY#^LN	
                    case "*ALY%":    //	ALY_PER	NM	13046-8	LN	13046-8^*ALY%^LN	
                    case "*LIC#":    //	LIC(大型未成熟细胞)	NM	10000	99MRC	10000^*LIC#^99MRC	
                    case "*LIC%":    //	LIC_PER(大型未成熟细胞百分比)	NM	10001	99MRC	10001^*LIC%^99MRC	
                    case "RBC":    //	RBC	NM	789-8	LN	789-8^RBC^LN	
                    case "HGB":    //	HGB	NM	718-7	LN	718-7^HGB^LN	
                    case "MCV":    //	MCV	NM	787-2	LN	787-2^MCV^LN	
                    case "MCH":    //	MCH	NM	785-6	LN	785-6^MCH^LN	
                    case "MCHC":    //	MCHC	NM	786-4	LN	786-4^MCHC^LN	
                    case "RDW-CV":    //	RDW_CV	NM	788-0	LN	788-0^RDW-CV^LN	
                    case "RDW-SD":    //	RDW_SD	NM	21000-5	LN	21000-5^RDW-SD^LN	
                    case "HCT":    //	HCT	NM	Mar-44	LN	4544-3^HCT^LN	
                    case "PLT":    //	PLT	NM	777-3	LN	777-3^PLT^LN	
                    case "MPV":    //	MPV	NM	32623-1	LN	32623-1^MPV^LN	
                    case "PDW":    //	PDW	NM	32207-3	LN	32207-3^PDW^LN	
                    case "PCT":    //	PCT(血小板压积)	NM	10002	99MRC	10002^PCT^99MRC	
                    case "PLCC":    //	PLCC	NM	10013	99MRC	10013^ PLCC^99MRC	
                    case "PLCR":    //	PLCR	NM	10014	99MRC	10014^ PLCR^99MRC	
                        itemList.Add(new ItemArgs(itemName, itemValue, true)); //OBX|7|NM|6690-2^WBC^LN||***.**|10*9/L|***.**-***.**|N|||F
                        break;
                    //	质控特有参数					
                    //case "GRAN-X":    //	GRAN-X	NM	10003	99MRC	10003^GRAN-X^99MRC	
                    //case "GRAN-Y":    //	GRAN-Y	NM	10004	99MRC	10004^GRAN-Y^99MRC	
                    //case "GRAN-Y(W)":    //	GRAN-Y(W)	NM	10005	99MRC	10005^GRAN-Y(W)^99MRC	
                    //case "WBC-MCV":    //	WBCMCV	NM	10006	99MRC	10006^WBC-MCV^99MRC	
                    //	检验结果中间数据(WBC、RBC、PLT直方图及散点图数据等)					

                    case "WBC Histogram. Left Line":    //	WBC直方图左分类线	NM	15001	99MRC	15001^WBC Histogram. Left Line^99MRC	
                    case "WBC Histogram. Right Line":    //	WBC直方图右分类线	NM	15002	99MRC	15002^WBC Histogram. Right Line^99MRC	
                    case "WBC Histogram. Middle Line":    //	WBC直方图中间分类线	NM	15003	99MRC	15003^WBC Histogram. Middle Line^99MRC	
                        WSepLine.Add(Cvt.ToByte(itemValue));
                        break;
                    case "WBC Histogram. Meta Length":    //	WBC直方图元数据长度	NM	15004	99MRC	15004^WBC Histogram. Meta Length^99MRC	
                        dictLength.Add(itemName, Cvt.ToInt(itemValue));
                        break;
                    case "WBC Histogram. Binary":    //	WBC直方图二进制数据	ED	15000	99MRC	15000^WBC Histogram. Binary^99MRC	
                        WHisto.AddRange(Comm.StringToByte(itemValue));
                        break;
                    //case "WBC Histogram. Left Line Adjusted":    //	WBC直方图左分类线调整标记	NM	15005	99MRC	15005^WBC Histogram. Left Line Adjusted^99MRC	
                    //case "WBC Histogram. Right Line Adjusted":    //	WBC直方图右分类线调整标记	NM	15006	99MRC	15006^WBC Histogram. Right Line Adjusted^99MRC	
                    //case "WBC Histogram. Middle Line Adjusted":    //	WBC直方图中间分类线调整标记	NM	15007	99MRC	15007^WBC Histogram. Middle Line Adjusted^99MRC	
                    case "WBC Histogram. BMP":    //	WBC直方图位图数据	ED	15008	99MRC	15008^WBC Histogram. BMP^99MRC	
                        bmpList.Add(Comm.Base64ToImage(itemValue.Substring("^Image^BMP^Base64^".Length)));
                        break;
                    case "RBC Histogram. BMP":    //	WBC直方图位图数据	ED	15008	99MRC	15008^WBC Histogram. BMP^99MRC	
                        bmpList.Add(Comm.Base64ToImage(itemValue.Substring("^Image^BMP^Base64^".Length)));
                        break;
                    case "PLT Histogram. BMP":    //	WBC直方图位图数据	ED	15008	99MRC	15008^WBC Histogram. BMP^99MRC	
                        bmpList.Add(Comm.Base64ToImage(itemValue.Substring("^Image^BMP^Base64^".Length)));
                        break;
                    //case "WBC Histogram. Total":    //	WBC直方图总数	NM	15009	99MRC	15009^WBC Histogram. Total^99MRC	
                    case "RBC Histogram. Binary":    //	RBC直方图二进制数据	ED	15050	99MRC	15050^RBC Histogram. Binary^99MRC	
                        RHisto.AddRange(Comm.StringToByte(itemValue));
                        break;
                    case "RBC Histogram. Left Line":    //	RBC直方图左分类线	NM	15051	99MRC	15051^RBC Histogram. Left Line^99MRC	
                    case "RBC Histogram. Right Line":    //	RBC直方图右分类线	NM	15052	99MRC	15052^RBC Histogram. Right Line^99MRC	
                        RSepLine.Add(Cvt.ToByte(itemValue));
                        break;
                    //case "RBC Histogram. Left Line Adjusted":    //	RBC直方图左分类线调整标记	IS	15054	99MRC	15054^RBC Histogram. Left Line Adjusted^99MRC	
                    //case "RBC Histogram. Right Line Adjusted":    //	RBC直方图右分类线调整标记	IS	15055	99MRC	15055^RBC Histogram. Right Line Adjusted^99MRC	
                    case "RBC Histogram. Binary Meta Length":    //	RBC直方图元数据长度	NM	15053	99MRC	15053^RBC Histogram. Binary Meta Length^99MRC	
                        dictLength.Add(itemName, Cvt.ToInt(itemValue));
                        break;
                    case "PLT Histogram. Binary":    //	PLT直方图二进制数据	ED	15100	99MRC	15100^PLT Histogram. Binary^99MRC	
                        PHisto.AddRange(Comm.StringToByte(itemValue));
                        break;
                    case "PLT Histogram. Left Line":    //	PLT直方图左分类线	NM	15111	99MRC	15111^PLT Histogram. Left Line^99MRC	
                    case "PLT Histogram. Right Line":    //	PLT直方图右分类线	NM	15112	99MRC	15112^PLT Histogram. Right Line^99MRC	
                        PSepLine.Add(Cvt.ToByte(itemValue));
                        break;
                    case "PLT Histogram. Binary Meta Length":    //	PLT直方图元数据长度	NM	15113	99MRC	15113^PLT Histogram. Binary Meta Length^99MRC	
                        dictLength.Add(itemName, Cvt.ToInt(itemValue));
                        break;
                    //case "PLT Histogram. Left Line Adjusted":    //	PLT直方图左分类线调整标记	IS	15114	99MRC	15114^PLT Histogram. Left Line Adjusted^99MRC	
                    //case "PLT Histogram. Right Line Adjusted":    //	PLT直方图右分类线调整标记	IS	15115	99MRC	15115^PLT Histogram. Right Line Adjusted^99MRC	
                    case "WBC DIFF Scattergram. BMP":    //	DIFF散点图位图数据	ED	15200	99MRC	15200^WBC DIFF Scattergram. BMP^99MRC	
                        bmpList.Add(Comm.Base64ToImage(itemValue.Substring("^Image^BMP^Base64^".Length)));
                        break;
                    case "WBC DIFF Scattergram. BIN":    //	DIFF散点图二进制数据	ED	15201	99MRC	15201^ WBC DIFF Scattergram. BIN^99MRC	
                        histDIFF.HistoBytes = Comm.Base64ToStream(itemValue.Substring("^Application^Octer-stream^Base64^".Length));
                        break;
                    //case "WBC DIFF Scattergram. BIN type data":    //	DIFF散点图Type数据	ED	15202	99MRC	15202^ WBC DIFF Scattergram. BIN type data^99MRC	
                    case "WBC DIFF Scattergram. Fsc dimension":    //	OBX|44|NM|15205^WBC DIFF Scattergram. Fsc dimension^99MRC||256||||||F 
                        histDIFF.Width = Cvt.ToInt(itemValue);
                        break;
                    case "WBC DIFF Scattergram. Ssc dimension":    //	OBX|45|NM|15206^WBC DIFF Scattergram. Ssc dimension^99MRC||256||||||F 
                        histDIFF.Height = Cvt.ToInt(itemValue);
                        break;
                    case "WBC DIFF Scattergram. Meta len":    //	DIFF散点图元数据长度	NM	15203	99MRC	15203^ WBC DIFF Scattergram. Meta len^99MRC	
                        dictLength.Add(itemName, Cvt.ToInt(itemValue));
                        break;
                    case "WBC DIFF Scattergram. Meta count":    //	DIFF散点图元数据数目	NM	15204	99MRC	15204^ WBC DIFF Scattergram. Meta count^99MRC	
                        dictLength.Add(itemName, Cvt.ToInt(itemValue));
                        break;
                    //	异常报警信息					
                    case "WBC Abnormal":    //	白细胞异常	IS	12011	99MRC	12011^WBC Abnormal^99MRC	
                    case "Imm Granulocytes?":    //	未成熟细胞?	IS	34165-1	LN	34165-1^Imm Granulocytes?^LN	
                    case "Atypical Lymphs?":    //	异常/异型淋巴细胞?	IS	15192-8	LN	15192-8^Atypical Lymphs?^LN	
                    case "RBC Abnormal distribution":    //	红细胞分布异常	IS	12013	99MRC	12013^RBC Abnormal distribution^99MRC	
                    case "Anemia":    //	贫血	IS	12014	99MRC	12014^Anemia^99MRC	
                    case "HGB Interfere":    //	血红蛋白异常/干扰?	IS	12015	99MRC	12015^HGB Interfere^99MRC	
                    case "PLT Abnormal Distribution":    //	血小板分布异常	IS	12016	99MRC	12016^PLT Abnormal Distribution^99MRC	
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    }
    args.ItemsList = itemList.ToArray();
    if (WHisto.Count > 0)
    {
        args.WHisto = WHisto.ToArray();
        HistoBox hist0 = new HistoBox(HistoBox.HistoType.WBC, args.WHisto, args.WSepLine);
        hist0.MaxFL = 385;
        //hist0.LineType = HistoBox.LineTypes.LinesSmooTh;
        hist0.XSpace = 1;// 400f / 256f;
        hist0.Draw();
        bmpList.Add((Bitmap)hist0.Image);
    }
    if (RHisto.Count > 0)
    {
        args.RHisto = RHisto.ToArray();
        HistoBox hist1 = new HistoBox(HistoBox.HistoType.RBC, args.RHisto, args.RSepLine);
        //hist1.LineType = HistoBox.LineTypes.LinesSmooTh;
        hist1.XSpace = 1;//250f / 256f;
        hist1.Draw();
        bmpList.Add((Bitmap)hist1.Image);
    }
    if (PHisto.Count > 0)
    {
        args.PHisto = PHisto.ToArray();
        HistoBox hist2 = new HistoBox(HistoBox.HistoType.PLT, args.PHisto, args.PSepLine);
        //hist2.LineType = HistoBox.LineTypes.LinesSmooTh;
        hist2.XSpace = 1;// 30f / 256f;
        hist2.Draw();
        bmpList.Add((Bitmap)hist2.Image);
    }
    if (histDIFF.HistoBytes != null)
    {
        histDIFF.Draw();
        bmpList.Add((Bitmap)histDIFF.Image);
    }

    args.ImageList = bmpList.ToArray();

    args.Completed = true;
    //向设备发送完成消息
    string ack = string.Format(@"MSH|^~\&|LIS||||{0}||ACK^R01|{1}|P|2.3.1||||||UNICODE
MSA|AA|{2}", Cvt.Date14(DateTime.Now), messageID, messageID);
    args.SendData = Encoding.UTF8.GetBytes(ack);
    return args;
}

 

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值