EPICS StreamDevice模块--1

一、介绍

1、StreamDevice是什么?

StreamDevice是一个用于使用基于"字节流"通信接口的设备的通用EPICS设备支持。这意味着能够通过发送和接收字符串(在最广泛意义上,包含不可打印字符甚至null字节)控制的设备。此类通信接口的示例是串行(RS-232, RS-485,...),IEEE-488(也称为GPIB或HP-IB),以及类似telnet的TCP/IP。

StreamDevice不被限制于一种特定设备类型或者厂家,也不需要重新编译任何东西来支持一种新设备类型。用协议文件为任何设备类型配置它,此协议文件使用一个纯ASCII文本,其描述一个设备能够理解的命令以及它发送的响应。如果能够用像"RF:FREQ 499.655 MHZ"的字符串控制这个设备,StreamDevice能够被使用。用类似于C函数printf()和scanf()那些格式转换器,用格式转换器进行格式化以及值的解析。要支持其它格式,编写你自己的转换器是可能的。

具有StreamDevice支持的每个记录运行来自协议文件的一个协议来读取或写它的值。协议可以就像一个输出字符串一样简单或者由被发送给或者从设备读取的很多字符串组成。但,一个协议是线性的。这意味着在每次运行这个记录时它从头运行到尾。它不提供循环或者分支。

StreamDevice作为asynDriver的一个接口出现,但可以被扩展成支持其它总线驱动。注意:StreamDevice不是asynDriver的备选或替代,而是对asynDriver的补充。StreamDevice转换记录值尾字符串以及从字符串转成记录值,但把它留给asynDriver(或其它总线接口)来与设备交换这些字符串。因而,由asynDriver(确切由asynOctet)支持的任何总线类型可以自动地与StreamDevice一起使用。

StreamDevice支持EPICS base可以有设备支持的所有标准记录。编写支持新记录类型的支持也是可能的。

2、StreamDevice不是什么?

它不是对应高级应用程序的编程语言。例如,在一个协议钟编写完整的扫描程序是不可能的。为此使用其它工具,并且StreamDevice仅用于基本命令。

它不是一个面向阻塞的设备支持。它不是用于大量二进制数据块,这些数据库包含了分布于很多记录的很多过程变量。为此考虑regDev。

它不是一个非常灵活的html,xml,jsom等解析器。数据要被StreamDevice解析,它需要以一个可预测顺序出现。

二、设置

1、预备条件

在从R3.14.6以上到R7.0.3的EPICS base版本上测试了StreamDevice的运行。在继续前首先下载并且构建你选择的EPICS版本。

在Windows上需要对base R3.14.2以及更早版本修补

直到发行版R3.14.2,在Windows上(非cygwin)构建StreamDevice需要对EPICS base一个修复。添加以下一行到src/iocsh/iocsh.h并且构建base。

epicsShareFunc int epicsShareAPI iocshCmd(const char *command);

下载StreamDevice

StreamDevice的最新版可以在github上找到:GitHub - paulscherrerinstitute/StreamDevice: EPICS Driver for message based I/O。或者下载一个zip文件或者克隆git repot:

git clone https://github.com/paulscherrerinstitute/StreamDevice.git

配置

StreamDevice现在带一个标准configure目录出现。由于与synApps兼容性问题,不再支持上一层../configure。

编辑configure/RELEASE文件来指定EPICS base以及其它软件模块的安装位置,或者添加一个configure/RELEASE.local文件去重写,例如:

EPICS_BASE=/home/epics/base-3.16.1

对asynDriver的支持

你可能最想要包含asynDriver的支持,因为那是StreamDevice与硬件交互的标准方式。在你构建SteamDevice前,首先获取和安装asynDriver版本4-3或者更高。我已经用最高到4-30版本的asynDriver测试了StreamDevice。通过添加指向你安装asyn的<top>目录到configure/RELEASE文件可以确保aysn库能够被找到:

ASYN=/home/epics/asyn4-30

对sCalcout记录的支持

