EPICS电机支持
1) 顶层对象是EPICS motor记录
已经对这个对象编写了很多代码:spec,IDL和Python类等
2)下一层是EPICS设备支持
了解motor记录,与驱动会话
3)最底层是EPICS驱动
对motor记录一无所知,与硬件会话
当前推荐的设备和驱动开发框架是asynMotor(模型3)
asynPortDriver用于扩展这个框架用于不被motorRecord支持的硬件特性。
asynMotor(模型3)
1)从2011年,在synApps motor模块中出现。
2)C++模型。
3)两个基类,asynMotorController和asynMotorAxis。
4)基类提供了大部分功能,只需要编写设备相关的实现。
5)易于支持控制器相关的特性。
6)在驱动API中对协同轮廓移动的直接支持。

基于synApps的motor驱动开发
1) synApps motor模块(需要ASYN,BUSY,IPAC和SNCSEQ)
a) motorRecord($(MOTOR)/motorApp/MotorSrc)
b) asynMotor设备支持(devMotorAsyn.c)
c) asynMotor驱动基类
i) asynMotorController.h, .cpp
ii) asynMotorAxis.h, .cpp
2) Motor驱动代码要实现asynMotor基类的控制器相关方法
a) <Name>MotorDriver.cpp
b) <Name>MotorDriver.h
c) <Name>MotorSupport.dbd
’控制器‘构造器做什么?
1) 创建一个实现了一个'真实'电机控制器的控制器对象(asynPortDriver)。
电机控制器硬件必须初始化
2)为在'CreateController'参数中,为每个请求的电机通道调用轴数次'Axis'构造器。
3)启动Poller任务,将更新所有电机通道的状态。
4)实现非-motorRecord特性。
-  
用于其它控制器参数的asynPortDriver方法
 -  
内建"轮廓移动"(协同多轴)方法
 
ACRController构造器
在从st.cmd调用iocInit()前:asynMotor.cmd(BCDA标准IOC启动文件)
ACR示例:motor/iocWithAsyn/st.cmd.acr
# portName, asynPort, num of axes, active poll period(ms), idle poll period(ms)
ACRCreateController("ACR1", "ARIES", 1, 20, 1000)
extern "C" int ACRCreateController(const char * portName, const char * ACRPortName, 
        int numAxes,
        int movingPollPeriod,
        int idlePollPeriod)
{
    new ACRController(portName, ACRPortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.)
} 
创建一个新的ACRController对象。
参数:
- [in] portName:将为这个驱动创建的asyn端口的名称。
 - [in] ACRPortName:先前创建的为连接ACR控制器的drvAsynIPPort的名称。
 - [in] numAxes:这个控制器支持的轴数。
 - [in] movingPollPeriod:当任何轴在移动时,轮询之间的时间。
 - [in] idlePollPeriod:当没有轴在移动时,轮询之间的时间。
 
ACRController::ACRController(const char * portName, 
const char * ACRPortName, int numAxes, double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, numAxes, NUM_ACR_PARAMS, asynUInt32DigitalMask,
asynUInt32DigitalMask, ASYN_CANBLOCK | ASYN_MULTIDEVICE, 1, 0, 0) 
asynMotorController:asynMotorController(const char * portName,
                                        int         numAxes,
                                        int         numParams,
                                        int         interfaceMask,
                                        int         interruptMask,
                                        int         asynFlags,
                                        int         autoConnect,
                                        int         priority,
                                        int         stackSize
) 
创建一个新的asynMotorController对象。所有参数只是被传递给了asynPortDriver基类的构造器。在调用这个基类构造器后,这个方法创建了在asynMotorDriver.h中定义的电机参数。
ACRController::ACRController(const char * portName, 
const char * ACRPortName, int numAxes, double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, 
                      numAxes, 
                      NUM_ACR_PARAMS, 
                      asynUInt32DigitalMask,
                      asynUInt32DigitalMask, 
                      ASYN_CANBLOCK | ASYN_MULTIDEVICE, 
                      1,  // 自动连接
                      0, 0) // 默认优先级和栈尺寸
{
    ...
    // 创建控制器相关的参数
    createParam(ACRJerkString,            asynParamFloat64,    &ACRJerk_);
    createParam(ACRReadBinaryIOString,    asynParamInt32,      &ACRReadBinaryIO_);
    // 连接到ACR控制器
    status = pasynOctetSyncIO->connect(ACRPortName, 0, &pasynUserContorller_, NULL);
     // 关闭命令回送
    sprintf(outString_, "ECHO 4");
    writeController();
    // 创建轴对象
    for (axis = 0; axis < numAxes; axis++){
        new ACRAxis(this, axis);
    }
    startPoller(movingPollPeriod, idlePollPeriod, 2);
} 
ACRAxis::ACRAxis(class ACRController * pc, int axisNo) 
创建一个ACRAxis对象。
参数:
[in] pC:指向这个轴所属的ACRController的指针
[in]axisNo:这个轴的索引,范围从0到pc->numAxes_-1。
初始化寄存器数目等。
asynStatus asynMotorController::startPoller(double movingPollPeriod,
                                            double indlePollPeriod,
                                            int    forcedFastPolls) 
