mirror of
https://github.com/Binary-Coalescence/motorDSM.git
synced 2025-08-05 06:05:40 -05:00
Compare commits
100 Commits
R1-1
...
documentat
Author | SHA1 | Date | |
---|---|---|---|
75a1ff060d | |||
f85ae07d2b | |||
3ecb9676c0 | |||
03a93101c1 | |||
95c227a553 | |||
3614a806ea
|
|||
b25f608e98
|
|||
![]() |
841b6f5b41 | ||
2379c90d90 | |||
cf26f426df | |||
c1025d711b | |||
8fc33fa14d
|
|||
05a223bd17
|
|||
5d706d4879
|
|||
707850e879
|
|||
8ec61fb3dc
|
|||
90b0fa8836
|
|||
40cfb47f05
|
|||
1a4794a9b2
|
|||
a3d6a24a01
|
|||
c8dbd0916d
|
|||
e9ca810318
|
|||
bf7b557dd7
|
|||
0600cba84d
|
|||
51fceaf7d7
|
|||
66ef37cb10
|
|||
200b68857d
|
|||
d0532c2552
|
|||
45c8ff064e
|
|||
4351ab56e3
|
|||
a90eea829a
|
|||
7b9f2870ca
|
|||
f73608c596
|
|||
19731d2f37
|
|||
a4012dda64
|
|||
c812afbe4e
|
|||
7551465733
|
|||
bdec17808a
|
|||
29a78e1023
|
|||
c930a77811
|
|||
df98f6667a
|
|||
37d22e58dd
|
|||
8c053dfa62
|
|||
4ab244925d
|
|||
5d343b33d1
|
|||
0d84bb4a29
|
|||
448e26ac23
|
|||
19467e5b5b
|
|||
402584345f
|
|||
c5eebd9597
|
|||
341bbb5980
|
|||
71ae063b23
|
|||
b8b090a804
|
|||
273e545759
|
|||
ba71c79a92
|
|||
996439589a
|
|||
d412000373
|
|||
9fa37e8cd0
|
|||
9a3d3d773d
|
|||
6c841c9041
|
|||
9403c24df0
|
|||
7b3675fbdf
|
|||
a1827ca152
|
|||
c2cbaf6bfd
|
|||
1b366684d0
|
|||
8101fcae72
|
|||
629c55bba4
|
|||
b616133ace
|
|||
c1ffe8b805
|
|||
c11e11659b
|
|||
b56a1f9a35
|
|||
4837e8f597
|
|||
0c32dd28eb
|
|||
0841ff3e15
|
|||
1205814767
|
|||
67eee854c0
|
|||
a4d5388531
|
|||
07f07d16ad
|
|||
a43acb8537
|
|||
d24486dfb4
|
|||
a2d7256948
|
|||
4615467616
|
|||
417802a9b4
|
|||
a92fda6560
|
|||
7d7774072c
|
|||
b03cda55ac
|
|||
eec0a1d8f0
|
|||
2df164b697
|
|||
c9db06b418
|
|||
fd6b276fc9
|
|||
4a9b6a91e0
|
|||
![]() |
324ff14fdf | ||
![]() |
3e2ccec808 | ||
![]() |
949cbcf393 | ||
![]() |
32ce3cbfd8 | ||
![]() |
7a050304be | ||
![]() |
a85334f396 | ||
![]() |
1a85f6ded5 | ||
![]() |
b33d89a508 | ||
![]() |
b52462a3cb |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,6 +1,7 @@
|
|||||||
*~
|
*~
|
||||||
O.*
|
O.*
|
||||||
*.swp
|
*.swp
|
||||||
|
*.bak
|
||||||
*BAK.adl
|
*BAK.adl
|
||||||
bin/
|
bin/
|
||||||
db/
|
db/
|
||||||
@@ -16,3 +17,4 @@ auto_settings.sav*
|
|||||||
auto_positions.sav*
|
auto_positions.sav*
|
||||||
.ccfxprepdir/
|
.ccfxprepdir/
|
||||||
*.local
|
*.local
|
||||||
|
*_history
|
||||||
|
231
README.md
231
README.md
@@ -1,8 +1,229 @@
|
|||||||
# motorAcs
|
motorDSM
|
||||||
EPICS motor drivers for the following [Advanced Control Systems Corporation](http://www.acsmotion.com) controllers: MCB-4B
|
==========
|
||||||
|
|
||||||
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.
|
EPICS motor drivers for the following [Dynamic Structures and Materials](https://www.dynamic-structures.com/) motor controllers: MD-90
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
# Running an example IOC
|
||||||
|
|
||||||
|
To run the example IOC, build the packages listed below, then:
|
||||||
|
|
||||||
|
1. Follow the steps in "Configuring the system for attached controllers" below.
|
||||||
|
2. Set the "EPICS_CA_ADDR_LIST" environment variable to include the IP address of the server.
|
||||||
|
If it's running on the same computer, you can use the loopback IP address.
|
||||||
|
`export EPICS_CA_ADDR_LIST='127.0.0.1'`
|
||||||
|
3. 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. Edit this file to use more than one unit; simply comment out the ones you don't need.
|
||||||
|
|
||||||
|
4. Test using the `caget` and `caput` arguments as described in the "Example usage" section below.
|
||||||
|
|
||||||
|
# Configuring the system for attached controllers
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
The following steps must be used in either st.cmd.md90 (for a single unit) or in st.cmd.md90.multiple (for multiple units).
|
||||||
|
st.cmd.md90.multiple includes 8 motors predefined on /dev/ttyUSB0 through /dev/ttyUSB7. Comment out all motors you don't need.
|
||||||
|
|
||||||
|
**1. Define a new serial port named "serial0" and set the location of the physical port**
|
||||||
|
`drvAsynSerialPortConfigure([serial name], [device location], 0, 0, 0)`
|
||||||
|
*e.g., `drvAsynSerialPortConfigure("serial0", "/dev/ttyUSB0", 0, 0, 0)`*
|
||||||
|
|
||||||
|
**2. Configure the port**
|
||||||
|
- Baud = 115200
|
||||||
|
- Bits = 8
|
||||||
|
- Parity = none
|
||||||
|
- Stop bits = 1
|
||||||
|
- Input end of message: "\r"
|
||||||
|
- Output end of message: "\r"
|
||||||
|
- Trace IO mask: 2
|
||||||
|
```
|
||||||
|
asynSetOption([serial name], 0, "baud", "115200")
|
||||||
|
asynSetOption([serial name], 0, "bits", "8")
|
||||||
|
asynSetOption([serial name], 0, "parity", "none")
|
||||||
|
asynSetOption([serial name], 0, "stop", "1")
|
||||||
|
asynOctetSetInputEos("serial0", 0, "\r")
|
||||||
|
asynOctetSetOutputEos("serial0", 0, "\r")
|
||||||
|
asynSetTraceIOMask("serial0", 0, 2)
|
||||||
|
```
|
||||||
|
where `[serial name]` is the name you assigned in step 1, surrounded by double quotes.
|
||||||
|
|
||||||
|
**3. Set initial parameters**
|
||||||
|
- Power supply enabled (`EPS` command)
|
||||||
|
- Deadband = 10 nm (`SDB 10` command)
|
||||||
|
```
|
||||||
|
asynOctetConnect("initConnection", [serial name], 0)
|
||||||
|
asynOctetWrite("initConnection", "EPS")
|
||||||
|
asynOctetWrite("initConnection", "SDB 10")
|
||||||
|
asynOctetDisconnect('initConnection')
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. Create MD90 Controller object**
|
||||||
|
`MD90CreateController([controller name], [serial name], 1, 100, 5000)`
|
||||||
|
where `[controller name]` is the name of the motor to assign. Convention is to use "MD90n", starting with n=0.
|
||||||
|
|
||||||
|
**5. Intialize the IOC**
|
||||||
|
After the call to `iocInit` (still in the st.cmd.md90[.multiple] file), issue the following commands for each motor. The example below uses `DSM:m0` but it should be run for each line described in motor.substitutions.md90 (or motor.substitutions.md90.multiple).
|
||||||
|
````
|
||||||
|
dbpf("DSM:m0.RTRY", "0") #sets retries to 0; this is automatic on the MD90
|
||||||
|
dbpf("DSM:m0.TWV", "0.1") #Tweak distance
|
||||||
|
dbpf("DSM:m0.VMAX", "1.0") #Sets max velocity to 1 mm/s
|
||||||
|
dbpf("DSM:m0.HVEL", "1.0") #Sets max velocity to 1 mm/s
|
||||||
|
````
|
||||||
|
|
||||||
|
**6. Update the substitutions file**
|
||||||
|
Save and close the st.cmd file you've been configuring, then open the motor substitutions file (motor.substitutions.md90[.multiple]).
|
||||||
|
Ensure the values in the `pattern` block's `PORT` field match the names used in the std.cmd file.
|
||||||
|
Note that, despite this field being called "Port", they use the names of the MD90 Controller object defined above (by default, MD900, MD901, etc.
|
||||||
|
Do __not__ use the direct serial port names (by default, serial0, serial1, etc.).
|
||||||
|
|
||||||
|
|
||||||
|
# Compiling motorDSM
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
------------------------
|
||||||
|
# Example usage
|
||||||
|
|
||||||
|
After building, run the example IOC described at the top of this section in one terminal window.
|
||||||
|
Open another terminal window and navigate to [EPICS install directory]/epics-base/bin/linux-x86_64/ (or wherever you built EPICS base.
|
||||||
|
Use the commands `caput` and `caget` to set and read process variables.
|
||||||
|
|
||||||
|
For example, to get the current position, use `./caget DSM:m0.REP`. This reads the REP variable, which is the "Raw Encoder Position". Set m0 to m1, m2, etc. for multiple motors.
|
||||||
|
|
||||||
|
Other examples
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Homing the motor (must be done before you can issue position commands):
|
||||||
|
`./caput DSM:m0.HOMF 1 #Begins homing sequence in the forward direction`
|
||||||
|
`./caput DSM:m0.HOMR 1 #Begins homing sequence in the reverse direction`
|
||||||
|
|
||||||
|
Moving to a position target:
|
||||||
|
`./caput DSM:m0.VAL 2.345 #Moves to 2.345 mm`
|
||||||
|
|
||||||
|
Setting a velocity target:
|
||||||
|
`./caput DSM:m0.VELO 0.5 #Sets velocity target to 0.5 mm/s`
|
||||||
|
(Note that velocity targets are appropriate only. They adjust the step rate of the motor and are not guaranteed to be exact.)
|
||||||
|
|
||||||
|
A note aboue velocity targets
|
||||||
|
-----------------------------
|
||||||
|
The I-20 motor driven by the MD-90 is a closed loop "step and repeat" motor that takes full steps towards its position target until it is
|
||||||
|
close, then will perform linear extensions to close the loop on the target position. This is handled internally on the MD-90, not by
|
||||||
|
EPICS.
|
||||||
|
|
||||||
|
The Velocity target parameter sets the step frequency
|
||||||
|
at which the motor operates on its way to the target position. The speed is not closed loop, and will depend on external loads, environmental
|
||||||
|
conditions, etc. A speed target of 1 mm/s will generate a roughly 1 mm/s motion, but it is not guaranteed.
|
||||||
|
|
||||||
|
Additionally, due to the way EPICS operates, setting VELO will not immediately send a command to the MD90. Instead, EPICS remembers the last value you set, and will set this new
|
||||||
|
velocity target when it sends the next move command. **However, the motor must not be in servo mode to accept a new velocity target.**
|
||||||
|
|
||||||
|
The motor enters servo mode when you send a new position target, and stays in servo mode until you issue a Stop command
|
||||||
|
(by setting the `DSM:m0.STOP` parameter to 1).
|
||||||
|
|
||||||
|
If you do not disable servo prior to issuing a Move command at the new velocity, then VELO will become out of sync with the actual motor
|
||||||
|
velocity, and EPICS will return error 3 "Cannot execute while moving" in its console each time you issue a Move command.
|
||||||
|
This is because each Move command internally sends a "Set step frequenc" command, which will error if you do not Stop the motor first.
|
||||||
|
Reading the VELO parameter at this point will return the wrong value- it returns the value you requested, not the actual speed setting
|
||||||
|
on the motor.
|
||||||
|
To fix this, you must Stop the motor, then send a new Move command. At
|
||||||
|
|
||||||
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.
|
|
||||||
|
@@ -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);
|
|
||||||
}
|
|
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
FILENAME... MCB4BDriver.h
|
|
||||||
USAGE... Motor driver support for the ACS MCB-4B controller.
|
|
||||||
|
|
||||||
Mark Rivers
|
|
||||||
March 1, 2012
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "asynMotorController.h"
|
|
||||||
#include "asynMotorAxis.h"
|
|
||||||
|
|
||||||
#define MAX_MCB4B_AXES 4
|
|
||||||
|
|
||||||
// No controller-specific parameters yet
|
|
||||||
#define NUM_MCB4B_PARAMS 0
|
|
||||||
|
|
||||||
class epicsShareClass MCB4BAxis : public asynMotorAxis
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/* These are the methods we override from the base class */
|
|
||||||
MCB4BAxis(class MCB4BController *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);
|
|
||||||
|
|
||||||
private:
|
|
||||||
MCB4BController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
|
||||||
* Abbreviated because it is used very frequently */
|
|
||||||
asynStatus sendAccelAndVelocity(double accel, double velocity);
|
|
||||||
|
|
||||||
friend class MCB4BController;
|
|
||||||
};
|
|
||||||
|
|
||||||
class epicsShareClass MCB4BController : public asynMotorController {
|
|
||||||
public:
|
|
||||||
MCB4BController(const char *portName, const char *MCB4BPortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
|
|
||||||
|
|
||||||
void report(FILE *fp, int level);
|
|
||||||
MCB4BAxis* getAxis(asynUser *pasynUser);
|
|
||||||
MCB4BAxis* getAxis(int axisNo);
|
|
||||||
|
|
||||||
friend class MCB4BAxis;
|
|
||||||
};
|
|
@@ -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)
|
|
||||||
|
|
||||||
|
|
@@ -1,4 +1,5 @@
|
|||||||
|
EPICS_BASE=
|
||||||
MOTOR=
|
MOTOR=
|
||||||
-include $(MOTOR)/modules/RELEASE.$(EPICS_HOST_ARCH).local
|
-include $(MOTOR)/modules/RELEASE.$(EPICS_HOST_ARCH).local
|
||||||
# path to motorAcs is needed to build the IOC inside motorAcs, but outside motor
|
# path to motorDsm is needed to build the IOC inside motorDsm, but outside motor
|
||||||
MOTOR_ACS=
|
MOTOR_DSM=
|
||||||
|
@@ -2,6 +2,6 @@
|
|||||||
|
|
||||||
# Use motor/module's generated release file when buidling inside motor
|
# Use motor/module's generated release file when buidling inside motor
|
||||||
-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local
|
-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
|
-include $(TOP)/configure/RELEASE.local
|
||||||
|
|
||||||
|
@@ -1,5 +1,42 @@
|
|||||||
|
# motorDSM Releases
|
||||||
|
|
||||||
|
## __v0.9.0-alpha__
|
||||||
|
|
||||||
|
### Changes since motorAcs R1-1-1
|
||||||
|
|
||||||
|
#### New features
|
||||||
|
* Global rename Acs -> DSM and MCB-4B -> MD-90
|
||||||
|
* Updated motor controller and axis methods to work with the DSM MD-90 controller
|
||||||
|
* Updated example IOC startup scripts for the MD-90
|
||||||
|
|
||||||
|
#### Modifications to existing features
|
||||||
|
* Removed Acs controller interface
|
||||||
|
|
||||||
|
#### Bug fixes
|
||||||
|
* None
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# motorAcs Releases
|
# motorAcs Releases
|
||||||
|
|
||||||
|
## __R1-1-1 (2023-04-11)__
|
||||||
|
R1-1-1 is a release based on the master branch.
|
||||||
|
|
||||||
|
### Changes since R1-1
|
||||||
|
|
||||||
|
#### New features
|
||||||
|
* None
|
||||||
|
|
||||||
|
#### Modifications to existing features
|
||||||
|
* None
|
||||||
|
|
||||||
|
#### Bug fixes
|
||||||
|
* None
|
||||||
|
|
||||||
|
#### Continuous integration
|
||||||
|
* Added ci-scripts (v3.0.1)
|
||||||
|
* Switched from Travis CI to Github Actions
|
||||||
|
|
||||||
## __R1-1 (2020-05-12)__
|
## __R1-1 (2020-05-12)__
|
||||||
R1-1 is a release based on the master branch.
|
R1-1 is a release based on the master branch.
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
# ### ACS_MCB4B.iocsh ###
|
# ### DSM_MD90.iocsh ###
|
||||||
|
|
||||||
#- ###################################################
|
#- ###################################################
|
||||||
#- PORT - Serial port for communications
|
#- PORT - Serial port for communications
|
||||||
@@ -17,9 +17,9 @@
|
|||||||
#- Default: 100
|
#- Default: 100
|
||||||
#- ###################################################
|
#- ###################################################
|
||||||
|
|
||||||
# ACS MCB-4B serial connection settings
|
# DSM MD-90 serial connection settings
|
||||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=19200, BITS=8, STOP=1, PARITY=none")
|
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=115200, BITS=8, STOP=1, PARITY=none")
|
||||||
asynOctetSetInputEos( "$(PORT)", -1, "\r")
|
asynOctetSetInputEos( "$(PORT)", -1, "\r")
|
||||||
asynOctetSetOutputEos("$(PORT)", -1, "\r")
|
asynOctetSetOutputEos("$(PORT)", -1, "\r")
|
||||||
|
|
||||||
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)))
|
@@ -1,6 +1,6 @@
|
|||||||
TOP = ../..
|
TOP = ../..
|
||||||
include $(TOP)/configure/CONFIG
|
include $(TOP)/configure/CONFIG
|
||||||
|
|
||||||
IOCSH += ACS_MCB4B.iocsh
|
IOCSH += DSM_MD90.iocsh
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
502
dsmApp/src/MD90Driver.cpp
Normal file
502
dsmApp/src/MD90Driver.cpp
Normal 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 / COUNTS_PER_STEP));
|
||||||
|
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 * COUNTS_PER_STEP;
|
||||||
|
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);
|
||||||
|
}
|
50
dsmApp/src/MD90Driver.h
Normal file
50
dsmApp/src/MD90Driver.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
FILENAME... MD90Driver.h
|
||||||
|
USAGE... Motor driver support for the DSM MD-90 controller.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "asynMotorController.h"
|
||||||
|
#include "asynMotorAxis.h"
|
||||||
|
|
||||||
|
#define MAX_MD90_AXES 1
|
||||||
|
|
||||||
|
// No controller-specific parameters yet
|
||||||
|
#define NUM_MD90_PARAMS 0
|
||||||
|
|
||||||
|
#define COUNTS_PER_STEP 1000.0 //Number of encoder counts per motor step (measured by testing)
|
||||||
|
|
||||||
|
class epicsShareClass MD90Axis : public asynMotorAxis
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/* These are the methods we override from the base class */
|
||||||
|
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 setClosedLoop(bool closedLoop);
|
||||||
|
asynStatus setIGain(double iGain);
|
||||||
|
asynStatus doMoveToHome();
|
||||||
|
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
class epicsShareClass MD90Controller : public asynMotorController {
|
||||||
|
public:
|
||||||
|
MD90Controller(const char *portName, const char *MD90PortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
|
||||||
|
|
||||||
|
void report(FILE *fp, int level);
|
||||||
|
MD90Axis* getAxis(asynUser *pasynUser);
|
||||||
|
MD90Axis* getAxis(int axisNo);
|
||||||
|
|
||||||
|
friend class MD90Axis;
|
||||||
|
};
|
@@ -5,18 +5,18 @@ include $(TOP)/configure/CONFIG
|
|||||||
# The following are used for debugging messages.
|
# The following are used for debugging messages.
|
||||||
USR_CXXFLAGS += -DDEBUG
|
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.
|
# Advanced Control Systems driver support.
|
||||||
SRCS += devMCB4B.c drvMCB4B.c
|
SRCS += devMD90.c drvMD90.c
|
||||||
SRCS += MCB4BDriver.cpp
|
SRCS += MD90Driver.cpp
|
||||||
|
|
||||||
Acs_LIBS += motor asyn
|
dsm_LIBS += motor asyn
|
||||||
Acs_LIBS += $(EPICS_BASE_IOC_LIBS)
|
dsm_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||||
|
|
||||||
include $(TOP)/configure/RULES
|
include $(TOP)/configure/RULES
|
||||||
|
|
11
dsmApp/src/devDsmMotor.dbd
Normal file
11
dsmApp/src/devDsmMotor.dbd
Normal 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)
|
||||||
|
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
/* File: devMCB4B.cc */
|
/* File: devMD90.cc */
|
||||||
|
|
||||||
/* Device Support Routines for motor */
|
/* Device Support Routines for motor */
|
||||||
/*
|
/*
|
||||||
@@ -20,21 +20,21 @@
|
|||||||
#include "motorRecord.h"
|
#include "motorRecord.h"
|
||||||
#include "motor.h"
|
#include "motor.h"
|
||||||
#include "motordevCom.h"
|
#include "motordevCom.h"
|
||||||
#include "drvMCB4B.h"
|
#include "drvMD90.h"
|
||||||
#include "epicsExport.h"
|
#include "epicsExport.h"
|
||||||
|
|
||||||
#define STATIC static
|
#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)
|
#define NINT(f) (long)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||||
|
|
||||||
volatile int devMCB4BDebug = 0;
|
volatile int devMD90Debug = 0;
|
||||||
extern "C" {epicsExportAddress(int, devMCB4BDebug);}
|
extern "C" {epicsExportAddress(int, devMD90Debug);}
|
||||||
|
|
||||||
static inline void Debug(int level, const char *format, ...) {
|
static inline void Debug(int level, const char *format, ...) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (level < devMCB4BDebug)
|
if (level < devMD90Debug)
|
||||||
{
|
{
|
||||||
va_list pVar;
|
va_list pVar;
|
||||||
va_start(pVar, format);
|
va_start(pVar, format);
|
||||||
@@ -45,35 +45,35 @@ static inline void Debug(int level, const char *format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Debugging levels:
|
/* Debugging levels:
|
||||||
* devMCB4BDebug >= 3 Print new part of command and command string so far
|
* devMD90Debug >= 3 Print new part of command and command string so far
|
||||||
* at the end of MCB4B_build_trans
|
* at the end of MD90_build_trans
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* ----------------Create the dsets for devMCB4B----------------- */
|
/* ----------------Create the dsets for devMD90----------------- */
|
||||||
STATIC struct driver_table *drvtabptr;
|
STATIC struct driver_table *drvtabptr;
|
||||||
STATIC long MCB4B_init(int);
|
STATIC long MD90_init(int);
|
||||||
STATIC long MCB4B_init_record(void *);
|
STATIC long MD90_init_record(void *);
|
||||||
STATIC long MCB4B_start_trans(struct motorRecord *);
|
STATIC long MD90_start_trans(struct motorRecord *);
|
||||||
STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd, double *, struct motorRecord *);
|
STATIC RTN_STATUS MD90_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||||
STATIC RTN_STATUS MCB4B_end_trans(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,
|
motor_update_values,
|
||||||
MCB4B_start_trans,
|
MD90_start_trans,
|
||||||
MCB4B_build_trans,
|
MD90_build_trans,
|
||||||
MCB4B_end_trans
|
MD90_end_trans
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" {epicsExportAddress(dset,devMCB4B);}
|
extern "C" {epicsExportAddress(dset,devMD90);}
|
||||||
|
|
||||||
|
|
||||||
/* --------------------------- program data --------------------- */
|
/* --------------------------- program data --------------------- */
|
||||||
/* This table is used to define the command types */
|
/* This table is used to define the command types */
|
||||||
|
|
||||||
static msg_types MCB4B_table[] = {
|
static msg_types MD90_table[] = {
|
||||||
MOTION, /* MOVE_ABS */
|
MOTION, /* MOVE_ABS */
|
||||||
MOTION, /* MOVE_REL */
|
MOTION, /* MOVE_REL */
|
||||||
MOTION, /* HOME_FOR */
|
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 --------------------- */
|
/* --------------------------- program data --------------------- */
|
||||||
|
|
||||||
|
|
||||||
/* initialize device support for MCB4B stepper motor */
|
/* initialize device support for MD90 stepper motor */
|
||||||
STATIC long MCB4B_init(int after)
|
STATIC long MD90_init(int after)
|
||||||
{
|
{
|
||||||
long rtnval;
|
long rtnval;
|
||||||
|
|
||||||
Debug(5, "MCB4B_init: entry\n");
|
Debug(5, "MD90_init: entry\n");
|
||||||
if (!after)
|
if (!after)
|
||||||
{
|
{
|
||||||
drvtabptr = &MCB4B_access;
|
drvtabptr = &MD90_access;
|
||||||
(drvtabptr->init)();
|
(drvtabptr->init)();
|
||||||
}
|
}
|
||||||
|
|
||||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MCB4B_cards);
|
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MD90_cards);
|
||||||
Debug(5, "MCB4B_init: exit\n");
|
Debug(5, "MD90_init: exit\n");
|
||||||
return(rtnval);
|
return(rtnval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* initialize a record instance */
|
/* initialize a record instance */
|
||||||
STATIC long MCB4B_init_record(void *arg)
|
STATIC long MD90_init_record(void *arg)
|
||||||
{
|
{
|
||||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||||
long rtnval;
|
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,
|
rtnval = motor_init_record_com(mr, *drvtabptr->cardcnt_ptr,
|
||||||
drvtabptr, MCB4B_cards);
|
drvtabptr, MD90_cards);
|
||||||
return(rtnval);
|
return(rtnval);
|
||||||
Debug(5, "MCB4B_init_record: exit\n");
|
Debug(5, "MD90_init_record: exit\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* start building a transaction */
|
/* start building a transaction */
|
||||||
STATIC long MCB4B_start_trans(struct motorRecord *mr)
|
STATIC long MD90_start_trans(struct motorRecord *mr)
|
||||||
{
|
{
|
||||||
return(OK);
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* end building a transaction */
|
/* end building a transaction */
|
||||||
STATIC RTN_STATUS MCB4B_end_trans(struct motorRecord *mr)
|
STATIC RTN_STATUS MD90_end_trans(struct motorRecord *mr)
|
||||||
{
|
{
|
||||||
return(OK);
|
return(OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add a part to the transaction */
|
/* 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 motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||||
struct mess_node *motor_call;
|
struct mess_node *motor_call;
|
||||||
struct controller *brdptr;
|
struct controller *brdptr;
|
||||||
struct MCB4Bcontroller *cntrl;
|
struct MD90controller *cntrl;
|
||||||
char buff[30];
|
char buff[30];
|
||||||
int axis, card;
|
int axis, card;
|
||||||
RTN_STATUS rtnval;
|
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;
|
dval = (parms == NULL) ? 0.0 : *parms;
|
||||||
ival = NINT(dval);
|
ival = NINT(dval);
|
||||||
|
|
||||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
|
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
|
||||||
Debug(5, "MCB4B_build_trans: entry, motor_start_trans_com=%d\n", rtnval);
|
Debug(5, "MD90_build_trans: entry, motor_start_trans_com=%d\n", rtnval);
|
||||||
|
|
||||||
motor_call = &(trans->motor_call);
|
motor_call = &(trans->motor_call);
|
||||||
motor_call->type = MCB4B_table[command];
|
motor_call->type = MD90_table[command];
|
||||||
card = motor_call->card;
|
card = motor_call->card;
|
||||||
axis = motor_call->signal;
|
axis = motor_call->signal;
|
||||||
brdptr = (*trans->tabptr->card_array)[card];
|
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)
|
if (brdptr == NULL)
|
||||||
return(rtnval = ERROR);
|
return(rtnval = ERROR);
|
||||||
|
|
||||||
cntrl = (struct MCB4Bcontroller *) brdptr->DevicePrivate;
|
cntrl = (struct MD90controller *) brdptr->DevicePrivate;
|
||||||
|
|
||||||
|
|
||||||
if (trans->state != BUILD_STATE)
|
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);
|
strcpy(motor_call->message, mr->init);
|
||||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
|
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
|
||||||
motor_call->type = MCB4B_table[command];
|
motor_call->type = MD90_table[command];
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (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);
|
strcpy(motor_call->message, mr->prem);
|
||||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
|
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
|
||||||
motor_call->type = MCB4B_table[command];
|
motor_call->type = MD90_table[command];
|
||||||
}
|
}
|
||||||
if (strlen(mr->post) != 0)
|
if (strlen(mr->post) != 0)
|
||||||
motor_call->postmsgptr = (char *) &mr->post;
|
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:
|
case SET_VEL_BASE:
|
||||||
send=false;
|
send=false;
|
||||||
trans->state = IDLE_STATE;
|
trans->state = IDLE_STATE;
|
||||||
break; /* MCB4B does not use base velocity */
|
break; /* MD90 does not use base velocity */
|
||||||
case SET_VELOCITY:
|
case SET_VELOCITY:
|
||||||
ival = (int) (fabs(115200./dval) + 0.5);
|
ival = (int) (fabs(115200./dval) + 0.5);
|
||||||
if (ival < 2) ival=2;
|
if (ival < 2) ival=2;
|
||||||
@@ -247,7 +247,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
|
|||||||
break;
|
break;
|
||||||
case SET_ACCEL:
|
case SET_ACCEL:
|
||||||
/* dval is acceleration in steps/sec/sec */
|
/* 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) */
|
/* dval (steps/sec/sec) = 720,000/(256-R) */
|
||||||
/* or R=256-(720,000/dval) */
|
/* or R=256-(720,000/dval) */
|
||||||
ival = (int) (256-(720000./dval)+0.5);
|
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;
|
break;
|
||||||
case GO:
|
case GO:
|
||||||
/*
|
/*
|
||||||
* The MCB4B starts moving immediately on move commands, GO command
|
* The MD90 starts moving immediately on move commands, GO command
|
||||||
* does nothing
|
* does nothing
|
||||||
*/
|
*/
|
||||||
send=false;
|
send=false;
|
||||||
@@ -265,7 +265,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
|
|||||||
break;
|
break;
|
||||||
case SET_ENC_RATIO:
|
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
|
* command
|
||||||
*/
|
*/
|
||||||
send=false;
|
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);
|
sprintf(motor_call->message, "#%02dQ", axis);
|
||||||
break;
|
break;
|
||||||
case JOG:
|
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);
|
ival = (int) (fabs(115200./dval) + 0.5);
|
||||||
if (ival < 2) ival=2;
|
if (ival < 2) ival=2;
|
||||||
if (ival > 65535) ival = 65535;
|
if (ival > 65535) ival = 65535;
|
||||||
sprintf(motor_call->message, "#%02dC=%ld", axis, ival);
|
sprintf(motor_call->message, "#%02dC=%ld", axis, ival);
|
||||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
rtnval = motor_end_trans_com(mr, drvtabptr);
|
||||||
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MCB4B_cards);
|
rtnval = (RTN_STATUS) motor_start_trans_com(mr, MD90_cards);
|
||||||
motor_call->type = MCB4B_table[command];
|
motor_call->type = MD90_table[command];
|
||||||
if (dval > 0.) {
|
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);
|
sprintf(motor_call->message, "#%02dM+1000000", axis);
|
||||||
} else {
|
} else {
|
||||||
/* This is a negative move in MCB4B coordinates */
|
/* This is a negative move in MD90 coordinates */
|
||||||
sprintf(motor_call->message, "#%02dM-1000000", axis);
|
sprintf(motor_call->message, "#%02dM-1000000", axis);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -325,7 +325,7 @@ STATIC RTN_STATUS MCB4B_build_trans(motor_cmnd command, double *parms, struct mo
|
|||||||
return(rtnval);
|
return(rtnval);
|
||||||
else {
|
else {
|
||||||
rtnval = motor_end_trans_com(mr, drvtabptr);
|
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);
|
return (rtnval);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,4 +1,4 @@
|
|||||||
/* File: drvMCB4B.cc */
|
/* File: drvMD90.cc */
|
||||||
|
|
||||||
/* Device Driver Support routines for motor */
|
/* Device Driver Support routines for motor */
|
||||||
/*
|
/*
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errlog.h>
|
#include <errlog.h>
|
||||||
#include "motor.h"
|
#include "motor.h"
|
||||||
#include "AcsRegister.h"
|
#include "dsmRegister.h"
|
||||||
#include "drvMCB4B.h"
|
#include "drvMD90.h"
|
||||||
#include "asynOctetSyncIO.h"
|
#include "asynOctetSyncIO.h"
|
||||||
#include "epicsExport.h"
|
#include "epicsExport.h"
|
||||||
|
|
||||||
@@ -35,14 +35,14 @@
|
|||||||
|
|
||||||
#define TIMEOUT 2.0 /* Command timeout in sec */
|
#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;
|
volatile int drvMD90Debug = 0;
|
||||||
extern "C" {epicsExportAddress(int, drvMCB4BDebug);}
|
extern "C" {epicsExportAddress(int, drvMD90Debug);}
|
||||||
|
|
||||||
static inline void Debug(int level, const char *format, ...) {
|
static inline void Debug(int level, const char *format, ...) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (level < drvMCB4BDebug)
|
if (level < drvMD90Debug)
|
||||||
{
|
{
|
||||||
va_list pVar;
|
va_list pVar;
|
||||||
va_start(pVar, format);
|
va_start(pVar, format);
|
||||||
@@ -53,14 +53,14 @@ static inline void Debug(int level, const char *format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Debugging notes:
|
/* Debugging notes:
|
||||||
* drvMCB4BDebug == 0 No debugging information is printed
|
* drvMD90Debug == 0 No debugging information is printed
|
||||||
* drvMCB4BDebug >= 1 Warning information is printed
|
* drvMD90Debug >= 1 Warning information is printed
|
||||||
* drvMCB4BDebug >= 2 Time-stamped messages are printed for each string
|
* drvMD90Debug >= 2 Time-stamped messages are printed for each string
|
||||||
* sent to and received from the controller
|
* 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" */
|
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||||
#include "motordrvComCode.h"
|
#include "motordrvComCode.h"
|
||||||
@@ -78,7 +78,7 @@ STATIC void query_done(int, int, struct mess_node *);
|
|||||||
|
|
||||||
/*----------------functions-----------------*/
|
/*----------------functions-----------------*/
|
||||||
|
|
||||||
struct driver_table MCB4B_access =
|
struct driver_table MD90_access =
|
||||||
{
|
{
|
||||||
motor_init,
|
motor_init,
|
||||||
motor_send,
|
motor_send,
|
||||||
@@ -102,16 +102,16 @@ struct driver_table MCB4B_access =
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
struct drvMCB4B_drvet
|
struct drvMD90_drvet
|
||||||
{
|
{
|
||||||
long number;
|
long number;
|
||||||
long (*report) (int);
|
long (*report) (int);
|
||||||
long (*init) (void);
|
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)
|
static long report(int level)
|
||||||
{
|
{
|
||||||
int card;
|
int card;
|
||||||
struct MCB4Bcontroller *cntrl;
|
struct MD90controller *cntrl;
|
||||||
|
|
||||||
if (MCB4B_num_cards <=0)
|
if (MD90_num_cards <=0)
|
||||||
printf(" NO MCB4B controllers found\n");
|
printf(" NO MD90 controllers found\n");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (card = 0; card < MCB4B_num_cards; card++) {
|
for (card = 0; card < MD90_num_cards; card++) {
|
||||||
if (motor_state[card]) {
|
if (motor_state[card]) {
|
||||||
cntrl = (struct MCB4Bcontroller *) motor_state[card]->DevicePrivate;
|
cntrl = (struct MD90controller *) motor_state[card]->DevicePrivate;
|
||||||
printf(" MCB4B controller %d, port=%s, id: %s \n",
|
printf(" MD90 controller %d, port=%s, id: %s \n",
|
||||||
card, cntrl->port,
|
card, cntrl->port,
|
||||||
motor_state[card]->ident);
|
motor_state[card]->ident);
|
||||||
}
|
}
|
||||||
@@ -148,10 +148,10 @@ static long init()
|
|||||||
* support
|
* support
|
||||||
*/
|
*/
|
||||||
/* Check for setup */
|
/* Check for setup */
|
||||||
if (MCB4B_num_cards <= 0)
|
if (MD90_num_cards <= 0)
|
||||||
{
|
{
|
||||||
Debug(1, "init: *MCB4B driver disabled*\n");
|
Debug(1, "init: *MD90 driver disabled*\n");
|
||||||
Debug(1, "MCB4BSetup() is missing from startup script.\n");
|
Debug(1, "MD90Setup() is missing from startup script.\n");
|
||||||
return (ERROR);
|
return (ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +170,7 @@ STATIC void query_done(int card, int axis, struct mess_node *nodeptr)
|
|||||||
*********************************************************/
|
*********************************************************/
|
||||||
STATIC void start_status(int card)
|
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,
|
* single command. This needs to be done on an axis-by-axis basis,
|
||||||
* so this function does nothing
|
* 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)
|
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 && nodeptr->postmsgptr != 0)
|
||||||
{
|
{
|
||||||
send_mess(card, nodeptr->postmsgptr, NULL);
|
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);
|
recv_mess(card, buff, WAIT);
|
||||||
nodeptr->postmsgptr = NULL;
|
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() */
|
/* send_mess() */
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
STATIC RTN_STATUS send_mess(int card, const char *com, const char *name)
|
STATIC RTN_STATUS send_mess(int card, const char *com, const char *name)
|
||||||
{
|
{
|
||||||
struct MCB4Bcontroller *cntrl;
|
struct MD90controller *cntrl;
|
||||||
size_t nwrite;
|
size_t nwrite;
|
||||||
|
|
||||||
/* Check that card exists */
|
/* 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 the string is NULL just return */
|
||||||
if (strlen(com) == 0) return(OK);
|
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",\
|
Debug(2, "send_mess: sending message to card %d, message=%s\n",\
|
||||||
card, com);
|
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() */
|
/* recv_mess() */
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
STATIC int recv_mess(int card, char *com, int flag)
|
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;
|
double timeout;
|
||||||
size_t nread=0;
|
size_t nread=0;
|
||||||
asynStatus status;
|
asynStatus status;
|
||||||
struct MCB4Bcontroller *cntrl;
|
struct MD90controller *cntrl;
|
||||||
int flush;
|
int flush;
|
||||||
int eomReason;
|
int eomReason;
|
||||||
|
|
||||||
@@ -324,7 +324,7 @@ STATIC int recv_mess(int card, char *com, int flag)
|
|||||||
return (-1);
|
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",\
|
Debug(3, "recv_mess entry: card %d, flag=%d\n",\
|
||||||
card, flag);
|
card, flag);
|
||||||
@@ -363,18 +363,18 @@ STATIC int recv_mess(int card, char *com, int flag)
|
|||||||
|
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
/* Setup system configuration */
|
/* Setup system configuration */
|
||||||
/* MCB4BSetup() */
|
/* MD90Setup() */
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
RTN_STATUS
|
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 scan_rate) /* polling rate - 1/60 sec units */
|
||||||
{
|
{
|
||||||
int itera;
|
int itera;
|
||||||
|
|
||||||
if (num_cards < 1 || num_cards > MCB4B_NUM_CARDS)
|
if (num_cards < 1 || num_cards > MD90_NUM_CARDS)
|
||||||
MCB4B_num_cards = MCB4B_NUM_CARDS;
|
MD90_num_cards = MD90_NUM_CARDS;
|
||||||
else
|
else
|
||||||
MCB4B_num_cards = num_cards;
|
MD90_num_cards = num_cards;
|
||||||
|
|
||||||
/* Set motor polling task rate */
|
/* Set motor polling task rate */
|
||||||
if (scan_rate >= 1 && scan_rate <= 60)
|
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
|
* 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
|
* 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
|
* if it really exists, which is not a serious problem since this is just
|
||||||
* an array of pointers.
|
* an array of pointers.
|
||||||
*/
|
*/
|
||||||
motor_state = (struct controller **) malloc(MCB4B_num_cards *
|
motor_state = (struct controller **) malloc(MD90_num_cards *
|
||||||
sizeof(struct controller *));
|
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;
|
motor_state[itera] = (struct controller *) NULL;
|
||||||
return (OK);
|
return (OK);
|
||||||
}
|
}
|
||||||
@@ -400,20 +400,20 @@ MCB4BSetup(int num_cards, /* maximum number of controllers in system */
|
|||||||
|
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
/* Configure a controller */
|
/* Configure a controller */
|
||||||
/* MCB4BConfig() */
|
/* MD90Config() */
|
||||||
/*****************************************************/
|
/*****************************************************/
|
||||||
RTN_STATUS
|
RTN_STATUS
|
||||||
MCB4BConfig(int card, /* card being configured */
|
MD90Config(int card, /* card being configured */
|
||||||
const char *name) /* port name for asyn */
|
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);
|
return (ERROR);
|
||||||
|
|
||||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct MCB4Bcontroller));
|
motor_state[card]->DevicePrivate = malloc(sizeof(struct MD90controller));
|
||||||
cntrl = (struct MCB4Bcontroller *) motor_state[card]->DevicePrivate;
|
cntrl = (struct MD90controller *) motor_state[card]->DevicePrivate;
|
||||||
strcpy(cntrl->port, name);
|
strcpy(cntrl->port, name);
|
||||||
return (OK);
|
return (OK);
|
||||||
}
|
}
|
||||||
@@ -429,7 +429,7 @@ MCB4BConfig(int card, /* card being configured */
|
|||||||
STATIC int motor_init()
|
STATIC int motor_init()
|
||||||
{
|
{
|
||||||
struct controller *brdptr;
|
struct controller *brdptr;
|
||||||
struct MCB4Bcontroller *cntrl;
|
struct MD90controller *cntrl;
|
||||||
int card_index, motor_index;
|
int card_index, motor_index;
|
||||||
char buff[BUFF_SIZE];
|
char buff[BUFF_SIZE];
|
||||||
int total_axis = 0;
|
int total_axis = 0;
|
||||||
@@ -439,21 +439,21 @@ STATIC int motor_init()
|
|||||||
initialized = true; /* Indicate that driver is initialized. */
|
initialized = true; /* Indicate that driver is initialized. */
|
||||||
|
|
||||||
/* Check for setup */
|
/* Check for setup */
|
||||||
if (MCB4B_num_cards <= 0)
|
if (MD90_num_cards <= 0)
|
||||||
{
|
{
|
||||||
Debug(1, "motor_init: *MCB4B driver disabled*\n");
|
Debug(1, "motor_init: *MD90 driver disabled*\n");
|
||||||
Debug(1, "MCB4BSetup() is missing from startup script.\n");
|
Debug(1, "MD90Setup() is missing from startup script.\n");
|
||||||
return (ERROR);
|
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])
|
if (!motor_state[card_index])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
brdptr = motor_state[card_index];
|
brdptr = motor_state[card_index];
|
||||||
total_cards = card_index + 1;
|
total_cards = card_index + 1;
|
||||||
cntrl = (struct MCB4Bcontroller *) brdptr->DevicePrivate;
|
cntrl = (struct MD90controller *) brdptr->DevicePrivate;
|
||||||
|
|
||||||
/* Initialize communications channel */
|
/* Initialize communications channel */
|
||||||
success_rtn = pasynOctetSyncIO->connect(cntrl->port, 0, &cntrl->pasynUser, NULL);
|
success_rtn = pasynOctetSyncIO->connect(cntrl->port, 0, &cntrl->pasynUser, NULL);
|
||||||
@@ -498,7 +498,7 @@ STATIC int motor_init()
|
|||||||
sprintf(buff,"#%02dQ", motor_index);
|
sprintf(buff,"#%02dQ", motor_index);
|
||||||
send_mess(card_index, buff, 0);
|
send_mess(card_index, buff, 0);
|
||||||
recv_mess(card_index, buff, WAIT); /* Throw away response */
|
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->status.All = 0;
|
||||||
motor_info->no_motion_count = 0;
|
motor_info->no_motion_count = 0;
|
||||||
motor_info->encoder_position = 0;
|
motor_info->encoder_position = 0;
|
||||||
@@ -521,7 +521,7 @@ STATIC int motor_init()
|
|||||||
|
|
||||||
Debug(3, "motor_init: spawning motor task\n");
|
Debug(3, "motor_init: spawning motor task\n");
|
||||||
|
|
||||||
epicsThreadCreate((char *) "tMCB4B", epicsThreadPriorityMedium,
|
epicsThreadCreate((char *) "tMD90", epicsThreadPriorityMedium,
|
||||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
/* File: drvMCB4B.h */
|
/* File: drvMD90.h */
|
||||||
|
|
||||||
|
|
||||||
/* Device Driver Support definitions for motor */
|
/* Device Driver Support definitions for motor */
|
||||||
@@ -12,23 +12,23 @@
|
|||||||
* .01 02/24/2002 mlr initialized from drvPM304.h
|
* .01 02/24/2002 mlr initialized from drvPM304.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCdrvMCB4Bh
|
#ifndef INCdrvMD90h
|
||||||
#define INCdrvMCB4Bh 1
|
#define INCdrvMD90h 1
|
||||||
|
|
||||||
#include "motordrvCom.h"
|
#include "motordrvCom.h"
|
||||||
#include "asynDriver.h"
|
#include "asynDriver.h"
|
||||||
|
|
||||||
/* MCB4B default profile. */
|
/* MD90 default profile. */
|
||||||
|
|
||||||
#define MCB4B_NUM_CARDS 4
|
#define MD90_NUM_CARDS 4
|
||||||
#define MCB4B_NUM_CHANNELS 4
|
#define MD90_NUM_CHANNELS 4
|
||||||
|
|
||||||
#define OUTPUT_TERMINATOR "\r"
|
#define OUTPUT_TERMINATOR "\r"
|
||||||
|
|
||||||
struct MCB4Bcontroller
|
struct MD90controller
|
||||||
{
|
{
|
||||||
asynUser *pasynUser; /* asynUser structure */
|
asynUser *pasynUser; /* asynUser structure */
|
||||||
char port[80]; /* asyn port name */
|
char port[80]; /* asyn port name */
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* INCdrvMCB4Bh */
|
#endif /* INCdrvMD90h */
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
FILENAME... AcsRegister.cc
|
FILENAME... dsmRegister.cc
|
||||||
USAGE... Register ACS motor device driver shell commands.
|
USAGE... Register DSM motor device driver shell commands.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -16,40 +16,40 @@ of this distribution.
|
|||||||
**********************************************************************/
|
**********************************************************************/
|
||||||
|
|
||||||
#include <iocsh.h>
|
#include <iocsh.h>
|
||||||
#include "AcsRegister.h"
|
#include "dsmRegister.h"
|
||||||
#include "epicsExport.h"
|
#include "epicsExport.h"
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
|
||||||
// ACS Setup arguments
|
// DSM Setup arguments
|
||||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||||
static const iocshArg setupArg1 = {"Polling rate", 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 configArg0 = {"Card being configured", iocshArgInt};
|
||||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||||
|
|
||||||
static const iocshArg * const MCB4BSetupArgs[2] = {&setupArg0, &setupArg1};
|
static const iocshArg * const MD90SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||||
static const iocshArg * const MCB4BConfigArgs[2] = {&configArg0, &configArg1};
|
static const iocshArg * const MD90ConfigArgs[2] = {&configArg0, &configArg1};
|
||||||
|
|
||||||
static const iocshFuncDef setupMCB4B = {"MCB4BSetup", 2, MCB4BSetupArgs};
|
static const iocshFuncDef setupMD90 = {"MD90Setup", 2, MD90SetupArgs};
|
||||||
static const iocshFuncDef configMCB4B = {"MCB4BConfig", 2, MCB4BConfigArgs};
|
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(&setupMD90, setupMD90CallFunc);
|
||||||
iocshRegister(&configMCB4B, configMCB4BCallFunc);
|
iocshRegister(&configMD90, configMD90CallFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
epicsExportRegistrar(AcsRegister);
|
epicsExportRegistrar(dsmRegister);
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
FILENAME... AcsRegister.h
|
FILENAME... dsmRegister.h
|
||||||
USAGE... This file contains function prototypes for ACS IOC shell commands.
|
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"
|
#include "motordrvCom.h"
|
||||||
|
|
||||||
/* Function prototypes. */
|
/* Function prototypes. */
|
||||||
extern RTN_STATUS MCB4BSetup(int, int);
|
extern RTN_STATUS MD90Setup(int, int);
|
||||||
extern RTN_STATUS MCB4BConfig(int, const char *);
|
extern RTN_STATUS MD90Config(int, const char *);
|
||||||
|
|
@@ -1,7 +1,7 @@
|
|||||||
TOP = ..
|
TOP = ..
|
||||||
include $(TOP)/configure/CONFIG
|
include $(TOP)/configure/CONFIG
|
||||||
|
|
||||||
DIRS += acsIOC
|
DIRS += dsmIOC
|
||||||
|
|
||||||
include $(TOP)/configure/RULES_TOP
|
include $(TOP)/configure/RULES_TOP
|
||||||
|
|
||||||
|
@@ -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
|
|
@@ -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, ""}
|
|
||||||
}
|
|
@@ -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")
|
|
@@ -37,8 +37,8 @@ CHECK_RELEASE = YES
|
|||||||
|
|
||||||
# Include motor's CONFIG_SITE.local when building inside motor
|
# Include motor's CONFIG_SITE.local when building inside motor
|
||||||
-include $(TOP)/../../../../configure/CONFIG_SITE.local
|
-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
|
-include $(TOP)/../../configure/CONFIG_SITE.local
|
||||||
# Use acsIOC's CONFIG_SITE.local
|
# Use dsmIOC's CONFIG_SITE.local
|
||||||
-include $(TOP)/configure/CONFIG_SITE.local
|
-include $(TOP)/configure/CONFIG_SITE.local
|
||||||
|
|
6
iocs/dsmIOC/configure/EXAMPLE_RELEASE.local
Normal file
6
iocs/dsmIOC/configure/EXAMPLE_RELEASE.local
Normal 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
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# Use motor/module's generated release file when buidling inside motor
|
# Use motor/module's generated release file when buidling inside motor
|
||||||
-include $(TOP)/../../../RELEASE.$(EPICS_HOST_ARCH).local
|
-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
|
-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
|
-include $(TOP)/configure/RELEASE.local
|
@@ -11,44 +11,44 @@ include $(TOP)/configure/CONFIG
|
|||||||
#=============================
|
#=============================
|
||||||
# Build the IOC application
|
# Build the IOC application
|
||||||
|
|
||||||
PROD_IOC = acs
|
PROD_IOC = dsm
|
||||||
# acs.dbd will be created and installed
|
# dsm.dbd will be created and installed
|
||||||
DBD += acs.dbd
|
DBD += dsm.dbd
|
||||||
|
|
||||||
# acs.dbd will be made up from these files:
|
# dsm.dbd will be made up from these files:
|
||||||
acs_DBD += base.dbd
|
dsm_DBD += base.dbd
|
||||||
|
|
||||||
# Include dbd files from all support applications:
|
# Include dbd files from all support applications:
|
||||||
#ifdef ASYN
|
#ifdef ASYN
|
||||||
acs_DBD += asyn.dbd
|
dsm_DBD += asyn.dbd
|
||||||
acs_DBD += drvAsynSerialPort.dbd
|
dsm_DBD += drvAsynSerialPort.dbd
|
||||||
acs_DBD += drvAsynIPPort.dbd
|
dsm_DBD += drvAsynIPPort.dbd
|
||||||
#endif
|
#endif
|
||||||
acs_DBD += motorSupport.dbd
|
dsm_DBD += motorSupport.dbd
|
||||||
acs_DBD += devAcsMotor.dbd
|
dsm_DBD += devDsmMotor.dbd
|
||||||
|
|
||||||
# Add all the support libraries needed by this IOC
|
# Add all the support libraries needed by this IOC
|
||||||
acs_LIBS += Acs
|
dsm_LIBS += dsm
|
||||||
acs_LIBS += motor
|
dsm_LIBS += motor
|
||||||
#ifdef ASYN
|
#ifdef ASYN
|
||||||
acs_LIBS += asyn
|
dsm_LIBS += asyn
|
||||||
#endif
|
#endif
|
||||||
#ifdef SNCSEQ
|
#ifdef SNCSEQ
|
||||||
acs_LIBS += seq pv
|
dsm_LIBS += seq pv
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
# acs_registerRecordDeviceDriver.cpp derives from acs.dbd
|
# dsm_registerRecordDeviceDriver.cpp derives from dsm.dbd
|
||||||
acs_SRCS += acs_registerRecordDeviceDriver.cpp
|
dsm_SRCS += dsm_registerRecordDeviceDriver.cpp
|
||||||
|
|
||||||
# Build the main IOC entry point on workstation OSs.
|
# Build the main IOC entry point on workstation OSs.
|
||||||
acs_SRCS_DEFAULT += acsMain.cpp
|
dsm_SRCS_DEFAULT += dsmMain.cpp
|
||||||
acs_SRCS_vxWorks += -nil-
|
dsm_SRCS_vxWorks += -nil-
|
||||||
|
|
||||||
# Add support from base/src/vxWorks if needed
|
# 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
|
# Finally link to the EPICS Base libraries
|
||||||
acs_LIBS += $(EPICS_BASE_IOC_LIBS)
|
dsm_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||||
|
|
||||||
#===========================
|
#===========================
|
||||||
|
|
@@ -1,4 +1,4 @@
|
|||||||
/* acsMain.cpp */
|
/* dsmMain.cpp */
|
||||||
/* Author: Marty Kraimer Date: 17MAR2000 */
|
/* Author: Marty Kraimer Date: 17MAR2000 */
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
26
iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90
Normal file
26
iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90
Normal 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)
|
33
iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90.multi
Normal file
33
iocs/dsmIOC/iocBoot/iocDsm/motor.substitutions.md90.multi
Normal 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)
|
@@ -1,24 +1,24 @@
|
|||||||
#!../../bin/linux-x86_64/acs
|
#!../../bin/linux-x86_64/dsm
|
||||||
|
|
||||||
< envPaths
|
< envPaths
|
||||||
|
|
||||||
cd "${TOP}"
|
cd "${TOP}"
|
||||||
|
|
||||||
## Register all support components
|
## Register all support components
|
||||||
dbLoadDatabase "dbd/acs.dbd"
|
dbLoadDatabase "dbd/dsm.dbd"
|
||||||
acs_registerRecordDeviceDriver pdbbase
|
dsm_registerRecordDeviceDriver pdbbase
|
||||||
|
|
||||||
cd "${TOP}/iocBoot/${IOC}"
|
cd "${TOP}/iocBoot/${IOC}"
|
||||||
|
|
||||||
|
|
||||||
## motorUtil (allstop & alldone)
|
## motorUtil (allstop & alldone)
|
||||||
dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=acs:")
|
dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=dsm:")
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
||||||
iocInit
|
iocInit
|
||||||
|
|
||||||
## motorUtil (allstop & alldone)
|
## motorUtil (allstop & alldone)
|
||||||
motorUtilInit("acs:")
|
motorUtilInit("dsm:")
|
||||||
|
|
||||||
# Boot complete
|
# Boot complete
|
38
iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90
Normal file
38
iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90
Normal 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")
|
178
iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90.multi
Normal file
178
iocs/dsmIOC/iocBoot/iocDsm/st.cmd.md90.multi
Normal 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")
|
Reference in New Issue
Block a user