精华内容
下载资源
问答
  • 仪器3Q认证

    2013-04-13 15:37:31
    仪器3Q认证.里面包括了很多有用的资料。希望能帮助一些有需要的人。
  • 按照药品认证合作组织(PIC/S)在GxP环境下的计算机化系统合规实践指南(PI011-3指南)的定义,计算机化系统由计算机系统和被其控制的功能或流程组成。原则 第二条、第条和第四条。主要描述了对于风险管理和供应商管理...

    内容解析

    范围 *条。描述了本附录的适用范围:适用于在药品生产质量管理过程中应用的计算机化系统,同时明确了系统“由一系列硬件和软件组成,以满足特定的功能”。按照药品认证合作组织(PIC/S)在GxP环境下的计算机化系统合规实践指南(PI011-3指南)的定义,计算机化系统由计算机系统和被其控制的功能或流程组成。

    原则 第二条、第三条和第四条。主要描述了对于风险管理和供应商管理两个方面的要求。

    对于风险管理,一方面是整个生命周期要实施风险管理;另一方面是验证的范围和程度要基于风险评估的结果来确定。

    对于供应商管理,需要制定相应规程,要有明确的协议来明确供应商及制药企业双方职责,以及需要基于风险评估的结果开展供应商审计并形成文件化的记录。

    人员 第五条。该章节强调了在系统验证、使用、维护、管理过程中各职能部门人员的紧密配合,并要求明确各自权限和职责;人员要接受相应培训以适合其岗位工作,且对实施培训和指导工作的人员提出了要求:“确保有适当的专业人员……”

    验证 第六条。应用程序的验证与基础架构的确认实际上是按照软件分类的原则(可参考IS GAMP5)实施不同生命周期验证活动。其实也是采用风险管理的理念,即软硬件类别不同导致其系统复杂性和新颖性带来的风险不同,使得验证的程度(或深度)不同——采用基于科学的风险评估来确认计算机化系统确认验证的范围和程度(比如通过GxP关键性评估确定验证的范围,通过功能性风险评估确定验证的程度);确保整个生命周期内系统处于验证的受控状态(可供参考的方法是在系统运行维护阶段遵循变更和配置管理,以及安全管理、对系统实施定期评估等)。

    第九条。确认验证过程中,在系统数据出现转换及迁移情况时需确认数据的值及意义没有改变(比如发酵罐PLC设备将罐压数据通过通讯协议转移至集散控制系统DCS,则在对DCS系统进行OQ检查时需要确认二者数值的*性)。

    系统 第十条。对安装计算机化系统的物理环境作出规定,制药企业制定清洁确证和用户需求说明(URS)和进行系统设计时需要将其考虑进去,安装确认(IQ)中要对系统的安装位置进行确认,保证系统的安装环境是不受外来因素干扰的。

    第十一条。对关键系统的技术资料提出需求(比如功能说明、硬件设计说明、软件设计说明、电路图、网络结构图等),这些技术资料要及时更新,保证和实际状态*。

    第十三条。针对软件的全面测试,根据软件级别的不同,其测试程度也不同(比如针对五类软件系统的源代码审核和模块测试,针对四类软件系统的配置测试,然后是基于“黑盒”的功能测试、需求测试,以及包括结合实际工艺或流程的性能测试程度都不同)。

    第十四条。对系统的访问权限控制提出要求,并且要求制定规程定期检查授权的使用、变更与取消。值得一提的是,也许出于国内实际情况考虑,新修订《计算机化系统》附录做出了硬件不足软件补的让步——“对于系统自身缺陷,无法实现人员控制的,必须具有书面程序、相关记录及相关物理隔离手段,保证只有经许可的人员方能进行操作”。需要注意的是,EU和FDA并没有类似要求。并且大部分企业目前不存在由于硬性缺陷问题而面临制定规程进行有效管理的问题。

    第十五条。对人工输入数据的准确性提出复核要求,复核的方式可以是另外的操作人员或者是经过验证的电子方式(比如经过验证的称量配料系统通过报警提示能够完成“超重”、“欠重”、“批号错误”、“忘记去皮”等关键信息复核,则岗位无需配备另一名用于复核的操作人员;再比如数据输入的有效性符合如下要求:对范围和小数点位数进行限制,超出范围和有效位数的数据无法输入)。

    第十六条。对审计跟踪提出要求(根据“风险评估的结果来考虑”给系统加入此功能),注意“每次修改已输入的关键数据均应当经过批准,并应当记录更改数据的理由”,其中记录更改数据的理由容易被制药企业忽视。

    第十七条。对计算机化系统的变更做出详细规定。制药企业应制定针对计算机化系统的变更管理规程,并按照既定的规程实施变更活动。如果第十四条“存在硬性缺陷”,则此条其实是无法实现的。

    第十八条。对于记录的形式(电子的、物理的或者混合的)做出说明。其中,“应当有文件明确规定以电子数据为主数据还是以纸质打印文稿为主数据”易被药企忽视。需要注意的是,企业采用从计算机化系统“誊抄”纸质版数据支持报告放行的做法,并不能规避对“电子记录”的监管要求,此时纸质数据和电子数据的*性也是检查员关注的重点,这也涉及数据完整问题。

    第十九条。对于采用电子数据作为主数据的情况提出管理要求,包括不限于:电子数据要能打印成清晰易懂的物理文稿(即一般人可读的物理文件);物理或电子的方式储存以及定期检查可读性和完整性;起草备份恢复规程按照记录的既定时限要求进行数据的备份管理等。

    第二十条和第二十一条。对制定应急方案、制定故障处理规程、实施纠正预防措施提出要求。可参考IS GAMP5的附录O4“突发事件管理”和附录O10“业务连续性管理”。

    第二十二条。对采用计算机化系统进行产品放行的情形作出明确规定。这其实就是前面提及的“审计跟踪”在产品放行环节的一个特定应用而已。此过程应通过使用电子签名来实现。而在此方面EU比我国要求要严格。

    第二十三条。对电子数据可采用电子签名的做法及其要求作出说明,“电子签名应当遵循相应法律法规的要求”。对于制药领域可供借鉴的相关法规,一般均采用美国联邦法规第21篇第11条款(21CFR Part11),此标准之下FDA将认为电子记录、电子签名和在电子记录上的手签名是可信赖的、可靠的且通常等同于纸质记录和在纸上的手写签名。

    术语 第二十四条。对电子签名、电子数据、数据审计追踪、数据完整性等七个术语进行了诠释。

    展开全文
  • 清洁器,该清洁器适用于CertiFiber Pro光纤测试仪CFP2-100-Q以及OptiFiber Pro光纤测试仪OFP2-100-Q。如果污染严重,则可以使用蘸有福禄克网络清洁剂的棉签,然后再使用干棉签进行擦拭。(小贴士:使用CertiFiber ...

    如何保持福禄克CFP2-100-Q、OFP2-100-Q等光纤测试仪器的洁净?

    从光纤端面到测试仪
    长期以来,清洁一直是安装光纤的更佳实践,但自从COVID-19(新冠病毒)疫情爆发以来,您需要担心的不再只是光纤端面的清洁问题。试想一下您和工作现场的其他工作人员经常触碰布线工具和测试仪的频繁程度,那么显而易见,它们也需要清洁。
    虽然清洗光纤端面和频繁接触的福禄克网络测试仪是出于两种完全不同的原因,但其目的都是在不造成任何损害的情况下进行清洗。因此,我们认为我们采用的清洁方式应该涵盖更佳的清洁方法,清洁从光纤端面上的灰尘到测试仪上的细菌。

    黄金法则
    截至目前,我们希望任何部署光纤设施的工作人员都了解连接器清洁的重要性,并遵循检查、清洁和再次检查的黄金法则。毕竟,光纤端面污染仍然是造成光纤网络问题的头号原因。
    进行清洁时,请牢记清洁的更佳方式以防止损坏。首先,请确保使用正确工具来完成工作。不建议使用罐装空气,因为其只会把颗粒吹散到周围,这些颗粒会重新落回到光纤端面上,并且灌装空气通常会排放出喷射剂,而其又会成为另一种需要清除的污染物。
    笔式清洁器(Quick Clean清洁器)非常适合用于去除灰尘和其他常见污染物,只需一次,足以彻底清洁端面。
    较为顽固的污染物则需要采用湿式清洁法。这种方法应使用溶剂来完成,而不是更为侵略性的干式方法,干式法会产生静电,从而吸附更多灰尘,但也必须采用正确的溶剂。异丙醇会留下“晕环”,导致衰减,并且很难去除,甚至会从一个端面扩散到另一个端面,使用专门用于光纤端面清洁的溶剂。

    如何保持福禄克CFP2-100-Q、OFP2-100-Q等光纤测试仪器的洁净?


    并且不要忘记施加压力和采用整体的清洁技巧。在坚硬的表面上进行清洁或者向下按压的力量太大可能会损坏光纤端面。您需要足够的压力来使清洁剂浸润整个端面的几何形状——通常只需一两次短暂按压即可。完成清洁后,请别忘了再次检查端面,使用福禄克网络的FI-7000 FiberInspector Pro,只需一秒多钟即可根据IEC 61300-3-35标准来认证光纤端面。

    清洁设备

    如何保持福禄克CFP2-100-Q、OFP2-100-Q等光纤测试仪器的洁净?


    美国疾病控制与预防中心(CDC)建议要对经常接触的表面进行清洁以避免感染COVID-19的风险,感染率急剧上升的同时我们又进入了流感高发季节,因此对福禄克网络的工具和测试仪进行清洁和消毒比以往任何时候都更为重要。与清洁光纤端面不同,在清洁测试设备时,实际上可以使用异丙醇。但要注意酒精含量。虽然80%的浓度对于洗手液来说是可以的,但不建议使用浓度超过70%的异丙醇,因为其可能会损坏测试仪上的标记或屏幕。还应始终避免使用任何类型的丙酮,因为其会溶解塑料。福禄克提供有仪表清洁湿巾,但日常清洁时应避免使用,并且请勿在LCD屏幕上使用该湿巾。3%的双氧水是测试仪日常清洁的绝佳选择。
    切勿在测试仪上使用研磨性清洁剂,尤其是在清洁屏幕时,因为其会在屏幕上留下划痕,使您很难清晰地看到测试结果,尤其是在光线昏暗的地方。清洁屏幕时,我们建议使用清洁智能手机或眼镜时用到的超细纤维布。市面上的镜头清洁剂非常适合上述应用,只需确保每次都使用新的清洁布,并且不要擦干——让屏幕自然风干,确保清洁剂迅速蒸发,没有残留。

    如何保持福禄克CFP2-100-Q、OFP2-100-Q等光纤测试仪器的洁净?


    端口脏污对于光纤测试仪来说非常常见。实际上,大多数需要维修的测试仪都需要清洁端口。测试仪端口脏污会导致测试结果不佳,但请注意,清洁测试端口需要遵循端面清洁建议——而非清洁测试仪表面相关建议。清洁测试端口的更简单方法是使用Quick Clean?清洁器,该清洁器适用于CertiFiber Pro光纤测试仪CFP2-100-Q以及OptiFiber Pro光纤测试仪OFP2-100-Q。如果污染严重,则可以使用蘸有福禄克网络清洁剂的棉签,然后再使用干棉签进行擦拭。(小贴士:使用CertiFiber Pro或OptiFiber Pro时,如果端口脏污,仪器会发出警告消息。)

    展开全文
  • 1. 前言 使用labview撰写程序的过程中,难免会面临软硬件的结合,尤其LabVIEW在...但公司里总是会有许许多多不同的测试仪器,要如何进行仪器 控制,真的很费神,在解决问题的过程中,从各方学习到不少经验...
    原文地址:https://bbs.elecfans.com/jishu_486554_1_1.html,转载过来用在留存学习。
     
     
    1.    前言
    使用labview撰写程序的过程中,难免会面临软硬件的结合,尤其LabVIEW在程序与测试仪器的应用范围甚广,要如何利用LabVIEW操作测试仪 器就成为相当重要的课题,笔者因工作需求也常面临这类问题,若是使用NI相关设备时都较好解决,但公司里总是会有许许多多不同的测试仪器,要如何进行仪器 控制,真的很费神,在解决问题的过程中,从各方学习到不少经验,在此分享笔者到目前的收获给各位。
     
    2. 利用范例程序(vi档)进行控制
    在使用测试仪器时,若是仪器厂商有提供LabVIEW的范例程序,最直接的就是能使用范例程序进行控制,若是程序需求不大,甚至能将范例程序稍作修改马上产出程序,以下以DAQ及传统箱型仪器为例;
     
    2-1.  以DAQ为例:
    连接上DAQ后,如图1-1-1,点选Block Diagram -> Measurement I/Q -> NI-DAQmx -> DAQ Assistant,进入如图1-1-2的设定画面,在此可以设定输入与输出的讯号,设定完成就可以直接在程序里使用。
    个人觉得DAQ蛮好用的,尤其是当你的仪器有电压输出又想要连接到LabVIEW分析时,就可以将电压讯号接到DAQ的Voltage,利用DAQ Assistant快速的建立分析程序,笔者就曾利用DAQ Assistant快速建立读取光侦测器数值的程序。

     
    图2-1-1 DAQ Assistant
     
    图2-1-2 DAQ设定画面
     
    除了使用DAQ Assistant来控制DAQ以外,NI Example Finder里也有许多DAQ相关的范例程序,从NI Example Finder -> Hardware Input and Output -> DAQmx,如图2-1-3,NI提供许多种范例程序,从类比输入输出、数位类比输入输出到计数功能皆有,且与DAQ Assistant不同的是,范例程序里使用的元件不是如同DAQ Assistant全包起来,而是每个独立元件,因此使用者可以依自己的需求将范例程序另存新档改成符合需求的程序,如图2-1-4,但有一点要注意的是 由于使用独立元件,所以要自行先确认DAQ已与计算机连接上,此部份可在Measurement & Automation Explorer中作好仪器的确认,如图2-1-5。
     
    图2-1-3 NI Example Finder
     
     
    图2-1-4 类比电流
     
    图2-1-5 Measurement & Automation Explorer
     
     
    2-2. 仪器厂商提供范例程序
     
    许多工程师应该会遇到同样的问题,就是手边或公司有非NI的设备,又希望能快速的进行程序撰写,此时就可以询问厂商,假如手上的资料撷取仪器有范例程序能 使用,只要安装驱动程序,即可在LabVIEW里轻松使用其DAQ;在RF仪器中,笔者使用过的传统箱型仪器同样有范例程序,让笔者在设计程序上减了不少 麻烦,如图1-2-1,将厂商提供的initial与Mask范例程序放进程式后并接好连线,就可以使用程序抓取IQnxn读取到的Mask讯号。
    图2-2-1 传统箱型仪器范例
     
     
    3. 使用DLL控制仪器
     
    DLL,又称为动态连结函式库,是将控制常用的程序码制作而成,当程序呼叫DLL时才会载入存储器中,利用DLL来操作仪器对计算机的使用上较节省存储器, 有些仪器厂商没有LabVIEW范例程序,仅提供DLL进行呼叫控制,虽然在操作上不如范例程序方便,但透过LabVIEW的呼叫功能,可以利用 LabVIEW的Call Library Function Node载入DLL来进行仪器的操作,网站上也有许多载入DLL相关的信息,因此在此作简单介绍。
     
    点选Block Diagram -> Connectivity -> Libraries & Executables -> Call Library Function Node,如图2-1~图2-3,并设定仪器DLL放置路径与资料型态后即可使用,不过要注意的一点是要载入DLL前要先了解此DLL送出来的资料为何, 这部份可透过仪器厂商的解说文件得知;在图2-4中,笔者使用Call Library Function Node载入读取Power的DLL档,在Function Name选择Getpower,由于Power的数值含小数点,因此在资料型态的部份选择8-type Double,并在输出的部份接一个Double Numeric Indicator,建立好后当程序执行到此部份就可以获得power数值并进行后续的程序。
    图3-1 Call Library Function Node
    图3-2 设定呼叫路径
     
    图3-3 设定资料型态
    图3-4 简易程序
     
     
    4.  利用SCPI控制仪器
     
    不少仪器有支援SCPI指令,一般常用的箱型讯号产生器皆有支援,在没有范例程序以及DLL可以呼叫的情况下,就可以思考使用SCPI指令来操作仪器,通 常仪器有支援SCPI指令都会有详细的指令集,取得指令集后,可使用RS232/GPIB/LAN等界面连接主机进行仪器控制,而要利用LabVIEW输 入SCPI指令给仪器就要透过Block Diagram -> Instrument I/Q -> VISA里的VISA元件进行操作,如图3-1,在VISA元件区,我们可以利用Open、Close、Write、Read等元件进行程序设计,笔者分 别以GPIB和LAN两种界面作介绍:
    图4-1 VISA
     
     
    4-1.   使用GPIB界面连接仪器
     
    将仪器与主机用GPIB线材连接后,就可以开始试着使用SCPI进行控制,但在此之前要先从仪器上取得GPIB Address,通常GPIB Address会在仪器的Information或Settings里,且当使用2台以上的GPIB仪器时,可以修改彼此间的数值才不会造成仪器冲突,取 得GPIB Address后要先建立主机与仪器的连线,在SCPI指令中开启连线的指令为
     
    GPIB0::GPIB Address::INSTR以笔者的讯号产生器为例,GPIB Address为23,因此笔者输入的指令为GPIB0::23::INSTR,将此串指令用字串连进LabVIEW VISA Open元件,如图3-1-1,
    图4-1-1 VISA Open
     
    连接后下一步就是要确定是否有连到仪器,此时我们可以利用另外一个指令来确认,确认指令为*IDN?
    这个指令主要是用来判断仪器的型号等,在此我们是拿来确认连接状况,因此就可以将指令用VISA Write跟VISA Read作结合,如图3-1-2,
     
    图4-1-2 GPIB确认仪器连接
     
    若执行上没问题,以常用的箱型讯号产生器为例,就会看到String Indicator收到一连串信息『......Technologies, N5182B,MY51350428, .........』,注意一点,每台仪器出来的讯息都不一样,因此详细资料意义要从指令集手册中了解;而为了使用让程序更严谨一点,我们可以对图 3-1-2的程序作修改,如图3-1-3,首先将GPIB Address独立用String Control,这样就可以任意更改,接下来用Case Structure接在Open的Error out,此步骤是为了确认是否连接正常,若连接正常进入『No Error』就写入读取仪器的指令并读出,连接错误就将错误讯息Open Fail连至dialog显示并停止程序,这样设计是为了让程序在连接错误的第一时间马上反馈给使用者,才不会未连接到仪器却程序持续进行,这一部份完成 后就可以依要完成的动作输入对应的指令来完成程序。
    图4-1-3 GPIB确认仪器连接进阶版
     
     
    4-2. 使用LAN界面连接仪器
     
    使用LAN界面,也就是使用网络线连接主机与仪器,这种连接方式只要将主机连到HUB,就可以接到多台测试仪器,也免去要接一堆GPIB线或是计算机USB 孔不够的问题,在此笔者是使用SCPI里的TCPIP进行控制,其实无论是使用GPIB或是LAN的SCPI指令都大同小异,举例来说,LAN界面的开启 连线指令为
     
    TCPIP0::IP Address::inst0::INSTR
     
    与GPIB指令比对,除了Address不一样外,基本上架构是一样的,就连查询仪器型号指令也是*IDN?,因此我们可以直接将GPIB的程序作点修改 来使用,例如目前测试仪器的IP Address为192.168.100.254,就可以将程序修改成如图3-2-1,同样的也可改成进阶版的程序,如图3-2-2;不过在使用LAN介 面时要注意IP是否会相冲,以笔者经验,通常测试仪器的IP Address不太能作修改,因此若程序会用到两台以上的仪器,而IP又相同时,就要考虑是否一台用GPIB,一台用LAN,若要用LAN的方式去连接, 就要去询问仪器厂商是否能协助调整IP
    图4-2-1 LAN确认仪器连接
     
    图4-2-2 LAN确认仪器连接进阶版
     
     
    5.   结语
     
    以上为目前有用到的连接测试仪器的方式,通常在遇到新的仪器时,笔者都会先去询问仪器厂商是否有范例程序,毕竟有范例程序的情况下能加速程序开发,若没有 笔者就会上网寻找或是连到NI网站『仪器驱动程序数据库IDNet』,NI网站上数据库有蛮多种各家仪器的范例程序,且这些程序基本上都相当完整,因此若 是想追求用vi档完成程序的可以到NI网站去寻宝,祝各位都能顺利使用LabVIEW控制仪器。
    展开全文
  • 检验串口仪器探秘

    2019-11-10 07:31:54
    一直对盒子串口仪器接口缺乏系统的了解。为什么仪器控制能启动停止,为什么能读到数据,接口结构为什么要那样写等等,特地系统的学习LIS连接TCP的秘密。 1.为啥仪器控制能启动仪器和停止仪器接口 启动 停止 ...

    一直对盒子串口仪器接口缺乏系统的了解。为什么仪器控制能启动停止,为什么能读到数据,接口结构为什么要那样写等等,特地系统的学习LIS连接TCP的秘密。

    1.为啥仪器控制能启动仪器和停止仪器接口
    启动
    启动仪器接口

    停止
    在这里插入图片描述

    在这里插入图片描述
    2.知道启动停止的机制后我们能做什么?
    对于调试仪器接口时候就可以不用界面启动仪器和停止仪器了,可以直接用terminal启动仪器接口主方法这样传输数据就能断点调试,增加调试效率,替换之前写globle猜测的方式(要注意仪器超时的问题)。
    在这里插入图片描述
    3.为什么执行主方法后能连接盒子的TCP
    重要的启动在$$Start^MI.MIF000
    在这里插入图片描述
    关键是对拼好的仪器端口串进行open命令启动tcp,同时设置连接的编码格式
    在这里插入图片描述
    在这里插入图片描述

    4.Mian循环方法解读
    一个字符一个字符读取命令
    在这里插入图片描述
    ASTM协议响应
    在这里插入图片描述
    读数据
    在这里插入图片描述
    解析保存结果
    在这里插入图片描述

    上传信息
    在这里插入图片描述

    事列代码

    MIFLISVMachine(mi)  
    	s mi=$g(mi) 
    	i '$l(mi) q
    	s ItemDeli=$li(^dbo.BTMIMachineParameterD(mi),12) //项目分隔符
    	s ResultDeli=$li(^dbo.BTMIMachineParameterD(mi),13) //结果分隔符
    	s AntDeli=$li(^dbo.BTMIMachineParameterD(mi),14) //抗生素分隔符
    	s SenDeli=$li(^dbo.BTMIMachineParameterD(mi),15) //药敏结果分隔符
    	s Port="|TCP|"_$li(^dbo.BTMIMachineParameterD(mi),17) //端口号
    	//控制字符
      	s stx=$c(2),etx=$c(3),ack=$c(6),enq=$c(5),eot=$c(4)
      	s lf=$c(10),cr=$c(13),nak=$c(21),(result,epis)="",etb=$c(23)
    	S $ZT="RuntimeError",$ECODE="",iError=0 //捕获运行时错误,并显示
    	//启动tcp连接,然后就会侦听tcp发来的消息和给tcp发送数据
    	i $$Start^MI.MIF000(mi) q
    	//循环执行Mian方法取或者发送数据到tcp
    	f  d Main i $$Stop^MI.MIF000(mi) q
      	c Port
      	q
    
     //在循环的Main方法读取一个字符直到收到ENQ的不可见字符控制命令(READ命令是阻塞的所以不会跳过去)
    Main r *R:10 e  d  q
      //收到ENQ才进入下面逻辑
      i $c(R)'=enq q
      s AllRecord=""
      d Trace^MI.MIF000(mi,"ENQ","H<--M")
      //先回复仪器我收到ENQ控制命令并且准备好接收数据了
      d ACK
      //循环等着读取数据,一直读到EOT结束(READ命令是阻塞的所以不会跳过去)
      f  r *R:10 q:$c(R)=eot  d
      .//这里没收到STX都认为是没用的数据退出掉
      .i $c(R)'=stx q
      .//收到STX后开始读取正式数据(调用包装的读取数据方法,还是指向READ阻塞读数据)
      .s record=$$Read^MI.MIF000(mi,"",lf) q:'$l(record)
      .d Trace^MI.MIF000(mi,record,"H<--M")
      .//把读取的记录拼接到总记录串上
      .s AllRecord=AllRecord_$p(record,etb,1)
      .//回复收到数据
      .d ACK
      d Trace^MI.MIF000(mi,$s($c(R)=eot:"EOT",1:R),"H<--M")
      //读取数据完成一轮就处理解析
      s (epis,rec,res,result,date,time,QC)=""
      f i=1:1:$l(AllRecord,cr) d
      .s rec=$p(AllRecord,cr,i)
      .s type=$tr($p(rec,"|")," ")
      .//判断为获取条码信息,给仪器上传标本信息
      .//格式:GetPatInfo|条码号|LISVMachine1.0|||||||||
      .//仪器要求格式:PatInfo|条码号|LISVMachine1.0|患者姓名|性别|年龄|科室|病区|诊断|采集日期|传输日期|通道^通道^通道
      .i type="GetPatInfo" d
      ..s epis=$tr($p(rec,"|",2)," ")
      ..s ^TMP($zn,$j,"ENQ",epis)=""
      .//判断为结果信息,解析结果
      .//格式:Result|条码号|通道|结果$c(13)
      .i type="Result" d  
      ..s epis=$tr($p(rec,"|",2)," ")
      ..s code=$tr($p(rec,"|",3)," ")
      ..s res=$tr($p(rec,"|",4)," ")
      ..s result=result_code_ResultDeli_res_ItemDeli
      .//格式:Last|条码号|END|$c(13)
      .i type="Last" d Last q
      d BUILD
      q
      
    Last	
    	s AllRecord=""
    	s epis=$tr($p(rec,"|",2)," ")
    	i $l(epis),$l(result) d
    	.d Save^MI.MIF000(mi,epis,result,date,time,QC)  
    	q
     
    BUILD
      i '$d(^TMP($zn)) q
      i '$d(^TMP($zn,$j)) q 
      s labno="" f  s labno=$o(^TMP($zn,$j,"ENQ",labno)) q:labno=""  d
      .d ScanOne^MI.MIF000(mi,labno)
      .s tcx=""
      .s chl="" f  s chl=$o(^TMP("MIFTESTCODE",$j,mi,labno,chl)) q:chl=""  d
      ..i $l(tcx) s tcx=tcx_"^"_chl
      ..e  s tcx=tcx_chl
      .i '$l(tcx) s tcx="Chl1^Chl2^Chl3^Chl4^Chl5"
      .s date=$zd(+$h,8)
      .s time=$tr($zt($p($h,",",2)),":")
      .s temepis=""
      .//取患者信息
      .s (PatName,Sex,Age,Location,Ward,Symptom,CollectDate,TransmitDate)=""
      .i $d(^dbo.RPVisitNumberI("IndexVisitNumber"," "_$zcvt(labno,"U"))) d
      ..s VisitNumberDR=$o(^dbo.RPVisitNumberI("IndexVisitNumber"," "_$zcvt(labno,"U"),""))
      ..//姓名
      ..s PatName=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),13)
      ..//性别
      ..s SpeciesDR=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),15)
      ..s Sex=""
      ..i $l(SpeciesDR) s Sex=$lg($g(^dbo.BTSpeciesD(SpeciesDR)),3)
      ..//年龄
      ..s Age=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),18)
      ..s AgeUnitDR=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),19)
      ..s AgeUnit=""
      ..i $l(AgeUnitDR) s AgeUnit=$lg($g(^dbo.BTAgeUnitD(AgeUnitDR)),3)
      ..s Age=Age_AgeUnit
      ..s LocationDR=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),22)
      ..//科室
      ..s Location=""
      ..i $l(LocationDR) s Location=$lg($g(^dbo.BTLocationD(LocationDR)),3)
      ..s WardDR=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),26)
      ..//病区
      ..s Ward=""
      ..i $l(WardDR) s Ward=$lg($g(^dbo.BTWardD(WardDR)),3)
      ..//诊断
      ..s Symptom=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),28)
      ..//采集日期
      ..s CollectDate=$lg($g(^dbo.RPVisitNumberD(VisitNumberDR)),51)
      ..//传输日期
      ..s TransmitDate=CollectDate
      .//要求格式:PatInfo|条码号|LISVMachine1.0|患者姓名|性别|年龄|科室|病区|诊断|采集日期|传输日期|通道^通道^通道
      .s str="PatInfo|"_labno_"|LISVMachine1.0|"_PatName_"|"_Sex_"|"_Age_"|"_Location_"|"_Ward_"|"_Symptom_"|"_CollectDate_"|"_TransmitDate_"|"_tcx
      .d Send(labno,str) 
      .k ^TMP($zn,$j,"ENQ",labno)
      q
    
    Send(epis,str)  ; send list of orders if exists
      w enq,*-3 d Trace^MI.MIF000(mi,"ENQ","H-->M")
      f j=1:1:10 r *R:1 i $c(R)=ack!($c(R)=enq) q
      //d trace^MIF000(mi,$s($c(R)=ack:"ACK",$c(R)=enq:"ENQ",$c(R)=nak:"NAK",1:R),"1H<--M")
      d Trace^MI.MIF000(mi,$s($c(R)=ack:"ACK",$c(R)=enq:"ENQ",$c(R)=nak:"NAK",1:R),"H<--M")
      i $c(R)=enq q
      i $c(R)'=ack w eot,*-3 d Trace^MI.MIF000(mi,"EOT","H-->M") q
      i $l(str)>241 d
      .s str1=$e(str,1,241)
      .s ret=$$SEND(str1,1)
      .s str2="2"_$e(str,242,$l(str))
      .s ret=$$SEND(str2,0)
      e  d
      .s ret=$$SEND(str,0)
      ;f j=1:1:10 r *R:1 i $c(R)=ack!($c(R)=enq) q
      ;d trace^MIF000(mi,$s($c(R)=ack:"ACK",$c(R)=enq:"ENQ",$c(R)=nak:"NAK",1:R),"2H<--M")
      w eot,*-3 d Trace^MI.MIF000(mi,"EOT","H-->M")
      q
     
    SEND(str,flag)  ; send string to instrument
      i flag=1 d
      .s str=str_etb
      .s chsum=$$CHSUM(str)
      e  d
      .s str=str_etx
      .s chsum=$$CHSUM(str)
      w stx,str,chsum,cr,lf,*-3 d Trace^MI.MIF000(mi,str_chsum,"H-->M")
      f j=1:1:6 r *R:1 i ($c(R)=ack)!($c(R)=eot) q
      i $c(R)=ack d Trace^MI.MIF000(mi,"ACK","H<--M") q 0
      i $c(R)=eot d Trace^MI.MIF000(mi,"EOT","H<--M") q 0
      i $c(R)=-1 w nak,*-3
      d Trace^MI.MIF000(mi,R,"H<--M")
      q 1
      
    CHSUM(x)  ; calculate check sum
      n (x) s z=0 f y=1:1:$l(x) s z=z+$a(x,y)
      s z=$e("0123456789ABCDEF",z#256\16+1)_$e("0123456789ABCDEF",z#16+1)
      q z
    ACK  ; send 'ack' to instrument
      w ack,*-3
      d Trace^MI.MIF000(mi,"ACK","H-->M")
      q
    
    RuntimeError
    	h 5
    	s iError=+$g(iError)+1
        d Trace^MI.MIF000(mi,"Error Code:"_$ECODE_",Error:"_$ZERROR,"Runtime Error")
        i iError>100  s ret=$$Stop^MI.MIF000(mi)
        Q    
          
    
    

    总结
    1.仪器接口一定要在mac里吗?
    接口没有要求,只是仪器控制启动进程那里拼串是mac调用,正常类方法也行,只是需要启动仪器控制的支持。
    2.调试仪器的时候只能写globle观察猜吗?
    可以直接terminal运行仪器接口的入口方法,然后进行断点调试,只是停止仪器时候可能需要到portal杀进程。
    3.仪器接口的核心命令就是用了OPEN命令和READ命令,为什么READ要分那么几次for循环读取呢,而不用一层循环一直READ?
    分层次读协议的体现更清晰,解析协议的是协议,读数据的是读数据逻辑。

    ASTM简单交互(ENQ开始、ACK中间回复、EOT结束)
    仪器给LIS发数据
    1.先发ENQ告诉LIS我要给你发数据
    2.LIS回复ACK给仪器
    3.仪器收到ACK后开发发数据给LIS,每段发送一STX控制开始LIS收到数据还是回ACK
    4.仪器如果发送数据完了后给LIS发送EOT告诉发送完毕(一个通信过程就完毕)
    在这里插入图片描述

    LIS给仪器发数据
    1.先发ENQ告诉仪器我要给你发数据
    2.仪器回复ACK给LIS
    3.仪器收到ACK后开发发数据给仪器,每段发送一STX控制开始仪器收到数据还是回ACK
    4.LIS如果发送数据完了后给仪器发送EOT告诉发送完毕(一个通信过程就完毕)
    在这里插入图片描述

    HL7简单交互(SB开始、CR分次,EB结束)
    HL7定义了消息交互结构,为:[SB]data[CR]data[CR][EB][CR]
    SB:消息开始控制字符
    EB:消息结束控制字符
    CR:消息换行控制字符

    仪器给LIS发数据
    1.先发SB给LIS告诉我要给你发数据
    2.LIS收到SB后准备接收发来的数据
    3.仪器接着发送要传输的数据(HL7格式的串,多个用CR分开发送)
    4.仪器发送完数据后发送EB、CR告诉LIS发送数据完毕
    在这里插入图片描述

    LIS给仪器发数据
    1.先发SB给仪器告诉我要给你发数据
    2.仪器收到SB后准备接收发来的数据
    3.LIS接着发送要传输的数据(HL7格式的串,多个用CR分开发送)
    4.LIS发送完数据后发送EB、CR告诉仪器发送数据完毕
    在这里插入图片描述

    以上说的ENQ,EOT,STX,ACK,SB,EB,CR都是ascii不可见字符,用不可见字符控制交互
    //控制字符
    stx=c(2),etx=c(2),etx=c(3),ack=c(6),enq=c(6),enq=c(5),eot=c(4)lf=c(4) lf=c(10),cr=c(13),nak=c(13),nak=c(21),etb=$c(23)

    附(C#模拟astm协议实现的虚拟仪器,重点就是txtLabNo_KeyDown触发的给LIS发数据和machSerialPort_DataReceived解析LIS发来的数据部分,帮助更深入了解交互)

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO.Ports;
    using System.IO;
    
    namespace LISVMachine
    {
        /// <summary>
        /// 绑定数据委托
        /// </summary>
        /// <param name="result"></param>
        delegate void BindDataDelegate(string result);
    
        public partial class FrmMian : Form
        {
            /// <summary>
            /// 通信模式,0:串口,1:文本,2:数据库
            /// </summary>
            private int Model = 0;
    
            /// <summary>
            /// ack
            /// </summary>
            private string ACK = "[6]";
    
            /// <summary>
            /// enq
            /// </summary>
            private string ENQ = "[5]";
    
            /// <summary>
            /// eot
            /// </summary>
            private string EOT = "[4]";
    
            /// <summary>
            /// stx
            /// </summary>
            private string STX = "[2]";
    
            /// <summary>
            /// etx
            /// </summary>
            private string ETX = "[3]";
    
            /// <summary>
            /// 存待发送信息
            /// </summary>
            private List<string> SendList = new List<string>();
    
            /// <summary>
            /// 存收到的字符串
            /// </summary>
            private string ReciveStr = "";
    
            /// <summary>
            /// 状态。0:正常,1:等待发送,2:等待接收
            /// </summary>
            private int State = 0;
    
            /// <summary>
            /// 连接串
            /// </summary>
            string ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=db.mdb";
    
            public FrmMian()
            {
                InitializeComponent();
            }
    
            private void FrmMian_Load(object sender, EventArgs e)
            {
                ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Application.StartupPath + "\\db.mdb";
                //初始化下拉串口名称列表框
                string[] ports = SerialPort.GetPortNames();
                Array.Sort(ports);
                cmbPortName.Items.AddRange(ports);
                cmbPortName.SelectedIndex = cmbPortName.Items.Count > 0 ? 0 : -1;
                RefreshGrid("1");
            }
    
            /// <summary>
            /// 通信方式切换
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void cmbPortName_SelectedIndexChanged(object sender, EventArgs e)
            {
                ChangeModel();
            }
    
            /// <summary>
            /// 切换通信方式
            /// </summary>
            private void ChangeModel()
            {
                try
                {
                    if (machSerialPort.IsOpen)
                    {
                        WriteLog("关闭已打开串口");
                        machSerialPort.Close();
                    }
                    machSerialPort.PortName = cmbPortName.Text;
                    WriteLog("尝试启动串口:" + machSerialPort.PortName);
                    machSerialPort.Open();
                    WriteLog("启动串口:" + machSerialPort.PortName + "成功");
                    WriteLog("串口通信模式");
                    labInfo.Text = "波特率9600,数据位8,停止位1,校验位None。文本上传在Order文件夹下,结果数据在Result文件夹下,图片在Image文件夹下。数据库双向直接操作MachResult表上传和取结果";
    
                }
                catch (Exception ex)
                {
                    WriteLog("启动串口异常:" + ex.Message);
                    //现实异常信息给客户。                    
                    MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK);
                }
            }
    
    
            /// <summary>
            /// 扫描
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void txtLabNo_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.KeyCode == Keys.Enter)
                {
                    if (txtLabNo.Text != "")
                    {
                        //等待发送数据
                        State = 1;
                        SendList.Add("GetPatInfo|" + txtLabNo.Text + "|LISVMachine1.0|||||||||");
                        Send(ENQ);
                        txtLabNo.Text = "";
                    }
                }
            }
    
            /// <summary>
            /// 发送
            /// </summary>
            /// <param name="sendStr"></param>
            private void Send(string sendStr)
            {
                //串口打开的话就转给串口
                if (machSerialPort.IsOpen)
                {
                    //处理为不可见字符
                    sendStr = DealNotSeeChar(sendStr);
                    byte[] byteArray = System.Text.Encoding.Default.GetBytes(sendStr);
                    //转发给串口
                    machSerialPort.Write(byteArray, 0, byteArray.Count());
                    WriteLog("发送给LIS:" + DealNotSeeToSeeCharLIS(sendStr));
                }
                else
                {
                    WriteLog("发送给LIS:串口未打开,无法发送");
                }
            }
    
    
    
            /// <summary>
            /// 串口收到数据
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void machSerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
            {
                int n = machSerialPort.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
                byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
                machSerialPort.Read(buf, 0, n);//读取缓冲数据
                string lineStr = System.Text.Encoding.Default.GetString(buf);
                string lineOld = lineStr;
                lineStr = DealNotSeeToSeeChar(lineStr);
                WriteLog("LIS给仪器:" + DealNotSeeToSeeCharLIS(lineOld));
                if (lineStr == ACK && State == 1)
                {
                    if (SendList.Count > 0)
                    {
                        string sendStr = SendList[0];
                        SendList.RemoveAt(0);
                        Send(STX);
                        Send(sendStr);
                    }
                    else
                    {
                        Send(EOT);
                        State = 0;
                    }
                }
                if (lineStr == ENQ)
                {
                    //等待接收数据
                    State = 2;
                    Send(ACK);
                    ReciveStr = "";
                }
                if (lineStr == EOT)
                {
                    //正常状态
                    State = 0;
                    //存数据
                    WriteLog("接收数据完毕,仪器分析中");
                    //要求格式:PatInfo|条码号|LISVMachine1.0|患者姓名|性别|年龄|科室|病区|诊断|采集日期|传输日期|通道^通道^通道
                    if (ReciveStr != "")
                    {
                        List<string> resListRet = DealPatInfo(ReciveStr);
                        if (resListRet != null && resListRet.Count > 0)
                        {
                            SendList.AddRange(resListRet);
                            WriteLog("仪器出结果");
                            Send(ENQ);
                            //待发送数据状态
                            State = 1;
                        }
                    }
                }
                //接收数据
                if (State == 2 && lineStr != ENQ && lineStr != EOT && lineStr != STX)
                {
                    ReciveStr += lineStr.Replace(STX, "");
                    Send(ACK);
                }
            }
    
    
    
            /// <summary>
            /// 写日志
            /// </summary>
            /// <param name="log"></param>
            private void WriteLog(string log)
            {
                //组装参数
                object[] paras = new object[] { log };
                this.Invoke(new BindDataDelegate(BindData), paras);
            }
    
            /// <summary>
            /// 绑定监听数据
            /// </summary>
            private void BindData(string log)
            {
                txtLog.Text += DateTime.Now.ToString("hh:mm:ss: ") + log + "\n";
            }
    
            /// <summary>
            /// 刷新表格数据
            /// </summary>
            /// <param name="log"></param>
            private void RefreshGrid(string code)
            {
                //组装参数
                object[] paras = new object[] { code };
                this.Invoke(new BindDataDelegate(BindGridData), paras);
            }
    
            /// <summary>
            /// 绑定监听数据
            /// </summary>
            private void BindGridData(string code)
            {
                dgData.DataSource = DBHelper.QryData(ConnectionString, "select * from MachResult");
            }
    
            /// <summary>
            /// 处理为不可见字符
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            private string DealNotSeeChar(string s)
            {
                for (int i = 0; i <= 31; i++)
                {
                    s = s.Replace("[" + i + "]", (char)i + "");
                }
                s = s.Replace("[127]", (char)127 + "");
                return s;
            }
    
            /// <summary>
            /// 处理不可见字符
            /// </summary>
            /// <param name="data">数据</param>
            /// <returns>返回</returns>
            public string DealNotSeeToSeeChar(string data)
            {
                for (int i = 0; i <= 31; i++)
                {
                    data = data.Replace((char)i + "", "[" + i + "]");
                }
                data.Replace((char)127 + "", "[127]");
                return data;
            }
    
    
            /// <summary>
            /// 处理不可见字符
            /// </summary>
            /// <param name="data">数据</param>
            /// <returns>返回</returns>
            public string DealNotSeeToSeeCharLIS(string data)
            {
                for (int i = 0; i <= 31; i++)
                {
                    if (i == 6)
                    {
                        data = data.Replace((char)i + "", "[ACK]");
                    }
                    else if (i == 5)
                    {
                        data = data.Replace((char)i + "", "[ENQ]");
                    }
                    else if (i == 4)
                    {
                        data = data.Replace((char)i + "", "[EOT]");
                    }
                    else if (i == 3)
                    {
                        data = data.Replace((char)i + "", "[ETX]");
                    }
                    else if (i == 4)
                    {
                        data = data.Replace((char)i + "", "[STX]");
                    }
                    else
                    {
                        data = data.Replace((char)i + "", "[" + i + "]");
                    }
                }
                data.Replace((char)127 + "", "[127]");
                return data;
            }
    
            /// <summary>
            /// 定时器,定时检测上传数据和出结果
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void timerMian_Tick(object sender, EventArgs e)
            {
                string orderPath = Application.StartupPath + "\\Order";
                DirectoryInfo di = new DirectoryInfo(orderPath);
                FileInfo[] orders = di.GetFiles("*.imedicallis");
                WriteLog("检测Order下是否有*.imedicallis的上传文件");
                if (orders != null && orders.Length > 0)
                {
                    foreach (FileInfo f in orders)
                    {
                        string orderStr = TxtUtil.ReadTxt(f.FullName);
                        WriteLog("解析:" + f.FullName);
                        DealPatInfo(orderStr);
                        File.Delete(f.FullName);
                    }
                }
                WriteLog("查询数据库SendFlag为空的上传记录");
                DataTable dt = DBHelper.QryData(ConnectionString, "select * from MachResult where SendFlag is null");
                if (dt.Rows.Count > 0)
                {
                    foreach (DataRow r in dt.Rows)
                    {
                        List<string> randomRes = new List<string>();
                        for (int i = 0; i < 20; i++)
                        {
                            Random rand = new Random(DateTime.Now.Millisecond);
                            randomRes.Add((rand.NextDouble() * 100).ToString());
                        }
                        string UPChl = r["UPChl"].ToString();
                        string updateSq = "update MachResult set SendFlag='" + DateTime.Now.ToString("yyyyMMddhhmmss") + "'";
                        for (int i = 0; i < 20; i++)
                        {
                            if ((UPChl != "") && (!UPChl.Contains("Chl" + (i + 1))))
                            {
                                continue;
                            }
                            updateSq += ",Chl" + (i + 1) + "='" + randomRes[i] + "'";
                        }
                        updateSq += " where RowID=" + r["RowID"].ToString();
                        try
                        {
                            int ret = DBHelper.ExeSql(ConnectionString, updateSq);
                            if (ret == 1)
                            {
                                WriteLog("更新" + r["EpisNo"].ToString() + "数据库结果");
                            }
                        }
                        catch (Exception ex)
                        {
                            WriteLog("仪器数据库结果插入异常" + ex.Message);
                        }
                    }
                }
            }
    
            /// <summary>
            /// 处理患者信息出结果
            /// </summary>
            /// <param name="oderStr"></param>
            /// <returns></returns>
            private List<string> DealPatInfo(string oderStr)
            {
                List<string> retList = new List<string>();
                if (oderStr != "")
                {
                    string[] patInfoArr = oderStr.Split('|');
                    if (patInfoArr.Length >= 12)
                    {
                        if (patInfoArr[0] == "PatInfo")
                        {
                            string EpisNo = patInfoArr[1];
                            string PatName = patInfoArr[3];
                            string Sex = patInfoArr[4];
                            string PatAge = patInfoArr[5];
                            string Location = patInfoArr[6];
                            string Ward = patInfoArr[7];
                            string Diagnose = patInfoArr[8];
                            string CollDate = patInfoArr[9];
                            if (CollDate == "")
                            {
                                CollDate = DateTime.Now.ToString("yyyyMMdd");
                            }
                            string TransDate = patInfoArr[10];
                            if (TransDate == "")
                            {
                                TransDate = DateTime.Now.ToString("yyyyMMdd");
                            }
                            string Chl = patInfoArr[11];
                            if (EpisNo != "" && PatName != "")
                            {
                                List<string> randomRes = new List<string>();
                                for (int i = 0; i < 20; i++)
                                {
                                    Random rand = new Random(DateTime.Now.Millisecond);
                                    randomRes.Add((rand.NextDouble() * 100).ToString());
                                }
                                string sql = "insert into MachResult(EpisNo,PatName,PatAge,Sex,Location,Ward,Diagnose,CollDate,TransDate,UPChl,Chl1,Chl2,Chl3,Chl4,Chl5,Chl6,Chl7,Chl8,Chl9,Chl10,Chl11,Chl12,Chl13,Chl14,Chl15,Chl16,Chl17,Chl18,Chl19,Chl20,Img1,Img2,SendFlag) values('" + EpisNo + "','" + PatName + "','" + PatAge + "','" + Sex + "','" + Location + "','" + Ward + "','" + Diagnose + "','" + CollDate + "','" + TransDate + "','" + Chl + "','" + randomRes[0] + "','" + randomRes[1] + "','" + randomRes[2] + "','" + randomRes[3] + "','" + randomRes[4] + "','" + randomRes[5] + "','" + randomRes[6] + "','" + randomRes[7] + "','" + randomRes[8] + "','" + randomRes[9] + "','" + randomRes[10] + "','" + randomRes[11] + "','" + randomRes[12] + "','" + randomRes[13] + "','" + randomRes[14] + "','" + randomRes[15] + "','" + randomRes[16] + "','" + randomRes[17] + "','" + randomRes[18] + "','" + randomRes[19] + "','" + "Image\\Img1.bmp" + "','" + "Image\\Img2.bmp" + "','" + DateTime.Now.ToString("yyyyMMddhhmmss") + "')";
                                try
                                {
                                    int ret = DBHelper.ExeSql(ConnectionString, sql);
                                    RefreshGrid("1");
                                    string[] ChlArr = Chl.Split('^');
                                    for (int j = 0; j < ChlArr.Length; j++)
                                    {
                                        string chlOne = ChlArr[j];
                                        if (chlOne == "Chl1")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[0] + (char)13);
                                        }
                                        else if (chlOne == "Chl2")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[1] + (char)13);
                                        }
                                        else if (chlOne == "Chl3")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[2] + (char)13);
                                        }
                                        else if (chlOne == "Chl4")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[3] + (char)13);
                                        }
                                        else if (chlOne == "Chl5")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[4] + (char)13);
                                        }
                                        else if (chlOne == "Chl6")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[5] + (char)13);
                                        }
                                        else if (chlOne == "Chl7")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[6] + (char)13);
                                        }
                                        else if (chlOne == "Chl8")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[7] + (char)13);
                                        }
                                        else if (chlOne == "Chl9")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[8] + (char)13);
                                        }
                                        else if (chlOne == "Chl10")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[9] + (char)13);
                                        }
                                        else if (chlOne == "Chl11")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[10] + (char)13);
                                        }
                                        else if (chlOne == "Chl12")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[11] + (char)13);
                                        }
                                        else if (chlOne == "Chl13")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[12] + (char)13);
                                        }
                                        else if (chlOne == "Chl14")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[13] + (char)13);
                                        }
                                        else if (chlOne == "Chl15")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[14] + (char)13);
                                        }
                                        else if (chlOne == "Chl16")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[15] + (char)13);
                                        }
                                        else if (chlOne == "Chl17")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[16] + (char)13);
                                        }
                                        else if (chlOne == "Chl18")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[17] + (char)13);
                                        }
                                        else if (chlOne == "Chl19")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[18] + (char)13);
                                        }
                                        else if (chlOne == "Chl20")
                                        {
                                            retList.Add("Result|" + EpisNo + "|" + chlOne + "|" + randomRes[19] + (char)13);
                                        }
                                        else
                                        {
                                            WriteLog("非Chl1-Chl20的通道");
                                        }
                                    }
                                    retList.Add("Last|" + EpisNo + "|END|" + (char)13);
                                    StringBuilder sb = new StringBuilder();
                                    foreach (var v in retList)
                                    {
                                        sb.Append(v);
                                    }
                                    string resultPath = Application.StartupPath + "\\Result\\" + DateTime.Now.ToString("yyyyMMddhhmmss-") + EpisNo + ".lisres";
                                    TxtUtil.WriteTxt(resultPath, sb.ToString());
                                    WriteLog("生成文件到:" + resultPath);
                                }
                                catch (Exception ex)
                                {
                                    WriteLog("患者信息入库失败:" + ex.Message);
                                }
                            }
                            else
                            {
                                WriteLog("流水号和患者姓名不能为空");
                            }
                        }
                        else
                        {
                            WriteLog("患者信息没有PatInfo头,例如:PatInfo|条码号|LISVMachine1.0|患者姓名|性别|年龄|科室|病区|诊断|采集日期|传输日期|通道^通道^通道");
                        }
                    }
                    else
                    {
                        WriteLog("患者信息位数不足,例如:PatInfo|条码号|LISVMachine1.0|患者姓名|性别|年龄|科室|病区|诊断|采集日期|传输日期|通道^通道^通道");
                    }
                }
                return retList;
            }
    
            /// <summary>
            /// 重传
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnToLis_Click(object sender, EventArgs e)
            {
                for (int i = 0; i < dgData.Rows.Count; i++)
                {
                    if ((bool)dgData.Rows[i].Cells["Check"].EditedFormattedValue == true)
                    {
                        if (dgData.Rows[i].Cells["RowID"] == null)
                        {
                            continue;
                        }
                        string RowID = dgData.Rows[i].Cells["RowID"].Value.ToString();
                        DataTable dt = DBHelper.QryData(ConnectionString, "select * from MachResult where RowID=" + RowID);
                        if (dt.Rows.Count >= 0)
                        {
                            StringBuilder sb = new StringBuilder();
                            foreach (DataRow r in dt.Rows)
                            {
                                string EpisNo = r["EpisNo"].ToString();
                                for (int j = 0; j < 20; j++)
                                {
                                    string chl = "Chl" + (j + 1);
                                    string res = r[chl].ToString();
                                    if (res != "")
                                    {
                                        sb.Append("Result|" + EpisNo + "|" + chl + "|" + res + (char)13);
                                    }
                                }
                                sb.Append("Last|" + EpisNo + "|END|" + (char)13);
                                string resultPath = Application.StartupPath + "\\Result\\" + DateTime.Now.ToString("yyyyMMddhhmmss-") + EpisNo + ".lisres";
                                TxtUtil.WriteTxt(resultPath, sb.ToString());
                                WriteLog("生成文件到:" + resultPath);
                                DBHelper.ExeSql(ConnectionString, "update MachResult set SendFlag='" + DateTime.Now.ToString("yyyyMMddhhmmss") + "' where RowID=" + r["RowID"].ToString());
                                WriteLog("更新" + r["RowID"].ToString() + "的SendFlag为当前时间");
                            }
                        }
                    }
                }
                MessageBox.Show("重传成功!", "提示", MessageBoxButtons.OK);
            }
    
            /// <summary>
            /// 查询
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btnSelect_Click(object sender, EventArgs e)
            {
                string dateStr=dtDate.Value.ToString("yyyyMMdd");
                dgData.DataSource = DBHelper.QryData(ConnectionString, "select * from MachResult where CollDate='" + dateStr+"'");
            }
    
            /// <summary>
            /// 查全部
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void button1_Click(object sender, EventArgs e)
            {
                string dateStr = dtDate.Value.ToString("yyyyMMdd");
                dgData.DataSource = DBHelper.QryData(ConnectionString, "select * from MachResult");
            }
        }
    }
    
    
    展开全文
  • 计算机技术在医疗仪器中的应用pla0q* 电(电压或电流),有直流和交流之分。在通信应用中,用作信号传输的一般郝是交流电。呈正弦变化的交流电信号,随着时间的变化,其幅度时正、时负,以一定的能量和速度向前传播(见图1)...
  • 虚拟仪器设计

    2021-03-06 11:33:18
    3)提高软件程序设计和代码编写能力 (4)培养按要求设计项目的学习能力 2 课程设计题目及要求 利用虚拟仪器相关技术,使用labview2016和proteus8.8制作电机运行状态监控系统,具体实现功能如下: 可利用LABVIEW...
  •  2)由试件有效部分的直径和材质,估算试件被扭断时的扭矩,然后转动量程选择旋钮,选择相应的测力刻度盘,使断裂时所需的扭矩处于量程的50%~80%的范围Q按下电源开关,接通电源,转动调零旋钮,使主动针对准零点,...
  • 什么是阻抗分析仪? 阻抗分析仪能在阻抗范围和宽频率... 异常情况下,导纳圆与电导曲线如下图: 1、基本度:0.05[%] 2、频率度:±0.005[%] 3、量测参数:Z, L, C, R, Q, D, Y, G, B, X 4、输出:10
  • 具体可参考:<德州仪器使用教程(二)>,因为设备中默认使用了2us的采样插槽和2us的切换插槽,所以一个正常的采样周期即为2 + 2 = 4us时间,而当恒定音波CTE为250Khz时,其周期也恰好为4us,这就使得天线的采样与...
  • 测绘仪器检定信息系统(SIVIS)V2.0,是严格依据国家相关测绘仪器检定/校准规范、规程的要求,并结合计量检定部门的工作实际,适合特定测绘仪器计量检定部门进行日常检定数据处理和信息管理的专门软件产品。测绘仪器...
  • 信号的滤波 滤波器是一种选频装置可以使信号中特定频率成分通过而极大地衰减其他频率成分 0 f fc1 fc2 A0 0.707A0 1)截止频率fc0.707A0所对应的频率 d 2)纹波幅度d绕幅频特性均值A0波动值 3)带宽B和品质因数Q下两截...
  •  2)由试件有效部分的直径和材质,估算试件被扭断时的最大扭矩,然后转动量程选择旋钮,选择相应的测力刻度盘,最好使断裂时所需的最大扭矩处于量程的50%~80%的范围Q按下电源开关,接通电源,转动调零旋钮,使主动...
  • 什么是? 阻抗分析仪能在阻抗范围和宽频率范围... 异常情况下,导纳圆与电导曲线如下图: 1、基本度:0.05[%] 2、频率度:±0.005[%] 3、量测参数:Z, L, C, R, Q, D, Y, G, B, X 4、输出:10mV to
  • TOF非弹性中子散射仪器可捕获许多BZ上的数据。 因此,在特定的减小的波矢处,属于重叠峰多重峰的声子峰在不同的BZ中将具有不同的强度,但是它们将具有相同的能量和固有的线宽。 为了进行拟合,我们首先从DFT计算的...
  • 拓展分析仪器产品方案,帮助中国及其他新兴市场客户获得环境及食品安全检测解决方案 利用上海光谱仪器有限公司的供应链及本地区的经销商网络,打开新的市场机会 拓展原子吸收领域的研发能力 上海--(美国商业资讯)--...
  • 855是ANSI X12国际标准报文规范下采购订单响应(Purchase Order Acknowledgment)的报文类型代码,德州仪器直供业务PO模式下报文类型还包含850(采购订单,Purchase Order)、860(采购订单变更,Purchase Order Change ...
  • 3Q18 3Q17   变化 营业收入 $ 4,261 $ 4,116 4% 营业利润 $ 1,937 $ 1,788 8% 净收入 $ ...
  • 高频Q表及其应用.pdf

    2009-08-24 20:54:35
    电阻器、电容器、电感器都是电路的基本元件。电路基本元件参数是电路测试的基本内容之一。电路参数测试仪器是基本测试仪器。由于电路元件的工作频率范围不同,...对于工作在高频电路中的元件,大多采用谐振法和Q表等。
  • 本项目为了实现对灯箱仪器的控制,自动从系统查找串口,并设置固定的通讯参数。 1、类关系 类之间的关系如下: Dialog为界面类,主要完成人机交互。LampCtrl为设备控制类,主要完成同仪器的通信。CLogManager为日志...
  • 问题:大型仪器一般都使用计算机进行控制,对该计算机除了在性能上能满足要求,在使用方面原则上有何要求。更多相关问题已知intx=43,y=0;charch='A';则表达式(x>y&&ch下面程序的功能是 : 计算 1 ~10 之间...
  • GB/T 30096-2013 实验室仪器和设备常用文字符号ICS01.080.20N61中华人 民共和 国国家标准/ —GBT30096 2013实实验室仪器和设备常用文字符号Maorlettersmbolsforlaboratorinstrumentandeuimentj y y q p2013-...
  • 仪器仪表在设计中少不了用户界面的设计,菜单界面作为人机交互的重要方式,在设计中也需要慎重考虑。下面以实际设计为例,介绍几种设计多功能菜单的设计模式。背景: 电力监控仪器是常见的工控设备,常见用于家庭...
  • 计算机电路基础实验报告班级__________姓名___________学号___________________实验一 戴维南定理的实验一、预习要求复习戴维南定理的内容,实验前将步骤...、实验设备稳压电源一台;万用表两块;戴维南实验电路板...
  • 文章目录瞬变电磁法一、方法原理二、操作步骤1、仪器简介2、接线打开仪器连接蓝牙打开采集软件设置通讯端口3、设置参数3.1参数设置3.2发射频率4、数据采样5、数据导出5、问题解决、数据处理 一、方法原理 二、操作...
  • 迅为 i.MX6Q 开发析平台基于 NXP 公司的 i.MX6Q 四核处理器设计,Cortex-A9 架构,兼容 单核、双核、工业级、汽车级、i.mx6Q PLUS 版本;采用核心板+底板结构,板对板连接器方 式,拆装方便,扩展性好。 ARM Cortex...
  • 3、电流的形成:电荷的定向移动形成电流.(任何电荷的定向移动都会形成电流)4、电流的方向:从电源正极流向负极.5、电源:能提供持续电流(或电压)的装置.6、电源是把其他形式的能转化为电能.如干电池是把化学能转化为...
  • 章 手持机外观界面说明 6 3.1 手持机外观说明 6 3.2 手持机按键说明 7 3.3 桌面界面 7 第四章 Hi-Q GIS采集软件 8 4.1 Hi-Q GIS主界面 8 4.2 关于 8 4.2.1 软件版权 8 4.2.2 手持机信息 9 4.2.3 手持机注册 9 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,556
精华内容 1,822
关键字:

仪器3q