Initial version of sinqMotor

This commit is contained in:
2024-11-12 15:13:12 +01:00
parent 611cde365f
commit af182bb73b
6 changed files with 603 additions and 0 deletions

49
src/Makefile Normal file
View 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
View 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
View 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
View 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
View 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