Files
sinqepicsapp/sinqEPICSApp/src/pmacController.cpp
koennecke 72afd02b4e Many improvements to the MasterMACS motor driver. It is working but the hardware is shaky.
Added support for dose rate controlled Phytron motors. Not tested!
Small bug fixes
2023-05-31 09:13:41 +02:00

1013 lines
36 KiB
C++

/********************************************
* pmacController.cpp
*
* PMAC Asyn motor based on the
* asynMotorController class.
*
* Matthew Pearson
* 23 May 2012
*
*
* Substantially modified for use at SINQ at PSI.
* The thing with the PMACS is that they can be programmed.
* This affects also the commands they understand.
*
* Mark Koennecke, February 2013
*
* Updated to use the MsgTxt field for error messages as
* used at ESS and SINQ
*
* Mark Koennecke, January 2019
********************************************/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <errno.h>
#include <iostream>
using std::cout;
using std::endl;
#include "epicsTime.h"
#include <epicsThread.h>
#include <epicsExport.h>
#include <epicsString.h>
#include <iocsh.h>
#include <drvSup.h>
#include <registryFunction.h>
#include <errlog.h>
#include "asynOctetSyncIO.h"
#include "pmacController.h"
#include "pmacAxis.h"
#define MULT 1000.
static const char *driverName = "pmacController";
const epicsUInt32 pmacController::PMAC_MAXBUF_ = 1024;
const epicsFloat64 pmacController::PMAC_TIMEOUT_ = 5.0;
const epicsUInt32 pmacController::PMAC_STATUS1_MAXRAPID_SPEED = (0x1<<0);
const epicsUInt32 pmacController::PMAC_STATUS1_ALT_CMNDOUT_MODE = (0x1<<1);
const epicsUInt32 pmacController::PMAC_STATUS1_SOFT_POS_CAPTURE = (0x1<<2);
const epicsUInt32 pmacController::PMAC_STATUS1_ERROR_TRIGGER = (0x1<<3);
const epicsUInt32 pmacController::PMAC_STATUS1_FOLLOW_ENABLE = (0x1<<4);
const epicsUInt32 pmacController::PMAC_STATUS1_FOLLOW_OFFSET = (0x1<<5);
const epicsUInt32 pmacController::PMAC_STATUS1_PHASED_MOTOR = (0x1<<6);
const epicsUInt32 pmacController::PMAC_STATUS1_ALT_SRC_DEST = (0x1<<7);
const epicsUInt32 pmacController::PMAC_STATUS1_USER_SERVO = (0x1<<8);
const epicsUInt32 pmacController::PMAC_STATUS1_USER_PHASE = (0x1<<9);
const epicsUInt32 pmacController::PMAC_STATUS1_HOMING = (0x1<<10);
const epicsUInt32 pmacController::PMAC_STATUS1_BLOCK_REQUEST = (0x1<<11);
const epicsUInt32 pmacController::PMAC_STATUS1_DECEL_ABORT = (0x1<<12);
const epicsUInt32 pmacController::PMAC_STATUS1_DESIRED_VELOCITY_ZERO = (0x1<<13);
const epicsUInt32 pmacController::PMAC_STATUS1_DATABLKERR = (0x1<<14);
const epicsUInt32 pmacController::PMAC_STATUS1_DWELL = (0x1<<15);
const epicsUInt32 pmacController::PMAC_STATUS1_INTEGRATE_MODE = (0x1<<16);
const epicsUInt32 pmacController::PMAC_STATUS1_MOVE_TIME_ON = (0x1<<17);
const epicsUInt32 pmacController::PMAC_STATUS1_OPEN_LOOP = (0x1<<18);
const epicsUInt32 pmacController::PMAC_STATUS1_AMP_ENABLED = (0x1<<19);
const epicsUInt32 pmacController::PMAC_STATUS1_X_SERVO_ON = (0x1<<20);
const epicsUInt32 pmacController::PMAC_STATUS1_POS_LIMIT_SET = (0x1<<21);
const epicsUInt32 pmacController::PMAC_STATUS1_NEG_LIMIT_SET = (0x1<<22);
const epicsUInt32 pmacController::PMAC_STATUS1_MOTOR_ON = (0x1<<23);
const epicsUInt32 pmacController::PMAC_STATUS2_IN_POSITION = (0x1<<0);
const epicsUInt32 pmacController::PMAC_STATUS2_WARN_FOLLOW_ERR = (0x1<<1);
const epicsUInt32 pmacController::PMAC_STATUS2_ERR_FOLLOW_ERR = (0x1<<2);
const epicsUInt32 pmacController::PMAC_STATUS2_AMP_FAULT = (0x1<<3);
const epicsUInt32 pmacController::PMAC_STATUS2_NEG_BACKLASH = (0x1<<4);
const epicsUInt32 pmacController::PMAC_STATUS2_I2T_AMP_FAULT = (0x1<<5);
const epicsUInt32 pmacController::PMAC_STATUS2_I2_FOLLOW_ERR = (0x1<<6);
const epicsUInt32 pmacController::PMAC_STATUS2_TRIGGER_MOVE = (0x1<<7);
const epicsUInt32 pmacController::PMAC_STATUS2_PHASE_REF_ERR = (0x1<<8);
const epicsUInt32 pmacController::PMAC_STATUS2_PHASE_SEARCH = (0x1<<9);
const epicsUInt32 pmacController::PMAC_STATUS2_HOME_COMPLETE = (0x1<<10);
const epicsUInt32 pmacController::PMAC_STATUS2_POS_LIMIT_STOP = (0x1<<11);
const epicsUInt32 pmacController::PMAC_STATUS2_DESIRED_STOP = (0x1<<12);
const epicsUInt32 pmacController::PMAC_STATUS2_FORE_IN_POS = (0x1<<13);
const epicsUInt32 pmacController::PMAC_STATUS2_NA14 = (0x1<<14);
const epicsUInt32 pmacController::PMAC_STATUS2_ASSIGNED_CS = (0x1<<15);
/*Global status ???*/
const epicsUInt32 pmacController::PMAC_GSTATUS_CARD_ADDR = (0x1<<0);
const epicsUInt32 pmacController::PMAC_GSTATUS_ALL_CARD_ADDR = (0x1<<1);
const epicsUInt32 pmacController::PMAC_GSTATUS_RESERVED = (0x1<<2);
const epicsUInt32 pmacController::PMAC_GSTATUS_PHASE_CLK_MISS = (0x1<<3);
const epicsUInt32 pmacController::PMAC_GSTATUS_MACRO_RING_ERRORCHECK = (0x1<<4);
const epicsUInt32 pmacController::PMAC_GSTATUS_MACRO_RING_COMMS = (0x1<<5);
const epicsUInt32 pmacController::PMAC_GSTATUS_TWS_PARITY_ERROR = (0x1<<6);
const epicsUInt32 pmacController::PMAC_GSTATUS_CONFIG_ERROR = (0x1<<7);
const epicsUInt32 pmacController::PMAC_GSTATUS_ILLEGAL_LVAR = (0x1<<8);
const epicsUInt32 pmacController::PMAC_GSTATUS_REALTIME_INTR = (0x1<<9);
const epicsUInt32 pmacController::PMAC_GSTATUS_FLASH_ERROR = (0x1<<10);
const epicsUInt32 pmacController::PMAC_GSTATUS_DPRAM_ERROR = (0x1<<11);
const epicsUInt32 pmacController::PMAC_GSTATUS_CKSUM_ACTIVE = (0x1<<12);
const epicsUInt32 pmacController::PMAC_GSTATUS_CKSUM_ERROR = (0x1<<13);
const epicsUInt32 pmacController::PMAC_GSTATUS_LEADSCREW_COMP = (0x1<<14);
const epicsUInt32 pmacController::PMAC_GSTATUS_WATCHDOG = (0x1<<15);
const epicsUInt32 pmacController::PMAC_GSTATUS_SERVO_REQ = (0x1<<16);
const epicsUInt32 pmacController::PMAC_GSTATUS_DATA_GATHER_START = (0x1<<17);
const epicsUInt32 pmacController::PMAC_GSTATUS_RESERVED2 = (0x1<<18);
const epicsUInt32 pmacController::PMAC_GSTATUS_DATA_GATHER_ON = (0x1<<19);
const epicsUInt32 pmacController::PMAC_GSTATUS_SERVO_ERROR = (0x1<<20);
const epicsUInt32 pmacController::PMAC_GSTATUS_CPUTYPE = (0x1<<21);
const epicsUInt32 pmacController::PMAC_GSTATUS_REALTIME_INTR_RE = (0x1<<22);
const epicsUInt32 pmacController::PMAC_GSTATUS_RESERVED3 = (0x1<<23);
const epicsUInt32 pmacController::PMAC_HARDWARE_PROB = (PMAC_GSTATUS_MACRO_RING_ERRORCHECK | PMAC_GSTATUS_MACRO_RING_COMMS | PMAC_GSTATUS_REALTIME_INTR | PMAC_GSTATUS_FLASH_ERROR | PMAC_GSTATUS_DPRAM_ERROR | PMAC_GSTATUS_CKSUM_ERROR | PMAC_GSTATUS_WATCHDOG | PMAC_GSTATUS_SERVO_ERROR);
const epicsUInt32 pmacController::PMAX_AXIS_GENERAL_PROB1 = 0;
const epicsUInt32 pmacController::PMAX_AXIS_GENERAL_PROB2 = (PMAC_STATUS2_DESIRED_STOP | PMAC_STATUS2_AMP_FAULT);
//C function prototypes, for the functions that can be called on IOC shell
extern "C" {
asynStatus pmacCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, int movingPollPeriod, int idlePollPeriod);
asynStatus SeleneCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, int movingPollPeriod, int idlePollPeriod);
asynStatus pmacV3CreateController(const char *portName,
const char *lowLevelPortName,
int lowLevelPortAddress, int numAxes,
int movingPollPeriod, int idlePollPeriod);
asynStatus pmacCreateAxis(const char *pmacName, int axis);
asynStatus pmacCreateAxis(const char *pmacName, int numAxis);
}
pmacController::pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, double movingPollPeriod, double idlePollPeriod, const int& extraParams)
: SINQController(portName, lowLevelPortName, numAxes+1, extraParams)
{
static const char *functionName = "pmacController::pmacController";
//Initialize non static data members
lowLevelPortUser_ = NULL;
debugFlag_ = 0;
pAxes_ = (pmacAxis **)(asynMotorController::pAxes_);
// Create controller-specific parameters
createParam(PMAC_C_CommsErrorString, asynParamInt32, &PMAC_C_CommsError_);
// Connect our Asyn user to the low level port that is a parameter to this constructor
if (lowLevelPortConnect(lowLevelPortName, lowLevelPortAddress, &lowLevelPortUser_, "\006", (char *)"\r") != asynSuccess) {
printf("%s: Failed to connect to low level asynOctetSyncIO port %s\n", functionName, lowLevelPortName);
setIntegerParam(PMAC_C_CommsError_, 1);
} else {
/* Create the poller thread for this controller
* NOTE: at this point the axis objects don't yet exist, but the poller tolerates this */
setIntegerParam(PMAC_C_CommsError_, 0);
}
startPoller(movingPollPeriod, idlePollPeriod, 10);
callParamCallbacks();
}
pmacController::~pmacController(void)
{
//Destructor
}
/**
* Connect to the underlying low level Asyn port that is used for comms.
* This uses the asynOctetSyncIO interface, and also sets the input and output terminators.
*/
int pmacController::lowLevelPortConnect(const char *port, int addr, asynUser **ppasynUser, char *inputEos, char *outputEos)
{
asynStatus status = asynSuccess;
static const char *functionName = "pmacController::lowLevelPortConnect";
debugFlow(functionName);
status = pasynOctetSyncIO->connect( port, addr, ppasynUser, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"pmacController::motorAxisAsynConnect: unable to connect to port %s\n",
port);
return status;
}
//Do I want to disconnect below? If the IP address comes up, will the driver recover
//if the poller functions are running? Might have to use asynManager->isConnected to
//test connection status of low level port (in the pollers). But then autosave
//restore doesn't work (and we would save wrong positions). So I need to
//have a seperate function(s) to deal with connecting after IOC init.
status = pasynOctetSyncIO->setInputEos(*ppasynUser, inputEos, strlen(inputEos) );
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"pmacController: unable to set input EOS on %s: %s\n",
port, (*ppasynUser)->errorMessage);
pasynOctetSyncIO->disconnect(*ppasynUser);
//Set my low level pasynUser pointer to NULL
*ppasynUser = NULL;
return status;
}
status = pasynOctetSyncIO->setOutputEos(*ppasynUser, outputEos, strlen(outputEos));
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"pmacController: unable to set output EOS on %s: %s\n",
port, (*ppasynUser)->errorMessage);
pasynOctetSyncIO->disconnect(*ppasynUser);
//Set my low level pasynUser pointer to NULL
*ppasynUser = NULL;
return status;
}
return status;
}
/**
* Utilty function to print the connected status of the low level asyn port.
*/
asynStatus pmacController::printConnectedStatus()
{
asynStatus status = asynSuccess;
int asynManagerConnected = 0;
if (lowLevelPortUser_) {
status = pasynManager->isConnected(lowLevelPortUser_, &asynManagerConnected);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"pmacController: Error calling pasynManager::isConnected.\n");
return asynError;
} else {
printf("pmacController::printConnectedStatus: isConnected: %d\n", asynManagerConnected);
}
}
return asynSuccess;
}
/**
* Wrapper for asynOctetSyncIO write/read functions.
* @param command - String command to send.
* @response response - String response back.
*/
asynStatus pmacController::lowLevelWriteRead(int axisNo, const char *command, char *response)
{
asynStatus status = asynSuccess;
int eomReason;
size_t nwrite = 0;
size_t nread = 0;
int commsError = 0;
static const char *functionName = "pmacController::lowLevelWriteRead";
pmacAxis *axis = getAxis(axisNo);
debugFlow(functionName);
if (!lowLevelPortUser_) {
setIntegerParam(this->motorStatusCommsError_, 1);
return asynError;
}
asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER, "%s: command: %s\n", functionName, command);
debugFlow("Sending: ");
debugFlow(command);
//Make sure the low level port is connected before we attempt comms
//Use the controller-wide param PMAC_C_CommsError_
getIntegerParam(PMAC_C_CommsError_, &commsError);
if (!commsError) {
status = pasynOctetSyncIO->writeRead(lowLevelPortUser_ ,
command, strlen(command),
response, PMAC_MAXBUF_,
PMAC_TIMEOUT_,
&nwrite, &nread, &eomReason );
if (status) {
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR, "%s: Error from pasynOctetSyncIO->writeRead. command: %s\n", functionName, command);
setIntegerParam(this->motorStatusCommsError_, 1);
if(axis!= NULL){
axis->updateMsgTxtFromDriver("Lost connection to motor controller");
}
} else {
setIntegerParam(this->motorStatusCommsError_, 0);
}
}
asynPrint(lowLevelPortUser_, ASYN_TRACEIO_DRIVER, "%s: response: %s\n", functionName, response);
debugFlow("Received: ");
debugFlow(response);
return status;
}
void pmacController::debugFlow(const char *message)
{
if (debugFlag_ == 1) {
printf(" %s\n", message);
}
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW, "%s\n", message);
}
void pmacController::report(FILE *fp, int level)
{
int axis = 0;
pmacAxis *pAxis = NULL;
fprintf(fp, "pmac motor driver %s, numAxes=%d, moving poll period=%f, idle poll period=%f\n",
this->portName, numAxes_, movingPollPeriod_, idlePollPeriod_);
if (level > 0) {
for (axis=0; axis<numAxes_; axis++) {
pAxis = getAxis(axis);
fprintf(fp, " axis %d\n"
" scale = %lf\n",
pAxis->axisNo_,
pAxis->scale_);
}
}
// Call the base class method
asynMotorController::report(fp, level);
}
asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
{
int function = pasynUser->reason;
asynStatus status = asynError;
pmacAxis *pAxis = NULL;
char command[64] = {0};
char response[64] = {0};
char message[132];
static const char *functionName = "pmacController::writeFloat64";
sprintf(message,"%s, reason %d", functionName, function);
debugFlow(message);
//debugFlow(functionName);
pAxis = this->getAxis(pasynUser);
if (!pAxis) {
return asynError;
}
/* Set the parameter and readback in the parameter library. */
status = pAxis->setDoubleParam(function, value);
// if (function == motorPosition_) {
// /*Set position on motor axis.*/
// epicsInt32 position = (epicsInt32) floor(value*32/pAxis->scale_ + 0.5);
// sprintf(command, "#%dK M%d61=%d*I%d08 M%d62=%d*I%d08",
// pAxis->axisNo_,
// pAxis->axisNo_, position, pAxis->axisNo_,
// pAxis->axisNo_, position, pAxis->axisNo_ );
// asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
// "%s: Set axis %d on controller %s to position %f\n",
// functionName, pAxis->axisNo_, portName, value);
// if ( command[0] != 0 && status == asynSuccess) {
// status = lowLevelWriteRead(command, response);
// }
// sprintf(command, "#%dJ/", pAxis->axisNo_);
// if (command[0] != 0 && status == asynSuccess) {
// status = lowLevelWriteRead(command, response);
// }
// /*Now set position on encoder axis, if one is in use.*/
// if (pAxis->encoder_axis_) {
// getDoubleParam(motorEncRatio_, &encRatio);
// encposition = (epicsInt32) floor((position*encRatio) + 0.5);
// sprintf(command, "#%dK M%d61=%d*I%d08 M%d62=%d*I%d08",
// pAxis->encoder_axis_,
// pAxis->encoder_axis_, encposition, pAxis->encoder_axis_,
// pAxis->encoder_axis_, encposition, pAxis->encoder_axis_ );
// asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
// "%s: Set encoder axis %d on controller %s to position %f\n",
// functionName, pAxis->axisNo_, portName, value);
// if (command[0] != 0 && status == asynSuccess) {
// status = lowLevelWriteRead(command, response);
// }
// sprintf(command, "#%dJ/", pAxis->encoder_axis_);
// //The lowLevelWriteRead will be done at the end of this function.
// }
// /*Now do an update, to get the new position from the controller.*/
// bool moving = true;
// pAxis->getAxisStatus(&moving);
// } else
/*
if (function == motorLowLimit_) {
sprintf(command, "I%d14=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Setting low limit on controller %s, axis %d to %f\n",
functionName, portName, pAxis->axisNo_, value);
} else if (function == motorHighLimit_) {
sprintf(command, "I%d13=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Setting high limit on controller %s, axis %d to %f\n",
functionName, portName, pAxis->axisNo_, value);
}
//Execute the command.
if (command[0] != 0 && status == asynSuccess) {
status = lowLevelWriteRead(pAxis->axisNo_,command, response);
}
*/
//Call base class method
//This will handle callCallbacks even if the function was handled here.
status = asynMotorController::writeFloat64(pasynUser, value);
return status;
}
asynStatus pmacController::writeInt32(asynUser *pasynUser, epicsInt32 value)
{
int function = pasynUser->reason;
asynStatus status = asynError;
pmacAxis *pAxis = NULL;
static const char *functionName = "pmacController::writeInt32";
debugFlow(functionName);
pAxis = this->getAxis(pasynUser);
if (!pAxis) {
return asynError;
}
/* Set the parameter and readback in the parameter library. This may be overwritten when we read back the
* status at the end, but that's OK */
status = pAxis->setIntegerParam(function, value);
//Call base class method
//This will handle callCallbacks even if the function was handled here.
status = asynMotorController::writeInt32(pasynUser, value);
return status;
}
/** Returns a pointer to an pmacAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
pmacAxis* pmacController::getAxis(asynUser *pasynUser)
{
int axisNo = 0;
getAddress(pasynUser, &axisNo);
return getAxis(axisNo);
}
/** Returns a pointer to an pmacAxis object.
* Returns NULL if the axis number is invalid.
* \param[in] axisNo Axis index number. */
pmacAxis* pmacController::getAxis(int axisNo)
{
if ((axisNo < 0) || (axisNo >= numAxes_)) return NULL;
return pAxes_[axisNo];
}
/** Polls the controller, rather than individual axis.*/
asynStatus pmacController::poll()
{
static const char *functionName = "pmacController::poll";
debugFlow(functionName);
if (!lowLevelPortUser_) {
setIntegerParam(this->motorStatusCommsError_, 1);
return asynError;
}
asynMotorController::poll();
callParamCallbacks();
return asynSuccess;
}
/*************************************************************************************/
/** The following functions have C linkage, and can be called directly or from iocsh */
extern "C" {
/**
* C wrapper for the pmacController constructor.
* See pmacController::pmacController.
*
*/
asynStatus pmacCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, int movingPollPeriod, int idlePollPeriod)
{
pmacController *ppmacController
= new pmacController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
ppmacController = NULL;
return asynSuccess;
}
asynStatus SeleneCreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, int movingPollPeriod, int idlePollPeriod)
{
SeleneController *ppmacController
= new SeleneController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
ppmacController = NULL;
return asynSuccess;
}
asynStatus pmacV3CreateController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, int movingPollPeriod, int idlePollPeriod)
{
pmacController *ppmacController = new pmacV3Controller(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
ppmacController = NULL;
return asynSuccess;
}
/*---------------------------------------------------------------------------------------------------------------------*/
SeleneController::SeleneController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress,
int numAxes, double movingPollPeriod, double idlePollPeriod) : pmacController(portName,
lowLevelPortName,
lowLevelPortAddress,
numAxes,
movingPollPeriod,
idlePollPeriod, 3) {
static const char *functionName = "seleneController::seleneController";
createParam(MotorSetPositionString, asynParamFloat64, &setMotorPosition_);
callParamCallbacks();
}
pmacV3Controller::pmacV3Controller(const char *portName,
const char *lowLevelPortName,
int lowLevelPortAddress, int numAxes,
double movingPollPeriod,
double idlePollPeriod,
const int &extraParams) :
pmacController(portName, lowLevelPortName, lowLevelPortAddress, numAxes, movingPollPeriod, idlePollPeriod, extraParams) {
static const char *functionName = "pmacV3Controller::pmacV3Controller";
createParam(EnableAxisString, asynParamInt32, &enableAxis_);
createParam(AxisEnabledString, asynParamInt32, &axisEnabled_);
callParamCallbacks();
}
/**
* C wrapper for the pmacAxis constructor.
* See pmacAxis::pmacAxis.
*
*/
asynStatus pmacCreateAxis(
const char *pmacName, /* specify which controller by port name */
int axis) /* axis number (start from 1). */
{
pmacController *pC;
pmacAxis *pAxis;
static const char *functionName = "pmacCreateAxis";
pC = (pmacController *)findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n", driverName, functionName,
pmacName);
return asynError;
}
pC->lock();
pAxis = new pmacAxis(pC, axis);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/**
* C wrapper for the pmacHRPTAxis constructor.
* See pmacHRPTAxis::pmacHRPTAxis.
*
*/
asynStatus pmacCreateHRPTAxis(const char *pmacName, /* specify which controller by port name */
int axis) /* axis number (start from 1). */
{
pmacController *pC;
pmacAxis *pAxis;
static const char *functionName = "pmacCreateHRPTAxis";
pC = (pmacController*) findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n",
driverName, functionName, pmacName);
return asynError;
}
pC->lock();
pAxis = new pmacHRPTAxis(pC, axis);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/**
* C wrapper for the SeleneAxis constructor.
* See SeleneAxis::SeleneAxis.
*
*/
asynStatus SeleneCreateAxis(const char *pmacName, /* specify which controller by port name */
int axis, /* axis number (start from 1). */
double limitTarget)
{
SeleneController *pC;
SeleneAxis *pAxis;
static const char *functionName = "SeleneCreateAxis";
pC = (SeleneController*) findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n",
driverName, functionName, pmacName);
return asynError;
}
pC->lock();
pAxis = new SeleneAxis(pC, axis, limitTarget);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/**
* C wrapper for the Selene LiftAxis constructor.
* See LiftAxis::LiftAxis.
*
*/
asynStatus LiftCreateAxis(const char *pmacName, /* specify which controller by port name */
int axis) /* axis number (start from 1). */
{
pmacController *pC;
LiftAxis *pAxis;
static const char *functionName = "LiftCreateAxis";
pC = (pmacController*) findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n",
driverName, functionName, pmacName);
return asynError;
}
pC->lock();
pAxis = new LiftAxis(pC, axis);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/**
* C wrapper for the pmacV3Axis constructor.
* See pmacAxis::pmacV3Axis.
*
*/
asynStatus pmacV3CreateAxis(
const char *pmacName, /* specify which controller by port name */
int axis) /* axis number (start from 1). */
{
pmacController *pC;
pmacAxis *pAxis;
static const char *functionName = "pmacV3CreateAxis";
pC = (pmacController *)findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n", driverName, functionName,
pmacName);
return asynError;
}
pC->lock();
pAxis = new pmacV3Axis(pC, axis);
pAxis = NULL;
pC->unlock();
return asynSuccess;
}
/**
* C Wrapper function for pmacHRPTAxis constructor.
* See pmacAxis::pmacAxis.
* This function allows creation of multiple pmacAxis objects with axis numbers 1 to numAxes.
* @param pmacName Asyn port name for the controller (const char *)
* @param numAxes The number of axes to create, starting at 1.
*
*/
asynStatus pmacCreateAxes(const char *pmacName,
int numAxes)
{
pmacController *pC;
pmacAxis *pAxis;
static const char *functionName = "pmacCreateAxis";
pC = (pmacController*) findAsynPortDriver(pmacName);
if (!pC) {
printf("%s:%s: Error port %s not found\n",
driverName, functionName, pmacName);
return asynError;
}
pC->lock();
for (int axis=1; axis<=numAxes; axis++) {
pAxis = new pmacAxis(pC, axis);
pAxis = NULL;
}
pC->unlock();
return asynSuccess;
}
/*================================ SeleneController ===============================================*/
asynStatus SeleneController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
{
int function = pasynUser->reason;
asynStatus status = asynError;
SeleneAxis *pAxis = NULL;
char command[64] = {0};
char response[64] = {0};
char message[132];
static const char *functionName = "SeleneController::writeFloat64";
sprintf(message,"%s, reason %d", functionName, function);
pAxis = (SeleneAxis *)this->getAxis(pasynUser);
if (!pAxis) {
return asynError;
}
/* Set the parameter and readback in the parameter library. */
status = pAxis->setDoubleParam(function, value);
if (function == motorLowLimit_) {
sprintf(command, "Q%d54=%f", pAxis->axisNo_, (float)value/(float)MULT);
// sprintf(command, "Q%d54=%d", pAxis->axisNo_, (int)(value/pAxis->scale_/MULT));
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Setting low limit on controller %s, axis %d to %f\n",
functionName, portName, pAxis->axisNo_, value);
errlogPrintf("Setting low limit of axis %d to %f, command = %s\n", pAxis->axisNo_, value, command);
} else if (function == motorHighLimit_) {
sprintf(command, "Q%d53=%f", pAxis->axisNo_, (float)value/(float)MULT);
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Setting high limit on controller %s, axis %d to %f\n",
functionName, portName, pAxis->axisNo_, value);
errlogPrintf("Setting high limit of axis %d to %f, command = %s\n", pAxis->axisNo_, value, command);
} else if(function == setMotorPosition_){
snprintf(command,sizeof(command),"Q%d59=%f", pAxis->axisNo_, value);
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Defining position of axis%d to %f\n",
functionName, pAxis->axisNo_, value);
errlogPrintf("Defining position of axis %d to %f, command = %s\n", pAxis->axisNo_, value, command);
}
//Execute the command.
if (command[0] != 0 && status == asynSuccess) {
status = lowLevelWriteRead(pAxis->axisNo_,command, response);
}
// What if now status != asynSuccess
//Call base class method
//This will handle callCallbacks even if the function was handled here.
status = asynMotorController::writeFloat64(pasynUser, value);
return status;
}
asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
int function = pasynUser->reason;
asynStatus status = asynSuccess;
pmacV3Axis *pAxis = NULL;
char command[64] = {0};
char response[64] = {0};
static const char *functionName = "pmacV3Controller::writeInt32";
debugFlow(functionName);
pAxis = (pmacV3Axis*)this->getAxis(pasynUser);
if (!pAxis) {
return asynError;
}
/* Set the parameter and readback in the parameter library. This may be
* overwritten when we read back the status at the end, but that's OK */
pAxis->setIntegerParam(function, value);
if (function == enableAxis_) {
if(value == 1) {
sprintf(command, "M%2.2d=15\n", pAxis->axisNo_);
lowLevelWriteRead(pAxis->axisNo_, command, response);
}
sprintf(command, "M%2.2d14=%d\n", pAxis->axisNo_, value);
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Enable axis on controller %s, axis %d enable=%d\n",
functionName, portName, pAxis->axisNo_, value);
pAxis->updateMsgTxtFromDriver("");
lowLevelWriteRead(pAxis->axisNo_, command, response);
}
return pmacController::writeInt32(pasynUser, value);
}
asynStatus pmacV3Controller::readInt32(asynUser *pasynUser, epicsInt32 *value) {
int function = pasynUser->reason;
asynStatus status = asynError;
pmacV3Axis *pAxis = NULL;
static const char *functionName = "pmacV3Controller::readInt32";
char command[128];
char response[128];
debugFlow(functionName);
pAxis = (pmacV3Axis*)(this->getAxis(pasynUser));
if (!pAxis) {
return asynError;
}
if (function == axisEnabled_) {
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
status = this->lowLevelWriteRead(pAxis->axisNo_, command, response);
*value = strtol(response, NULL, 10);
int st = setIntegerParam(axisEnabled_, *value);
callParamCallbacks();
}
return pmacController::readInt32(pasynUser, value);
}
/* Code for iocsh registration */
#ifdef vxWorks
#else
/* pmacCreateController */
static const iocshArg pmacCreateControllerArg0 = {"Controller port name", iocshArgString};
static const iocshArg pmacCreateControllerArg1 = {"Low level port name", iocshArgString};
static const iocshArg pmacCreateControllerArg2 = {"Low level port address", iocshArgInt};
static const iocshArg pmacCreateControllerArg3 = {"Number of axes", iocshArgInt};
static const iocshArg pmacCreateControllerArg4 = {"Moving poll rate (ms)", iocshArgInt};
static const iocshArg pmacCreateControllerArg5 = {"Idle poll rate (ms)", iocshArgInt};
static const iocshArg * const pmacCreateControllerArgs[] = {&pmacCreateControllerArg0,
&pmacCreateControllerArg1,
&pmacCreateControllerArg2,
&pmacCreateControllerArg3,
&pmacCreateControllerArg4,
&pmacCreateControllerArg5};
static const iocshFuncDef configpmacCreateController = {"pmacCreateController", 6, pmacCreateControllerArgs};
static void configpmacCreateControllerCallFunc(const iocshArgBuf *args)
{
pmacCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival);
}
static const iocshFuncDef configSeleneCreateController = {"SeleneCreateController", 6, pmacCreateControllerArgs};
static void configSeleneCreateControllerCallFunc(const iocshArgBuf *args)
{
SeleneCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].ival);
}
static const iocshFuncDef configpmacV3CreateController = {
"pmacV3CreateController", 6, pmacCreateControllerArgs
};
static void configpmacV3CreateControllerCallFunc(const iocshArgBuf *args) {
pmacV3CreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival,
args[4].ival, args[5].ival);
}
/* pmacCreateAxis */
static const iocshArg pmacCreateAxisArg0 = {"Controller port name", iocshArgString};
static const iocshArg pmacCreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg * const pmacCreateAxisArgs[] = {&pmacCreateAxisArg0,
&pmacCreateAxisArg1};
static const iocshFuncDef configpmacAxis = {"pmacCreateAxis", 2, pmacCreateAxisArgs};
static void configpmacAxisCallFunc(const iocshArgBuf *args)
{
pmacCreateAxis(args[0].sval, args[1].ival);
}
/* pmacCreateHRPTAxis */
static const iocshArg pmacCreateHRPTAxisArg0 = {"Controller port name", iocshArgString};
static const iocshArg pmacCreateHRPTAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg * const pmacCreateHRPTAxisArgs[] = {&pmacCreateAxisArg0,
&pmacCreateAxisArg1};
static const iocshFuncDef configpmacHRPTAxis = {"pmacCreateHRPTAxis", 2, pmacCreateHRPTAxisArgs};
static void configpmacHRPTAxisCallFunc(const iocshArgBuf *args)
{
pmacCreateHRPTAxis(args[0].sval, args[1].ival);
}
/* SeleneCreateAxis */
static const iocshArg SeleneCreateAxisArg0 = {"Controller port name", iocshArgString};
static const iocshArg SeleneCreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg SeleneCreateAxisArg2 = {"limitTraget", iocshArgDouble};
static const iocshArg * const SeleneCreateAxisArgs[] = {&SeleneCreateAxisArg0,
&SeleneCreateAxisArg1,
&SeleneCreateAxisArg2};
static const iocshFuncDef configSeleneCreateAxis = {"SeleneCreateAxis", 3, SeleneCreateAxisArgs};
static void configSeleneCreateAxisCallFunc(const iocshArgBuf *args)
{
SeleneCreateAxis(args[0].sval, args[1].ival,args[2].dval);
}
/* LiftCreateAxis */
static const iocshArg LiftCreateAxisArg0 = {"Controller port name", iocshArgString};
static const iocshArg LiftCreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg * const LiftCreateAxisArgs[] = {&LiftCreateAxisArg0,
&LiftCreateAxisArg1};
static const iocshFuncDef configLiftAxis = {"LiftCreateAxis", 2, LiftCreateAxisArgs};
static void configLiftAxisCallFunc(const iocshArgBuf *args)
{
LiftCreateAxis(args[0].sval, args[1].ival);
}
/* pmacV3CreateAxis */
static const iocshArg pmacV3CreateAxisArg0 = {"Controller port name",
iocshArgString};
static const iocshArg pmacV3CreateAxisArg1 = {"Axis number", iocshArgInt};
static const iocshArg *const pmacV3CreateAxisArgs[] = {&pmacV3CreateAxisArg0,
&pmacV3CreateAxisArg1};
static const iocshFuncDef configpmacV3Axis = {"pmacV3CreateAxis", 2,
pmacV3CreateAxisArgs};
static void configpmacV3AxisCallFunc(const iocshArgBuf *args) {
pmacV3CreateAxis(args[0].sval, args[1].ival);
}
/* pmacCreateAxes */
static const iocshArg pmacCreateAxesArg0 = {"Controller port name", iocshArgString};
static const iocshArg pmacCreateAxesArg1 = {"Num Axes", iocshArgInt};
static const iocshArg * const pmacCreateAxesArgs[] = {&pmacCreateAxesArg0,
&pmacCreateAxesArg1};
static const iocshFuncDef configpmacAxes = {"pmacCreateAxes", 2, pmacCreateAxesArgs};
static void configpmacAxesCallFunc(const iocshArgBuf *args)
{
pmacCreateAxes(args[0].sval, args[1].ival);
}
static void pmacControllerRegister(void)
{
iocshRegister(&configpmacCreateController, configpmacCreateControllerCallFunc);
iocshRegister(&configSeleneCreateController, configSeleneCreateControllerCallFunc);
iocshRegister(&configpmacV3CreateController, configpmacV3CreateControllerCallFunc);
iocshRegister(&configpmacAxis, configpmacAxisCallFunc);
iocshRegister(&configpmacHRPTAxis, configpmacHRPTAxisCallFunc);
iocshRegister(&configSeleneCreateAxis, configSeleneCreateAxisCallFunc);
iocshRegister(&configLiftAxis, configLiftAxisCallFunc);
iocshRegister(&configpmacV3Axis, configpmacV3AxisCallFunc);
iocshRegister(&configpmacAxes, configpmacAxesCallFunc);
}
epicsExportRegistrar(pmacControllerRegister);
#endif
} // extern "C"