77 Commits

Author SHA1 Message Date
707850e879 Merge branch 'dev' 2024-06-28 16:10:22 -05:00
8ec61fb3dc Removed hard line wrapping in README to fix markdown rendering issues. 2024-06-28 16:09:50 -05:00
90b0fa8836 Cleaned up IOC startup file. 2024-06-28 16:06:46 -05:00
40cfb47f05 Made /dev/ttyUSB0 default serial port again. 2024-06-28 16:05:17 -05:00
1a4794a9b2 Clarified install instructions in README. 2024-06-28 16:04:24 -05:00
a3d6a24a01 Merge branch 'dev' 2024-06-25 15:22:01 -05:00
c8dbd0916d Merge branch 'status' into dev 2024-06-25 15:21:46 -05:00
e9ca810318 Added limit switch triggering back in for end of travel error. 2024-06-25 15:17:10 -05:00
bf7b557dd7 Added reading of persistent move state to polling. 2024-06-25 14:54:57 -05:00
0600cba84d Added reading step frequency/approx. velocity to polling. 2024-06-25 14:26:02 -05:00
51fceaf7d7 Added error printouts in IOC for motor polling codes. 2024-06-25 14:01:21 -05:00
66ef37cb10 Merge branch 'dev' 2024-06-25 12:34:09 -05:00
200b68857d Updated README about running the IOC for one or multi controllers. 2024-06-25 12:33:34 -05:00
d0532c2552 Added IOC files for running with 8 MD90 controllers. 2024-06-25 12:26:24 -05:00
45c8ff064e Updated default IOC baud rate and idle poll period. 2024-06-25 11:56:31 -05:00
4351ab56e3 Updated README for setting up IOC build config file. 2024-06-25 11:49:42 -05:00
a90eea829a Merge branch 'status' into dev 2024-06-25 11:32:22 -05:00
7b9f2870ca Added call to parseReply in remaining command methods. 2024-06-25 11:09:08 -05:00
f73608c596 Added method to parse and print out controller return strings. 2024-06-25 11:01:55 -05:00
19731d2f37 Merge branch 'dev' 2024-06-24 14:23:41 -05:00
a4012dda64 Updated README with dependencies and build instructions. 2024-06-24 14:18:45 -05:00
c812afbe4e Merge branch 'dev' 2024-06-21 16:55:30 -05:00
7551465733 Set hasEncoder and gainSupport to true. Can now set motor gain. 2024-06-21 16:36:48 -05:00
bdec17808a Added home position status to poll. 2024-06-21 16:31:17 -05:00
29a78e1023 Moved line back to fix status update problem. 2024-06-21 16:07:54 -05:00
c930a77811 Added gain checking to the poll method. 2024-06-21 15:37:33 -05:00
df98f6667a Changed iGain range from 1-100 to 1-1000. 2024-06-21 15:30:00 -05:00
37d22e58dd Removed step frequency limits. 2024-06-21 14:56:48 -05:00
8c053dfa62 Reordered status polling commands. 2024-06-21 14:53:50 -05:00
4ab244925d Updated serial port to USB adapter. 2024-06-21 14:18:49 -05:00
5d343b33d1 Merge branch 'dev' 2024-06-06 14:28:04 -05:00
0d84bb4a29 Changed to max 1 axis. 2024-06-06 14:27:15 -05:00
448e26ac23 Merge branch 'commands' into dev 2024-06-06 14:26:33 -05:00
19467e5b5b Updated method to set velocity and removed acceleration. 2024-06-06 14:20:47 -05:00
402584345f Added doMoveToHome method. 2024-06-05 16:14:40 -05:00
c5eebd9597 Added setIGain method. 2024-06-05 16:04:30 -05:00
341bbb5980 Changed motor status from atHome to Homed when GHS returns 1. 2024-06-05 15:38:57 -05:00
71ae063b23 Updated to use the setClosedLoop method to set persistent move. 2024-06-05 15:32:14 -05:00
b8b090a804 Removed setPosition method as not supported by md90. 2024-06-05 14:50:52 -05:00
273e545759 Added missing call to writeReadController to set max jog steps. 2024-06-05 14:39:35 -05:00
ba71c79a92 Updated moveVelocity command for md90. 2024-06-05 14:34:59 -05:00
996439589a Merge branch 'dev' 2024-05-24 16:18:07 -05:00
d412000373 Merge branch 'commands' into dev 2024-05-24 16:17:58 -05:00
9fa37e8cd0 Set max velocity in ioc launch script. 2024-05-24 16:14:26 -05:00
9a3d3d773d Updated subst with usable velocities and description comments. 2024-05-24 15:57:58 -05:00
6c841c9041 Fixed to disconnect real initConnection. 2024-05-24 15:47:01 -05:00
9403c24df0 Changed substitutions file to use millimeters instead of micrometers. 2024-05-24 14:56:20 -05:00
7b3675fbdf Updated internal units to encoder steps (10 nm). 2024-05-24 14:31:22 -05:00
a1827ca152 Updated ioc to set motor deadband to minimum. 2024-05-24 14:15:16 -05:00
c2cbaf6bfd Updated ioc to send enable power supply command to md90. 2024-05-24 13:41:54 -05:00
1b366684d0 Changed some record field values to better match the md90. 2024-05-24 13:41:25 -05:00
8101fcae72 Updated home command for md90. 2024-05-24 09:46:58 -05:00
629c55bba4 Updated move command for md90. 2024-05-24 09:42:53 -05:00
b616133ace Merge branch 'polling' into dev 2024-05-24 08:46:38 -05:00
c1ffe8b805 Set problem and limit flags when md90 error status returned. 2024-05-24 08:44:02 -05:00
c11e11659b Merge branch 'dev' 2024-05-23 17:28:57 -05:00
b56a1f9a35 Merge branch 'polling' into dev 2024-05-23 17:28:45 -05:00
4837e8f597 Added switch case table template for possible status codes. 2024-05-23 17:04:37 -05:00
0c32dd28eb Updated to read md90 power state. 2024-05-23 16:02:03 -05:00
0841ff3e15 Fixed incorrectly reading ints as doubles. 2024-05-23 15:54:46 -05:00
1205814767 Updated to read md90 home status. 2024-05-23 15:47:39 -05:00
67eee854c0 Changed engineering units to encoder counts for get position. 2024-05-23 14:19:43 -05:00
a4d5388531 Updated to read md90 moving status. 2024-05-23 14:12:04 -05:00
07f07d16ad Updated to read md90 position. 2024-05-23 14:05:25 -05:00
a43acb8537 Updated motor stop command string. 2024-05-22 16:55:58 -05:00
d24486dfb4 Merge branch 'rename' 2024-05-22 11:58:26 -05:00
a2d7256948 One more ACS -> DSM substitution in hidden directory. 2024-05-22 11:57:54 -05:00
4615467616 Merge branch 'rename' 2024-05-22 11:50:46 -05:00
417802a9b4 Substituted string "mcb4b" with "md90".
The following case replacements were applied (in order):
	mcb4b -> md90
	MCB4B -> MD90
	mcb-4b -> md-90
	MCB-4B -> MD-90
	MCB -> MD-90
2024-05-22 11:38:43 -05:00
a92fda6560 Substituted string "acs" with "dsm".
The following case replacements were applied (in order):
	AcsRegister -> dsmRegister
	Acs_LIBS -> dsm_LIBS
	' Acs' -> ' dsm'
	acs -> dsm
	Acs -> Dsm
	ACS -> DSM
2024-05-22 11:01:27 -05:00
7d7774072c Updated readme with new names and paths. 2024-05-20 15:05:13 -05:00
b03cda55ac Renamed "*acs*" files to "*dsm*". 2024-05-20 14:51:50 -05:00
eec0a1d8f0 Renamed *mcb4b* files to *md90*. 2024-05-20 14:41:09 -05:00
2df164b697 Merge branch 'ioc' 2024-05-20 14:24:11 -05:00
c9db06b418 Updated example IOC to use DSM prefix and zero-based indexing. 2024-05-20 14:23:12 -05:00
fd6b276fc9 Updated example IOC for one axis and to use local serial port. 2024-05-20 14:14:36 -05:00
4a9b6a91e0 Ignored additional unneeded files. 2024-05-20 14:05:54 -05:00
47 changed files with 1115 additions and 611 deletions

View File

@@ -24,7 +24,7 @@ def sanity_check(filename):
print("{}End of {}{}".format(ANSI_BLUE, filename, ANSI_RESET))
# Add the path to the driver module to the RELEASE.local file, since it is needed by the example IOC
update_release_local('MOTOR_ACS', os.getenv('TRAVIS_BUILD_DIR'))
update_release_local('MOTOR_DSM', os.getenv('TRAVIS_BUILD_DIR'))
# Copy the travis RELEASE.local to the configure dir
filename = "configure/RELEASE.local"

2
.gitignore vendored
View File

@@ -1,6 +1,7 @@
*~
O.*
*.swp
*.bak
*BAK.adl
bin/
db/
@@ -16,3 +17,4 @@ auto_settings.sav*
auto_positions.sav*
.ccfxprepdir/
*.local
*_history

115
README.md
View File

