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_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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值