diff --git a/README.md b/README.md index 5fe6bc0..f2ca560 100644 --- a/README.md +++ b/README.md @@ -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 configuration is needed. -motorDSM can also be built outside of motor by copying it's -``EXAMPLE_RELEASE.local`` file to ``RELEASE.local`` and defining the paths to -``EPICS_BASE``, ``MOTOR``, and itself. +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. -motorDSM contains an example IOC that is built if ``CONFIG_SITE.local`` sets -``BUILD_IOCS = YES``. The example IOC can be built outside of driver module. +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. + +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 $ 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`` to ``CONFIG_SITE.local`` and set: BUILD_IOCS = YES -In ``motorDSM/configure``, copy ``EXAMPLE_RELEASE.local`` to ``RELEASE.local`` -and set paths for ``EPICS_BASE``, ``MOTOR``, and ``MOTOR_DSM``. +In ``motorDSM/iocs/dsmIOC/configure``, copy ``EXAMPLE_RELEASE.local`` to +``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 $ make distclean diff --git a/dsmApp/iocsh/DSM_MD90.iocsh b/dsmApp/iocsh/DSM_MD90.iocsh index 1891ce1..6c80563 100644 --- a/dsmApp/iocsh/DSM_MD90.iocsh +++ b/dsmApp/iocsh/DSM_MD90.iocsh @@ -18,8 +18,8 @@ #- ################################################### # 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") 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))) diff --git a/dsmApp/src/MD90Driver.cpp b/dsmApp/src/MD90Driver.cpp index afdeeb6..2405fe9 100644 --- a/dsmApp/src/MD90Driver.cpp +++ b/dsmApp/src/MD90Driver.cpp @@ -140,6 +140,37 @@ void MD90Axis::report(FILE *fp, int 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 * \param[in] acceleration The accelerations to ramp up to max velocity * \param[in] velocity Motor velocity in steps / sec @@ -148,7 +179,7 @@ asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity) { asynStatus status; int freq; - // static const char *functionName = "MD90::sendAccelAndVelocity"; + static const char *functionName = "MD90::sendAccelAndVelocity"; // Send the velocity // Velocity provided in steps/sec @@ -157,6 +188,9 @@ asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity) freq = NINT(fabs(velocity / 500.)); sprintf(pC_->outString_, "SSF %d", freq); status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } 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 status; - // static const char *functionName = "MD90Axis::move"; + static const char *functionName = "MD90Axis::move"; 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)); } status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } asynStatus MD90Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards) { asynStatus status; - // static const char *functionName = "MD90Axis::home"; + static const char *functionName = "MD90Axis::home"; status = sendAccelAndVelocity(acceleration, maxVelocity); sprintf(pC_->outString_, "HOM"); status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } @@ -214,16 +254,22 @@ asynStatus MD90Axis::moveVelocity(double minVelocity, double maxVelocity, double sprintf(pC_->outString_, "ESB"); } status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } asynStatus MD90Axis::stop(double acceleration ) { asynStatus status; - //static const char *functionName = "MD90Axis::stop"; + static const char *functionName = "MD90Axis::stop"; sprintf(pC_->outString_, "STP"); status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } @@ -233,7 +279,7 @@ asynStatus MD90Axis::stop(double acceleration ) asynStatus MD90Axis::setClosedLoop(bool closedLoop) { asynStatus status; - //static const char *functionName = "MD90Axis::setClosedLoop"; + static const char *functionName = "MD90Axis::setClosedLoop"; if (closedLoop == 1) { sprintf(pC_->outString_, "EPM"); @@ -241,6 +287,9 @@ asynStatus MD90Axis::setClosedLoop(bool closedLoop) sprintf(pC_->outString_, "DPM"); } status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } @@ -251,23 +300,29 @@ asynStatus MD90Axis::setClosedLoop(bool closedLoop) asynStatus MD90Axis::setIGain(double iGain) { asynStatus status; - //static const char *functionName = "MD90Axis::setIGain"; + static const char *functionName = "MD90Axis::setIGain"; iGain = iGain * 1000; if (iGain < 1) iGain = 1.0; if (iGain > 1000) iGain = 1000.0; sprintf(pC_->outString_, "SGN %d", NINT(iGain)); status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } asynStatus MD90Axis::doMoveToHome() { asynStatus status; - //static const char *functionName = "MD90Axis::doMoveToHome"; + static const char *functionName = "MD90Axis::doMoveToHome"; sprintf(pC_->outString_, "CLM 0"); status = pC_->writeReadController(); + if (!status) { + status = parseReply(functionName, pC_->inString_); + } return status; } @@ -298,7 +353,7 @@ asynStatus MD90Axis::poll(bool *moving) comStatus = pC_->writeReadController(); if (comStatus) goto skip; // 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; setIntegerParam(pC_->motorStatusPowerOn_, driveOn); @@ -307,7 +362,7 @@ asynStatus MD90Axis::poll(bool *moving) comStatus = pC_->writeReadController(); if (comStatus) goto skip; // 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; setIntegerParam(pC_->motorStatusHomed_, homed); @@ -316,7 +371,7 @@ asynStatus MD90Axis::poll(bool *moving) comStatus = pC_->writeReadController(); if (comStatus) goto skip; // 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; setIntegerParam(pC_->motorStatusDone_, done); *moving = done ? false:true; @@ -367,7 +422,7 @@ asynStatus MD90Axis::poll(bool *moving) comStatus = pC_->writeReadController(); if (comStatus) goto skip; // 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); setIntegerParam(pC_->motorStatusAtHome_, (position == 0) ? 1:0); // home limit switch setIntegerParam(pC_->motorStatusHome_, (position == 0) ? 1:0); // at home position @@ -377,7 +432,7 @@ asynStatus MD90Axis::poll(bool *moving) comStatus = pC_->writeReadController(); if (comStatus) goto skip; // 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); // set some default params diff --git a/dsmApp/src/MD90Driver.h b/dsmApp/src/MD90Driver.h index 45715d1..0b1e056 100644 --- a/dsmApp/src/MD90Driver.h +++ b/dsmApp/src/MD90Driver.h @@ -34,6 +34,7 @@ private: MD90Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs. * Abbreviated because it is used very frequently */ asynStatus sendAccelAndVelocity(double accel, double velocity); + asynStatus parseReply(const char *functionName, const char *reply); friend class MD90Controller; }; diff --git a/iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90.multi b/iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90.multi new file mode 100644 index 0000000..d8d483d --- /dev/null +++ b/iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90.multi @@ -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) diff --git a/iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90.multi b/iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90.multi new file mode 100644 index 0000000..c2550f6 --- /dev/null +++ b/iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90.multi @@ -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")