sCalcout记录是synApps的组成部分。如果用对这个记录的支持构建StreamDevice,你必须至少先安装来自synApps的calc模块。按如下所示添加引用到RELEASE:

CALC=/home/epics/synApps/calc-R3-6-1

直到calc发行R2-6(synApps发行R5_1),sCalcout记录需要一个修补。并且calc模块依赖其它synApps模块。推荐发行R2-8或者更新的。

对sCalcout的支持是可选的。StreamDevice没有sCalcout或synApps一样运行。

对正则表达式匹配的支持

如果你想要启用正则表达式匹配,你需要PCRE包。对于大部分Linux系统,已经安装了它。在这种情况中,告诉StreamDevice PCRE头文件和库文件的位置。但预安装的包只能用于主机架构。因而,不是添加它们到RELEASE,而是到RELEASE.Common.linux-x86(如果linux-x86是你的EPICS_HOST_ARCH)。注意:不同的Linux发行版在不同位置放置这些文件。

PCRE_INCLUDE=/usr/include/pcre
PCRE_LIB=/usr/lib

对于64位安装,到这个库文件的路径会不同:

PCRE_INCLUDE=/usr/include/pcre
PCRE_LIB=/usr/lib64

Download GnuWin from SourceForge.net位置可以获取一个预编译的Windows版本PCRE。如果你想要在不本地支持PCRE的平台上有PCRE支持,例如vxWorks,以EPICS模块构建PCRE可能是最简单的方法。

以一个EPICS模块构建这个PCRE包

  • https://www.pcre.org/下载PCRE包
  • 在StreamDevice顶层目录中提取PCRE包或者使用makeBaseApp.pl创建一个单独的<top>位置。
  • 下载Makefile和fixforvxworks.pl脚本并且保存它们到提取的pcre目录。
  • 切换到pcre目录并且运行perl fixforvxworks.pl
  • 运行make(gmake)

在对应StreamDevice的RELEASE文件中定义pcre <top>位置。

PCRE=/home/epics/pcre

正则表达式是可选的。如果你不想要它们,你不需要这个。

2、构建StreamDevice

进入StreamDevice目录并且运行make(或gmake)。这将创建和安装stream库文件和stream.dbd文件以及一个示例IOC应用程序。要使用StreamDevice,必须用stream和asyn(和可选的pcre)库文件构建你自己的应用程序并且必须装载asyn.dbd和stream.dbd。

PROD_LIBS += stream
PROD_LIBS += asyn
PROD_LIBS += pcre

在你的xxxAppInclude.dbd文件中包含以下行来以串行,IP套接字和vxi11(“GPIB over ethernet”)支持使用stream和asyn。

include "base.dbd"
include "stream.dbd"
include "asyn.dbd"
registrar(drvAsynIPPortRegisterCommands)
registrar(drvAsynSerialPortRegisterCommands)
registrar(vxi11RegisterCommands)

你可以在streamApp子目录中找到一个示例应用程序。

3、启动脚本

StreamDevice是基于协议文件的。要告诉StreamDevice到哪里搜索协议文件,设置环境变量STREAM_PROTOCOL_PATH为要搜索的目录列表。在Unix和vxWorks上系统上,目录由:分隔,在windows系统上由;分隔。默认值是STREAM_PROTOCOL_PATH=.,即是:当前目录。也配置你想要使用StreamDevice的总线(用asynDriver术语:ports)。你可以赋给总线你想要的任何名字,如COM1或socket,但我推荐使用预连接设备相关联的名称。

示例:

一个带串行通信(9600 baud, 8N1,不流控)的设备连接到/dev/ttyS1。这个设备的名称应该是PS1。协议文件或在当前工作目录或者在../protocols目录。

接着启动脚本可能看起来像这样:

epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")

drvAsynSerialPortConfigure ("PS1","/dev/ttyS1")
asynSetOption ("PS1", 0, "baud", "9600")
asynSetOption ("PS1", 0, "bits", "8")
asynSetOption ("PS1", 0, "parity", "none")
asynSetOption ("PS1", 0, "stop", "1")
asynSetOption ("PS1", 0, "clocal", "Y")
asynSetOption ("PS1", 0, "crtscts", "N")

