/* asynMotorAxis.cpp * * Mark Rivers * * This file defines the base class for an asynMotorAxis. It is the class * from which real motor axes are derived. */ #include #include #include #include #define epicsExportSharedSymbols #include #include "asynMotorAxis.h" #include "asynMotorController.h" static const char *driverName = "asynMotorAxis"; /** Creates a new asynMotorAxis object. * \param[in] pC Pointer to the asynMotorController to which this axis belongs. * \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1. * * Checks that pC is not null, and that axisNo is in the valid range. * Sets a pointer to itself in pC->pAxes[axisNo_]. * Connects pasynUser_ to this asyn port and axisNo. */ asynMotorAxis::asynMotorAxis(class asynMotorController *pC, int axisNo) : pC_(pC), axisNo_(axisNo), statusChanged_(1) { static const char *functionName = "asynMotorAxis"; if (!pC) { printf("%s:%s: Error, controller is NULL\n", driverName, functionName); return; } if ((axisNo < 0) || (axisNo >= pC->numAxes_)) { printf("%s:%s: Error, axis=%d is not in range 0 to %d\n", driverName, functionName, axisNo, pC->numAxes_-1); return; } pC->pAxes_[axisNo] = this; status_.status = 0; profilePositions_ = NULL; profileReadbacks_ = NULL; profileFollowingErrors_ = NULL; /* Used to keep track of referencing mode in the driver.*/ referencingMode_ = 0; /* Used to enable/disable move to home, and to tell driver how far to move.*/ referencingModeMove_ = 0; wasMovingFlag_ = 0; disableFlag_ = 0; lastEndOfMoveTime_ = 0; // Create the asynUser, connect to this axis pasynUser_ = pasynManager->createAsynUser(NULL, NULL); pasynManager->connectDevice(pasynUser_, pC->portName, axisNo); // Initialize some parameters setIntegerParam(pC_->motorPowerAutoOnOff_, 0); setDoubleParam(pC_->motorPowerOffDelay_, 0.); setDoubleParam(pC_->motorPowerOnDelay_, 0.); } asynMotorAxis::~asynMotorAxis() { } /** Move the motor to an absolute location or by a relative amount. * \param[in] position The absolute position to move to (if relative=0) or the relative distance to move * by (if relative=1). Units=steps. * \param[in] relative Flag indicating relative move (1) or absolute move (0). * \param[in] minVelocity The initial velocity, often called the base velocity. Units=steps/sec. * \param[in] maxVelocity The maximum velocity, often called the slew velocity. Units=steps/sec. * \param[in] acceleration The acceleration value. Units=steps/sec/sec. */ asynStatus asynMotorAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration) { return asynSuccess; } /** Move the motor at a fixed velocity until told to stop. * \param[in] minVelocity The initial velocity, often called the base velocity. Units=steps/sec. * \param[in] maxVelocity The maximum velocity, often called the slew velocity. Units=steps/sec. * \param[in] acceleration The acceleration value. Units=steps/sec/sec. */ asynStatus asynMotorAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration) { return asynSuccess; } /** Move the motor to the home position. * \param[in] minVelocity The initial velocity, often called the base velocity. Units=steps/sec. * \param[in] maxVelocity The maximum velocity, often called the slew velocity. Units=steps/sec. * \param[in] acceleration The acceleration value. Units=steps/sec/sec. * \param[in] forwards Flag indicating to move the motor in the forward direction(1) or reverse direction(0). * Some controllers need to be told the direction, others know which way to go to home. */ asynStatus asynMotorAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards) { return asynSuccess; } /** Stop the motor. * \param[in] acceleration The acceleration value. Units=steps/sec/sec. */ asynStatus asynMotorAxis::stop(double acceleration) { return asynSuccess; } /** Poll the axis. * This function should read the controller position, encoder position, and as many of the motorStatus flags * as the hardware supports. It should call setIntegerParam() and setDoubleParam() for each item that it polls, * and then call callParamCallbacks() at the end. * \param[out] moving A flag that the function must set indicating that the axis is moving (1) or done (0). */ asynStatus asynMotorAxis::poll(bool *moving) { return asynSuccess; } /** Set the current position of the motor. * \param[in] position The new absolute motor position that should be set in the hardware. Units=steps.*/ asynStatus asynMotorAxis::setPosition(double position) { return asynSuccess; } /** Set the current encoder position of the motor. * \param[in] position The new absolute encoder position that should be set in the hardware. Units=steps.*/ asynStatus asynMotorAxis::setEncoderPosition(double position) { return asynSuccess; } /** Set the high limit position of the motor. * \param[in] highLimit The new high limit position that should be set in the hardware. Units=steps.*/ asynStatus asynMotorAxis::setHighLimit(double highLimit) { return asynSuccess; } /** Set the low limit position of the motor. * \param[in] lowLimit The new low limit position that should be set in the hardware. Units=steps.*/ asynStatus asynMotorAxis::setLowLimit(double lowLimit) { return asynSuccess; } /** Set the proportional gain of the motor. * \param[in] pGain The new proportional gain. */ asynStatus asynMotorAxis::setPGain(double pGain) { return asynSuccess; } /** Set the integral gain of the motor. * \param[in] iGain The new integral gain. */ asynStatus asynMotorAxis::setIGain(double iGain) { return asynSuccess; } /** Set the derivative gain of the motor. * \param[in] dGain The new derivative gain. */ asynStatus asynMotorAxis::setDGain(double dGain) { return asynSuccess; } /** Set the motor closed loop status. * \param[in] closedLoop true = close loop, false = open looop. */ asynStatus asynMotorAxis::setClosedLoop(bool closedLoop) { return asynSuccess; } /** Set the motor encoder ratio. * \param[in] ratio The new encoder ratio */ asynStatus asynMotorAxis::setEncoderRatio(double ratio) { return asynSuccess; } void asynMotorAxis::report(FILE *fp, int details) { } /** * Default implementation of doMoveToHome. * Derived classes need to implement this to actually perform the * axis move to the home position. */ asynStatus asynMotorAxis::doMoveToHome() { static const char *functionName="doMoveToHome"; asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s:%s: Axis=%d no implementation\n", driverName, functionName, pC_->moveToHomeAxis_); return asynSuccess; } /** * Set method for referencingModeMove_ */ void asynMotorAxis::setReferencingModeMove(int distance) { referencingModeMove_ = distance; } /** * Get method for referencingModeMove_ */ int asynMotorAxis::getReferencingModeMove() { return referencingModeMove_; } // We implement the setIntegerParam, setDoubleParam, and callParamCallbacks methods so we can construct // the aggregate status structure and do callbacks on it /** Sets the value for an integer for this axis in the parameter library. * This function takes special action if the parameter is one of the motorStatus parameters * (motorStatusDirection_, motorStatusHomed_, etc.). In that case it sets or clears the appropriate * bit in its private MotorStatus.status structure and if that status has changed sets a flag to * do callbacks to devMotorAsyn when callParamCallbacks() is called. * \param[in] function The function (parameter) number * \param[in] value Value to set */ asynStatus asynMotorAxis::setIntegerParam(int function, int value) { int mask; epicsUInt32 status=0; // This assumes the parameters defined above are in the same order as the bits the motor record expects! if (function >= pC_->motorStatusDirection_ && function <= pC_->motorStatusHomed_) { status = status_.status; mask = 1 << (function - pC_->motorStatusDirection_); if (value) status |= mask; else status &= ~mask; if (status != status_.status) { status_.status = status; statusChanged_ = 1; } } // Call the base class method pC_->setIntegerParam(axisNo_, pC_->motorStatus_, status); return pC_->setIntegerParam(axisNo_, function, value); } /** Sets the value for a double for this axis in the parameter library. * This function takes special action if the parameter is motorPosition_ or motorEncoderPosition_. * In that case it sets the value in the private MotorStatus structure and if the value has changed * then sets a flag to do callbacks to devMotorAsyn when callParamCallbacks() is called. * \param[in] function The function (parameter) number * \param[in] value Value to set */ asynStatus asynMotorAxis::setDoubleParam(int function, double value) { if (function == pC_->motorPosition_) { if (value != status_.position) { statusChanged_ = 1; status_.position = value; } } else if (function == pC_->motorEncoderPosition_) { if (value != status_.encoderPosition) { statusChanged_ = 1; status_.encoderPosition = value; } } // Call the base class method return pC_->setDoubleParam(axisNo_, function, value); } /** * Sets the value for a string for this axis in the parameter library. * \param[in] function The function (parameter) number * \param[in] value Value to set */ asynStatus asynMotorAxis::setStringParam(int function, const char *value) { // Call the base class method return pC_->setStringParam(axisNo_, function, value); } /** Calls the callbacks for any parameters that have changed for this axis in the parameter library. * This function takes special action if the aggregate MotorStatus structure has changed. * In that case it does callbacks on the asynGenericPointer interface, typically to devMotorAsyn. */ asynStatus asynMotorAxis::callParamCallbacks() { if (statusChanged_) { statusChanged_ = 0; pC_->doCallbacksGenericPointer((void *)&status_, pC_->motorStatus_, axisNo_); } return pC_->callParamCallbacks(axisNo_); } /* These are the functions for profile moves */ asynStatus asynMotorAxis::initializeProfile(size_t maxProfilePoints) { if (profilePositions_) free(profilePositions_); profilePositions_ = (double *)calloc(maxProfilePoints, sizeof(double)); if (profileReadbacks_) free(profileReadbacks_); profileReadbacks_ = (double *)calloc(maxProfilePoints, sizeof(double)); if (profileFollowingErrors_) free(profileFollowingErrors_); profileFollowingErrors_ = (double *)calloc(maxProfilePoints, sizeof(double)); return asynSuccess; } /** Function to define the motor positions for a profile move. * This base class function converts the positions from user units * to controller units, using the profileMotorOffset_, profileMotorDirection_, * and profileMotorResolution_ parameters. * \param[in] positions Array of profile positions for this axis in user units. * \param[in] numPoints The number of positions in the array. */ asynStatus asynMotorAxis::defineProfile(double *positions, size_t numPoints) { size_t i; double resolution; double offset; int direction; double scale; int status=0; static const char *functionName = "defineProfile"; asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s:%s: axis=%d, numPoints=%d, positions[0]=%f\n", driverName, functionName, axisNo_, (int)numPoints, positions[0]); if (numPoints > pC_->maxProfilePoints_) return asynError; status |= pC_->getDoubleParam(axisNo_, pC_->motorRecResolution_, &resolution); status |= pC_->getDoubleParam(axisNo_, pC_->motorRecOffset_, &offset); status |= pC_->getIntegerParam(axisNo_, pC_->motorRecDirection_, &direction); asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s:%s: axis=%d, status=%d, offset=%f direction=%d, resolution=%f\n", driverName, functionName, axisNo_, status, offset, direction, resolution); if (status) return asynError; if (resolution == 0.0) return asynError; // Convert to controller units scale = 1.0/resolution; if (direction != 0) scale = -scale; for (i=0; igetDoubleParam(axisNo_, pC_->motorRecResolution_, &resolution); status |= pC_->getDoubleParam(axisNo_, pC_->motorRecOffset_, &offset); status |= pC_->getIntegerParam(axisNo_, pC_->motorRecDirection_, &direction); status |= pC_->getIntegerParam(0, pC_->profileNumReadbacks_, &numReadbacks); if (status) return asynError; // Convert to user units if (direction != 0) resolution = -resolution; for (i=0; idoCallbacksFloat64Array(profileReadbacks_, numReadbacks, pC_->profileReadbacks_, axisNo_); status |= pC_->doCallbacksFloat64Array(profileFollowingErrors_, numReadbacks, pC_->profileFollowingErrors_, axisNo_); return asynSuccess; } /****************************************************************************/ /* The following functions are used by the automatic drive power control in the base class poller in the asynMotorController class.*/ /** * Read the flag that indicates if the last poll was moving. */ int asynMotorAxis::getWasMovingFlag(void) { return wasMovingFlag_; } /** * Set this to 1 if the previous poll indicated moving state */ void asynMotorAxis::setWasMovingFlag(int wasMovingFlag) { wasMovingFlag_ = wasMovingFlag; } /** * Read the flag that indicates if the drive should be automatically * disabled. */ int asynMotorAxis::getDisableFlag(void) { return disableFlag_; } /** * Set this to 1 if the drive should be automatically disabled. */ void asynMotorAxis::setDisableFlag(int disableFlag) { disableFlag_ = disableFlag; } /** * Read the time in seconds of the last end of move. */ double asynMotorAxis::getLastEndOfMoveTime(void) { return lastEndOfMoveTime_; } /** * Set this to the current time at the end of a move. */ void asynMotorAxis::setLastEndOfMoveTime(double time) { lastEndOfMoveTime_ = time; } /********************************************************************/