Merge branch 'dev'

This commit is contained in:
2024-06-25 12:34:09 -05:00
6 changed files with 299 additions and 21 deletions

View File

@@ -10,12 +10,19 @@ motorDSM is a submodule of [motor](https://github.com/epics-modules/motor).
When motorDSM is built in the ``motor/modules`` directory, no manual When motorDSM is built in the ``motor/modules`` directory, no manual
configuration is needed. configuration is needed.
motorDSM can also be built outside of motor by copying it's motorDSM can also be built outside of motor by copying it's ``configure/EXAMPLE_RELEASE.local`` file to ``RELEASE.local`` and defining the paths to ``EPICS_BASE``, ``MOTOR``, and itself.
``EXAMPLE_RELEASE.local`` file to ``RELEASE.local`` and defining the paths to
``EPICS_BASE``, ``MOTOR``, and itself.
motorDSM contains an example IOC that is built if ``CONFIG_SITE.local`` sets motorDSM contains an example IOC that is built if ``configure/CONFIG_SITE.local`` sets ``BUILD_IOCS = YES``. The example IOC can be built outside of the driver module. Copy ``iocs/dsmIOC/configure/EXAMPLE_RELEASE.local`` to ``RELEASE.local`` and uncomment and set the paths for the appropriate lines depending on whether motorDSM was built inside the motor module or independently.
``BUILD_IOCS = YES``. The example IOC can be built outside of driver module.
To run the example IOC, in the ``iocs/dsmIOC/iocBoot/iocDsm`` directory, run
$ ../../bin/linux-x86_64/dsm st.cmd.md90
for one attached MD-90 controller, or
$ ../../bin/linux-x86_64/dsm st.cmd.md90.multi
for eight attached MD-90 controllers.
------------------------ ------------------------
@@ -116,12 +123,16 @@ motorDSM (this package)
$ cd $SUPPORT $ cd $SUPPORT
$ git clone git@github.com:Binary-Coalescence/motorDSM.git $ git clone git@github.com:Binary-Coalescence/motorDSM.git
In ``motorDSM/configure``, copy ``EXAMPLE_RELEASE.local`` to ``RELEASE.local``
and set paths for ``EPICS_BASE``, ``MOTOR``, and ``MOTOR_DSM``.
In ``motorDSM/configure``, copy ``EXAMPLE_CONFIG_SITE.local`` In ``motorDSM/configure``, copy ``EXAMPLE_CONFIG_SITE.local``
to ``CONFIG_SITE.local`` and set: to ``CONFIG_SITE.local`` and set:
BUILD_IOCS = YES BUILD_IOCS = YES
In ``motorDSM/configure``, copy ``EXAMPLE_RELEASE.local`` to ``RELEASE.local`` In ``motorDSM/iocs/dsmIOC/configure``, copy ``EXAMPLE_RELEASE.local`` to
and set paths for ``EPICS_BASE``, ``MOTOR``, and ``MOTOR_DSM``. ``RELEASE.local``. Comment out the "if built inside motor" lines, uncomment the
"if built outside motor" lines, and set the path for ``MOTOR_DSM``.
$ cd motorDSM $ cd motorDSM
$ make distclean $ make distclean

View File

@@ -18,8 +18,8 @@
#- ################################################### #- ###################################################
# DSM MD-90 serial connection settings # DSM MD-90 serial connection settings
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=19200, BITS=8, STOP=1, PARITY=none") iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=115200, BITS=8, STOP=1, PARITY=none")
asynOctetSetInputEos( "$(PORT)", -1, "\r") asynOctetSetInputEos( "$(PORT)", -1, "\r")
asynOctetSetOutputEos("$(PORT)", -1, "\r") asynOctetSetOutputEos("$(PORT)", -1, "\r")
MD90CreateController("$(INSTANCE)", "$(PORT)", $(NUM_AXES=1), $(MOVING_POLL=$(POLL_RATE=100)), $(IDLE_POLL=$(POLL_RATE=100))) MD90CreateController("$(INSTANCE)", "$(PORT)", $(NUM_AXES=1), $(MOVING_POLL=$(POLL_RATE=100)), $(IDLE_POLL=$(POLL_RATE=1000)))

View File