启动这个电机的poller线程。派生类将在它们构造器接近末尾处调用这个方法。派生类一般可以使用这个poller线程的基类实现,但如果需要,可以自动重新实现。
参数:
- [in] movingPollPeriod:当电机正在运动时,轮询之间的时间。
 - [in] idlePollPeriod:当没有轴运动时,轮询之间的时间。
 - [in] forcedFastPolls:在唤醒这个poller后,执行movingPollPeriod的次数。对于在告诉一个轴已经启动后,不立即报告那个轴正在移动的控制器,这需要非0。
 
asynMotorController方法ACRController自定义参数
asynStatus ACRController::writeFloat64(asynUser * pasynUser, epicsFloat64 value)
{
    int function = pasynUser->reason;
    asynStatus status = asynSuccess;
    ACRAxis * pAxis = getAxis(pasynUser);
    static const char * functionName = "writeFloat64";
    if (function == ACRJerk_){
        sprintf(outString_, "%s JOG JRK %f", pAxis->axisName_, value);
    }
    else{
        /* 调用基类方法 */
        status = asynMotorController::writeFloat64(pasynUser, value);
    }
    /* 进行回调, 因而更高层看到任何变化 */
    pAxis->callParamCallbacks();
} 
asynStatus ACRController::writeFloat64(asynUser * pasynUser, epicsFloat64 value) 
当客户端调用pasynFloat64->write()时,被调用。
从pasynUser中提取功能和轴编号。在参数库中设置这个值。如果功能时ACRJerk_,它设置控制器中的jerk值。对这个pasynUser->reason和地址,调用任何已注册的回调。对于所有其它功能,它调用asynMotorController::writeFloat64()。
参数:
[in] pasynUser:编码reasone和地址的asynUser结构体。
[in] value:要写的值。
对asynMotorController的重新实现。
asynMotorAxis构造器
创建一个Axis对象,它自定义为一个特定的电机控制器。
1)在控制器硬件中的电机轴必须初始化。
2)根据motorRecord表征motorRecord:GrainSupport, HasEncoder
3)实现提供所有可用motorRecord功能的方法:move,moveVelocity, home, setPosition,...
实现'report'方法
ACRAxis
ACRAxis::ACRAxis(ACRController * pc, int axisNo) : asynMotorAxis(pC, axisNo), pC_(pC)
ACRAxis::ACRAxis(ACRController * pc, int axisNo)  
创建一个新的asynMotorAxis对象。
参数:
[in] pC:指向这个轴所属的asynMotorController的指针。
[in] axisNo:这个轴的索引号,范围从0到pC->numAxies_ - 1。
检查那个pC不是NULL,并且axisNo在有效范围内。在pC->pAxes[axisNo_]中设置一个指向自身的指针。连接pasynUser_为这个asyn端口和axisNo。
asynMotorAxis方法
ACRAxis Move
asynStatus ACRAxis::move(double position,
                         int    relative,
                         double minVelocity,
                         double maxVelocity,
                         double acceleration) 
移动电机到一个绝对位置或者通过相对量。
参数:
[in] position:(如果relative=0)移动到绝对位置,或者(如果relative=1)要移动的相对位置。(单位steps)。
[in] relative:表明相对移动(1)或者绝对移动(0)的标记。
[in] minVelocity:初始速度,经常称为基速度。单位=steps/sec。
[in] maxVelocity:最大速度,经常称为回转速度。单位=steps/sec。
[in] acceleration:加速度值。单位=steps/sec/sec。
asynStatus ACRAxis::move(double position, int relative, double minVelocity,
                         double maxVelocity, double acceleration)
{
    sprintf(pc_->outString_, "%s JOG ACC %f", axisName_, acceleration/pulsesPerUnit_);
    status = pC_->writeController();
    sprintf(pc_->outString_, "%s JOG VEL %f",  axisName_, maxVelocity/pulsePerUnit_);
    status = pc_->writeCOntroller();
    if (relative){
        sprintf(pC_->outString_, "%c:%s JOG INC %f", CtlY, axisName_, position/pulsePerUnit_);
        status = pC_->writeController();
    }
    else{
        sprintf(pC_->outString_, "%c:%s JOG ABS %f", CtlY, axisName_, position/pulsesPerUnit_);
        status = pC_->writeController();
    }
} 
 
