From c4fe45c0cb9699c6a755c2ba0ec38f6f2d9fc653 Mon Sep 17 00:00:00 2001 From: michele-brambilla Date: Mon, 17 Feb 2020 11:10:02 +0100 Subject: [PATCH] Add a set PV for the SeleneMotor - make the number of extra parameters in SINQController configurable - add database entry for the motor set field - add the new function "setMotorPosition_" to the Selene controller - execute Qx59= to set the new position --- configure/RELEASE | 25 ++-- sinqEPICSApp/Db/motorSet.db | 6 + sinqEPICSApp/src/SINQController.cpp | 4 +- sinqEPICSApp/src/SINQController.h | 2 +- sinqEPICSApp/src/pmacAxis.cpp | 130 ++++++++++++++++++- sinqEPICSApp/src/pmacAxis.h | 49 +++++++ sinqEPICSApp/src/pmacController.cpp | 190 +++++++++++++++++++++++++++- sinqEPICSApp/src/pmacController.h | 32 ++++- 8 files changed, 411 insertions(+), 27 deletions(-) create mode 100644 sinqEPICSApp/Db/motorSet.db diff --git a/configure/RELEASE b/configure/RELEASE index 41fe199..118ef2c 100644 --- a/configure/RELEASE +++ b/configure/RELEASE @@ -25,17 +25,20 @@ TEMPLATE_TOP=$(EPICS_BASE)/templates/makeBaseApp/top #SNCSEQ=$(EPICS_BASE)/../modules/soft/seq # EPICS_BASE usually appears last so other apps can override stuff: -EPICS_BASE=/opt/epics/bases/base-3.14.12.5 + +#EPICS_BASE= +#MODULES=/home/epics/modules # Set RULES here if you want to take build rules from somewhere # other than EPICS_BASE: -#RULES=/path/to/epics/support/module/rules/x-y -MOTOR=/opt/epics/modules/motor/6.10.0/3.14.12.5 -ASYN=/opt/epics/modules/asyn/4.27.0/3.14.12.5 -SYNAPPSSTD=/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/ -#ANC=/usr/local/epics/anc350v17 -STREAMS=/opt/epics/modules/streamdevice/2.6.0/3.14.12.5 -#LAKESHORE336=/usr/local/epics/support/lakeshore336 -BUSY=/opt/epics/modules/busy/1.6.0/3.14.12.5 -#OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3 -PCRE=/opt/epics/modules/pcre/8.36.0/3.14.12.5 +##RULES=/path/to/epics/support/module/rules/x-y +#MOTOR=/opt/epics/modules/motor/6.10.0/3.14.12.5 +#ASYN=/opt/epics/modules/asyn/4.27.0/3.14.12.5 +#SYNAPPSSTD=/opt/epics/modules/synAppsStd/3.4.1/3.14.12.5/ +##ANC=/usr/local/epics/anc350v17 +#STREAMS=/opt/epics/modules/streamdevice/2.6.0/3.14.12.5 +##LAKESHORE336=/usr/local/epics/support/lakeshore336 +#BUSY=/opt/epics/modules/busy/1.6.0/3.14.12.5 +##OXINSTCRYOJET=/usr/local/epics/support/OxInstCryojet-2-18-3 +#PCRE=/opt/epics/modules/pcre/8.36.0/3.14.12.5 + diff --git a/sinqEPICSApp/Db/motorSet.db b/sinqEPICSApp/Db/motorSet.db new file mode 100644 index 0000000..91d7b80 --- /dev/null +++ b/sinqEPICSApp/Db/motorSet.db @@ -0,0 +1,6 @@ +# workaround over set position +record(ao, "$(P)$(M)-SetPosition") { + field(DTYP, "asynFloat64") + field(OUT, "@asyn($(PORT),$(N),1) SET_MOTOR_POSITION") + field(PINI, "YES") +} diff --git a/sinqEPICSApp/src/SINQController.cpp b/sinqEPICSApp/src/SINQController.cpp index afbe3ef..4070156 100644 --- a/sinqEPICSApp/src/SINQController.cpp +++ b/sinqEPICSApp/src/SINQController.cpp @@ -10,8 +10,8 @@ #include "SINQController.h" #include "asynMotorController.h" -SINQController::SINQController(const char *portName, const char *SINQPortName, int numAxes) - : asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS+2, +SINQController::SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams) + : asynMotorController(portName, numAxes+1, NUM_MOTOR_DRIVER_PARAMS+extraParams, 0, // No additional interfaces beyond those in base class 0, // No additional callback interfaces beyond those in base class ASYN_CANBLOCK | ASYN_MULTIDEVICE, diff --git a/sinqEPICSApp/src/SINQController.h b/sinqEPICSApp/src/SINQController.h index 15850e3..27cdd62 100644 --- a/sinqEPICSApp/src/SINQController.h +++ b/sinqEPICSApp/src/SINQController.h @@ -17,7 +17,7 @@ class epicsShareClass SINQController : public asynMotorController { public: - SINQController(const char *portName, const char *SINQPortName, int numAxes); + SINQController(const char *portName, const char *SINQPortName, int numAxes, const int& extraParams=2); friend class SINQAxis; protected: diff --git a/sinqEPICSApp/src/pmacAxis.cpp b/sinqEPICSApp/src/pmacAxis.cpp index 52c0060..c7a5d7f 100644 --- a/sinqEPICSApp/src/pmacAxis.cpp +++ b/sinqEPICSApp/src/pmacAxis.cpp @@ -8,9 +8,9 @@ * 23 May 2012 * * Substantially modified for use at SINQ at PSI. - * The thing with the PMACS is that they can be programmed. + * The thing with the PMAC's is that they can be programmed. * This affects also the commands they understand. - * Our PMACS also do not seem to like to return multiple replies..... + * Our PMAC's also do not seem to like to return multiple replies..... * * I use a starting flag to catch a peculiar feature of our PMAC implementation: * when the motor is hung, it wont start. I check for this and cause an alarm. @@ -44,6 +44,8 @@ #define MULT 1000. +#define ABS(x) (x < 0 ? -(x) : (x)) + extern "C" void shutdownCallback(void *pPvt) { pmacController *pC = static_cast(pPvt); @@ -244,7 +246,8 @@ asynStatus pmacAxis::setPosition(double position) { //int status = 0; static const char *functionName = "pmacAxis::setPosition"; - + errlogPrintf("executing : %s\n", functionName); + pC_->debugFlow(functionName); // Cannot do this. @@ -417,6 +420,8 @@ asynStatus pmacAxis::getAxisStatus(bool *moving) previous_position_ = position; previous_direction_ = direction; + // errlogPrintf("Polling, axStat = %d, axErr = %d, position = %f\n", axStat, axErr, position); + /* are we done? */ if((axStat == 0 || axStat == 14 || axStat < 0) && starting == 0 ){ done = 1; @@ -561,3 +566,122 @@ asynStatus pmacHRPTAxis::getAxisStatus(bool *moving) } return result; } + +/*================================= SeleneAxis code ======================================================*/ +asynStatus SeleneAxis::home(double min_velocity, double max_velocity, double acceleration, int forwards) +{ + asynStatus status = asynError; + static const char *functionName = "SeleneAxis::home"; + + pC_->debugFlow(functionName); + + updateMsgTxtFromDriver("Cannot home on this axis type"); + + + return status; +} +/*----------------------------------------------------------------------------------------------------------------*/ +asynStatus SeleneAxis::move(double position, int relative, double min_velocity, double max_velocity, double acceleration) +{ + asynStatus status = asynError; + static const char *functionName = "SeleneAxis::move"; + double realPosition; + + updateMsgTxtFromDriver(""); + + pC_->debugFlow(functionName); + + char command[128] = {0}; + char response[32] = {0}; + + pC_->debugFlow(functionName); + + if(relative){ + realPosition = previous_position_ + position/MULT; + } else { + realPosition = position/MULT; + } + startTime = time(NULL); + status6Time = 0; + starting = 1; + + /* + Run into limit when asked for by a suitable position, else + position absolutely + */ + if(ABS(realPosition - limitTarget) < .05){ + sprintf(command,"P%d50=3", axisNo_); + } else { + sprintf(command,"Q%d51=%f P%x50=1",axisNo_, realPosition, axisNo_); + } + + errlogPrintf("Sending drive command: %s\n", command); + + status = pC_->lowLevelWriteRead(axisNo_,command, response); + + return status; +} +/*----------------------------------------------------------------------------------------------------*/ +asynStatus SeleneAxis::setPosition(double position) { + asynStatus status = asynError; + return status; +} +/*======================================= Selene Lift Axis Code ===========================================*/ +asynStatus LiftAxis::move(double position, int relative, double min_velocity, + double max_velocity, double acceleration) +{ + asynStatus status = asynError; + static const char *functionName = "LiftAxis::move"; + double realPosition; + + updateMsgTxtFromDriver(""); + pC_->debugFlow(functionName); + + char command[128] = {0}; + char response[32] = {0}; + + pC_->debugFlow(functionName); + + if(relative){ + realPosition = previous_position_ + position/MULT; + } else { + realPosition = position/MULT; + } + startTime = time(NULL); + status6Time = 0; + starting = 1; + + sprintf( command, "Q15%d=%12.4f", axisNo_, realPosition); + + status = pC_->lowLevelWriteRead(axisNo_,command, response); + waitStart = 1; + + return status; +} +/*-------------------------------------------------------------------------------------------------------- + Return *moving until the motor moved started moving. This enables the start command + to be sent separatly. +----------------------------------------------------------------------------------------------------------*/ +asynStatus LiftAxis::poll(bool *moving) +{ + asynStatus status; + + status = getAxisStatus(moving); + if(*moving == false && waitStart == 1){ + *moving = true; + setIntegerParam(pC_->motorStatusMoving_, true); + setIntegerParam(pC_->motorStatusDone_, false); + } + if(*moving){ + waitStart = 0; + } + callParamCallbacks(); + return status; +} +/*--------------------------------------------------------------------------------------------------------------*/ +asynStatus LiftAxis::stop(double acceleration) +{ + waitStart = 0; + return pmacAxis::stop(acceleration); +} +/*-------------------------------------------------------------------------------------------------------------*/ diff --git a/sinqEPICSApp/src/pmacAxis.h b/sinqEPICSApp/src/pmacAxis.h index bb995eb..824f91d 100644 --- a/sinqEPICSApp/src/pmacAxis.h +++ b/sinqEPICSApp/src/pmacAxis.h @@ -10,6 +10,9 @@ * Modified to use the MsgTxt field for SINQ * * Mark Koennecke, January 2019 + * + * EXtended with special motor axis for the Selene + * guide, Mark Koennecke, February 2020 ********************************************/ #ifndef pmacAxis_H @@ -19,6 +22,7 @@ #include "SINQAxis.h" class pmacController; +class SeleneController; class pmacAxis : public SINQAxis { @@ -76,4 +80,49 @@ class pmacHRPTAxis : public pmacAxis }; +class SeleneAxis : public pmacAxis +{ + + public: + SeleneAxis(SeleneController *pController, int axisNo, double limitTarget) : pmacAxis((pmacController *)pController,axisNo) + { + this->limitTarget = limitTarget; + }; + asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration); + asynStatus setPosition(double position); + asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards); + + protected: + friend class SeleneController; + friend class pmacController; + + private: + double limitTarget; + +}; + +/* + Yet another special set of motors for the Selene Guide at AMOR. Each segment can be lifted or tilted. This is + two motors. One acts as a slave and only writes a new target, the other also sets a new target and sends the + actual movement command. Both motors are coordianted in the motor controller in order to avoid tension on + the guide elements. This gaves rise to the function code LIFTSLAVE and LIFTMASTER. + + In another mode the whole guide can be lifted or tilted. Then motor 1 and 6 get new values and one of them + sends the drive command. This causes all 6 motors to drive synchronously to their new targets. This is + implemented through the LIFTSEGMENT function code. + + Mark Koennecke, February 2020 + + */ +class LiftAxis : public pmacAxis +{ + public: + LiftAxis(pmacController *pController, int axisNo) : pmacAxis((pmacController *)pController,axisNo) {}; + asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration); + asynStatus poll(bool *moving); + asynStatus stop(double acceleration); + private: + int waitStart; +}; + #endif /* pmacAxis_H */ diff --git a/sinqEPICSApp/src/pmacController.cpp b/sinqEPICSApp/src/pmacController.cpp index 39d5434..8f299f3 100644 --- a/sinqEPICSApp/src/pmacController.cpp +++ b/sinqEPICSApp/src/pmacController.cpp @@ -39,6 +39,7 @@ using std::endl; #include #include #include +#include #include "asynOctetSyncIO.h" @@ -130,6 +131,8 @@ const epicsUInt32 pmacController::PMAX_AXIS_GENERAL_PROB2 = (PMAC_STATUS2_DESIRE 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 pmacCreateAxis(const char *pmacName, int axis); asynStatus pmacCreateAxis(const char *pmacName, int numAxis); @@ -137,8 +140,8 @@ extern "C" { } pmacController::pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, - int numAxes, double movingPollPeriod, double idlePollPeriod) - : SINQController(portName, lowLevelPortName, numAxes+1) + int numAxes, double movingPollPeriod, double idlePollPeriod, const int& extraParams) + : SINQController(portName, lowLevelPortName, numAxes+1, extraParams) { static const char *functionName = "pmacController::pmacController"; @@ -154,7 +157,7 @@ pmacController::pmacController(const char *portName, const char *lowLevelPortNam 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) { + 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 { @@ -344,8 +347,6 @@ asynStatus pmacController::writeFloat64(asynUser *pasynUser, epicsFloat64 value) 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"; @@ -532,6 +533,31 @@ asynStatus pmacCreateController(const char *portName, const char *lowLevelPortNa 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; +} + + + 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(); + } + + /** * C wrapper for the pmacAxis constructor. * See pmacAxis::pmacAxis. @@ -585,6 +611,61 @@ asynStatus pmacCreateHRPTAxis(const char *pmacName, /* specify which con 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 function for pmacHRPTAxis constructor. * See pmacAxis::pmacAxis. @@ -617,6 +698,67 @@ asynStatus pmacCreateAxes(const char *pmacName, 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); + + // TODO: somethign is really shitty here: lowLimit and highLimit cannot be on the command + if (function == motorLowLimit_) { + 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=%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); + 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); + } + + //Call base class method + //This will handle callCallbacks even if the function was handled here. + status = asynMotorController::writeFloat64(pasynUser, value); + + return status; + +} + + /* Code for iocsh registration */ #ifdef vxWorks @@ -641,6 +783,12 @@ 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); +} + /* pmacCreateAxis */ static const iocshArg pmacCreateAxisArg0 = {"Controller port name", iocshArgString}; @@ -666,6 +814,34 @@ 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); +} + + /* pmacCreateAxes */ static const iocshArg pmacCreateAxesArg0 = {"Controller port name", iocshArgString}; static const iocshArg pmacCreateAxesArg1 = {"Num Axes", iocshArgInt}; @@ -683,8 +859,11 @@ static void configpmacAxesCallFunc(const iocshArgBuf *args) static void pmacControllerRegister(void) { iocshRegister(&configpmacCreateController, configpmacCreateControllerCallFunc); + iocshRegister(&configSeleneCreateController, configSeleneCreateControllerCallFunc); iocshRegister(&configpmacAxis, configpmacAxisCallFunc); iocshRegister(&configpmacHRPTAxis, configpmacHRPTAxisCallFunc); + iocshRegister(&configSeleneCreateAxis, configSeleneCreateAxisCallFunc); + iocshRegister(&configLiftAxis, configLiftAxisCallFunc); iocshRegister(&configpmacAxes, configpmacAxesCallFunc); } epicsExportRegistrar(pmacControllerRegister); @@ -693,3 +872,4 @@ epicsExportRegistrar(pmacControllerRegister); } // extern "C" + diff --git a/sinqEPICSApp/src/pmacController.h b/sinqEPICSApp/src/pmacController.h index d794f2c..2f67fcf 100644 --- a/sinqEPICSApp/src/pmacController.h +++ b/sinqEPICSApp/src/pmacController.h @@ -26,8 +26,8 @@ class pmacController : public SINQController { public: - pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod, - double idlePollPeriod); + pmacController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, int numAxes, double movingPollPeriod, + double idlePollPeriod, const int& extraParams=2); virtual ~pmacController(); @@ -49,13 +49,13 @@ class pmacController : public SINQController { int PMAC_C_GlobalStatus_; int PMAC_C_CommsError_; #define LAST_PMAC_PARAM PMAC_C_CommsError__ + void debugFlow(const char *message); + asynStatus lowLevelWriteRead(int axisNo, const char *command, char *response); private: asynUser* lowLevelPortUser_; epicsUInt32 debugFlag_; - asynStatus lowLevelWriteRead(int axisNo, const char *command, char *response); int lowLevelPortConnect(const char *port, int addr, asynUser **ppasynUser, char *inputEos, char *outputEos); - void debugFlow(const char *message); //static class data members @@ -137,9 +137,31 @@ class pmacController : public SINQController { friend class pmacAxis; friend class pmacHRPTAxis; - + friend class SeleneAxis; + friend class LiftAxis; }; #define NUM_PMAC_PARAMS (&LAST_PMAC_PARAM - &FIRST_PMAC_PARAM + 1) +#define MotorSetPositionString "SET_MOTOR_POSITION" + +class SeleneController : public pmacController { + public: + SeleneController(const char *portName, const char *lowLevelPortName, int lowLevelPortAddress, + int numAxes, double movingPollPeriod, double idlePollPeriod); + + ~SeleneController(void) { } + + // overloaded because we have a different command to set the limits + asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value); + + friend class SeleneAxis; + friend class pmacAxis; + + protected: + int setMotorPosition_; + +}; + + #endif /* pmacController_H */