@@ -140,6 +140,37 @@ void MD90Axis::report(FILE *fp, int level)
asynMotorAxis::report(fp, level); asynMotorAxis::report(fp, level);
} }
/** Print out message if the motor controller returns a non-zero error code
* \param[in] functionName The function originating the call
* \param[in] reply Reply message returned from motor controller
*/
asynStatus MD90Axis::parseReply(const char *functionName, const char *reply)
{
int replyStatus;
char replyString[256];
int replyValue;
asynStatus comStatus;
comStatus = asynSuccess;
if (reply[0] == '\0') {
comStatus = asynError;
replyStatus = -1;
} else if ( strcmp(reply, "Unrecognized command.") == 0 ) {
replyStatus = 6;
} else {
sscanf(reply, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
}
if (replyStatus != 0) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
"%s: %s\n",
functionName, reply);
}
return comStatus;
}
/** Acceleration currently unsupported with MD-90 controller /** Acceleration currently unsupported with MD-90 controller
* \param[in] acceleration The accelerations to ramp up to max velocity * \param[in] acceleration The accelerations to ramp up to max velocity
* \param[in] velocity Motor velocity in steps / sec * \param[in] velocity Motor velocity in steps / sec
@@ -148,7 +179,7 @@ asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity)
{ {
asynStatus status; asynStatus status;
int freq; int freq;
// static const char *functionName = "MD90::sendAccelAndVelocity"; static const char *functionName = "MD90::sendAccelAndVelocity";
// Send the velocity // Send the velocity
// Velocity provided in steps/sec // Velocity provided in steps/sec
@@ -157,6 +188,9 @@ asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity)
freq = NINT(fabs(velocity / 500.)); freq = NINT(fabs(velocity / 500.));
sprintf(pC_->outString_, "SSF %d", freq); sprintf(pC_->outString_, "SSF %d", freq);
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
@@ -165,7 +199,7 @@ asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity)
asynStatus MD90Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration) asynStatus MD90Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{ {
asynStatus status; asynStatus status;
// static const char *functionName = "MD90Axis::move"; static const char *functionName = "MD90Axis::move";
status = sendAccelAndVelocity(acceleration, maxVelocity); status = sendAccelAndVelocity(acceleration, maxVelocity);
@@ -177,18 +211,24 @@ asynStatus MD90Axis::move(double position, int relative, double minVelocity, dou
sprintf(pC_->outString_, "CLM %d", NINT(position)); sprintf(pC_->outString_, "CLM %d", NINT(position));
} }
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
asynStatus MD90Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards) asynStatus MD90Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
{ {
asynStatus status; asynStatus status;
// static const char *functionName = "MD90Axis::home"; static const char *functionName = "MD90Axis::home";
status = sendAccelAndVelocity(acceleration, maxVelocity); status = sendAccelAndVelocity(acceleration, maxVelocity);
sprintf(pC_->outString_, "HOM"); sprintf(pC_->outString_, "HOM");
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
@@ -214,16 +254,22 @@ asynStatus MD90Axis::moveVelocity(double minVelocity, double maxVelocity, double
sprintf(pC_->outString_, "ESB"); sprintf(pC_->outString_, "ESB");
} }
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
asynStatus MD90Axis::stop(double acceleration ) asynStatus MD90Axis::stop(double acceleration )
{ {
asynStatus status; asynStatus status;
//static const char *functionName = "MD90Axis::stop"; static const char *functionName = "MD90Axis::stop";
sprintf(pC_->outString_, "STP"); sprintf(pC_->outString_, "STP");
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
@@ -233,7 +279,7 @@ asynStatus MD90Axis::stop(double acceleration )
asynStatus MD90Axis::setClosedLoop(bool closedLoop) asynStatus MD90Axis::setClosedLoop(bool closedLoop)
{ {
asynStatus status; asynStatus status;
//static const char *functionName = "MD90Axis::setClosedLoop"; static const char *functionName = "MD90Axis::setClosedLoop";
if (closedLoop == 1) { if (closedLoop == 1) {
sprintf(pC_->outString_, "EPM"); sprintf(pC_->outString_, "EPM");
@@ -241,6 +287,9 @@ asynStatus MD90Axis::setClosedLoop(bool closedLoop)
sprintf(pC_->outString_, "DPM"); sprintf(pC_->outString_, "DPM");
} }
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
@@ -251,23 +300,29 @@ asynStatus MD90Axis::setClosedLoop(bool closedLoop)
asynStatus MD90Axis::setIGain(double iGain) asynStatus MD90Axis::setIGain(double iGain)
{ {
asynStatus status; asynStatus status;
//static const char *functionName = "MD90Axis::setIGain"; static const char *functionName = "MD90Axis::setIGain";
iGain = iGain * 1000; iGain = iGain * 1000;
if (iGain < 1) iGain = 1.0; if (iGain < 1) iGain = 1.0;
if (iGain > 1000) iGain = 1000.0; if (iGain > 1000) iGain = 1000.0;
sprintf(pC_->outString_, "SGN %d", NINT(iGain)); sprintf(pC_->outString_, "SGN %d", NINT(iGain));
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
asynStatus MD90Axis::doMoveToHome() asynStatus MD90Axis::doMoveToHome()
{ {
asynStatus status; asynStatus status;
//static const char *functionName = "MD90Axis::doMoveToHome"; static const char *functionName = "MD90Axis::doMoveToHome";
sprintf(pC_->outString_, "CLM 0"); sprintf(pC_->outString_, "CLM 0");
status = pC_->writeReadController(); status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status; return status;
} }
@@ -298,7 +353,7 @@ asynStatus MD90Axis::poll(bool *moving)
comStatus = pC_->writeReadController(); comStatus = pC_->writeReadController();
if (comStatus) goto skip; if (comStatus) goto skip;
// The response string is of the form "0: Power supply enabled state: 1" // The response string is of the form "0: Power supply enabled state: 1"
sscanf (pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue); sscanf(pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
driveOn = (replyValue == '1') ? 1:0; driveOn = (replyValue == '1') ? 1:0;
setIntegerParam(pC_->motorStatusPowerOn_, driveOn); setIntegerParam(pC_->motorStatusPowerOn_, driveOn);
@@ -307,7 +362,7 @@ asynStatus MD90Axis::poll(bool *moving)
comStatus = pC_->writeReadController(); comStatus = pC_->writeReadController();
if (comStatus) goto skip; if (comStatus) goto skip;
// The response string is of the form "0: Home status: 1" // The response string is of the form "0: Home status: 1"
sscanf (pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue); sscanf(pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
homed = (replyValue == '1') ? 1:0; homed = (replyValue == '1') ? 1:0;
setIntegerParam(pC_->motorStatusHomed_, homed); setIntegerParam(pC_->motorStatusHomed_, homed);
@@ -316,7 +371,7 @@ asynStatus MD90Axis::poll(bool *moving)
comStatus = pC_->writeReadController(); comStatus = pC_->writeReadController();
if (comStatus) goto skip; if (comStatus) goto skip;
// The response string is of the form "0: Current status value: 0" // The response string is of the form "0: Current status value: 0"
sscanf (pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue); sscanf(pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
done = (replyValue == '2') ? 0:1; done = (replyValue == '2') ? 0:1;
setIntegerParam(pC_->motorStatusDone_, done); setIntegerParam(pC_->motorStatusDone_, done);
*moving = done ? false:true; *moving = done ? false:true;
@@ -367,7 +422,7 @@ asynStatus MD90Axis::poll(bool *moving)
comStatus = pC_->writeReadController(); comStatus = pC_->writeReadController();
if (comStatus) goto skip; if (comStatus) goto skip;
// The response string is of the form "0: Current position in encoder counts: 1000" // The response string is of the form "0: Current position in encoder counts: 1000"
sscanf (pC_->inString_, "%d: %[^:]: %lf", &replyStatus, replyString, &position); sscanf(pC_->inString_, "%d: %[^:]: %lf", &replyStatus, replyString, &position);
setDoubleParam(pC_->motorPosition_, position); setDoubleParam(pC_->motorPosition_, position);
setIntegerParam(pC_->motorStatusAtHome_, (position == 0) ? 1:0); // home limit switch setIntegerParam(pC_->motorStatusAtHome_, (position == 0) ? 1:0); // home limit switch
setIntegerParam(pC_->motorStatusHome_, (position == 0) ? 1:0); // at home position setIntegerParam(pC_->motorStatusHome_, (position == 0) ? 1:0); // at home position
@@ -377,7 +432,7 @@ asynStatus MD90Axis::poll(bool *moving)
comStatus = pC_->writeReadController(); comStatus = pC_->writeReadController();
if (comStatus) goto skip; if (comStatus) goto skip;
// The response string is of the form "0: Gain: 1000" // The response string is of the form "0: Gain: 1000"
sscanf (pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue); sscanf(pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
setDoubleParam(pC_->motorIGain_, replyValue); setDoubleParam(pC_->motorIGain_, replyValue);
// set some default params // set some default params

View File

@@ -34,6 +34,7 @@ private:
MD90Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs. MD90Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
* Abbreviated because it is used very frequently */ * Abbreviated because it is used very frequently */
asynStatus sendAccelAndVelocity(double accel, double velocity); asynStatus sendAccelAndVelocity(double accel, double velocity);
asynStatus parseReply(const char *functionName, const char *reply);
friend class MD90Controller; friend class MD90Controller;
}; };

