diff --git a/sinqEPICSApp/src/MasterMACSDriver.cpp b/sinqEPICSApp/src/MasterMACSDriver.cpp index 7add320..b1d1db6 100644 --- a/sinqEPICSApp/src/MasterMACSDriver.cpp +++ b/sinqEPICSApp/src/MasterMACSDriver.cpp @@ -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(); diff --git a/sinqEPICSApp/src/MasterMACSDriver.h b/sinqEPICSApp/src/MasterMACSDriver.h index 1a89477..e51430a 100644 --- a/sinqEPICSApp/src/MasterMACSDriver.h +++ b/sinqEPICSApp/src/MasterMACSDriver.h @@ -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; }; diff --git a/sinqEPICSApp/src/PhytronDriver.cpp b/sinqEPICSApp/src/PhytronDriver.cpp index 17645b1..ae6a617 100644 --- a/sinqEPICSApp/src/PhytronDriver.cpp +++ b/sinqEPICSApp/src/PhytronDriver.cpp @@ -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(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(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(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); } diff --git a/sinqEPICSApp/src/PhytronDriver.h b/sinqEPICSApp/src/PhytronDriver.h index dc6bb4a..421a7a0 100644 --- a/sinqEPICSApp/src/PhytronDriver.h +++ b/sinqEPICSApp/src/PhytronDriver.h @@ -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; + +}; + diff --git a/sinqEPICSApp/src/devScalerEL737.c b/sinqEPICSApp/src/devScalerEL737.c index 4724db2..73612fd 100644 --- a/sinqEPICSApp/src/devScalerEL737.c +++ b/sinqEPICSApp/src/devScalerEL737.c @@ -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; } } } diff --git a/sinqEPICSApp/src/pmacController.cpp b/sinqEPICSApp/src/pmacController.cpp index 7ad60c0..af752df 100644 --- a/sinqEPICSApp/src/pmacController.cpp +++ b/sinqEPICSApp/src/pmacController.cpp @@ -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); } diff --git a/testmmac/testmmacs.cmd b/testmmac/testmmacs.cmd index 19c0833..08b5c4d 100755 --- a/testmmac/testmmacs.cmd +++ b/testmmac/testmmacs.cmd @@ -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, "") + diff --git a/utils/syncMasterMAC.py b/utils/syncMasterMAC.py index f15eb65..eda6dda 100755 --- a/utils/syncMasterMAC.py +++ b/utils/syncMasterMAC.py @@ -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('{}') diff --git a/utils/syncPmacSub.py b/utils/syncPmacSub.py index 4185e9a..c57c943 100755 --- a/utils/syncPmacSub.py +++ b/utils/syncPmacSub.py @@ -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):