100 Commits

Author SHA1 Message Date
75a1ff060d Added speed algorithm description 2024-08-06 16:30:44 -05:00
f85ae07d2b Update README.md
Missed a ' mark
2024-08-06 15:21:25 -05:00
3ecb9676c0 Update README.md
Clearer explanations
2024-08-06 12:54:43 -05:00
03a93101c1 Update README.md
Fixed some markdown formatting
2024-08-06 11:09:15 -05:00
95c227a553 Update README.md
Gave example IOC usage and described more about the process of initializing motors
2024-08-06 11:07:09 -05:00
3614a806ea Removed build status from readme. 2024-08-05 12:05:38 -05:00
b25f608e98 Removed old continuous integration scripts. 2024-08-05 11:58:21 -05:00
BScatterplot
841b6f5b41 Merge pull request #5 from Binary-Coalescence/Speed-conversion-update
Fixed speed conversions
2024-08-05 11:01:22 -05:00
2379c90d90 Fixed speed conversions
Fixed speed conversions based on testing data.
2024-08-05 10:56:31 -05:00
cf26f426df Revert "Updated speed conversions"
This reverts commit c1025d711b.
2024-08-02 16:37:24 -05:00
c1025d711b Updated speed conversions
Updated speed conversions based on test data.
2024-08-02 16:31:31 -05:00
8fc33fa14d Merge branch 'dev' 2024-07-05 09:11:27 -05:00
05a223bd17 Updated release doc with ACS -> DSM updates. 2024-07-05 09:10:48 -05:00
5d706d4879 Reverted release doc to undo rename clobbering. 2024-07-05 08:54:43 -05:00
707850e879 Merge branch 'dev' 2024-06-28 16:10:22 -05:00
8ec61fb3dc Removed hard line wrapping in README to fix markdown rendering issues. 2024-06-28 16:09:50 -05:00
90b0fa8836 Cleaned up IOC startup file. 2024-06-28 16:06:46 -05:00
40cfb47f05 Made /dev/ttyUSB0 default serial port again. 2024-06-28 16:05:17 -05:00
1a4794a9b2 Clarified install instructions in README. 2024-06-28 16:04:24 -05:00
a3d6a24a01 Merge branch 'dev' 2024-06-25 15:22:01 -05:00
c8dbd0916d Merge branch 'status' into dev 2024-06-25 15:21:46 -05:00
e9ca810318 Added limit switch triggering back in for end of travel error. 2024-06-25 15:17:10 -05:00
bf7b557dd7 Added reading of persistent move state to polling. 2024-06-25 14:54:57 -05:00
0600cba84d Added reading step frequency/approx. velocity to polling. 2024-06-25 14:26:02 -05:00
51fceaf7d7 Added error printouts in IOC for motor polling codes. 2024-06-25 14:01:21 -05:00
66ef37cb10 Merge branch 'dev' 2024-06-25 12:34:09 -05:00
200b68857d Updated README about running the IOC for one or multi controllers. 2024-06-25 12:33:34 -05:00
d0532c2552 Added IOC files for running with 8 MD90 controllers. 2024-06-25 12:26:24 -05:00
45c8ff064e Updated default IOC baud rate and idle poll period. 2024-06-25 11:56:31 -05:00
4351ab56e3 Updated README for setting up IOC build config file. 2024-06-25 11:49:42 -05:00
a90eea829a Merge branch 'status' into dev 2024-06-25 11:32:22 -05:00
7b9f2870ca Added call to parseReply in remaining command methods. 2024-06-25 11:09:08 -05:00
f73608c596 Added method to parse and print out controller return strings. 2024-06-25 11:01:55 -05:00
19731d2f37 Merge branch 'dev' 2024-06-24 14:23:41 -05:00
a4012dda64 Updated README with dependencies and build instructions. 2024-06-24 14:18:45 -05:00
c812afbe4e Merge branch 'dev' 2024-06-21 16:55:30 -05:00
7551465733 Set hasEncoder and gainSupport to true. Can now set motor gain. 2024-06-21 16:36:48 -05:00
bdec17808a Added home position status to poll. 2024-06-21 16:31:17 -05:00
29a78e1023 Moved line back to fix status update problem. 2024-06-21 16:07:54 -05:00
c930a77811 Added gain checking to the poll method. 2024-06-21 15:37:33 -05:00
df98f6667a Changed iGain range from 1-100 to 1-1000. 2024-06-21 15:30:00 -05:00
37d22e58dd Removed step frequency limits. 2024-06-21 14:56:48 -05:00
8c053dfa62 Reordered status polling commands. 2024-06-21 14:53:50 -05:00
4ab244925d Updated serial port to USB adapter. 2024-06-21 14:18:49 -05:00
5d343b33d1 Merge branch 'dev' 2024-06-06 14:28:04 -05:00
0d84bb4a29 Changed to max 1 axis. 2024-06-06 14:27:15 -05:00
448e26ac23 Merge branch 'commands' into dev 2024-06-06 14:26:33 -05:00
19467e5b5b Updated method to set velocity and removed acceleration. 2024-06-06 14:20:47 -05:00
402584345f Added doMoveToHome method. 2024-06-05 16:14:40 -05:00
c5eebd9597 Added setIGain method. 2024-06-05 16:04:30 -05:00
341bbb5980 Changed motor status from atHome to Homed when GHS returns 1. 2024-06-05 15:38:57 -05:00
71ae063b23 Updated to use the setClosedLoop method to set persistent move. 2024-06-05 15:32:14 -05:00
b8b090a804 Removed setPosition method as not supported by md90. 2024-06-05 14:50:52 -05:00
273e545759 Added missing call to writeReadController to set max jog steps. 2024-06-05 14:39:35 -05:00
ba71c79a92 Updated moveVelocity command for md90. 2024-06-05 14:34:59 -05:00
996439589a Merge branch 'dev' 2024-05-24 16:18:07 -05:00
d412000373 Merge branch 'commands' into dev 2024-05-24 16:17:58 -05:00
9fa37e8cd0 Set max velocity in ioc launch script. 2024-05-24 16:14:26 -05:00
9a3d3d773d Updated subst with usable velocities and description comments. 2024-05-24 15:57:58 -05:00
6c841c9041 Fixed to disconnect real initConnection. 2024-05-24 15:47:01 -05:00
9403c24df0 Changed substitutions file to use millimeters instead of micrometers. 2024-05-24 14:56:20 -05:00
7b3675fbdf Updated internal units to encoder steps (10 nm). 2024-05-24 14:31:22 -05:00
a1827ca152 Updated ioc to set motor deadband to minimum. 2024-05-24 14:15:16 -05:00
c2cbaf6bfd Updated ioc to send enable power supply command to md90. 2024-05-24 13:41:54 -05:00
1b366684d0 Changed some record field values to better match the md90. 2024-05-24 13:41:25 -05:00
8101fcae72 Updated home command for md90. 2024-05-24 09:46:58 -05:00
629c55bba4 Updated move command for md90. 2024-05-24 09:42:53 -05:00
b616133ace Merge branch 'polling' into dev 2024-05-24 08:46:38 -05:00
c1ffe8b805 Set problem and limit flags when md90 error status returned. 2024-05-24 08:44:02 -05:00
c11e11659b Merge branch 'dev' 2024-05-23 17:28:57 -05:00
b56a1f9a35 Merge branch 'polling' into dev 2024-05-23 17:28:45 -05:00
4837e8f597 Added switch case table template for possible status codes. 2024-05-23 17:04:37 -05:00
0c32dd28eb Updated to read md90 power state. 2024-05-23 16:02:03 -05:00
0841ff3e15 Fixed incorrectly reading ints as doubles. 2024-05-23 15:54:46 -05:00
1205814767 Updated to read md90 home status. 2024-05-23 15:47:39 -05:00
67eee854c0 Changed engineering units to encoder counts for get position. 2024-05-23 14:19:43 -05:00
a4d5388531 Updated to read md90 moving status. 2024-05-23 14:12:04 -05:00
07f07d16ad Updated to read md90 position. 2024-05-23 14:05:25 -05:00
a43acb8537 Updated motor stop command string. 2024-05-22 16:55:58 -05:00
d24486dfb4 Merge branch 'rename' 2024-05-22 11:58:26 -05:00
a2d7256948 One more ACS -> DSM substitution in hidden directory. 2024-05-22 11:57:54 -05:00
4615467616 Merge branch 'rename' 2024-05-22 11:50:46 -05:00
417802a9b4 Substituted string "mcb4b" with "md90".
The following case replacements were applied (in order):
	mcb4b -> md90
	MCB4B -> MD90
	mcb-4b -> md-90
	MCB-4B -> MD-90
	MCB -> MD-90
