电机控制器的基类,实际的电机控制器从这个类派生
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_32
NUM_MOTOR_DRIVER_PARAMS+numParams,
#endif
interfaceMask | 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);
else
asynPrint(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);
else
asynPrint(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_TIMEOUT
return 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