以上选项都是默认的。因而在这里,它们的使用可选。

如果设备使用硬件流控,更改最后两行为:

asynSetOption ("PS1", 0, "clocal", "N")
asynSetOption ("PS1", 0, "crtscts", "Y")

更新版本的asyn也支持软件流控(CTRL-S, CTRL-Q)。如果设备使用这个,你可能想要设置:

asynSetOption ("PS1", 0, "ixon", "Y")
asynSetOption ("PS1", 0, "ixany", "Y")

如果设备连接了在地址192.168.164.10端口23上telnet风格的TCP/IP,启动脚本包含:

epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
drvAsynIPPortConfigure ("PS1", "192.168.164.10:23")

用VXI11(经常TCP/IP的GPIB)连接,例如,在IP地址192.168.164.10上HP E2050A,它看起来像这样:

epicsEnvSet ("STREAM_PROTOCOL_PATH", ".:../protocols")
vxi11Configure ("PS1","192.168.164.10",1,1000,"hpib")

4、协议文件

对于每种不同硬件类型,创建一个协议文件,其为所有所需设备功能定义协议。文件名是任意的,但我推荐它包含设备类型。它一定不能包含空白并且应该简单。在iocInit过程中,streamDevice装载并且解析所需的协议文件。如果这些文件包含错误,它们被打印到IOC shell。把这个协议文件放置在STREAM_PROTOCOL_PATH中列出的其中一个目录中。

示例:

PS1是一个ExamplePS电源。它通过ASCII字符串通信,这些字符串由<回车><换行>(ASCII代码13,10)结束。通过发送像"CURRENT 5.13"的字符串能够设置输出电流。当用字符串"CURRENT?"询问时,设备用"CURRENT 5.13 A"的字符串返回上次设置的值。通常,一个模拟输出记录应该写它的值到设备。但在启动过程中,应该从设备初始化记录。协议文件ExamplePS.proto定义协议getCurrent和setCurrent。

Terminator = CR LF;

getCurent {
        out "CURRENT?";
        in "CURRENT %f A";
    }

setCurrent {
    out "CURRENT %.2f";
    @init {
        getCurent;
    }
}

装载协议文件

 在开发过程中,协议文件可能经常变化。要放置总是重启IOC,用shell函数streamReload("record")重启装载一个或多个记录是可能的。如果没有给出"record"或控,所有记录使用StreamDevice重新装载它们的协议。在EPICS 3.14或更高中,recrord可以是一个glob模式。

再者,streamReloadSub函数可以预一个subroutine记录一起使用来重新装载所有协议。

重新装载协议文件取消当前正在运行的协议。这会设置SEVR=INVALID和STAT=UDF。如果一个记录不能重新装载它的协议文件(例如,由于一个语法错误),在装载一个有效协议前它保持INVALID/UDF。

重新触发一个@init handler。深入见下一章协议文件。

5、调试和错误消息

用两个shell变量控制调试和错误信息的产生,streamDebug和streamError。设置这些变量为1(实际除0外的任何数值)启用这些消息。每条默认调试消息被关闭以及错误消息被打开。在装载协议文件时发生的错误总是被显示。

警告:启用调试消息会创建大量输出!到目前,没有对调试或错误消息设置过滤器的方法。

可以用命令streamSetLogfile("filename")重新定向调试输出到一个文件。当不带文件名被调用时,调试输出被定向回console。

默认,如果终端允许它上色,调试/错误输出被设置成着色,但通过设置streamDebugColored各自为1或0,这可以被设置成总是被上色或者不被上色。

除非变量streamMsgTimeStamped被设置为0,否则错误和调试消息带一个时间戳前缀。

当一个设备被连接时,StreamDevice可以产生很多重复的超时消息。要减少这种日志,你可以设置streamErrorDeadTime为一个整数数值秒数。当这被设置时,在上条消息后,在指定的死时间内,将不打印重复的超时消息。默认的死时间是0,导致每条消息被打印。

示例(vxWorks)