2024-05-22 11:38:43 -05:00
a92fda6560 Substituted string "acs" with "dsm".
The following case replacements were applied (in order):
	AcsRegister -> dsmRegister
	Acs_LIBS -> dsm_LIBS
	' Acs' -> ' dsm'
	acs -> dsm
	Acs -> Dsm
	ACS -> DSM
2024-05-22 11:01:27 -05:00
7d7774072c Updated readme with new names and paths. 2024-05-20 15:05:13 -05:00
b03cda55ac Renamed "*acs*" files to "*dsm*". 2024-05-20 14:51:50 -05:00
eec0a1d8f0 Renamed *mcb4b* files to *md90*. 2024-05-20 14:41:09 -05:00
2df164b697 Merge branch 'ioc' 2024-05-20 14:24:11 -05:00
c9db06b418 Updated example IOC to use DSM prefix and zero-based indexing. 2024-05-20 14:23:12 -05:00
fd6b276fc9 Updated example IOC for one axis and to use local serial port. 2024-05-20 14:14:36 -05:00
4a9b6a91e0 Ignored additional unneeded files. 2024-05-20 14:05:54 -05:00
Kevin Peterson
324ff14fdf Updated documentation for R1-1-1 2023-04-11 10:05:42 -05:00
Kevin Peterson
3e2ccec808 Github Actions fix: set BASE env var to matrix.base 2022-11-30 14:08:05 -06:00
Kevin Peterson
949cbcf393 Don't do github actions builds for documentation changes in pull requests 2022-05-12 09:47:42 -05:00
Kevin Peterson
32ce3cbfd8 Merge pull request #2 from epics-motor/github-actions
Configured to build with github-actions
2022-04-28 13:49:36 -05:00
Kevin Peterson
7a050304be Configured to build with github-actions 2022-04-28 13:48:49 -05:00
Kevin Peterson
a85334f396 Eliminated calls to os.system(). Example IOCs now build on Windows (VS2017). 2020-06-17 09:29:35 -05:00
Kevin Peterson
1a85f6ded5 Upgraded ci-scripts to v3.0.1 2020-06-15 14:54:44 -05:00
Kevin Peterson
b33d89a508 Trigger 1st Travis build 2020-05-26 13:42:32 -05:00
Kevin Peterson
b52462a3cb Added epics-base ci-scripts 2020-05-26 11:55:28 -05:00
47 changed files with 1296 additions and 636 deletions

