- Fixed a enable PV initialisation bug in MasterMACS
- Made the HRPT axis base itself on V3 of the pmacAxis - Improved and added utils programs
This commit is contained in:
@ -4,6 +4,7 @@
|
|||||||
Marcel Schildt
|
Marcel Schildt
|
||||||
|
|
||||||
Mark Koennecke, March-August 2023
|
Mark Koennecke, March-August 2023
|
||||||
|
Mark Koenencke, More fixes in June 2024
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
@ -13,6 +14,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <sys/time.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
@ -28,6 +30,18 @@
|
|||||||
#define ABS(x) (x < 0 ? -(x) : (x))
|
#define ABS(x) (x < 0 ? -(x) : (x))
|
||||||
|
|
||||||
#define debug 0
|
#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.
|
/** Creates a new MasterMACSController object.
|
||||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
* \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;
|
size_t in, out;
|
||||||
int reason, len, idx, lenPayload;
|
int reason, len, idx, lenPayload;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
double startTime, now;
|
||||||
char *mmacsData =
|
char *mmacsData =
|
||||||
NULL, ackchar, mmacsResponse[COMLEN], hexResponse[256];
|
NULL, ackchar, mmacsResponse[COMLEN], hexResponse[256];
|
||||||
SINQAxis *axis = getAxis(axisNo);
|
SINQAxis *axis = getAxis(axisNo);
|
||||||
@ -173,10 +188,19 @@ asynStatus
|
|||||||
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
|
errlogSevPrintf(errlogMajor,"Sending command: %s\n", command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
startTime = DoubleTime();
|
||||||
status =
|
status =
|
||||||
pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData,
|
pasynOctetSyncIO->writeRead(pasynUserController_, mmacsData,
|
||||||
len - 1, mmacsResponse, 35, 5., &out,
|
len - 1, mmacsResponse, 35, 10., &out,
|
||||||
&in, &reason);
|
&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 (status != asynSuccess) {
|
||||||
if (axis != NULL) {
|
if (axis != NULL) {
|
||||||
errlogSevPrintf(errlogMajor,
|
errlogSevPrintf(errlogMajor,
|
||||||
@ -247,6 +271,34 @@ asynStatus
|
|||||||
return status;
|
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
|
asynStatus
|
||||||
MasterMACSController::writeInt32(asynUser * pasynUser,
|
MasterMACSController::writeInt32(asynUser * pasynUser,
|
||||||
epicsInt32 value)
|
epicsInt32 value)
|
||||||
@ -305,10 +357,14 @@ asynStatus
|
|||||||
errlogPrintf("MMACS: Failure to enable or disable axis %d",
|
errlogPrintf("MMACS: Failure to enable or disable axis %d",
|
||||||
pAxis->axisNo_);
|
pAxis->axisNo_);
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* wait max 2 seconds for success of the operation
|
||||||
|
*/
|
||||||
startTime = time(NULL);
|
startTime = time(NULL);
|
||||||
while(time(NULL) < startTime + 2.){
|
while(time(NULL) < startTime + 2.){
|
||||||
// wait for the change to happen
|
// wait for the change to happen
|
||||||
devStatus = pAxis->readStatus();
|
devStatus = pAxis->readStatus();
|
||||||
|
// errlogPrintf("MMACS: switching enable: target, devStatus, isOn: %d, %d, %d\n", value, devStatus, pAxis->isOn(devStatus));
|
||||||
if(pAxis->isOn(devStatus) == value){
|
if(pAxis->isOn(devStatus) == value){
|
||||||
pAxis->active = true;
|
pAxis->active = true;
|
||||||
pAxis->poll(&moving); // to update the Enable_RBV field
|
pAxis->poll(&moving); // to update the Enable_RBV field
|
||||||
@ -317,7 +373,7 @@ asynStatus
|
|||||||
}
|
}
|
||||||
usleep(200);
|
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);
|
return asynMotorController::writeInt32(pasynUser, value);
|
||||||
}
|
}
|
||||||
@ -332,11 +388,17 @@ asynStatus
|
|||||||
* Initializes register numbers, etc.
|
* Initializes register numbers, etc.
|
||||||
*/
|
*/
|
||||||
MasterMACSAxis::MasterMACSAxis(MasterMACSController * pC, int axisNo):SINQAxis(pC, axisNo),
|
MasterMACSAxis::MasterMACSAxis(MasterMACSController * pC, int axisNo):SINQAxis(pC, axisNo),
|
||||||
pC_
|
pC_(pC)
|
||||||
(pC)
|
|
||||||
{
|
{
|
||||||
hasStarted = false;
|
hasStarted = false;
|
||||||
active = 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
|
/** Reports on status of the axis
|
||||||
@ -361,7 +423,7 @@ int MasterMACSAxis::readStatus()
|
|||||||
/*
|
/*
|
||||||
* The MasterMACS sends invalid responses with a low frequency.
|
* The MasterMACS sends invalid responses with a low frequency.
|
||||||
* Therefore I send cached status responses in such a case in order
|
* 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_);
|
sprintf(command, "%dR10", axisNo_);
|
||||||
status = pC_->transactController(axisNo_, command, reply);
|
status = pC_->transactController(axisNo_, command, reply);
|
||||||
@ -548,7 +610,7 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
|||||||
{
|
{
|
||||||
asynStatus comStatus = asynSuccess;
|
asynStatus comStatus = asynSuccess;
|
||||||
char command[COMLEN], reply[COMLEN], *pPtr, buffer[80];
|
char command[COMLEN], reply[COMLEN], *pPtr, buffer[80];
|
||||||
unsigned int errCode, derCode, devStatus;
|
unsigned int errCode, derCode, devStatus = 0;
|
||||||
float errStatus;
|
float errStatus;
|
||||||
struct tm* tm_info;
|
struct tm* tm_info;
|
||||||
time_t timer;
|
time_t timer;
|
||||||
@ -599,7 +661,7 @@ asynStatus MasterMACSAxis::poll(bool * moving)
|
|||||||
|
|
||||||
// Read the overall status of this motor */
|
// Read the overall status of this motor */
|
||||||
devStatus = readStatus();
|
devStatus = readStatus();
|
||||||
if(debug) {
|
if(debug || timeDebug) {
|
||||||
errlogPrintf("Axis %d, position %lf, devStatus %d\n", axisNo_,
|
errlogPrintf("Axis %d, position %lf, devStatus %d\n", axisNo_,
|
||||||
position, devStatus);
|
position, devStatus);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ public:
|
|||||||
MasterMACSAxis* getAxis(int axisNo);
|
MasterMACSAxis* getAxis(int axisNo);
|
||||||
|
|
||||||
// overloaded because we want to enable/disable the motor
|
// overloaded because we want to enable/disable the motor
|
||||||
|
asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value);
|
||||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||||
|
|
||||||
friend class MasterMACSAxis;
|
friend class MasterMACSAxis;
|
||||||
|
@ -596,7 +596,7 @@ asynStatus pmacHRPTAxis::getAxisStatus(bool *moving) {
|
|||||||
char response[pC_->PMAC_MAXBUF_];
|
char response[pC_->PMAC_MAXBUF_];
|
||||||
int cmdStatus = 0, nvals, crashSignal;
|
int cmdStatus = 0, nvals, crashSignal;
|
||||||
|
|
||||||
asynStatus result = pmacAxis::getAxisStatus(moving);
|
asynStatus result = pmacV3Axis::getAxisStatus(moving);
|
||||||
sprintf(command, "P%2.2d53", axisNo_);
|
sprintf(command, "P%2.2d53", axisNo_);
|
||||||
cmdStatus = pC_->lowLevelWriteRead(axisNo_, command, response);
|
cmdStatus = pC_->lowLevelWriteRead(axisNo_, command, response);
|
||||||
nvals = sscanf(response, "%d", &crashSignal);
|
nvals = sscanf(response, "%d", &crashSignal);
|
||||||
|
@ -70,22 +70,6 @@ protected:
|
|||||||
friend class pmacController;
|
friend class pmacController;
|
||||||
friend class pmacV3Controller;
|
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
|
class SeleneAxis : public pmacAxis
|
||||||
{
|
{
|
||||||
@ -157,6 +141,23 @@ public:
|
|||||||
friend class pmacV3Controller;
|
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
|
* Special motors for the AMOR detector movement. The whole
|
||||||
* command set is different but on a pmac controller. This implements
|
* command set is different but on a pmac controller. This implements
|
||||||
|
@ -869,10 +869,14 @@ static const char *functionName = "pmacV3Controller::writeInt32";
|
|||||||
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
snprintf(command, sizeof(command), "P%2.2d00", pAxis->axisNo_);
|
||||||
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
this->lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||||
isOn = strtol(response, NULL, 10) != -3;
|
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) {
|
if(value == 1 && isOn) {
|
||||||
sprintf(command, "M%2.2d=15", pAxis->axisNo_);
|
sprintf(command, "M%2.2d=15", pAxis->axisNo_);
|
||||||
// lowLevelWriteRead(pAxis->axisNo_, command, response);
|
// lowLevelWriteRead(pAxis->axisNo_, command, response);
|
||||||
}
|
}
|
||||||
|
// Valid code continues here
|
||||||
sprintf(command, "M%2.2d14=%d", pAxis->axisNo_, value);
|
sprintf(command, "M%2.2d14=%d", pAxis->axisNo_, value);
|
||||||
pAxis->updateMsgTxtFromDriver("");
|
pAxis->updateMsgTxtFromDriver("");
|
||||||
if(isOn != value) {
|
if(isOn != value) {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Usage: macmaster.py macmasterhost port
|
Usage: macmaster.py macmasterhost port
|
||||||
Listen for commands to send and returns reponse
|
Listen for commands to send and returns reponse
|
||||||
|
58
utils/physhell.tcl
Executable file
58
utils/physhell.tcl
Executable file
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@ Mark Koennecke, January 2023
|
|||||||
|
|
||||||
import socket
|
import socket
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
socke = None
|
socke = None
|
||||||
sockfd = None
|
sockfd = None
|
||||||
@ -33,6 +34,7 @@ def transact(command):
|
|||||||
global socke, sockfd
|
global socke, sockfd
|
||||||
sockfd.write(command + '\r')
|
sockfd.write(command + '\r')
|
||||||
sockfd.flush()
|
sockfd.flush()
|
||||||
|
time.sleep(.1)
|
||||||
return sockfd.readline()
|
return sockfd.readline()
|
||||||
|
|
||||||
def find_commas(rawline):
|
def find_commas(rawline):
|
||||||
@ -61,8 +63,10 @@ def fix_line(par_list, index_list):
|
|||||||
addridx = index_list.index('ADDR')
|
addridx = index_list.index('ADDR')
|
||||||
motNo = par_list[addridx]
|
motNo = par_list[addridx]
|
||||||
limits = transact('H ' + motNo)
|
limits = transact('H ' + motNo)
|
||||||
|
time.sleep(.1)
|
||||||
l = limits.split()
|
l = limits.split()
|
||||||
lowidx = index_list.index('DLLM')
|
lowidx = index_list.index('DLLM')
|
||||||
|
# import pdb; pdb.set_trace()
|
||||||
par_list[lowidx] = l[0]
|
par_list[lowidx] = l[0]
|
||||||
highidx = index_list.index('DHLM')
|
highidx = index_list.index('DHLM')
|
||||||
par_list[highidx] = l[1]
|
par_list[highidx] = l[1]
|
||||||
@ -93,7 +97,7 @@ def scan_substitution_file(filename):
|
|||||||
newlist = fix_line(l, index_list)
|
newlist = fix_line(l, index_list)
|
||||||
# newline = ','.join(newlist)
|
# newline = ','.join(newlist)
|
||||||
newline = pretty_line(newlist, comma_list)
|
newline = pretty_line(newlist, comma_list)
|
||||||
sys.stdout.write('{' + newline)
|
sys.stdout.write('{' + newline + '\n')
|
||||||
else:
|
else:
|
||||||
sys.stdout.write(rawline)
|
sys.stdout.write(rawline)
|
||||||
rawline = fin.readline()
|
rawline = fin.readline()
|
||||||
|
Reference in New Issue
Block a user