|
|
|
@ -23,6 +23,12 @@ Though this driver has been written in 2016, the MCC-2 version used is probably
|
|
|
|
|
Mark Koennecke
|
|
|
|
|
September 2016
|
|
|
|
|
|
|
|
|
|
Updated to use the new MsgTxt field through SINQAxis
|
|
|
|
|
Added a selector to support multiple phytrons on a connection
|
|
|
|
|
|
|
|
|
|
Mark Koennecke
|
|
|
|
|
January 2019
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -49,19 +55,17 @@ September 2016
|
|
|
|
|
* \param[in] PhytronPortName The name of the drvAsynSerialPort that was created previously to connect to the Phytron controller
|
|
|
|
|
* \param[in] numAxes The number of axes that this controller supports
|
|
|
|
|
*/
|
|
|
|
|
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, int encX, int encY)
|
|
|
|
|
: asynMotorController(portName, 3, 0,
|
|
|
|
|
0, // No additional interfaces beyond those in base class
|
|
|
|
|
0, // No additional callback interfaces beyond those in base class
|
|
|
|
|
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
|
|
|
|
|
1, // autoconnect
|
|
|
|
|
0, 0) // Default priority and stack size
|
|
|
|
|
PhytronController::PhytronController(const char *portName, const char *PhytronPortName, const char *sel ,
|
|
|
|
|
int encX, int encY)
|
|
|
|
|
: SINQController(portName, PhytronPortName,2)
|
|
|
|
|
{
|
|
|
|
|
asynStatus status;
|
|
|
|
|
PhytronAxis *pAxis;
|
|
|
|
|
static const char *functionName = "PhytronController::PhytronController";
|
|
|
|
|
char etx[2];
|
|
|
|
|
|
|
|
|
|
selector = strdup(sel);
|
|
|
|
|
|
|
|
|
|
/* Connect to Phytron controller */
|
|
|
|
|
status = pasynOctetSyncIO->connect(PhytronPortName, 0, &pasynUserController_, NULL);
|
|
|
|
|
if (status) {
|
|
|
|
@ -87,10 +91,11 @@ PhytronController::PhytronController(const char *portName, const char *PhytronPo
|
|
|
|
|
* \param[in] PhytronPortName The name of the drvAsynIPPPort that was created previously to connect to the Phytron controller
|
|
|
|
|
* \param[in] numAxes The number of axes that this controller supports
|
|
|
|
|
*/
|
|
|
|
|
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, int encX, int encY)
|
|
|
|
|
extern "C" int PhytronCreateController(const char *portName, const char *PhytronPortName, const char *selector,
|
|
|
|
|
int encX, int encY)
|
|
|
|
|
{
|
|
|
|
|
PhytronController *pPhytronController
|
|
|
|
|
= new PhytronController(portName, PhytronPortName, encX, encY);
|
|
|
|
|
= new PhytronController(portName, PhytronPortName,selector, encX, encY);
|
|
|
|
|
pPhytronController = NULL;
|
|
|
|
|
return(asynSuccess);
|
|
|
|
|
}
|
|
|
|
@ -176,7 +181,7 @@ asynStatus PhytronController::transactController(char command[COMLEN], char repl
|
|
|
|
|
I may need to replace the ETX. But I am not sure if asyn did
|
|
|
|
|
not remove it for me.
|
|
|
|
|
*/
|
|
|
|
|
strncat(reply,pPtr,sizeof(reply));
|
|
|
|
|
strncat(reply,pPtr,COMLEN-1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
@ -191,7 +196,7 @@ asynStatus PhytronController::transactController(char command[COMLEN], char repl
|
|
|
|
|
* Initializes register numbers, etc.
|
|
|
|
|
*/
|
|
|
|
|
PhytronAxis::PhytronAxis(PhytronController *pC, int axisNo, int enc)
|
|
|
|
|
: asynMotorAxis(pC, axisNo),
|
|
|
|
|
: SINQAxis(pC, axisNo),
|
|
|
|
|
pC_(pC)
|
|
|
|
|
{
|
|
|
|
|
encoder = enc;
|
|
|
|
@ -229,15 +234,17 @@ asynStatus PhytronAxis::move(double position, int relative, double minVelocity,
|
|
|
|
|
//static const char *functionName = "PhytronAxis::move";
|
|
|
|
|
char command[COMLEN], reply[COMLEN];
|
|
|
|
|
|
|
|
|
|
updateMsgTxtFromDriver("");
|
|
|
|
|
|
|
|
|
|
if (relative) {
|
|
|
|
|
position += this->position;
|
|
|
|
|
}
|
|
|
|
|
homing = 0;
|
|
|
|
|
sprintf(command, "0%cA%f", phytronChar,position/1000.);
|
|
|
|
|
sprintf(command, "%s%cA%f", pC_->selector,phytronChar,position/1000.);
|
|
|
|
|
status = pC_->transactController(command,reply);
|
|
|
|
|
if(strstr(reply,"NACK") != NULL){
|
|
|
|
|
errlogSevPrintf(errlogMajor, "Drive command not acknowledged on %d", axisNo_);
|
|
|
|
|
updateMsgTxtFromDriver("Drive command not acknowledged");
|
|
|
|
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
@ -251,13 +258,16 @@ asynStatus PhytronAxis::home(double minVelocity, double maxVelocity, double acce
|
|
|
|
|
//static const char *functionName = "PhytronAxis::home";
|
|
|
|
|
char command[COMLEN], reply[COMLEN];
|
|
|
|
|
|
|
|
|
|
sprintf(command, "0%cO-",phytronChar);
|
|
|
|
|
updateMsgTxtFromDriver("");
|
|
|
|
|
|
|
|
|
|
sprintf(command, "%s%cO-",pC_->selector,phytronChar);
|
|
|
|
|
homing = 1;
|
|
|
|
|
next_poll= -1;
|
|
|
|
|
status = pC_->transactController(command,reply);
|
|
|
|
|
if(strstr(reply,"NACK") != NULL){
|
|
|
|
|
errlogSevPrintf(errlogMajor, "Home command not acknowledged on %d", axisNo_);
|
|
|
|
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
|
|
|
|
updateMsgTxtFromDriver("Home command not acknowledged");
|
|
|
|
|
return asynError;
|
|
|
|
|
}
|
|
|
|
|
return status;
|
|
|
|
@ -274,6 +284,7 @@ asynStatus PhytronAxis::moveVelocity(double minVelocity, double maxVelocity, dou
|
|
|
|
|
// "%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
|
|
|
|
// functionName, minVelocity, maxVelocity, acceleration);
|
|
|
|
|
|
|
|
|
|
updateMsgTxtFromDriver("");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (maxVelocity > 0.) {
|
|
|
|
@ -294,9 +305,10 @@ asynStatus PhytronAxis::stop(double acceleration )
|
|
|
|
|
//static const char *functionName = "PhytronAxis::stop";
|
|
|
|
|
char command[COMLEN], reply[COMLEN];
|
|
|
|
|
|
|
|
|
|
sprintf(command, "0%cSN", phytronChar);
|
|
|
|
|
sprintf(command, "%s%cSN", pC_->selector,phytronChar);
|
|
|
|
|
status = pC_->transactController(command,reply);
|
|
|
|
|
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
|
|
|
|
|
updateMsgTxtFromDriver("Axis interrupted");
|
|
|
|
|
|
|
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
@ -307,9 +319,9 @@ asynStatus PhytronAxis::setPosition(double position)
|
|
|
|
|
//static const char *functionName = "PhytronAxis::setPosition";
|
|
|
|
|
char command[COMLEN], reply[COMLEN];
|
|
|
|
|
|
|
|
|
|
sprintf(command, "0%cP22S%f", phytronChar, position/1000.);
|
|
|
|
|
sprintf(command, "%s%cP22S%f", pC_->selector,phytronChar, position/1000.);
|
|
|
|
|
status = pC_->transactController(command,reply);
|
|
|
|
|
sprintf(command, "0%cP20S%f", phytronChar, position/1000.);
|
|
|
|
|
sprintf(command, "%s%cP20S%f", pC_->selector,phytronChar, position/1000.);
|
|
|
|
|
status = pC_->transactController(command,reply);
|
|
|
|
|
next_poll = -1;
|
|
|
|
|
|
|
|
|
@ -349,9 +361,9 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
|
|
|
|
|
// Read the current motor position
|
|
|
|
|
if(encoder) {
|
|
|
|
|
sprintf(command,"0%cP22R",phytronChar);
|
|
|
|
|
sprintf(command,"%s%cP22R",pC_->selector,phytronChar);
|
|
|
|
|
} else {
|
|
|
|
|
sprintf(command,"0%cP20R",phytronChar);
|
|
|
|
|
sprintf(command,"%s%cP20R",pC_->selector,phytronChar);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
comStatus = pC_->transactController(command,reply);
|
|
|
|
@ -360,7 +372,8 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
if(strstr(reply,"NACK") != NULL){
|
|
|
|
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
|
|
|
|
errlogSevPrintf(errlogMajor, "Bad reply for position on %d", axisNo_);
|
|
|
|
|
goto skip;
|
|
|
|
|
updateMsgTxtFromDriver("Bad reply reading position");
|
|
|
|
|
goto skip;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
read over the ACK
|
|
|
|
@ -372,7 +385,7 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Read the moving status of this motor
|
|
|
|
|
sprintf(command,"0%c=H",phytronChar);
|
|
|
|
|
sprintf(command,"%s%c=H",pC_->selector,phytronChar);
|
|
|
|
|
comStatus = pC_->transactController(command,reply);
|
|
|
|
|
if(comStatus) goto skip;
|
|
|
|
|
/* errlogPrintf("Axis %d, status reply %s, position %lf\n", axisNo_, reply, position); */
|
|
|
|
@ -396,11 +409,12 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
/*
|
|
|
|
|
check limits and errors, upper
|
|
|
|
|
*/
|
|
|
|
|
sprintf(command,"0%c=I+",phytronChar);
|
|
|
|
|
sprintf(command,"%s%c=I+",pC_->selector,phytronChar);
|
|
|
|
|
comStatus = pC_->transactController(command,reply);
|
|
|
|
|
if(comStatus) goto skip;
|
|
|
|
|
if(strstr(reply,"ACKE") != NULL){
|
|
|
|
|
setIntegerParam(pC_->motorStatusHighLimit_, true);
|
|
|
|
|
updateMsgTxtFromDriver("High Limit Hit");
|
|
|
|
|
} else {
|
|
|
|
|
setIntegerParam(pC_->motorStatusHighLimit_, false);
|
|
|
|
|
}
|
|
|
|
@ -408,11 +422,12 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
/*
|
|
|
|
|
lower limit
|
|
|
|
|
*/
|
|
|
|
|
sprintf(command,"0%c=I-",phytronChar);
|
|
|
|
|
sprintf(command,"%s%c=I-",pC_->selector,phytronChar);
|
|
|
|
|
comStatus = pC_->transactController(command,reply);
|
|
|
|
|
if(comStatus) goto skip;
|
|
|
|
|
if(strstr(reply,"ACKE") != NULL){
|
|
|
|
|
setIntegerParam(pC_->motorStatusLowLimit_, true);
|
|
|
|
|
updateMsgTxtFromDriver("Low Limit Hit");
|
|
|
|
|
} else {
|
|
|
|
|
setIntegerParam(pC_->motorStatusLowLimit_, false);
|
|
|
|
|
}
|
|
|
|
@ -420,12 +435,13 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
/*
|
|
|
|
|
error
|
|
|
|
|
*/
|
|
|
|
|
sprintf(command,"0%c=E",phytronChar);
|
|
|
|
|
sprintf(command,"%s%c=E",pC_->selector,phytronChar);
|
|
|
|
|
comStatus = pC_->transactController(command,reply);
|
|
|
|
|
if(comStatus) goto skip;
|
|
|
|
|
if(strstr(reply,"ACKE") != NULL){
|
|
|
|
|
setIntegerParam(pC_->motorStatusProblem_, true);
|
|
|
|
|
errlogSevPrintf(errlogMajor, "Electronics on %d", axisNo_);
|
|
|
|
|
updateMsgTxtFromDriver("Electronics error");
|
|
|
|
|
} else {
|
|
|
|
|
setIntegerParam(pC_->motorStatusProblem_, false);
|
|
|
|
|
}
|
|
|
|
@ -442,16 +458,18 @@ asynStatus PhytronAxis::poll(bool *moving)
|
|
|
|
|
/** Code for iocsh registration */
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg0 = {"Port name", iocshArgString};
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg1 = {"Phytron port name", iocshArgString};
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg2 = {"EnoderX", iocshArgInt};
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg3 = {"EnoderY", iocshArgInt};
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg2 = {"Phytron Selector", iocshArgString};
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg3 = {"EnoderX", iocshArgInt};
|
|
|
|
|
static const iocshArg PhytronCreateControllerArg4 = {"EnoderY", iocshArgInt};
|
|
|
|
|
static const iocshArg * const PhytronCreateControllerArgs[] = {&PhytronCreateControllerArg0,
|
|
|
|
|
&PhytronCreateControllerArg1,
|
|
|
|
|
&PhytronCreateControllerArg2,
|
|
|
|
|
&PhytronCreateControllerArg3};
|
|
|
|
|
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 4, PhytronCreateControllerArgs};
|
|
|
|
|
&PhytronCreateControllerArg3,
|
|
|
|
|
&PhytronCreateControllerArg4};
|
|
|
|
|
static const iocshFuncDef PhytronCreateControllerDef = {"PhytronCreateController", 5, PhytronCreateControllerArgs};
|
|
|
|
|
static void PhytronCreateContollerCallFunc(const iocshArgBuf *args)
|
|
|
|
|
{
|
|
|
|
|
PhytronCreateController(args[0].sval, args[1].sval, args[2].ival,args[3].ival);
|
|
|
|
|
PhytronCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival,args[4].ival);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void PhytronRegister(void)
|
|
|
|
|