2
.gitignore vendored
View File

@@ -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
View File

@@ -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.

View File

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

View File

@@ -1,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;
};

View File

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

View File

@@ -1,4 +1,5 @@
EPICS_BASE=
MOTOR= 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=

View File

@@ -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

View File

@@ -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.

View File

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

View File

@@ -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
View File

@@ -0,0 +1,502 @@
/*
FILENAME... MD90Driver.cpp
USAGE... Motor driver support for the DSM MD-90 controller.
Mark Rivers
March 1, 2012
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <iocsh.h>
#include <epicsThread.h>
#include <asynOctetSyncIO.h>
#include <epicsExport.h>
#include "MD90Driver.h"
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
/** Creates a new MD90Controller object.
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] MD90PortName The name of the drvAsynSerialPort that was created previously to connect to the MD90 controller
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time between polls when any axis is moving
* \param[in] idlePollPeriod The time between polls when no axis is moving
*/
MD90Controller::MD90Controller(const char *portName, const char *MD90PortName, int numAxes,
double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, numAxes, NUM_MD90_PARAMS,
0, // No additional interfaces beyond those in base class
0, // No additional callback interfaces beyond those in base class
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
int axis;
asynStatus status;
MD90Axis *pAxis;
static const char *functionName = "MD90Controller::MD90Controller";
/* Connect to MD90 controller */
status = pasynOctetSyncIO->connect(MD90PortName, 0, &pasynUserController_, NULL);
if (status) {
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
"%s: cannot connect to MD-90 controller\n",
functionName);
}
for (axis=0; axis<numAxes; axis++) {
pAxis = new MD90Axis(this, axis);
}
startPoller(movingPollPeriod, idlePollPeriod, 2);
}
/** Creates a new MD90Controller object.
* Configuration command, called directly or from iocsh
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] MD90PortName The name of the drvAsynIPPPort that was created previously to connect to the MD90 controller
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time in ms between polls when any axis is moving
* \param[in] idlePollPeriod The time in ms between polls when no axis is moving
*/
extern "C" int MD90CreateController(const char *portName, const char *MD90PortName, int numAxes,
int movingPollPeriod, int idlePollPeriod)
{
MD90Controller *pMD90Controller
= new MD90Controller(portName, MD90PortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
pMD90Controller = NULL;
return(asynSuccess);
}
/** Reports on status of the driver
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* If details > 0 then information is printed about each axis.
* After printing controller-specific information it calls asynMotorController::report()
*/
void MD90Controller::report(FILE *fp, int level)
{
fprintf(fp, "MD-90 motor driver %s, numAxes=%d, moving poll period=%f, idle poll period=%f\n",
this->portName, numAxes_, movingPollPeriod_, idlePollPeriod_);
// Call the base class method
asynMotorController::report(fp, level);
}
/** Returns a pointer to an MD90Axis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
MD90Axis* MD90Controller::getAxis(asynUser *pasynUser)
{
return static_cast<MD90Axis*>(asynMotorController::getAxis(pasynUser));
}
/** Returns a pointer to an MD90Axis object.
* Returns NULL if the axis number encoded in pasynUser is invalid.
* \param[in] axisNo Axis index number. */
MD90Axis* MD90Controller::getAxis(int axisNo)
{
return static_cast<MD90Axis*>(asynMotorController::getAxis(axisNo));
}
// These are the MD90Axis methods
/** Creates a new MD90Axis object.
* \param[in] pC Pointer to the MD90Controller to which this axis belongs.
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
*
* Initializes register numbers, etc.
*/
MD90Axis::MD90Axis(MD90Controller *pC, int axisNo)
: asynMotorAxis(pC, axisNo),
pC_(pC)
{
}
/** Reports on status of the axis
* \param[in] fp The file pointer on which report information will be written
* \param[in] level The level of report detail desired
*
* After printing device-specific information calls asynMotorAxis::report()
*/
void MD90Axis::report(FILE *fp, int level)
{
if (level > 0) {
fprintf(fp, " axis %d\n",
axisNo_);
}
// Call the base class method
asynMotorAxis::report(fp, level);
}
/** Print out message if the motor controller returns a non-zero error code
* \param[in] functionName The function originating the call
* \param[in] reply Reply message returned from motor controller
*/
asynStatus MD90Axis::parseReply(const char *functionName, const char *reply)
{
int replyStatus;
char replyString[256];
int replyValue;
asynStatus comStatus;
comStatus = asynSuccess;
if (reply[0] == '\0') {
comStatus = asynError;
replyStatus = -1;
} else if ( strcmp(reply, "Unrecognized command.") == 0 ) {
replyStatus = 6;
} else {
sscanf(reply, "%d: %[^:]: %d", &replyStatus, replyString, &replyValue);
}
if (replyStatus != 0) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
"%s: %s\n",
functionName, reply);
}
return comStatus;
}
/** Acceleration currently unsupported with MD-90 controller
* \param[in] acceleration The accelerations to ramp up to max velocity
* \param[in] velocity Motor velocity in steps / sec
*/
asynStatus MD90Axis::sendAccelAndVelocity(double acceleration, double velocity)
{
asynStatus status;
int freq;
static const char *functionName = "MD90::sendAccelAndVelocity";
// Send the velocity
// Velocity provided in steps/sec
// Our unit step size of the encoder is 10 nm, but the motor moves in steps approx. 5 micrometers.
// Motor controller accepts step frequency in Hz.
freq = NINT(fabs(velocity / 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
View 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;
};

View File

@@ -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

View File

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

View File

@@ -1,4 +1,4 @@
/* File: devMCB4B.cc */ /* File: devMD90.cc */
/* Device Support Routines for motor */ /* 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);
} }
} }

View File

@@ -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);

View File

@@ -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 */

View File

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

View File

@@ -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 *);

View File

@@ -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

View File

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

View File

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

View File

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

View File

@@ -37,8 +37,8 @@ CHECK_RELEASE = YES
# Include motor's CONFIG_SITE.local when building inside motor # Include 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

View File

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

View File

@@ -2,7 +2,7 @@
# Use motor/module's generated release file when buidling inside motor # 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

View File

@@ -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)
#=========================== #===========================

