EPICS -- 测试asynDriver和设备支持的示例1-- 连接测试

这个应用程序可以用于测试连接管理。它用drvAsynIPPort连接一个设备并且在一个后台线程中周期地写入此设备。取决于是否连接了设备,将打印出错消息。可以通过循环上电或者断开网线连接或断开这个设备来测试这种行为。

以下是建立并且测试这个程序的完整过程:

1) 建立IOC应用程序框架

[blctrl@main-machine exer]$ mkdir exer41
[blctrl@main-machine exer]$ cd exer41
[blctrl@main-machine exer41]$ makeBaseApp.pl -t ioc testAsynDriver
[blctrl@main-machine exer41]$ makeBaseApp.pl -i -t ioc testAsynDriver
Using target architecture linux-x86_64 (only one available)
The following applications are available:
    testAsynDriver
What application should the IOC(s) boot?
The default uses the IOC's name, even if not listed above.
Application name?
[blctrl@main-machine exer41]$ ls
configure  iocBoot  Makefile  testAsynDriverApp

2) 编辑configure/RELEASE目录,添加以下内容:

SUPPORT=/usr/local/EPICS/synApps/support
ASYN=$(SUPPORT)/asyn
IPAC=$(SUPPORT)/ipac

3) 进入testAsynDriverApp/src目录中,创建一个名testConnect.cpp为的c++源文件:

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

#include <epicsThread.h>
#include <epicsString.h>
#include <iocsh.h>
#include <asynPortDriver.h>
#include <asynOctetSyncIO.h>


#include <epicsExport.h>

class testConnect :  public asynPortDriver {
public:
        // 构造函数
        testConnect(const char * portName, const char * IPPortName, const char * outputString);
        void pollerTask(void);
private:
        asynUser * pasynUserIPPort_;
        const char * outputString_;
};

static const char * driverName = "testConnect";

// 定义程序轮询时间
#define POLLER_PERIOD 1
// 定义响应的最大长度
#define MAX_RESPONSE_LEN 256

//定义静态函数,只能被从这个文件中调用
static void pollerTask(void * drvPvt);

testConnect::testConnect(const char * portName, const char * IPPortName, const char * outputString)
        : asynPortDriver(portName,
                1, /*maxAddr*/
                asynOctetMask, /*接口掩码*/
                0, /*中断掩码*/
                ASYN_CANBLOCK, /*asynFlag.这个驱动程序阻塞,并且它不是多设备*/
                1,/*自动连接*/
                0,/*默认优先级y*/
                0)/*默认栈大小*/
{
        asynStatus status;
        const char * functionName = "testConnect";
        // 开辟空间,存储传入字符串
        outputString_ = epicsStrDup(outputString);
        /*
 *              asynStatus (*connect)(const char *port, int addr,
 *                     asynUser **ppasynUser, const char *drvInfo);
 *              传入端口名称,传出一个asynUser指针
 *      */
        status = pasynOctetSyncIO->connect(IPPortName, 0, &pasynUserIPPort_,NULL);

        if (status) //连接失败
        {
                printf("%s:%s: pasynOctetSyncIO->connect failure, status=%d\n", driverName, functionName, status);
                return;
        }

        /*  创建在后台运行的线程 */
        status = (asynStatus)(epicsThreadCreate("testConnectTask",
                                                epicsThreadPriorityMedium,
                                                epicsThreadGetStackSize(epicsThreadStackMedium),
                                                (EPICSTHREADFUNC)::pollerTask,
                                                this) == NULL);

        if (status){
                printf("%s:%s: epicsThreadCreate failed, status=%d\n", driverName, functionName, status);
                return;
        }

        printf("Start new Thread testConnectTask successfully!\n\n");
}

static void pollerTask(void * drvPvt)
{
        testConnect * pPvt = (testConnect *)drvPvt;
        pPvt->pollerTask();
}