streamError=1
streamDebug=1
streamDebugColored=1
streamErrorDeadTime=30
streamMsgTimeStamped=1
streamSetLogfile("logfile.txt")

示例(iocsh)

var streamError 1
var streamDebug 1
var streamDebugColored 1
var streamErrorDeadTime 30
var streamMsgTimeStamped 1
streamSetLogfile("logfile.txt")

6、配置这些记录

要告诉一个记录使用StreamDevice,设置DTYP字段为"stream"。

INP或OUT链接有格式"@filename protocol[(arg1,arg2,...)] bus [address [parameters]]"。

(在[]中的元素是可选的。不要输入[])。

在这里,filename是协议文件名称而protocol是在这个文件中定义的一个协议的名称。

如果协议需要参数,在封闭小括号中指定它们:protocol(arg1, arg2, ...)。在参数列表中现在允许空格。忽略前面第一个空格以及在参数后第一个空格。还有的空格被认为参数的组成部分。

用bus(即:asynDriver "port")和addr指定通信通道。如果总线没有地址,addr可被忽略。可选的parameters被传递给总线驱动程序。(到目前,没有总线支持参数)。

示例:

创建一个要读取的输入记录和一个输出记录来设置PS1的电流。使用来自文件ExamplePS.proto的协议getCurrent和setCurrent。被称为PS1的总线像设备。

record (ai, "PS1:I-get")
{
    field (DESC, "Read current of PS1")
    field (DTYP, "stream")
    field (INP,  "@ExamplePS.proto getCurrent PS1")
    field (EGU,  "A")
    field (PREC, "2")
    field (LOPR, "0")
    field (HOPR, "60")
    field (PINI, "YES")
    field (SCAN, "10 second")
}
record (ao, "PS1:I-set")
{
    field (DESC, "Set current of PS1")
    field (DTYP, "stream")
    field (OUT,  "@ExamplePS.proto setCurrent PS1")
    field (EGU,  "A")
    field (PREC, "2")
    field (DRVL, "0")
    field (DRVH, "60")
    field (LOPR, "0")
    field (HOPR, "60")
}
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是使用 Qt 实现视频流播放的示例代码: 首先,在 Qt 中使用视频播放需要用到 QtMultimedia 模块,需要在项目文件中添加 `QT += multimedia`。 然后,创建一个 `QMediaPlayer` 对象和一个 `QVideoWidget` 对象,用于播放视频和显示视频画面: ```cpp QMediaPlayer *player = new QMediaPlayer(this); QVideoWidget *videoWidget = new QVideoWidget(this); player->setVideoOutput(videoWidget); ``` 接着,加载视频文件或者从网络中获取视频流: ```cpp QUrl videoUrl("http://example.com/video.mp4"); player->setMedia(videoUrl); ``` 如果要从网络中获取视频流,则需要使用 `QNetworkAccessManager` 和 `QNetworkReply`: ```cpp QNetworkAccessManager *networkManager = new QNetworkAccessManager(this); QUrl videoStreamUrl("http://example.com/video_stream"); QNetworkReply *reply = networkManager->get(QNetworkRequest(videoStreamUrl)); QIODevice *streamDevice = reply->readAll(); player->setMedia(QMediaContent(), streamDevice); ``` 最后,开始播放视频: ```cpp player->play(); videoWidget->show(); ``` 完整的视频播放代码如下: ```cpp #include <QtWidgets> #include <QtMultimedia> class VideoPlayerWidget : public QWidget { public: VideoPlayerWidget(QWidget *parent = nullptr) : QWidget(parent) { QMediaPlayer *player = new QMediaPlayer(this); QVideoWidget *videoWidget = new QVideoWidget(this); player->setVideoOutput(videoWidget); QUrl videoUrl("http://example.com/video.mp4"); player->setMedia(videoUrl); player->play(); videoWidget->show(); } }; int main(int argc, char *argv[]) { QApplication app(argc, argv); VideoPlayerWidget widget; widget.show(); return app.exec(); } ``` 请注意,此示例代码仅用于演示如何在 Qt 中实现视频流播放,具体实现方式可以根据实际需求进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值