diff --git a/.gitmodules b/.gitmodules index 429e8422..aa6090be 100644 --- a/.gitmodules +++ b/.gitmodules @@ -58,3 +58,6 @@ [submodule "modules/motorNewFocus"] path = modules/motorNewFocus url = https://github.com/epics-motor/motorNewFocus.git +[submodule "modules/motorIms"] + path = modules/motorIms + url = https://github.com/epics-motor/motorIms.git diff --git a/iocBoot/iocWithAsyn/motor.substitutions.ims b/iocBoot/iocWithAsyn/motor.substitutions.ims deleted file mode 100644 index 9b6b69d4..00000000 --- a/iocBoot/iocWithAsyn/motor.substitutions.ims +++ /dev/null @@ -1,60 +0,0 @@ -# ImsMDrivePlus asyn model 3 substitutions file - -# SREV (not shown) is the number of steps per revolution is 200 by -# default -# -# There are three pivot points to which the six motors are attached. -# Three provide vertical motion: M0Y, M1Y, and M2Y. One provides -# horizontal motion in the Z direction (along beamline): M2Z. Two -# provide horizontal motion in the X direction (perpendicular to -# beamline): M0X, M2X. -# - -# - -# For SREV: -# 2048 = internal encoder (EQ) -# 250 = external encoder, NUMERIK-JENA -# 200 = external encoder, Renishaw -# 51200 = no encoder - -# CXI DG4 Support Motion Stand (DG4) Substitution file - - -file "$(MOTOR)/db/basic_asyn_motor.db" -{ -pattern -{P, N, M, DTYP, PORT, DESC, ADDR, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, DHLM, DLLM, MRES, PREC, INIT} -{IMS:, 1, 1, "asynMotor", IMS1, "MDrive23", 0, mm, Pos, 3.0, 0.017, 2.0, 0, 0.017, 2.0, 100, -100, 0.000083, 4, ""} -} - -file "$(MOTOR)/db/IMS_extra.db" -{ -pattern -{DEV, AREA, LOC, PORT, ADDR, TIMEOUT} -{IMS, IOC, 1, IMS1, 0, 1} -} -# field(DESC,"Y DG4 DS North Motor") # same -# field(DTYP,"ImsMDrivePlus") # same -# field(OUT, "#C0 S0 @") # same -# field(DIR, "Pos") # same -# field(SREV,"2048") # SREV [steps/rev], MRES = UREV/SREV -# field(UREV,"0.017") # UREV [egu/rev], MRES = UREV/SREV -# field(UEIP,"No") -# field(S, "10") # no equivalent -# field(SMAX,"20") # SMAX[rev/s], VELO = SMAX * UREV -# field(SBAS,"1") # VBAS = SBAS * UREV -# field(ACCL,"2.0") # same -# field(BDST,"0") # same -# field(RDBD,"0.0005") -# field(RTRY,"1") -# field(SBAK,"1") # BVEL = SBAK * UREV -# field(BACC,"2.0") # same -# field(DLY, "0") -# field(PREC,"4") # same -# field(EGU, "mm") # same -# field(DHLM,"200.0") # same -# field(DLLM,"-200.0") # same -# field(INIT,"") # same -# field(TWV, "1") # same - diff --git a/iocBoot/iocWithAsyn/st.cmd.Vx b/iocBoot/iocWithAsyn/st.cmd.Vx index 05a4675e..90a1168e 100644 --- a/iocBoot/iocWithAsyn/st.cmd.Vx +++ b/iocBoot/iocWithAsyn/st.cmd.Vx @@ -1,5 +1,5 @@ -# The is the "ASYN" example for communication to an -# IMS483 controller. The examples must be configured by including or omitting +# The is the "ASYN" example for communication to a controller +# The examples must be configured by including or omitting # comment characters (i.e., #'s) from this file. # "#!" marks lines that can be uncommented. @@ -28,33 +28,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:") # Configure the ASYN server code. This MUST be configured too! < st_asynserver.cmd.Vx -# IMS IM483 driver setup parameters: -# (1) maximum number of controllers in system -# (2) motor task polling rate (min=1Hz,max=60Hz) -# SM - single mode PL - party mode -#!IM483SMSetup(1, 10) -#!IM483PLSetup(1, 10) - -# IMS IM483 configuration parameters: -# (1) controller# (chain#) being configured, -# (2) ASYN port name -# SM - single mode PL - party mode -#!IM483SMConfig(0, "a-Serial[0]") -#!drvIM483SMdebug=4 -#!IM483PLConfig(0, "a-Serial[0]") -#!drvIM483PLdebug=4 - - -# IMS MDrive driver setup parameters: -# (1) maximum number of controllers in system -# (2) motor task polling rate (min=1Hz,max=60Hz) -#!MDriveSetup(1, 10) - -# IMS MDrive driver configuration parameters: -# (1) controller# being configured -#!MDriveConfig(0, "a-Serial[0]") -#!drvMDrivedebug = 4 - # Aerotech Ensemble digital servo controller Setup # (1) maximum number of controllers in system diff --git a/iocBoot/iocWithAsyn/st.cmd.ims b/iocBoot/iocWithAsyn/st.cmd.ims deleted file mode 100644 index dedfb06a..00000000 --- a/iocBoot/iocWithAsyn/st.cmd.ims +++ /dev/null @@ -1,29 +0,0 @@ -< envPaths - -# Tell EPICS all about the record types, device-support modules, drivers, -# etc. in this build from CARS -dbLoadDatabase("../../dbd/WithAsyn.dbd") -WithAsyn_registerRecordDeviceDriver(pdbbase) - -### Motors -# Motors substitutions, customize this for your motor -dbLoadTemplate "motor.substitutions.ims" - -# Configure asyn communication port, first -# drvAsynIPPortConfigure(IOPortName, port, priority, disable auto-connect, no process EOS) -drvAsynIPPortConfigure("M06", "ts-b34-nw09:2101", 0, 0, 0 ) - -# Configure one controller per motor, each controller just has 1 axis -# motorPortName, portName, deviceName, movingPollPeriod, idlePollPeriod -ImsMDrivePlusCreateController("IMS1", "M06", "1", 200, 5000) - -# Optional: Enable tracing -#asynSetTraceIOMask("IMS1",0,0) -asynSetTraceMask("IMS1",0,9) - -# Initialize the IOC and start processing records -iocInit() - - - - diff --git a/iocBoot/iocWithAsyn/st.cmd.unix b/iocBoot/iocWithAsyn/st.cmd.unix index 0fcef594..fd41c49a 100644 --- a/iocBoot/iocWithAsyn/st.cmd.unix +++ b/iocBoot/iocWithAsyn/st.cmd.unix @@ -21,33 +21,6 @@ asynSetOption("L0", -1, "stop", "1") asynSetOption("L0", -1, "clocal", "Y") asynSetOption("L0", -1, "crtscts", "N") -# IMS IM483 driver setup parameters: -# (1) maximum number of controllers in system -# (2) motor task polling rate (min=1Hz,max=60Hz) -# SM - single mode PL - party mode -#!IM483SMSetup(1, 10) -#!IM483PLSetup(1, 10) - -# IMS IM483 configuration parameters: -# (1) controller# (chain#) being configured, -# (2) ASYN port name -# SM - single mode PL - party mode -#!IM483SMConfig(0, "L0") -#!var drvIM483SMdebug 4 -#!IM483PLConfig(0, "L0") -#!var drvIM483PLdebug 4 - -# IMS MDrive driver setup parameters: -# (1) maximum number of controllers in system -# (2) motor task polling rate (min=1Hz,max=60Hz) -#!MDriveSetup(1, 10) - -# IMS MDrive driver configuration parameters: -# (1) controller# being configured, -# (2) ASYN port name -#!MDriveConfig(0, "L0") -#!var drvMDrivedebug 4 - # Aerotech Ensemble digital servo controller Setup # (1) maximum number of controllers in system diff --git a/iocBoot/iocWithAsyn/st.cmd.win32 b/iocBoot/iocWithAsyn/st.cmd.win32 index a7276cc4..2290704b 100755 --- a/iocBoot/iocWithAsyn/st.cmd.win32 +++ b/iocBoot/iocWithAsyn/st.cmd.win32 @@ -10,33 +10,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:") # This is for WIN32, local serial ports not supported. Must use IP terminal server. -# IMS IM483 driver setup parameters: -# (1) maximum number of controllers in system -# (2) motor task polling rate (min=1Hz,max=60Hz) -# SM - single mode PL - party mode -#!IM483SMSetup(1, 10) -#!IM483PLSetup(1, 10) - -# IMS IM483 configuration parameters: -# (1) controller# (chain#) being configured, -# (2) ASYN port name -# SM - single mode PL - party mode -#!IM483SMConfig(0, "L0") -#!var drvIM483SMdebug 4 -#!IM483PLConfig(0, "L0") -#!var drvIM483PLdebug 4 - -# IMS MDrive driver setup parameters: -# (1) maximum number of controllers in system -# (2) motor task polling rate (min=1Hz,max=60Hz) -#!MDriveSetup(1, 10) - -# IMS MDrive driver configuration parameters: -# (1) controller# being configured, -# (2) ASYN port name -#!MDriveConfig(0, "L0") -#!var drvMDrivedebug 4 - # Aerotech Ensemble digital servo controller Setup # (1) maximum number of controllers in system # (2) motor task polling rate (min=1Hz,max=60Hz) diff --git a/modules/Makefile b/modules/Makefile index 7d1e1b5b..43ea47f9 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -13,6 +13,7 @@ SUBMODULES += motorFaulhaber ifdef IPAC SUBMODULES += motorHytec endif +SUBMODULES += motorIms SUBMODULES += motorKohzu SUBMODULES += motorMclennan SUBMODULES += motorMicos diff --git a/modules/motorIms b/modules/motorIms new file mode 160000 index 00000000..47aefe2c --- /dev/null +++ b/modules/motorIms @@ -0,0 +1 @@ +Subproject commit 47aefe2c61fe226148010c45ca1b542fe6dbf8c0 diff --git a/motorApp/Db/IMS_extra.db b/motorApp/Db/IMS_extra.db deleted file mode 100644 index 0807ca43..00000000 --- a/motorApp/Db/IMS_extra.db +++ /dev/null @@ -1,13 +0,0 @@ -# Database for IMS - -# send IMS S command to save parameters to NVM -record(bo,"$(DEV):$(AREA):$(LOC):IMS_S") { - field(DESC, "Ims Save to NVM") - field(PINI, "NO") - field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))IMS_SAVETONVM") - field(VAL, "0") - field(ZNAM, "No") - field(ONAM, "Yes") -} - diff --git a/motorApp/ImsSrc/ImsMDrivePlusMotorAxis.cpp b/motorApp/ImsSrc/ImsMDrivePlusMotorAxis.cpp deleted file mode 100644 index 7d9e8213..00000000 --- a/motorApp/ImsSrc/ImsMDrivePlusMotorAxis.cpp +++ /dev/null @@ -1,596 +0,0 @@ -//! @File : ImsMDrivePlusMotorAxis.cpp -//! Motor record driver level support for Intelligent Motion Systems, Inc. -//! MDrivePlus series; M17, M23, M34. -//! Use "model 3" asyn motor, asynMotorController and asynMotorAxis classes. -//! -//! Original Author : Nia Fong -//! Date : 11-21-2011 -//! Current Author : Mitch D'Ewart (SLAC) -// -// Revision History -// ---------------- -// 11-21-2011 NF Initial version -// 12-15-2014 RLS Bug fix from Thierry Zamofing (PSI); acceleration was set to the same value as the speed. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "asynMotorController.h" -#include "asynMotorAxis.h" - -#include -#include "ImsMDrivePlusMotorController.h" - -//////////////////////////////////////////////////////// -//! ImsMDrivePlusMotorAxis() -// Constructor -// -//! @param[in] pC pointer to ImsMDrivePlusMotorController -//! @param[in] axisNum axis number -//////////////////////////////////////////////////////// -ImsMDrivePlusMotorAxis::ImsMDrivePlusMotorAxis(ImsMDrivePlusMotorController *pC, int axisNum) - : asynMotorAxis(pC, axisNum), pController(pC) -{ - static const char *functionName = "ImsMDrivePlusMotorAxis()"; - asynPrint(pC->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: Create Axis %d\n", DRIVER_NAME, functionName, axisNum); - - // run setup/initialize routines here - // check communication, set moving status - if (configAxis() == asynError) { - asynPrint(pC->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: controller config failed for motor port=%s\n", DRIVER_NAME, functionName, pController->motorName); - // TODO throw exception - } - callParamCallbacks(); -} - -//////////////////////////////////////// -//! configAxis() -//! Used smarACTMCMotorDriver.cpp as reference -// -//! check communication by checking version returns a good string -//! set moving status (PR MV) -//////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::configAxis() -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - char resp[MAX_BUFF_LEN]; - size_t nread; - int maxRetries=3; - static const char *functionName = "configAxis()"; - // figure out what needs to be done to initialize controller - - // try getting firmware version to make sure communication works - sprintf(cmd, "PR VR"); - for (int i=0; iwriteReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: Version retry.\n", DRIVER_NAME, functionName); - if (status == asynError) { - asynPrint(pController->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Version inquiry FAILED.\n", DRIVER_NAME, functionName); - } else { // ok to check firmware level/format or just strlen? v3.009 - if (strlen(resp) < 2) { - asynPrint(pController->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: Version inquiry FAILED version=%s.\n", DRIVER_NAME, functionName, resp); - setIntegerParam(pController->motorStatusProblem_, 1); - setIntegerParam(pController->motorStatusCommsError_, 1); - status = asynError; return(status); - } - break; - } - } - - // set encoder flags - sprintf(cmd, "PR EE"); - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status == asynSuccess) { - int val = atoi(resp); - setIntegerParam(pController->motorStatusHasEncoder_, val ? 1:0); - setIntegerParam(pController->motorStatusGainSupport_, val ? 1:0); - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: set motorStatusHasEncoder_=%d, motorStatusGainSupport_=%d.\n", DRIVER_NAME, functionName, val, val); - } - - // start idle timer - //idleTimeStart = epicsTime::getCurrent(); - - return status; -} - - -//////////////////////////////////////////////////////// -//! setAxisMoveParameters() -//! set base velocity, moving velocity, and acceleration -// -//! @param[in] minVelocity -//! @param[in] maxVelocity -//! @param[in] acceleration -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::setAxisMoveParameters(double minVelocity, double maxVelocity, double acceleration) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - static const char *functionName = "setAxisMoveParameters()"; - - // check if using base velocity (VI) - // for MDrivePlus initial velocity must be below max_velocity - if (minVelocity > 0) { // base velocity set - if (minVelocity > maxVelocity) { // illegal state - asynPrint(pController->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: base velocity=%f cannot be greater than max velocity=%f\n", DRIVER_NAME, functionName, minVelocity, maxVelocity); - goto bail; - } - // set base velocity - sprintf(cmd, "VI=%ld", (long)minVelocity); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - } - - - // set velocity - sprintf(cmd, "VM=%ld", (long)maxVelocity); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - - // set accceleration - if (acceleration != 0) { - sprintf(cmd, "A=%ld", (long)acceleration); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - } - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR setting motor velocity and acceleration", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); - return status; -} - -//////////////////////////////////////////////////////// -//! move() -//! Override asynMotorAxis class implementation -// Based on smarActMCSMotorDriver.cpp -// -//! @param[in] position -//! @param[in] relative making absolute or relative move -//! @param[in] minVelocity -//! @param[in] maxVelocity -//! @param[in] acceleration -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - static const char *functionName = "move()"; - - // sent commands to motor to set velocities and acceleration - status = setAxisMoveParameters(minVelocity, maxVelocity, acceleration); - if (status) goto bail; - - // move - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: VBASE=%f, VELO=%f, ACCL=%f, position=%f, relative=%d\n", DRIVER_NAME, functionName, minVelocity, maxVelocity, acceleration, position, relative); - if (relative) { // relative move MR - sprintf(cmd, "MR %ld", (long)position); - } else { // absolute move MA - sprintf(cmd, "MA %ld", (long)position); - } - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR moving motor", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); - return status; -} - -//////////////////////////////////////////////////////// -//! moveVelocity() -//! Override asynMotorAxis class implementation -// Based on smarActMCSMotorDriver.cpp -//! move at a fixed velocity until stop() called -// -//! @param[in] minVelocity -//! @param[in] maxVelocity -//! @param[in] acceleration -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - static const char *functionName = "moveVelocity()"; - - // sent commands to motor to set velocities and acceleration - status = setAxisMoveParameters(minVelocity, maxVelocity, acceleration); - if (status) goto bail; - - // move - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: VBASE=%f, VELO=%f, ACCL=%f\n", DRIVER_NAME, functionName, minVelocity, maxVelocity, acceleration); - sprintf(cmd, "SL %ld", (long)maxVelocity); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR jogging motor", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); - return status; -} - -//////////////////////////////////////////////////////// -//! stop() -//! Override asynMotorAxis class implementation -// Based on smarActMCSMotorDriver.cpp -// -//! @param[in] acceleration -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::stop(double acceleration) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - static const char *functionName = "stop()"; - - // set accceleration - if (acceleration != 0) { - sprintf(cmd, "A=%ld", (long)acceleration); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - } - - // move - sprintf(cmd, "SL 0"); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR stopping motor", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); - return status; -} - -//////////////////////////////////////////////////////// -//! home() -//! Override asynMotorAxis class implementation -// Based on smarActMCSMotorDriver.cpp -// -//! direction=1: slew at maxVelocity in the minus direction (until switch activates) then creep at vi in the plus direction (until switch becomes inactive again) -//! direction=3: slew at maxVelocity in the plus direction (until switch activates) then creep at vi in the minus direction (until switch becomes inactive again) -// -//! @param[in] minVelocity -//! @param[in] maxVelocity -//! @param[in] acceleration -//! @param[in] forwards direction to home, 0=minus direction, 1=plus direction -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - char resp[MAX_BUFF_LEN]; - size_t nread; - int direction = 1; // direction to home, initialize homing in minus direction - double baseVelocity=0; - static const char *functionName = "home()"; - - // check if using base velocity (VI) - // for MDrivePlus initial velocity must be below max_velocity - if (minVelocity > 0) { // base velocity being configured - if (minVelocity > maxVelocity) { // illegal state - asynPrint(pController->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: base velocity=%f cannot be greater than max velocity=%f\n", DRIVER_NAME, functionName, minVelocity, maxVelocity); - goto bail; - } - } else { // base velocity needs to be set because creeping back to home switch at base velocity, so make sure it's nonzero - sprintf(cmd, "PR VI"); // get base velocity setting - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status) goto bail; - baseVelocity = atof(resp); - if (baseVelocity == 0) { // set to factory default of 1000 - baseVelocity=1000; - } - } - - // sent commands to motor to set velocities and acceleration - if (status = setAxisMoveParameters(minVelocity, maxVelocity, acceleration)) goto bail; - - // home - if (forwards == 1) { // homing in forward direction - direction = 3; - } - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: VBASE=%f, VELO=%f, ACCL=%f, forwards=%d\n", DRIVER_NAME, functionName, minVelocity, maxVelocity, acceleration, forwards); - sprintf(cmd, "HM %d", direction); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR homing motor", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); - return status; -} - -//////////////////////////////////////////////////////// -//! setPosition() -//! Override asynMotorAxis class implementation -// Based on smarActMCSMotorDriver.cpp -// -//! @param[in] position value to set motor's internal position -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::setPosition(double position) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - static const char *functionName = "setPosition()"; - - // set position - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: position=%f\n", DRIVER_NAME, functionName, position); - sprintf(cmd, "P=%ld", (long)position); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR setting motor position", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); - return status; -} - - -//////////////////////////////////////////////////////// -//! poll() -//! Override asynMotorAxis class implementation -// Based on smarActMCSMotorDriver.cpp -// -//! Set position and moving flag -// -//! @param[in] moving pointer to moving flag -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::poll(bool *moving) -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - char resp[MAX_BUFF_LEN]; - size_t nread; - int val=0; - double position; - *moving = false; - static const char *functionName = "poll()"; - //epicsTime currentTime; - - // get position - sprintf(cmd, "PR P"); - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status) goto bail; - position = atof(resp); - // update motor record position values, just update encoder's even if not using one - setDoubleParam(pController->motorEncoderPosition_, position); - setDoubleParam(pController->motorPosition_, position); - - // get moving flag - sprintf(cmd, "PR MV"); - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status) goto bail; - val = atoi(resp); - if (val == 1) *moving = true; // updating moving flag -/* else { // not moving - if (prevMovingState == 1) {// state changed, moving before, start idle timer - idleTimeStart = epicsTime::getCurrent(); - } - } - prevMovingState = val; -*/ - // update motor record status done with moving status - setIntegerParam(pController->motorStatusDone_, ! *moving ); - -/* - // if position has changed and moving stopped for over 30sec, update NVM with current position so the motor will remember - // its location just in case its power dies - currentTime = epicsTime::getCurrent(); - idleTime = currentTime - idleTimeStart; - //printf("prevPos=%f, pos=%f, moving=%d, idleTime=%f\n", prevPosition, position, *moving, idleTime); - if (prevPosition != position && *moving == false && idleTime > 30) { - sprintf(cmd, "S"); - if (status = pController->writeController(cmd, IMS_TIMEOUT)) { - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:poll(): ERROR saving position to NVM\n", DRIVER_NAME); - goto bail; - } - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:poll(): saving parameters to NVM\n", DRIVER_NAME); - idleTimeStart = epicsTime::getCurrent(); - prevPosition = position; - } -*/ - - // get home switch value - if (pController->homeSwitchInput != -1) { - sprintf(cmd, "PR I%d", pController->homeSwitchInput); - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status) goto bail; - val = atoi(resp); - setIntegerParam(pController->motorStatusHome_, val); - } - - // get positive limit switch value - if (pController->posLimitSwitchInput != -1) { - sprintf(cmd, "PR I%d", pController->posLimitSwitchInput); - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status) goto bail; - val = atoi(resp); - setIntegerParam(pController->motorStatusHighLimit_, val); - } - - // get negative limit switch value - if (pController->negLimitSwitchInput != -1) { - sprintf(cmd, "PR I%d", pController->negLimitSwitchInput); - status = pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - if (status) goto bail; - val = atoi(resp); - setIntegerParam(pController->motorStatusLowLimit_, val); - } - - // error polling - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR polling motor", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - // update motor status if polling was successful - if (status == 0) { - setIntegerParam(pController->motorStatusCommsError_, 0); // reset COMM error - setIntegerParam(pController->motorStatusProblem_, 0); // reset problem error, bit 10 - } - - // update motor record - callParamCallbacks(); - - int mstat; - pController->getIntegerParam(pController->motorStatus_, &mstat); - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: POS=%f, MSTAT=%d\n", DRIVER_NAME, functionName, position, mstat); - - return status; - -} - -//////////////////////////////////////////////////////// -//! saveToNVM() -//! Save user variables and flags to non-volatile RAM in case of power loss -// -//////////////////////////////////////////////////////// -asynStatus ImsMDrivePlusMotorAxis::saveToNVM() -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - static const char *functionName = "saveToNVM()"; - - // send save command - sprintf(cmd, "S"); - status = pController->writeController(cmd, IMS_TIMEOUT); - if (status) goto bail; - asynPrint(pController->pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: Saved to NVM\n", DRIVER_NAME, functionName); - - bail: - if (status) { - char buff[LOCAL_LINE_LEN]; - sprintf(buff, "%s:%s: ERROR saving to NVM", DRIVER_NAME, functionName); - handleAxisError(buff); - } - - callParamCallbacks(); //FIXME is this necessary?? - return status; -} - -//////////////////////////////////////////////////////// -//! handleAxisError() -//! Set motorStatusProblem_ -//! Then try to get and print error code -// -////! @param[in] errMsg pointer to error message from calling function -//////////////////////////////////////////////////////// -void ImsMDrivePlusMotorAxis::handleAxisError(char *errMsg) -{ - char cmd[MAX_CMD_LEN]; - char resp[MAX_BUFF_LEN]; - size_t nread=0; - int errCode=0; - char errCodeString[MAX_BUFF_LEN]; - static const char *functionName = "handleAxisError()"; - - // set motorStatusProblem_ bit - setIntegerParam(pController->motorStatusProblem_, 1); - - // read error code - sprintf(cmd, "PR ER"); - pController->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - errCode = atoi(resp); - - switch (errCode) { - case 0: strcpy(errCodeString, "No Error"); break; - case 6: strcpy(errCodeString, "An I/O is already set to this type. Applies to non-General Purpose I/O"); break; - case 8: strcpy(errCodeString, "Tried to set an I/O to an incorrect I/O type"); break; - case 9: strcpy(errCodeString, "Tried to write to I/O set as Input or is 'TYPED'"); break; - case 10: strcpy(errCodeString, "Illegal I/O number"); break; - case 11: strcpy(errCodeString, "Incorrect CLOCK type"); break; - case 12: strcpy(errCodeString, "Illegal Trip/Capture"); break; - case 20: strcpy(errCodeString, "Tried to set unknown variable or flag"); break; - case 21: strcpy(errCodeString, "Tried to set an incorrect value"); break; - case 22: strcpy(errCodeString, "VI is set greater than or equal to VM"); break; - case 23: strcpy(errCodeString, "VM is set less than or equal to VI"); break; - case 24: strcpy(errCodeString, "Illegal data entered"); break; - case 25: strcpy(errCodeString, "Variable or flag is read only"); break; - case 26: strcpy(errCodeString, "Variable or flag is not allowed to be incremented or decremented"); break; - case 27: strcpy(errCodeString, "Trip not defined"); break; - case 28: strcpy(errCodeString, "Trying to redefine a program label or variable"); break; - case 29: strcpy(errCodeString, "Trying to redefine a build in command, variable, or flag"); break; - case 30: strcpy(errCodeString, "Unknown label or user variable"); break; - case 31: strcpy(errCodeString, "Program label or user variable table is full"); break; - case 32: strcpy(errCodeString, "Trying to set a label"); break; - case 33: strcpy(errCodeString, "Trying to set and instruction"); break; - case 34: strcpy(errCodeString, "Trying to execute a variable or flag"); break; - case 35: strcpy(errCodeString, "Trying to print illegal variable or flag"); break; - case 36: strcpy(errCodeString, "Illegal motor count to encoder count ratio"); break; - case 37: strcpy(errCodeString, "Command, variable, or flag not available in drive"); break; - case 38: strcpy(errCodeString, "Missing parameter separator"); break; - case 39: strcpy(errCodeString, "Trip on position and trip on relative distance not allowed together"); break; - case 40: strcpy(errCodeString, "Program not running"); break; - case 41: strcpy(errCodeString, "Stack overflow"); break; - case 42: strcpy(errCodeString, "Illegal program address"); break; - case 43: strcpy(errCodeString, "Tried to overflow program stack"); break; - case 44: strcpy(errCodeString, "Program locked"); break; - case 45: strcpy(errCodeString, "Trying to overflow program space"); break; - case 46: strcpy(errCodeString, "Not in program mode"); break; - case 47: strcpy(errCodeString, "Tried to write in illegal flash address"); break; - case 48: strcpy(errCodeString, "Program execution stopped by I/O set as stop"); break; - case 61: strcpy(errCodeString, "Trying to set illegal baud rate"); break; - case 62: strcpy(errCodeString, "IV already pending or IF flag already true"); break; - case 63: strcpy(errCodeString, "Character over-run"); break; - case 64: strcpy(errCodeString, "Startup calibration failed"); break; - case 70: strcpy(errCodeString, "Flash check sum failed"); break; - case 71: strcpy(errCodeString, "Internal temperature warning, 10 C to shutdown"); break; - case 72: strcpy(errCodeString, "Internal over temp fault, disabling drive"); break; - case 73: strcpy(errCodeString, "Tried to save while moving"); break; - case 74: strcpy(errCodeString, "Tried to initialize parameters or clear program while moving"); break; - case 75: strcpy(errCodeString, "Linear over temperature error"); break; - case 80: strcpy(errCodeString, "Home switch not defined"); break; - case 81: strcpy(errCodeString, "Home type not defined"); break; - case 82: strcpy(errCodeString, "Went to both limits and did not find home"); break; - case 83: strcpy(errCodeString, "Reached plus limit switch"); break; - case 84: strcpy(errCodeString, "Reached minus limit switch"); break; - case 85: strcpy(errCodeString, "MA or MR isn't allowed during home and home isn't allowed while moving"); break; - case 86: strcpy(errCodeString, "Stall detected"); break; - case 87: strcpy(errCodeString, "In clock mode"); break; - case 88: strcpy(errCodeString, "Following error"); break; - case 90: strcpy(errCodeString, "Motion variables are too low switching to EE=1"); break; - case 91: strcpy(errCodeString, "Motion stopped by I/O set as stop"); break; - case 92: strcpy(errCodeString, "Position error in closed loop"); break; - case 93: strcpy(errCodeString, "MR or MA not allowed while correcting position"); break; - } - - asynPrint(pController->pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: %s, %d:'%s'\n", DRIVER_NAME, functionName, errMsg, errCode, errCodeString); -} diff --git a/motorApp/ImsSrc/ImsMDrivePlusMotorAxis.h b/motorApp/ImsSrc/ImsMDrivePlusMotorAxis.h deleted file mode 100644 index 1db01430..00000000 --- a/motorApp/ImsSrc/ImsMDrivePlusMotorAxis.h +++ /dev/null @@ -1,71 +0,0 @@ -// Description : This is the "model 3" asyn motor driver for IMS MDrivePlus. -// Based on HytecMotorDriver.h. - -#ifndef ImsMDrivePlusMotorAxis_H -#define ImsMDrivePlusMotorAxis_H - -#include - -#include "asynMotorController.h" -#include "asynMotorAxis.h" - -#define DRIVER_NAME "ImsMDrivePlusMotorDriver" - -#define NUM_AXES 1 -#define DEFAULT_NUM_CARDS 32 -#define MAX_MESSAGES 100 -#define IMS_TIMEOUT 2 -#define MAX_BUFF_LEN 80 -#define MAX_CMD_LEN MAX_BUFF_LEN-10 // leave room for line feeds surrounding command -#define MAX_NAME_LEN 10 -#define LOCAL_LINE_LEN 256 - -class epicsShareClass ImsMDrivePlusMotorController; - -//////////////////////////////////// -// ImsMDrivePlusMotorAxis class -// derived from asynMotorAxis class -//////////////////////////////////// -class ImsMDrivePlusMotorAxis : public asynMotorAxis -{ -public: - /////////////////////////////////// - // Override asynMotorAxis functions - /////////////////////////////////// - ImsMDrivePlusMotorAxis(ImsMDrivePlusMotorController *pC, int axis); - asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration); - asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration); - asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards); - asynStatus stop(double acceleration); - asynStatus poll(bool *moving); - asynStatus setPosition(double position); - - //////////////////////////////////////////////////// - // IMS MDrivePlus specific functions - //////////////////////////////////////////////////// - asynStatus saveToNVM(); -protected: - - -private: - ImsMDrivePlusMotorController *pController; - - //int useEncoder; //! using encoder flag - // FIXME handle lost position in driver or ioc?? -// epicsTime idleTimeStart; //! timer used to track idle time for saving to NVM -// double prevPosition; //! previous position used to see if motor has moved and need to update position in NVM in case of power failure -// int prevMovingState; //! saves previous moving value - - //////////////////////////////////////////////////// - // IMS MDrivePlus specific functions - //////////////////////////////////////////////////// - asynStatus configAxis(); - asynStatus setAxisMoveParameters(double min_velocity, double max_velocity, double acceleration); - void handleAxisError(char *errMsg); - -friend class ImsMDrivePlusMotorController; -}; - -#endif // ImsMDrivePlusMotorAxis_H - - diff --git a/motorApp/ImsSrc/ImsMDrivePlusMotorController.cpp b/motorApp/ImsSrc/ImsMDrivePlusMotorController.cpp deleted file mode 100644 index 440529e4..00000000 --- a/motorApp/ImsSrc/ImsMDrivePlusMotorController.cpp +++ /dev/null @@ -1,361 +0,0 @@ -//! @File : ImsMDrivePlusController.cpp -//! Motor record driver level support for Intelligent Motion Systems, Inc. -//! MDrivePlus series; M17, M23, M34. -//! Simple implementation using "model 3" asynMotorController and asynMotorAxis base classes (derived from asynPortDriver) -//! -//! Original Author : Nia Fong -//! Date : 11-21-2011 -//! Current Author : Mitch D'Ewart (SLAC) -//! -//! Assumptions : -//! 1) Like all controllers, the MDrivePlus must be powered-on when EPICS is first booted up. -//! 2) Assume single controller-card-axis relationship; 1 controller = 1 axis. -//! 3) Append Line Feed (ctrl-J) to end of command string for party mode support -//! 4) If not using device name to address device, config ImsMDrivePlusCreateController() with empty string "" for deviceName -// -// Revision History -// ---------------- -// 11-21-2011 NF Initial version - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "asynMotorController.h" -#include "asynMotorAxis.h" -#include "ImsMDrivePlusMotorAxis.h" - -#include -#include "ImsMDrivePlusMotorController.h" - -//////////////////////////////////////////////////////// -//! @ImsMDrivePlusMotorController() -//! Constructor -//! Driver assumes only 1 axis configured per controller for now... -//! -//! @param[in] motorPortName Name assigned to the port created to communicate with the motor -//! @param[in] IOPortName Name assigned to the asyn IO port, name that was assigned in drvAsynIPPortConfigure() -//! @param[in] devName Name of device (DN) assigned to motor axis in MCode, the device name is prepended to the MCode command to support Party Mode (PY) multidrop communication setup -//! set to empty string "" if no device name needed/not using Party Mode -//! @param[in] movingPollPeriod Moving polling period in milliseconds -//! @param[in] idlePollPeriod Idle polling period in milliseconds -//////////////////////////////////////////////////////// -ImsMDrivePlusMotorController::ImsMDrivePlusMotorController(const char *motorPortName, const char *IOPortName, const char *devName, double movingPollPeriod, double idlePollPeriod) - : asynMotorController(motorPortName, NUM_AXES, NUM_IMS_PARAMS, - asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask, - asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask, - ASYN_CANBLOCK | ASYN_MULTIDEVICE, - 1, // autoconnect - 0, 0), // Default priority and stack size - pAsynUserIMS(0) -{ - static const char *functionName = "ImsMDrivePlusMotorController()"; - asynStatus status; - ImsMDrivePlusMotorAxis *pAxis; - // asynMotorController constructor calloc's memory for array of axis pointers - pAxes_ = (ImsMDrivePlusMotorAxis **)(asynMotorController::pAxes_); - - // copy names - strncpy(motorName, motorPortName, (MAX_NAME_LEN - 1)); - - // setup communication - status = pasynOctetSyncIO->connect(IOPortName, 0, &pAsynUserIMS, NULL); - if (status != asynSuccess) { - printf("\n\n%s:%s: ERROR connecting to Controller's IO port=%s\n\n", DRIVER_NAME, functionName, IOPortName); - // TODO would be good to implement exceptions - // TODO THROW_(SmarActMCSException(MCSConnectionError, "SmarActMCSController: unable to connect serial channel")); - } - - // write version, cannot use asynPrint() in constructor since controller (motorPortName) hasn't been created yet - printf("%s:%s: motorPortName=%s, IOPortName=%s, devName=%s \n", DRIVER_NAME, functionName, motorPortName, IOPortName, devName); - - - // init - pasynOctetSyncIO->setInputEos(pAsynUserIMS, "\n", 1); - pasynOctetSyncIO->setOutputEos(pAsynUserIMS, "\r\n", 2); - - // Create controller-specific parameters - createParam(ImsMDrivePlusSaveToNVMControlString, asynParamInt32, &ImsMDrivePlusSaveToNVM_); - createParam(ImsMDrivePlusLoadMCodeControlString, asynParamOctet, &this->ImsMDrivePlusLoadMCode_); - createParam(ImsMDrivePlusClearMCodeControlString, asynParamOctet, &this->ImsMDrivePlusClearMCode_); - - // Check the validity of the arguments and init controller object - initController(devName, movingPollPeriod, idlePollPeriod); - - // Create axis - // Assuming single axis per controller the way drvAsynIPPortConfigure( "M06", "ts-b34-nw08:2101", 0, 0 0 ) is called in st.cmd script - pAxis = new ImsMDrivePlusMotorAxis(this, 0); - pAxis = NULL; // asynMotorController constructor tracking array of axis pointers - - // read home and limit config from S1-S4 - readHomeAndLimitConfig(); - - startPoller(movingPollPeriod, idlePollPeriod, 2); -} - -//////////////////////////////////////// -//! initController() -//! config controller variables - axis, etc. -//! only support single axis per controller -// -//! @param[in] devName Name of device (DN) used to identify axis within controller for Party Mode -//! @param[in] movingPollPeriod Moving polling period in milliseconds -//! @param[in] idlePollPeriod Idle polling period in milliseconds -//////////////////////////////////////// -void ImsMDrivePlusMotorController::initController(const char *devName, double movingPollPeriod, double idlePollPeriod) -{ - strncpy(this->deviceName, devName, (MAX_NAME_LEN - 1)); - - // initialize asynMotorController variables - this->numAxes_ = NUM_AXES; // only support single axis - this->movingPollPeriod_ = movingPollPeriod; - this->idlePollPeriod_ = idlePollPeriod; - - // initialize switch inputs - this->homeSwitchInput=-1; - this->posLimitSwitchInput=-1; - this->negLimitSwitchInput=-1; - - // flush io buffer - pasynOctetSyncIO->flush(pAsynUserIMS); -} - -//////////////////////////////////////// -//! readHomeAndLimitConfig -//! read home, positive limit, and neg limit switch configuration from MCode S1-S4 settings -//! S1-S4 must be set up beforehand -//! I1-I4 are used to read the status of S1-S4 -// Use logic from existing drvMDrive.cc -//////////////////////////////////////// -int ImsMDrivePlusMotorController::readHomeAndLimitConfig() -{ - asynStatus status = asynError; - char cmd[MAX_CMD_LEN]; - char resp[MAX_BUFF_LEN]; - size_t nread; - static const char *functionName = "readHomeAndLimitConfig()"; - int type; - - // iterate through S1-S4 and parse each configuration to see if home, pos, and neg limits are set - for (int i=1; i<=4; i++) { - sprintf(cmd, "PR S%d", i); // query S1-S4 setting - status = this->writeReadController(cmd, resp, sizeof(resp), &nread, IMS_TIMEOUT); - sscanf(resp, "%d", &type); - //asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: S%d: type=%d\n", DRIVER_NAME, functionName, i, type); - if (type != 0) - //printf("%s:%s: S%d: type=%d\n", DRIVER_NAME, functionName, i, type); - switch (type) { - case 0: break; // general purpose input - case 1: // home switch input - homeSwitchInput = i; break; - case 2: // positive limit switch input - posLimitSwitchInput = i; break; - case 3: // negative limit switch input - negLimitSwitchInput = i; break; - default: - printf("%s:%s: ERROR invalid data type for S%d=%d\n", DRIVER_NAME, functionName, i, type); - } - } - - printf("homeSwitchInput=%d, posLimitSwitchInput=%d, negLimitSwitchInput=%d\n", homeSwitchInput, posLimitSwitchInput, negLimitSwitchInput); - - return status; -} - -//////////////////////////////////////// -//! getAxis() -//! Override asynMotorController function to return pointer to IMS axis object -// -//! Returns a pointer to an ImsMDrivePlusAxis object. -//! Returns NULL if the axis number encoded in pasynUser is invalid -// -//! param[in] pasynUser asynUser structure that encodes the axis index number -//////////////////////////////////////// -ImsMDrivePlusMotorAxis* ImsMDrivePlusMotorController::getAxis(asynUser *pasynUser) -{ - int axisNo; - - getAddress(pasynUser, &axisNo); - return getAxis(axisNo); -} - -//////////////////////////////////////// -//! getAxis() -//! Override asynMotorController function to return pointer to IMS axis object -// -//! Returns a pointer to an ImsMDrivePlusAxis object. -//! Returns NULL if the axis number is invalid. -// -//! param[in] axisNo Axis index number -//////////////////////////////////////// -ImsMDrivePlusMotorAxis* ImsMDrivePlusMotorController::getAxis(int axisNo) -{ - if ((axisNo < 0) || (axisNo >= numAxes_)) return NULL; - return pAxes_[axisNo]; -} - -//////////////////////////////////////// -//! writeInt32() -//! Override asynMotorController function to add hooks to IMS records -// Based on XPSController.cpp -// -//! param[in] pointer to asynUser object -//! param[in] value to pass to function -//////////////////////////////////////// -asynStatus ImsMDrivePlusMotorController::writeInt32(asynUser *pasynUser, epicsInt32 value) -{ - int reason = pasynUser->reason; - int status = asynSuccess; - ImsMDrivePlusMotorAxis *pAxis; - static const char *functionName = "writeInt32"; - - pAxis = this->getAxis(pasynUser); - if (!pAxis) return asynError; - - asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: function=%s, val=%d\n", DRIVER_NAME, functionName, value); - - // Set the parameter and readback in the parameter library. This may be overwritten when we read back the - // status at the end, but that's OK - status = pAxis->setIntegerParam(reason, value); - - if (reason == ImsMDrivePlusSaveToNVM_) { - if (value == 1) { // save current user parameters to NVM - status = pAxis->saveToNVM(); - if (status) asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: ERROR saving to NVM\n", DRIVER_NAME, functionName); - else asynPrint(pasynUserSelf, ASYN_TRACE_FLOW, "%s:%s: Successfully saved to NVM\n", DRIVER_NAME, functionName); - } else { - asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, "%s:%s: ERROR, value of 1 to save to NVM\n", DRIVER_NAME, functionName); - } - } else { // call base class method to continue handling - status = asynMotorController::writeInt32(pasynUser, value); - } - - callParamCallbacks(pAxis->axisNo_); - return (asynStatus)status; -} - -//////////////////////////////////////// -//! writeController() -//! reference ACRMotorDriver -// -//! Writes a string to the IMS controller. -//! Prepends deviceName to command string, if party mode not enabled, set device name to "" -//! @param[in] output the string to be written. -//! @param[in] timeout Timeout before returning an error. -//////////////////////////////////////// -asynStatus ImsMDrivePlusMotorController::writeController(const char *output, double timeout) -{ - size_t nwrite; - asynStatus status; - char outbuff[MAX_BUFF_LEN]; - static const char *functionName = "writeController()"; - - // in party-mode Line Feed must follow command string - sprintf(outbuff, "%s%s", deviceName, output); - asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: deviceName=%s, command=%s\n", DRIVER_NAME, functionName, deviceName, outbuff); - status = pasynOctetSyncIO->write(pAsynUserIMS, outbuff, strlen(outbuff), timeout, &nwrite); - if (status) { // update comm flag - setIntegerParam(this->motorStatusCommsError_, 1); - } - return status ; -} - -//////////////////////////////////////// -//! writeReadController() -//! reference ACRMotorDriver -// -//! Writes a string to the IMS controller and reads a response. -//! Prepends deviceName to command string, if party mode not enabled, set device name to "" -//! param[in] output Pointer to the output string. -//! param[out] input Pointer to the input string location. -//! param[in] maxChars Size of the input buffer. -//! param[out] nread Number of characters read. -//! param[out] timeout Timeout before returning an error.*/ -//////////////////////////////////////// -asynStatus ImsMDrivePlusMotorController::writeReadController(const char *output, char *input, size_t maxChars, size_t *nread, double timeout) -{ - size_t nwrite; - asynStatus status; - int eomReason; - char outbuff[MAX_BUFF_LEN]; - static const char *functionName = "writeReadController()"; - - // in party-mode Line Feed must follow command string - sprintf(outbuff, "%s%s", deviceName, output); - status = pasynOctetSyncIO->writeRead(pAsynUserIMS, outbuff, strlen(outbuff), input, maxChars, timeout, &nwrite, nread, &eomReason); - if (status) { // update comm flag - setIntegerParam(this->motorStatusCommsError_, 1); - } - asynPrint(pasynUserSelf, ASYN_TRACEIO_DRIVER, "%s:%s: deviceName=%s, command=%s, response=%s\n", DRIVER_NAME, functionName, deviceName, outbuff, input); - return status; -} - -//////////////////////////////////////////////////////// -// Start code for iocsh Registration : -// Available Functions : -// ImsMDrivePlusCreateController() -//////////////////////////////////////////////////////// - -//////////////////////////////////////////////////////// -//! ImsMDrivePlusCreateController() -//! IOCSH function -//! Creates a new IMSMDrivePlusController object -// -//! Configuration command, called directly or from iocsh -//! @param[in] motorPortName User-specific name of motor port -//! @param[in] IOPortName User-specific name of port that was configured by drvAsynIPPortConfigure() -//! @param[in] deviceName Name of device, used to address motor by MCODE in party mode -// If not using party mode, config ImsMDrivePlusCreateController() with empty string "" for deviceName -//! @param[in] movingPollPeriod time in ms between polls when any axis is moving -//! @param[in] idlePollPeriod time in ms between polls when no axis is moving -//////////////////////////////////////////////////////// -extern "C" int ImsMDrivePlusCreateController(const char *motorPortName, const char *IOPortName, char *devName, double movingPollPeriod, double idlePollPeriod) -{ - ImsMDrivePlusMotorController *pImsController; - pImsController = new ImsMDrivePlusMotorController(motorPortName, IOPortName, devName, movingPollPeriod/1000., idlePollPeriod/1000.); - pImsController = NULL; - return(asynSuccess); -} - -//////////////////////////////////////////////////////// -// ImsMDrivePlus IOCSH Registration -// Copied from ACRMotorDriver.cpp -// -// Motor port name : user-specified name of port -// IO port name : user-specific name of port that was initialized with drvAsynIPPortConfigure() -// Device name : name of device, used to address motor by MCODE in party mode -// : if not using party mode, config ImsMDrivePlusCreateController() with empty string "" for deviceName -// Moving poll period : time in ms between polls when any axis is moving -// Idle poll period : time in ms between polls when no axis is moving -//////////////////////////////////////////////////////// -static const iocshArg ImsMDrivePlusCreateControllerArg0 = {"Motor port name", iocshArgString}; -static const iocshArg ImsMDrivePlusCreateControllerArg1 = {"IO port name", iocshArgString}; -static const iocshArg ImsMDrivePlusCreateControllerArg2 = {"Device name", iocshArgString}; -static const iocshArg ImsMDrivePlusCreateControllerArg3 = {"Moving poll period (ms)", iocshArgDouble}; -static const iocshArg ImsMDrivePlusCreateControllerArg4 = {"Idle poll period (ms)", iocshArgDouble}; -static const iocshArg * const ImsMDrivePlusCreateControllerArgs[] = {&ImsMDrivePlusCreateControllerArg0, - &ImsMDrivePlusCreateControllerArg1, - &ImsMDrivePlusCreateControllerArg2, - &ImsMDrivePlusCreateControllerArg3, - &ImsMDrivePlusCreateControllerArg4}; -static const iocshFuncDef ImsMDrivePlusCreateControllerDef = {"ImsMDrivePlusCreateController", 5, ImsMDrivePlusCreateControllerArgs}; -static void ImsMDrivePlusCreateControllerCallFunc(const iocshArgBuf *args) -{ - ImsMDrivePlusCreateController(args[0].sval, args[1].sval, args[2].sval, args[3].dval, args[4].dval); -} - -static void ImsMDrivePlusMotorRegister(void) -{ - iocshRegister(&ImsMDrivePlusCreateControllerDef, ImsMDrivePlusCreateControllerCallFunc); -} - -extern "C" { - epicsExportRegistrar(ImsMDrivePlusMotorRegister); -} diff --git a/motorApp/ImsSrc/ImsMDrivePlusMotorController.h b/motorApp/ImsSrc/ImsMDrivePlusMotorController.h deleted file mode 100644 index caf5b038..00000000 --- a/motorApp/ImsSrc/ImsMDrivePlusMotorController.h +++ /dev/null @@ -1,74 +0,0 @@ -//! Description : This is the "model 3" asyn motor driver for IMS MDrivePlus. -//! Based on HytecMotorDriver.h. -//! @ImsMDrivePlus.h - -#ifndef ImsMDrivePlusMotorController_H -#define ImsMDrivePlusMotorController_H - -#include "asynMotorController.h" -#include "asynMotorAxis.h" -#include "ImsMDrivePlusMotorAxis.h" - -//////////////////////////////////// -// ImsMDrivePlusMotorController class -//! derived from asynMotorController class -//////////////////////////////////// -class epicsShareClass ImsMDrivePlusMotorController : public asynMotorController -{ -public: - ///////////////////////////////////////// - // Override asynMotorController functions - ///////////////////////////////////////// - ImsMDrivePlusMotorController(const char *motorPortName, const char *IOPortName, const char *deviceName, double movingPollPeriod, double idlePollPeriod); - ImsMDrivePlusMotorAxis* getAxis(asynUser *pasynUser); - ImsMDrivePlusMotorAxis* getAxis(int axisNo); - //void report(FILE *fp, int level); - asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); - - ///////////////////////////////////////// - // IMS specific functions - ///////////////////////////////////////// - asynStatus writeReadController(const char *output, char *input, size_t maxChars, size_t *nread, double timeout); - asynStatus writeController(const char *output, double timeout); - - - -protected: - ImsMDrivePlusMotorAxis **pAxes_; // Array of pointers to axis objects - - /////////////////////////////////////////// - // IMS MDrivePlus controller function codes - /////////////////////////////////////////// - - //! extra parameters that the ImsMDrivePlus controller supports - int ImsMDrivePlusLoadMCode_; //! Load MCode string, NOT SUPPORTED YET - int ImsMDrivePlusClearMCode_; //! Clear program buffer, NOT SUPPORTED YET - int ImsMDrivePlusSaveToNVM_; //! Store current user variables and flags to nonvolatile ram -#define FIRST_IMS_PARAM ImsMDrivePlusLoadMCode_ -#define LAST_IMS_PARAM ImsMDrivePlusSaveToNVM_ -#define NUM_IMS_PARAMS (&LAST_IMS_PARAM - &FIRST_IMS_PARAM + 1) - -private: -// drvInfo strings for extra parameters that the ImsMDrivePlus controller supports -#define ImsMDrivePlusLoadMCodeControlString "IMS_LOADMCODE" // NOT SUPPORTED YET -#define ImsMDrivePlusClearMCodeControlString "IMS_CLEARMCODE" // NOT SUPPORTED YET -#define ImsMDrivePlusSaveToNVMControlString "IMS_SAVETONVM" - - asynUser *pAsynUserIMS; - char motorName[MAX_NAME_LEN]; - char deviceName[MAX_NAME_LEN]; - int homeSwitchInput; - int posLimitSwitchInput; - int negLimitSwitchInput; - - void initController(const char *devName, double movingPollPeriod, double idlePollPeriod); - int readHomeAndLimitConfig(); // read home, positive limit, and neg limit switch configuration from controller (S1-S4 settings) - - friend class ImsMDrivePlusMotorAxis; -}; -//! iocsh function to create controller object -//! NOTE: drvAsynIPPortConfigure() must be called first -//extern "C" int ImsMDrivePlusCreateController(const char *motorPortName, const char *IOPortName, char *devName, double movingPollPeriod, double idlePollPeriod); - -#endif // ImsMDrivePlusMotorController_H - diff --git a/motorApp/ImsSrc/ImsRegister.cc b/motorApp/ImsSrc/ImsRegister.cc deleted file mode 100644 index 15298d76..00000000 --- a/motorApp/ImsSrc/ImsRegister.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* -FILENAME... ImsRegister.cc -USAGE... Register IMS motor device driver shell commands. - -*/ - -/***************************************************************** - COPYRIGHT NOTIFICATION -***************************************************************** - -(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO - -This software was developed under a United States Government license -described on the COPYRIGHT_UniversityOfChicago file included as part -of this distribution. -**********************************************************************/ - -#include -#include -#include -#include -#include -#include "motor.h" -#include "drvIM483.h" -#include "epicsExport.h" - -extern "C" -{ - -// Ims Setup arguments -static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt}; -static const iocshArg setupArg1 = {"Polling rate", iocshArgInt}; -// Ims Config arguments -static const iocshArg configArg0 = {"Card being configured", iocshArgInt}; -static const iocshArg configArg1 = {"asyn port name", iocshArgString}; - - -static const iocshArg * const IM483SetupArgs[2] = {&setupArg0, &setupArg1}; -static const iocshArg * const IM483ConfigArgs[2] = {&configArg0, &configArg1}; - -static const iocshFuncDef setupIM483SM = {"IM483SMSetup", 2, IM483SetupArgs}; -static const iocshFuncDef setupIM483PL = {"IM483PLSetup", 2, IM483SetupArgs}; -static const iocshFuncDef setupMDrive = {"MDriveSetup", 2, IM483SetupArgs}; - -static const iocshFuncDef configIM483SM = {"IM483SMConfig", 2, IM483ConfigArgs}; -static const iocshFuncDef configIM483PL = {"IM483PLConfig", 2, IM483ConfigArgs}; -static const iocshFuncDef configMDrive = {"MDriveConfig", 2, IM483ConfigArgs}; - -static void setupSMCallFunc(const iocshArgBuf *args) -{ - IM483SMSetup(args[0].ival, args[1].ival); -} -static void setupPLCallFunc(const iocshArgBuf *args) -{ - IM483PLSetup(args[0].ival, args[1].ival); -} -static void setupMDriveCallFunc(const iocshArgBuf *args) -{ - MDriveSetup(args[0].ival, args[1].ival); -} - - -static void configSMCallFunc(const iocshArgBuf *args) -{ - IM483SMConfig(args[0].ival, args[1].sval); -} -static void configPLCallFunc(const iocshArgBuf *args) -{ - IM483PLConfig(args[0].ival, args[1].sval); -} -static void configMDriveCallFunc(const iocshArgBuf *args) -{ - MDriveConfig(args[0].ival, args[1].sval); -} - - -static void IMSmotorRegister(void) -{ - iocshRegister(&setupIM483SM, setupSMCallFunc); - iocshRegister(&setupIM483PL, setupPLCallFunc); - iocshRegister(&setupMDrive, setupMDriveCallFunc); - - iocshRegister(&configIM483SM, configSMCallFunc); - iocshRegister(&configIM483PL, configPLCallFunc); - iocshRegister(&configMDrive, configMDriveCallFunc); -} - -epicsExportRegistrar(IMSmotorRegister); - -} // extern "C" diff --git a/motorApp/ImsSrc/Makefile b/motorApp/ImsSrc/Makefile deleted file mode 100644 index 57ff8351..00000000 --- a/motorApp/ImsSrc/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -# Makefile -TOP = ../.. -include $(TOP)/configure/CONFIG - -# The following are used for debugging messages. -#USR_CXXFLAGS += -DDEBUG - -DBD += devImsMotor.dbd - -LIBRARY_IOC = Ims - -# Intelligent Motion Systems driver support. -SRCS += ImsRegister.cc -SRCS += devIM483SM.cc drvIM483SM.cc -SRCS += devIM483PL.cc drvIM483PL.cc -SRCS += devMDrive.cc drvMDrive.cc -# model3 driver -SRCS += ImsMDrivePlusMotorController.cpp ImsMDrivePlusMotorAxis.cpp - -Ims_LIBS += motor asyn -Ims_LIBS += $(EPICS_BASE_IOC_LIBS) - -include $(TOP)/configure/RULES - diff --git a/motorApp/ImsSrc/README b/motorApp/ImsSrc/README deleted file mode 100644 index 5fc90e90..00000000 --- a/motorApp/ImsSrc/README +++ /dev/null @@ -1,151 +0,0 @@ - - MDrive 17,23,34 -============================================================================== - -Configuring MDrive for party mode. ----------------------------------- - -The following is a modified version of the procedure defined in Section 2.1, -"Multiple MDrive Motion Control System (Party Mode)", page #27, of the -"MDrive Motion Control" manual; Revision 01.24.2005. - -1. Connect the first MDrive Motion Control to the Host PC configured for Single - Mode Operation. Since the MDrive uses RS-485, a RS-232 to RS-485 - converter is required for a Host PC to MDrive communication connection. - Set the PC Host RS-232 port characteristics to 9600 Baud, 8 Data bits, - 1 Stop bit, No parity, No flow control. - -2. Establish communications. - If you can see the sign-on message "Copyright 2001-2003 by Intelligent - Motion Systems, Inc.", then you are up and running. If the sign-on - message does not appear, try using a software reset. Hold down the - "Ctrl" key and press "C" (^C). If the sign-on message still does not - appear then there may be a problem with either the connections, - hardware or software configuration of the MDrive Motion Control or - Host. - -3. Using the command DN, name the MDrive Motion Control. This must be a number - 1-9. (DN="1"{enter}). Label the motor with the device name. - -4. Define the plus, minus and home limit switches, if available, using the - S<1-4> command. - -5. Set Echo Mode EM=2{enter}. - -6. Set the party flag PY=1{enter}. - -7. Type CTRL+J to activate the Party Mode. - -8. Type {DN}S CTRL+J where {DN} is the device name given in step #3 (Save - device name, Echo mode, I/O Setup and Party Mode). - -9. Remove power. - -10. Repeat steps 1 through 8 for each additional MDrive in the system using - successive device names "1" through "9". - - -IMPORTANT NOTES ---------------- - -1. The EPICS motor record does NOT support the optional encoder mode. The - Encoder Enable Flag (EE) must be 0. - - -MDrive Facts ------------- - -* Default step resolution - 51,200 steps / 1 motor revolution (MS=256). -* Encoder resolution - 2048 ticks / 1 motor revolution. - - - IM483 -============================================================================== - - -Configuring IM483's for Party Mode communication. ------------------------------------------------- - -The following is a modified version of the procedure defined in the -"Communication" section, page #9, of the "Software Reference Manual"; Revision -051794. - -1) Power down the IM483's. Configure each IM483 module for stand alone (single -mode) communications. For the APS Diviero chassis, jumper J4 for Stand Alone -(1-2) and J7 for Master (1-2). - -2) Connect an RS-232 serial connection (9600,none,8,1) from a host terminal to -the first ("A") controller's front panel connector. - -3) Power up the IM483. - -4) Assign the axis name. At the host terminal, enter the letter "A" (0x41) -followed by a space charter (0x20). - -5) The IM483 controller should respond by echoing the "A" character and the -sign-on message at the host terminal, i.e., - -A 1342 4038 ADVANCED MICRO SYSTEMS, INC -MAX-2000 v1.15i - -6) Change the "Limit Polarity" to active high. At the host terminal, enter -"l1". The IM483 should echo your input at the host terminal. - -7) Store parameters. At the host terminal, enter "S". - -8) Move RS-232 connection to next controller. At the host terminal, enter -control c (^c). Repeat steps 4 through 7 while incrementing the axis name -(i.e, A, B, C, etc.). - -9) Set all the IM483's for Party Mode communication. For the APS Diviero -chassis, configure all of the IM483's for Party Mode by setting J4 to (2-3). -Connect the RS-232 port to the Master IM483 and set all the remaining IM483's -to Slave mode by setting J7 to (2-3). - - -SSCAN THROUGH-PUT NOTES ------------------------ - -The following results where done using the following; - -- SSCAN support module R2.5.1, with scan.db configured as follows; - - Read(R1PV) set to "time". - - Drive(P1PV) set to motor record VAL field. - - #PTS(NPTS) set to 1000. - - Step Size(P1SI) set to MRES of the motor record. -- Motor record R5.7; configured as follows; - - Set slew velocity (VELO) 5.0 = (500 * MRES). - - Set base velocity (VBAS) 4.9 = (499 * MRES). - - Acceleration time (ACCL) does not matter. -- EPICS base R3.14.7 -- WRS Tornado 2.2.1 -- MVME5100 -- IM483SM with firmware version; 1342 4038 AMS, INC MAX-2000 v1.15i - - -Controller | sysClkRate | polling rate | ms/scan pt. ------------|------------|--------------|------------ -IMS483SM | 60 | 1HZ | 121.0 ------------|------------|--------------|------------ -IMS483SM | 60 | 1HZ | 834.2 with VBAS/VELO removed ------------|------------|--------------|------------ -IMS483SM | 60 | 10HZ | 121.0 ------------|------------|--------------|------------ -IMS483SM | 60 | 10HZ | 154.4 with VBAS/VELO removed ------------|------------|--------------|------------ -IMS483SM | 60 | 60HZ | 121.0 ------------|------------|--------------|------------ -IMS483SM | 60 | 60HZ | 102.9 with VBAS/VELO removed ------------|------------|--------------|------------ -IMS483SM | 100 | 1HZ | 121.0 ------------|------------|--------------|------------ -IMS483SM | 1000 | 1000HZ | 121.0 ------------|------------|--------------|------------ -IMS483SM | 1000 | 1000HZ | 96.0 with VBAS/VELO removed - - -KNOWN PROBLEMS -============== - -- The MDrive overshoots the target position on small moves when the velocity -base is large. diff --git a/motorApp/ImsSrc/README.ImsMDrivePlusMotor b/motorApp/ImsSrc/README.ImsMDrivePlusMotor deleted file mode 100644 index 372fe929..00000000 --- a/motorApp/ImsSrc/README.ImsMDrivePlusMotor +++ /dev/null @@ -1,120 +0,0 @@ -======================================= -ImsMDrivePlusMotor AsynPortDriver Notes - -Author: Nia Fong, SLAC National Laboratory - -First Initial: 10/28/2011 - -This driver is based on "model 3" motor asyn port driver defined by Mark Rivers. -The driver assumes: - 1) each controller is configured for a single axis - 2) the motor is set up for Party Mode (PY=1) and Echo Mode 2 (EM=2) -======================================= - -======================= -Building an Application -======================= -Building the driver into an application requires - -1) The 'asyn', 'motor' and 'ImsMDrivePlusMotor' (this driver) packages/modules to be built and - installed. The application's RELEASE file must point to these packages so that the build process - locates headers and libraries etc. - -2) The application's '.dbd' file must contain - - motorSupport.dbd - - drvAsynIPPort.dbd (or equivalent 'asyn' port driver package) - - devImsMotor.dbd (this include support for all Ims drivers) - - These '.dbd' files are best listed in the application src/Makefile: - _DBD += motorSupport.dbd - _DBD += devImsMotor.dbd - _DBD += drvAsynIPPort.dbd - -3) The application must be linked against the 'Ims', 'motor' and 'asyn' - libraries, e.g., - - _LIBS += Ims motor asyn - -=============== -Custom Database -=============== -There is an IMS specific IMS_extra.db database that contains IMS-specific records. - -IMS_S: saves user variables and flags to controller's NVM - -record(bo,"$(DEV):$(AREA):$(LOC):IMS_S") { - field(DESC, "Ims Save to NVM") - field(PINI, "NO") - field(DTYP, "asynInt32") - field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))IMS_SAVETONVM") - field(VAL, "0") - field(ZNAM, "No") - field(ONAM, "Yes") -} - -============================= -Driver Run-Time Configuration -============================= -To configure the motor from the iocsh or a C/C++ application - -1) Create and configure an asyn IP port - - drvAsynIPPortConfigure(IOPortName, port, priority, disable auto-connect, no process EOS) - motorPortName: name string assigned to the asyn IP port being created - port: host:port [protocol] - -2) Create and configure an ImsMDrivePlus controller - - ImsMDrivePlusCreateController(motorPortName, IOPortName, devName, movingPollPeriod, idlePollPeriod) - motorPortName: name string assigned to the controller - IOPortName: name of asyn IO port that was created by drvAsynIPPortConfigure() - devName: unique device name used to address the motor in MCode - NOTE: the device name is prepended to all MCode commands to communicate in Party Mode. - See README file for more information. - movingPollPeriod: time in milliseconds between polls when axis is moving - idlePollPeriod: time in milliseconds between polls when axis is not moving - -========================= -Example iocsh st.cmd file -========================= -#!../../bin/linux-x86/ImsMDrivePlus - -# Register all support components -dbLoadDatabase("dbd/ImsMDrivePlus.dbd") -ImsMDrivePlus_registerRecordDeviceDriver pdbbase - -# Motors substitutions, customize this for your motor -dbLoadTemplate "db/motor.mdriveplus.substitutions" - -# Configure asyn communication port, first -drvAsynIPPortConfigure("M06", "ts-b34-nw08:2101", 0, 0, 0 ) - -# Configure one controller per motor, each controller just has 1 axis -ImsMDrivePlusCreateController("IMS1", "M06", "1", 200, 5000) - -# Optional: Enable tracing -asynSetTraceIOMask("IMS1",0,2) -asynSetTraceMask("IMS1",0,2) - -============================================= -Example application database substitions file -============================================= -Db/motor.mdrive.substitutions file: - -file "$(MOTOR)/db/basic_asyn_motor.db" -{ -pattern -{P, N, M, DTYP, PORT, DESC, ADDR, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, DHLM, DLLM, MRES, PREC, INIT} -{IMS:, 1, 1, "asynMotor", IMS1, "MDrive23", 0, mm, Pos, 3.0, 0.017, 2.0, 0, 0.017, 2.0, 100, -100, 0.000083, 4, ""} -} - -file "$(MOTOR)/db/IMS_extra.db" -{ -pattern -{DEV, AREA, LOC, PORT, ADDR, TIMEOUT} -{ims, IOC, 1, IMS1, 0, 1} - - - - - diff --git a/motorApp/ImsSrc/devIM483PL.cc b/motorApp/ImsSrc/devIM483PL.cc deleted file mode 100644 index ca9ce843..00000000 --- a/motorApp/ImsSrc/devIM483PL.cc +++ /dev/null @@ -1,315 +0,0 @@ -/* -FILENAME... devIM483PL.cc -USAGE... Motor record device level support for Intelligent Motion - Systems, Inc. IM483(I/IE). - -*/ - -/* - * Original Author: Ron Sluiter - * Date: 07/10/2000 - * - * Experimental Physics and Industrial Control System (EPICS) - * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. - * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. - * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory - * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * Modification Log: - * ----------------- - * .01 07/10/00 rls copied from devIM483SM.c - * .02 05/16/01 rls Added support for changing jog velocity while jogging. - * .03 03/01/02 rls eliminated "ASCII record separator (IS2) = /x1E". - * .04 04/15/02 rls Must support PRIMITIVE in build_trans() for INIT field to - * work, and add axis name place holder (?) to message. - * .05 03/07/03 rls R3.14 conversion. - */ - -#include -#include -#include "motorRecord.h" -#include "motor.h" -#include "motordevCom.h" -#include "drvIM483.h" -#include "epicsExport.h" - -#define STATIC static - -extern struct driver_table IM483PL_access; - -/* ----------------Create the dsets for devIM483PL----------------- */ -STATIC struct driver_table *drvtabptr; -STATIC long IM483PL_init(int); -STATIC long IM483PL_init_record(void *); -STATIC long IM483PL_start_trans(struct motorRecord *); -STATIC RTN_STATUS IM483PL_build_trans(motor_cmnd, double *, struct motorRecord *); -STATIC RTN_STATUS IM483PL_end_trans(struct motorRecord *); - -struct motor_dset devIM483PL = -{ - {8, NULL, (DEVSUPFUN) IM483PL_init, (DEVSUPFUN) IM483PL_init_record, NULL}, - motor_update_values, - IM483PL_start_trans, - IM483PL_build_trans, - IM483PL_end_trans -}; - -extern "C" {epicsExportAddress(dset,devIM483PL);} - -/* --------------------------- program data --------------------- */ - -/* This table is used to define the command types */ -/* WARNING! this must match "motor_cmnd" in motor.h */ - -static msg_types IM483PL_table[] = { - MOTION, /* MOVE_ABS */ - MOTION, /* MOVE_REL */ - MOTION, /* HOME_FOR */ - MOTION, /* HOME_REV */ - IMMEDIATE, /* LOAD_POS */ - IMMEDIATE, /* SET_VEL_BASE */ - IMMEDIATE, /* SET_VELOCITY */ - IMMEDIATE, /* SET_ACCEL */ - IMMEDIATE, /* GO */ - IMMEDIATE, /* SET_ENC_RATIO */ - INFO, /* GET_INFO */ - MOVE_TERM, /* STOP_AXIS */ - VELOCITY, /* JOG */ - IMMEDIATE, /* SET_PGAIN */ - IMMEDIATE, /* SET_IGAIN */ - IMMEDIATE, /* SET_DGAIN */ - IMMEDIATE, /* ENABLE_TORQUE */ - IMMEDIATE, /* DISABL_TORQUE */ - IMMEDIATE, /* PRIMITIVE */ - IMMEDIATE, /* SET_HIGH_LIMIT */ - IMMEDIATE, /* SET_LOW_LIMIT */ - VELOCITY /* JOG_VELOCITY */ -}; - - -static struct board_stat **IM483PL_cards; - -/* --------------------------- program data --------------------- */ - - -/* initialize device support for IM483PL stepper motor */ -STATIC long IM483PL_init(int after) -{ - long rtnval; - - if (!after) - { - drvtabptr = &IM483PL_access; - (drvtabptr->init)(); - } - - rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &IM483PL_cards); - return(rtnval); -} - - -/* initialize a record instance */ -STATIC long IM483PL_init_record(void *arg) -{ - struct motorRecord *mr = (struct motorRecord *) arg; - return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, IM483PL_cards)); -} - - -/* start building a transaction */ -STATIC long IM483PL_start_trans(struct motorRecord *mr) -{ - return(OK); -} - - -/* end building a transaction */ -STATIC RTN_STATUS IM483PL_end_trans(struct motorRecord *mr) -{ - return(OK); -} - - -/* add a part to the transaction */ -STATIC RTN_STATUS IM483PL_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr) -{ - struct motor_trans *trans = (struct motor_trans *) mr->dpvt; - struct mess_node *motor_call; - struct controller *brdptr; - struct IM483controller *cntrl; - char buff[110]; - int axis, card, maxdigits; - unsigned int size; - double dval, cntrl_units; - RTN_STATUS rtnval; - bool send; - - send = true; /* Default to send motor command. */ - rtnval = OK; - buff[0] = '\0'; - - /* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */ - dval = (parms == NULL) ? 0.0 : *parms; - - motor_start_trans_com(mr, IM483PL_cards); - - motor_call = &(trans->motor_call); - card = motor_call->card; - axis = motor_call->signal + 1; - brdptr = (*trans->tabptr->card_array)[card]; - if (brdptr == NULL) - return(rtnval = ERROR); - - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - cntrl_units = dval; - maxdigits = 2; - - if (IM483PL_table[command] > motor_call->type) - motor_call->type = IM483PL_table[command]; - - if (trans->state != BUILD_STATE) - return(rtnval = ERROR); - - if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0) - { - strcat(motor_call->message, "? "); - strcat(motor_call->message, mr->init); - } - - switch (command) - { - case MOVE_ABS: - case MOVE_REL: - case HOME_FOR: - case HOME_REV: - case JOG: - if (strlen(mr->prem) != 0) - { - strcat(motor_call->message, mr->prem); - strcat(motor_call->message, ";"); - } - if (strlen(mr->post) != 0) - motor_call->postmsgptr = (char *) &mr->post; - break; - - default: - break; - } - - - switch (command) - { - case MOVE_ABS: - sprintf(buff, " R%.*f", maxdigits, cntrl_units); - break; - - case MOVE_REL: - sprintf(buff, " %+.*f", maxdigits, cntrl_units); - break; - - case HOME_FOR: - sprintf(buff, " F1000 0"); - break; - - case HOME_REV: - sprintf(buff, " F1000 1"); - break; - - case LOAD_POS: - if (cntrl_units == 0.0) - sprintf(buff, " O"); - else - { - send = false; - rtnval = ERROR; - } - break; - - case SET_VEL_BASE: - sprintf(buff, " I%.*f;", maxdigits, cntrl_units); - break; - - case SET_VELOCITY: - sprintf(buff, " V%.*f;", maxdigits, cntrl_units); - break; - - case SET_ACCEL: - /* ????? MAKE SENSE OF ACCELERATION PARAMETER ??????*/ - send = false; - break; - - case GO: - /* The IM483PL starts moving immediately on move commands, GO command - * does nothing. */ - send = false; - break; - - case PRIMITIVE: - case GET_INFO: - /* These commands are not actually done by sending a message, but - rather they will indirectly cause the driver to read the status - of all motors */ - break; - - case STOP_AXIS: - sprintf(buff, " @ 0"); - break; - - case JOG_VELOCITY: - case JOG: - sprintf(buff, " M%.*f;", maxdigits, cntrl_units); - break; - - case SET_PGAIN: - case SET_IGAIN: - case SET_DGAIN: - send = false; - break; - - case ENABLE_TORQUE: - sprintf(buff, " MO;"); - break; - - case DISABL_TORQUE: - sprintf(buff, " MF;"); - break; - - case SET_HIGH_LIMIT: - case SET_LOW_LIMIT: - case SET_ENC_RATIO: - trans->state = IDLE_STATE; /* No command sent to the controller. */ - send = false; - break; - - default: - send = false; - rtnval = ERROR; - } - - size = strlen(buff); - if (send == false) - return(rtnval); - else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE) - errlogMessage("IM483PL_build_trans(): buffer overflow.\n"); - else - { - strcat(motor_call->message, buff); - motor_end_trans_com(mr, drvtabptr); - } - return(rtnval); -} diff --git a/motorApp/ImsSrc/devIM483SM.cc b/motorApp/ImsSrc/devIM483SM.cc deleted file mode 100644 index b4321e01..00000000 --- a/motorApp/ImsSrc/devIM483SM.cc +++ /dev/null @@ -1,312 +0,0 @@ -/* -FILENAME... devIM483SM.cc -USAGE... Motor record device level support for Intelligent Motion - Systems, Inc. IM483(I/IE). - -*/ - -/* - * Original Author: Ron Sluiter - * Date: 02/10/2000 - * - * Experimental Physics and Industrial Control System (EPICS) - * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. - * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. - * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory - * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * Modification Log: - * ----------------- - * .01 02/10/00 rls copied from devMM4000.c - * .02 05/16/01 rls Added support for changing jog velocity while jogging. - * .03 03/01/02 rls eliminated "ASCII record separator (IS2) = /x1E". - * .04 04/15/02 rls Must support PRIMITIVE in build_trans() for INIT field to - * work. - * .05 03/07/03 rls R3.14 conversion. - */ - -#include -#include -#include "motorRecord.h" -#include "motor.h" -#include "motordevCom.h" -#include "drvIM483.h" -#include "epicsExport.h" - -#define STATIC static - -extern struct driver_table IM483SM_access; - -/* ----------------Create the dsets for devIM483SM----------------- */ -STATIC struct driver_table *drvtabptr; -STATIC long IM483SM_init(int); -STATIC long IM483SM_init_record(void *); -STATIC long IM483SM_start_trans(struct motorRecord *); -STATIC RTN_STATUS IM483SM_build_trans(motor_cmnd, double *, struct motorRecord *); -STATIC RTN_STATUS IM483SM_end_trans(struct motorRecord *); - -struct motor_dset devIM483SM = -{ - {8, NULL, (DEVSUPFUN) IM483SM_init, (DEVSUPFUN) IM483SM_init_record, NULL}, - motor_update_values, - IM483SM_start_trans, - IM483SM_build_trans, - IM483SM_end_trans -}; - -extern "C" {epicsExportAddress(dset,devIM483SM);} - -/* --------------------------- program data --------------------- */ - -/* This table is used to define the command types */ -/* WARNING! this must match "motor_cmnd" in motor.h */ - -static msg_types IM483SM_table[] = { - MOTION, /* MOVE_ABS */ - MOTION, /* MOVE_REL */ - MOTION, /* HOME_FOR */ - MOTION, /* HOME_REV */ - IMMEDIATE, /* LOAD_POS */ - IMMEDIATE, /* SET_VEL_BASE */ - IMMEDIATE, /* SET_VELOCITY */ - IMMEDIATE, /* SET_ACCEL */ - IMMEDIATE, /* GO */ - IMMEDIATE, /* SET_ENC_RATIO */ - INFO, /* GET_INFO */ - MOVE_TERM, /* STOP_AXIS */ - VELOCITY, /* JOG */ - IMMEDIATE, /* SET_PGAIN */ - IMMEDIATE, /* SET_IGAIN */ - IMMEDIATE, /* SET_DGAIN */ - IMMEDIATE, /* ENABLE_TORQUE */ - IMMEDIATE, /* DISABL_TORQUE */ - IMMEDIATE, /* PRIMITIVE */ - IMMEDIATE, /* SET_HIGH_LIMIT */ - IMMEDIATE, /* SET_LOW_LIMIT */ - VELOCITY /* JOG_VELOCITY */ -}; - - -static struct board_stat **IM483SM_cards; - -/* --------------------------- program data --------------------- */ - - -/* initialize device support for IM483SM stepper motor */ -STATIC long IM483SM_init(int after) -{ - long rtnval; - - if (!after) - { - drvtabptr = &IM483SM_access; - (drvtabptr->init)(); - } - - rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &IM483SM_cards); - return(rtnval); -} - - -/* initialize a record instance */ -STATIC long IM483SM_init_record(void *arg) -{ - struct motorRecord *mr = (struct motorRecord *) arg; - return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, IM483SM_cards)); -} - - -/* start building a transaction */ -STATIC long IM483SM_start_trans(struct motorRecord *mr) -{ - return(OK); -} - - -/* end building a transaction */ -STATIC RTN_STATUS IM483SM_end_trans(struct motorRecord *mr) -{ - return(OK); -} - - -/* add a part to the transaction */ -STATIC RTN_STATUS IM483SM_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr) -{ - struct motor_trans *trans = (struct motor_trans *) mr->dpvt; - struct mess_node *motor_call; - struct controller *brdptr; - struct IM483controller *cntrl; - char buff[110]; - int axis, card, maxdigits; - unsigned int size; - double dval, cntrl_units; - RTN_STATUS rtnval; - bool send; - - send = true; /* Default to send motor command. */ - rtnval = OK; - buff[0] = '\0'; - - /* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */ - dval = (parms == NULL) ? 0.0 : *parms; - - motor_start_trans_com(mr, IM483SM_cards); - - motor_call = &(trans->motor_call); - card = motor_call->card; - axis = motor_call->signal + 1; - brdptr = (*trans->tabptr->card_array)[card]; - if (brdptr == NULL) - return(rtnval = ERROR); - - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - cntrl_units = dval; - maxdigits = 2; - - if (IM483SM_table[command] > motor_call->type) - motor_call->type = IM483SM_table[command]; - - if (trans->state != BUILD_STATE) - return(rtnval = ERROR); - - if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0) - strcat(motor_call->message, mr->init); - - switch (command) - { - case MOVE_ABS: - case MOVE_REL: - case HOME_FOR: - case HOME_REV: - case JOG: - if (strlen(mr->prem) != 0) - { - strcat(motor_call->message, mr->prem); - strcat(motor_call->message, ";"); - } - if (strlen(mr->post) != 0) - motor_call->postmsgptr = (char *) &mr->post; - break; - - default: - break; - } - - - switch (command) - { - case MOVE_ABS: - sprintf(buff, "R%.*f", maxdigits, cntrl_units); - break; - - case MOVE_REL: - sprintf(buff, "%+.*f", maxdigits, cntrl_units); - break; - - case HOME_FOR: - sprintf(buff, "F1000 0"); - break; - - case HOME_REV: - sprintf(buff, "F1000 1"); - break; - - case LOAD_POS: - if (cntrl_units == 0.0) - sprintf(buff, "O"); - else - { - send = false; - rtnval = ERROR; - } - break; - - case SET_VEL_BASE: - sprintf(buff, "I%.*f;", maxdigits, cntrl_units); - break; - - case SET_VELOCITY: - sprintf(buff, "V%.*f;", maxdigits, cntrl_units); - break; - - case SET_ACCEL: - /* ????? MAKE SENSE OF ACCELERATION PARAMETER ??????*/ - send = false; - break; - - case GO: - /* The IM483 starts moving immediately on move commands, GO command - * does nothing. */ - send = false; - break; - - case PRIMITIVE: - case GET_INFO: - /* These commands are not actually done by sending a message, but - rather they will indirectly cause the driver to read the status - of all motors */ - break; - - case STOP_AXIS: - sprintf(buff, "@ 0"); - break; - - case JOG_VELOCITY: - case JOG: - sprintf(buff, "M%.*f;", maxdigits, cntrl_units); - break; - - case SET_PGAIN: - case SET_IGAIN: - case SET_DGAIN: - send = false; - break; - - case ENABLE_TORQUE: - sprintf(buff, "MO;"); - break; - - case DISABL_TORQUE: - sprintf(buff, "MF;"); - break; - - case SET_HIGH_LIMIT: - case SET_LOW_LIMIT: - case SET_ENC_RATIO: - trans->state = IDLE_STATE; /* No command sent to the controller. */ - send = false; - break; - - default: - send = false; - rtnval = ERROR; - } - - size = strlen(buff); - if (send == false) - return(rtnval); - else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE) - errlogMessage("IM483SM_build_trans(): buffer overflow.\n"); - else - { - strcat(motor_call->message, buff); - motor_end_trans_com(mr, drvtabptr); - } - return(rtnval); -} diff --git a/motorApp/ImsSrc/devImsMotor.dbd b/motorApp/ImsSrc/devImsMotor.dbd deleted file mode 100644 index b3e9f5f7..00000000 --- a/motorApp/ImsSrc/devImsMotor.dbd +++ /dev/null @@ -1,12 +0,0 @@ -# Intelligent Motion Systems driver support. -device(motor,VME_IO,devIM483SM,"IM483SM") -device(motor,VME_IO,devIM483PL,"IM483PL") -device(motor,VME_IO,devMDrive, "MDrive") -driver(drvIM483SM) -driver(drvIM483PL) -driver(drvMDrive) -registrar(IMSmotorRegister) -registrar(ImsMDrivePlusMotorRegister) -variable(drvIM483SMdebug) -variable(drvIM483PLdebug) -variable(drvMDrivedebug) diff --git a/motorApp/ImsSrc/devMDrive.cc b/motorApp/ImsSrc/devMDrive.cc deleted file mode 100644 index 633a3714..00000000 --- a/motorApp/ImsSrc/devMDrive.cc +++ /dev/null @@ -1,327 +0,0 @@ -/* -FILENAME... devMDrive.cc -USAGE... Motor record device level support for Intelligent Motion - Systems, Inc. MDrive series of controllers. - -*/ - -/* - * Original Author: Ron Sluiter - * Date: 03/21/03 - * - * Experimental Physics and Industrial Control System (EPICS) - * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. - * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. - * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory - * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * Modification Log: - * ----------------- - * .01 03/21/03 rls copied from devIM483PL.c - * .02 05/15/03 rls R3.14 compatible. - * .03 03/15/04 rls bug fix for LOAD_POS command with encoder. - * .04 03/16/04 rls Protect against NULL "parms" argument in - * MDrive_build_trans(). - * .05 09/20/04 rls remove '?' command string padding. - * .06 04/06/05 rls Bug fix for not setting accel = decel. - * .07 01/28/11 jps MDrive Release 3.x requires an '=' on velocity commands. - */ - -#include -#include - -#include "motorRecord.h" -#include "motor.h" -#include "motordevCom.h" -#include "drvIM483.h" -#include "epicsExport.h" - -#define STATIC static - -extern struct driver_table MDrive_access; - -/* ----------------Create the dsets for devMDrive----------------- */ -STATIC struct driver_table *drvtabptr; -STATIC long MDrive_init(int); -STATIC long MDrive_init_record(void *); -STATIC long MDrive_start_trans(struct motorRecord *); -STATIC RTN_STATUS MDrive_build_trans(motor_cmnd, double *, struct motorRecord *); -STATIC RTN_STATUS MDrive_end_trans(struct motorRecord *); - -struct motor_dset devMDrive = -{ - {8, NULL, (DEVSUPFUN) MDrive_init, (DEVSUPFUN) MDrive_init_record, NULL}, - motor_update_values, - MDrive_start_trans, - MDrive_build_trans, - MDrive_end_trans -}; - -extern "C" {epicsExportAddress(dset,devMDrive);} - -/* --------------------------- program data --------------------- */ - -/* This table is used to define the command types */ -/* WARNING! this must match "motor_cmnd" in motor.h */ - -static msg_types MDrive_table[] = { - MOTION, /* MOVE_ABS */ - MOTION, /* MOVE_REL */ - MOTION, /* HOME_FOR */ - MOTION, /* HOME_REV */ - IMMEDIATE, /* LOAD_POS */ - IMMEDIATE, /* SET_VEL_BASE */ - IMMEDIATE, /* SET_VELOCITY */ - IMMEDIATE, /* SET_ACCEL */ - IMMEDIATE, /* GO */ - IMMEDIATE, /* SET_ENC_RATIO */ - INFO, /* GET_INFO */ - MOVE_TERM, /* STOP_AXIS */ - VELOCITY, /* JOG */ - IMMEDIATE, /* SET_PGAIN */ - IMMEDIATE, /* SET_IGAIN */ - IMMEDIATE, /* SET_DGAIN */ - IMMEDIATE, /* ENABLE_TORQUE */ - IMMEDIATE, /* DISABL_TORQUE */ - IMMEDIATE, /* PRIMITIVE */ - IMMEDIATE, /* SET_HIGH_LIMIT */ - IMMEDIATE, /* SET_LOW_LIMIT */ - VELOCITY /* JOG_VELOCITY */ -}; - - -static struct board_stat **MDrive_cards; - -/* --------------------------- program data --------------------- */ - - -/* initialize device support for MDrive stepper motor */ -STATIC long MDrive_init(int after) -{ - long rtnval; - - if (!after) - { - drvtabptr = &MDrive_access; - (drvtabptr->init)(); - } - - rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MDrive_cards); - return(rtnval); -} - - -/* initialize a record instance */ -STATIC long MDrive_init_record(void *arg) -{ - struct motorRecord *mr = (struct motorRecord *) arg; - return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, MDrive_cards)); -} - - -/* start building a transaction */ -STATIC long MDrive_start_trans(struct motorRecord *mr) -{ - return(OK); -} - - -/* end building a transaction */ -STATIC RTN_STATUS MDrive_end_trans(struct motorRecord *mr) -{ - return(OK); -} - - -/* add a part to the transaction */ -STATIC RTN_STATUS MDrive_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr) -{ - struct motor_trans *trans = (struct motor_trans *) mr->dpvt; - struct mess_node *motor_call; - struct controller *brdptr; - struct IM483controller *cntrl; - char buff[110]; - int axis, card, intval; - unsigned int size; - RTN_STATUS rtnval; - bool send; - msta_field msta; - - send = true; /* Default to send motor command. */ - rtnval = OK; - buff[0] = '\0'; - - /* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */ - intval = (parms == NULL) ? 0 : NINT(parms[0]); - - msta.All = mr->msta; - - motor_start_trans_com(mr, MDrive_cards); - - motor_call = &(trans->motor_call); - card = motor_call->card; - axis = motor_call->signal + 1; - brdptr = (*trans->tabptr->card_array)[card]; - if (brdptr == NULL) - return(rtnval = ERROR); - - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - - if (MDrive_table[command] > motor_call->type) - motor_call->type = MDrive_table[command]; - - if (trans->state != BUILD_STATE) - return(rtnval = ERROR); - - if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0) - { - strcat(motor_call->message, " "); - strcat(motor_call->message, mr->init); - } - - switch (command) - { - case MOVE_ABS: - case MOVE_REL: - case HOME_FOR: - case HOME_REV: - case JOG: - if (strlen(mr->prem) != 0) - { - strcat(motor_call->message, mr->prem); - strcat(motor_call->message, " "); - } - if (strlen(mr->post) != 0) - motor_call->postmsgptr = (char *) &mr->post; - break; - - default: - break; - } - - - switch (command) - { - case MOVE_ABS: - sprintf(buff, "MA %d", intval); - break; - - case MOVE_REL: - sprintf(buff, "MR %d", intval); - break; - - case HOME_FOR: - sprintf(buff, " F1000 0"); - break; - - case HOME_REV: - sprintf(buff, " F1000 1"); - break; - - case LOAD_POS: - sprintf(buff, "P=%d", intval); - if (msta.Bits.EA_PRESENT == 1) - { - /* Finish 1st message; MDrive can only handle one msg. */ - strcpy(motor_call->message, buff); - rtnval = motor_end_trans_com(mr, drvtabptr); - rtnval = (RTN_STATUS) motor_start_trans_com(mr, MDrive_cards); - - intval = NINT(mr->dval / mr->eres); - sprintf(buff, "C2=%d", intval); - motor_call->type = MDrive_table[command]; - } - break; - - case SET_VEL_BASE: - sprintf(buff, "VI=%d", intval); - break; - - case SET_VELOCITY: - sprintf(buff, "VM=%d", intval); - break; - - case SET_ACCEL: - sprintf(buff, "A=%d", intval); - strcpy(motor_call->message, buff); - rtnval = motor_end_trans_com(mr, drvtabptr); - rtnval = (RTN_STATUS) motor_start_trans_com(mr, MDrive_cards); - sprintf(buff, "D=A"); - motor_call->type = MDrive_table[command]; - break; - - case GO: - /* The MDrive starts moving immediately on move commands, GO command - * does nothing. */ - send = false; - break; - - case PRIMITIVE: - case GET_INFO: - /* These commands are not actually done by sending a message, but - rather they will indirectly cause the driver to read the status - of all motors */ - break; - - case STOP_AXIS: - sprintf(buff, "SL 0"); - break; - - case JOG_VELOCITY: - case JOG: - sprintf(buff, "SL=%d", intval); - break; - - case SET_PGAIN: - case SET_IGAIN: - case SET_DGAIN: - send = false; - break; - - case ENABLE_TORQUE: - sprintf(buff, "DE=1"); - break; - - case DISABL_TORQUE: - sprintf(buff, "DE=0"); - break; - - case SET_HIGH_LIMIT: - case SET_LOW_LIMIT: - case SET_ENC_RATIO: - trans->state = IDLE_STATE; /* No command sent to the controller. */ - send = false; - break; - - default: - send = false; - rtnval = ERROR; - } - - size = strlen(buff); - if (send == false) - return(rtnval); - else if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE) - errlogMessage("MDrive_build_trans(): buffer overflow.\n"); - else - { - strcat(motor_call->message, buff); - motor_end_trans_com(mr, drvtabptr); - } - return(rtnval); -} diff --git a/motorApp/ImsSrc/drvIM483.h b/motorApp/ImsSrc/drvIM483.h deleted file mode 100644 index f971c56a..00000000 --- a/motorApp/ImsSrc/drvIM483.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -FILENAME... drvIM483.h -USAGE... This file contains driver "include" information that is specific to - Intelligent Motion Systems, Inc. IM483(I/IE) and MDrive controllers. - -*/ - -/* - * Original Author: Ron Sluiter - * Date: 02/10/2000 - * - * Experimental Physics and Industrial Control System (EPICS) - * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. - * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. - * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory - * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * - * - * Modification Log: - * ----------------- - * .01 02/10/2000 rls copied from drvMM4000.h - * .02 07/01/2004 rls Converted from MPF to asyn. - * .03 03/18/2005 rls Added MDrive input configuration structure. - */ - -#ifndef INCdrvIM483h -#define INCdrvIM483h 1 - -#include "motordrvCom.h" -#include "asynDriver.h" -#include "asynOctetSyncIO.h" - -#define COMM_TIMEOUT 2 /* Timeout in seconds */ - -/* MDrive input configuration - 0 indicates unassigned. */ -typedef struct inputc -{ - epicsUInt8 plusLS; /* Input # of + limit switch. */ - epicsUInt8 minusLS; /* Input # of - limit switch. */ - epicsUInt8 homeLS; /* Input # of home switch. */ -} input_config; - - -/* IMS specific data is stored in this structure. */ -struct IM483controller -{ - asynUser *pasynUser; /* For RS-232 */ - char asyn_port[80]; /* asyn port name */ - CommStatus status; /* Controller communication status. */ - input_config *inconfig; /* Discrete input configuration - MDrive only. */ -}; - -/* Function prototypes. */ -extern RTN_STATUS IM483SMSetup(int, int); -extern RTN_STATUS IM483PLSetup(int, int); -extern RTN_STATUS MDriveSetup(int, int); -extern RTN_STATUS IM483SMConfig(int, const char *); -extern RTN_STATUS IM483PLConfig(int, const char *); -extern RTN_STATUS MDriveConfig(int, const char *); - -#endif /* INCdrvIM483h */ - diff --git a/motorApp/ImsSrc/drvIM483PL.cc b/motorApp/ImsSrc/drvIM483PL.cc deleted file mode 100644 index c503ae66..00000000 --- a/motorApp/ImsSrc/drvIM483PL.cc +++ /dev/null @@ -1,622 +0,0 @@ -/* -FILENAME... drvIM483PL.cc -USAGE... Motor record driver level support for Intelligent Motion - Systems, Inc. IM483(I/IE). - -*/ - -/***************************************************************** - COPYRIGHT NOTIFICATION -***************************************************************** - -(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO - -This software was developed under a United States Government license -described on the COPYRIGHT_UniversityOfChicago file included as part -of this distribution. -**********************************************************************/ - -/* - * Original Author: Ron Sluiter - * Date: 07/10/2000 - * - * Modification Log: - * ----------------- - * .01 07/10/00 rls copied from drvIM483SM.c - * .02 10/02/01 rls allow one retry after a communication error. - * .03 04/15/02 rls Bug fix for limit switches. Set RA_DIRECTION in - * set_status() based on (new - old) commanded position. - * Removed support for "ASCII record separator (IS2) = /x1E" - * from send_mess(). - * .04 03/07/03 rls R3.14 conversion. - * .05 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR". - * .06 07/01/04 rls Converted from MPF to asyn. - * .07 09/20/04 rls - increase BUFF_SIZE; response was exceeding 13 characters. - * - support for 32axes/controller. - * - remove '?' command line padding. - * .08 12/14/04 rls - asyn R4.0 support. - * - make debug variables always available. - * - MS Visual C compatibility; make all epicsExportAddress - * extern "C" linkage. - * - retry on initial communication. - */ - -/* -DESIGN LIMITATIONS... - 1 - Like all controllers, the IM483 must be powered-on when EPICS is first - booted up. - 2 - The IM483 cannot be power cycled while EPICS is up and running. The - consequences are permanent communication lose with the IM483 until - EPICS is rebooted. - 3 - Like the Newport MM3000, the IM483's position can only be set to zero. - 4 - The IM483 uses an internal look-up table for acceleration/deceleration. - Translation between the IM483 and the ACCL/BACC fields is not obvious. -*/ - -#include -#include -#include -#include -#include -#include "motor.h" -#include "drvIM483.h" -#include "asynOctetSyncIO.h" -#include "epicsExport.h" - -/* Read Limit Status response values. */ -#define L_ALIMIT 1 -#define L_BLIMIT 2 -#define L_BOTH_LIMITS 3 - - -#define IM483PL_NUM_CARDS 8 -#define MAX_AXES 8 -#define BUFF_SIZE 50 /* Maximum length of string to/from IM483PL */ - -/*----------------debugging-----------------*/ -volatile int drvIM483PLdebug = 0; -extern "C" {epicsExportAddress(int, drvIM483PLdebug);} - -static inline void Debug(int level, const char *format, ...) { - #ifdef DEBUG - if (level < drvIM483PLdebug) { - va_list pVar; - va_start(pVar, format); - vprintf(format, pVar); - va_end(pVar); - } - #endif -} - -/* --- Local data. --- */ -int IM483PL_num_cards = 0; -static char *IM483PL_axis[] = {"A", "B", "C", "D", "E", "F", "G", "H"}; - -/* Local data required for every driver; see "motordrvComCode.h" */ -#include "motordrvComCode.h" - -/*----------------functions-----------------*/ -static int recv_mess(int, char *, int); -static RTN_STATUS send_mess(int, char const *, char *); -static int set_status(int, int); -static long report(int); -static long init(); -static int motor_init(); -static void query_done(int, int, struct mess_node *); - -/*----------------functions-----------------*/ - -struct driver_table IM483PL_access = -{ - motor_init, - motor_send, - motor_free, - motor_card_info, - motor_axis_info, - &mess_queue, - &queue_lock, - &free_list, - &freelist_lock, - &motor_sem, - &motor_state, - &total_cards, - &any_motor_in_motion, - send_mess, - recv_mess, - set_status, - query_done, - NULL, - &initialized, - IM483PL_axis -}; - -struct -{ - long number; - long (*report) (int); - long (*init) (void); -} drvIM483PL = {2, report, init}; - -extern "C" {epicsExportAddress(drvet, drvIM483PL);} - -static struct thread_args targs = {SCAN_RATE, &IM483PL_access, 0.0}; - -/********************************************************* - * Print out driver status report - *********************************************************/ -static long report(int level) -{ - int card; - - if (IM483PL_num_cards <=0) - printf(" No IM483PL controllers configured.\n"); - else - { - for (card = 0; card < IM483PL_num_cards; card++) - { - struct controller *brdptr = motor_state[card]; - - if (brdptr == NULL) - printf(" IM483PL controller %d connection failed.\n", card); - else - { - struct IM483controller *cntrl; - - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - printf(" IM483PL controller #%d, port=%s, id: %s \n", card, - cntrl->asyn_port, brdptr->ident); - } - } - } - return(OK); -} - - -static long init() -{ - /* - * We cannot call motor_init() here, because that function can do GPIB I/O, - * and hence requires that the drvGPIB have already been initialized. - * That cannot be guaranteed, so we need to call motor_init from device - * support - */ - /* Check for setup */ - if (IM483PL_num_cards <= 0) - { - Debug(1, "init(): IM483PL driver disabled. IM483PLSetup() missing from startup script.\n"); - } - return((long) 0); -} - - -static void query_done(int card, int axis, struct mess_node *nodeptr) -{ -} - - -/******************************************************************************** -* * -* FUNCTION NAME: set_status * -* * -* LOGIC: * -* Initialize. * -* Send "Moving Status" query. * -* Read response. * -* IF normal response to query. * -* Set communication status to NORMAL. * -* ELSE * -* IF communication status is NORMAL. * -* Set communication status to RETRY. * -* NORMAL EXIT. * -* ELSE * -* Set communication status error. * -* ERROR EXIT. * -* ENDIF * -* ENDIF * -* * -* IF "Moving Status" indicates any motion (i.e. status != 0). * -* Clear "Done Moving" status bit. * -* ELSE * -* Set "Done Moving" status bit. * -* ENDIF * -* * -* * -********************************************************************************/ - -static int set_status(int card, int signal) -{ - struct IM483controller *cntrl; - struct mess_node *nodeptr; - register struct mess_info *motor_info; - /* Message parsing variables */ - char buff[BUFF_SIZE]; - int rtnval, rtn_state; - double motorData; - bool plusdir, ls_active = false; - msta_field status; - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - motor_info = &(motor_state[card]->motor_info[signal]); - nodeptr = motor_info->motor_motion; - status.All = motor_info->status.All; - - send_mess(card, " ^", IM483PL_axis[signal]); - rtn_state = recv_mess(card, buff, 1); - if (rtn_state > 0) - { - cntrl->status = NORMAL; - status.Bits.CNTRL_COMM_ERR = 0; - } - else - { - if (cntrl->status == NORMAL) - { - cntrl->status = RETRY; - rtn_state = 0; - goto exit; - } - else - { - cntrl->status = COMM_ERR; - status.Bits.CNTRL_COMM_ERR = 1; - status.Bits.RA_PROBLEM = 1; - rtn_state = 1; - goto exit; - } - } - - rtnval = atoi(&buff[4]); - - status.Bits.RA_DONE = (rtnval != 0) ? 0 : 1; - - /* - * Parse motor position - * Position string format: 1TP5.012,2TP1.123,3TP-100.567,... - * Skip to substring for this motor, convert to double - */ - - send_mess(card, " Z 0", IM483PL_axis[signal]); - recv_mess(card, buff, 1); - - motorData = atof(&buff[5]); - - if (motorData == motor_info->position) - { - if (nodeptr != 0) /* Increment counter only if motor is moving. */ - motor_info->no_motion_count++; - } - else - { - epicsInt32 newposition; - - newposition = NINT(motorData); - status.Bits.RA_DIRECTION = (newposition >= motor_info->position) ? 1 : 0; - motor_info->position = newposition; - motor_info->no_motion_count = 0; - } - - plusdir = (status.Bits.RA_DIRECTION) ? true : false; - - send_mess(card, " ] 0", IM483PL_axis[signal]); - recv_mess(card, buff, 1); - rtnval = atoi(&buff[5]); - - /* Set limit switch error indicators. */ - if (rtnval & 1) - { - status.Bits.RA_PLUS_LS = 1; - if (plusdir == true) - ls_active = true; - } - else - status.Bits.RA_PLUS_LS = 0; - - if (rtnval & 2) - { - status.Bits.RA_MINUS_LS = 1; - if (plusdir == false) - ls_active = true; - } - else - status.Bits.RA_MINUS_LS = 0; - - send_mess(card, " ] 1", IM483PL_axis[signal]); - recv_mess(card, buff, 1); - rtnval = buff[5]; - - status.Bits.RA_HOME = (rtnval & 0x01) ? 1 : 0; - - /* !!! Assume no closed-looped control!!!*/ - status.Bits.EA_POSITION = 0; - - /* encoder status */ - status.Bits.EA_SLIP = 0; - status.Bits.EA_SLIP_STALL = 0; - status.Bits.EA_HOME = 0; - - if (motor_state[card]->motor_info[signal].encoder_present == NO) - motor_info->encoder_position = 0; - else - { - send_mess(card, " z 0", IM483PL_axis[signal]); - recv_mess(card, buff, 1); - motorData = atof(&buff[5]); - motor_info->encoder_position = (epicsInt32) motorData; - } - - status.Bits.RA_PROBLEM = 0; - - /* Parse motor velocity? */ - /* NEEDS WORK */ - - motor_info->velocity = 0; - - if (!status.Bits.RA_DIRECTION) - motor_info->velocity *= -1; - - rtn_state = (!motor_info->no_motion_count || ls_active == true || - status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0; - - /* Test for post-move string. */ - if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 && nodeptr->postmsgptr != 0) - { - strcpy(buff, nodeptr->postmsgptr); - send_mess(card, buff, IM483PL_axis[signal]); - nodeptr->postmsgptr = NULL; - } - -exit: - motor_info->status.All = status.All; - return(rtn_state); -} - - -/*****************************************************/ -/* send a message to the IM483PL board */ -/* send_mess() */ -/*****************************************************/ -static RTN_STATUS send_mess(int card, char const *com, char *name) -{ - char local_buff[MAX_MSG_SIZE]; - struct IM483controller *cntrl; - int comsize, namesize; - size_t nwrite; - - comsize = (com == NULL) ? 0 : strlen(com); - namesize = (name == NULL) ? 0 : strlen(name); - - if ((comsize + namesize) > MAX_MSG_SIZE) - { - errlogMessage("drvIM483PL.c:send_mess(); message size violation.\n"); - return(ERROR); - } - else if (comsize == 0) /* Normal exit on empty input message. */ - return(OK); - - if (!motor_state[card]) - { - errlogPrintf("drvIM483PL.c:send_mess() - invalid card #%d\n", card); - return(ERROR); - } - - /* Make a local copy of the string and add the command line terminator. */ - if (namesize != 0) - { - strcpy(local_buff, name); /* put in axis */ - strcat(local_buff, com); - } - else - strcpy(local_buff, com); - - Debug(2, "send_mess(): message = %s\n", local_buff); - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff), COMM_TIMEOUT, &nwrite); - - return(OK); -} - - -/*****************************************************/ -/* receive a message from the IM483 board */ -/* recv_mess() */ -/*****************************************************/ -static int recv_mess(int card, char *com, int flag) -{ - struct IM483controller *cntrl; - size_t nread = 0; - asynStatus status = asynError; - int eomReason; - - /* Check that card exists */ - if (!motor_state[card]) - return(ERROR); - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - - if (flag == FLUSH) - pasynOctetSyncIO->flush(cntrl->pasynUser); - else - status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE, COMM_TIMEOUT, &nread, &eomReason); - - if ((status != asynSuccess) || (nread <= 0)) - { - com[0] = '\0'; - nread = 0; - } - - Debug(2, "recv_mess(): message = \"%s\"\n", com); - return(nread); -} - - -/*****************************************************/ -/* Setup system configuration */ -/* IM483PLSetup() */ -/*****************************************************/ -RTN_STATUS -IM483PLSetup(int num_cards, /* maximum number of controllers in system. */ - int scan_rate) /* polling rate - 1/60 sec units. */ -{ - int itera; - - if (num_cards < 1 || num_cards > IM483PL_NUM_CARDS) - IM483PL_num_cards = IM483PL_NUM_CARDS; - else - IM483PL_num_cards = num_cards; - - /* Set motor polling task rate */ - if (scan_rate >= 1 && scan_rate <= 60) - targs.motor_scan_rate = scan_rate; - else - targs.motor_scan_rate = SCAN_RATE; - - /* - * Allocate space for motor_state structures. Note this must be done - * before IM483Config is called, so it cannot be done in motor_init() - * This means that we must allocate space for a card without knowing - * if it really exists, which is not a serious problem - */ - motor_state = (struct controller **) malloc(IM483PL_num_cards * sizeof(struct controller *)); - - for (itera = 0; itera < IM483PL_num_cards; itera++) - motor_state[itera] = (struct controller *) NULL; - - return(OK); -} - - -/*****************************************************/ -/* Configure a controller */ -/* IM483PLConfig() */ -/*****************************************************/ -RTN_STATUS -IM483PLConfig(int card, /* card being configured */ - const char *name) /* asyn server task name */ -{ - struct IM483controller *cntrl; - - if (card < 0 || card >= IM483PL_num_cards) - return(ERROR); - - motor_state[card] = (struct controller *) malloc(sizeof(struct controller)); - motor_state[card]->DevicePrivate = malloc(sizeof(struct IM483controller)); - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - - strcpy(cntrl->asyn_port, name); - return(OK); -} - - -/*****************************************************/ -/* initialize all software and hardware */ -/* This is called from the initialization routine in */ -/* device support. */ -/* motor_init() */ -/*****************************************************/ -static int motor_init() -{ - struct controller *brdptr; - struct IM483controller *cntrl; - int card_index, motor_index; - char buff[BUFF_SIZE]; - int total_axis = 0; - int status; - asynStatus success_rtn; - static const char output_terminator[] = "\n"; - static const char input_terminator[] = "\n"; - - initialized = true; /* Indicate that driver is initialized. */ - - /* Check for setup */ - if (IM483PL_num_cards <= 0) - return(ERROR); - - for (card_index = 0; card_index < IM483PL_num_cards; card_index++) - { - if (!motor_state[card_index]) - continue; - - brdptr = motor_state[card_index]; - brdptr->ident[0] = (char) NULL; /* No controller identification message. */ - brdptr->cmnd_response = true; - total_cards = card_index + 1; - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - - /* Initialize communications channel */ - success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0, &cntrl->pasynUser, NULL); - - if (success_rtn == asynSuccess) - { - pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator, strlen(output_terminator)); - pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator, strlen(input_terminator)); - /* Send a message to the board, see if it exists */ - /* flush any junk at input port - should not be any data available */ - pasynOctetSyncIO->flush(cntrl->pasynUser); - - for (total_axis = 0; total_axis < MAX_AXES; total_axis++) - { - int retry = 0; - - do - { - send_mess(card_index, " Z 0", IM483PL_axis[total_axis]); - status = recv_mess(card_index, buff, 1); - retry++; - } while (status <= 0 && retry < 3); - - if (status <= 0) - break; - } - brdptr->total_axis = total_axis; - } - - if (success_rtn == asynSuccess && total_axis > 0) - { - brdptr->localaddr = (char *) NULL; - brdptr->motor_in_motion = 0; - - for (motor_index = 0; motor_index < total_axis; motor_index++) - { - struct mess_info *motor_info = &brdptr->motor_info[motor_index]; - int loop_state; - - motor_info->status.All = 0; - motor_info->no_motion_count = 0; - motor_info->encoder_position = 0; - motor_info->position = 0; - brdptr->motor_info[motor_index].motor_motion = NULL; - /* Assume encoder support, i.e., IM483IE. */ - motor_info->encoder_present = YES; - motor_info->status.Bits.EA_PRESENT = 1; - - /* Determine if encoder present based on open/closed loop mode. */ - loop_state = 0; - if (loop_state != 0) - { - motor_info->pid_present = YES; - motor_info->status.Bits.GAIN_SUPPORT = 1; - } - - set_status(card_index, motor_index); /* Read status of each motor */ - } - } - else - motor_state[card_index] = (struct controller *) NULL; - } - - any_motor_in_motion = 0; - - mess_queue.head = (struct mess_node *) NULL; - mess_queue.tail = (struct mess_node *) NULL; - - free_list.head = (struct mess_node *) NULL; - free_list.tail = (struct mess_node *) NULL; - - epicsThreadCreate((char *) "IM483PL_motor", epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackMedium), - (EPICSTHREADFUNC) motor_task, (void *) &targs); - - return(OK); -} - diff --git a/motorApp/ImsSrc/drvIM483SM.cc b/motorApp/ImsSrc/drvIM483SM.cc deleted file mode 100644 index 5d0157ef..00000000 --- a/motorApp/ImsSrc/drvIM483SM.cc +++ /dev/null @@ -1,654 +0,0 @@ -/* -FILENAME... drvIM483SM.cc -USAGE... Motor record driver level support for Intelligent Motion - Systems, Inc. IM483(I/IE). - -*/ - -/***************************************************************** - COPYRIGHT NOTIFICATION -***************************************************************** - -(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO - -This software was developed under a United States Government license -described on the COPYRIGHT_UniversityOfChicago file included as part -of this distribution. -**********************************************************************/ - -/* - * Original Author: Ron Sluiter - * Date: 02/10/2000 - * - * Modification Log: - * ----------------- - * .01 02/10/00 rls copied from drvMM4000.c - * .02 10/02/01 rls allow one retry after a communication error. - * .03 04/15/02 rls Bug fix for limit switches. Set RA_DIRECTION in - * set_status() based on (new - old) commanded position. - * Removed support for "ASCII record separator (IS2) = /x1E" - * from send_mess(). - * .04 03/07/03 rls R3.14 conversion. - * .05 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR". - * .06 07/01/04 rls Converted from MPF to asyn. - * .07 09/20/04 rls support for 32axes/controller. - * .08 12/14/04 rls - asyn R4.0 support. - * - make debug variables always available. - * - MS Visual C compatibility; make all epicsExportAddress - * extern "C" linkage. - * - retry on initial communication. - */ - -/* -DESIGN LIMITATIONS... - 1 - Like all controllers, the IM483 must be powered-on when EPICS is first - booted up. - 2 - The IM483 cannot be power cycled while EPICS is up and running. The - consequences are permanent communication lose with the IM483 until - EPICS is rebooted. - 3 - Like the Newport MM3000, the IM483's position can only be set to zero. - 4 - The IM483 uses an internal look-up table for acceleration/deceleration. - Translation between the IM483 and the ACCL/BACC fields is not obvious. -*/ - -#include -#include -#include -#include -#include -#include -#include "motor.h" -#include "drvIM483.h" -#include "asynOctetSyncIO.h" -#include "epicsExport.h" - -/* Read Limit Status response values. */ -#define L_ALIMIT 1 -#define L_BLIMIT 2 -#define L_BOTH_LIMITS 3 - - -#define IM483SM_NUM_CARDS 8 -#define BUFF_SIZE 50 /* Maximum length of string to/from IM483 */ - -/*----------------debugging-----------------*/ -volatile int drvIM483SMdebug = 0; -extern "C" {epicsExportAddress(int, drvIM483SMdebug);} - -static inline void Debug(int level, const char *format, ...) { - #ifdef DEBUG - if (level < drvIM483SMdebug) { - va_list pVar; - va_start(pVar, format); - vprintf(format, pVar); - va_end(pVar); - } - #endif -} - -/* --- Local data. --- */ -int IM483SM_num_cards = 0; - -/* Local data required for every driver; see "motordrvComCode.h" */ -#include "motordrvComCode.h" - -/*----------------functions-----------------*/ -static int recv_mess(int, char *, int); -static RTN_STATUS send_mess(int, char const *, char *); -static int set_status(int, int); -static long report(int); -static long init(); -static int motor_init(); -static void query_done(int, int, struct mess_node *); - -/*----------------functions-----------------*/ - -struct driver_table IM483SM_access = -{ - motor_init, - motor_send, - motor_free, - motor_card_info, - motor_axis_info, - &mess_queue, - &queue_lock, - &free_list, - &freelist_lock, - &motor_sem, - &motor_state, - &total_cards, - &any_motor_in_motion, - send_mess, - recv_mess, - set_status, - query_done, - NULL, - &initialized, - NULL -}; - -struct -{ - long number; - long (*report) (int); - long (*init) (void); -} drvIM483SM = {2, report, init}; - -extern "C" {epicsExportAddress(drvet, drvIM483SM);} - -static struct thread_args targs = {SCAN_RATE, &IM483SM_access, 0.0}; - - -/********************************************************* - * Print out driver status report - *********************************************************/ -static long report(int level) -{ - int card; - - if (IM483SM_num_cards <=0) - printf(" No IM483SM controllers configured.\n"); - else - { - for (card = 0; card < IM483SM_num_cards; card++) - { - struct controller *brdptr = motor_state[card]; - - if (brdptr == NULL) - printf(" IM483SM controller %d connection failed.\n", card); - else - { - struct IM483controller *cntrl; - - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - printf(" IM483SM controller #%d, port=%s, id: %s \n", card, - cntrl->asyn_port, brdptr->ident); - } - } - } - return(OK); -} - - -static long init() -{ - /* - * We cannot call motor_init() here, because that function can do GPIB I/O, - * and hence requires that the drvGPIB have already been initialized. - * That cannot be guaranteed, so we need to call motor_init from device - * support - */ - /* Check for setup */ - if (IM483SM_num_cards <= 0) - { - Debug(1, "init(): IM483SM driver disabled. IM483SMSetup() missing from startup script.\n"); - } - return((long) 0); -} - - -static void query_done(int card, int axis, struct mess_node *nodeptr) -{ -} - - -/******************************************************************************** -* * -* FUNCTION NAME: set_status * -* * -* LOGIC: * -* Initialize. * -* Send "Moving Status" query. * -* Read response. * -* IF normal response to query. * -* Set communication status to NORMAL. * -* ELSE * -* IF communication status is NORMAL. * -* Set communication status to RETRY. * -* NORMAL EXIT. * -* ELSE * -* Set communication status error. * -* ERROR EXIT. * -* ENDIF * -* ENDIF * -* * -* IF "Moving Status" indicates any motion (i.e. status != 0). * -* Clear "Done Moving" status bit. * -* ELSE * -* Set "Done Moving" status bit. * -* ENDIF * -* * -* * -********************************************************************************/ - -static int set_status(int card, int signal) -{ - struct IM483controller *cntrl; - struct mess_node *nodeptr; - register struct mess_info *motor_info; - /* Message parsing variables */ - char buff[BUFF_SIZE]; - int rtnval, rtn_state; - double motorData; - bool plusdir, ls_active = false; - msta_field status; - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - motor_info = &(motor_state[card]->motor_info[signal]); - nodeptr = motor_info->motor_motion; - status.All = motor_info->status.All; - - send_mess(card, "^", (char*) NULL); - rtn_state = recv_mess(card, buff, 1); - if (rtn_state > 0) - { - cntrl->status = NORMAL; - status.Bits.CNTRL_COMM_ERR = 0; - } - else - { - if (cntrl->status == NORMAL) - { - cntrl->status = RETRY; - rtn_state = 0; - goto exit; - } - else - { - cntrl->status = COMM_ERR; - status.Bits.CNTRL_COMM_ERR = 1; - status.Bits.RA_PROBLEM = 1; - rtn_state = 1; - goto exit; - } - } - - rtnval = atoi(&buff[4]); - - status.Bits.RA_DONE = (rtnval != 0) ? 0 : 1; - - /* - * Parse motor position - * Position string format: 1TP5.012,2TP1.123,3TP-100.567,... - * Skip to substring for this motor, convert to double - */ - - send_mess(card, "Z 0", (char*) NULL); - recv_mess(card, buff, 1); - - motorData = atof(&buff[5]); - - if (motorData == motor_info->position) - { - if (nodeptr != 0) /* Increment counter only if motor is moving. */ - motor_info->no_motion_count++; - } - else - { - epicsInt32 newposition; - - newposition = NINT(motorData); - status.Bits.RA_DIRECTION = (newposition >= motor_info->position) ? 1 : 0; - motor_info->position = newposition; - motor_info->no_motion_count = 0; - } - - plusdir = (status.Bits.RA_DIRECTION) ? true : false; - - send_mess(card, "] 0", (char*) NULL); - recv_mess(card, buff, 1); - rtnval = atoi(&buff[5]); - - /* Set limit switch error indicators. */ - if (rtnval & 1) - { - status.Bits.RA_PLUS_LS = 1; - if (plusdir == true) - ls_active = true; - } - else - status.Bits.RA_PLUS_LS = 0; - - if (rtnval & 2) - { - status.Bits.RA_MINUS_LS = 1; - if (plusdir == false) - ls_active = true; - } - else - status.Bits.RA_MINUS_LS = 0; - - send_mess(card, "] 1", (char*) NULL); - recv_mess(card, buff, 1); - rtnval = buff[5]; - - status.Bits.RA_HOME = (rtnval & 0x01) ? 1 : 0; - - /* !!! Assume no closed-looped control!!!*/ - status.Bits.EA_POSITION = 0; - - /* encoder status */ - status.Bits.EA_SLIP = 0; - status.Bits.EA_SLIP_STALL = 0; - status.Bits.EA_HOME = 0; - - if (motor_state[card]->motor_info[signal].encoder_present == NO) - motor_info->encoder_position = 0; - else - { - send_mess(card, "z 0", (char*) NULL); - recv_mess(card, buff, 1); - motorData = atof(&buff[5]); - motor_info->encoder_position = (epicsInt32) motorData; - } - - status.Bits.RA_PROBLEM = 0; - - /* Parse motor velocity? */ - /* NEEDS WORK */ - - motor_info->velocity = 0; - - if (!status.Bits.RA_DIRECTION) - motor_info->velocity *= -1; - - rtn_state = (!motor_info->no_motion_count || ls_active == true || status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0; - - /* Test for post-move string. */ - if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 && - nodeptr->postmsgptr != 0) - { - strcpy(buff, nodeptr->postmsgptr); - send_mess(card, buff, (char*) NULL); - nodeptr->postmsgptr = NULL; - } - -exit: - motor_info->status.All = status.All; - return(rtn_state); -} - - -/*****************************************************/ -/* send a message to the IM483SM board */ -/* send_mess() */ -/*****************************************************/ -static RTN_STATUS send_mess(int card, char const *com, char *name) -{ - struct IM483controller *cntrl; - int size; - size_t nwrite; - - size = strlen(com); - - if (size > MAX_MSG_SIZE) - { - errlogMessage("drvIM483SM.c:send_mess(); message size violation.\n"); - return(ERROR); - } - else if (size == 0) /* Normal exit on empty input message. */ - return(OK); - - if (!motor_state[card]) - { - errlogPrintf("drvIM483SM.c:send_mess() - invalid card #%d\n", card); - return(ERROR); - } - - if (name != NULL) - { - errlogPrintf("drvIM483SM.c:send_mess() - invalid argument = %s\n", name); - return(ERROR); - } - - Debug(2, "send_mess(): message = %s\n", com); - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - pasynOctetSyncIO->write(cntrl->pasynUser, com, size, COMM_TIMEOUT, &nwrite); - - return(OK); -} - - -/*****************************************************/ -/* receive a message from the IM483 board */ -/* recv_mess() */ -/*****************************************************/ -static int recv_mess(int card, char *com, int flag) -{ - struct IM483controller *cntrl; - size_t nread = 0; - asynStatus status = asynError; - int eomReason; - - /* Check that card exists */ - if (!motor_state[card]) - return(ERROR); - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - - if (flag == FLUSH) - pasynOctetSyncIO->flush(cntrl->pasynUser); - else - status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE, COMM_TIMEOUT, &nread, &eomReason); - - if ((status != asynSuccess) || (nread <= 0)) - { - com[0] = '\0'; - nread = 0; - } - - Debug(2, "recv_mess(): message = \"%s\"\n", com); - return(nread); -} - - -/*****************************************************/ -/* Setup system configuration */ -/* IM483SMSetup() */ -/*****************************************************/ -RTN_STATUS -IM483SMSetup(int num_cards, /* maximum number of controllers in system. */ - int scan_rate) /* polling rate - 1/60 sec units. */ -{ - int itera; - - if (num_cards < 1 || num_cards > IM483SM_NUM_CARDS) - IM483SM_num_cards = IM483SM_NUM_CARDS; - else - IM483SM_num_cards = num_cards; - - /* Set motor polling task rate */ - if (scan_rate >= 1 && scan_rate <= 60) - targs.motor_scan_rate = scan_rate; - else - targs.motor_scan_rate = SCAN_RATE; - - /* - * Allocate space for motor_state structures. Note this must be done - * before IM483SMConfig is called, so it cannot be done in motor_init() - * This means that we must allocate space for a card without knowing - * if it really exists, which is not a serious problem - */ - motor_state = (struct controller **) malloc(IM483SM_num_cards * sizeof(struct controller *)); - - for (itera = 0; itera < IM483SM_num_cards; itera++) - motor_state[itera] = (struct controller *) NULL; - - return(OK); -} - - -/*****************************************************/ -/* Configure a controller */ -/* IM483SMConfig() */ -/*****************************************************/ -RTN_STATUS -IM483SMConfig(int card, /* card being configured */ - const char *name) /* asyn server task name */ -{ - struct IM483controller *cntrl; - - if (card < 0 || card >= IM483SM_num_cards) - return(ERROR); - - motor_state[card] = (struct controller *) malloc(sizeof(struct controller)); - motor_state[card]->DevicePrivate = malloc(sizeof(struct IM483controller)); - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - - strcpy(cntrl->asyn_port, name); - return(OK); -} - - -/*****************************************************/ -/* initialize all software and hardware */ -/* This is called from the initialization routine in */ -/* device support. */ -/* motor_init() */ -/*****************************************************/ -static int motor_init() -{ - struct controller *brdptr; - struct IM483controller *cntrl; - int card_index, motor_index; - char buff[BUFF_SIZE]; - int total_axis = 0; - int status = 0; - asynStatus success_rtn; - static const char output_terminator[] = "\r"; - static const char input_terminator[] = "\r\n"; - - initialized = true; /* Indicate that driver is initialized. */ - - /* Check for setup */ - if (IM483SM_num_cards <= 0) - return(ERROR); - - for (card_index = 0; card_index < IM483SM_num_cards; card_index++) - { - if (!motor_state[card_index]) - continue; - - brdptr = motor_state[card_index]; - brdptr->cmnd_response = true; - total_cards = card_index + 1; - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - - /* Initialize communications channel */ - success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0, &cntrl->pasynUser, NULL); - - if (success_rtn == asynSuccess) - { - int itera, retry = 0; - char *src, *dest; - - pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator, strlen(output_terminator)); - pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator, strlen(input_terminator)); - do - { - /* Send a message to the board, see if it exists */ - /* flush any junk at input port - should not be any data available */ - pasynOctetSyncIO->flush(cntrl->pasynUser); - - send_mess(card_index, "\003", (char*) NULL); /* Reset device. */ - epicsThreadSleep(1.0); - send_mess(card_index, " ", (char*) NULL); - - /* Save controller identification message. */ - src = buff; - dest = brdptr->ident; - *src = (char) NULL; - - for (itera = 0; itera < 50; itera++) - { - if (*src == (char) NULL) - { - status = recv_mess(card_index, buff, 1); - if (status <= 0) - { - if (itera != 0) - { - *dest = (char) NULL; - status = 1; - } - break; - } - src = buff; - while (isspace(*src++)); - --src; - if (itera != 0) - { - *dest++ = ' '; - itera++; - } - } - else if (isspace(*src)) - { - while (isspace(*src++)); - src -= 2; - } - else if (strncmp(src, "AD", 2) == 0) - { - strcpy(dest, "AMS"); - src += 22; - dest += 3; - itera += 3; - } - *dest++ = *src++; - } - retry++; - /* Return value is length of response string */ - } while (status == 0 && retry < 3); - } - - if (success_rtn == asynSuccess && status > 0) - { - brdptr->localaddr = (char *) NULL; - brdptr->motor_in_motion = 0; - - brdptr->total_axis = total_axis = 1; - - for (motor_index = 0; motor_index < total_axis; motor_index++) - { - struct mess_info *motor_info = &brdptr->motor_info[motor_index]; - int loop_state; - - motor_info->status.All = 0; - motor_info->no_motion_count = 0; - motor_info->encoder_position = 0; - motor_info->position = 0; - brdptr->motor_info[motor_index].motor_motion = NULL; - - /* Determine if encoder present based on open/closed loop mode. */ - loop_state = 0; - if (loop_state != 0) - { - motor_info->encoder_present = YES; - motor_info->status.Bits.EA_PRESENT = 1; - motor_info->pid_present = YES; - motor_info->status.Bits.GAIN_SUPPORT = 1; - } - - set_status(card_index, motor_index); /* Read status of each motor */ - } - } - else - motor_state[card_index] = (struct controller *) NULL; - } - - any_motor_in_motion = 0; - - mess_queue.head = (struct mess_node *) NULL; - mess_queue.tail = (struct mess_node *) NULL; - - free_list.head = (struct mess_node *) NULL; - free_list.tail = (struct mess_node *) NULL; - - epicsThreadCreate((char *) "IM483SM_motor", epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackMedium), - (EPICSTHREADFUNC) motor_task, (void *) &targs); - - return(OK); -} - diff --git a/motorApp/ImsSrc/drvMDrive.cc b/motorApp/ImsSrc/drvMDrive.cc deleted file mode 100644 index 22ceabc6..00000000 --- a/motorApp/ImsSrc/drvMDrive.cc +++ /dev/null @@ -1,745 +0,0 @@ -/* -FILENAME... drvMDrive.cc -USAGE... Motor record driver level support for Intelligent Motion - Systems, Inc. MDrive series; M17, M23, M34. - -*/ - -/* - * Original Author: Ron Sluiter - * Date: 03/21/03 - * - * Experimental Physics and Industrial Control System (EPICS) - * - * Copyright 1991, the Regents of the University of California, - * and the University of Chicago Board of Governors. - * - * This software was produced under U.S. Government contracts: - * (W-7405-ENG-36) at the Los Alamos National Laboratory, - * and (W-31-109-ENG-38) at Argonne National Laboratory. - * - * Initial development by: - * The Controls and Automation Group (AT-8) - * Ground Test Accelerator - * Accelerator Technology Division - * Los Alamos National Laboratory - * - * Co-developed with - * The Controls and Computing Group - * Accelerator Systems Division - * Advanced Photon Source - * Argonne National Laboratory - * - * NOTES - * ----- - * Verified with firmware: - * - * - 1.071 E - * - 3.003 (MDI1FRD17B4-EQ) - * - 3.010 - * - * Modification Log: - * ----------------- - * .01 03/21/03 rls copied from drvIM483PL.c - * .02 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR". - * .03 03/15/04 rls Previous driver releases not working. Fixed by adding - * Kevin Peterson's eat_garbage() function. Added support - * for encoder detection via "ident". - * .04 07/01/04 rls Converted from MPF to asyn. - * .05 09/20/04 rls - support for 32axes/controller. - * - remove '?' command string padding. - * .06 12/16/04 rls - asyn R4.0 support. - * - make debug variables always available. - * - MS Visual C compatibility; make all epicsExportAddress - * extern "C" linkage. - * .07 03/18/05 rls - Flexible MDrive I/O configuration. - * - Change Echo mode to 2; eliminate eat_garbage(). - * .08 12/17/10 rls - Test to determine if encoder is present changed to - * accommodate new firmware. - * - support actual velocity status update. - * .09 02/06/11 rls - "PR PN" response overflows input buffer; increased - * BUFF_SIZE from 13 to 80 bytes. - * - Slow "PR PN" response; increased timeout from 1 to 2 sec. - * - Extra "\r\n" from "PR PN" response; buffer flush added. - * - Eliminate compiler warnings on MDrive_axis[]. - */ - -/* -DESIGN LIMITATIONS... - 1 - Like all controllers, the MDrive must be powered-on when EPICS is first - booted up. - 2 - The MDrive cannot be power cycled while EPICS is up and running. The - consequences are permanent communication lose with the MDrive until - EPICS is rebooted. -*/ - -#include -#include -#include -#include -#include -#include "motor.h" -#include "drvIM483.h" -#include "asynOctetSyncIO.h" -#include "epicsExport.h" - -#define MDrive_NUM_CARDS 8 -#define MAX_AXES 8 -#define BUFF_SIZE 80 /* Maximum length of string to/from MDrive */ - -/*----------------debugging-----------------*/ -volatile int drvMDrivedebug = 0; -extern "C" {epicsExportAddress(int, drvMDrivedebug);} - -static inline void Debug(int level, const char *format, ...) { - #ifdef DEBUG - if (level < drvMDrivedebug) { - va_list pVar; - va_start(pVar, format); - vprintf(format, pVar); - va_end(pVar); - } - #endif -} - -/* --- Local data. --- */ -int MDrive_num_cards = 0; -static const char* const MDrive_axis[] = {"1", "2", "3", "4", "5", "6", "7", "8"}; - -/* Local data required for every driver; see "motordrvComCode.h" */ -#include "motordrvComCode.h" - -/*----------------functions-----------------*/ -static int recv_mess(int, char *, int); -static RTN_STATUS send_mess(int, char const *, const char *const); -static int set_status(int, int); -static long report(int); -static long init(); -static int motor_init(); -static void query_done(int, int, struct mess_node *); - -/*----------------functions-----------------*/ - -struct driver_table MDrive_access = -{ - motor_init, - motor_send, - motor_free, - motor_card_info, - motor_axis_info, - &mess_queue, - &queue_lock, - &free_list, - &freelist_lock, - &motor_sem, - &motor_state, - &total_cards, - &any_motor_in_motion, - (RTN_STATUS (*)(int, const char*, char*)) send_mess, - recv_mess, - set_status, - query_done, - NULL, - &initialized, - (char **) MDrive_axis -}; - -struct drvMDrive_drvet -{ - long number; - long (*report) (int); - long (*init) (void); -} drvMDrive = {2, report, init}; - -extern "C" {epicsExportAddress(drvet, drvMDrive);} - -static struct thread_args targs = {SCAN_RATE, &MDrive_access, 0.0}; - - -/********************************************************* - * Print out driver status report - *********************************************************/ -static long report(int level) -{ - int card; - - if (MDrive_num_cards <= 0) - printf(" No MDrive controllers configured.\n"); - else - { - for (card = 0; card < MDrive_num_cards; card++) - { - struct controller *brdptr = motor_state[card]; - - if (brdptr == NULL) - printf(" MDrive controller %d connection failed.\n", card); - else - { - struct IM483controller *cntrl; - - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - printf(" MDrive controller #%d, port=%s, id: %s \n", card, - cntrl->asyn_port, brdptr->ident); - } - } - } - return(OK); -} - - -static long init() -{ - /* - * We cannot call motor_init() here, because that function can do GPIB I/O, - * and hence requires that the drvGPIB have already been initialized. That - * cannot be guaranteed, so we need to call motor_init from device support - */ - /* Check for setup */ - if (MDrive_num_cards <= 0) - { - Debug(1, "init(): MDrive driver disabled. MDriveSetup() missing from startup script.\n"); - } - return((long) 0); -} - - -static void query_done(int card, int axis, struct mess_node *nodeptr) -{ -} - - -/****************************************************************************** -* -* FUNCTION NAME: set_status -* -* LOGIC: -* Initialize. -* Send "Moving Status" query. -* Read response. -* IF normal response to query. -* Set communication status to NORMAL. -* ELSE -* IF communication status is NORMAL. -* Set communication status to RETRY. -* NORMAL EXIT. -* ELSE -* Set communication status error. -* ERROR EXIT. -* ENDIF -* ENDIF -* -* IF "Moving Status" indicates any motion (i.e. status != 0). -* Clear "Done Moving" status bit. -* ELSE -* Set "Done Moving" status bit. -* ENDIF -* -******************************************************************************/ - -static int set_status(int card, int signal) -{ - struct IM483controller *cntrl; - struct mess_node *nodeptr; - register struct mess_info *motor_info; - /* Message parsing variables */ - char buff[BUFF_SIZE]; - int rtnval, rtn_state; - double motorData; - epicsUInt8 Lswitch; - bool plusdir, ls_active = false; - msta_field status; - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - input_config *confptr = cntrl->inconfig; - motor_info = &(motor_state[card]->motor_info[signal]); - nodeptr = motor_info->motor_motion; - status.All = motor_info->status.All; - - /* Protect against extra "\r\n" terminator. */ - rtn_state = recv_mess(card, buff, FLUSH); - - send_mess(card, "PR MV", MDrive_axis[signal]); - rtn_state = recv_mess(card, buff, 1); - if (rtn_state > 0) - { - cntrl->status = NORMAL; - status.Bits.CNTRL_COMM_ERR = 0; - } - else - { - if (cntrl->status == NORMAL) - { - cntrl->status = RETRY; - rtn_state = OK; - goto exit; - } - else - { - cntrl->status = COMM_ERR; - status.Bits.CNTRL_COMM_ERR = 1; - status.Bits.RA_PROBLEM = 1; - rtn_state = 1; - goto exit; - } - } - - rtnval = atoi(buff); - - status.Bits.RA_DONE = (rtnval != 0) ? 0 : 1; - - /* - * Parse motor position - * Position string format: 1TP5.012,2TP1.123,3TP-100.567,... - * Skip to substring for this motor, convert to double - */ - - send_mess(card, "PR P", MDrive_axis[signal]); - recv_mess(card, buff, 1); - - motorData = atof(buff); - - if (motorData == motor_info->position) - { - if (nodeptr != 0) /* Increment counter only if motor is moving. */ - motor_info->no_motion_count++; - } - else - { - epicsInt32 newposition; - - newposition = NINT(motorData); - status.Bits.RA_DIRECTION = (newposition >= motor_info->position) ? 1 : 0; - motor_info->position = newposition; - motor_info->no_motion_count = 0; - } - - plusdir = (status.Bits.RA_DIRECTION) ? true : false; - - if (confptr->plusLS == 0 || confptr->minusLS == 0) - { - status.Bits.RA_PLUS_LS = 0; - status.Bits.RA_MINUS_LS = 0; - } - else - { - sprintf(buff, "PR I%d", confptr->plusLS); - send_mess(card, buff, MDrive_axis[signal]); - recv_mess(card, buff, 1); - Lswitch = atoi(buff); - - /* Set limit Lswitch error indicators. */ - if (Lswitch != 0) - { - status.Bits.RA_PLUS_LS = 1; - if (plusdir == true) - ls_active = true; - } - else - status.Bits.RA_PLUS_LS = 0; - - sprintf(buff, "PR I%d", confptr->minusLS); - send_mess(card, buff, MDrive_axis[signal]); - recv_mess(card, buff, 1); - Lswitch = atoi(buff); - - if (Lswitch != 0) - { - status.Bits.RA_MINUS_LS = 1; - if (plusdir == false) - ls_active = true; - } - else - status.Bits.RA_MINUS_LS = 0; - } - - if (confptr->homeLS == 0) - status.Bits.RA_HOME = 0; - else - { - sprintf(buff, "PR I%d", confptr->homeLS); - send_mess(card, buff, MDrive_axis[signal]); - recv_mess(card, buff, 1); - Lswitch = atoi(buff); - status.Bits.RA_HOME = (Lswitch) ? 1 : 0; - } - - /* !!! Assume no closed-looped control!!! */ - status.Bits.EA_POSITION = 0; - - /* encoder status */ - status.Bits.EA_SLIP = 0; - status.Bits.EA_SLIP_STALL = 0; - status.Bits.EA_HOME = 0; - - if (motor_state[card]->motor_info[signal].encoder_present == NO) - motor_info->encoder_position = 0; - else - { - send_mess(card, "PR C2", MDrive_axis[signal]); - recv_mess(card, buff, 1); - motorData = atof(buff); - motor_info->encoder_position = (epicsInt32) motorData; - } - - status.Bits.RA_PROBLEM = 0; - - /* Get current motor velocity */ - - send_mess(card, "PR V", MDrive_axis[signal]); - recv_mess(card, buff, 1); - motorData = atof(buff); - motor_info->velocity = (epicsInt32) motorData; - - if (!status.Bits.RA_DIRECTION) - motor_info->velocity *= -1; - - rtn_state = (!motor_info->no_motion_count || ls_active == true || - status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0; - - /* Test for post-move string. */ - if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 && - nodeptr->postmsgptr != 0) - { - strcpy(buff, nodeptr->postmsgptr); - send_mess(card, buff, MDrive_axis[signal]); - nodeptr->postmsgptr = NULL; - } - -exit: - motor_info->status.All = status.All; - return(rtn_state); -} - - -/*****************************************************/ -/* send a message to the MDrive board */ -/* send_mess() */ -/*****************************************************/ -static RTN_STATUS send_mess(int card, char const *com, const char *const name) -{ - char local_buff[MAX_MSG_SIZE]; - struct IM483controller *cntrl; - int comsize, namesize; - size_t nwrite; - - comsize = (com == NULL) ? 0 : strlen(com); - namesize = (name == NULL) ? 0 : strlen(name); - - if ((comsize + namesize) > MAX_MSG_SIZE) - { - errlogMessage("drvMDrive.c:send_mess(); message size violation.\n"); - return(ERROR); - } - else if (comsize == 0) /* Normal exit on empty input message. */ - return(OK); - - if (!motor_state[card]) - { - errlogPrintf("drvMDrive.c:send_mess() - invalid card #%d\n", card); - return(ERROR); - } - - /* Make a local copy of the string and add the command line terminator. */ - if (namesize != 0) - { - strcpy(local_buff, name); /* put in axis */ - strcat(local_buff, com); - } - else - strcpy(local_buff, com); - - Debug(2, "send_mess(): message = %s\n", local_buff); - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - pasynOctetSyncIO->write(cntrl->pasynUser, local_buff, strlen(local_buff), - COMM_TIMEOUT, &nwrite); - - return(OK); -} - - -/*****************************************************/ -/* receive a message from the MDrive board */ -/* recv_mess() */ -/*****************************************************/ -static int recv_mess(int card, char *com, int flag) -{ - struct IM483controller *cntrl; - const double timeout = 2.0; - size_t nread = 0; - asynStatus status = asynError; - int eomReason; - - /* Check that card exists */ - if (!motor_state[card]) - return(ERROR); - - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - - if (flag == FLUSH) - pasynOctetSyncIO->flush(cntrl->pasynUser); - else - status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE, - timeout, &nread, &eomReason); - - if ((status != asynSuccess) || (nread <= 0)) - { - com[0] = '\0'; - nread = 0; - } - - Debug(2, "recv_mess(): message = \"%s\"\n", com); - return(nread); -} - - -/*****************************************************/ -/* Setup system configuration */ -/* MDriveSetup() */ -/*****************************************************/ -RTN_STATUS -MDriveSetup(int num_cards, /* maximum number of chains in system. */ - int scan_rate) /* polling rate - 1/60 sec units. */ -{ - int itera; - - if (num_cards < 1 || num_cards > MDrive_NUM_CARDS) - MDrive_num_cards = MDrive_NUM_CARDS; - else - MDrive_num_cards = num_cards; - - /* Set motor polling task rate */ - if (scan_rate >= 1 && scan_rate <= 60) - targs.motor_scan_rate = scan_rate; - else - targs.motor_scan_rate = SCAN_RATE; - - /* - * Allocate space for motor_state structures. Note this must be done - * before IM483Config is called, so it cannot be done in motor_init() This - * means that we must allocate space for a card without knowing if it - * really exists, which is not a serious problem - */ - motor_state = (struct controller **) - malloc(MDrive_num_cards * sizeof(struct controller *)); - - for (itera = 0; itera < MDrive_num_cards; itera++) - motor_state[itera] = (struct controller *) NULL; - - return(OK); -} - - -/*****************************************************/ -/* Configure a controller */ -/* MDriveConfig() */ -/*****************************************************/ -RTN_STATUS -MDriveConfig(int card, /* chain being configured */ - const char *name) /* ASYN port name */ -{ - struct IM483controller *cntrl; - - if (card < 0 || card >= MDrive_num_cards) - return(ERROR); - - motor_state[card] = (struct controller *) malloc(sizeof(struct controller)); - motor_state[card]->DevicePrivate = malloc(sizeof(struct IM483controller)); - cntrl = (struct IM483controller *) motor_state[card]->DevicePrivate; - - strcpy(cntrl->asyn_port, name); - return(OK); -} - - -/*****************************************************/ -/* initialize all software and hardware */ -/* This is called from the initialization routine in */ -/* device support. */ -/* motor_init() */ -/*****************************************************/ -static int motor_init() -{ - struct controller *brdptr; - struct IM483controller *cntrl; - int card_index, motor_index; - char buff[BUFF_SIZE]; - int total_axis = 0; - int status; - asynStatus success_rtn; - static const char output_terminator[] = "\n"; - static const char input_terminator[] = "\r\n"; - - initialized = true; /* Indicate that driver is initialized. */ - - /* Check for setup */ - if (MDrive_num_cards <= 0) - return(ERROR); - - for (card_index = 0; card_index < MDrive_num_cards; card_index++) - { - if (!motor_state[card_index]) - continue; - - brdptr = motor_state[card_index]; - brdptr->ident[0] = (char) NULL; /* No controller ID message. */ - brdptr->cmnd_response = false; - total_cards = card_index + 1; - cntrl = (struct IM483controller *) brdptr->DevicePrivate; - - /* Initialize communications channel */ - success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port, 0, - &cntrl->pasynUser, NULL); - - if (success_rtn == asynSuccess) - { - pasynOctetSyncIO->setOutputEos(cntrl->pasynUser, output_terminator, - strlen(output_terminator)); - pasynOctetSyncIO->setInputEos(cntrl->pasynUser, input_terminator, - strlen(input_terminator)); - /* Send a message to the board, see if it exists */ - /* flush any junk at input port - should not be any data available */ - pasynOctetSyncIO->flush(cntrl->pasynUser); - - for (total_axis = 0; total_axis < MAX_AXES; total_axis++) - { - int retry = 0; - - /* Try 3 times to connect to controller. */ - do - { - send_mess(card_index, "PR VR", MDrive_axis[total_axis]); - status = recv_mess(card_index, buff, 1); - retry++; - } while (status == 0 && retry < 3); - - if (status <= 0) - break; - else if (total_axis == 0) - strcpy(brdptr->ident, buff); - } - brdptr->total_axis = total_axis; - cntrl->inconfig = (input_config *) - malloc(sizeof(struct IM483controller) * total_axis); - } - - if (success_rtn == asynSuccess && total_axis > 0) - { - input_config *confptr = cntrl->inconfig; - - brdptr->localaddr = (char *) NULL; - brdptr->motor_in_motion = 0; - - for (motor_index = 0; motor_index < total_axis; motor_index++) - { - int itera; - bool encoder = false; /* Default to no encoder detected. */ - struct mess_info *motor_info = &brdptr->motor_info[motor_index]; - - motor_info->status.All = 0; - motor_info->no_motion_count = 0; - motor_info->encoder_position = 0; - motor_info->position = 0; - brdptr->motor_info[motor_index].motor_motion = NULL; - - /* Determine if encoder present based last character of "ident". */ - if (brdptr->ident[strlen(brdptr->ident) - 1] == 'E') - encoder = true; - else - { - int size; - - /* Try to get "Part number" (not in old firmware). */ - send_mess(card_index, "PR PN", MDrive_axis[motor_index]); - size = recv_mess(card_index, buff, 1); - if (size > 0) - { - bool found = false; - - found |= !strcmp(&buff[size-1],"E"); - found |= !strcmp(&buff[size-2],"EQ"); - found |= !strcmp(&buff[size-2],"EE"); - found |= !strcmp(&buff[size-3],"EJM"); - found |= !strcmp(&buff[size-5],"EJM-N"); - encoder = found; - } - } - - if (encoder == true) - { - motor_info->pid_present = YES; - motor_info->status.Bits.GAIN_SUPPORT = 1; - motor_info->encoder_present = YES; - motor_info->status.Bits.EA_PRESENT = 1; - } - else - motor_info->encoder_present = NO; - - /* Protect against extra "\r\n" terminator. */ - status = recv_mess(card_index, buff, 1); - - /* Determine input configuration. */ - confptr->homeLS = confptr->minusLS = confptr->plusLS = 0; - - for (itera = 1; itera <= 4; itera++) - { - int type, active; - - sprintf(buff, "PR S%d", itera); - send_mess(card_index, buff, MDrive_axis[motor_index]); - status = recv_mess(card_index, buff, 1); - if (status == 0) - { - errlogPrintf("Error reading I/O configuration.\n"); - break; - } - - status = sscanf(buff, "%d,%d", &type, &active); - switch (type) - { - case 0: - break; - case 1: /* Home switch. */ - confptr->homeLS = itera; - break; - case 2: /* Plus limit switch. */ - confptr->plusLS = itera; - break; - case 3: /* Minus limit switch. */ - confptr->minusLS = itera; - break; - default: - errlogPrintf("Invalid I/O type: %d.\n", type); - - } - } - /* Test for missing configuration. */ - if (confptr->minusLS == 0 || confptr->plusLS == 0) - { - const char p_label[6] = "Plus", m_label[6] = "Minus"; - errlogPrintf("MDrive chain #%d, motor #%d %s LS not configured.\n", - card_index, motor_index, - (confptr->minusLS == 0) ? m_label : p_label); - } - - set_status(card_index, motor_index); /* Read status of each motor */ - } - } - else - motor_state[card_index] = (struct controller *) NULL; - } - - any_motor_in_motion = 0; - - mess_queue.head = (struct mess_node *) NULL; - mess_queue.tail = (struct mess_node *) NULL; - - free_list.head = (struct mess_node *) NULL; - free_list.tail = (struct mess_node *) NULL; - - epicsThreadCreate((char *) "MDrive_motor", epicsThreadPriorityMedium, - epicsThreadGetStackSize(epicsThreadStackMedium), - (EPICSTHREADFUNC) motor_task, (void *) &targs); - - return(OK); -} diff --git a/motorApp/Makefile b/motorApp/Makefile index 13eff83e..c93eabae 100644 --- a/motorApp/Makefile +++ b/motorApp/Makefile @@ -21,9 +21,6 @@ OmsAsynSrc_DEPEND_DIRS = MotorSrc DIRS += MotorSimSrc MotorSimSrc_DEPEND_DIRS = MotorSrc -DIRS += ImsSrc -ImsSrc_DEPEND_DIRS = MotorSrc - DIRS += PIGCS2Src PIGCS2Src_DEPEND_DIRS = MotorSrc