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
This commit is contained in:
2023-05-31 09:13:41 +02:00
parent f333a27482
commit 72afd02b4e
9 changed files with 394 additions and 183 deletions

View File

@ -141,6 +141,12 @@ asynStatus
SINQAxis *axis = getAxis(axisNo);
pasynOctetSyncIO->flush(pasynUserController_);
/* read with a short timeout in order to remove duplicate messages
* from the line. This also serves to slow down communication
*/
pasynOctetSyncIO->read(pasynUserController_, mmacsResponse, 35, .4, &in, &reason);
/* pack data for MasterMACS */
len = strlen(command) + 6;
mmacsData = (char *) malloc(len * sizeof(char));
@ -158,7 +164,7 @@ asynStatus
/* 0x03 is appended by asyn */
/* send the stuff away ... */
//errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
status =
pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData,
@ -180,13 +186,14 @@ asynStatus
}
free(mmacsData);
/* format and print the response in hex for debugging purposes
/* format and print the response in hex for debugging purposes */
/*
for(i = 0, idx = 0; i < in; i++){
sprintf(hexResponse + idx, "%02x ", (unsigned int)mmacsResponse[i]);
idx = strlen(hexResponse);
}
errlogSevPrintf(errlogMajor,"Reply in hex: %s\n", hexResponse);
*/
*/
/* Here we have read the data from the MasterMACS. We proceed to extract
* the payload and the state of the ACK byte and place that reply into data
@ -227,7 +234,7 @@ asynStatus
lenPayload = idx - 4;
memcpy(reply + 4, mmacsResponse + 4, lenPayload);
reply[4 + lenPayload] = (char) 0;
//errlogSevPrintf(errlogMajor, "Completed reply at end of transactController: %s ", reply);
errlogSevPrintf(errlogMajor, "Completed reply at end of transactController: %s ", reply);
return status;
}
@ -241,6 +248,7 @@ asynStatus
MasterMACSAxis *pAxis = NULL;
char command[64] = { 0 };
char response[64] = { 0 };
int devStatus;
pAxis = (MasterMACSAxis *) this->getAxis(pasynUser);
if (!pAxis) {
@ -252,19 +260,29 @@ asynStatus
pAxis->setIntegerParam(function, value);
if (function == enableAxis_) {
if (value == 1) {
/* download parameters, does not work as of now */
/*
sprintf(command, "%dS85=1.", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response);
*/
/*
* Read the status in order to prevent execssiove commands
*/
devStatus = pAxis->readStatus();
if(devStatus < 900){
return asynError;
}
if (value == 1 && !pAxis->isOn(devStatus) ) {
/* download parameters, does not work as of now */
/*
sprintf(command, "%dS85=1.", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response);
*/
/* actually enable */
sprintf(command, "%dS04=1.0", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response);
} else {
sprintf(command, "%dS04=0.0", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response);
/* actually enable */
sprintf(command, "%dS04=1", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response);
} else {
if(pAxis->isOn(devStatus)) {
// only send command when necessary
sprintf(command, "%dS04=0", pAxis->axisNo_);
status = transactController(pAxis->axisNo_, command, response);
}
}
if (status == asynSuccess) {
pAxis->updateMsgTxtFromDriver("");
@ -300,8 +318,13 @@ asynStatus
return asynError;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &fval);
devStatus = (int) fval;
if(pPtr) {
sscanf(pPtr + 1, "%f", &fval);
devStatus = (int) fval;
} else {
devStatus = 0;
errlogPrintf(" Bad reply %s when trying to read motor status %d\n", reply, pAxis->axisNo_);
}
isOn = pAxis->isOn(devStatus);
/* errlogPrintf("isOn in readInt32: %d, devStatus = %d\n", isOn, devStatus); */
setIntegerParam(axisEnabled_, isOn);
@ -343,6 +366,24 @@ void MasterMACSAxis::report(FILE * fp, int level)
}
}
int MasterMACSAxis::readStatus()
{
char command[COMLEN], reply[COMLEN], *pPtr;
float fval;
int devStatus, status;
sprintf(command, "%dR10", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
if (status == asynError) {
return -1000;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &fval);
devStatus = (int) fval;
return devStatus;
}
int MasterMACSAxis::isOn(int axisStatus)
{
if (CHECK_BIT(axisStatus, 0) && CHECK_BIT(axisStatus, 1)) {
@ -356,9 +397,8 @@ asynStatus
double maxVelocity, double acceleration)
{
asynStatus status;
char command[COMLEN], reply[COMLEN], *pPtr;
char command[COMLEN], reply[COMLEN];
int devStatus;
float fval;
errlogPrintf("minVelocity = %f, maxVelocity = %f\n", minVelocity,
maxVelocity);
@ -370,33 +410,33 @@ asynStatus
/*
* reset error code
*/
sprintf(command, "%dS17=0", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
if(errorCodeFound){
sprintf(command, "%dS17=0", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
errorCodeFound = 0;
}
/*
* test if the thing is On
*/
sprintf(command, "%dR10", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
if (status == asynError) {
return asynError;
devStatus = readStatus();
if(devStatus < 900) {
return asynError;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &fval);
devStatus = (int) fval;
if (!isOn(devStatus)) {
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled");
errlogPrintf("ERROR: trying to start disabled axis %d\n", axisNo_);
return asynError;
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled");
errlogPrintf("ERROR: trying to start disabled axis %d\n", axisNo_);
return asynError;
}
/*
* set speed
*/
/* temporarily disabled in order to get the basic logic right
sprintf(command, "%dS05=%f", axisNo_, maxVelocity / 1000);
status = pC_->transactController(axisNo_, command, reply);
*/
if (relative) {
position += this->position;
@ -432,28 +472,23 @@ asynStatus
double acceleration, int forwards)
{
asynStatus status;
char command[COMLEN], reply[COMLEN], *pPtr;
char command[COMLEN], reply[COMLEN];
int devStatus;
float fval;
memset(command, 0, COMLEN * sizeof(char));
/*
* test if the thing is On
*/
sprintf(command, "%dR10", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
if (status == asynError) {
return asynError;
devStatus = readStatus();
if(devStatus < 900) {
return asynError;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &fval);
devStatus = (int) fval;
if (!isOn(devStatus)) {
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled");
errlogPrintf("ERROR: trying to home disabled axis %d\n", axisNo_);
return asynError;
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled");
errlogPrintf("ERROR: trying to home disabled axis %d\n", axisNo_);
return asynError;
}
setIntegerParam(pC_->motorStatusProblem_, false);
@ -483,15 +518,20 @@ asynStatus MasterMACSAxis::stop(double acceleration)
{
asynStatus status = asynSuccess;
char command[COMLEN], reply[COMLEN];
int devStatus;
memset(command, 0, COMLEN * sizeof(char));
if (errorReported == 0) {
sprintf(command, "%dS00=8", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
updateMsgTxtFromDriver("Axis interrupted");
errorReported = 1;
devStatus = readStatus();
if(!CHECK_BIT(devStatus, 10)) {
// only try to stop when running ...
sprintf(command, "%dS00=8", axisNo_);
status = pC_->transactController(axisNo_, command, reply);
errlogPrintf("Sent STOP on Axis %d\n", axisNo_);
updateMsgTxtFromDriver("Axis interrupted");
errorReported = 1;
}
}
return status;
}
@ -525,7 +565,7 @@ asynStatus MasterMACSAxis::poll(bool * moving)
{
asynStatus comStatus = asynSuccess;
char command[COMLEN], reply[COMLEN], *pPtr;
float errStatus, fval;
float errStatus;
unsigned int errCode, derCode, devStatus;
// protect against excessive polling
@ -560,25 +600,21 @@ asynStatus MasterMACSAxis::poll(bool * moving)
// Read the overall status of this motor */
sprintf(command, "%dR10", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
goto skip;
devStatus = readStatus();
if(devStatus < 900) {
setIntegerParam(pC_->motorStatusProblem_, true);
goto skip;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &fval);
devStatus = (int) fval;
errlogPrintf("Axis %d, position %lf, devStatus %d\n", axisNo_,
position, devStatus);
if (!isOn(devStatus)) {
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled");
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
goto skip;
setIntegerParam(pC_->motorStatusProblem_, true);
updateMsgTxtFromDriver("Motor disabled");
*moving = false;
setIntegerParam(pC_->motorStatusDone_, true);
goto skip;
}
/*
@ -613,48 +649,13 @@ asynStatus MasterMACSAxis::poll(bool * moving)
setIntegerParam(pC_->motorStatusAtHome_, true);
}
/* read error codes */
sprintf(command, "%dR11", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
goto skip;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &errStatus);
errCode = (unsigned int) errStatus;
sprintf(command, "%dR18", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
goto skip;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &errStatus);
derCode = (unsigned int) errStatus;
errlogPrintf("Axis %d, errCode(R11) %d, derCode(R18) %d\n", axisNo_,
errCode, derCode);
setIntegerParam(pC_->motorStatusLowLimit_, false);
/* check for limit switches*/
setIntegerParam(pC_->motorStatusLowLimit_, false);
setIntegerParam(pC_->motorStatusHighLimit_, false);
if (errCode == 0) {
/* There still may be errors in the status code */
if (CHECK_BIT(devStatus, 3)) {
if (CHECK_BIT(devStatus, 11)) {
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor,
"Fault bit in status code, but no error code on %d",
axisNo_);
updateMsgTxtFromDriver
("Fault bit in status code without error code");
}
if (CHECK_BIT(devStatus, 11)) {
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor,
"Limit bit in status code, but no error code on %d",
"Limit bit in status code %d",
axisNo_);
/* guessing which limit has been hit ... */
if (position > 0) {
@ -666,69 +667,99 @@ asynStatus MasterMACSAxis::poll(bool * moving)
setIntegerParam(pC_->motorStatusLowLimit_, true);
setIntegerParam(pC_->motorStatusProblem_, false);
}
goto skip;
}
goto skip;
}
/* check for error conditions */
if (CHECK_BIT(devStatus, 3)) {
/* read error codes */
sprintf(command, "%dR11", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
goto skip;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &errStatus);
errCode = (unsigned int) errStatus;
/*
* from here on we are processing errors
*/
sprintf(command, "%dR18", axisNo_);
comStatus = pC_->transactController(axisNo_, command, reply);
if (comStatus == asynError) {
setIntegerParam(pC_->motorStatusProblem_, true);
goto skip;
}
pPtr = strstr(reply, "=");
sscanf(pPtr + 1, "%f", &errStatus);
derCode = (unsigned int) errStatus;
setIntegerParam(pC_->motorStatusProblem_, true);
errlogPrintf("Axis %d, errCode(R11) %d, derCode(R18) %d\n", axisNo_,
errCode, derCode);
if (CHECK_BIT(errCode, 0)) {
errlogSevPrintf(errlogMajor, "CAN error on %d", axisNo_);
updateMsgTxtFromDriver("CAN error");
} else if (CHECK_BIT(errCode, 1)) {
errlogSevPrintf(errlogMajor, "Short circuit on %d", axisNo_);
updateMsgTxtFromDriver("Short circuit");
} else if (CHECK_BIT(errCode, 2)) {
errlogSevPrintf(errlogMajor, "Invalide Setup on %d", axisNo_);
updateMsgTxtFromDriver("Invalid Setup");
} else if (CHECK_BIT(errCode, 3)) {
errlogSevPrintf(errlogMajor, "Control error on %d", axisNo_);
updateMsgTxtFromDriver("Control error");
} else if (CHECK_BIT(errCode, 4)) {
errlogSevPrintf(errlogMajor, "CAN communication error on %d",
setIntegerParam(pC_->motorStatusProblem_, true);
if (errCode == 0) {
setIntegerParam(pC_->motorStatusProblem_, true);
errlogSevPrintf(errlogMajor,
"Fault bit in status code, but no error code on %d\n", axisNo_);
updateMsgTxtFromDriver ("Fault bit in status code without error code");
goto skip;
}
errorCodeFound = 1;
if (CHECK_BIT(errCode, 0)) {
errlogSevPrintf(errlogMajor, "CAN error on %d", axisNo_);
updateMsgTxtFromDriver("CAN error");
} else if (CHECK_BIT(errCode, 1)) {
errlogSevPrintf(errlogMajor, "Short circuit on %d", axisNo_);
updateMsgTxtFromDriver("Short circuit");
} else if (CHECK_BIT(errCode, 2)) {
errlogSevPrintf(errlogMajor, "Invalide Setup on %d", axisNo_);
updateMsgTxtFromDriver("Invalid Setup");
} else if (CHECK_BIT(errCode, 3)) {
errlogSevPrintf(errlogMajor, "Control error on %d", axisNo_);
updateMsgTxtFromDriver("Control error");
} else if (CHECK_BIT(errCode, 4)) {
errlogSevPrintf(errlogMajor, "CAN communication error on %d",
axisNo_);
updateMsgTxtFromDriver("CAN communication error");
} else if (CHECK_BIT(errCode, 5)) {
errlogSevPrintf(errlogMajor, "Feedback error on %d", axisNo_);
updateMsgTxtFromDriver("Feedback error");
} else if (CHECK_BIT(errCode, 6)) {
updateMsgTxtFromDriver("Hit positive limit switch");
setIntegerParam(pC_->motorStatusHighLimit_, true);
setIntegerParam(pC_->motorStatusProblem_, false);
} else if (CHECK_BIT(errCode, 7)) {
updateMsgTxtFromDriver("Hit negative limit switch");
setIntegerParam(pC_->motorStatusLowLimit_, true);
setIntegerParam(pC_->motorStatusProblem_, false);
} else if (CHECK_BIT(errCode, 8)) {
errlogSevPrintf(errlogMajor, "Over current %d", axisNo_);
updateMsgTxtFromDriver("Over current");
} else if (CHECK_BIT(errCode, 9)) {
errlogSevPrintf(errlogMajor, "I2T protection on %d", axisNo_);
updateMsgTxtFromDriver("I2t protection");
} else if (CHECK_BIT(errCode, 10)) {
errlogSevPrintf(errlogMajor, "Over heated motor on %d", axisNo_);
updateMsgTxtFromDriver("Motor overheated");
} else if (CHECK_BIT(errCode, 11)) {
errlogSevPrintf(errlogMajor, "Over temperature drive on %d",
axisNo_);
updateMsgTxtFromDriver("CAN communication error");
} else if (CHECK_BIT(errCode, 5)) {
errlogSevPrintf(errlogMajor, "Feedback error on %d", axisNo_);
updateMsgTxtFromDriver("Feedback error");
} else if (CHECK_BIT(errCode, 6)) {
updateMsgTxtFromDriver("Hit positive limit switch");
setIntegerParam(pC_->motorStatusHighLimit_, true);
setIntegerParam(pC_->motorStatusProblem_, false);
} else if (CHECK_BIT(errCode, 7)) {
updateMsgTxtFromDriver("Hit negative limit switch");
setIntegerParam(pC_->motorStatusLowLimit_, true);
setIntegerParam(pC_->motorStatusProblem_, false);
} else if (CHECK_BIT(errCode, 8)) {
errlogSevPrintf(errlogMajor, "Over current %d", axisNo_);
updateMsgTxtFromDriver("Over current");
} else if (CHECK_BIT(errCode, 9)) {
errlogSevPrintf(errlogMajor, "I2T protection on %d", axisNo_);
updateMsgTxtFromDriver("I2t protection");
} else if (CHECK_BIT(errCode, 10)) {
errlogSevPrintf(errlogMajor, "Over heated motor on %d", axisNo_);
updateMsgTxtFromDriver("Motor overheated");
} else if (CHECK_BIT(errCode, 11)) {
errlogSevPrintf(errlogMajor, "Over temperature drive on %d",
axisNo_);
updateMsgTxtFromDriver("Over temperature drive");
} else if (CHECK_BIT(errCode, 12)) {
errlogSevPrintf(errlogMajor, "Over voltage on %d", axisNo_);
updateMsgTxtFromDriver("Over voltage");
} else if (CHECK_BIT(errCode, 13)) {
errlogSevPrintf(errlogMajor, "Under voltage on %d", axisNo_);
updateMsgTxtFromDriver("Under voltage");
} else if (CHECK_BIT(errCode, 14)) {
errlogSevPrintf(errlogMajor, "Command error on %d", axisNo_);
updateMsgTxtFromDriver("Command error");
} else if (CHECK_BIT(errCode, 15)) {
errlogSevPrintf(errlogMajor, "Motor disabled on %d", axisNo_);
updateMsgTxtFromDriver("Motor disabled");
}
updateMsgTxtFromDriver("Over temperature drive");
} else if (CHECK_BIT(errCode, 12)) {
errlogSevPrintf(errlogMajor, "Over voltage on %d", axisNo_);
updateMsgTxtFromDriver("Over voltage");
} else if (CHECK_BIT(errCode, 13)) {
errlogSevPrintf(errlogMajor, "Under voltage on %d", axisNo_);
updateMsgTxtFromDriver("Under voltage");
} else if (CHECK_BIT(errCode, 14)) {
errlogSevPrintf(errlogMajor, "Command error on %d", axisNo_);
updateMsgTxtFromDriver("Command error");
} else if (CHECK_BIT(errCode, 15)) {
errlogSevPrintf(errlogMajor, "Motor disabled on %d", axisNo_);
updateMsgTxtFromDriver("Motor disabled");
}
}
skip:
callParamCallbacks();

View File

@ -38,6 +38,8 @@ private:
int errorReported;
int hasStarted; /* The motor status is invalid if the thing has not run once */
int isOn(int axisStatus);
int readStatus();
int errorCodeFound;
friend class MasterMACSController;
};

View File

@ -77,12 +77,27 @@ PhytronController::PhytronController(const char *portName, const char *PhytronPo
pasynOctetSyncIO->setOutputEos(pasynUserController_,etx,strlen(etx));
pasynOctetSyncIO->setInputEos(pasynUserController_,etx,strlen(etx));
new PhytronAxis(this, 1, encX);
new PhytronAxis(this, 2, encY);
/* The special selector D selects the dose controlled axis version */
if(strcmp(sel, (const char *)"D") == 0) {
new PhytronDoseAxis(this, 1, encX);
new PhytronDoseAxis(this, 2, encY);
} else {
new PhytronAxis(this, 1, encX);
new PhytronAxis(this, 2, encY);
}
startPoller(1000./1000., IDLEPOLL, 2);
}
PhytronDoseController::PhytronDoseController(const char *portName, const char *PhytronPortName, const char *sel ,
int encX, int encY)
: PhytronController(portName, PhytronPortName, sel, encX, encY)
{
new PhytronDoseAxis(this, 1, encX);
new PhytronDoseAxis(this, 2, encY);
}
/** Creates a new PhytronController object.
* Configuration command, called directly or from iocsh
@ -97,6 +112,14 @@ extern "C" int PhytronCreateController(const char *portName, const char *Phytron
return(asynSuccess);
}
extern "C" int PhytronDoseCreateController(const char *portName, const char *PhytronPortName, const char *selector,
int encX, int encY)
{
new PhytronDoseController(portName, PhytronPortName,selector, encX, encY);
return(asynSuccess);
}
/** Reports on status of the driver
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
@ -129,6 +152,23 @@ PhytronAxis* PhytronController::getAxis(int axisNo)
return static_cast<PhytronAxis*>(asynMotorController::getAxis(axisNo));
}
/** Returns a pointer to an PhytronDoseAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
PhytronDoseAxis* PhytronDoseController::getAxis(asynUser *pasynUser)
{
return static_cast<PhytronDoseAxis*>(asynMotorController::getAxis(pasynUser));
}
/** Returns a pointer to an PhytronDoseAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
PhytronDoseAxis* PhytronDoseController::getAxis(int axisNo)
{
return static_cast<PhytronDoseAxis*>(asynMotorController::getAxis(axisNo));
}
/**
* send a command to the Phytron and read the reply. Do some error and controller
* issue fixing on the way
@ -569,6 +609,79 @@ asynStatus PhytronAxis::poll(bool *moving)
return comStatus;
}
/* The special PhytronDoseAxis code used when the speed is controlled through the neutron flux
*/
PhytronDoseAxis::PhytronDoseAxis(PhytronController *pC, int axisNo, int enc)
: PhytronAxis(pC, axisNo, enc)
{
if(axisNo == 1){
doseChar = '3';
} else {
doseChar = '4';
}
}
asynStatus PhytronDoseAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
//static const char *functionName = "PhytronDoseAxis::move";
char command[COMLEN], reply[COMLEN];
float realTarget;
updateMsgTxtFromDriver("");
/*
set conversion factor from neutron rate to speed
*/
sprintf(command, "R%c3S%f", doseChar, maxVelocity);
status = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Speed not accepted on %d", axisNo_);
updateMsgTxtFromDriver("Invalid speed");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
/*
actually send a move command
*/
if (relative) {
position += this->position;
}
homing = 0;
/* set target */
realTarget = position/1000.;
if(realTarget > this->position) {
sprintf(command, "R%c1S%f", doseChar,realTarget);
} else {
sprintf(command, "R%c2S%f", doseChar,realTarget);
}
status = pC_->transactController(axisNo_,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;
}
/* really start the move */
sprintf(command, "R%c01S", doseChar);
status = pC_->transactController(axisNo_,command,reply);
if(strstr(reply,"NACK") != NULL){
errlogSevPrintf(errlogMajor, "Drive start command not acknowledged on %d", axisNo_);
updateMsgTxtFromDriver("Drive command not acknowledged");
setIntegerParam(pC_->motorStatusProblem_, true);
return asynError;
}
next_poll = -1;
return status;
}
extern "C" asynStatus PhytronConfBrake(const char *port, /* specify which controller by port name */
int axis, /* axis: 0, 1 */
int brakeNO) /* brakeIO No, 1-8 */
@ -615,6 +728,21 @@ static void PhytronCreateContollerCallFunc(const iocshArgBuf *args)
PhytronCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival,args[4].ival);
}
static const iocshArg PhytronDoseCreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg PhytronDoseCreateControllerArg1 = {"Phytron port name", iocshArgString};
static const iocshArg PhytronDoseCreateControllerArg2 = {"Phytron Selector", iocshArgString};
static const iocshArg PhytronDoseCreateControllerArg3 = {"EncoderX", iocshArgInt};
static const iocshArg PhytronDoseCreateControllerArg4 = {"EncoderY", iocshArgInt};
static const iocshArg * const PhytronDoseCreateControllerArgs[] = {&PhytronDoseCreateControllerArg0,
&PhytronDoseCreateControllerArg1,
&PhytronDoseCreateControllerArg2,
&PhytronDoseCreateControllerArg3,
&PhytronDoseCreateControllerArg4};
static const iocshFuncDef PhytronDoseCreateControllerDef = {"PhytronDoseCreateController", 5, PhytronDoseCreateControllerArgs};
static void PhytronDoseCreateContollerCallFunc(const iocshArgBuf *args)
{
PhytronDoseCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival,args[4].ival);
}
/* PhytronConfigureBrake */
static const iocshArg phytronBrakeArg0 = {"Controller port name", iocshArgString};
@ -634,6 +762,7 @@ static void phytronBrakeCallFunc(const iocshArgBuf *args)
static void PhytronRegister(void)
{
iocshRegister(&PhytronCreateControllerDef, PhytronCreateContollerCallFunc);
iocshRegister(&PhytronDoseCreateControllerDef, PhytronDoseCreateContollerCallFunc);
iocshRegister(&phytronBrakeDef, phytronBrakeCallFunc);
}

View File

@ -10,6 +10,11 @@ Updated to go through SINQAxis for -MsgTxt support
Added a selector to support multiple phytrons on a connection
Mark Koennecke, January 2019
Added PhytronDoseAxis. The speed of this axis is controlled by the
neutron dose rate fed in as analog signal
Mark Koennecke, April 2023
*/
#include "SINQController.h"
@ -17,6 +22,10 @@ Mark Koennecke, January 2019
#define COMLEN 80
class PhytronController;
class PhytronDoseController;
class PhytronAxis : public SINQAxis
{
public:
@ -32,7 +41,7 @@ public:
asynStatus setClosedLoop(bool closedLoop);
int setBrake(int brakeIO);
private:
protected:
char phytronChar;
PhytronController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
* Abbreviated because it is used very frequently */
@ -47,6 +56,21 @@ private:
friend class PhytronController;
};
class PhytronDoseAxis : public PhytronAxis
{
// A special version of PhytronAxis where the speed is controlled by the neutron flux.
public:
PhytronDoseAxis(class PhytronController *pC, int axis, int enc);
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
friend class PhytronDoseController;
protected:
char doseChar;
PhytronDoseController *pC_;
};
class PhytronController : public SINQController {
public:
PhytronController(const char *portName, const char *PhytronPortName, const char *selector,
@ -57,7 +81,8 @@ public:
PhytronAxis* getAxis(int axisNo);
friend class PhytronAxis;
private:
protected:
asynUser *pasynUserController_;
asynStatus transactController(int axisNo, char command[COMLEN], char reply[COMLEN]);
@ -65,3 +90,20 @@ friend class PhytronAxis;
const char *selector;
};
class PhytronDoseController : public PhytronController {
public:
PhytronDoseController(const char *portName, const char *PhytronPortName, const char *selector,
int encX, int encY);
PhytronDoseAxis* getAxis(asynUser *pasynUser);
PhytronDoseAxis* getAxis(int axisNo);
friend class PhytronDoseAxis;
protected:
asynUser *pasynUserController_;
const char *selector;
};

View File

@ -389,7 +389,7 @@ static asynStatus el737_transactCommand(EL737priv *priv,char command[COMLEN],cha
if(errno == EAGAIN){
errlogPrintf("Lost response to %s with EAGAIN\n", command);
} else {
strncpy(message,"Lost communication",sizeof(message));
snprintf(message,sizeof(message), "Lost communication with errno %d", errno);
}
}
if(priv->dbInit){
@ -455,9 +455,7 @@ static void runEvents(EL737priv *priv)
if(priv->sendThreshold == 1) {
// fallback when we do not have the DB fields or threshCounter is invalid
if(priv->presets[THRESHMON] <= 0) {
errlogPrintf("Invalid threshold preset monitor %ld, no threshold sent\n", priv->presets[THRESHMON]);
} else {
if(priv->presets[THRESHMON] > 0) {
sprintf(command,"DL %d %d", (int)priv->presets[THRESHMON],
(int)priv->presets[THRESHVAL]);
errlogPrintf("Sending threshold from presets, command %s\n", command);
@ -465,7 +463,7 @@ static void runEvents(EL737priv *priv)
sprintf(command,"DR %d", (int)priv->presets[THRESHMON]);
status = el737_transactCommand(priv, command,reply);
if(status == asynSuccess) {
priv->sendThreshold = 0;
priv->sendThreshold = 0;
}
}
}

View File

@ -842,15 +842,9 @@ asynStatus pmacV3Controller::writeInt32(asynUser *pasynUser, epicsInt32 value) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_FLOW,
"%s: Enable axis on controller %s, axis %d enable=%d\n",
functionName, portName, pAxis->axisNo_, value);
if(value){
pAxis->updateMsgTxtFromDriver("");
}
}
// Execute the command.
if (command[0] != 0 && status == asynSuccess) {
pAxis->updateMsgTxtFromDriver("");
lowLevelWriteRead(pAxis->axisNo_, command, response);
}
}
return pmacController::writeInt32(pasynUser, value);
}

View File

@ -1,19 +1,33 @@
#!/usr/local/bin/iocsh
require sinq,koennecke
require autosave,koennecke
epicsEnvSet("TOP","/afs/psi.ch/project/sinqdev/sinqepicsapp/testmmac")
set_requestfile_path("$(TOP)", "")
set_savefile_path("$(TOP)/autosave")
save_restoreSet_Debug(0)
#--------------------------------- restore autosave
set_pass0_restoreFile("$(TOP)/autosave/test.sav","")
set_pass1_restoreFile("$(TOP)/autosave/test.sav","")
#drvAsynMMACSPortConfigure("macs1", "localhost:8080",0,0,0)
#asynInterposeEosConfig("macs1", 0, 0, 0)
#dbLoadRecords("$(TOP)/db/asynRecord.db","P=KM36:,R=macs1,PORT=macs1,ADDR=0,OMAX=80,IMAX=80")
#asynSetTraceMask("macs1", 0, 255)
drvAsynIPPortConfigure("macs1", "localhost:8080",0,0,0)
#asynSetTraceMask("macs1", 0, 255)
#drvAsynIPPortConfigure("macs1", "localhost:8080",0,0,0)
drvAsynIPPortConfigure("macs1", "Marcel1--MACS:1917")
MasterMACSCreateController("mota","macs1",7)
MasterMACSCreateAxis("mota",5)
MasterMACSCreateAxis("mota",6)
dbLoadTemplate "mmacs2.sub"
iocInit()
create_monitor_set("test.req", 10, "")

View File

@ -59,6 +59,7 @@ def scan_substitution_file(filename):
# import pdb; pdb.set_trace()
with open(filename, 'r') as fin:
rawline = fin.readline()
import pdb; pdb.set_trace()
while rawline:
line = rawline.replace(' ','')
line = line.strip('{}')

View File

@ -63,8 +63,8 @@ def fix_line(par_list, index_list):
highidx = index_list.index('DHLM')
par_list[highidx] = highlim.strip()
speed = transact('Q%d03' % motNo)
speedidx = index_list['VELO']
par_list[speedidx] = speed.trim()
speedidx = index_list.index('VELO')
par_list[speedidx] = speed.strip()
return par_list
def scan_substitution_file(filename):