asyn queueRequest使用实例
使用queueRequest读写端口驱动的示例,驱动驱动程序使用一个基于asyn实现了asynCommon和asynOctet的驱动程序-CSDN博客中编写的驱动程序,本程序的C代码如下:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>#include <cantProceed.h>
#include <epicsMutex.h>
#include <epicsEvent.h>
#include <epicsStdio.h>
#include <epicsAssert.h>
#include <asynDriver.h>
#include <asynOctet.h>
#include <iocsh.h>
#include <registryFunction.h>
#include <epicsExport.h>#define BUFFSIZE 80
/* 定义一个结构体:事件ID在驱动程序可以阻塞时,才有作用,一个asynOcte接口,驱动专用数据以及数据缓存*/
typedef struct MyData{epicsEventId done;asynOctet *pasynOctet;void *drvPvt;char buffer[BUFFSIZE];int id;
}MyData;static void timeoutCallback(asynUser *pasynUser){printf("in timeoutCallback\n");
}/* queueRequest的回调函数,原型:typedef void (*userCallback)(asynUser *pasynUser); */
static void queueCallback(asynUser *pasynUser)
{MyData *pmydata = pasynUser->userPvt; //用户数据区asynOctet *pasynOctet = pmydata->pasynOctet; //asynOcte接口void *pdrvPvt = pmydata->drvPvt; //驱动程序专用asynStatus status;size_t writeBytes, readBytes;int eomReason;asynPrint(pasynUser, ASYN_TRACE_FLOW, "queueCallback entered for Data ID: %d\n", pmydata->id);//将用户传入的数据写入设备printf("Start to Write '%s' to device\n", pmydata->buffer);/*原型:asynStatus (*write)(void *drvPvt,asynUser *pasynUser,const char *data,size_t numchars,size_t *nbytesTransfered);*/status = pasynOctet->write(pdrvPvt, pasynUser, pmydata->buffer, strlen(pmydata->buffer), &writeBytes);if (status != asynSuccess){asynPrint(pasynUser, ASYN_TRACE_ERROR, "queueCallback write failed:%s\n" ,pasynUser->errorMessage);}else{asynPrintIO(pasynUser, ASYN_TRACEIO_DEVICE, pmydata->buffer, strlen(pmydata->buffer),"queueCallback write sent %lu bytes\n", (unsigned long)writeBytes);printf("finished writing!\n");}// 清空用户缓存中的数据,为了验证回读的数据memset(pmydata->buffer, 0, BUFFSIZE);// 从设备读取数据到用户传入的缓存// asynStatus (*read)(void *drvPvt,asynUser *pasynUser,// char *data,size_t maxchars,size_t *nbytesTransfered,// int *eomReason);printf("Start to read from device\n");status = pasynOctet->read(pdrvPvt, pasynUser, pmydata->buffer, BUFFSIZE, &readBytes, &eomReason);if (status != asynSuccess){asynPrint(pasynUser, ASYN_TRACE_ERROR, "queueCallback read failed %s\n", pasynUser->errorMessage);}else{asynPrintIO(pasynUser, ASYN_TRACEIO_DEVICE, pmydata->buffer, BUFFSIZE, "queueCallback read returned: retlen %lu eomReason 0x%x data %s\n",(unsigned long)readBytes, eomReason, pmydata->buffer);printf("Finished reading,content: '%s'\n", pmydata->buffer);}// 如果驱动程序可阻塞,需要对阻塞线程发送信号,表示数据已经处理完成if (pmydata->done){epicsEventSignal(pmydata->done);}else{pasynManager->memFree(pasynUser->userPvt, sizeof(MyData));}status = pasynManager->freeAsynUser(pasynUser);if (status){asynPrint(pasynUser, ASYN_TRACE_ERROR, "freeAsynUser failed %s\n", pasynUser->errorMessage);}
}static void asynQueueRequest(const char *port, int addr, const char *message)
{MyData *pmyData1,*pmyData2;asynUser *pasynUser, *pasynUserDuplicate;asynStatus status;asynInterface *pasynInterface;int canBlock;// 分配两个结构体,并且初始化这两个结构体pmyData1 = (MyData *)pasynManager->memMalloc(sizeof(MyData));pmyData2 = (MyData *)pasynManager->memMalloc(sizeof(MyData));memset(pmyData1, 0, sizeof(MyData));memset(pmyData2, 0, sizeof(MyData));// 字符串传入第一个结构体缓存中strcpy(pmyData1->buffer, message);pmyData1->id = 1;// 使用queueRequest需要创建asynUser结构体,并且放入回调程序pasynUser = pasynManager->createAsynUser(queueCallback, NULL);pasynUser->timeout = 1.0;pasynUser->userPvt = pmyData1;// 通过port和addr连接驱动程序和使用的asynUserstatus = pasynManager->connectDevice(pasynUser, port, addr);if (status != asynSuccess){printf("can't connect to port:%s\n", pasynUser->errorMessage);return;}// 根据接口名称,查找对应的接口/*typedef struct asynInterface{const char *interfaceType;void *pinterface;void *drvPvt;}asynInterface;*/pasynInterface = pasynManager->findInterface(pasynUser, asynOctetType, 1);if (!pasynInterface){printf("this driver do not support interface: %s\n", asynOctetType);return;}// 获取asynOctet接口起始位置pmyData1->pasynOctet = (asynOctet *)pasynInterface->pinterface;// 获取驱动程序专用数据pmyData1->drvPvt = pasynInterface->drvPvt;// 结构体复制*pmyData2 = *pmyData1;pmyData2->id = 2;strcat(pmyData2->buffer, " repeated!");// 获取驱动程序是否可以阻塞canBlock = 0;pasynManager->canBlock(pasynUser, &canBlock);if (canBlock) pmyData2->done = epicsEventCreate(epicsEventEmpty);pasynUserDuplicate = pasynManager->duplicateAsynUser(pasynUser, queueCallback, NULL);pasynUserDuplicate->userPvt = pmyData2;// 排队两个请求status = pasynManager->queueRequest(pasynUser, asynQueuePriorityLow, 0.0);if (status){asynPrint(pasynUser, ASYN_TRACE_ERROR, "First queueRequest failed %s\n", pasynUser->errorMessage);}status = pasynManager->queueRequest(pasynUserDuplicate, asynQueuePriorityLow, 0.0);if (status){asynPrint(pasynUser, ASYN_TRACE_ERROR, "Second queueRequest failed %s\n", pasynUser->errorMessage);}if (canBlock){// 读写端口驱动的操作是在另外一个线程中进行,等待那个线程发送数据操作结束的事件epicsEventWait(pmyData2->done); // 数据2已经处理好了epicsEventDestroy(pmyData2->done);pasynManager->memFree(pmyData2, sizeof(MyData));}
}/* 向IOC shell注册 */
static const iocshArg asynQueueRequestArg0 = {"port", iocshArgString};
static const iocshArg asynQueueRequestArg1 = {"addr", iocshArgInt};
static const iocshArg asynQueueRequestArg2 = {"message", iocshArgString};
static const iocshArg *const asynQueueRequestArgs[] = {&asynQueueRequestArg0, &asynQueueRequestArg1, &asynQueueRequestArg2
};
static const iocshFuncDef asynQueueRequestDef = {"asynQueueRequest", 3, asynQueueRequestArgs};static void asynQueueRequestCall(const iocshArgBuf * args)
{asynQueueRequest(args[0].sval, args[1].ival, args[2].sval);
}static void asynQueueRequestRegister(void)
{static int firstTime = 1;if (!firstTime) return;firstTime = 0;iocshRegister(&asynQueueRequestDef, asynQueueRequestCall);
}epicsExportRegistrar(asynQueueRequestRegister);
添加一个文件asynQueueRequest.dbd,内容如下:
registrar("asynQueueRequestRegister")
更改同一路径下的Makefile文件:
...
echoDriver_DBD += asynQueueRequest.dbdechoDriver_SRCS += asynQueueRequest.c
...
编译以上文件,编写启动脚本:
...
# 可以阻塞驱动程序,模拟单设备端口
echoDriverInit("SIM", 0.1, 0, 0)
...
启动IOC,测试以上asynQueueRequest命令读写为名SIM的端口驱动:
可以看出客户端进行了两次写入-回读操作。
epics> asynQueueRequest "SIM" 0 "hello world"
Start to Write 'hello world' to device
finished writing!
Start to read from device
Finished reading,content: 'hello world'
Start to Write 'hello world repeated!' to device
finished writing!
Start to read from device
Finished reading,content: 'hello world repeated!'
使用asynOctet接口的窗口进行测试,直接运行Read一次,可以从Input ASCII文本框中读取了驱动程序回传的数据,与最后一次写入驱动的数据相同。

