EPICS 3.14通道访问手册(3) --函数调用接口指南

清空和阻塞

 

当CA客户端库不等待每次请求后从服务器返回的响应时,可以实现性能的显著提高。请求与CA服务器交互的所有请求被累积(缓存),并且在在ca_flush_io(), ca_pend_io(), ca_pend_event()或者ca_sg_block()被调用前不被转发给IOC,使得若干操作可以通过网络一起被高效地发送。在从ca_pend_io()接收到ECA_NORMAL前,不应该引用由ca_get()写入你程序变量的任何过程变量。

状态代码

如果成功,这里描述的例程返回状态代码ECA_NORMAL。从客户端库返回的失败的状态代码在本手册中与每个例程一起被列出。对客户端视乎有效的操作在服务器中仍然会出错。写字符串"off"到一个浮点字段是一个这种错误类型的示例。如果一个通道的服务器位与与客户端不同地址空间,则与服务器通信的ca_xxx()操作返回一个状态,它表明请求的有效项以及它是否成功地排队到这个服务器,但结束状态地通信被延时到一个用户回调被调用,或者缺少那,一个异常处理程序被调用。一个错误数值和错误的严重性被嵌入到一个CA状态(错误)常数。程序不应该通过检测返回的值是否是0(如UNIX规则),测试一个CA函数调用是否成功。以下是若干测试CA函数返回的函数。有关这个话题,更多信息见ca_signal()和SEVCHK()。

status = ca_XXXX();
SEVCHK( status, "ca_XXXX() returned failure status");

if ( status & CA_M_SUCCESS ) {
        printf ( "The requested ca_XXXX() operation didn't complete successfully");
}

if ( status != ECA_NORMAL ) {
        printf("The requested ca_XXXX() operation didn't complete successfully because \"%s\"\n",
                ca_message ( status ) );
}

通道访问数据类型

CA通道在过程变量和客户端程序直接安形成一个虚拟电路。使用CA服务器库连接各种各样的数据源到EPICS是可能的。当一个CA通道与一个EPICS输入输出控制器(IOC)通信时,一个字段是一个PV的专属化,并且一个EPICS记录是一个包含字段的兼容功能块,并且以下元数据经常通过EPICS记录支持被映射成在EPICS记录内特定字段。

类型chtype的参数指定你想要传递的数据类型。它们期望在db_access.h中定义的DBR_XXXX数据类型代码集合之一。有对应所有C原始类型的数据类型,并且也有复合(C结构体)类型,包括各种过程变量属性,诸如单位,限制,时间戳或者警报状态。原始C类型遵循一个命名规则:C typedef dbr_xxxx_t对应DBR_XXXX数据类型代码。复合(C结构体)类型遵循一个命名规则,C结构体标签dbr_xxx对应DBR_XXX数据类型代码。以下表格更详细地提供了CA数据类型空间地结构体。由于数据地址以无类型"void *"指针被传递给CA客户端库,则应该小心确保你传递了对应你已经指定地DBR_XXXX类型的正确C数据类型。在db_access.h中提供了架构无关类型来帮助程序员编写可移植代码。例如,"dbr_short_t"应该用于发送或接收类型DBR_SHORT。注意:为了少混淆类型名DBR_SHORT,类型名DBR_INT已经被弃用。实际中,DBR_INT类型代码和DBR_SHORT类型代码都指向一个16位整数类型,并且功能上相同。

通道访问原始数据类型

通道访问数据类型空间的结构体

CA类型代码读/写原始C数据类型过程变量属性
DBR_<PRIMITIVE_TYPE>RWdbr_<primitivetype>_t
DBR_STS_<PRIMITIVE_TYPE>R

struct

dbr_sts_<priimitivetype>

值,警报状态,和警报严重性
DBR_TIME_<PRIMITIVETYPE>R

struct

dbr_time_<primitivetype>

值,警报状态,警报严重性和时间戳
DBR_GR_<PRIMITIVETYPE>R

struct

dbr_gr_<primitivetype>

值,警报状态,警报严重性,单位,显式精度和图形限制
DBR_CTRL_<PRIMITIVETYPE>R

struct 

dbr_ctrl_<primitivetype>

