Initial version of sinqMotor
This commit is contained in:
49
src/Makefile
Normal file
49
src/Makefile
Normal file
@ -0,0 +1,49 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#=============================
|
||||
# Build the IOC application
|
||||
|
||||
PROD_IOC = sinqEPICS
|
||||
# sinqEPICS.dbd will be created and installed
|
||||
DBD += sinqEPICS.dbd
|
||||
|
||||
# sinqEPICS.dbd will be made up from these files:
|
||||
sinqEPICS_DBD += base.dbd
|
||||
|
||||
# Include dbd files from all support applications:
|
||||
sinqEPICS_DBD += sinq.dbd
|
||||
#sinqEPICS_DBD += pmacAsynIPPort.dbd pmacAsynMotorPort.dbd
|
||||
|
||||
# Add all the support libraries needed by this IOC
|
||||
sinqEPICS_LIBS += motor asyn busy synAppsStd streamdevice pcre
|
||||
|
||||
# sinqEPICS_registerRecordDeviceDriver.cpp derives from sinqEPICS.dbd
|
||||
sinqEPICS_SRCS += sinqEPICS_registerRecordDeviceDriver.cpp
|
||||
sinqEPICS_SRCS += EL734Driver.cpp devScalerEL737.c pmacAsynIPPort.c sinqAxis.cpp sinqController.cpp
|
||||
sinqEPICS_SRCS += pmacController.cpp pmacAxis.cpp
|
||||
sinqEPICS_SRCS += NanotecDriver.cpp stptok.cpp
|
||||
sinqEPICS_SRCS += PhytronDriver.cpp
|
||||
sinqEPICS_SRCS += EuroMoveDriver.cpp
|
||||
|
||||
|
||||
# Build the main IOC entry point on workstation OSs.
|
||||
sinqEPICS_SRCS_DEFAULT += sinqEPICSMain.cpp
|
||||
sinqEPICS_SRCS_vxWorks += -nil-
|
||||
|
||||
# Add support from base/src/vxWorks if needed
|
||||
#sinqEPICS_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
|
||||
|
||||
# Finally link to the EPICS Base libraries
|
||||
sinqEPICS_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
#===========================
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
91
src/sinqAxis.cpp
Normal file
91
src/sinqAxis.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "sinqAxis.h"
|
||||
#include "sinqController.h"
|
||||
#include <unistd.h>
|
||||
|
||||
sinqAxis::sinqAxis(class sinqController *pC, int axis)
|
||||
: asynMotorAxis((asynMotorController *)pC, axis), pC_(pC) {
|
||||
|
||||
bool initial_poll_ = true;
|
||||
int init_poll_counter_ = 0;
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::atFirstPoll() { return asynSuccess; }
|
||||
|
||||
asynStatus sinqAxis::poll(bool *moving) {
|
||||
// Local variable declaration
|
||||
asynStatus pl_status = asynSuccess;
|
||||
asynStatus poll_status = asynSuccess;
|
||||
|
||||
// =========================================================================
|
||||
|
||||
// If this poll is the initial poll, check if the parameter library has
|
||||
// already been initialized. If not, force EPCIS to repeat the poll until
|
||||
// the initialization is complete (or until a timeout is reached). Once the
|
||||
// parameter library has been initialized, read configuration data from the
|
||||
// motor controller into it.
|
||||
if (initial_poll_) {
|
||||
poll_status = atFirstPoll();
|
||||
if (poll_status == asynSuccess) {
|
||||
initial_poll_ = false;
|
||||
} else {
|
||||
// Send a message to the IOC shell every 10 trials.
|
||||
init_poll_counter_ += 1;
|
||||
if (init_poll_counter_ % 10 == 0) {
|
||||
asynPrint(pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\nRunning function 'atFirstPoll' "
|
||||
"failed %d times with error %s.",
|
||||
__PRETTY_FUNCTION__, __LINE__, init_poll_counter_,
|
||||
pC_->stringifyAsynStatus(poll_status));
|
||||
}
|
||||
|
||||
// Wait for 100 ms until trying the entire poll again
|
||||
usleep(100000);
|
||||
return poll_status;
|
||||
}
|
||||
}
|
||||
|
||||
// The poll function is just a wrapper around doPoll and
|
||||
// handles mainly the callParamCallbacks() function. This wrapper is used
|
||||
// to make sure callParamCallbacks() is called in case of a premature
|
||||
// return.
|
||||
poll_status = doPoll(moving);
|
||||
|
||||
// If the poll status is ok, reset the error indicators in the parameter
|
||||
// library
|
||||
if (poll_status == asynSuccess) {
|
||||
pl_status = setIntegerParam(pC_->motorStatusProblem_, false);
|
||||
if (pl_status != asynSuccess) {
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusProblem_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
pl_status = setIntegerParam(pC_->motorStatusCommsError_, false);
|
||||
if (pl_status != asynSuccess) {
|
||||
pC_->paramLibAccessFailed(pl_status, "motorStatusCommsError_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
|
||||
pl_status = setStringParam(pC_->motorMessageText_, "");
|
||||
if (pl_status != asynSuccess) {
|
||||
return pC_->paramLibAccessFailed(pl_status, "motorMessageText_",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
}
|
||||
}
|
||||
|
||||
// According to the function documentation of asynMotorAxis::poll, this
|
||||
// function should be called at the end of a poll implementation.
|
||||
pl_status = callParamCallbacks();
|
||||
if (pl_status != asynSuccess) {
|
||||
// If we can't communicate with the parameter library, it doesn't make
|
||||
// sense to try and upstream this to the user -> Just log the error
|
||||
asynPrint(
|
||||
pC_->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\ncallParamCallbacks failed with %s for axis %d",
|
||||
__PRETTY_FUNCTION__, __LINE__,
|
||||
pC_->stringifyAsynStatus(poll_status), axisNo_);
|
||||
poll_status = pl_status;
|
||||
}
|
||||
|
||||
return poll_status;
|
||||
}
|
||||
|
||||
asynStatus sinqAxis::doPoll(bool *moving) { return asynSuccess; }
|
39
src/sinqAxis.h
Normal file
39
src/sinqAxis.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
This class extends asynMotorAxis by some features used in SINQ.
|
||||
|
||||
Stefan Mathis, November 2024
|
||||
*/
|
||||
#ifndef __SINQDRIVER
|
||||
#define __SINQDRIVER
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
class epicsShareClass sinqAxis : public asynMotorAxis {
|
||||
public:
|
||||
sinqAxis(class sinqController *pC_, int axis);
|
||||
|
||||
/**
|
||||
This function is executed at the very first poll after the IOC startup. If
|
||||
it returns anything else than 'asynSuccess', the function is evaluated again
|
||||
after 100 ms until it succeeds. Every 10 trials a warning is emitted.
|
||||
*/
|
||||
asynStatus atFirstPoll();
|
||||
|
||||
asynStatus poll(bool *moving);
|
||||
|
||||
/**
|
||||
Implementation of the "proper", device-specific poll method. This method
|
||||
should be implemented by a child class of sinqAxis.
|
||||
*/
|
||||
asynStatus doPoll(bool *moving);
|
||||
|
||||
friend class sinqController;
|
||||
|
||||
protected:
|
||||
bool initial_poll_;
|
||||
int init_poll_counter_;
|
||||
|
||||
private:
|
||||
sinqController *pC_;
|
||||
};
|
||||
|
||||
#endif
|
124
src/sinqController.cpp
Normal file
124
src/sinqController.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
/*
|
||||
This class contains the necessary changes to have an additional text fields
|
||||
for messages with each axis.
|
||||
|
||||
Code lifted from Torsten Boegershausen ESS code.
|
||||
|
||||
Mark Koennecke, March 2017
|
||||
|
||||
Added code to manage an interMessageSleep
|
||||
|
||||
Mark Koennecke, February 2024
|
||||
*/
|
||||
|
||||
#include "sinqController.h"
|
||||
#include "asynMotorController.h"
|
||||
#include "epicsExport.h"
|
||||
#include "iocsh.h"
|
||||
#include <errlog.h>
|
||||
|
||||
sinqController::sinqController(const char *portName, const char *SINQPortName,
|
||||
int numAxes, const int &extraParams)
|
||||
: asynMotorController(
|
||||
portName, numAxes + 1, NUM_MOTOR_DRIVER_PARAMS + extraParams,
|
||||
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
|
||||
{
|
||||
createParam(motorMessageIsFromDriverString, asynParamInt32,
|
||||
&motorMessageIsFromDriver_);
|
||||
createParam(motorMessageTextString, asynParamOctet, &motorMessageText_);
|
||||
}
|
||||
|
||||
asynStatus sinqController::errMsgCouldNotParseResponse(const char *command,
|
||||
const char *response,
|
||||
int axisNo_,
|
||||
const char *functionName,
|
||||
int lineNumber) {
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\n Could not interpret response %s for "
|
||||
"command %s.\n",
|
||||
functionName, lineNumber, response, command);
|
||||
|
||||
setStringParam(motorMessageText_,
|
||||
"Could not interpret MCU response. Please "
|
||||
"call the software support");
|
||||
setIntegerParam(motorStatusCommsError_, 1);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
asynStatus sinqController::paramLibAccessFailed(asynStatus status,
|
||||
const char *parameter,
|
||||
const char *functionName,
|
||||
int lineNumber) {
|
||||
|
||||
if (status != asynSuccess) {
|
||||
// Log the error message and try to propagate it
|
||||
asynPrint(lowLevelPortUser_, ASYN_TRACE_ERROR,
|
||||
"%s => line %d:\n Accessing the parameter library failed for "
|
||||
"parameter %s",
|
||||
functionName, lineNumber, parameter);
|
||||
setStringParam(
|
||||
motorMessageText_,
|
||||
"Accessing paramLib failed. Please call the software support.");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// Static pointers (valid for the entire lifetime of the IOC). The number behind
|
||||
// the strings gives the integer number of each variant (see also method
|
||||
// stringifyAsynStatus)
|
||||
static char *asynSuccessStringified = "success"; // 0
|
||||
static char *asynTimeoutStringified = "timeout"; // 1
|
||||
static char *asynOverflowStringified = "overflow"; // 2
|
||||
static char *asynErrorStringified = "error"; // 3
|
||||
static char *asynDisconnectedStringified = "disconnected"; // 4
|
||||
static char *asynDisabledStringified = "disabled"; // 5
|
||||
static char *asynParamAlreadyExistsStringified =
|
||||
"parameter already exists"; // 6
|
||||
static char *asynParamNotFoundStringified = "parameter not found"; // 7
|
||||
static char *asynParamWrongTypeStringified = "wrong type"; // 8
|
||||
static char *asynParamBadIndexStringified = "bad index"; // 9
|
||||
static char *asynParamUndefinedStringified = "parameter undefined"; // 10
|
||||
static char *asynParamInvalidListStringified = "invalid list"; // 11
|
||||
|
||||
char *sinqController::stringifyAsynStatus(asynStatus status) {
|
||||
// See
|
||||
// https://github.com/epics-modules/asyn/blob/master/asyn/asynDriver/asynDriver.h
|
||||
// and
|
||||
// https://github.com/epics-modules/asyn/blob/master/asyn/asynPortDriver/paramErrors.h
|
||||
// for the definition of the error codes
|
||||
switch (status) {
|
||||
case asynSuccess:
|
||||
return asynSuccessStringified;
|
||||
case asynTimeout:
|
||||
return asynTimeoutStringified;
|
||||
case asynOverflow:
|
||||
return asynOverflowStringified;
|
||||
case asynError:
|
||||
return asynErrorStringified;
|
||||
case asynDisconnected:
|
||||
return asynDisconnectedStringified;
|
||||
case asynDisabled:
|
||||
return asynDisabledStringified;
|
||||
case asynParamAlreadyExists:
|
||||
return asynParamAlreadyExistsStringified;
|
||||
case asynParamNotFound:
|
||||
return asynParamNotFoundStringified;
|
||||
case asynParamWrongType:
|
||||
return asynParamWrongTypeStringified;
|
||||
case asynParamBadIndex:
|
||||
return asynParamBadIndexStringified;
|
||||
case asynParamUndefined:
|
||||
return asynParamUndefinedStringified;
|
||||
case asynParamInvalidList:
|
||||
return asynParamInvalidListStringified;
|
||||
}
|
||||
|
||||
errlogPrintf("%s => line %d:\nReached unreachable code.",
|
||||
__PRETTY_FUNCTION__, __LINE__);
|
||||
return "unreachable code reached";
|
||||
}
|
54
src/sinqController.h
Normal file
54
src/sinqController.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
This class contains the necessary changes to have an additional text fields
|
||||
for messages with each axis.
|
||||
|
||||
Code lifted from Torsten Boegershausens ESS code.
|
||||
|
||||
Mark Koennecke, March 2017
|
||||
*/
|
||||
|
||||
#ifndef __sinqController
|
||||
#define __sinqController
|
||||
#include "asynMotorController.h"
|
||||
|
||||
#define motorMessageIsFromDriverString "MOTOR_MESSAGE_DRIVER"
|
||||
#define motorMessageTextString "MOTOR_MESSAGE_TEXT"
|
||||
|
||||
class epicsShareClass sinqController : public asynMotorController {
|
||||
public:
|
||||
sinqController(const char *portName, const char *SINQPortName, int numAxes,
|
||||
const int &extraParams = 2);
|
||||
|
||||
friend class sinqAxis;
|
||||
|
||||
/**
|
||||
If accessing the parameter library failed (return status != asynSuccess),
|
||||
calling this function writes a standardized message to both the IOC shell
|
||||
and the motor message text PV. It then returns the input status.
|
||||
*/
|
||||
asynStatus paramLibAccessFailed(asynStatus status, const char *parameter,
|
||||
const char *functionName, int lineNumber);
|
||||
|
||||
/**
|
||||
This function writes a standardized message to both the IOC shell and
|
||||
the motor message text PV in case parsing a response (e.g. via sscanf)
|
||||
failed. It always returns asynError.
|
||||
*/
|
||||
asynStatus errMsgCouldNotParseResponse(const char *command,
|
||||
const char *response, int axisNo_,
|
||||
const char *functionName,
|
||||
int lineNumber);
|
||||
|
||||
/**
|
||||
Convert an asynStatus into a descriptive string. This string can then e.g.
|
||||
be used to create debugging messages.
|
||||
*/
|
||||
char *stringifyAsynStatus(asynStatus status);
|
||||
|
||||
protected:
|
||||
asynUser *lowLevelPortUser_;
|
||||
int motorMessageIsFromDriver_;
|
||||
int motorMessageText_;
|
||||
};
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user