asynMotorController控制器类

电机控制器的基类,实际的电机控制器从这个类派生

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/419714.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【初识Linux】Linux下基本指令

01. ls 指令 语法&#xff1a; ls [选项][目录或文件] 功能&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 . 开头的隐含文件。 -…

Linux实用操作

简介&#xff1a;个人学习分享&#xff0c;如有错误&#xff0c;欢迎批评指正。 一、常用快捷键 ctrl c 强制停止 Linux某些程序的运行&#xff0c;如果想要强制停止它&#xff0c;可以使用快捷键ctrl c 命令输入错误&#xff0c;也可以通过快捷键ctrl c&#xff0c;退出当…

基于vue框架的车辆信息检索系统的设计与实现6eph8(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;车辆信息,事故登记,维修记录,用户,汽车类型,保养记录,违章信息,年检记录 开题报告内容 基于Vue框架的车辆信息检索系统的设计与实现开题报告 一、项目背景与意义 随着汽车市场的不断扩大和车辆保有量的急剧增加&#xff0c;车辆信息的…

【无人机设计与控制】 四轴飞行器的位移控制

摘要 本文介绍了一种四轴飞行器的位移控制方法&#xff0c;并通过Simulink模型进行仿真和验证。该方法通过PID控制器对飞行器的位移进行精确调节&#xff0c;以实现飞行器在三维空间中的稳定定位和路径跟踪。通过参数调节&#xff0c;能够适应不同的飞行任务需求&#xff0c;确…

梨花声音研修院退费配音市场现状分析

配音市场近年来显示出强劲的增长势头&#xff0c;涵盖了影视作品、广告、游戏、动画、电子书、企业宣传片等多个领域。随着全球化进程的加速和数字媒体的快速发展&#xff0c;配音需求不断增加&#xff0c;市场前景广阔。本文将详细探讨配音市场的现状&#xff0c;从市场规模、…

java中实现缓存的几种方式

一、通过HashMap实现缓存 这种方式可以简单实现本地缓存&#xff0c;但是实际开发中不推荐使用&#xff0c;下面我们来实现一下这种方式。 首先创建一个管理缓存的类 public class LocalCache {public static ConcurrentMap<String,String> cache new ConcurrentHashM…

SQL插入、更新和删除数据

SQL插入、更新和删除数据 一、直接向表插入数据 1.1、插入完整的行 这里所说的完整行指的是包含表内所有字段的数据行&#xff1b;假设表中有n个字段&#xff0c;则插入完整行的语法&#xff1a; INSERT INTO 表名或视图名 VALUES(字段1的值,字段2的值,字段3的值,...,字段n的…

基于Java+SpringBoot+Vue+MySQL的地方美食分享网站

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于SpringBootVue的地方美食分享网站【附源码文档】、前后…

【Redis入门到精通一】什么是Redis?

目录 Redis 1. Redis的背景知识 2.Redis特性 3.Redis的使用场景 4.Ubuntu上安装配置Redis Redis Redis在当今编程技术中的地位可以说非常重要&#xff0c;大多数互联网公司内部都在使用这个技术&#xff0c;熟练使用Redis已经成为开发人员的一个必备技能。 本章将带领读者…

JavaScript使用高德API显示地图

前言 在JavaScript中&#xff0c;使用Leaflet库显示地图是一种常见的做法。Leaflet是一个开源的JavaScript库&#xff0c;用于在Web应用程序中创建互动地图。它非常轻量级&#xff0c;易于使用&#xff0c;并且提供了多种功能&#xff0c;使开发者能够轻松地将地图集成到他们的…

“知识启航·新年新题”——2025年粉丝专属学术助力计划

一、活动背景与目的 为了感谢广大粉丝一直以来的支持与厚爱&#xff0c;我们特别推出“知识启航新年新题”2025年粉丝专属学术助力计划。本次活动旨在通过提供免费的开题报告、免费的任务书以及一系列学术指导服务&#xff0c;助力粉丝在新的一年里开启学术与项目研究的新篇章…

C# 获取系统使用情况

一个简单的小工具&#xff0c;主要用来获取当期的电脑信息以及内存的使用情况。本来也没想着写这个玩意&#xff0c;还不如随便下个相关的软件好使&#xff0c;但是前一段时间为了追查系统卡顿的问题&#xff0c;所以就加上了一段统计内存的代码&#xff0c;用来看看是否由这个…

DDComponentForAndroid:探索Android组件化方案

在现代Android应用开发中&#xff0c;随着应用规模的不断扩大&#xff0c;传统的单体应用架构已经无法满足快速迭代和维护的需求。组件化架构作为一种解决方案&#xff0c;可以将应用拆分成多个独立的模块&#xff0c;每个模块负责特定的功能&#xff0c;从而提高代码的可维护性…

PWR电源控制(低功耗模式)

1 PWR简介 1 程序后面是空循环&#xff0c;即使不用也会耗电&#xff0c;所以有了低功耗&#xff08;例如遥控器&#xff09; 2 也要保留唤醒模式&#xff0c;如串口接收数据中断唤醒&#xff0c;外部中断唤醒&#xff0c;RTC闹钟唤醒&#xff0c;在需要工作是&#xff0c;ST…

【redis】redis的特性和主要应用场景

文章目录 redis 的特性在内存中存储数据可编程的扩展能力持久化集群高可用快 redis 的应用场景实时数据存储缓存消息队列 redis 的特性 redis 的一些特性&#xff08;优点&#xff09;成就了它 在内存中存储数据 In-memory data structures MySQL 主要是通过“表”的方式来…

分享基于PDF.JS的移动端PDF阅读器代码

一、前言 在之前的文章《分享基于PDF.js的pdf阅读器代码》里提到了PC端基于PDF.js的阅读器&#xff0c;本文将提供针对移动端的版本。 二、pdfViewer 为了能够直接使用&#xff0c;这里分享一下经过简单修改后能直接使用的pdfViewer代码&#xff1a; pdfViewer代码目录&…

如何在红米手机中恢复已删除的照片?(6 种方式可供选择)

凭借出色的相机和实惠的价格&#xff0c;小米红米系列已成为全球知名品牌。但是&#xff0c;最近有些人抱怨他们在 红米设备上丢失了许多珍贵的图片或视频&#xff0c;并希望弄清楚如何从小米手机恢复已删除的照片。好吧&#xff0c;在小米设备上恢复已删除的视频/照片并不难。…

基于Pytorch框架的深度学习U2Net网络精细天空分割系统源码

第一步&#xff1a;准备数据 头发分割数据&#xff0c;总共有10276张图片&#xff0c;里面的像素值为0和1&#xff0c;所以看起来全部是黑的&#xff0c;不影响使用 第二步&#xff1a;搭建模型 级联模式 通常多个类似U-Net按顺序堆叠&#xff0c;以建立级联模型&#xff0c…

移动端视频编辑SDK解决方案,AI语音识别添加字幕

对于众多Vlog创作者而言&#xff0c;繁琐的字幕添加过程往往成为提升内容质量的绊脚石。为了彻底改变这一现状&#xff0c;美摄科技凭借其深厚的AI技术积累与创新的移动端视频编辑SDK解决方案&#xff0c;推出了革命性的AI语音识别添加字幕功能&#xff0c;让视频创作更加高效、…

【数据结构】LinkedList ------ java实现

知识框架图&#xff1a; LinkedList是一种常用的数据结构。底层是一个双向链表。每个节点包含数据以及指向前一个节点和后一个节点的引用。 一&#xff1a;LinkedList的使用 1.1 LinkedList的构造方法 方法 解释LinkedList() 无参构造public LinkedList(Collection<? exte…