相关文章:
asyn queueRequest使用实例
使用queueRequest读写端口驱动的示例,驱动驱动程序使用一个基于asyn实现了asynCommon和asynOctet的驱动程序-CSDN博客中编写的驱动程序,本程序的C代码如下: #include <stdlib.h> #include <stdio.h> #include <string.h>#…...
关于jmeter设置为中文问题之后无法保存设置的若干问题
1、jemeter如何设置中文模式 Options--->Choose Language--->Chinese(Simplifies), 如此设置后就可显示中文模式(缺点:下次打开还是英文);如下图所示: 操作完成之后: 但是下次重启之后依旧是英文; 2、在jmeter.…...
基于FPGA的信号发生器verilog实现,可以输出方波,脉冲波,m序列以及正弦波,可调整输出信号频率
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 输出方波 输出脉冲波 输出m随机序列 输出正弦波 2.算法运行软件版本 vivado2019.2 3.部分核心程序 (完整…...
背景全文及翻译
背景 Oracle数据向MySQL同步,没有最新数据,于是在plsql手敲SQL筛选最新数据时,执行报错。 问题描述 通过日期字段筛选最近的数据,我用了类似这样的语句: SELECT * FROM orders WHERE order_date > 2022/01/01;我…...
JAVA地狱级笑话
为什么Java开发者总是不怕黑暗? 因为他们总是有null指针来照亮路。 Java程序员最讨厌的音乐是什么? Garbage Collection旋律,节奏总是让他们烦躁。 为什么Java中的HashMap很擅长社交? 因为它总是能快速找到key对应的朋友。 Java开…...
宝塔PHP8.1安装fileinfo拓展失败解决办法
在宝塔面板中安装PHP8.1后,安装fileinfo扩展一直安装不上,查看日志有报错,于是手动来安装也报错。 宝塔报错: 手动命令行编译安装同,也有报错 cd /www/server/php/81/src/ext/fileinfo/ make distclean ./configure …...
Python 魔术方法
在Python中,魔术方法(Magic Methods)或称为双下划线方法(Dunder Methods),是一类具有特殊用途的方法,其名称前后都带有两个下划线(如 __init__、__str__ 等)。这些方法定…...
03 go语言(golang) - fmt包基本类型
fmt包 在Go语言中,fmt 包是一个非常重要且广泛使用的标准库包,它提供了格式化I/O(输入/输出)功能,类似于C语言中的 printf 和 scanf。通过这个包,你可以读取输入并将数据格式化输出到标准输出或其他写入器…...
Docker本地镜像发布到阿里云镜像服务的简易指南
1 阿里云容器镜像服务 阿里云容器镜像服务(Alibaba Cloud Container Registry,简称ACR)是一个为容器镜像、Helm Chart等云原生资产提供安全托管及高效分发的平台。它支持多架构容器镜像,包括Linux、Windows、ARM等,以…...
大数据学习---快速了解clickhouse数据库
ClickHouse数据库介绍 ClickHouse是一款由Yandex开发的列式数据库管理系统(DBMS),适用于在线分析处理(OLAP)场景。它具有高性能、可扩展性、实时更新等特点,适用于处理大规模数据。 特点 列式存储&#x…...
哪些方法可以缓解面试紧张?
面试紧张是许多人在面对重要职业机会时的一种常见情绪。虽然一定程度的紧张可能激发人的潜能,但过度的紧张则可能影响到面试表现。为了缓解面试紧张,以下是一些有效的方法: 1.充分准备: 深入了解公司背景、职位要求以及公司文化…...
即时通讯未读消息计数
单聊未读消息计数 未读消息的计数,分为两个部分:增加和减少 其中,未读消息计数的增加,是由数据库(redis)在写入消息的同时,增加对应接收方的未读消息计数 在线 用户在线时,客户端…...
在Openshift(K8S)上通过EMQX Operator部署Emqx集群
EMQX Operator 简介 EMQX Broker/Enterprise 是一个云原生的 MQTT 消息中间件。 我们提供了 EMQX Kubernetes Operator 来帮助您在 Kubernetes 的环境上快速创建和管理 EMQX Broker/Enterprise 集群。 它可以大大简化部署和管理 EMQX 集群的流程,对于管理和配置的知…...
Python酷玩之旅_数据分析入门(matplotlib)
导览 前言matplotlib入门1. 简介1.1 Pairwise data1.2 Statistical distributions1.3 Gridded data1.4 Irregularly gridded data1.5 3D and volumetric data 2. 实践2.1 安装2.2 示例 结语系列回顾 前言 翻看日历,今年的日子已划到了2024年10月19日,今天…...
uiautomatorviewer安卓9以上正常使用及问题处理
一、安卓9以上使用uiautomatorviewer问题现象 打开Unexpected error while obtaining UI hierarchy 问题详情 Unexpected error while obtaining UI hierarchy java.lang.reflect.InvocationTargetException 二、问题处理 需要的是替换对应D:\software\android-sdk-windows…...
Go语言gRPC快速入门
文章目录 前言gRPC是什么Go语言的gRPC技术栈准备工作接口定义代码生成服务端代码编写客户端代码编写效果演示完整代码链接最后 前言 你好,我是醉墨居士,这篇博客想帮助初学者能够快速入门gRPC,希望能够为你节省宝贵的时间,让时间…...
Golang | Leetcode Golang题解之第479题最大回文数乘积
题目: 题解: func largestPalindrome(n int) int {if n 1 {return 9}upper : int(math.Pow10(n)) - 1for left : upper; ; left-- { // 枚举回文数的左半部分p : leftfor x : left; x > 0; x / 10 {p p*10 x%10 // 翻转左半部分到其自身末尾&…...
UDP协议讲解
预备知识: 端口号port: 我们在正常网络通信时,实际上是进程在互相通信。 我们所有的网络通信的行为,本质上都是进程间通信。 对双方而言,1.先保证数据能到达自己的机器 ip解决 2.找到指定的进程 端口号 ip地址用来…...
交叉注意力融合时域、频域特征的FFT + CNN -BiLSTM-CrossAttention轴承故障识别模型
往期精彩内容: Python-凯斯西储大学(CWRU)轴承数据解读与分类处理 Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客 Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客 Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客 三十多个开源…...
CSDN Markdown 编辑器语法大全
Markdown 是一种轻量级标记语言,它以简洁、易读易写的特点,被广泛应用于技术文档、博客文章、笔记等领域。CSDN 的 Markdown 编辑器为用户提供了丰富的功能,让用户能够轻松地创建格式规范、内容丰富的文档。以下是一份详细的 CSDN Markdown 编…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
java 实现excel文件转pdf | 无水印 | 无限制
文章目录 目录 文章目录 前言 1.项目远程仓库配置 2.pom文件引入相关依赖 3.代码破解 二、Excel转PDF 1.代码实现 2.Aspose.License.xml 授权文件 总结 前言 java处理excel转pdf一直没找到什么好用的免费jar包工具,自己手写的难度,恐怕高级程序员花费一年的事件,也…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
命令行关闭Windows防火墙
命令行关闭Windows防火墙 引言一、防火墙:被低估的"智能安检员"二、优先尝试!90%问题无需关闭防火墙方案1:程序白名单(解决软件误拦截)方案2:开放特定端口(解决网游/开发端口不通)三、命令行极速关闭方案方法一:PowerShell(推荐Win10/11)方法二:CMD命令…...
云原生安全实战:API网关Envoy的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关 作为微服务架构的统一入口,负责路由转发、安全控制、流量管理等核心功能。 2. Envoy 由Lyft开源的高性能云原生…...