View File

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

View File

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

View File

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

View File

@@ -1,24 +1,24 @@
#!../../bin/linux-x86_64/acs #!../../bin/linux-x86_64/dsm
< envPaths < 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

View File

@@ -0,0 +1,38 @@
#errlogInit(5000)
< envPaths
# Tell EPICS all about the record types, device-support modules, drivers, etc.
dbLoadDatabase("../../dbd/dsm.dbd")
dsm_registerRecordDeviceDriver(pdbbase)
# Network device
#!drvAsynIPPortConfigure("serial0", "192.168.1.16:4002",0,0,0)
# Local serial port
drvAsynSerialPortConfigure("serial0", "/dev/ttyUSB0", 0, 0, 0)
asynSetOption("serial0", 0, "baud", "115200")
asynSetOption("serial0", 0, "bits", "8")
asynSetOption("serial0", 0, "parity", "none")
asynSetOption("serial0", 0, "stop", "1")
asynOctetSetInputEos("serial0", 0, "\r")
asynOctetSetOutputEos("serial0", 0, "\r")
asynSetTraceIOMask("serial0", 0, 2)
# Turn on the power supply and set the deadband
asynOctetConnect("initConnection", "serial0", 0)
asynOctetWrite("initConnection", "EPS")
asynOctetWrite("initConnection", "SDB 10")
asynOctetDisconnect('initConnection')
MD90CreateController("MD900", "serial0", 1, 100, 5000)
### Motors
dbLoadTemplate "motor.substitutions.md90"
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=DSM:,R=serial0,PORT=serial0,ADDR=0,OMAX=80,IMAX=80")
iocInit
# This IOC does not use save/restore, so set values of some PVs
dbpf("DSM:m0.RTRY", "0")
dbpf("DSM:m0.TWV", "0.1")
dbpf("DSM:m0.VMAX", "0.625")

View File

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