值,警报状态,警报严重性,单位,显示精度,图形限制和控制限制
DBR_PUT_ACKTWdbr_put_ackt_t用于全局警报确认。瞬态警报必须被确认?(0,1)表示(no, yes)
DBR_PUT_ACKSWdbr_put_acks_t用于全局警报确认。要确认最高警报。如果当前警报严重性低于或等于这个值,这个警报被确认。
DBR_STSACK_STRINGR

struct

dbr_stsack_string

值,警报状态,警报严重性,ackt,acks
DBR_CLASS_NAMERdbr_class_name_t封闭接口的名称(如果通道连接到运行时间数据库的EPICS,记录的名称)

通道值数组也可以被包含在结构化CA数据类型内。如果请求了多个元素,则通过索引指向DBR_XXX结构体中值字段的指针,在程序中可以访问各自元素。例如,以下代码加u四年一个数组过程变量中元素之和并且打印它的时间戳。dbr_size_n()函数可以用于确定一个结构化CA数据类型中有多个值元素时要保留的正群字节数目。

#include <stdio.h>
#include <stdlib.h>

#include "cadef.h"

int main ( int argc, char ** argv )
{
    struct dbr_time_double * pTD;
    const dbr_double_t * pValue;
    unsigned nBytes;
    unsigned elementCount;
    char timeString[32];
    unsigned i;
    chid chan;
    double sum;
    int status;

    if ( argc != 2 ) {
        fprintf ( stderr, "usage: %s <channel name>", argv[0] );
        return -1;
    }

    status = ca_create_channel ( argv[1], 0, 0, 0, & chan );
    SEVCHK ( status, "ca_create_channel()" );
    status = ca_pend_io ( 15.0 );
    if ( status != ECA_NORMAL ) {
        fprintf ( stderr, "\"%s\" not found.\n", argv[1] );
        return -1;
    }

    elementCount = ca_element_count ( chan );
    nBytes = dbr_size_n ( DBR_TIME_DOUBLE, elementCount );
    pTD = ( struct dbr_time_double * ) malloc ( nBytes );
    if ( ! pTD ) {
        fprintf ( stderr, "insufficient memory to complete request\n" );
        return -1;
    }

    status = ca_array_get ( DBR_TIME_DOUBLE, elementCount, chan, pTD );
    SEVCHK ( status, "ca_array_get()" );
    status = ca_pend_io ( 15.0 );
    if ( status != ECA_NORMAL ) {
        fprintf ( stderr, "\"%s\" didn't return a value.\n", argv[1] );
        return -1;
    }

    pValue = & pTD->value;
    sum = 0.0;
    for ( i = 0; i < elementCount; i++ ) {
        sum += pValue[i];
    }

    epicsTimeToStrftime ( timeString, sizeof ( timeString ),
        "%a %b %d %Y %H:%M:%S.%f", & pTD->stamp );

    printf ( "The sum of elements in %s at %s was %f\n",
        argv[1], timeString, sum );

    ca_clear_channel ( chan );
    ca_task_exit ();
    free ( pTD );

    return 0;
}

用户提供的回调函数

在一个响应达到时,某个CA客户端初始化的请求在客户端进行中异步执行一个程序提供的回调。函数ca_put_callback(), ca_get_callback()和ca_create_subscription()都通过这种机制请求异步完成的通知。event_handler_args结构体通过值被传递给程序提供的回调。在这个结构体中,dbr字段是一个指向可能被返回的任何数据的void指针。status字段将被设置成在caerr.h中CA错误代码之一,并且将表示在IOC中运行的状态。如果状态字段未被设置为ECA_NORMAL或者数据未被正常地从这个操作返回(即:put回调),则你应该预计dbr字段将被设置为一个null指针(0)。当程序进行请求时,字段usr,chid和type被设置为指定的值。dbr和其指向的任何数据仅在在用户的回调函数内执行时才有效。

typedef struct event_handler_args {
    void            *usr;   /* user argument supplied with request */
    chanId          chid;   /* channel id */
    long            type;   /* the type of the item returned */
    long            count;  /* the element count of the item returned */
    const void      *dbr;   /* a pointer to the item returned */
    int             status; /* ECA_XXX status of the requested op from the server */
} evargs;

