电机控制器的基类,实际的电机控制器从这个类派生
asynMotorController.h头文件
/* asynMotorController.h* 这个文件为asynMotorController定义了基类。* 真实电机控制器从这个类派生。它派生字PortDriver.*/
#ifndef asynMotorController_H
#define asynMotorController_H#include <epicsEvent.h>
#include <epicsTypes.h>#define MAX_CONTROLLER_STRING_SIZE 256
#define DEFAULT_CONTROLLER_TIMEOUT 2.0/** 此驱动程序的字符串定义参数。这些时传递给drvUserCreate的值。* 当标准的asyn接口方法被调用时,驱动将在pasynUser->reason中放入一个被被使用的整数。
*/
#define motorMoveRelString "MOTOR_MOVE_REL" //相对移动
#define motorMoveAbsString "MOTOR_MOVE_ABS" //绝对移动
#define motorMoveVelString "MOTOR_MOVE_VEL" //指定速度移动
#define motorHomeString "MOTOR_HOME" //归零
#define motorStopString "MOTOR_STOP_AXIS"//停止轴
#define motorVelocityString "MOTOR_VELOCITY" //速度
#define motorVelBaseString "MOTOR_VEL_BASE" //基速度
#define motorAccelString "MOTOR_ACCEL" //加速度
#define motorPositionString "MOTOR_POSITION" //位置
#define motorEncoderPositionString "MOTOR_ENCODER_POSITION" //编码器位置
#define motorDeferMovesString "MOTOR_DEFER_MOVES"
#define motorMoveToHomeString "MOTOR_MOVE_HOME"
#define motorResolutionString "MOTOR_RESOLUTION" //分辨率
#define motorEncoderRatioString "MOTOR_ENCODER_RATIO" //编码器比率
#define motorPGainString "MOTOR_PGAIN"
#define motorIGainString "MOTOR_IGAIN"
#define motorDGainString "MOTOR_DGAIN"
#define motorHighLimitString "MOTOR_HIGH_LIMIT" //上限位
#define motorLowLimitString "MOTOR_LOW_LIMIT" //下限位
#define motorClosedLoopString "MOTOR_CLOSED_LOOP" //闭环
#define motorPowerAutoOnOffString "MOTOR_POWER_AUTO_ONOFF"
#define motorPowerOnDelayString "MOTOR_POWER_ON_DELAY"
#define motorPowerOffDelayString "MOTOR_POWER_OFF_DELAY"
#define motorPowerOffFractionString "MOTOR_POWER_OFF_FRACTION"
#define motorPostMoveDelayString "MOTOR_POST_MOVE_DELAY"
#define motorStatusString "MOTOR_STATUS" //状态
#define motorUpdateStatusString "MOTOR_UPDATE_STATUS" //
#define motorStatusDirectionString "MOTOR_STATUS_DIRECTION" //方向
#define motorStatusDoneString "MOTOR_STATUS_DONE" //结束
#define motorStatusHighLimitString "MOTOR_STATUS_HIGH_LIMIT" //高限位
#define motorStatusAtHomeString "MOTOR_STATUS_AT_HOME" //归零
#define motorStatusSlipString "MOTOR_STATUS_SLIP" //滑动
#define motorStatusPowerOnString "MOTOR_STATUS_POWERED"
#define motorStatusFollowingErrorString "MOTOR_STATUS_FOLLOWING_ERROR"
#define motorStatusHomeString "MOTOR_STATUS_HOME" //
#define motorStatusHasEncoderString "MOTOR_STATUS_HAS_ENCODER" //有编码器
#define motorStatusProblemString "MOTOR_STATUS_PROBLEM"
#define motorStatusMovingString "MOTOR_STATUS_MOVING" //正在移动
#define motorStatusGainSupportString "MOTOR_STATUS_GAIN_SUPPORT"
#define motorStatusCommsErrorString "MOTOR_STATUS_COMMS_ERROR" //下限位
#define motorStatusLowLimitString "MOTOR_STATUS_LOW_LIMIT"
#define motorStatusHomedString "MOTOR_STATUS_HOMED"/* 这些是每个轴的参数,用于传递更多电机基类信息给驱动程序 */
#define motorRecResolutionString "MOTOR_REC_RESOLUTION" //分辨率
#define motorRecDirectionString "MOTOR_REC_DIRECTION" //方向
#define motorRecOffsetString "MOTOR_REC_OFFSET" //偏移/* 这些是用于轮廓移动的每个控制器参数(联动运动) */
#define profileNumAxesString "PROFILE_NUM_AXES"
#define profileNumPointsString "PROFILE_NUM_POINTS"
#define profileCurrentPointString "PROFILE_CURRENT_POINT"
#define profileNumPulsesString "PROFILE_NUM_PULSES"
#define profileStartPulsesString "PROFILE_START_PULSES"
#define profileEndPulsesString "PROFILE_END_PULSES"
#define profileActualPulsesString "PROFILE_ACTUAL_PULSES"
#define profileNumReadbacksString "PROFILE_NUM_READBACKS"
#define profileTimeModeString "PROFILE_TIME_MODE"
#define profileFixedTimeString "PROFILE_FIXED_TIME"
#define profileTimeArrayString "PROFILE_TIME_ARRAY"
#define profileAccelerationString "PROFILE_ACCELERATION"
#define profileMoveModeString "PROFILE_MOVE_MODE"
#define profileBuildString "PROFILE_BUILD"
#define profileBuildStateString "PROFILE_BUILD_STATE"
#define profileBuildStatusString "PROFILE_BUILD_STATUS"
#define profileBuildMessageString "PROFILE_BUILD_MESSAGE"
#define profileExecuteString "PROFILE_EXECUTE"
#define profileExecuteStateString "PROFILE_EXECUTE_STATE"
#define profileExecuteStatusString "PROFILE_EXECUTE_STATUS"
#define profileExecuteMessageString "PROFILE_EXECUTE_MESSAGE"
#define profileAbortString "PROFILE_ABORT"
#define profileReadbackString "PROFILE_READBACK"
#define profileReadbackStateString "PROFILE_READBACK_STATE"
#define profileReadbackStatusString "PROFILE_READBACK_STATUS"
#define profileReadbackMessageString "PROFILE_READBACK_MESSAGE"/* 这些是用于轮廓运动的每轴参数 */
#define profileUseAxisString "PROFILE_USE_AXIS"
#define profilePositionsString "PROFILE_POSITIONS"
#define profileReadbacksString "PROFILE_READBACKS"
#define profileFollowingErrorsString "PROFILE_FOLLOWING_ERRORS"/**
* 当状态改变时,被传递给devMotorAsyn的结构体
*/
typedef struct MotorStatus {double position; /**< 命令的电机位置 */double encoderPosition; /**< 实际编码器位置 */double velocity; /**< 实际速度 */epicsUInt32 status; /**< 包含状态位(运动结束,限位等)的字*/
} MotorStatus;enum ProfileTimeMode{PROFILE_TIME_MODE_FIXED,PROFILE_TIME_MODE_ARRAY
};enum ProfileMoveMode{PROFILE_MOVE_MODE_ABSOLUTE,PROFILE_MOVE_MODE_RELATIVE
};/* 对应构建,读取和执行的状态代码.* 小心,这些必须匹配相应的MBBI基类,但没有检查此的方法
*/
enum ProfileBuildState{PROFILE_BUILD_DONE,PROFILE_BUILD_BUSY
};enum ProfileExecuteState{PROFILE_EXECUTE_DONE,PROFILE_EXECUTE_MOVE_START,PROFILE_EXECUTE_EXECUTING,PROFILE_EXECUTE_FLYBACK
};enum ProfileReadbackState{PROFILE_READBACK_DONE,PROFILE_READBACK_BUSY
};/* 对应构建,执行和读取的状态代码 */
enum ProfileStatus {PROFILE_STATUS_UNDEFINED,PROFILE_STATUS_SUCCESS,PROFILE_STATUS_FAILURE,PROFILE_STATUS_ABORT,PROFILE_STATUS_TIMEOUT
};#ifdef __cplusplus
#include <asynPortDriver.h>class asynMotorAxis;class epicsShareClass asynMotorController : public asynPortDriver {public:/* 这是这个类的构造器 */asynMotorController(const char *portName, int numAxes, int numParams,int interfaceMask, int interruptMask,int asynFlags, int autoConnect, int priority, int stackSize);virtual ~asynMotorController();/* 我们重写了asynPortDriver 的方法 */virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);virtual asynStatus writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements);virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nRead);virtual asynStatus readGenericPointer(asynUser *pasynUser, void *pointer);virtual void report(FILE *fp, int details);/* 这些是这个类的新方法 */virtual asynMotorAxis* getAxis(asynUser *pasynUser);virtual asynMotorAxis* getAxis(int axisNo);virtual asynStatus startPoller(double movingPollPeriod, double idlePollPeriod, int forcedFastPolls);virtual asynStatus wakeupPoller();virtual asynStatus poll();virtual asynStatus setDeferredMoves(bool defer);void asynMotorPoller(); // 这应该私有,但被从C函数调用/* 处理moveToHome的函数 */virtual asynStatus startMoveToHomeThread();void asynMotorMoveToHome();/* 这些是用于轮廓移动的函数 */virtual asynStatus initializeProfile(size_t maxPoints);virtual asynStatus buildProfile();virtual asynStatus executeProfile();virtual asynStatus abortProfile();virtual asynStatus readbackProfile();virtual asynStatus setMovingPollPeriod(double movingPollPeriod);virtual asynStatus setIdlePollPeriod(double idlePollPeriod);/* 表示IOC正在关闭的标记。停止poller */int shuttingDown_; protected:/* 这些是参数库中参数的索引。 它们是在从设备支持调用中pasynUser->reason的值 *///这些是电机命令#define FIRST_MOTOR_PARAM motorMoveRel_int motorMoveRel_;int motorMoveAbs_;int motorMoveVel_;int motorHome_;int motorStop_;int motorVelocity_;int motorVelBase_;int motorAccel_;int motorPosition_;int motorEncoderPosition_;int motorDeferMoves_;int motorMoveToHome_;int motorResolution_;int motorEncoderRatio_;int motorPGain_;int motorIGain_;int motorDGain_;int motorHighLimit_;int motorLowLimit_;int motorClosedLoop_;int motorPowerAutoOnOff_;int motorPowerOnDelay_;int motorPowerOffDelay_;int motorPowerOffFraction_;int motorPostMoveDelay_;int motorStatus_;int motorUpdateStatus_;// 这些是状态位int motorStatusDirection_;int motorStatusDone_;int motorStatusHighLimit_;int motorStatusAtHome_;int motorStatusSlip_;int motorStatusPowerOn_;int motorStatusFollowingError_;int motorStatusHome_;int motorStatusHasEncoder_;int motorStatusProblem_;int motorStatusMoving_;int motorStatusGainSupport_;int motorStatusCommsError_;int motorStatusLowLimit_;int motorStatusHomed_;//这些是每个轴参数,用于传递更多电机记录信息到驱动int motorRecResolution_;int motorRecDirection_;int motorRecOffset_;// 这些是每个控制器参数,用于轮廓移动int profileNumAxes_;int profileNumPoints_;int profileCurrentPoint_;int profileNumPulses_;int profileStartPulses_;int profileEndPulses_;int profileActualPulses_;int profileNumReadbacks_;int profileTimeMode_;int profileFixedTime_;int profileTimeArray_;int profileAcceleration_;int profileMoveMode_;int profileBuild_;int profileBuildState_;int profileBuildStatus_;int profileBuildMessage_;int profileExecute_;int profileExecuteState_;int profileExecuteStatus_;int profileExecuteMessage_;int profileAbort_;int profileReadback_;int profileReadbackState_;int profileReadbackStatus_;int profileReadbackMessage_;// 这些是每轴参数,用于轮廓移动int profileUseAxis_;int profilePositions_;int profileReadbacks_;int profileFollowingErrors_;#define LAST_MOTOR_PARAM profileFollowingErrors_int numAxes_; /**< 控制器支持的轴数*/asynMotorAxis **pAxes_; /**< 轴对象指针的数组 */epicsEventId pollEventId_; /**< 唤醒poller的事件ID */epicsEventId moveToHomeId_; /**< 唤醒移动到归零线程的事件ID */double idlePollPeriod_; /**< 在没有轴在移动时,轮询之间的时间 */double movingPollPeriod_; /**< 当任何轴正在移动时,轮询之间的时间。 */int forcedFastPolls_; /**< 当poller唤醒时,强制快速轮询的次数 */size_t maxProfilePoints_; /**< 轮廓点的最大数目*/double *profileTimes_; /**< 每个轮廓点次数的数组 */int moveToHomeAxis_;/* 这些是控制器的便捷函数,它们对硬件使用asynOcter接口 */asynStatus writeController();asynStatus writeController(const char *output, double timeout);asynStatus writeReadController();asynStatus writeReadController(const char *output, char *response, size_t maxResponseLen, size_t *responseLen, double timeout);asynUser *pasynUserController_;char outString_[MAX_CONTROLLER_STRING_SIZE]; //存储发送给控制器的字符串char inString_[MAX_CONTROLLER_STRING_SIZE]; //存储从控制器接收的字符串friend class asynMotorAxis;
};
//计算电机驱动参数数目
#define NUM_MOTOR_DRIVER_PARAMS (&LAST_MOTOR_PARAM - &FIRST_MOTOR_PARAM + 1)#endif /* _cplusplus */
asynMotorController.cpp基类实现:
/* asynMotorController.cpp* 这个文件为一个asynMotorContorller定义基类。真实电机控制器从这个类派生。* 它拍摄于asynPortDriver.*/
#include <stdlib.h>
#include <string.h>#include <epicsThread.h>
#include <iocsh.h>#include <asynPortDriver.h>
#include <asynOctetSyncIO.h>
#include <epicsExport.h>
#define epicsExportSharedSymbols
#include <shareLib.h>
#include "asynMotorController.h"
#include "asynMotorAxis.h"#ifndef VERSION_INT
# define VERSION_INT(V,R,M,P) ( ((V)<<24) | ((R)<<16) | ((M)<<8) | (P))
#endif#define MOTOR_ASYN_VERSION_INT VERSION_INT(ASYN_VERSION,ASYN_REVISION,ASYN_MODIFICATION,0)#define VERSION_INT_4_32 VERSION_INT(4,32,0,0)static const char *driverName = "asynMotorController";
static void asynMotorPollerC(void *drvPvt);
static void asynMotorMoveToHomeC(void *drvPvt);/** 创建一个asynMotorController对象* 所有参数只是被传递给了asynPortDriver基类。* 在调用这个基类构造器后,这个方法创建了在asynMotorDirver.h中定义的电机参数。*/
asynMotorController::asynMotorController(const char *portName, int numAxes, int numParams,int interfaceMask, int interruptMask,int asynFlags, int autoConnect, int priority, int stackSize): asynPortDriver(portName, numAxes,
#if MOTOR_ASYN_VERSION_INT < VERSION_INT_4_32NUM_MOTOR_DRIVER_PARAMS+numParams,
#endifinterfaceMask | asynOctetMask | asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynGenericPointerMask | asynDrvUserMask,interruptMask | asynOctetMask | asynInt32Mask | asynFloat64Mask | asynFloat64ArrayMask | asynGenericPointerMask,asynFlags, autoConnect, priority, stackSize),shuttingDown_(0), numAxes_(numAxes)
{static const char *functionName = "asynMotorController";/* parameters创建电机参数的基本集合 */createParam(motorMoveRelString, asynParamFloat64, &motorMoveRel_);createParam(motorMoveAbsString, asynParamFloat64, &motorMoveAbs_);createParam(motorMoveVelString, asynParamFloat64, &motorMoveVel_);createParam(motorHomeString, asynParamFloat64, &motorHome_);createParam(motorStopString, asynParamInt32, &motorStop_);createParam(motorVelocityString, asynParamFloat64, &motorVelocity_);createParam(motorVelBaseString, asynParamFloat64, &motorVelBase_);createParam(motorAccelString, asynParamFloat64, &motorAccel_);createParam(motorPositionString, asynParamFloat64, &motorPosition_);createParam(motorEncoderPositionString, asynParamFloat64, &motorEncoderPosition_);createParam(motorDeferMovesString, asynParamInt32, &motorDeferMoves_);createParam(motorMoveToHomeString, asynParamInt32, &motorMoveToHome_);createParam(motorResolutionString, asynParamFloat64, &motorResolution_);createParam(motorEncoderRatioString, asynParamFloat64, &motorEncoderRatio_);createParam(motorPGainString, asynParamFloat64, &motorPGain_);createParam(motorIGainString, asynParamFloat64, &motorIGain_);createParam(motorDGainString, asynParamFloat64, &motorDGain_);createParam(motorHighLimitString, asynParamFloat64, &motorHighLimit_);createParam(motorLowLimitString, asynParamFloat64, &motorLowLimit_);createParam(motorClosedLoopString, asynParamInt32, &motorClosedLoop_);createParam(motorPowerAutoOnOffString, asynParamInt32, &motorPowerAutoOnOff_);createParam(motorPowerOnDelayString, asynParamFloat64, &motorPowerOnDelay_);createParam(motorPowerOffDelayString, asynParamFloat64, &motorPowerOffDelay_);createParam(motorPowerOffFractionString,asynParamInt32, &motorPowerOffFraction_);createParam(motorPostMoveDelayString, asynParamFloat64, &motorPostMoveDelay_);createParam(motorStatusString, asynParamInt32, &motorStatus_);createParam(motorUpdateStatusString, asynParamInt32, &motorUpdateStatus_);createParam(motorStatusDirectionString, asynParamInt32, &motorStatusDirection_);createParam(motorStatusDoneString, asynParamInt32, &motorStatusDone_);createParam(motorStatusHighLimitString, asynParamInt32, &motorStatusHighLimit_);createParam(motorStatusAtHomeString, asynParamInt32, &motorStatusAtHome_);createParam(motorStatusSlipString, asynParamInt32, &motorStatusSlip_);createParam(motorStatusPowerOnString, asynParamInt32, &motorStatusPowerOn_);createParam(motorStatusFollowingErrorString, asynParamInt32, &motorStatusFollowingError_);createParam(motorStatusHomeString, asynParamInt32, &motorStatusHome_);createParam(motorStatusHasEncoderString,asynParamInt32, &motorStatusHasEncoder_);createParam(motorStatusProblemString, asynParamInt32, &motorStatusProblem_);createParam(motorStatusMovingString, asynParamInt32, &motorStatusMoving_);createParam(motorStatusGainSupportString,asynParamInt32, &motorStatusGainSupport_);createParam(motorStatusCommsErrorString,asynParamInt32, &motorStatusCommsError_);createParam(motorStatusLowLimitString, asynParamInt32, &motorStatusLowLimit_);createParam(motorStatusHomedString, asynParamInt32, &motorStatusHomed_);//这些是每个轴参数,用于传递更多motor基类信息给这个驱动:分辨率,方向,偏移量
createParam(motorRecResolutionString, asynParamFloat64, &motorRecResolution_);
createParam(motorRecDirectionString, asynParamInt32, &motorRecDirection_);
createParam(motorRecOffsetString, asynParamFloat64, &motorRecOffset_);//这些是每个控制器参数,用于轮廓移动
createParam(profileNumAxesString, asynParamInt32, &profileNumAxes_);
createParam(profileNumPointsString, asynParamInt32, &profileNumPoints_);
createParam(profileCurrentPointString, asynParamInt32, &profileCurrentPoint_);
createParam(profileNumPulsesString, asynParamInt32, &profileNumPulses_);
createParam(profileStartPulsesString, asynParamInt32, &profileStartPulses_);
createParam(profileEndPulsesString, asynParamInt32, &profileEndPulses_);
createParam(profileActualPulsesString, asynParamInt32, &profileActualPulses_);
createParam(profileNumReadbacksString, asynParamInt32, &profileNumReadbacks_);
createParam(profileTimeModeString, asynParamInt32, &profileTimeMode_);
createParam(profileFixedTimeString, asynParamFloat64, &profileFixedTime_);
createParam(profileTimeArrayString, asynParamFloat64Array,&profileTimeArray_);
createParam(profileAccelerationString, asynParamFloat64, &profileAcceleration_);
createParam(profileMoveModeString, asynParamInt32, &profileMoveMode_);
createParam(profileBuildString, asynParamInt32, &profileBuild_);
createParam(profileBuildStateString, asynParamInt32, &profileBuildState_);
createParam(profileBuildStatusString, asynParamInt32, &profileBuildStatus_);
createParam(profileBuildMessageString, asynParamOctet, &profileBuildMessage_);
createParam(profileExecuteString, asynParamInt32, &profileExecute_);
createParam(profileExecuteStateString, asynParamInt32, &profileExecuteState_);
createParam(profileExecuteStatusString, asynParamInt32, &profileExecuteStatus_);
createParam(profileExecuteMessageString,asynParamOctet, &profileExecuteMessage_);
createParam(profileAbortString, asynParamInt32, &profileAbort_);
createParam(profileReadbackString, asynParamInt32, &profileReadback_);
createParam(profileReadbackStateString, asynParamInt32, &profileReadbackState_);
createParam(profileReadbackStatusString,asynParamInt32, &profileReadbackStatus_);
createParam(profileReadbackMessageString,asynParamOctet, &profileReadbackMessage_);// 这些是每轴参数,用于轮廓移动
createParam(profileUseAxisString, asynParamInt32, &profileUseAxis_);
createParam(profilePositionsString, asynParamFloat64Array, &profilePositions_);
createParam(profileReadbacksString, asynParamFloat64Array, &profileReadbacks_);
createParam(profileFollowingErrorsString,asynParamFloat64Array, &profileFollowingErrors_);//根据总共的轴数分配存储asynMotorAxis结构体指针的空间
pAxes_ = (asynMotorAxis**) calloc(numAxes, sizeof(asynMotorAxis*));
pollEventId_ = epicsEventMustCreate(epicsEventEmpty); //创建用于轮询的事件
moveToHomeId_ = epicsEventMustCreate(epicsEventEmpty); maxProfilePoints_ = 0;
profileTimes_ = NULL;
setIntegerParam(profileExecuteState_, PROFILE_EXECUTE_DONE);moveToHomeAxis_ = 0;asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: constructor complete\n",driverName, functionName);
}asynMotorController::~asynMotorController()
{
}/** 在asyn客户端调用pasynManager->report()时,被调用。* 这个方法调用每个轴的report方法,并且接着调用基类asynPortDriver report方法。* 参数[in] fp FILE文件指针.* 参数[in] level :要输出的详细程度.
*/void asynMotorController::report(FILE *fp, int level)
{int axis;asynMotorAxis *pAxis;for (axis=0; axis<numAxes_; axis++) {pAxis = getAxis(axis);//根据轴编号,或者对应的asynMotorAxis结构体if (!pAxis) continue;pAxis->report(fp, level);}// 调用基类asynPortDriver::report(fp, level);
}/** 当asyn客户端调用时pasynInt32->write()被调用。* 从pasynUser中提取功能和轴编号.* 设置参数库中的值.* 如果功能是motorStop_,则它调用pAxis->stop().* 如果功能是motorUpdateStatus_,则它进行一次poll并且执行一次回调.* 为pasynUser->reason和address,调用任何注册的回调。* 如果电机驱动在asynInt32接口上支持控制器专用参数,它们将重新实现这个函数。* 它们应该为不是控制器专用的任何参数,调用这个基类方法。*参数[in] pasynUser 编码reason和address的asynUser结构体 *参数 [in] value 要写的值
*/
asynStatus asynMotorController::writeInt32(asynUser *pasynUser, epicsInt32 value)
{// 获取功能编码 int function = pasynUser->reason;asynStatus status=asynSuccess;asynMotorAxis *pAxis;int axis;static const char *functionName = "writeInt32";// 从asynUser结构体获取对应的asynMotorAxis结构体pAxis = getAxis(pasynUser);if (!pAxis) return asynError;// 获取轴的编号axis = pAxis->axisNo_;/* 在参数库中设置这个参数和回读*/pAxis->setIntegerParam(function, value);if (function == motorStop_) {//如果功能码motorStop_,获取加速度并且用这个加速度停止轴double accel;getDoubleParam(axis, motorAccel_, &accel);status = pAxis->stop(accel);} else if (function == motorDeferMoves_) {//?status = setDeferredMoves(value);} else if (function == motorClosedLoop_) {//如果功能码motorClosedLoop_,设置轴闭环情况status = pAxis->setClosedLoop(value);} else if (function == motorUpdateStatus_) {//如果功能码motorUpdateStatus_bool moving;/* 做一次查询, 并且接着执行一次回调 */poll();status = pAxis->poll(&moving);pAxis->statusChanged_ = 1;} else if (function == profileBuild_) {status = buildProfile();} else if (function == profileExecute_) {status = executeProfile();} else if (function == profileAbort_) {status = abortProfile();} else if (function == profileReadback_) {status = readbackProfile();} else if (function == motorMoveToHome_) {if (value == 1) {//进行归零的轴asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s:: Starting a move to home for axis %d\n", driverName, functionName, axis);moveToHomeAxis_ = axis;epicsEventSignal(moveToHomeId_);}}/* 进行回调,因此更高层看到任何变化 */pAxis->callParamCallbacks();if (status)asynPrint(pasynUser, ASYN_TRACE_ERROR,"%s:%s error, status=%d axis=%d, function=%d, value=%d\n",driverName, functionName, status, axis, function, value);elseasynPrint(pasynUser, ASYN_TRACEIO_DRIVER,"%s:%s:: axis=%d, function=%d, value=%d\n",driverName, functionName, axis, function, value);return status;
}/** 当asyn客户端调用pasynFloat64->write()时,被调用.* 从pasynUser提取功能和轴编号.* 设置参数库中这个值.* 如果功能是motorMoveRel_, motorMoveAbs_, motorMoveVel_, motorHome_, 或 motorPosition_,* 则它调用pAxis->move(), pAxis->moveVelocity(), pAxis->home(), 或 pAxis->setPosition().* 为这个pasynUser->reason和address,调用任何已经注册的回调。* 如果电机驱动支持asynFloat64接口上控制器专用参数,电机驱动将重新实现这个函数。* 参数[in] paysnUser:编码reason和地址的结构体User* 参数[in] value:要写的值. */
asynStatus asynMotorController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
{int function = pasynUser->reason;double baseVelocity, velocity, acceleration;asynMotorAxis *pAxis;int axis;int forwards;int autoPower = 0;double autoPowerOnDelay = 0.0;asynStatus status = asynError;static const char *functionName = "writeFloat64";// 获取asynMotorAxis结构体pAxis = getAxis(pasynUser);if (!pAxis) return asynError;// 获取轴编号axis = pAxis->axisNo_;// 获取轴的两个参数getIntegerParam(axis, motorPowerAutoOnOff_, &autoPower);getDoubleParam(axis, motorPowerOnDelay_, &autoPowerOnDelay);/* 设置参数库中参数和回调 */status = pAxis->setDoubleParam(function, value);// 相对移动if (function == motorMoveRel_) {if (autoPower == 1) {status = pAxis->setClosedLoop(true);pAxis->setWasMovingFlag(1);epicsThreadSleep(autoPowerOnDelay);}// 获取轴的基速度,速度,加速度getDoubleParam(axis, motorVelBase_, &baseVelocity);getDoubleParam(axis, motorVelocity_, &velocity);getDoubleParam(axis, motorAccel_, &acceleration);// 进行相对移动status = pAxis->move(value, 1, baseVelocity, velocity, acceleration);// 设置移动结束标记pAxis->setIntegerParam(motorStatusDone_, 0);pAxis->callParamCallbacks();wakeupPoller();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d move relative by %f, base velocity=%f, velocity=%f, acceleration=%f\n",driverName, functionName, portName, pAxis->axisNo_, value, baseVelocity, velocity, acceleration );} else if (function == motorMoveAbs_) { // 绝对移动if (autoPower == 1) {status = pAxis->setClosedLoop(true);pAxis->setWasMovingFlag(1);epicsThreadSleep(autoPowerOnDelay);}getDoubleParam(axis, motorVelBase_, &baseVelocity);getDoubleParam(axis, motorVelocity_, &velocity);getDoubleParam(axis, motorAccel_, &acceleration);status = pAxis->move(value, 0, baseVelocity, velocity, acceleration);pAxis->setIntegerParam(motorStatusDone_, 0);pAxis->callParamCallbacks();wakeupPoller();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d move absolute to %f, base velocity=%f, velocity=%f, acceleration=%f\n",driverName, functionName, portName, pAxis->axisNo_, value, baseVelocity, velocity, acceleration );} else if (function == motorMoveVel_) {/以指定速度移动if (autoPower == 1) {status = pAxis->setClosedLoop(true);pAxis->setWasMovingFlag(1);epicsThreadSleep(autoPowerOnDelay);}getDoubleParam(axis, motorVelBase_, &baseVelocity);getDoubleParam(axis, motorAccel_, &acceleration);status = pAxis->moveVelocity(baseVelocity, value, acceleration);pAxis->setIntegerParam(motorStatusDone_, 0);pAxis->callParamCallbacks();wakeupPoller();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set port %s, axis %d move with velocity of %f, acceleration=%f\n",driverName, functionName, portName, pAxis->axisNo_, value, acceleration);// 注意:在asynFloat64接口上发生了motorHome命令,即使这个值(方向)是一个真正的整数} else if (function == motorHome_) {if (autoPower == 1) {status = pAxis->setClosedLoop(true);pAxis->setWasMovingFlag(1);epicsThreadSleep(autoPowerOnDelay);}getDoubleParam(axis, motorVelBase_, &baseVelocity);getDoubleParam(axis, motorVelocity_, &velocity);getDoubleParam(axis, motorAccel_, &acceleration);forwards = (value == 0) ? 0 : 1; //确定方向status = pAxis->home(baseVelocity, velocity, acceleration, forwards);pAxis->setIntegerParam(motorStatusDone_, 0);pAxis->callParamCallbacks();wakeupPoller();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d to home %s, base velocity=%f, velocity=%f, acceleration=%f\n",driverName, functionName, portName, pAxis->axisNo_, (forwards?"FORWARDS":"REVERSE"), baseVelocity, velocity, acceleration);} else if (function == motorPosition_) {// 设置电机位置status = pAxis->setPosition(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d to position=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorEncoderPosition_) {// 设置编码器位置status = pAxis->setEncoderPosition(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d to encoder position=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorHighLimit_) {// 设置高限位status = pAxis->setHighLimit(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d high limit=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorLowLimit_) { // 设置低限位status = pAxis->setLowLimit(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d low limit=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorPGain_) { // 设置比率增益status = pAxis->setPGain(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d proportional gain=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorIGain_) { // 设置积分增益status = pAxis->setIGain(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d integral gain=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorDGain_) { //设置微分增益status = pAxis->setDGain(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d derivative gain=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);} else if (function == motorEncoderRatio_) { // 设置编码器比率status = pAxis->setEncoderRatio(value);pAxis->callParamCallbacks();asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: Set driver %s, axis %d encoder ratio=%f\n",driverName, functionName, portName, pAxis->axisNo_, value);}/* 进行回调,因此更高层看到任何变化*/pAxis->callParamCallbacks();if (status)asynPrint(pasynUser, ASYN_TRACE_ERROR,"%s:%s error, status=%d axis=%d, function=%d, value=%f\n",driverName, functionName, status, axis, function, value);elseasynPrint(pasynUser, ASYN_TRACEIO_DRIVER,"%s:%s:: axis=%d, function=%d, value=%f\n",driverName, functionName, axis, function, value);return status;}/** 当asyn客户端调用pasynFloat64Array->write()时,被调用.* 参数[in] pasynUser :编码reason和address的pasynUser结构体* 参数[in] value:指向要写入数组的指针 * 参数[in] nElements :要写的元素数目
*/
asynStatus asynMotorController::writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements)
{int function = pasynUser->reason;asynMotorAxis *pAxis;static const char *functionName = "writeFloat64Array";pAxis = getAxis(pasynUser);if (!pAxis) return asynError;// 能够写的元素数目上限为maxProfilePoints_if (nElements > maxProfilePoints_) nElements = maxProfilePoints_;// if (function == profileTimeArray_) {memcpy(profileTimes_, value, nElements*sizeof(double));}else if (function == profilePositions_) {pAxis->defineProfile(value, nElements);}else {asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,"%s:%s: unknown parameter number %d\n",driverName, functionName, function);return asynError ;}return asynSuccess;
}/** 当asyn客户端调用 pasynFloat64Array->read()时,被调用.* 从轮廓移动返回回调或跟随的误差数组* 参数[in] pasynUser 编码reason和address的pasynUser结构体.* 参数[in] value :指向要被读取的数组的指针* 参数[in] nElements:要读取元素的最大数目 .* 参数[in] nRead :实际范围的值数目*/
asynStatus asynMotorController::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value,size_t nElements, size_t *nRead)
{int function = pasynUser->reason;asynMotorAxis *pAxis;int numReadbacks;static const char *functionName = "readFloat64Array";pAxis = getAxis(pasynUser);if (!pAxis) return asynError;getIntegerParam(profileNumReadbacks_, &numReadbacks);*nRead = numReadbacks;if (*nRead > nElements) *nRead = nElements;if (function == profileReadbacks_) {memcpy(value, pAxis->profileReadbacks_, *nRead*sizeof(double));}else if (function == profileFollowingErrors_) {memcpy(value, pAxis->profileFollowingErrors_, *nRead*sizeof(double));}else {asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,"%s:%s: unknown parameter number %d\n",driverName, functionName, function);return asynError ;}return asynSuccess;
}/** 当asyn客户端调用pasynGenericPointer->read()时,被调用。* 在输入指针的内存位置构建一个聚合的MotorStatus结构体* 参数[in] pasynUser:编码reason和address的asynUser结构体* 参数[in] pointer: 指向返回的MotorStatus对象的指针*/
asynStatus asynMotorController::readGenericPointer(asynUser *pasynUser, void *pointer)
{MotorStatus *pStatus = (MotorStatus *)pointer; // 指向传递的地址int axis;asynMotorAxis *pAxis;static const char *functionName = "readGenericPointer";//获取传入pasynUser指向结构体对应的asynMotorAxis地址pAxis = getAxis(pasynUser);if (!pAxis) return asynError;// 获取轴编号axis = pAxis->axisNo_;// ? 也是获取轴编号getAddress(pasynUser, &axis);// 获取电机状态,电机位置,电机编码器位置,电机速度getIntegerParam(axis, motorStatus_, (int *)&pStatus->status);getDoubleParam(axis, motorPosition_, &pStatus->position);getDoubleParam(axis, motorEncoderPosition_, &pStatus->encoderPosition);getDoubleParam(axis, motorVelocity_, &pStatus->velocity);asynPrint(pasynUser, ASYN_TRACE_FLOW,"%s:%s: MotorStatus = status%d, position=%f, encoder position=%f, velocity=%f\n",driverName, functionName, pStatus->status, pStatus->position, pStatus->encoderPosition, pStatus->velocity);return asynSuccess;
}/** 返回一个指向一个asynMotorAxis对象的指针. * 如果在pasynUser中编码的轴编号无效,返回NULL。* 派生类将重新实现这个函数,返回一个指向派生轴类型的指针* 输入[in] pasynUser 编码这个轴索引号的asynUser结构体
*/
asynMotorAxis* asynMotorController::getAxis(asynUser *pasynUser)
{int axisNo;getAddress(pasynUser, &axisNo); //从pasynUser传入的结构体获取轴编号return getAxis(axisNo);
}/** Processes deferred moves. 处理推迟的移动。* 参数[in] deferMoves : 推迟移动直到之后(true)或者现在处理移动(false)
**/
asynStatus asynMotorController::setDeferredMoves(bool deferMoves)
{return asynSuccess;
}/** 返回一个指向一个asynMotorAxis的指针* 如果轴编号无效,返回NULL* 派生类将重新实现这个函数,返回一个指向派生的轴类型的指针* 参数[in] axisNo 轴的索引编号.*/
asynMotorAxis* asynMotorController::getAxis(int axisNo)
{if ((axisNo < 0) || (axisNo >= numAxes_)) return NULL; // 传入的轴索引编号无效return pAxes_[axisNo];
}/** 启动一个电机查询线程。* 派生类一般将在它们的构造函数接近结束时调用这个。* 派生类一般可以使用这个查询线程的基类实现方式,但如果需要,可以自由地重新实现它。* 参数[in] movingPollPeriod : 当任意轴正移动时,查询之间的时间* 参数[in] idlePollPeriod :当没有轴正移动时,查询之间的时间T* 参数[in] forcedFastPolls : 在唤醒这个poller后,执行movingPollPeriod的次数* 对于已经通知轴启动后,不立即报告这个轴正在移动的控制器,这需要非零。
*/
asynStatus asynMotorController::startPoller(double movingPollPeriod, double idlePollPeriod, int forcedFastPolls)
{movingPollPeriod_ = movingPollPeriod;idlePollPeriod_ = idlePollPeriod;forcedFastPolls_ = forcedFastPolls;epicsThreadCreate("motorPoller",epicsThreadPriorityLow,epicsThreadGetStackSize(epicsThreadStackMedium),(EPICSTHREADFUNC)asynMotorPollerC, (void *)this);return asynSuccess;
}/** 唤醒poller线程,使其在movingPollingPeriod_时启动查询。* 一般在通知一个轴移动后,这被调用,因此这个poller立即快速地启动查询。
*/
asynStatus asynMotorController::wakeupPoller()
{epicsEventSignal(pollEventId_);return asynSuccess;
}/** 查询asynMotorController (非一个特定的asynMotorAxis).* 就在基类asynMotorPoller线程为每个轴调用asynMotorAxis前,它调用这个这个方法一次* 这个基类什么也没有实现。如果有需要被查询的整个控制器参数,派生类可以实现这个方法。* 在某些情况下,它也可以用于提高效率。* 例如,某些控制器可以在单条命令中返回所有轴的状态或位置。* 在此情况下,asynMotorController::poll()可读取那些信息,并且接着asynMotorAxis::poll()* 可以才从结果提供轴相关的信息。*/
asynStatus asynMotorController::poll()
{return asynSuccess;
}static void asynMotorPollerC(void *drvPvt)
{asynMotorController *pController = (asynMotorController*)drvPvt;pController->asynMotorPoller();
}/** 默认的poller函数,它运行在由asynMotorController::startPoller()创建的线程中。* 这个基类实现可以被大多数派生类使用* 它在没有轴移动时以idlePollPeriod_查询,而在任何轴在移动时以movingPollPeriod_查询* 当asynMotorController::wakeupPoller()被调用时,它将立即进行一次查询,并且如果没有轴在移动,在恢复到idlePollPeriod_前,用movingPollPeriod进行forcedFastPolls_次。* 当它正在查询时,它获取端口驱动上的锁。*/
void asynMotorController::asynMotorPoller()
{double timeout;int i;int forcedFastPolls=0;bool anyMoving;bool moving;epicsTimeStamp nowTime;double nowTimeSecs = 0.0;asynMotorAxis *pAxis;int autoPower = 0;double autoPowerOffDelay = 0.0;int status;timeout = idlePollPeriod_;wakeupPoller(); /* 启动时,执行查询 */while(1) {// 根据timeout,带或不带超时时间地等待查询信号if (timeout != 0.) status = epicsEventWaitWithTimeout(pollEventId_, timeout);else status = epicsEventWait(pollEventId_);if (status == epicsEventWaitOK) {/* * 我们获取了一个事件,而不是超时。这是因为其它软件知道一个轴应该已经更高了状态* (启动地移动等)。执行最少次数的快速查询,因为前几次查询,控制器状态可能还没有变化。*/forcedFastPolls = forcedFastPolls_;}anyMoving = false;lock();if (shuttingDown_) {unlock();break;}poll();// 根据轴编号,获取对应的asynMotorAxis结构体for (i=0; i<numAxes_; i++) {pAxis=getAxis(i);if (!pAxis) continue;// 获取motorPowerAutoOnOff_和motorPowerOffDelay_索引对应的参数值getIntegerParam(i, motorPowerAutoOnOff_, &autoPower);getDoubleParam(i, motorPowerOffDelay_, &autoPowerOffDelay);pAxis->poll(&moving);if (moving) {anyMoving = true;pAxis->setWasMovingFlag(1);} else {// 之前设置了移动标记,但现在停止了if ((pAxis->getWasMovingFlag() == 1) && (autoPower == 1)) {pAxis->setDisableFlag(1);pAxis->setWasMovingFlag(0);epicsTimeGetCurrent(&nowTime);pAxis->setLastEndOfMoveTime(nowTime.secPastEpoch + (nowTime.nsec / 1.e9));}}// 如果发现了移动结束,// 我们不再移动,// 电源自动关闭使能// 电源自动关闭延时计时器失效// 电源自动关闭驱动if ((!moving) && (autoPower == 1) && (pAxis->getDisableFlag() == 1)) {epicsTimeGetCurrent(&nowTime);nowTimeSecs = nowTime.secPastEpoch + (nowTime.nsec / 1.e9);if ((nowTimeSecs - pAxis->getLastEndOfMoveTime()) >= autoPowerOffDelay) {pAxis->setClosedLoop(0);pAxis->setDisableFlag(0);}}}if (forcedFastPolls > 0) {timeout = movingPollPeriod_;forcedFastPolls--;} else if (anyMoving) {timeout = movingPollPeriod_;} else {timeout = idlePollPeriod_;}unlock();}
}/*** 启动处理移动轴到它们归零位置的线程* 在对象初始化时,这是被派生的具体控制器类调用,因此,不需要这个功能的驱动没有这个线程的开销*/
asynStatus asynMotorController::startMoveToHomeThread()
{epicsThreadCreate("motorMoveToHome",epicsThreadPriorityMedium,epicsThreadGetStackSize(epicsThreadStackMedium),(EPICSTHREADFUNC)asynMotorMoveToHomeC, (void *)this);return asynSuccess;
}static void asynMotorMoveToHomeC(void *drvPvt)
{asynMotorController *pController = (asynMotorController*)drvPvt;pController->asynMotorMoveToHome();
}/*** 默认移动到归零的线程。不通常被重写*/
void asynMotorController::asynMotorMoveToHome()
{asynMotorAxis *pAxis;int status = 0;static const char *functionName = "asynMotorMoveToHome";while(1) {status = epicsEventWait(moveToHomeId_); // 等待信号moveToHomeId_if (status == epicsEventWaitOK) {pAxis = getAxis(this->moveToHomeAxis_); // 更加归零轴编号,获取对应的asynMotorAxis对象if (!pAxis) continue;status = pAxis->doMoveToHome(); // 调用轴对象的归零方法if (status) {asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,"%s:%s: move to home failed in asynMotorController::asynMotorMoveToHome. Axis number=%d\n",driverName, functionName, this->moveToHomeAxis_);}}}
}/** 写字符串到控制器。* 用字符串的默认要写位置和默认超时时间调用writeController()。*/
asynStatus asynMotorController::writeController()
{ // 字符串默认位置在outString_, 默认超时时间DEFAULT_CONTROLLER_TIMEOUTreturn writeController(outString_, DEFAULT_CONTROLLER_TIMEOUT);
}/** 写一个字符串到控制器* 参数[in] output :要被写的字符串.* 参数[in] timeout : 在返回一个错误前的超时时间.*/
asynStatus asynMotorController::writeController(const char *output, double timeout)
{size_t nwrite;asynStatus status;// const char *functionName="writeController";status = pasynOctetSyncIO->write(pasynUserController_, output,strlen(output), timeout, &nwrite);return status ;
}/** 写一个字符串到控制器并且回读响应,用输入和输出字符串的默认位置和默认事件调用 writeReadController()*/
asynStatus asynMotorController::writeReadController()
{size_t nread;return writeReadController(outString_, inString_, sizeof(inString_), &nread, DEFAULT_CONTROLLER_TIMEOUT);
}/** Writes a string to the controller and reads a response 写一个字符串到控制器并读取响应.* 参数[in] output :指向输出字符串的指针* 参数[out] input :指向输入字符串位置的指针* 参数[in] maxChars : 输入缓冲区的尺寸* 参数[out] nread :Number of characters read. 读取字符的数目* 参数[out] timeout :在返回错误前的超时时间T
*/
asynStatus asynMotorController::writeReadController(const char *output, char *input,size_t maxChars, size_t *nread, double timeout)
{size_t nwrite;asynStatus status;int eomReason;// const char *functionName="writeReadController";status = pasynOctetSyncIO->writeRead(pasynUserController_, output,strlen(output), input, maxChars, timeout,&nwrite, nread, &eomReason);return status;
}/* 这些是用于轮廓移动的函数 */
/** 初始化一个多轴的轮廓移动 */
asynStatus asynMotorController::initializeProfile(size_t maxProfilePoints)
{int axis;asynMotorAxis *pAxis;// static const char *functionName = "initializeProfile";maxProfilePoints_ = maxProfilePoints;if (profileTimes_) free(profileTimes_);profileTimes_ = (double *)calloc(maxProfilePoints, sizeof(double));for (axis=0; axis<numAxes_; axis++) {pAxis = getAxis(axis);if (!pAxis) continue;pAxis->initializeProfile(maxProfilePoints);}return asynSuccess;
}/** 构建一个多轴的轮廓移动 */
asynStatus asynMotorController::buildProfile()
{//static const char *functionName = "buildProfile";asynMotorAxis *pAxis;int i;int status=0;double time;int timeMode;int numPoints;status |= getIntegerParam(profileTimeMode_, &timeMode);status |= getDoubleParam(profileFixedTime_, &time);status |= getIntegerParam(profileNumPoints_, &numPoints);if (status) return asynError;if (timeMode == PROFILE_TIME_MODE_FIXED) {memset(profileTimes_, 0, maxProfilePoints_*sizeof(double));for (i=0; i<numPoints; i++) {profileTimes_[i] = time;}}for (i=0; i<numAxes_; i++) {pAxis = getAxis(i);if (!pAxis) continue;pAxis->buildProfile();}return asynSuccess;
}/** 执行一个多轴的轮廓移动 */
asynStatus asynMotorController::executeProfile()
{// static const char *functionName = "executeProfile";int axis;asynMotorAxis *pAxis;for (axis=0; axis<numAxes_; axis++) {pAxis = getAxis(axis);if (!pAxis) continue;pAxis->executeProfile();}return asynSuccess;
}/** 取消一个轮廓移动 */
asynStatus asynMotorController::abortProfile()
{// static const char *functionName = "abortProfile";int axis;asynMotorAxis *pAxis;for (axis=0; axis<numAxes_; axis++) {pAxis = getAxis(axis);if (!pAxis) continue;pAxis->abortProfile();}return asynSuccess;
}/** 从一个多轴的轮廓移动回读实际电机位置 */
asynStatus asynMotorController::readbackProfile()
{// static const char *functionName = "readbackProfile";int axis;asynMotorAxis *pAxis;for (axis=0; axis<numAxes_; axis++) {pAxis = getAxis(axis);if (!pAxis) continue;pAxis->readbackProfile();}return asynSuccess;
}/** 在运行时,设置移动查询周期(秒为单位) */
asynStatus asynMotorController::setMovingPollPeriod(double movingPollPeriod)
{static const char *functionName = "setMovingPollPeriod";asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Setting moving poll period to %f\n",driverName, functionName, movingPollPeriod);lock();movingPollPeriod_ = movingPollPeriod;wakeupPoller();unlock();return asynSuccess;
}/** 运行时,设置空闲的轮询周期(以秒为单位)*/
asynStatus asynMotorController::setIdlePollPeriod(double idlePollPeriod)
{static const char *functionName = "setIdlePollPeriod";asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Setting idle poll period to %f\n",driverName, functionName, idlePollPeriod);lock();idlePollPeriod_ = idlePollPeriod;wakeupPoller();unlock();return asynSuccess;
}/**以下函数有C可链接的,并且可以直接或者从iocsh被调用
*/extern "C" {asynStatus setMovingPollPeriod(const char *portName, double movingPollPeriod)
{asynMotorController *pC;static const char *functionName = "setMovingPollPeriod";// 通过端口名称,查找asynMotorController结构体pC = (asynMotorController*) findAsynPortDriver(portName);if (!pC) {printf("%s:%s: Error port %s not found\n", driverName, functionName, portName);return asynError;}//在运行时,设置移动查询周期(秒为单位)return pC->setMovingPollPeriod(movingPollPeriod);
}asynStatus setIdlePollPeriod(const char *portName, double idlePollPeriod)
{asynMotorController *pC;static const char *functionName = "setIdlePollPeriod";pC = (asynMotorController*) findAsynPortDriver(portName);if (!pC) {printf("%s:%s: Error port %s not found\n", driverName, functionName, portName);return asynError;}// 运行时,设置空闲的轮询周期(以秒为单位)return pC->setIdlePollPeriod(idlePollPeriod);
}/*
*/
asynStatus asynMotorEnableMoveToHome(const char *portName, int axis, int distance)
{asynMotorController *pC = NULL;asynMotorAxis *pA = NULL;static const char *functionName = "asynMotorEnableMoveToHome";pC = (asynMotorController*) findAsynPortDriver(portName);if (!pC) {printf("%s:%s: Error port %s not found\n", driverName, functionName, portName);return asynError;}pA = pC->getAxis(axis);if (!pA) {printf("%s:%s: Error axis %d not found\n", driverName, functionName, axis);;return asynError;}if (distance<=0) {printf("%s:%s: Error distance must be positive integer axis=%d\n", driverName, functionName, axis);} else {pA->setReferencingModeMove(distance);}return asynSuccess;
}/* setMovingPollPeriod */
static const iocshArg setMovingPollPeriodArg0 = {"Controller port name", iocshArgString};
static const iocshArg setMovingPollPeriodArg1 = {"Axis number", iocshArgDouble};
static const iocshArg * const setMovingPollPeriodArgs[] = {&setMovingPollPeriodArg0,&setMovingPollPeriodArg1};
static const iocshFuncDef setMovingPollPeriodDef = {"setMovingPollPeriod", 2, setMovingPollPeriodArgs};static void setMovingPollPeriodCallFunc(const iocshArgBuf *args)
{setMovingPollPeriod(args[0].sval, args[1].dval);
}/* setIdlePollPeriod */
static const iocshArg setIdlePollPeriodArg0 = {"Controller port name", iocshArgString};
static const iocshArg setIdlePollPeriodArg1 = {"Axis number", iocshArgDouble};
static const iocshArg * const setIdlePollPeriodArgs[] = {&setIdlePollPeriodArg0,&setIdlePollPeriodArg1};
static const iocshFuncDef setIdlePollPeriodDef = {"setIdlePollPeriod", 2, setIdlePollPeriodArgs};static void setIdlePollPeriodCallFunc(const iocshArgBuf *args)
{setIdlePollPeriod(args[0].sval, args[1].dval);
}/* asynMotorEnableMoveToHome */
static const iocshArg asynMotorEnableMoveToHomeArg0 = {"Controller port name", iocshArgString};
static const iocshArg asynMotorEnableMoveToHomeArg1 = {"Axis number", iocshArgInt};
static const iocshArg asynMotorEnableMoveToHomeArg2 = {"Distance", iocshArgInt};
static const iocshArg * const asynMotorEnableMoveToHomeArgs[] = {&asynMotorEnableMoveToHomeArg0, &asynMotorEnableMoveToHomeArg1, &asynMotorEnableMoveToHomeArg2};
static const iocshFuncDef enableMoveToHome = {"asynMotorEnableMoveToHome", 3, asynMotorEnableMoveToHomeArgs};static void enableMoveToHomeCallFunc(const iocshArgBuf *args)
{asynMotorEnableMoveToHome(args[0].sval, args[1].ival, args[2].ival);
}static void asynMotorControllerRegister(void)
{iocshRegister(&setMovingPollPeriodDef, setMovingPollPeriodCallFunc);iocshRegister(&setIdlePollPeriodDef, setIdlePollPeriodCallFunc);iocshRegister(&enableMoveToHome, enableMoveToHomeCallFunc);
}
epicsExportRegistrar(asynMotorControllerRegister);} //extern C