diff --git a/sinqEPICSApp/src/MasterMACSDriver.cpp b/sinqEPICSApp/src/MasterMACSDriver.cpp index 157d6af..79b5602 100644 --- a/sinqEPICSApp/src/MasterMACSDriver.cpp +++ b/sinqEPICSApp/src/MasterMACSDriver.cpp @@ -4,6 +4,7 @@ Marcel Schildt Mark Koennecke, March-August 2023 + Mark Koenencke, More fixes in June 2024 */ @@ -13,6 +14,7 @@ #include #include #include +#include #include #include @@ -28,6 +30,18 @@ #define ABS(x) (x < 0 ? -(x) : (x)) #define debug 0 +#define timeDebug 0 + +double DoubleTime(void) +{ + struct timeval now; + /* the resolution of this function is usec, if the machine supports this + and the mantissa of a double is 51 bits or more (31 bits for seconds + and 20 for microseconds) + */ + gettimeofday(&now, NULL); + return now.tv_sec + now.tv_usec / 1e6; +} /** Creates a new MasterMACSController object. * \param[in] portName The name of the asyn port that will be created for this driver @@ -141,6 +155,7 @@ asynStatus size_t in, out; int reason, len, idx, lenPayload; unsigned int i; + double startTime, now; char *mmacsData = NULL, ackchar, mmacsResponse[COMLEN], hexResponse[256]; SINQAxis *axis = getAxis(axisNo); @@ -173,10 +188,19 @@ asynStatus errlogSevPrintf(errlogMajor,"Sending command: %s\n", command); } + startTime = DoubleTime(); status = pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData, - len - 1, mmacsResponse, 35, 5., &out, + len - 1, mmacsResponse, 35, 10., &out, &in, &reason); + + if(timeDebug) { + now = DoubleTime(); + if((now - startTime) > 1.) { + errlogSevPrintf(errlogMajor, "Unusual response time %lf to command %s\n", (now - startTime), command); + } + } + if (status != asynSuccess) { if (axis != NULL) { errlogSevPrintf(errlogMajor, @@ -247,6 +271,34 @@ asynStatus return status; } +/*--------------------------------------------------------------------------------------------*/ +asynStatus + MasterMACSController::readInt32(asynUser * pasynUser, + epicsInt32 * value) +{ + + int function = pasynUser->reason; + MasterMACSAxis *pAxis = NULL; + int devStatus, isOn; + + pAxis = (MasterMACSAxis *) (this->getAxis(pasynUser)); + if (!pAxis) { + return asynError; + } + if (function == axisEnabled_) { + devStatus = pAxis->readStatus(); + isOn = pAxis->isOn(devStatus); + // errlogPrintf("isOn in readInt32: %d, devStatus = %d\n", isOn, devStatus); + pAxis->setIntegerParam(enableAxis_, isOn); + pAxis->setIntegerParam(axisEnabled_, isOn); + *value = isOn; + callParamCallbacks(); + return asynSuccess; + } + return asynMotorController::readInt32(pasynUser, value); +} +/*------------------------------------------------------------------------------------------*/ + asynStatus MasterMACSController::writeInt32(asynUser * pasynUser, epicsInt32 value) @@ -305,10 +357,14 @@ asynStatus errlogPrintf("MMACS: Failure to enable or disable axis %d", pAxis->axisNo_); } + /* + * wait max 2 seconds for success of the operation + */ startTime = time(NULL); while(time(NULL) < startTime + 2.){ // wait for the change to happen devStatus = pAxis->readStatus(); + // errlogPrintf("MMACS: switching enable: target, devStatus, isOn: %d, %d, %d\n", value, devStatus, pAxis->isOn(devStatus)); if(pAxis->isOn(devStatus) == value){ pAxis->active = true; pAxis->poll(&moving); // to update the Enable_RBV field @@ -317,7 +373,7 @@ asynStatus } usleep(200); } - errlogPrintf("MMACS: Failed to enable motor %d within 2 seconds\n", pAxis->axisNo_); + errlogPrintf("MMACS: Failed to dis/enable motor %d within 2 seconds\n", pAxis->axisNo_); } return asynMotorController::writeInt32(pasynUser, value); } @@ -332,11 +388,17 @@ asynStatus * Initializes register numbers, etc. */ MasterMACSAxis::MasterMACSAxis(MasterMACSController * pC, int axisNo):SINQAxis(pC, axisNo), -pC_ -(pC) +pC_(pC) { hasStarted = false; active = false; + errorCodeFound = 0; + /* + * Try to read the initial enable status of the motor + */ + int devStatus = readStatus(); + setIntegerParam(pC_->enableAxis_, isOn(devStatus)); + setIntegerParam(pC_->axisEnabled_, isOn(devStatus)); } /** Reports on status of the axis @@ -361,7 +423,7 @@ int MasterMACSAxis::readStatus() /* * The MasterMACS sends invalid responses with a low frequency. * Therefore I send cached status responses in such a case in order - * to help the logic evrywhere else in the code. + * to help the logic everywhere else in the code. */ sprintf(command, "%dR10", axisNo_); status = pC_->transactController(axisNo_, command, reply); @@ -548,7 +610,7 @@ asynStatus MasterMACSAxis::poll(bool * moving) { asynStatus comStatus = asynSuccess; char command[COMLEN], reply[COMLEN], *pPtr, buffer[80]; - unsigned int errCode, derCode, devStatus; + unsigned int errCode, derCode, devStatus = 0; float errStatus; struct tm* tm_info; time_t timer; @@ -599,7 +661,7 @@ asynStatus MasterMACSAxis::poll(bool * moving) // Read the overall status of this motor */ devStatus = readStatus(); - if(debug) { + if(debug || timeDebug) { errlogPrintf("Axis %d, position %lf, devStatus %d\n", axisNo_, position, devStatus); } diff --git a/sinqEPICSApp/src/MasterMACSDriver.h b/sinqEPICSApp/src/MasterMACSDriver.h index 98ccf62..3470f59 100644 --- a/sinqEPICSApp/src/MasterMACSDriver.h +++ b/sinqEPICSApp/src/MasterMACSDriver.h @@ -62,6 +62,7 @@ public: MasterMACSAxis* getAxis(int axisNo); // overloaded because we want to enable/disable the motor + asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value); asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); friend class MasterMACSAxis; diff --git a/sinqEPICSApp/src/pmacAxis.cpp b/sinqEPICSApp/src/pmacAxis.cpp index dd6b53e..79cd046 100644 --- a/sinqEPICSApp/src/pmacAxis.cpp +++ b/sinqEPICSApp/src/pmacAxis.cpp @@ -596,7 +596,7 @@ asynStatus pmacHRPTAxis::getAxisStatus(bool *moving) { char response[pC_->PMAC_MAXBUF_]; int cmdStatus = 0, nvals, crashSignal; - asynStatus result = pmacAxis::getAxisStatus(moving); + asynStatus result = pmacV3Axis::getAxisStatus(moving); sprintf(command, "P%2.2d53", axisNo_); cmdStatus = pC_->lowLevelWriteRead(axisNo_, command, response); nvals = sscanf(response, "%d", &crashSignal); diff --git a/sinqEPICSApp/src/pmacAxis.h b/sinqEPICSApp/src/pmacAxis.h index 83712c2..658a2ec 100644 --- a/sinqEPICSApp/src/pmacAxis.h +++ b/sinqEPICSApp/src/pmacAxis.h @@ -70,22 +70,6 @@ protected: friend class pmacController; friend class pmacV3Controller; }; -/*----------------------------------------------------------------------------------------------*/ -class pmacHRPTAxis : public pmacAxis -{ - public: - pmacHRPTAxis(pmacController *pController, int axisNo) : pmacAxis(pController,axisNo) {}; - /** - * Override getAxisStatus in order to read the special parameter indicating a - * slit blade crash at HRPT - */ - asynStatus getAxisStatus(bool *moving); - - protected: - friend class pmacController; - -}; - /*--------------------------------------------------------------------------------------------*/ class SeleneAxis : public pmacAxis { @@ -157,6 +141,23 @@ public: friend class pmacV3Controller; }; +/*----------------------------------------------------------------------------------------------*/ +class pmacHRPTAxis : public pmacV3Axis +{ + public: + pmacHRPTAxis(pmacController *pController, int axisNo) : pmacV3Axis(pController,axisNo) {}; + /** + * Override getAxisStatus in order to read the special parameter indicating a + * slit blade crash at HRPT + */ + asynStatus getAxisStatus(bool *moving); + + protected: + friend class pmacController; + +}; + + /* * Special motors for the AMOR detector movement. The whole * command set is different but on a pmac controller. This implements diff --git a/sinqEPICSApp/src/pmacController.cpp b/sinqEPICSApp/src/pmacController.cpp index 877581b..8548e32 100644 --- a/sinqEPICSApp/src/pmacController.cpp +++ b/sinqEPICSApp/src/pmacController.cpp @@ -869,10 +869,14 @@ static const char *functionName = "pmacV3Controller::writeInt32"; snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_); this->lowLevelWriteRead(pAxis->axisNo_, command, response); isOn = strtol(response, NULL, 10) != -3; + /* This was an attempt at automatically reading the encoder. + This is disabled as it did not work. + */ if(value == 1 && isOn) { sprintf(command, "M%2.2d=15", pAxis->axisNo_); // lowLevelWriteRead(pAxis->axisNo_, command, response); } + // Valid code continues here sprintf(command, "M%2.2d14=%d", pAxis->axisNo_, value); pAxis->updateMsgTxtFromDriver(""); if(isOn != value) { diff --git a/utils/macmaster.py b/utils/macmaster.py index f625a37..838e900 100755 --- a/utils/macmaster.py +++ b/utils/macmaster.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 """ Usage: macmaster.py macmasterhost port Listen for commands to send and returns reponse diff --git a/utils/physhell.tcl b/utils/physhell.tcl new file mode 100755 index 0000000..9bf68cf --- /dev/null +++ b/utils/physhell.tcl @@ -0,0 +1,58 @@ +#!/usr/bin/tclsh +# This is a little program which acts as a shell to the phytron. +# It connects to another program which is supposed to talk to the phytron controller +# It reads from stdin, packages the message into the phytron format and sends it to +# the phytron communication program. Then it reads from the phytron communication program +# and unpacks the reply. +# +# This is also a nice exampe for dealing with binary in Tcl +# Making the binary character only worked with %c +# The only way to do the comparison is with the string comare +# +# Mark Könnecke, September 2016 + + +if {[llength $argv] < 1} { + puts stdout "Usage:\n\t physhell.tcl phytronprogram" + exit +} + +set phprogram [lindex $argv 0] + +set phyio [open "| $phprogram" "w+b"] +fconfigure $phyio -buffering none +fconfigure $phyio -translation {binary binary} +set etx [format "%c" 0x03] +set stx [format "%c" 0x02] +set ack [format "%c" 0x06] +set nack [format "%c" 0x05] + + +while {1} { + set inp [gets stdin] + puts -nonewline $phyio [format "%c%s%c" 0x02 $inp 0x03] + set mode start + set reply "" + while {[string compare $mode done] != 0 } { + set c [read $phyio 1] + switch $mode { + start { + if {[string compare $c $stx] == 0} { + set mode data + } + } + data { + if {[string compare $c $etx] == 0} { + puts stdout $reply + set mode done + } elseif {[string compare $c $nack] == 0} { + append reply NACK + } elseif {[string compare $c $ack] == 0} { + append reply ACK + } else { + append reply $c + } + } + } + } +} diff --git a/utils/syncEL734Sub.py b/utils/syncEL734Sub.py index df52660..caa4903 100755 --- a/utils/syncEL734Sub.py +++ b/utils/syncEL734Sub.py @@ -11,6 +11,7 @@ Mark Koennecke, January 2023 import socket import sys +import time socke = None sockfd = None @@ -33,6 +34,7 @@ def transact(command): global socke, sockfd sockfd.write(command + '\r') sockfd.flush() + time.sleep(.1) return sockfd.readline() def find_commas(rawline): @@ -61,8 +63,10 @@ def fix_line(par_list, index_list): addridx = index_list.index('ADDR') motNo = par_list[addridx] limits = transact('H ' + motNo) + time.sleep(.1) l = limits.split() lowidx = index_list.index('DLLM') + # import pdb; pdb.set_trace() par_list[lowidx] = l[0] highidx = index_list.index('DHLM') par_list[highidx] = l[1] @@ -93,7 +97,7 @@ def scan_substitution_file(filename): newlist = fix_line(l, index_list) # newline = ','.join(newlist) newline = pretty_line(newlist, comma_list) - sys.stdout.write('{' + newline) + sys.stdout.write('{' + newline + '\n') else: sys.stdout.write(rawline) rawline = fin.readline()