void myCallback ( struct event_handler_args args )
{
    if ( args.status != ECA_NORMAL ) {
    }
    if ( args.type == DBR_TIME_DOUBLE ) {
         const struct dbr_time_double * pTD =
              ( const struct dbr_time_double * ) args.dbr;
    }
}

通道访问异常

当服务器探测到错误,并且没有连接这个请求的客户端回调函数,在客户端中一个异常处理程序被执行。默认的异常处理程序在console上打印一条消息并且如果异常情况严重则退出。在CA客户端库内被SEVCHK宏探测到的某些内部异常,和错误可能也使得这个异常处理程序被调用。要修改这种行为,见ca_add_exception_event()。

服务器和客户端在相同主机上共享相同地址空间

如果过程变量的服务器和其客户端位于相同内存地址空间和相同主机内,则ca_xxx()操作绕过服务器并且直接与服务器工具组件(通常IOC的功能块数据库)交互。在这种情况中,ca_xxx()例程经常把请求操作的结束状态直接返回给调用者,没有机会给通过异常处理程序的异步错误通告。同样,回调可能直接被请求它们的CA库函数调用。

数组

对于需要一个指定数组元素数目的参数的例程,不可以请求比过程变量本地元素数目更多的数目。过程变量的最大本地元素数目在通道连接时从ca_element_count()获取。如果请求元素数目少于过程变量的本地元素数目,被请求值将从元素0开始获取。默认,CA限制数组中元素数目不多于近似16K除以数组中一个元素大小的数目。从EPICS 3.14开始,在客户端和服务器中可以配置这个最大数组尺寸。

连接管理

程序应该认为CA服务器可以被重启,以及网络连接是瞬态的。当你创建一个CA通道,其初始连接状态最常见是断开的。如果过程变量的服务器可达,这个库将立即初始化必要操作来与它进行连接。否则,客户端库将监视网络上服务器的状态并且在它变得可用时连接或重连这个过程变量的服务器。在通道连接后,程序可以通过这个通道自由执行IO操作,但应该预计这个通道在任何时刻由于网络连接中断或者服务器重启而断开。

三种方法可以用于确定一个通道是否连接:程序可以 调用ca_state()获取当前连接状态,在通道连接前在ca_pend_io()中阻塞,或者在其调用ca_create_channel()时安装一个连接回调处理程序。ca_pend_io()方法是最适合短运行持续时间的简单命令行程序,而连接回调方法最适合有长运行持续时间的toolkit组件。ca_state()的使用仅适合首选查询连接状态变化而不是选择异步通知的程序。ca_pend_io()函数仅阻塞指定null连接处理程序回调函数的通道。如果CA客户端和CA服务器都被托管在相同地址空间(在相同进程内),用户的连接状态变化函数将立即从ca_create_channel()内被运行。

线程安装和对用户代码的抢占式回调

从EPICS R3.14开始,CA客户端库在所有OS上都是线程安全的(在以前发行版中,仅在vxWorks上库才是线程安全的)。当客户端库被初始化时,程序员可以指定是否启用抢占式回调。抢占式回调默认被禁用。如果启用了抢占式回调,当主启动通道访问线程未在通道访问库中一个函数中时,用户的回调函数可能被CA的辅助线程调用。否则,仅在主启动通道访问线程在CA客户端库内执行时,用户的回调函数才将被调用。当CA客户端库调用用户的回调函数时,在执行另一个回调函数前,它总是等待当前回调结束。启用抢占回调的程序员应该熟悉使用互斥锁来创建一个可靠的多线程程序。

设置一个传统的单线程客户端,你将需要像这样的代码(见ca_context_create()和CA客户端上下文和程序特定的辅助线程)。

SEVCHK ( ca_context_create(ca_disable_preemptive_callback ), "application pdq calling ca_context_create" );

设置抢占式回调启用的CA客户端上下文,你将需要像这样的代码(见ca_context_create()和CA客户端上下文和程序特定的辅助线程)。

SEVCHK ( ca_context_create(ca_enable_preemptive_callback ), "application pdq calling ca_context_create" );

CA客户端上下文和程序特定的辅助线程