ACRAxis MoveVelocity
asynStatus ACRAxis::moveVelocity(double minVelocity, double maxVelocity, double acceration) 
以固定速度移动电机,直到告诉电机停止。
参数:
[in] minVelocity:初始速度,经常被称为基速度。单位=steps/sec。
[in] maxVelocity:最大速度,经常称为回转速度。单位=steps/sec。
[in] acceration:加速度值。单位=steps/sec/sec。
对来自asynMotorAxis的重新实现。
ACRAxis Poll
asynStatus ACRAxis::poll(bool * moving) 
查询这个轴。这个函数读取控制器位置,编码器位置,限位状态,移动状态和驱动上电状态。它为它轮询的每项调用setIntegerParam()和setDoubleParam(),并且接着在末尾调用callParamCallbacks()。
参数:
[out] moving:一个标记,设置它来表明这个轴是移动(1)或者结束(0)。
asynStatus ACRAxis::poll(bool * moving)
{
    // 读取当前编码器位置
    sprintf(pC_->outString, "?P%d", encoderPostionReg_);
    comStatus = pC_->writeReadController();
    if (comStatus) goto skip;
    encoderPosition_ = atof(pC_->inString);
    setDoubleParam(pC_->motorEncoderPosition_, encoderPostion);
    // 读取当前标记
    sprintf(pC_->outString_, "?P%d", flagReg_);
    comStatus = pC_->writeReadController();
    if (comStatus) goto skip;
    currentFlag_ = atoi(pC_->inString_);
    done = (currentFlags & 0x1000000) ? 0: 1;
    setIntegerParam(pC_->motorStatusDone_, done);
    * moving = done ? false : true;
        
    // 读取当前状态
    sprintf(pC_->outString, "?P%d", limitsReg_);
    comStatus = pC_->writeReadController();
    if (comStatus) goto skip;
    currentLimits_ = atoi(pC->inString_);
    limit = (currentLimts_ & 0x1) ? 1:0;
    setIntegerParam(pC_->motorStatusHighLimit_, limit);
    limit = (currentLimits_ & 0x2)?1:0;
    setIntegerParam(pC_->motorStatusAtHome_, limit);
    
skip:
    setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1: 0);
    callParamCallbacks();
    return comStatus ? asynError : asynSuccess;
} 
 
ACRAxis Home
asynStatus ACRAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards) 
移动电机到home位置。
参数:
[in] minVelocity:初始速度,经常称为基速度。单位=steps/sec。
[in] maxVelocity:最大速度,经常称为回转速度。单位=steps/sec。
[in] acceraltion:加速度值。单位=steps/sec/sec。
[in] forwards:表明正(1)反(0)方向移动电机的标记。某些控制器需要被告知方向,另一些直到用哪种方式移动到home。
ACRAxis Report
void ACRAxis::report(FILE *fp, int level) 
报告驱动的状态。
参数:
[in] fp:文件指针,报告信息将写入这个文件。
[in] level:详细程度。
如果detail>0,则输出每个轴的信息。在打印控制器相关信息后,调用asynMotorController::report()。
ACRAxis setPosition
asynStatus ACRAxis::setPosition(double position) 
设置电机的当前值。
参数:
[in] position:新的绝对电机位置应该被设置到硬件中。Units=Steps。
ACRAxis Stop
asynStatus ACRAxis::stop(double acceleration) 
停止电机。
参数:
[in] acceleration:绝对值。单位=steps/sec/sec。



![[网鼎杯 2020 青龙组]singal详细题解--VMP 直接逆向,angr模拟执行,ponce符号化](https://img-blog.csdnimg.cn/5cfe85650cf048d487d293facdda8003.png)



![二分查找[整数二分]](https://img-blog.csdnimg.cn/d8ddc4df4e1043b4a2c88cd92b665577.png)