/*  轮询任务作为一个单独线程运行 */
void testConnect::pollerTask(void)
{
        asynStatus status;
        char response[MAX_RESPONSE_LEN] = "";
        size_t numWrite, numRead;
        int isConnected;
        int eomReason;
        static const char * functionName = "pollerTask";

        /* 一直循环 */
        while(1){
                // 父类的公有成员函数
                lock();
                /* 根据端口或设备是否连接,isConnect被设置0或1 */
                status = pasynManager->isConnected(pasynUserIPPort_, &isConnected);
                if (status){
                        //父类的保护成员变量
                        asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
                        "%s:%s: error calling pasyManager->isConnected, status=%d, error=%s\n",
                        driverName, functionName, status, pasynUserIPPort_->errorMessage);

                }
                asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER,
                        "%s:%s: isConnected = %d\n", driverName, functionName, isConnected);

                /*
 *                      asynStatus (*writeRead)(asynUser *pasynUser, const char *write_buffer, size_t write_buffer_len,
 *              char *read_buffer, size_t read_buffer_len,  double timeout,size_t *nbytesOut, size_t *nbytesIn, int *eomReason);
 *              */
                status = pasynOctetSyncIO->writeRead(pasynUserIPPort_, outputString_, strlen(outputString_),
                        response, sizeof(response),
                        1.0, &numWrite, &numRead, &eomReason);

                if (status){
                        asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
                        "%s:%s: error calling pasynOctetSyncIO->writeRead,status=%d, error=%s\n",
                        driverName, functionName, status, pasynUserIPPort_->errorMessage);
                }
                else{
                        printf("From Server: %s\n", response);
                        asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER,
                        "%s:%s: numWrite=%ld, wrote:%s, numRead=%ld, response=%s\n",
                        driverName, functionName, (long)numWrite,outputString_,(long)numRead, response);
                }
                unlock();
                epicsThreadSleep(POLLER_PERIOD);
        }
}

extern "C" {
int testConnectConfigure(const char * portName, const char * IPPortName, const char * outputString)
{
        new testConnect(portName, IPPortName, outputString);
        return(asynSuccess);
}

/*  EPICS iocsh shell command */
static const iocshArg initArg0 = {"portName", iocshArgString};
static const iocshArg initArg1 = {"IPPortName", iocshArgString};
static const iocshArg initArg2 = {"output string", iocshArgString};
static const iocshArg * const initArgs[] = {&initArg0, &initArg1, &initArg2};
static const iocshFuncDef initFuncDef = {"testConnectConfigure",3, initArgs};

static void initCallFunc(const iocshArgBuf * args)
{
        testConnectConfigure(args[0].sval,args[1].sval, args[2].sval);
}

void testConnectRegister(void)
{
        iocshRegister(&initFuncDef, initCallFunc);
}

epicsExportRegistrar(testConnectRegister);
}

4) 在与第(3)步相同路径下,创建一个名为testConnectSupport.dbd的文件,在此文件中添加以下一行:

registrar("testConnectRegister")

5) 编译 在第(3)步相同路径下的Makefile文件,内容如下:

TOP=../..

include $(TOP)/configure/CONFIG
#----------------------------------------
#  ADD MACRO DEFINITIONS AFTER THIS LINE
#=============================
LIBRARY_IOC += testAsynDriverSupport

# Compile and add code to the support library
LIB_SRCS += testConnect.cpp
LIB_LIBS += asyn
LIB_LIBS += $(EPICS_BASE_IOC_LIBS)

#
#=============================
# Build the IOC application

PROD_IOC = testAsynDriver
# testAsynDriver.dbd will be created and installed
DBD += testAsynDriver.dbd

# testAsynDriver.dbd will be made up from these files:
testAsynDriver_DBD += base.dbd
testAsynDriver_DBD += testConnectSupport.dbd

# Include dbd files from all support applications:
testAsynDriver_DBD += asyn.dbd
testAsynDriver_DBD += drvAsynIPPort.dbd
testAsynDriver_DBD += testConnectSupport.dbd

# Add all the support libraries needed by this IOC
testAsynDriver_LIBS += asyn
testAsynDriver_LIBS += testAsynDriverSupport

# testAsynDriver_registerRecordDeviceDriver.cpp derives from testAsynDriver.dbd
testAsynDriver_SRCS += testAsynDriver_registerRecordDeviceDriver.cpp