在相同地址空间(进程中)运行的若干客户端工具相互独立经常是必要的。例如,数据库CA链接和sequencer被设计成不使用相同CA客户端库线程,网络回路,以及数据结构。每个线程首次直接调用ca_context_create()直接或者在首次调用任何CA库函数时隐式地创建一个CA客户端库上下文。一个CA客户端库上下文包含连接和与CA客户端程序创建的通道所需的线程,网络回路和数据结构。由CA客户端库产生的辅助线程的优先级固定地偏移调用ca_context_create()的优先级。一个程序特定的辅助线程可以通过使用从ca_current_context()返回的CA上下文标识符调用ca_attach_context()加入这个CA上下文。一个要被加入的上下文必须是抢占式,必须使用ca_context_create(ca_enable_preemptive_callback)创建它。连接一个线程到一个显式或隐式用ca_create_context(ca_disable_preemptive_callback)创建的非抢占式CA上下文是不可能的。一旦一个线程加入了一个CA上下文,它只需要进行常规ca_xxx()库调用来使用这个上下文。

在销毁任何通道或连接它的程序特定线程后,通过调用ca_context_destroy()一个CA客户端库上下文可以被关闭和清理。上下文件可以被不同线程创建和销毁,只要它们都是相同上下文的组成。

从单线程程序查询CA客户端库

如果抢占式回调未被启用,则为了合适的操作,CA必须周期地被查询来管理后台活动。这要求你地程序必须在ca_pend_event(), ca_pend_io()或ca_sg_block()之一中等待,或者要么它应该至少每100毫秒调用ca_poll()。在单线程程序中,一个像Xt的文件描述符管理器或者在fdManager.h中描述的接口可以用于监视鼠标点击和CA的文件描述符,因而当CA服务器消息通过网络到达时,ca_poll()能立即被调用。

避免模仿仍然常见的坏习惯

EPICS发行初期,通过使用存储在类型chid中指针访问一个结构体中字段,检查一个通道的连接状态其本地类型和其本地元素数目是常见习惯。同样,在每个通道结构体中的用户私有指针也常通过访问通道结构体中字段直接被设置。由这个习惯产生了很多问题。例如,在3.13发行版前,意识到在每个通道结构中某个私有字段的瞬态变化使得直接使用私有字段可靠地测试通道连接状态是困难的。因而,在3.13发行版中,某些字段的名称被更改来阻止这种用法。从3.14发行版开始,这种方式编写的代码将编译不了。打算在大范围EPICSs版本上保持最高可移植性的代码应该尤其小心。例如,你应该用ca_element_count(channel_id)替代所有channel_id->count。这种方法应该在现在所有在用EPICS上可靠。ca_puser(chid)=xxxx尤其是一个问题。设置每个通道私有指针的最好机制是在创建这个通道时传递用户私有指针。在所有版本上都实现这种方法。另外,你也可以使用ca_set_puser(CHID, PUSER),但这个函数仅在EPICS 3.13官方发行版后才可用。

从POSIX信号处理程序调用CA函数

如你所预计,从POSIX信号处理程序调用CA客户端库是不安全的。同样,从中断上下文调用CA客户端库是不安全的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【优质项目推荐】 1、项目代码均经过严格本地测试,运行OK,确保功能稳定后才上传平台。可放心下载并立即投入使用,若遇到任何使用问题,随时欢迎私信反馈与沟通,博主会第一时间回复。 2、项目适用于计算机相关专业(如计科、信息安全、数据科学、人工智能、通信、物联网、自动化、电子信息等)的在校学生、专业教师,或企业员工,小白入门等都适用。 3、该项目不仅具有很高的学习借鉴价值,对于初学者来说,也是入门进阶的绝佳选择;当然也可以直接用于 毕设、课设、期末大作业或项目初期立项演示等。 3、开放创新:如果您有一定基础,且热爱探索钻研,可以在此代码基础上二次开发,进行修改、扩展,创造出属于自己的独特应用。 欢迎下载使用优质资源!欢迎借鉴使用,并欢迎学习交流,共同探索编程的无穷魅力! 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip 基于业务逻辑生成特征变量python实现源码+数据集+超详细注释.zip
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值