Files
sinqepicsapp/sinqEPICSApp/src/pmacController.cpp

652 lines
23 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
********************************************/
#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 "asynOctetSyncIO.h"
#include "pmacController.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 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)
: asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS,
0, // No additional interfaces
0, // No addition interrupt interfaces
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
static const char *functionName = "pmacController::pmacController";
printf(" Constructor: %s\n", functionName);
//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", "\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(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";
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);
} 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};
double encRatio = 1.0;
epicsInt32 encposition = 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(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;
}
/**
* 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 function for pmacAxis 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;
}
/* 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);
}
/* 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);
}
/* 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(&configpmacAxis, configpmacAxisCallFunc);
iocshRegister(&configpmacAxes, configpmacAxesCallFunc);
}
epicsExportRegistrar(pmacControllerRegister);
#endif
} // extern "C"