# Build the main IOC entry point on workstation OSs.
testAsynDriver_SRCS_DEFAULT += testAsynDriverMain.cpp
testAsynDriver_SRCS_vxWorks += -nil-

# Add support from base/src/vxWorks if needed
#testAsynDriver_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary

# Finally link to the EPICS Base libraries
testAsynDriver_LIBS += $(EPICS_BASE_IOC_LIBS)

#===========================

include $(TOP)/configure/RULES
#----------------------------------------
#  ADD RULES AFTER THIS LINE

6) 切换倒这个IOC的顶层目录中执行make进行编译。

7)切换到iocBoot/ioctestAsynDriver/目录下,编辑启动文件st.cmd,内容如下:

#!../../bin/linux-x86_64/testAsynDriver

#- You may have to change testAsynDriver to something else
#- everywhere it appears in this file

< envPaths

cd "${TOP}"

## Register all support components
dbLoadDatabase "dbd/testAsynDriver.dbd"
testAsynDriver_registerRecordDeviceDriver pdbbase

## Load record instances
#dbLoadRecords("db/xxx.db","user=blctrl")
drvAsynIPPortConfigure("IPPort", "127.0.0.1:6666", 0, 0, 1);
testConnectConfigure("PORT1", "IPPort", "Hello EPICS ")

cd "${TOP}/iocBoot/${IOC}"
iocInit

8) 用python编写一个服务器程序server.py,对以上IOC程序进行测试:

#!/usr/bin/python3

import socket

serverIP = "127.0.0.1"
serverPort = 6666


class Tcp_Server(object):
    def __init__(self, ip, port):
        self.server_ip = ip
        self.server_port = port

        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.bind((self.server_ip, self.server_port))

        self.server.listen(10)

        while True:
            while True:
                sock, ip_port = self.server.accept()
                if sock is not None:
                    print('New Client: %s' % str(ip_port))
                    break

            while True:
                print("start receive!")
                data = sock.recv(1024)
                print("Client: %s" % data)
                sock.send(data)

                if len(data) == 0:
                    sock.close()
                    break

    def server_close(self):
        self.server.close()


def main():
    Tcp_Server(serverIP, serverPort)


if __name__ == "__main__":
    main()

9) 启动服务程序和IOC应用程序:

IOC应用程序终端:

[blctrl@main-machine ioctestAsynDriver]$ ../../bin/linux-x86_64/testAsynDriver st.cmd
#!../../bin/linux-x86_64/testAsynDriver
< envPaths
epicsEnvSet("IOC","ioctestAsynDriver")
epicsEnvSet("TOP","/home/blctrl/exer/exer41")
epicsEnvSet("SUPPORT","/usr/local/EPICS/synApps/support")
epicsEnvSet("ASYN","/usr/local/EPICS/synApps/support/asyn")
epicsEnvSet("IPAC","/usr/local/EPICS/synApps/support/ipac")
epicsEnvSet("EPICS_BASE","/usr/local/EPICS/base")
cd "/home/blctrl/exer/exer41"
## Register all support components
dbLoadDatabase "dbd/testAsynDriver.dbd"
testAsynDriver_registerRecordDeviceDriver pdbbase
## Load record instances
#dbLoadRecords("db/xxx.db","user=blctrl")
drvAsynIPPortConfigure("IPPort", "127.0.0.1:6666", 0, 0, 1);
testConnectConfigure("PORT1", "IPPort", "Hello EPICS")
cd "/home/blctrl/exer/exer41/iocBoot/ioctestAsynDriver"
iocInit
Starting iocInit
############################################################################
## EPICS R7.0.3.1
## EPICS Base built Sep  8 2022
############################################################################
From Server: Hello EPICS
iocRun: All initialization complete
## Start any sequence programs
#seq sncxxx,"user=blctrl"
epics> From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS
From Server: Hello EPICS

服务程序的终端:

[blctrl@main-machine python_server]$ ./server.py
New Client: ('127.0.0.1', 50312)
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'
start receive!
Client: b'Hello EPICS'

猜你喜欢

转载自blog.csdn.net/yuyuyuliang00/article/details/128150585