@@ -1,11 +1,112 @@
# motorAcs
EPICS motor drivers for the following [Advanced Control Systems Corporation](http://www.acsmotion.com) controllers: MCB-4B
motorDSM
==========
[![Build Status](https://github.com/epics-motor/motorAcs/actions/workflows/ci-scripts-build.yml/badge.svg)](https://github.com/epics-motor/motorAcs/actions/workflows/ci-scripts-build.yml)
<!--[![Build Status](https://travis-ci.org/epics-motor/motorAcs.png)](https://travis-ci.org/epics-motor/motorAcs)-->
EPICS motor drivers for the following [Dynamic Structures and Materials](https://www.dynamic-structures.com/) motor controllers: MD-90
motorAcs is a submodule of [motor](https://github.com/epics-modules/motor). When motorAcs is built in the ``motor/modules`` directory, no manual configuration is needed.
[![Build Status](https://github.com/Binary-Coalescence/motorDSM/actions/workflows/ci-scripts-build.yml/badge.svg)](https://github.com/Binary-Coalescence/motorDSM/actions/workflows/ci-scripts-build.yml)
motorAcs can also be built outside of motor by copying it's ``EXAMPLE_RELEASE.local`` file to ``RELEASE.local`` and defining the paths to ``MOTOR`` and itself.
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.
motorAcs 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 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 ``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. You may need to change the path(s) for the serial port(s) in ``st.cmd.md90`` or ``st.cmd.md90.multi`` if the MD-90 is not attached at ``/dev/ttyUSB0``.
------------------------
To set up a full EPICS stack for development and testing, install and configure all of the following dependencies:
------------------------
epics-base
------------------------
Install make, gcc, and perl packages if not already installed, then clone and build epics-base:
$ export SUPPORT=/path/to/install/directory
$ cd $SUPPORT
$ git clone git@github.com:epics-base/epics-base.git
$ cd epics-base
$ make distclean
$ make
------------------------
asyn
------------------------
$ cd $SUPPORT
$ git clone git@github.com:epics-modules/asyn.git
You may need to install (on Arch Linux) ``rpcsvc-proto`` package to get ``rpcgen`` binary needed to make asyn.
In ``asyn/configure``, create the file ``RELEASE.local`` with contents:
SUPPORT=/path/to/install/directory
EPICS_BASE=/path/to/epics-base
In ``asyn/configure``, create ``CONFIG_SITE.local`` file with the line:
TIRPC=YES
if appropriate header files are in ``/usr/include/tirpc/rpc`` instead of ``/usr/include/rpc``.
$ cd $SUPPORT/asyn
$ make clean
$ make
------------------------
seq
------------------------
$ cd $SUPPORT
$ git clone git@github.com:ISISComputingGroup/EPICS-seq.git seq
Install the ``re2c`` package (Arch) if needed.
Create ``seq/configure/RELEASE.local`` and set path for ``EPICS_BASE``. (Note this package seems to forget to git-ignore the .local file.)
Edit ``seq/configure/RELEASE`` to add the missing '-' before the ``include`` for ``ISIS_CONFIG`` on the next to last line. This seems to be a typo.
$ cd $SUPPORT/seq
$ make clean
$ make
------------------------
motor
------------------------
$ cd $SUPPORT
$ git clone git@github.com:epics-modules/motor.git
Create ``motor/configure/RELEASE.local`` and set ``SUPPORT``, ``ASYN``, ``SNCSEQ``, and ``EPICS_BASE`` to the appropriate paths.
$ cd $SUPPORT/motor
$ make distclean
$ make
------------------------
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 uncomment to set:
BUILD_IOCS = YES
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 $SUPPORT/motorDSM
$ make distclean
$ make

View File

@@ -1,336 +0,0 @@
/*
FILENAME... MCB4BDriver.cpp
USAGE... Motor driver support for the ACS MCB-4B controller.
Mark Rivers
March 1, 2012
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <iocsh.h>
#include <epicsThread.h>
#include <asynOctetSyncIO.h>
#include <epicsExport.h>
#include "MCB4BDriver.h"
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
/** Creates a new MCB4BController object.
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] MCB4BPortName The name of the drvAsynSerialPort that was created previously to connect to the MCB4B controller
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time between polls when any axis is moving
* \param[in] idlePollPeriod The time between polls when no axis is moving
*/
MCB4BController::MCB4BController(const char *portName, const char *MCB4BPortName, int numAxes,
double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, numAxes, NUM_MCB4B_PARAMS,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
int axis;
asynStatus status;
MCB4BAxis *pAxis;
static const char *functionName = "MCB4BController::MCB4BController";
/* Connect to MCB4B controller */
status = pasynOctetSyncIO->connect(MCB4BPortName, 0, &pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: cannot connect to MCB-4B controller\n",
functionName);
}
for (axis=0; axis<numAxes; axis++) {
pAxis = new MCB4BAxis(this, axis);
}
startPoller(movingPollPeriod, idlePollPeriod, 2);
}
/** Creates a new MCB4BController object.
* Configuration command, called directly or from iocsh
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] MCB4BPortName The name of the drvAsynIPPPort that was created previously to connect to the MCB4B controller
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time in ms between polls when any axis is moving
* \param[in] idlePollPeriod The time in ms between polls when no axis is moving
*/
extern "C" int MCB4BCreateController(const char *portName, const char *MCB4BPortName, int numAxes,
int movingPollPeriod, int idlePollPeriod)
{
MCB4BController *pMCB4BController
= new MCB4BController(portName, MCB4BPortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
pMCB4BController = NULL;
return(asynSuccess);
}
/** Reports on status of the driver
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* If details > 0 then information is printed about each axis.
* After printing controller-specific information it calls asynMotorController::report()
*/
void MCB4BController::report(FILE *fp, int level)
{
fprintf(fp, "MCB-4B motor driver %s, numAxes=%d, moving poll period=%f, idle poll period=%f\n",
this->portName, numAxes_, movingPollPeriod_, idlePollPeriod_);
// Call the base class method
asynMotorController::report(fp, level);
}
/** Returns a pointer to an MCB4BAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
MCB4BAxis* MCB4BController::getAxis(asynUser *pasynUser)
{
return static_cast<MCB4BAxis*>(asynMotorController::getAxis(pasynUser));
}
/** Returns a pointer to an MCB4BAxis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
MCB4BAxis* MCB4BController::getAxis(int axisNo)
{
return static_cast<MCB4BAxis*>(asynMotorController::getAxis(axisNo));
}
// These are the MCB4BAxis methods
/** Creates a new MCB4BAxis object.
* \param[in] pC Pointer to the MCB4BController to which this axis belongs.
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
*
* Initializes register numbers, etc.
*/
MCB4BAxis::MCB4BAxis(MCB4BController *pC, int axisNo)
: asynMotorAxis(pC, axisNo),
pC_(pC)
{
}
/** Reports on status of the axis
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* After printing device-specific information calls asynMotorAxis::report()
*/
void MCB4BAxis::report(FILE *fp, int level)
{
if (level > 0) {
fprintf(fp, " axis %d\n",
axisNo_);
}
// Call the base class method
asynMotorAxis::report(fp, level);
}
asynStatus MCB4BAxis::sendAccelAndVelocity(double acceleration, double velocity)
{
asynStatus status;
int ival;
// static const char *functionName = "MCB4B::sendAccelAndVelocity";
// Send the velocity
ival = NINT(fabs(115200./velocity));
if (ival < 2) ival=2;
if (ival > 255) ival = 255;
sprintf(pC_->outString_, "#%02dV=%d", axisNo_, ival);
status = pC_->writeReadController();
// Send the acceleration
// acceleration is in steps/sec/sec
// MCB is programmed with Ramp Index (R) where:
// dval (steps/sec/sec) = 720,000/(256-R) */
// or R=256-(720,000/dval) */
ival = NINT(256-(720000./acceleration));
if (ival < 1) ival=1;
if (ival > 255) ival=255;
sprintf(pC_->outString_, "#%02dR=%d", axisNo_, ival);
status = pC_->writeReadController();
return status;
}
asynStatus MCB4BAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
// static const char *functionName = "MCB4BAxis::move";
status = sendAccelAndVelocity(acceleration, maxVelocity);
if (relative) {
sprintf(pC_->outString_, "#%02dI%+d", axisNo_, NINT(position));
} else {
sprintf(pC_->outString_, "#%02dG%+d", axisNo_, NINT(position));
}
status = pC_->writeReadController();
return status;
}
asynStatus MCB4BAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
{
asynStatus status;
// static const char *functionName = "MCB4BAxis::home";
status = sendAccelAndVelocity(acceleration, maxVelocity);
if (forwards) {
sprintf(pC_->outString_, "#%02dH+", axisNo_);
} else {
sprintf(pC_->outString_, "#%02dH-", axisNo_);
}
status = pC_->writeReadController();
return status;
}
asynStatus MCB4BAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
static const char *functionName = "MCB4BAxis::moveVelocity";
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
"%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
functionName, minVelocity, maxVelocity, acceleration);
status = sendAccelAndVelocity(acceleration, maxVelocity);
/* MCB-4B does not have jog command. Move 1 million steps */
if (maxVelocity > 0.) {
/* This is a positive move in MCB4B coordinates */
sprintf(pC_->outString_, "#%02dI+1000000", axisNo_);
} else {
/* This is a negative move in MCB4B coordinates */
sprintf(pC_->outString_, "#%02dI-1000000", axisNo_);
}
status = pC_->writeReadController();
return status;
}
asynStatus MCB4BAxis::stop(double acceleration )
{
asynStatus status;
//static const char *functionName = "MCB4BAxis::stop";
sprintf(pC_->outString_, "#%02dQ", axisNo_);
status = pC_->writeReadController();
return status;
}
asynStatus MCB4BAxis::setPosition(double position)
{
asynStatus status;
//static const char *functionName = "MCB4BAxis::setPosition";
sprintf(pC_->outString_, "#%02dP=%+d", axisNo_, NINT(position));
status = pC_->writeReadController();
return status;
}
asynStatus MCB4BAxis::setClosedLoop(bool closedLoop)
{
asynStatus status;
//static const char *functionName = "MCB4BAxis::setClosedLoop";
sprintf(pC_->outString_, "#%02dW=%d", axisNo_, closedLoop ? 1:0);
status = pC_->writeReadController();
return status;
}
/** Polls the axis.
* This function reads the motor position, the limit status, the home status, the moving status,
* and the drive power-on status.
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
* and then calls callParamCallbacks() at the end.
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false). */
asynStatus MCB4BAxis::poll(bool *moving)
{
int done;
int driveOn;
int limit;
double position;
asynStatus comStatus;
// Read the current motor position
sprintf(pC_->outString_, "#%02dP", axisNo_);
comStatus = pC_->writeReadController();
if (comStatus) goto skip;
// The response string is of the form "#01P=+1000"
position = atof(&pC_->inString_[5]);
setDoubleParam(pC_->motorPosition_, position);
// Read the moving status of this motor
sprintf(pC_->outString_, "#%02dX", axisNo_);
comStatus = pC_->writeReadController();
if (comStatus) goto skip;
// The response string is of the form "#01X=1"
done = (pC_->inString_[5] == '0') ? 1:0;
setIntegerParam(pC_->motorStatusDone_, done);
*moving = done ? false:true;
// Read the limit status
sprintf(pC_->outString_, "#%02dE", axisNo_);
comStatus = pC_->writeReadController();
if (comStatus) goto skip;
// The response string is of the form "#01E=1"
limit = (pC_->inString_[5] == '1') ? 1:0;
setIntegerParam(pC_->motorStatusHighLimit_, limit);
limit = (pC_->inString_[6] == '1') ? 1:0;
setIntegerParam(pC_->motorStatusLowLimit_, limit);
limit = (pC_->inString_[7] == '1') ? 1:0;
setIntegerParam(pC_->motorStatusAtHome_, limit);
// Read the drive power on status
sprintf(pC_->outString_, "#%02dW", axisNo_);
comStatus = pC_->writeReadController();
if (comStatus) goto skip;
driveOn = (pC_->inString_[5] == '1') ? 1:0;
setIntegerParam(pC_->motorStatusPowerOn_, driveOn);
setIntegerParam(pC_->motorStatusProblem_, 0);
skip:
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
callParamCallbacks();
return comStatus ? asynError : asynSuccess;
}
/** Code for iocsh registration */
static const iocshArg MCB4BCreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg MCB4BCreateControllerArg1 = {"MCB-4B port name", iocshArgString};
static const iocshArg MCB4BCreateControllerArg2 = {"Number of axes", iocshArgInt};
static const iocshArg MCB4BCreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
static const iocshArg MCB4BCreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
static const iocshArg * const MCB4BCreateControllerArgs[] = {&MCB4BCreateControllerArg0,
&MCB4BCreateControllerArg1,
&MCB4BCreateControllerArg2,
&MCB4BCreateControllerArg3,
&MCB4BCreateControllerArg4};
static const iocshFuncDef MCB4BCreateControllerDef = {"MCB4BCreateController", 5, MCB4BCreateControllerArgs};
static void MCB4BCreateContollerCallFunc(const iocshArgBuf *args)
{
MCB4BCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival);
}
static void MCB4BRegister(void)
{
iocshRegister(&MCB4BCreateControllerDef, MCB4BCreateContollerCallFunc);
}
extern "C" {
epicsExportRegistrar(MCB4BRegister);
}

View File

@@ -1,11 +0,0 @@
# Advanced Control Systems driver support.
# Model 1 (non-asyn) driver
device(motor,VME_IO,devMCB4B,"ACS MCB-4B")
driver(drvMCB4B)
registrar(AcsRegister)
# Model 3 driver
registrar(MCB4BRegister)

View File

@@ -1,4 +1,5 @@
EPICS_BASE=
MOTOR=
-include $(MOTOR)/modules/RELEASE.$(EPICS_HOST_ARCH).local
# path to motorAcs is needed to build the IOC inside motorAcs, but outside motor
MOTOR_ACS=
# path to motorDsm is needed to build the IOC inside motorDsm, but outside motor
MOTOR_DSM=

View File

@@ -2,6 +2,6 @@
# Use motor/module's generated release file when buidling inside motor
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
# Use motorAcs's RELEASE.local when building outside motor
# Use motorDsm's RELEASE.local when building outside motor
-include $(TOP)/configure/RELEASE.local

View File

@@ -1,4 +1,4 @@
# motorAcs Releases
# motorDsm Releases
## __R1-1-1 (2023-04-11)__
R1-1-1 is a release based on the master branch.
@@ -27,22 +27,22 @@ R1-1 is a release based on the master branch.
* None
#### Modifications to existing features
* Commit [1bd580a](https://github.com/epics-motor/motorAcs/commit/1bd580a87869fb140939978c0b06856917282da9): ``iocsh`` dir moved into ``acsApp`` dir; ``ACS_MCB4B.iocsh`` is now installed at build time
* Commit [1bd580a](https://github.com/epics-motor/motorDsm/commit/1bd580a87869fb140939978c0b06856917282da9): ``iocsh`` dir moved into ``dsmApp`` dir; ``DSM_MD90.iocsh`` is now installed at build time
#### Bug fixes
* Commit [5ab502c](https://github.com/epics-motor/motorAcs/commit/5ab502c53ac81885e2a511ade95f22d0a0db4f43): Include ``$(MOTOR)/modules/RELEASE.$(EPICS_HOST_ARCH).local`` instead of ``$(MOTOR)/configure/RELEASE``
* Pull request [#1](https://github.com/epics-motor/motorAcs/pull/1): Eliminated compiler warnings
* Commit [5ab502c](https://github.com/epics-motor/motorDsm/commit/5ab502c53ac81885e2a511ade95f22d0a0db4f43): Include ``$(MOTOR)/modules/RELEASE.$(EPICS_HOST_ARCH).local`` instead of ``$(MOTOR)/configure/RELEASE``
* Pull request [#1](https://github.com/epics-motor/motorDsm/pull/1): Eliminated compiler warnings
## __R1-0 (2019-04-18)__
R1-0 is a release based on the master branch.
### Changes since motor-6-11
motorAcs is now a standalone module, as well as a submodule of [motor](https://github.com/epics-modules/motor)
motorDsm is now a standalone module, as well as a submodule of [motor](https://github.com/epics-modules/motor)
#### New features
* motorAcs can be built outside of the motor directory
* motorAcs has a dedicated example IOC that can be built outside of motorAcs
* motorDsm can be built outside of the motor directory
* motorDsm has a dedicated example IOC that can be built outside of motorDsm
#### Modifications to existing features
* None

View File

@@ -1,4 +1,4 @@
# ### ACS_MCB4B.iocsh ###
# ### DSM_MD90.iocsh ###
#- ###################################################
#- PORT - Serial port for communications
@@ -17,9 +17,9 @@
#- Default: 100
#- ###################################################
# ACS MCB-4B serial connection settings
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=19200, BITS=8, STOP=1, PARITY=none")
# DSM MD-90 serial connection settings
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=115200, BITS=8, STOP=1, PARITY=none")
asynOctetSetInputEos( "$(PORT)", -1, "\r")
asynOctetSetOutputEos("$(PORT)", -1, "\r")
MCB4BCreateController("$(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

@@ -1,6 +1,6 @@
TOP = ../..
include $(TOP)/configure/CONFIG
IOCSH += ACS_MCB4B.iocsh
IOCSH += DSM_MD90.iocsh
include $(TOP)/configure/RULES

502
dsmApp/src/MD90Driver.cpp Normal file
View File

@@ -0,0 +1,502 @@
/*
FILENAME... MD90Driver.cpp
USAGE... Motor driver support for the DSM MD-90 controller.
Mark Rivers
March 1, 2012
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <iocsh.h>
#include <epicsThread.h>
#include <asynOctetSyncIO.h>
#include <epicsExport.h>
#include "MD90Driver.h"
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
/** Creates a new MD90Controller object.
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] MD90PortName The name of the drvAsynSerialPort that was created previously to connect to the MD90 controller
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time between polls when any axis is moving
* \param[in] idlePollPeriod The time between polls when no axis is moving
*/
MD90Controller::MD90Controller(const char *portName, const char *MD90PortName, int numAxes,
double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, numAxes, NUM_MD90_PARAMS,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
int axis;
asynStatus status;
MD90Axis *pAxis;
static const char *functionName = "MD90Controller::MD90Controller";
/* Connect to MD90 controller */
status = pasynOctetSyncIO->connect(MD90PortName, 0, &pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: cannot connect to MD-90 controller\n",
functionName);
}
for (axis=0; axis<numAxes; axis++) {
pAxis = new MD90Axis(this, axis);
}
startPoller(movingPollPeriod, idlePollPeriod, 2);
}
/** Creates a new MD90Controller object.
* Configuration command, called directly or from iocsh
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] MD90PortName The name of the drvAsynIPPPort that was created previously to connect to the MD90 controller
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time in ms between polls when any axis is moving
* \param[in] idlePollPeriod The time in ms between polls when no axis is moving
*/
extern "C" int MD90CreateController(const char *portName, const char *MD90PortName, int numAxes,
int movingPollPeriod, int idlePollPeriod)
{
MD90Controller *pMD90Controller
= new MD90Controller(portName, MD90PortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
pMD90Controller = NULL;
return(asynSuccess);
}
/** Reports on status of the driver
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* If details > 0 then information is printed about each axis.
* After printing controller-specific information it calls asynMotorController::report()
*/
void MD90Controller::report(FILE *fp, int level)
{
fprintf(fp, "MD-90 motor driver %s, numAxes=%d, moving poll period=%f, idle poll period=%f\n",
this->portName, numAxes_, movingPollPeriod_, idlePollPeriod_);
// Call the base class method
asynMotorController::report(fp, level);
}
/** Returns a pointer to an MD90Axis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
MD90Axis* MD90Controller::getAxis(asynUser *pasynUser)
{
return static_cast<MD90Axis*>(asynMotorController::getAxis(pasynUser));
}
/** Returns a pointer to an MD90Axis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
MD90Axis* MD90Controller::getAxis(int axisNo)
{
return static_cast<MD90Axis*>(asynMotorController::getAxis(axisNo));
}
// These are the MD90Axis methods
/** Creates a new MD90Axis object.
* \param[in] pC Pointer to the MD90Controller to which this axis belongs.
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
*
* Initializes register numbers, etc.
*/
MD90Axis::MD90Axis(MD90Controller *pC, int axisNo)
: asynMotorAxis(pC, axisNo),
pC_(pC)
{
}
/** Reports on status of the axis
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* After printing device-specific information calls asynMotorAxis::report()
*/
void MD90Axis::report(FILE *fp, int level)
{
if (level > 0) {
fprintf(fp, " axis %d\n",
axisNo_);
}
// Call the base class method
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
*/
asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity)
{
asynStatus status;
int freq;
static const char *functionName = "MD90::sendAccelAndVelocity";
// Send the velocity
// Velocity provided in steps/sec
// Our unit step size of the encoder is 10 nm, but the motor moves in steps approx. 5 micrometers.
// Motor controller accepts step frequency in Hz.
freq = NINT(fabs(velocity / 500.));
sprintf(pC_->outString_, "SSF %d", freq);
status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status;
}
asynStatus MD90Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
static const char *functionName = "MD90Axis::move";
status = sendAccelAndVelocity(acceleration, maxVelocity);
// Position specified in encoder steps (10 nm), but motor move commands are in nanometers
position = position * 10;
if (relative) {
sprintf(pC_->outString_, "CRM %d", NINT(position));
} else {
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";
status = sendAccelAndVelocity(acceleration, maxVelocity);
sprintf(pC_->outString_, "HOM");
status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status;
}
asynStatus MD90Axis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
{
asynStatus status;
static const char *functionName = "MD90Axis::moveVelocity";
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
"%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
functionName, minVelocity, maxVelocity, acceleration);
status = sendAccelAndVelocity(acceleration, maxVelocity);
/* MD-90 does not have jog command. Move max 6000 steps */
sprintf(pC_->outString_, "SNS 6000");
status = pC_->writeReadController();
if (maxVelocity > 0.) {
/* This is a positive move in MD90 coordinates */
sprintf(pC_->outString_, "ESF");
} else {
/* This is a negative move in MD90 coordinates */
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";
sprintf(pC_->outString_, "STP");
status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status;
}
/** The ACS driver used this to turn on/off the motor winding current, so
* we'll use this for enabling/disabling the persistent move state.
*/
asynStatus MD90Axis::setClosedLoop(bool closedLoop)
{
asynStatus status;
static const char *functionName = "MD90Axis::setClosedLoop";
if (closedLoop == 1) {
sprintf(pC_->outString_, "EPM");
} else {
sprintf(pC_->outString_, "DPM");
}
status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status;
}
/** Set the I Gain of the motor control loop. The motor is an I- controller
* and has no P or D terms.
* \param[in] iGain The current I gain in the control loop
*/
asynStatus MD90Axis::setIGain(double iGain)
{
asynStatus status;
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";
sprintf(pC_->outString_, "CLM 0");
status = pC_->writeReadController();
if (!status) {
status = parseReply(functionName, pC_->inString_);
}
return status;
}
/** Polls the axis.
* This function reads the motor position, the limit status, the home status, the moving status,
* and the drive power-on status.
* It calls setIntegerParam() and setDoubleParam() for each item that it polls,
* and then calls callParamCallbacks() at the end.
* \param[out] moving A flag that is set indicating that the axis is moving (true) or done (false).
*/
asynStatus MD90Axis::poll(bool *moving)
{
int replyStatus;
char replyString[256];
int replyValue;
int done;
int driveOn;
int homed;
double position;
double velocity;
asynStatus comStatus;
static const char *functionName = "MD90Axis::poll";
// TODO: Will need to add some more error handling for the motor return codes.
setIntegerParam(pC_->motorStatusProblem_, 0);
// Read the drive power on status
sprintf(pC_->outString_, "GPS");
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);
driveOn = (replyValue == '1') ? 1:0;
setIntegerParam(pC_->motorStatusPowerOn_, driveOn);
// Read the home status
sprintf(pC_->outString_, "GHS");
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);
homed = (replyValue == '1') ? 1:0;
setIntegerParam(pC_->motorStatusHomed_, homed);
// Read the moving status of this motor
sprintf(pC_->outString_, "STA");
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);
done = (replyValue == '2') ? 0:1;
setIntegerParam(pC_->motorStatusDone_, done);
*moving = done ? false:true;
switch(replyValue) {
case 0: // Idle
asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s: Idle\n", functionName);
break;
case 1: // Open loop move complete
asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s: Open loop move complete\n", functionName);
break;
case 2: // Move in progress
asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s: Move in progress\n", functionName);
break;
case 3: // Move stopped
asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s: Move stopped\n", functionName);
break;
case 4: // Homing error
setIntegerParam(pC_->motorStatusProblem_, 1);
asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s: Homing error\n", functionName);
break;
case 5: // Stance error
setIntegerParam(pC_->motorStatusProblem_, 1);
asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s: Stance error (Error resetting pose during closed loop move)\n", functionName);
break;
case 6: // Stance complete
asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s: Stance complete (Finished resetting pose, starting extension move)\n", functionName);
break;
case 7: // Open loop move error
setIntegerParam(pC_->motorStatusProblem_, 1);
asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s: Open loop move error\n", functionName);
break;
case 8: // Closed loop move error
setIntegerParam(pC_->motorStatusProblem_, 1);
asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s: Closed loop move error\n", functionName);
break;
case 9: // Closed loop move complete
asynPrint(pasynUser_, ASYN_TRACE_FLOW, "%s: Closed loop move complete\n", functionName);
break;
case 10: // End of travel error
setIntegerParam(pC_->motorStatusProblem_, 1);
asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s: End of travel error\n", functionName);
if (position > 0) {
setIntegerParam(pC_->motorStatusHighLimit_, 1);
} else {
setIntegerParam(pC_->motorStatusLowLimit_, 1);
}
break;
case 11: // Ramp move error
setIntegerParam(pC_->motorStatusProblem_, 1);
asynPrint(pasynUser_, ASYN_TRACE_ERROR, "%s: Ramp move error\n", functionName);
break;
default:
break;
}
// Read the current motor position in encoder steps (10 nm)
sprintf(pC_->outString_, "GEC");
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);
setDoubleParam(pC_->motorPosition_, position);
setDoubleParam(pC_->motorEncoderPosition_, position);
setIntegerParam(pC_->motorStatusAtHome_, (position == 0) ? 1:0); // home limit switch
setIntegerParam(pC_->motorStatusHome_, (position == 0) ? 1:0); // at home position
// Read the current motor step frequency to calculate approx. set velocity in (encoder step lengths / s)
sprintf(pC_->outString_, "GSF");
comStatus = pC_->writeReadController();
if (comStatus) goto skip;
// The response string is of the form "0: Current step frequency: 100"
sscanf(pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
velocity = replyValue * 500.0;
setDoubleParam(pC_->motorVelocity_, velocity);
// Read the current motor integral gain (range 1-1000)
sprintf(pC_->outString_, "GGN");
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);
setDoubleParam(pC_->motorIGain_, replyValue);
// Read the current motor persistent move state (using EPICS motorClosedLoop to report this)
sprintf(pC_->outString_, "GPM");
comStatus = pC_->writeReadController();
if (comStatus) goto skip;
// The response string is of the form "0: Current persistent move state: 1"
sscanf(pC_->inString_, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
setIntegerParam(pC_->motorClosedLoop_, (replyValue == 0) ? 0:1);
// set some default params
setIntegerParam(pC_->motorStatusHasEncoder_, 1);
setIntegerParam(pC_->motorStatusGainSupport_, 1);
skip:
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
callParamCallbacks();
return comStatus ? asynError : asynSuccess;
}
/** Code for iocsh registration */
static const iocshArg MD90CreateControllerArg0 = {"Port name", iocshArgString};
static const iocshArg MD90CreateControllerArg1 = {"MD-90 port name", iocshArgString};
static const iocshArg MD90CreateControllerArg2 = {"Number of axes", iocshArgInt};
static const iocshArg MD90CreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
static const iocshArg MD90CreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
static const iocshArg * const MD90CreateControllerArgs[] = {&MD90CreateControllerArg0,
&MD90CreateControllerArg1,
&MD90CreateControllerArg2,
&MD90CreateControllerArg3,
&MD90CreateControllerArg4};
static const iocshFuncDef MD90CreateControllerDef = {"MD90CreateController", 5, MD90CreateControllerArgs};
static void MD90CreateContollerCallFunc(const iocshArgBuf *args)
{
MD90CreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival);
}
static void MD90Register(void)
{
iocshRegister(&MD90CreateControllerDef, MD90CreateContollerCallFunc);
}
extern "C" {
epicsExportRegistrar(MD90Register);
}

View File

@@ -1,6 +1,6 @@
/*
FILENAME... MCB4BDriver.h
USAGE... Motor driver support for the ACS MCB-4B controller.
FILENAME... MD90Driver.h
USAGE... Motor driver support for the DSM MD-90 controller.
Mark Rivers
March 1, 2012
@@ -10,40 +10,42 @@ March 1, 2012
#include "asynMotorController.h"
#include "asynMotorAxis.h"
#define MAX_MCB4B_AXES 4
#define MAX_MD90_AXES 1
// No controller-specific parameters yet
#define NUM_MCB4B_PARAMS 0
#define NUM_MD90_PARAMS 0
class epicsShareClass MCB4BAxis : public asynMotorAxis
class epicsShareClass MD90Axis : public asynMotorAxis
{
public:
/* These are the methods we override from the base class */
MCB4BAxis(class MCB4BController *pC, int axis);
MD90Axis(class MD90Controller *pC, int axis);
void report(FILE *fp, int level);
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);
asynStatus setClosedLoop(bool closedLoop);
asynStatus setIGain(double iGain);
asynStatus doMoveToHome();
private:
MCB4BController *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 */
asynStatus sendAccelAndVelocity(double accel, double velocity);
asynStatus parseReply(const char *functionName, const char *reply);
friend class MCB4BController;
friend class MD90Controller;
};
class epicsShareClass MCB4BController : public asynMotorController {
class epicsShareClass MD90Controller : public asynMotorController {
public:
MCB4BController(const char *portName, const char *MCB4BPortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
MD90Controller(const char *portName, const char *MD90PortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
void report(FILE *fp, int level);
MCB4BAxis* getAxis(asynUser *pasynUser);
MCB4BAxis* getAxis(int axisNo);
MD90Axis* getAxis(asynUser *pasynUser);
MD90Axis* getAxis(int axisNo);
friend class MCB4BAxis;
friend class MD90Axis;
};

View File

@@ -5,18 +5,18 @@ include $(TOP)/configure/CONFIG
# The following are used for debugging messages.
USR_CXXFLAGS += -DDEBUG
DBD += devAcsMotor.dbd
DBD += devDsmMotor.dbd
LIBRARY_IOC = Acs
LIBRARY_IOC = dsm
SRCS += AcsRegister.cc
SRCS += dsmRegister.cc
# Advanced Control Systems driver support.
SRCS += devMCB4B.c drvMCB4B.c
SRCS += MCB4BDriver.cpp
SRCS += devMD90.c drvMD90.c
SRCS += MD90Driver.cpp
Acs_LIBS += motor asyn
Acs_LIBS += $(EPICS_BASE_IOC_LIBS)
dsm_LIBS += motor asyn
dsm_LIBS += $(EPICS_BASE_IOC_LIBS)
include $(TOP)/configure/RULES

View File

@@ -0,0 +1,11 @@
# Advanced Control Systems driver support.
# Model 1 (non-asyn) driver
device(motor,VME_IO,devMD90,"DSM MD-90")
driver(drvMD90)
registrar(dsmRegister)
# Model 3 driver
registrar(MD90Register)

View File

@@ -1,4 +1,4 @@
/* File: devMCB4B.cc */
/* File: devMD90.cc */
/* Device Support Routines for motor */
/*
@@ -20,21 +20,21 @@
#include "motorRecord.h"
#include "motor.h"
#include "motordevCom.h"
#include "drvMCB4B.h"
#include "drvMD90.h"
#include "epicsExport.h"
#define STATIC static
extern struct driver_table MCB4B_access;
extern struct driver_table MD90_access;
#define NINT(f) (long)((f)>0 ? (f)+0.5 : (f)-0.5)
volatile int devMCB4BDebug = 0;
extern "C" {epicsExportAddress(int, devMCB4BDebug);}
volatile int devMD90Debug = 0;
extern "C" {epicsExportAddress(int, devMD90Debug);}
static inline void Debug(int level, const char *format, ...) {
#ifdef DEBUG
if (level < devMCB4BDebug)
if (level < devMD90Debug)
{
va_list pVar;
va_start(pVar, format);
@@ -45,35 +45,35 @@ static inline void Debug(int level, const char *format, ...) {
}
/* Debugging levels:
* devMCB4BDebug >= 3 Print new part of command and command string so far
* at the end of MCB4B_build_trans
* devMD90Debug >= 3 Print new part of command and command string so far
* at the end of MD90_build_trans
*/
/* ----------------Create the dsets for devMCB4B----------------- */
/* ----------------Create the dsets for devMD90----------------- */
STATIC struct driver_table *drvtabptr;
STATIC long MCB4B_init(int);
STATIC long MCB4B_init_record(void *);
STATIC long MCB4B_start_trans(struct motorRecord *);
STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd, double *, struct motorRecord *);
STATIC RTN_STATUS MCB4B_end_trans(struct motorRecord *);
STATIC long MD90_init(int);
STATIC long MD90_init_record(void *);
STATIC long MD90_start_trans(struct motorRecord *);
STATIC RTN_STATUS MD90_build_trans(motor_cmnd, double *, struct motorRecord *);
STATIC RTN_STATUS MD90_end_trans(struct motorRecord *);
struct motor_dset devMCB4B =
struct motor_dset devMD90 =
{
{8, NULL, (DEVSUPFUN) MCB4B_init, (DEVSUPFUN) MCB4B_init_record, NULL},
{8, NULL, (DEVSUPFUN) MD90_init, (DEVSUPFUN) MD90_init_record, NULL},
motor_update_values,
MCB4B_start_trans,
MCB4B_build_trans,
MCB4B_end_trans
MD90_start_trans,
MD90_build_trans,
MD90_end_trans
};
extern "C" {epicsExportAddress(dset,devMCB4B);}
extern "C" {epicsExportAddress(dset,devMD90);}
/* --------------------------- program data --------------------- */
/* This table is used to define the command types */
static msg_types MCB4B_table[] = {
static msg_types MD90_table[] = {
MOTION, /* MOVE_ABS */
MOTION, /* MOVE_REL */
MOTION, /* HOME_FOR */
@@ -99,63 +99,63 @@ static msg_types MCB4B_table[] = {
};
static struct board_stat **MCB4B_cards;
static struct board_stat **MD90_cards;
/* --------------------------- program data --------------------- */
/* initialize device support for MCB4B stepper motor */
STATIC long MCB4B_init(int after)
/* initialize device support for MD90 stepper motor */
STATIC long MD90_init(int after)
{
long rtnval;
Debug(5, "MCB4B_init: entry\n");
Debug(5, "MD90_init: entry\n");
if (!after)
{
drvtabptr = &MCB4B_access;
drvtabptr = &MD90_access;
(drvtabptr->init)();
}
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MCB4B_cards);
Debug(5, "MCB4B_init: exit\n");
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MD90_cards);
Debug(5, "MD90_init: exit\n");
return(rtnval);
}
/* initialize a record instance */
STATIC long MCB4B_init_record(void *arg)
STATIC long MD90_init_record(void *arg)
{
struct motorRecord *mr = (struct motorRecord *) arg;
long rtnval;
Debug(5, "MCB4B_init_record: entry\n");
Debug(5, "MD90_init_record: entry\n");
rtnval = motor_init_record_com(mr, *drvtabptr->cardcnt_ptr,
drvtabptr, MCB4B_cards);
drvtabptr, MD90_cards);
return(rtnval);
Debug(5, "MCB4B_init_record: exit\n");
Debug(5, "MD90_init_record: exit\n");
}
/* start building a transaction */
STATIC long MCB4B_start_trans(struct motorRecord *mr)
STATIC long MD90_start_trans(struct motorRecord *mr)
{
return(OK);
}
/* end building a transaction */
STATIC RTN_STATUS MCB4B_end_trans(struct motorRecord *mr)
STATIC RTN_STATUS MD90_end_trans(struct motorRecord *mr)
{
return(OK);
}
/* add a part to the transaction */
STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
STATIC RTN_STATUS MD90_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 MCB4Bcontroller *cntrl;
struct MD90controller *cntrl;
char buff[30];
int axis, card;
RTN_STATUS rtnval;
@@ -170,19 +170,19 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
dval = (parms == NULL) ? 0.0 : *parms;
ival = NINT(dval);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
Debug(5, "MCB4B_build_trans: entry, motor_start_trans_com=%d\n", rtnval);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
Debug(5, "MD90_build_trans: entry, motor_start_trans_com=%d\n", rtnval);
motor_call = &(trans->motor_call);
motor_call->type = MCB4B_table[command];
motor_call->type = MD90_table[command];
card = motor_call->card;
axis = motor_call->signal;
brdptr = (*trans->tabptr->card_array)[card];
Debug(5, "MCB4B_build_trans: axis=%d, command=%d\n", axis, command);
Debug(5, "MD90_build_trans: axis=%d, command=%d\n", axis, command);
if (brdptr == NULL)
return(rtnval = ERROR);
cntrl = (struct MCB4Bcontroller *) brdptr->DevicePrivate;
cntrl = (struct MD90controller *) brdptr->DevicePrivate;
if (trans->state != BUILD_STATE)
@@ -192,8 +192,8 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
{
strcpy(motor_call->message, mr->init);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
motor_call->type = MCB4B_table[command];
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
motor_call->type = MD90_table[command];
}
switch (command)
@@ -207,8 +207,8 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
{
strcpy(motor_call->message, mr->prem);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
motor_call->type = MCB4B_table[command];
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
motor_call->type = MD90_table[command];
}
if (strlen(mr->post) != 0)
motor_call->postmsgptr = (char *) &mr->post;
@@ -238,7 +238,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
case SET_VEL_BASE:
send=false;
trans->state = IDLE_STATE;
break; /* MCB4B does not use base velocity */
break; /* MD90 does not use base velocity */
case SET_VELOCITY:
ival = (int) (fabs(115200./dval) + 0.5);
if (ival < 2) ival=2;
@@ -247,7 +247,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
break;
case SET_ACCEL:
/* dval is acceleration in steps/sec/sec */
/* MCB is programmed with Ramp Index (R) where: */
/* MD-90 is programmed with Ramp Index (R) where: */
/* dval (steps/sec/sec) = 720,000/(256-R) */
/* or R=256-(720,000/dval) */
ival = (int) (256-(720000./dval)+0.5);
@@ -257,7 +257,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
break;
case GO:
/*
* The MCB4B starts moving immediately on move commands, GO command
* The MD90 starts moving immediately on move commands, GO command
* does nothing
*/
send=false;
@@ -265,7 +265,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
break;
case SET_ENC_RATIO:
/*
* The MCB4B does not have the concept of encoder ratio, ignore this
* The MD90 does not have the concept of encoder ratio, ignore this
* command
*/
send=false;
@@ -280,19 +280,19 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
sprintf(motor_call->message, "#%02dQ", axis);
break;
case JOG:
/* MCB-4B does not have jog command. Move 1 million steps */
/* MD-90 does not have jog command. Move 1 million steps */
ival = (int) (fabs(115200./dval) + 0.5);
if (ival < 2) ival=2;
if (ival > 65535) ival = 65535;
sprintf(motor_call->message, "#%02dC=%ld", axis, ival);
rtnval = motor_end_trans_com(mr, drvtabptr);
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
motor_call->type = MCB4B_table[command];
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
motor_call->type = MD90_table[command];
if (dval > 0.) {
/* This is a positive move in MCB4B coordinates */
/* This is a positive move in MD90 coordinates */
sprintf(motor_call->message, "#%02dM+1000000", axis);
} else {
/* This is a negative move in MCB4B coordinates */
/* This is a negative move in MD90 coordinates */
sprintf(motor_call->message, "#%02dM-1000000", axis);
}
break;
@@ -325,7 +325,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
return(rtnval);
else {
rtnval = motor_end_trans_com(mr, drvtabptr);
Debug(5, "MCB4B_send_msg: motor_end_trans_com status=%d, exit\n", rtnval);
Debug(5, "MD90_send_msg: motor_end_trans_com status=%d, exit\n", rtnval);
return (rtnval);
}
}

View File

@@ -1,4 +1,4 @@
/* File: drvMCB4B.cc */
/* File: drvMD90.cc */
/* Device Driver Support routines for motor */
/*
@@ -24,8 +24,8 @@
#include <stdlib.h>
#include <errlog.h>
#include "motor.h"
#include "AcsRegister.h"
#include "drvMCB4B.h"
#include "dsmRegister.h"
#include "drvMD90.h"
#include "asynOctetSyncIO.h"
#include "epicsExport.h"
@@ -35,14 +35,14 @@
#define TIMEOUT 2.0 /* Command timeout in sec */
#define BUFF_SIZE 100 /* Maximum length of string to/from MCB4B */
#define BUFF_SIZE 100 /* Maximum length of string to/from MD90 */
volatile int drvMCB4BDebug = 0;
extern "C" {epicsExportAddress(int, drvMCB4BDebug);}
volatile int drvMD90Debug = 0;
extern "C" {epicsExportAddress(int, drvMD90Debug);}
static inline void Debug(int level, const char *format, ...) {
#ifdef DEBUG
if (level < drvMCB4BDebug)
if (level < drvMD90Debug)
{
va_list pVar;
va_start(pVar, format);
@@ -53,14 +53,14 @@ static inline void Debug(int level, const char *format, ...) {
}
/* Debugging notes:
* drvMCB4BDebug == 0 No debugging information is printed
* drvMCB4BDebug >= 1 Warning information is printed
* drvMCB4BDebug >= 2 Time-stamped messages are printed for each string
* drvMD90Debug == 0 No debugging information is printed
* drvMD90Debug >= 1 Warning information is printed
* drvMD90Debug >= 2 Time-stamped messages are printed for each string
* sent to and received from the controller
* drvMCB4BDebug >= 3 Additional debugging messages
* drvMD90Debug >= 3 Additional debugging messages
*/
int MCB4B_num_cards = 0;
int MD90_num_cards = 0;
/* Local data required for every driver; see "motordrvComCode.h" */
#include "motordrvComCode.h"
@@ -78,7 +78,7 @@ STATIC void query_done(int, int, struct mess_node *);
/*----------------functions-----------------*/
struct driver_table MCB4B_access =
struct driver_table MD90_access =
{
motor_init,
motor_send,
@@ -102,16 +102,16 @@ struct driver_table MCB4B_access =
NULL
};
struct drvMCB4B_drvet
struct drvMD90_drvet
{
long number;
long (*report) (int);
long (*init) (void);
} drvMCB4B = {2, report, init};
} drvMD90 = {2, report, init};
extern "C" {epicsExportAddress(drvet, drvMCB4B);}
extern "C" {epicsExportAddress(drvet, drvMD90);}
STATIC struct thread_args targs = {SCAN_RATE, &MCB4B_access, 0.0};
STATIC struct thread_args targs = {SCAN_RATE, &MD90_access, 0.0};
/*********************************************************
@@ -120,16 +120,16 @@ STATIC struct thread_args targs = {SCAN_RATE, &MCB4B_access, 0.0};
static long report(int level)
{
int card;
struct MCB4Bcontroller *cntrl;
struct MD90controller *cntrl;
if (MCB4B_num_cards <=0)
printf(" NO MCB4B controllers found\n");
if (MD90_num_cards <=0)
printf(" NO MD90 controllers found\n");
else
{
for (card = 0; card < MCB4B_num_cards; card++) {
for (card = 0; card < MD90_num_cards; card++) {
if (motor_state[card]) {
cntrl = (struct MCB4Bcontroller *) motor_state[card]->DevicePrivate;
printf(" MCB4B controller %d, port=%s, id: %s \n",
cntrl = (struct MD90controller *) motor_state[card]->DevicePrivate;
printf(" MD90 controller %d, port=%s, id: %s \n",
card, cntrl->port,
motor_state[card]->ident);
}
@@ -148,10 +148,10 @@ static long init()
* support
*/
/* Check for setup */
if (MCB4B_num_cards <= 0)
if (MD90_num_cards <= 0)
{
Debug(1, "init: *MCB4B driver disabled*\n");
Debug(1, "MCB4BSetup() is missing from startup script.\n");
Debug(1, "init: *MD90 driver disabled*\n");
Debug(1, "MD90Setup() is missing from startup script.\n");
return (ERROR);
}
@@ -170,7 +170,7 @@ STATIC void query_done(int card, int axis, struct mess_node *nodeptr)
*********************************************************/
STATIC void start_status(int card)
{
/* The MCB4B cannot query status or positions of all axes with a
/* The MD90 cannot query status or positions of all axes with a
* single command. This needs to be done on an axis-by-axis basis,
* so this function does nothing
*/
@@ -265,7 +265,7 @@ STATIC int set_status(int card, int signal)
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 && nodeptr->postmsgptr != 0)
{
send_mess(card, nodeptr->postmsgptr, NULL);
/* The MCB4B always sends back a response, read it and discard */
/* The MD90 always sends back a response, read it and discard */
recv_mess(card, buff, WAIT);
nodeptr->postmsgptr = NULL;
}
@@ -276,12 +276,12 @@ STATIC int set_status(int card, int signal)
/*****************************************************/
/* send a message to the MCB4B board */
/* send a message to the MD90 board */
/* send_mess() */
/*****************************************************/
STATIC RTN_STATUS send_mess(int card, const char *com, const char *name)
{
struct MCB4Bcontroller *cntrl;
struct MD90controller *cntrl;
size_t nwrite;
/* Check that card exists */
@@ -293,7 +293,7 @@ STATIC RTN_STATUS send_mess(int card, const char *com, const char *name)
/* If the string is NULL just return */
if (strlen(com) == 0) return(OK);
cntrl = (struct MCB4Bcontroller *) motor_state[card]->DevicePrivate;
cntrl = (struct MD90controller *) motor_state[card]->DevicePrivate;
Debug(2, "send_mess: sending message to card %d, message=%s\n",\
card, com);
@@ -305,7 +305,7 @@ STATIC RTN_STATUS send_mess(int card, const char *com, const char *name)
/*****************************************************/
/* Read a response string from the MCB4B board */
/* Read a response string from the MD90 board */
/* recv_mess() */
/*****************************************************/
STATIC int recv_mess(int card, char *com, int flag)
@@ -313,7 +313,7 @@ STATIC int recv_mess(int card, char *com, int flag)
double timeout;
size_t nread=0;
asynStatus status;
struct MCB4Bcontroller *cntrl;
struct MD90controller *cntrl;
int flush;
int eomReason;
@@ -324,7 +324,7 @@ STATIC int recv_mess(int card, char *com, int flag)
return (-1);
}
cntrl = (struct MCB4Bcontroller *) motor_state[card]->DevicePrivate;
cntrl = (struct MD90controller *) motor_state[card]->DevicePrivate;
Debug(3, "recv_mess entry: card %d, flag=%d\n",\
card, flag);
@@ -363,18 +363,18 @@ STATIC int recv_mess(int card, char *com, int flag)
/*****************************************************/
/* Setup system configuration */
/* MCB4BSetup() */
/* MD90Setup() */
/*****************************************************/
RTN_STATUS
MCB4BSetup(int num_cards, /* maximum number of controllers in system */
MD90Setup(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 > MCB4B_NUM_CARDS)
MCB4B_num_cards = MCB4B_NUM_CARDS;
if (num_cards < 1 || num_cards > MD90_NUM_CARDS)
MD90_num_cards = MD90_NUM_CARDS;
else
MCB4B_num_cards = num_cards;
MD90_num_cards = num_cards;
/* Set motor polling task rate */
if (scan_rate >= 1 && scan_rate <= 60)
@@ -384,15 +384,15 @@ MCB4BSetup(int num_cards, /* maximum number of controllers in system */
/*
* Allocate space for motor_state structure pointers. Note this must be done
* before MCB4BConfig is called, so it cannot be done in motor_init()
* before MD90Config 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 since this is just
* an array of pointers.
*/
motor_state = (struct controller **) malloc(MCB4B_num_cards *
motor_state = (struct controller **) malloc(MD90_num_cards *
sizeof(struct controller *));
for (itera = 0; itera < MCB4B_num_cards; itera++)
for (itera = 0; itera < MD90_num_cards; itera++)
motor_state[itera] = (struct controller *) NULL;
return (OK);
}
@@ -400,20 +400,20 @@ MCB4BSetup(int num_cards, /* maximum number of controllers in system */
/*****************************************************/
/* Configure a controller */
/* MCB4BConfig() */
/* MD90Config() */
/*****************************************************/
RTN_STATUS
MCB4BConfig(int card, /* card being configured */
MD90Config(int card, /* card being configured */
const char *name) /* port name for asyn */
{
struct MCB4Bcontroller *cntrl;
struct MD90controller *cntrl;
if (card < 0 || card >= MCB4B_num_cards)
if (card < 0 || card >= MD90_num_cards)
return (ERROR);
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
motor_state[card]->DevicePrivate = malloc(sizeof(struct MCB4Bcontroller));
cntrl = (struct MCB4Bcontroller *) motor_state[card]->DevicePrivate;
motor_state[card]->DevicePrivate = malloc(sizeof(struct MD90controller));
cntrl = (struct MD90controller *) motor_state[card]->DevicePrivate;
strcpy(cntrl->port, name);
return (OK);
}
@@ -429,7 +429,7 @@ MCB4BConfig(int card, /* card being configured */
STATIC int motor_init()
{
struct controller *brdptr;
struct MCB4Bcontroller *cntrl;
struct MD90controller *cntrl;
int card_index, motor_index;
char buff[BUFF_SIZE];
int total_axis = 0;
@@ -439,21 +439,21 @@ STATIC int motor_init()
initialized = true; /* Indicate that driver is initialized. */
/* Check for setup */
if (MCB4B_num_cards <= 0)
if (MD90_num_cards <= 0)
{
Debug(1, "motor_init: *MCB4B driver disabled*\n");
Debug(1, "MCB4BSetup() is missing from startup script.\n");
Debug(1, "motor_init: *MD90 driver disabled*\n");
Debug(1, "MD90Setup() is missing from startup script.\n");
return (ERROR);
}
for (card_index = 0; card_index < MCB4B_num_cards; card_index++)
for (card_index = 0; card_index < MD90_num_cards; card_index++)
{
if (!motor_state[card_index])
continue;
brdptr = motor_state[card_index];
total_cards = card_index + 1;
cntrl = (struct MCB4Bcontroller *) brdptr->DevicePrivate;
cntrl = (struct MD90controller *) brdptr->DevicePrivate;
/* Initialize communications channel */
success_rtn = pasynOctetSyncIO->connect(cntrl->port, 0, &cntrl->pasynUser, NULL);
@@ -498,7 +498,7 @@ STATIC int motor_init()
sprintf(buff,"#%02dQ", motor_index);
send_mess(card_index, buff, 0);
recv_mess(card_index, buff, WAIT); /* Throw away response */
strcpy(brdptr->ident, "MCB-4B");
strcpy(brdptr->ident, "MD-90");
motor_info->status.All = 0;
motor_info->no_motion_count = 0;
motor_info->encoder_position = 0;
@@ -521,7 +521,7 @@ STATIC int motor_init()
Debug(3, "motor_init: spawning motor task\n");
epicsThreadCreate((char *) "tMCB4B", epicsThreadPriorityMedium,
epicsThreadCreate((char *) "tMD90", epicsThreadPriorityMedium,
epicsThreadGetStackSize(epicsThreadStackMedium),
(EPICSTHREADFUNC) motor_task, (void *) &targs);

View File

@@ -1,4 +1,4 @@
/* File: drvMCB4B.h */
/* File: drvMD90.h */
/* Device Driver Support definitions for motor */
@@ -12,23 +12,23 @@
* .01 02/24/2002 mlr initialized from drvPM304.h
*/
#ifndef INCdrvMCB4Bh
#define INCdrvMCB4Bh 1
#ifndef INCdrvMD90h
#define INCdrvMD90h 1
#include "motordrvCom.h"
#include "asynDriver.h"
/* MCB4B default profile. */
/* MD90 default profile. */
#define MCB4B_NUM_CARDS 4
#define MCB4B_NUM_CHANNELS 4
#define MD90_NUM_CARDS 4
#define MD90_NUM_CHANNELS 4
#define OUTPUT_TERMINATOR "\r"
struct MCB4Bcontroller
struct MD90controller
{
asynUser *pasynUser; /* asynUser structure */
char port[80]; /* asyn port name */
};
#endif /* INCdrvMCB4Bh */
#endif /* INCdrvMD90h */

View File

@@ -1,6 +1,6 @@
/*
FILENAME... AcsRegister.cc
USAGE... Register ACS motor device driver shell commands.
FILENAME... dsmRegister.cc
USAGE... Register DSM motor device driver shell commands.
*/
@@ -16,40 +16,40 @@ of this distribution.
**********************************************************************/
#include <iocsh.h>
#include "AcsRegister.h"
#include "dsmRegister.h"
#include "epicsExport.h"
extern "C"
{
// ACS Setup arguments
// DSM Setup arguments
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
// ACS Config arguments
// DSM Config arguments
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
static const iocshArg * const MCB4BSetupArgs[2] = {&setupArg0, &setupArg1};
static const iocshArg * const MCB4BConfigArgs[2] = {&configArg0, &configArg1};
static const iocshArg * const MD90SetupArgs[2] = {&setupArg0, &setupArg1};
static const iocshArg * const MD90ConfigArgs[2] = {&configArg0, &configArg1};
static const iocshFuncDef setupMCB4B = {"MCB4BSetup", 2, MCB4BSetupArgs};
static const iocshFuncDef configMCB4B = {"MCB4BConfig", 2, MCB4BConfigArgs};
static const iocshFuncDef setupMD90 = {"MD90Setup", 2, MD90SetupArgs};
static const iocshFuncDef configMD90 = {"MD90Config", 2, MD90ConfigArgs};
static void setupMCB4BCallFunc(const iocshArgBuf *args)
static void setupMD90CallFunc(const iocshArgBuf *args)
{
MCB4BSetup(args[0].ival, args[1].ival);
MD90Setup(args[0].ival, args[1].ival);
}
static void configMCB4BCallFunc(const iocshArgBuf *args)
static void configMD90CallFunc(const iocshArgBuf *args)
{
MCB4BConfig(args[0].ival, args[1].sval);
MD90Config(args[0].ival, args[1].sval);
}
static void AcsRegister(void)
static void dsmRegister(void)
{
iocshRegister(&setupMCB4B, setupMCB4BCallFunc);
iocshRegister(&configMCB4B, configMCB4BCallFunc);
iocshRegister(&setupMD90, setupMD90CallFunc);
iocshRegister(&configMD90, configMD90CallFunc);
}
epicsExportRegistrar(AcsRegister);
epicsExportRegistrar(dsmRegister);
} // extern "C"

View File

@@ -1,6 +1,6 @@
/*
FILENAME... AcsRegister.h
USAGE... This file contains function prototypes for ACS IOC shell commands.
FILENAME... dsmRegister.h
USAGE... This file contains function prototypes for DSM IOC shell commands.
*/
@@ -37,6 +37,6 @@ USAGE... This file contains function prototypes for ACS IOC shell commands.
#include "motordrvCom.h"
/* Function prototypes. */
extern RTN_STATUS MCB4BSetup(int, int);
extern RTN_STATUS MCB4BConfig(int, const char *);
extern RTN_STATUS MD90Setup(int, int);
extern RTN_STATUS MD90Config(int, const char *);

View File

@@ -1,7 +1,7 @@
TOP = ..
include $(TOP)/configure/CONFIG
DIRS += acsIOC
DIRS += dsmIOC
include $(TOP)/configure/RULES_TOP

View File

@@ -1,6 +0,0 @@
# Use the following lines if motorAcs was built inside motor
MOTOR=
-include $(MOTOR)/configure/RELEASE
# Use the following lines if motorAcs was built outside motor
#!MOTOR_ACS=
#!-include $(MOTOR_ACS)/configure/RELEASE.local

View File

@@ -1,9 +0,0 @@
file "$(MOTOR)/db/basic_asyn_motor.db"
{
pattern
{P, N, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT}
{IOC:, 1, "m$(N)", "asynMotor", MCB4B1, 0, "Bottom", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, -.001, 3, 16, 0, ""}
{IOC:, 2, "m$(N)", "asynMotor", MCB4B1, 1, "Top", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, -.001, 3, 16, 0, ""}
{IOC:, 3, "m$(N)", "asynMotor", MCB4B1, 2, "Inboard", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, -.001, 3, 16, 0, ""}
{IOC:, 4, "m$(N)", "asynMotor", MCB4B1, 3, "Outboard", mm, Pos, 2.0, 0.1, .2, 0, 1, .2, -.001, 3, 16, 0, ""}
}

View File

@@ -1,34 +0,0 @@
#errlogInit(5000)
< envPaths
# Tell EPICS all about the record types, device-support modules, drivers, etc.
dbLoadDatabase("../../dbd/acs.dbd")
acs_registerRecordDeviceDriver(pdbbase)
# Port 2 on a Moxa
drvAsynIPPortConfigure("serial1", "192.168.1.16:4002",0,0,0)
# Local serial port
#!drvAsynSerialPortConfigure("serial1", "/dev/ttyS0", 0, 0, 0)
asynOctetSetInputEos("serial1",0,"\r")
asynOctetSetOutputEos("serial1",0,"\r")
asynSetTraceIOMask("serial1", 0, 2)
#asynSetTraceMask("serial1", 0, 255)
MCB4BCreateController("MCB4B1", "serial1", 4, 100, 5000)
### Motors
dbLoadTemplate "motor.substitutions.mcb4b"
dbLoadRecords("$(ASYN)/db/asynRecord.db","P=IOC:,R=serial1,PORT=serial1,ADDR=0,OMAX=80,IMAX=80")
iocInit
# This IOC does not use save/restore, so set values of some PVs
dbpf("IOC:m1.RTRY", "0")
dbpf("IOC:m1.TWV", "0.1")
dbpf("IOC:m2.RTRY", "0")
dbpf("IOC:m2.TWV", "0.1")
dbpf("IOC:m3.RTRY", "0")
dbpf("IOC:m3.TWV", "0.1")
dbpf("IOC:m4.RTRY", "0")
dbpf("IOC:m4.TWV", "0.1")

View File

@@ -37,8 +37,8 @@ CHECK_RELEASE = YES
# Include motor's CONFIG_SITE.local when building inside motor
-include $(TOP)/../../../../configure/CONFIG_SITE.local
# Include motorAcs's CONFIG_SITE.local when building inside motorAcs
# Include motorDsm's CONFIG_SITE.local when building inside motorDsm
-include $(TOP)/../../configure/CONFIG_SITE.local
# Use acsIOC's CONFIG_SITE.local
# Use dsmIOC's CONFIG_SITE.local
-include $(TOP)/configure/CONFIG_SITE.local

View File

@@ -0,0 +1,6 @@
# Use the following lines if motorDsm was built inside motor
MOTOR=
-include $(MOTOR)/configure/RELEASE
# Use the following lines if motorDsm was built outside motor
#!MOTOR_DSM=
#!-include $(MOTOR_DSM)/configure/RELEASE.local

View File

@@ -2,7 +2,7 @@
# Use motor/module's generated release file when buidling inside motor
-include $(TOP)/../../../RELEASE.$(EPICS_HOST_ARCH).local
# Use motorAcs's release file when building inside motorAcs, but outside motor
# Use motorDsm's release file when building inside motorDsm, but outside motor
-include $(TOP)/../../configure/RELEASE.local
# Use acsIOC's RELEASE.local when building outside motorAcs
# Use dsmIOC's RELEASE.local when building outside motorDsm
-include $(TOP)/configure/RELEASE.local

View File

@@ -11,44 +11,44 @@ include $(TOP)/configure/CONFIG
#=============================
# Build the IOC application
PROD_IOC = acs
# acs.dbd will be created and installed
DBD += acs.dbd
PROD_IOC = dsm
# dsm.dbd will be created and installed
DBD += dsm.dbd
# acs.dbd will be made up from these files:
acs_DBD += base.dbd
# dsm.dbd will be made up from these files:
dsm_DBD += base.dbd
# Include dbd files from all support applications:
#ifdef ASYN
acs_DBD += asyn.dbd
acs_DBD += drvAsynSerialPort.dbd
acs_DBD += drvAsynIPPort.dbd
dsm_DBD += asyn.dbd
dsm_DBD += drvAsynSerialPort.dbd
dsm_DBD += drvAsynIPPort.dbd
#endif
acs_DBD += motorSupport.dbd
acs_DBD += devAcsMotor.dbd
dsm_DBD += motorSupport.dbd
dsm_DBD += devDsmMotor.dbd
# Add all the support libraries needed by this IOC
acs_LIBS += Acs
acs_LIBS += motor
dsm_LIBS += dsm
dsm_LIBS += motor
#ifdef ASYN
acs_LIBS += asyn
dsm_LIBS += asyn
#endif
#ifdef SNCSEQ
acs_LIBS += seq pv
dsm_LIBS += seq pv
#endif
# acs_registerRecordDeviceDriver.cpp derives from acs.dbd
acs_SRCS += acs_registerRecordDeviceDriver.cpp
# dsm_registerRecordDeviceDriver.cpp derives from dsm.dbd
dsm_SRCS += dsm_registerRecordDeviceDriver.cpp
# Build the main IOC entry point on workstation OSs.
acs_SRCS_DEFAULT += acsMain.cpp
acs_SRCS_vxWorks += -nil-
dsm_SRCS_DEFAULT += dsmMain.cpp
dsm_SRCS_vxWorks += -nil-
# Add support from base/src/vxWorks if needed
#acs_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
#dsm_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary
# Finally link to the EPICS Base libraries
acs_LIBS += $(EPICS_BASE_IOC_LIBS)
dsm_LIBS += $(EPICS_BASE_IOC_LIBS)
#===========================

View File

@@ -1,4 +1,4 @@
/* acsMain.cpp */
/* dsmMain.cpp */
/* Author: Marty Kraimer Date: 17MAR2000 */
#include <stddef.h>

View File

@@ -0,0 +1,26 @@
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, ""}
}
# 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,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

@@ -1,24 +1,24 @@
#!../../bin/linux-x86_64/acs
#!../../bin/linux-x86_64/dsm
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/acs.dbd"
acs_registerRecordDeviceDriver pdbbase
dbLoadDatabase "dbd/dsm.dbd"
dsm_registerRecordDeviceDriver pdbbase
cd "${TOP}/iocBoot/${IOC}"
## motorUtil (allstop & alldone)
dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=acs:")
dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=dsm:")
##
iocInit
## motorUtil (allstop & alldone)
motorUtilInit("acs:")
motorUtilInit("dsm:")
# Boot complete

View File

@@ -0,0 +1,38 @@
#errlogInit(5000)
< envPaths
# Tell EPICS all about the record types, device-support modules, drivers, etc.
dbLoadDatabase("../../dbd/dsm.dbd")
dsm_registerRecordDeviceDriver(pdbbase)
# Network device
#!drvAsynIPPortConfigure("serial0", "192.168.1.16:4002",0,0,0)
# Local serial port
drvAsynSerialPortConfigure("serial0", "/dev/ttyUSB0", 0, 0, 0)
asynSetOption("serial0", 0, "baud", "115200")
asynSetOption("serial0", 0, "bits", "8")
asynSetOption("serial0", 0, "parity", "none")
asynSetOption("serial0", 0, "stop", "1")
asynOctetSetInputEos("serial0", 0, "\r")
asynOctetSetOutputEos("serial0", 0, "\r")
asynSetTraceIOMask("serial0", 0, 2)
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial0", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
MD90CreateController("MD900", "serial0", 1, 100, 5000)
### Motors
dbLoadTemplate "motor.substitutions.md90"
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial0,PORT=serial0,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")

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")