View File

@@ -0,0 +1,33 @@
file "$(MOTOR)/db/basic_asyn_motor.db"
{
pattern
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, VMAX, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
{DSM:, 0, "m$(N)", "asynMotor", MD900, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 1, "m$(N)", "asynMotor", MD901, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 2, "m$(N)", "asynMotor", MD902, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 3, "m$(N)", "asynMotor", MD903, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 4, "m$(N)", "asynMotor", MD904, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 5, "m$(N)", "asynMotor", MD905, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 6, "m$(N)", "asynMotor", MD906, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
{DSM:, 7, "m$(N)", "asynMotor", MD907, 0, "MD-90", mm, Pos, 0.5, 0.025, 0.625, 0, 0, 0.03, 0, .00001, 2, 20, -20, ""}
}
# P IOC prefix
# N Port number
# M Record name pattern
# DTYP Datatype
# PORT Port
# ADDR Address
# DESC Description
# EGU Engineering units
# DIR Direction
# VELO Velocity (EGU / s) (note: jog velocity set separately by JVEL)
# VBAS Minimum velocity (EGU / s)
# VMAX Maximum velocity (EGU / s) (note: not getting set here with basic_asyn_motor.db)
# ACCL Acceleration (time in seconds until VELO)
# BDST Backlash distance
# MRES Motor step size (EGU)
# PREC Display precision number of decimal places
# DHLM Dial high travel limit (EGU)
# DLLM Dial low travel limit (EGU)
# INIT Initialization string (seems to be unused/broken)

View File

@@ -0,0 +1,178 @@
#errlogInit(5000)
< envPaths
# Tell EPICS all about the record types, device-support modules, drivers, etc.
dbLoadDatabase("../../dbd/dsm.dbd")
dsm_registerRecordDeviceDriver(pdbbase)
# Unfortunately, iocsh doesn't support looping...
# Local serial port
drvAsynSerialPortConfigure("serial0", "/dev/ttyUSB0", 0, 0, 0)
drvAsynSerialPortConfigure("serial1", "/dev/ttyUSB1", 0, 0, 0)
drvAsynSerialPortConfigure("serial2", "/dev/ttyUSB2", 0, 0, 0)
drvAsynSerialPortConfigure("serial3", "/dev/ttyUSB3", 0, 0, 0)
drvAsynSerialPortConfigure("serial4", "/dev/ttyUSB4", 0, 0, 0)
drvAsynSerialPortConfigure("serial5", "/dev/ttyUSB5", 0, 0, 0)
drvAsynSerialPortConfigure("serial6", "/dev/ttyUSB6", 0, 0, 0)
drvAsynSerialPortConfigure("serial7", "/dev/ttyUSB7", 0, 0, 0)
asynSetOption("serial0", 0, "baud", "115200")
asynSetOption("serial1", 0, "baud", "115200")
asynSetOption("serial2", 0, "baud", "115200")
asynSetOption("serial3", 0, "baud", "115200")
asynSetOption("serial4", 0, "baud", "115200")
asynSetOption("serial5", 0, "baud", "115200")
asynSetOption("serial6", 0, "baud", "115200")
asynSetOption("serial7", 0, "baud", "115200")
asynSetOption("serial0", 0, "bits", "8")
asynSetOption("serial1", 0, "bits", "8")
asynSetOption("serial2", 0, "bits", "8")
asynSetOption("serial3", 0, "bits", "8")
asynSetOption("serial4", 0, "bits", "8")
asynSetOption("serial5", 0, "bits", "8")
asynSetOption("serial6", 0, "bits", "8")
asynSetOption("serial7", 0, "bits", "8")
asynSetOption("serial0", 0, "parity", "none")
asynSetOption("serial1", 0, "parity", "none")
asynSetOption("serial2", 0, "parity", "none")
asynSetOption("serial3", 0, "parity", "none")
asynSetOption("serial4", 0, "parity", "none")
asynSetOption("serial5", 0, "parity", "none")
asynSetOption("serial6", 0, "parity", "none")
asynSetOption("serial7", 0, "parity", "none")
asynSetOption("serial0", 0, "stop", "1")
asynSetOption("serial1", 0, "stop", "1")
asynSetOption("serial2", 0, "stop", "1")
asynSetOption("serial3", 0, "stop", "1")
asynSetOption("serial4", 0, "stop", "1")
asynSetOption("serial5", 0, "stop", "1")
asynSetOption("serial6", 0, "stop", "1")
asynSetOption("serial7", 0, "stop", "1")
asynOctetSetInputEos("serial0", 0, "\r")
asynOctetSetInputEos("serial1", 0, "\r")
asynOctetSetInputEos("serial2", 0, "\r")
asynOctetSetInputEos("serial3", 0, "\r")
asynOctetSetInputEos("serial4", 0, "\r")
asynOctetSetInputEos("serial5", 0, "\r")
asynOctetSetInputEos("serial6", 0, "\r")
asynOctetSetInputEos("serial7", 0, "\r")
asynOctetSetOutputEos("serial0", 0, "\r")
asynOctetSetOutputEos("serial1", 0, "\r")
asynOctetSetOutputEos("serial2", 0, "\r")
asynOctetSetOutputEos("serial3", 0, "\r")
asynOctetSetOutputEos("serial4", 0, "\r")
asynOctetSetOutputEos("serial5", 0, "\r")
asynOctetSetOutputEos("serial6", 0, "\r")
asynOctetSetOutputEos("serial7", 0, "\r")
asynSetTraceIOMask("serial0", 0, 2)
asynSetTraceIOMask("serial1", 0, 2)
asynSetTraceIOMask("serial2", 0, 2)
asynSetTraceIOMask("serial3", 0, 2)
asynSetTraceIOMask("serial4", 0, 2)
asynSetTraceIOMask("serial5", 0, 2)
asynSetTraceIOMask("serial6", 0, 2)
asynSetTraceIOMask("serial7", 0, 2)
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial0", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial1", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial2", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial3", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial4", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial5", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial6", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial7", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
MD90CreateController("MD900", "serial0", 1, 100, 5000)
MD90CreateController("MD901", "serial1", 1, 100, 5000)
MD90CreateController("MD902", "serial2", 1, 100, 5000)
MD90CreateController("MD903", "serial3", 1, 100, 5000)
MD90CreateController("MD904", "serial4", 1, 100, 5000)
MD90CreateController("MD905", "serial5", 1, 100, 5000)
MD90CreateController("MD906", "serial6", 1, 100, 5000)
MD90CreateController("MD907", "serial7", 1, 100, 5000)
### Motors
dbLoadTemplate "motor.substitutions.md90.multi"
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial0,PORT=serial0,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial2,PORT=serial2,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial3,PORT=serial3,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial4,PORT=serial4,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial5,PORT=serial5,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial6,PORT=serial6,ADDR=0,OMAX=80,IMAX=80")
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial7,PORT=serial7,ADDR=0,OMAX=80,IMAX=80")
iocInit
# This IOC does not use save/restore, so set values of some PVs
dbpf("DSM:m0.RTRY", "0")
dbpf("DSM:m0.TWV", "0.1")
dbpf("DSM:m0.VMAX", "0.625")
dbpf("DSM:m1.RTRY", "0")
dbpf("DSM:m1.TWV", "0.1")
dbpf("DSM:m1.VMAX", "0.625")
dbpf("DSM:m2.RTRY", "0")
dbpf("DSM:m2.TWV", "0.1")
dbpf("DSM:m2.VMAX", "0.625")
dbpf("DSM:m3.RTRY", "0")
dbpf("DSM:m3.TWV", "0.1")
dbpf("DSM:m3.VMAX", "0.625")
dbpf("DSM:m4.RTRY", "0")
dbpf("DSM:m4.TWV", "0.1")
dbpf("DSM:m4.VMAX", "0.625")
dbpf("DSM:m5.RTRY", "0")
dbpf("DSM:m5.TWV", "0.1")
dbpf("DSM:m5.VMAX", "0.625")
dbpf("DSM:m6.RTRY", "0")
dbpf("DSM:m6.TWV", "0.1")
dbpf("DSM:m6.VMAX", "0.625")
dbpf("DSM:m7.RTRY", "0")
dbpf("DSM:m7.TWV", "0.1")
dbpf("DSM:m7.VMAX", "0.625")