forked from epics_driver_modules/motorBase
Removed AMCISrc; Added motorAMCI submodule
This commit is contained in:
@@ -76,3 +76,6 @@
|
||||
[submodule "modules/motorPI"]
|
||||
path = modules/motorPI
|
||||
url = https://github.com/epics-motor/motorPI.git
|
||||
[submodule "modules/motorAMCI"]
|
||||
path = modules/motorAMCI
|
||||
url = https://github.com/epics-motor/motorAMCI.git
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
# ANF2 motors command file example (run in iocsh)
|
||||
#
|
||||
### Note: Modbus support (the EPICS modbus module) is required to be included in the
|
||||
### EPICS application where the ANF2 support will be loaded. This file is an
|
||||
### example of how to load the ANF2 support, in an ioc that is built with the
|
||||
### EPICS modbus module.
|
||||
|
||||
epicsEnvSet("PORT1", "ANF2_C1")
|
||||
epicsEnvSet("PORT2", "ANF2_C2")
|
||||
|
||||
# drvAsynIPPortConfigure("portName", "hostInfo", priority, noAutoConnect, noProcessEos);
|
||||
drvAsynIPPortConfigure("$(PORT1)_IP","192.168.0.50:502",0,0,1)
|
||||
drvAsynIPPortConfigure("$(PORT2)_IP","192.168.0.51:502",0,0,1)
|
||||
|
||||
# modbusInterposeConfig("portName", linkType, timeoutMsec, writeDelayMsec)
|
||||
modbusInterposeConfig("$(PORT1)_IP",0,2000,0)
|
||||
modbusInterposeConfig("$(PORT2)_IP",0,2000,0)
|
||||
|
||||
# NOTE: modbusLength = 10 * number of axes
|
||||
# drvModbusAsynConfigure("portName", "tcpPortName", slaveAddress, modbusFunction,
|
||||
# modbusStartAddress, modbusLength, dataType, pollMsec, "plcType")
|
||||
drvModbusAsynConfigure("$(PORT1)_In", "$(PORT1)_IP", 0, 4, 0, 120, 0, 100, "ANF2_stepper")
|
||||
drvModbusAsynConfigure("$(PORT2)_In", "$(PORT2)_IP", 0, 4, 0, 60, 0, 100, "ANF2_stepper")
|
||||
|
||||
# NOTE: modbusLength = 10 * number of axes
|
||||
# drvModbusAsynConfigure("portName", "tcpPortName", slaveAddress, modbusFunction,
|
||||
# modbusStartAddress, modbusLength, dataType, pollMsec, "plcType")
|
||||
drvModbusAsynConfigure("$(PORT1)_Out", "$(PORT1)_IP", 0, 16, 1024, 120, 6, 1, "ANF2_stepper")
|
||||
drvModbusAsynConfigure("$(PORT2)_Out", "$(PORT2)_IP", 0, 16, 1024, 60, 6, 1, "ANF2_stepper")
|
||||
|
||||
# Asyn traces for debugging
|
||||
#!asynSetTraceIOMask "$(PORT1)_In",0,4
|
||||
#!asynSetTraceMask "$(PORT1)_In",0,9
|
||||
#!asynSetTraceIOMask "$(PORT1)_Out",0,4
|
||||
#!asynSetTraceMask "$(PORT1)_Out",0,9
|
||||
#!asynSetTraceInfoMask "$(PORT1)_Out",0,15
|
||||
|
||||
# Asyn records for debugging
|
||||
#!dbLoadRecords("$(ASYN)/db/asynRecord.db","P=IOC:,R=asyn:c1ip,PORT=$(PORT1)_IP,ADDR=0,OMAX=256,IMAX=256")
|
||||
#!dbLoadRecords("$(ASYN)/db/asynRecord.db","P=IOC:,R=asyn:c1in,PORT=$(PORT1)_In,ADDR=0,OMAX=256,IMAX=256")
|
||||
#!dbLoadRecords("$(ASYN)/db/asynRecord.db","P=IOC:,R=asyn:c1out,PORT=$(PORT1)_Out,ADDR=0,OMAX=256,IMAX=256")
|
||||
#!dbLoadRecords("$(ASYN)/db/asynRecord.db","P=IOC:,R=asyn:c1,PORT=$(PORT1),ADDR=0,OMAX=256,IMAX=256")
|
||||
|
||||
# Load the motor records
|
||||
dbLoadTemplate("templates/motor.substitutions.ANF2")
|
||||
|
||||
# AMCI ANF2 stepper controller driver support
|
||||
#
|
||||
# ANF2CreateController(
|
||||
# portName, The name of the asyn port that will be created by this driver
|
||||
# ANF2InPortName, The name of the In drvAsynIPPPort to read from the ANF2 controller
|
||||
# ANF2OutPortName, The name of the Out drvAsynIPPPort to write to the ANF2 controller
|
||||
# numAxes) The number of axes in the stack (max=12)
|
||||
#
|
||||
# ANF2CreateAxis(
|
||||
# ANF2Name, The controller's asyn port
|
||||
# axis, The axis to be configured (zero-based numbering)
|
||||
# hexConfig, The desired hex configuration (see manual & AMCI Net Configurator for details)
|
||||
# baseSpeed, The base speed (steps/second; min=1, max=1,000,000)
|
||||
# homingTimeout) The homing timeout (integer number of seconds; min=0, max=300)
|
||||
#
|
||||
# Note: The base speed can't be changed using the VBAS field of the motor record, but the driver
|
||||
# does correct the acceleration sent by the motor record to give the desired acceleration time.
|
||||
|
||||
# Controller 1 (One ANF2E, Five ANF2's)
|
||||
ANF2CreateController("$(PORT1)", "$(PORT1)_In", "$(PORT1)_Out", 12)
|
||||
# Axes for Controller 1
|
||||
ANF2CreateAxis("$(PORT1)", 0, "0x86280000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 1, "0x86000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 2, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 3, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 4, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 5, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 6, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 7, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 8, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 9, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 10, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT1)", 11, "0x84000000", 100, 0)
|
||||
|
||||
# Controller 2 (One ANF1E, Five ANF1's)
|
||||
ANF2CreateController("$(PORT2)", "$(PORT2)_In", "$(PORT2)_Out", 6)
|
||||
# Axes for Controller 2
|
||||
ANF2CreateAxis("$(PORT2)", 0, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT2)", 1, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT2)", 2, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT2)", 3, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT2)", 4, "0x84000000", 100, 0)
|
||||
ANF2CreateAxis("$(PORT2)", 5, "0x84000000", 100, 0)
|
||||
|
||||
# NOTE: the poller needs to be started after iocInit
|
||||
|
||||
|
||||
|
||||
##########
|
||||
# iocInit
|
||||
##########
|
||||
|
||||
|
||||
|
||||
# ANF2StartPoller(
|
||||
# portName, The controller's asyn port
|
||||
# movingPollPeriod, The time in ms between polls when any axis is moving
|
||||
# idlePollPeriod) The time in ms between polls when no axis is moving
|
||||
#
|
||||
ANF2StartPoller("$(PORT1)", 200, 1000)
|
||||
ANF2StartPoller("$(PORT2)", 200, 1000)
|
||||
@@ -1,54 +0,0 @@
|
||||
file "$(MOTOR)/motorApp/Db/asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT, RTRY}
|
||||
|
||||
{IOC:, "m1", "asynMotor", "ANF2_C1", 0, "ANF2 C1 M1", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m2", "asynMotor", "ANF2_C1", 1, "ANF2 C1 M2", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m3", "asynMotor", "ANF2_C1", 2, "ANF2 C1 M3", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m4", "asynMotor", "ANF2_C1", 3, "ANF2 C1 M4", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m5", "asynMotor", "ANF2_C1", 4, "ANF2 C1 M5", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m6", "asynMotor", "ANF2_C1", 5, "ANF2 C1 M6", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m7", "asynMotor", "ANF2_C1", 6, "ANF2 C1 M7", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m8", "asynMotor", "ANF2_C1", 7, "ANF2 C1 M8", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m9", "asynMotor", "ANF2_C1", 8, "ANF2 C1 M9", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m10", "asynMotor", "ANF2_C1", 9, "ANF2 C1 M10", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m11", "asynMotor", "ANF2_C1", 10, "ANF2 C1 M11", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m12", "asynMotor", "ANF2_C1", 11, "ANF2 C1 M12", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
|
||||
{IOC:, "m13", "asynMotor", "ANF2_C2", 0, "ANF2 C2 M1", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m14", "asynMotor", "ANF2_C2", 1, "ANF2 C2 M2", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m15", "asynMotor", "ANF2_C2", 2, "ANF2 C2 M3", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m16", "asynMotor", "ANF2_C2", 3, "ANF2 C2 M4", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m17", "asynMotor", "ANF2_C2", 4, "ANF2 C2 M5", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, "m18", "asynMotor", "ANF2_C2", 5, "ANF2 C2 M6", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
|
||||
}
|
||||
|
||||
file "$(MOTOR)/motorApp/Db/ANF2Aux.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, ADDR}
|
||||
|
||||
{IOC:, m1:, "ANF2_C1", 0}
|
||||
{IOC:, m2:, "ANF2_C1", 1}
|
||||
{IOC:, m3:, "ANF2_C1", 2}
|
||||
{IOC:, m4:, "ANF2_C1", 3}
|
||||
{IOC:, m5:, "ANF2_C1", 4}
|
||||
{IOC:, m6:, "ANF2_C1", 5}
|
||||
{IOC:, m7:, "ANF2_C1", 6}
|
||||
{IOC:, m8:, "ANF2_C1", 7}
|
||||
{IOC:, m9:, "ANF2_C1", 8}
|
||||
{IOC:, m10:, "ANF2_C1", 9}
|
||||
{IOC:, m11:, "ANF2_C1", 10}
|
||||
{IOC:, m12:, "ANF2_C1", 11}
|
||||
|
||||
{IOC:, m13:, "ANF2_C2", 0}
|
||||
{IOC:, m14:, "ANF2_C2", 1}
|
||||
{IOC:, m15:, "ANF2_C2", 2}
|
||||
{IOC:, m16:, "ANF2_C2", 3}
|
||||
{IOC:, m17:, "ANF2_C2", 4}
|
||||
{IOC:, m18:, "ANF2_C2", 5}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
file "$(MOTOR)/motorApp/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, RTRY}
|
||||
|
||||
{IOC:, 1, "m$(N)", "asynMotor", "ANG1_1_1", 0, "AMCI ANG1 1", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", "ANG1_1_2", 0, "AMCI ANG1 2", steps, Pos, 100, 0, .2, 0, 50, .2, 1, 5, 1e9, -1e9, ""}
|
||||
}
|
||||
|
||||
file "$(MOTOR)/motorApp/Db/ANG1Aux.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, ADDR}
|
||||
{IOC:, m1:, ANG1_1_1, 0}
|
||||
{IOC:, m2:, ANG1_1_2, 0}
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
# ANG1 motors Command file Example
|
||||
#
|
||||
### Note: Modbus support (the EPICS modbus module) is required to be included in the
|
||||
### EPICS application where the ANG1 support will be loaded. This file is an
|
||||
### example of how to load the ANG1 support, in an ioc that is built with the
|
||||
### EPICS modbus module.
|
||||
|
||||
|
||||
# Use the following commands for TCP/IP
|
||||
#drvAsynIPPortConfigure(const char *portName,
|
||||
# const char *hostInfo,
|
||||
# unsigned int priority,
|
||||
# int noAutoConnect,
|
||||
# int noProcessEos);
|
||||
# One per controller. One controller can support up to six drivers.
|
||||
drvAsynIPPortConfigure("ang1_1","164.54.53.107:502",0,0,1)
|
||||
#drvAsynIPPortConfigure("ang1_2","164.54.53.23:502",0,0,1)
|
||||
#drvAsynIPPortConfigure("ang1_3","164.54.xxx.xxx:502",0,0,1)
|
||||
|
||||
#modbusInterposeConfig(const char *portName,
|
||||
# modbusLinkType linkType,
|
||||
# int timeoutMsec,
|
||||
# int writeDelayMsec)
|
||||
# One per controller. One controller can support up to six drivers.
|
||||
modbusInterposeConfig("ang1_1",0,2000,0)
|
||||
#modbusInterposeConfig("ang1_2",0,2000,0)
|
||||
|
||||
# Word access at Modbus address 0
|
||||
# Access 1 words as inputs.
|
||||
# Function code=3
|
||||
# default data type unsigned integer.
|
||||
# drvModbusAsynConfigure("portName", "tcpPortName", slaveAddress, modbusFunction, modbusStartAddress, modbusLength, dataType, pollMsec, "plcType")
|
||||
# One per axis. Note: "ANG1" is the AMCI model. "ANG1_1" is the controller. "ANG1_1_1" is the axis.
|
||||
drvModbusAsynConfigure("ANG1_1_1_In_Word", "ang1_1", 0, 4, 0, 10, 0, 100, "ANG1_stepper")
|
||||
drvModbusAsynConfigure("ANG1_1_2_In_Word", "ang1_1", 0, 4, 10, 10, 0, 100, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_3_In_Word", "ang1_1", 0, 3, 20, 10, 0, 100, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_4_In_Word", "ang1_1", 0, 3, 30, 10, 0, 100, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_5_In_Word", "ang1_1", 0, 3, 40, 10, 0, 100, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_6_In_Word", "ang1_1", 0, 3, 50, 10, 0, 100, "ANG1_stepper")
|
||||
|
||||
# Access 1 words as outputs.
|
||||
# Either function code=6 (single register) or 16 (multiple registers) can be used, but 16
|
||||
# is better because it is "atomic" when writing values longer than 16-bits.
|
||||
# Default data type unsigned integer.
|
||||
# drvModbusAsynConfigure("portName", "tcpPortName", slaveAddress, modbusFunction, modbusStartAddress, modbusLength, dataType, pollMsec, "plcType")
|
||||
# Not sure why the outputs can't be configured for Modbus data type 4?
|
||||
drvModbusAsynConfigure("ANG1_1_1_Out_Word", "ang1_1", 0, 6, 1024, 10, 0, 1, "ANG1_stepper")
|
||||
drvModbusAsynConfigure("ANG1_1_2_Out_Word", "ang1_1", 0, 6, 1034, 10, 0, 1, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_3_Out_Word", "ang1_1", 0, 6, 1044, 10, 0, 1, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_4_Out_Word", "ang1_1", 0, 6, 1054, 10, 0, 1, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_5_Out_Word", "ang1_1", 0, 6, 1064, 10, 0, 1, "ANG1_stepper")
|
||||
#drvModbusAsynConfigure("ANG1_1_6_Out_Word", "ang1_1", 0, 6, 1074, 10, 0, 1, "ANG1_stepper")
|
||||
|
||||
# Second ANG1 controller...
|
||||
#drvModbusAsynConfigure("ANG1_2_1_Out_Word_0", "ang1_2", 0, 6, 1024, 1, 0, 1, "ANG1_stepper")
|
||||
|
||||
dbLoadTemplate("ANG1_motors.substitutions")
|
||||
|
||||
# AMCI ANG1 stepper controller/driver support
|
||||
# portName The name of the asyn port that will be created for this driver
|
||||
# ANG1InPortName The name of the In drvAsynIPPPort that was created previously to connect to the ANG1 controller
|
||||
# ANG1OutPortName The name of the Out drvAsynIPPPort that was created previously to connect to the ANG1 controller
|
||||
# numAxes The number of axes that this controller supports
|
||||
# movingPollPeriod The time in ms between polls when any axis is moving
|
||||
# idlePollPeriod The time in ms between polls when no axis is moving
|
||||
#
|
||||
# One per axis. Note: "ANG1" is the AMCI model. "ANG1_1" is the controller. "ANG1_1_1" is the axis.
|
||||
# Also, ANG1_1_1 is the port name needed for motor.substitutions.
|
||||
ANG1CreateController(ANG1_1_1, ANG1_1_1_In_Word, ANG1_1_1_Out_Word, 1, 100, 0)
|
||||
ANG1CreateController(ANG1_1_2, ANG1_1_2_In_Word, ANG1_1_2_Out_Word, 1, 100, 0)
|
||||
#ANG1CreateController(ANG1_1, ANG1_1_3_In_Word, ANG1_1_3_Out_Word, 1, 100, 0)
|
||||
#ANG1CreateController(ANG1_1, ANG1_1_4_In_Word, ANG1_1_4_Out_Word, 1, 100, 0)
|
||||
#ANG1CreateController(ANG1_1, ANG1_1_5_In_Word, ANG1_1_5_Out_Word, 1, 100, 0)
|
||||
#ANG1CreateController(ANG1_1, ANG1_1_6_In_Word, ANG1_1_6_Out_Word, 1, 100, 0)
|
||||
@@ -5,6 +5,7 @@ include $(TOP)/configure/CONFIG
|
||||
#SUBMODULES += motorVendor
|
||||
SUBMODULES += motorOms
|
||||
SUBMODULES += motorNewport
|
||||
SUBMODULES += motorAMCI
|
||||
SUBMODULES += motorACR
|
||||
SUBMODULES += motorAcs
|
||||
SUBMODULES += motorAcsTech80
|
||||
|
||||
Submodule
+1
Submodule modules/motorAMCI added at 0bbd957f21
@@ -1,2 +0,0 @@
|
||||
include "ANG1Support.dbd"
|
||||
include "ANF2Support.dbd"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,151 +0,0 @@
|
||||
/*
|
||||
FILENAME... ANF2Driver.h
|
||||
USAGE... Motor driver support for the AMCI ANF2 controller.
|
||||
|
||||
Kevin Peterson
|
||||
|
||||
Based on the AMCI ANG1 Model 3 device driver written by Kurt Goetze
|
||||
|
||||
*/
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
//#include <asynInt32Array.h>
|
||||
#include <asynInt32ArraySyncIO.h>
|
||||
|
||||
#define MAX_AXES 12
|
||||
|
||||
#define MAX_INPUT_REGS 10
|
||||
#define MAX_OUTPUT_REGS 10
|
||||
|
||||
#define AXIS_REG_OFFSET 10
|
||||
|
||||
/*** Input CMD Registers (16-bit) ***/
|
||||
#define STATUS_1 0
|
||||
#define STATUS_2 1
|
||||
#define POS_RD_UPR 2
|
||||
#define POS_RD_LWR 3
|
||||
#define EN_POS_UPR 4
|
||||
#define EN_POS_LWR 5
|
||||
#define EN_CAP_UPR 6
|
||||
#define EN_CAP_LWR 7
|
||||
// Not used must equal zero #define RESERVED 8
|
||||
#define NET_CONN 9
|
||||
|
||||
/*** Output Command Registers (32-bit) ***/
|
||||
#define COMMAND 0
|
||||
#define POSITION 1
|
||||
#define SPEED 2
|
||||
#define ACCEL_DECEL 3
|
||||
#define CMD_REG_4 4
|
||||
|
||||
/*** Output Configuration Registers (32-bit) ***/
|
||||
#define CONFIGURATION 0
|
||||
#define BASE_SPEED 1
|
||||
#define HOME_TIMEOUT 2
|
||||
#define CONFIG_REG_3 3
|
||||
#define CONFIG_REG_4 4
|
||||
|
||||
// No. of controller-specific parameters
|
||||
#define NUM_ANF2_PARAMS 2
|
||||
|
||||
/** drvInfo strings for extra parameters that the ACR controller supports */
|
||||
#define ANF2ResetErrorsString "ANF2_RESET_ERRORS"
|
||||
#define ANF2GetInfoString "ANF2_GET_INFO"
|
||||
//#define ANF2ReconfigString "ANF2_RECONFIG"
|
||||
|
||||
class ANF2Axis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
ANF2Axis(class ANF2Controller *pC, int axisNo, epicsInt32 config, epicsInt32 baseSpeed, epicsInt32 homingTimeout);
|
||||
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:
|
||||
ANF2Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
asynStatus sendAccelAndVelocity(double accel, double velocity);
|
||||
double correctAccel(double minVelocity, double maxVelocity, double acceleration);
|
||||
asynStatus resetErrors();
|
||||
void getInfo();
|
||||
epicsInt32 inputReg_[10];
|
||||
//void reconfig(epicsInt32 value);
|
||||
void zeroRegisters(epicsInt32 *reg);
|
||||
asynUser *pasynUserForceRead_;
|
||||
int axisNo_;
|
||||
epicsInt32 baseSpeed_;
|
||||
epicsInt32 homingTimeout_;
|
||||
epicsInt32 config_;
|
||||
epicsInt32 motionReg_[5];
|
||||
epicsInt32 confReg_[5];
|
||||
epicsInt32 zeroReg_[5];
|
||||
bool jogging_;
|
||||
// Configuration bits
|
||||
short CaptInput_;
|
||||
short ExtInput_;
|
||||
short HomeInput_;
|
||||
short CWInput_;
|
||||
short CCWInput_;
|
||||
short BHPO_;
|
||||
short QuadEnc_;
|
||||
short DiagFbk_;
|
||||
short OutPulse_;
|
||||
short HomeOp_;
|
||||
short CardAxis_;
|
||||
short OpMode_;
|
||||
// LSW
|
||||
short CaptInputAS_;
|
||||
short ExtInputAS_;
|
||||
short HomeInputAS_;
|
||||
short CWInputAS_;
|
||||
short CCWInputAS_;
|
||||
|
||||
friend class ANF2Controller;
|
||||
};
|
||||
|
||||
class ANF2Controller : public asynMotorController {
|
||||
public:
|
||||
ANF2Controller(const char *portName, const char *ANF2InPortName, const char *ANF2OutPortName, int numAxes);
|
||||
void doStartPoller(double movingPollPeriod, double idlePollPeriod);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
ANF2Axis* getAxis(asynUser *pasynUser);
|
||||
ANF2Axis* getAxis(int axisNo);
|
||||
asynUser *pasynUserInReg_[MAX_AXES][MAX_INPUT_REGS];
|
||||
asynUser *pasynUserOutReg_[MAX_AXES];
|
||||
|
||||
/* These are the methods that we override from asynMotorDriver */
|
||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
//asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
||||
//void report(FILE *fp, int level);
|
||||
|
||||
/* These are the methods that are new to this class */
|
||||
|
||||
protected:
|
||||
int ANF2ResetErrors_; /** Reset Errors parameter index */
|
||||
int ANF2GetInfo_; /**< Get Info parameter index */
|
||||
//int ANF2Reconfig_; /**< Reconfig parameter index */
|
||||
|
||||
private:
|
||||
asynStatus writeReg16(int, int, int, double);
|
||||
asynStatus writeReg32(int, int, int, double);
|
||||
asynStatus writeReg32Array(int, epicsInt32*, int, double);
|
||||
asynStatus readReg16(int, int, epicsInt32*, double);
|
||||
asynStatus readReg32(int, int, epicsInt32*, double);
|
||||
char *inputDriver_;
|
||||
int numAxes_;
|
||||
int numModules_;
|
||||
int axesPerModule_;
|
||||
double movingPollPeriod_;
|
||||
double idlePollPeriod_;
|
||||
int axesCreated_;
|
||||
|
||||
friend class ANF2Axis;
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
#registrar(ANF2MotorRegister)
|
||||
registrar(ANF2Register)
|
||||
@@ -1,640 +0,0 @@
|
||||
/*
|
||||
FILENAME... ANG1Driver.cpp
|
||||
USAGE... Motor record driver support for the AMCI ANG1 stepper motor controller over Modbus/TCP.
|
||||
|
||||
Kurt Goetze
|
||||
|
||||
Based on the ACS MCB-4B Model 3 device driver written by Mark Rivers
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsString.h>
|
||||
|
||||
#include <asynInt32SyncIO.h>
|
||||
|
||||
#include "ANG1Driver.h"
|
||||
#include <epicsExport.h>
|
||||
|
||||
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||
|
||||
static const char *driverName = "ANG1MotorDriver";
|
||||
|
||||
/*** Input Registers ***/
|
||||
#define STATUS_1 0
|
||||
#define STATUS_2 1
|
||||
#define POS_RD_UPR 2
|
||||
#define POS_RD_LWR 3
|
||||
#define EN_POS_UPR 4
|
||||
#define EN_POS_LWR 5
|
||||
#define EN_CAP_UPR 6
|
||||
#define EN_CAP_LWR 7
|
||||
#define MOT_CUR 8 // programmed motor current (x10)
|
||||
#define JERK_RD 9
|
||||
|
||||
/*** Output Registers ***/
|
||||
#define CMD_MSW 0 // module 0 starts at register address 1024. This is set in drvModbusAsynConfigure.
|
||||
#define CMD_LSW 1
|
||||
#define POS_WR_UPR 2
|
||||
#define POS_WR_LWR 3
|
||||
#define SPD_UPR 4
|
||||
#define SPD_LWR 5
|
||||
#define ACCEL 6
|
||||
#define DECEL 7
|
||||
// Not used must equal zero #define RESERVED 8
|
||||
#define JERK 9
|
||||
|
||||
/** Constructor, Creates a new ANG1Controller object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] ANG1InPortName The name of the drvAsynSerialPort that was created previously to connect to the ANG1 controller
|
||||
* \param[in] ANG1OutPortName The name of the drvAsynSerialPort that was created previously to connect to the ANG1 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
|
||||
*/
|
||||
ANG1Controller::ANG1Controller(const char *portName, const char *ANG1InPortName, const char *ANG1OutPortName, int numAxes,
|
||||
double movingPollPeriod, double idlePollPeriod)
|
||||
: asynMotorController(portName, numAxes, NUM_ANG1_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, i;
|
||||
asynStatus status;
|
||||
ANG1Axis *pAxis;
|
||||
static const char *functionName = "ANG1Controller::ANG1Controller";
|
||||
|
||||
inputDriver_ = epicsStrDup(ANG1InPortName); // Set this before calls to create Axis objects
|
||||
|
||||
// Create controller-specific parameters
|
||||
createParam(ANG1JerkString, asynParamInt32, &ANG1Jerk_);
|
||||
|
||||
/* Connect to ANG1 controller */
|
||||
for (i=0; i<MAX_INPUT_REGS; i++) {
|
||||
status = pasynInt32SyncIO->connect(ANG1InPortName, i, &pasynUserInReg_[i], NULL);
|
||||
}
|
||||
for (i=0; i<MAX_OUTPUT_REGS; i++) {
|
||||
status = pasynInt32SyncIO->connect(ANG1OutPortName, i, &pasynUserOutReg_[i], NULL);
|
||||
}
|
||||
if (status) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to ANG1 controller\n",
|
||||
functionName);
|
||||
}
|
||||
for (axis=0; axis<numAxes; axis++) {
|
||||
pAxis = new ANG1Axis(this, axis);
|
||||
}
|
||||
|
||||
startPoller(movingPollPeriod, idlePollPeriod, 2);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new ANG1Controller 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] ANG1InPortName The name of the drvAsynIPPPort that was created previously to connect to the ANG1 controller
|
||||
* \param[in] ANG1OutPortName The name of the drvAsynIPPPort that was created previously to connect to the ANG1 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 ANG1CreateController(const char *portName, const char *ANG1InPortName, const char *ANG1OutPortName, int numAxes,
|
||||
int movingPollPeriod, int idlePollPeriod)
|
||||
{
|
||||
ANG1Controller *pANG1Controller
|
||||
= new ANG1Controller(portName, ANG1InPortName, ANG1OutPortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
|
||||
pANG1Controller = 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 ANG1Controller::report(FILE *fp, int level)
|
||||
{
|
||||
fprintf(fp, "ANG1 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 ANG1Axis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
ANG1Axis* ANG1Controller::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
// ? return static_cast<ANG1Axis*>(asynMotorController::getAxis(pANG1Axis methodsasynUser));
|
||||
return static_cast<ANG1Axis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an ANG1Axis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] No Axis index number. */
|
||||
ANG1Axis* ANG1Controller::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<ANG1Axis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
/** Called when asyn clients call pasynInt32->write().
|
||||
* Extracts the function and axis number from pasynUser.
|
||||
* Sets the value in the parameter library (?)
|
||||
* If the function is ANG1Jerk_ it sets the jerk value in the controller.
|
||||
* Calls any registered callbacks for this pasynUser->reason and address.
|
||||
* For all other functions it calls asynMotorController::writeInt32.
|
||||
* \param[in] pasynUser asynUser structure that encodes the reason and address.
|
||||
* \param[in] value Value to write. */
|
||||
asynStatus ANG1Controller::writeInt32(asynUser *pasynUser, epicsInt32 value)
|
||||
{
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynSuccess;
|
||||
ANG1Axis *pAxis = getAxis(pasynUser);
|
||||
static const char *functionName = "writeInt32";
|
||||
|
||||
/* Set the parameter and readback in the parameter library. */
|
||||
status = setIntegerParam(pAxis->axisNo_, function, value);
|
||||
|
||||
if (function == ANG1Jerk_)
|
||||
{
|
||||
// Jerk in units steps/sec/sec/sec (0 - 5000)
|
||||
printf("Jerk = %d\n", value);
|
||||
status = writeReg16(JERK, value, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
// sprintf(outString_, "%s JOG JRK %f", pAxis->axisName_, value);
|
||||
// status = writeController();
|
||||
|
||||
} else {
|
||||
/* Call base class method */
|
||||
status = asynMotorController::writeInt32(pasynUser, value);
|
||||
}
|
||||
|
||||
/* Do callbacks so higher layers see any changes */
|
||||
pAxis->callParamCallbacks();
|
||||
if (status)
|
||||
asynPrint(pasynUser, ASYN_TRACE_ERROR,
|
||||
"%s:%s: error, status=%d function=%d, value=%d\n",
|
||||
driverName, functionName, status, function, value);
|
||||
else
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"%s:%s: function=%d, value=%d\n",
|
||||
driverName, functionName, function, value);
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus ANG1Controller::writeReg16(int reg, int output, double timeout)
|
||||
{
|
||||
asynStatus status;
|
||||
|
||||
//printf("writeReg16: writing %d to register %d\n", output, reg);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,"writeReg16: writing %d to register %d\n", output, reg);
|
||||
status = pasynInt32SyncIO->write(pasynUserOutReg_[reg], output, timeout);
|
||||
epicsThreadSleep(0.01);
|
||||
|
||||
return status ;
|
||||
}
|
||||
|
||||
asynStatus ANG1Controller::writeReg32(int reg, int output, double timeout)
|
||||
{
|
||||
//.. break 32-bit integer into 2 pieces
|
||||
//.. write the pieces into ANG1 registers
|
||||
|
||||
asynStatus status;
|
||||
float fnum;
|
||||
int lower,upper;
|
||||
|
||||
fnum = (output / 1000.0);
|
||||
upper = (int)fnum;
|
||||
fnum = fnum - upper;
|
||||
fnum = NINT(fnum * 1000);
|
||||
lower = (int)fnum;
|
||||
|
||||
//could write the words this way
|
||||
// status = pasynInt32SyncIO->write(pasynUserOutReg_[reg], upper, timeout);
|
||||
// status = pasynInt32SyncIO->write(pasynUserOutReg_[reg+1], lower, timeout);
|
||||
|
||||
//or this way
|
||||
// writeReg16(piece1 ie MSW ...
|
||||
status = writeReg16(reg, upper, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
// writeReg16(piece2 ie LSW ...
|
||||
reg++;
|
||||
status = writeReg16(reg, lower, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
return status ;
|
||||
}
|
||||
|
||||
asynStatus ANG1Controller::readReg16(int reg, epicsInt32 *input, double timeout)
|
||||
{
|
||||
asynStatus status;
|
||||
|
||||
//printf("reg = %d\n", reg);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,"readReg16 reg = %d\n", reg);
|
||||
status = pasynInt32SyncIO->read(pasynUserInReg_[reg], input, timeout);
|
||||
|
||||
return status ;
|
||||
}
|
||||
|
||||
asynStatus ANG1Controller::readReg32(int reg, epicsInt32 *combo, double timeout)
|
||||
{
|
||||
//.. read 2 16-bit words from ANG1 registers
|
||||
//.. assemble 2 16-bit pieces into 1 32-bit integer
|
||||
|
||||
asynStatus status;
|
||||
// float fnum;
|
||||
epicsInt32 lowerWord32, upperWord32; // only have pasynInt32SyncIO, not pasynInt16SyncIO ,
|
||||
epicsInt16 lowerWord16, upperWord16; // so we need to get 32-bits and cast to 16-bit integer
|
||||
|
||||
//printf("calling readReg16\n");
|
||||
status = readReg16(reg, &upperWord32, timeout); //get Upper Word
|
||||
upperWord16 = (epicsInt16)upperWord32;
|
||||
//printf("upperWord16: %d\n", upperWord16);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,"readReg32 upperWord16: %d\n", upperWord16);
|
||||
|
||||
// if status != 1 :
|
||||
reg++;
|
||||
status = readReg16(reg, &lowerWord32, timeout); //get Lower Word
|
||||
lowerWord16 = (epicsInt16)lowerWord32;
|
||||
//printf("lowerWord16: %d\n", lowerWord16);
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACEIO_DRIVER,"readReg32 lowerWord16: %d\n", lowerWord16);
|
||||
|
||||
*combo = NINT((upperWord16 * 1000) + lowerWord16);
|
||||
|
||||
return status ;
|
||||
}
|
||||
|
||||
|
||||
// ANG1Axis methods Here
|
||||
// These are the ANG1Axis methods
|
||||
|
||||
/** Creates a new ANG1Axis object.
|
||||
* \param[in] pC Pointer to the ANG1Controller to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
ANG1Axis::ANG1Axis(ANG1Controller *pC, int axisNo)
|
||||
: asynMotorAxis(pC, axisNo),
|
||||
pC_(pC)
|
||||
{
|
||||
int status;
|
||||
|
||||
//status = pasynInt32SyncIO->connect(myModbusInputDriver, 0, &pasynUserForceRead_, "MODBUS_READ");
|
||||
status = pasynInt32SyncIO->connect(pC_->inputDriver_, 0, &pasynUserForceRead_, "MODBUS_READ");
|
||||
if (status) {
|
||||
//printf("%s:%s: Error, unable to connect pasynUserForceRead_ to Modbus input driver %s\n", pC_->inputDriver_, pC_->functionName, myModbusInputDriver);
|
||||
printf("%s: Error, unable to connect pasynUserForceRead_ to Modbus input driver\n", pC_->inputDriver_);
|
||||
}
|
||||
printf("ANG1Axis::ANG1Axis : pasynUserForceRead_->reason=%d\n", pasynUserForceRead_->reason);
|
||||
|
||||
// set position to 0
|
||||
setPosition(0);
|
||||
}
|
||||
|
||||
/** 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 ANG1Axis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axis %d\n",
|
||||
axisNo_);
|
||||
}
|
||||
|
||||
// Call the base class method
|
||||
asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
// SET VEL & ACCEL
|
||||
asynStatus ANG1Axis::sendAccelAndVelocity(double acceleration, double velocity)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "ANG1::sendAccelAndVelocity";
|
||||
|
||||
// Send the velocity in egus
|
||||
//sprintf(pC_->outString_, "%1dVA%f", axisNo_ + 1, (velocity*stepSize_));
|
||||
//status = pC_->writeController();
|
||||
status = pC_->writeReg32(SPD_UPR, NINT(velocity), DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
// Send the acceleration in egus/sec/sec
|
||||
//printf(" velocity: %f\n", velocity);
|
||||
//printf(" acceleration: %f\n", acceleration);
|
||||
// ANG1 acceleration range 1 to 5000 steps/ms/sec
|
||||
// Therefore need to limit range received by motor record from 1000 to 5e6 steps/sec/sec
|
||||
if (acceleration < 1000) {
|
||||
// print message noting that accel has been capped low
|
||||
acceleration = 1000;
|
||||
}
|
||||
if (acceleration > 5000000) {
|
||||
// print message noting that accel has been capped high
|
||||
acceleration = 5000000;
|
||||
}
|
||||
// ANG1 acceleration units are steps/millisecond/second, so we divide by 1000 here
|
||||
status = pC_->writeReg16(ACCEL, NINT(acceleration/1000.0), DEFAULT_CONTROLLER_TIMEOUT);
|
||||
status = pC_->writeReg16(DECEL, NINT(acceleration/1000.0), DEFAULT_CONTROLLER_TIMEOUT);
|
||||
return status;
|
||||
}
|
||||
|
||||
// MOVE
|
||||
asynStatus ANG1Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
int velo, distance, move_bit;
|
||||
|
||||
printf(" ** ANG1Axis::move called, relative = %d\n", relative);
|
||||
|
||||
status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
|
||||
//velo = maxVelocity * SOME_SCALE_FACTOR
|
||||
velo = NINT(maxVelocity);
|
||||
if (relative) {
|
||||
printf(" ** relative move called\n");
|
||||
//status = pC_->writeReg32(SPD_UPR, velo, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
//distance = position * SOM_OTHER_SCALE_FACTOR;
|
||||
distance = NINT(position);
|
||||
status = pC_->writeReg32(POS_WR_UPR, distance, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x2;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
} else {
|
||||
// absolute
|
||||
printf(" ** absolute move called\n");
|
||||
//status = pC_->writeReg32(SPD_UPR, velo, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
//distance = position * SOM_OTHER_SCALE_FACTOR;
|
||||
distance = NINT(position);
|
||||
printf(" ** distance = %d\n", distance);
|
||||
status = pC_->writeReg32(POS_WR_UPR, distance, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x1;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
}
|
||||
// Delay the first status read, give the controller some time to return moving status
|
||||
epicsThreadSleep(0.05);
|
||||
return status;
|
||||
}
|
||||
|
||||
// HOME (needs work)
|
||||
asynStatus ANG1Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status;
|
||||
int home_bit;
|
||||
// static const char *functionName = "ANG1Axis::home";
|
||||
|
||||
//status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
|
||||
if (forwards) {
|
||||
printf(" ** HOMING FORWARDS **\n");
|
||||
home_bit = 0x20;
|
||||
status = pC_->writeReg16(CMD_MSW, home_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
} else {
|
||||
home_bit = 0x40;
|
||||
status = pC_->writeReg16(CMD_MSW, home_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
// JOG
|
||||
asynStatus ANG1Axis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
int velo, distance, move_bit;
|
||||
static const char *functionName = "ANG1Axis::moveVelocity";
|
||||
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||
functionName, minVelocity, maxVelocity, acceleration);
|
||||
|
||||
velo = NINT(fabs(maxVelocity));
|
||||
|
||||
status = sendAccelAndVelocity(acceleration, velo);
|
||||
|
||||
/* ANG1 does not have jog command. Move 1 million steps */
|
||||
if (maxVelocity > 0.) {
|
||||
/* This is a positive move in ANG1 coordinates */
|
||||
//printf(" ** relative move (JOG pos) called\n");
|
||||
distance = 1000000;
|
||||
status = pC_->writeReg32(POS_WR_UPR, distance, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x2;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
} else {
|
||||
/* This is a negative move in ANG1 coordinates */
|
||||
//printf(" ** relative move (JOG neg) called\n");
|
||||
distance = -1000000;
|
||||
status = pC_->writeReg32(POS_WR_UPR, distance, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
move_bit = 0x2;
|
||||
status = pC_->writeReg16(CMD_MSW, move_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
}
|
||||
// Delay the first status read, give the controller some time to return moving status
|
||||
epicsThreadSleep(0.05);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// STOP
|
||||
asynStatus ANG1Axis::stop(double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
int stop_bit;
|
||||
//static const char *functionName = "ANG1Axis::stop";
|
||||
|
||||
printf("\n STOP \n\n");
|
||||
|
||||
stop_bit = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, stop_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
// stop_bit = 0x10; Immediate stop
|
||||
stop_bit = 0x4; // Hold move
|
||||
status = pC_->writeReg16(CMD_MSW, stop_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// SET
|
||||
asynStatus ANG1Axis::setPosition(double position)
|
||||
{
|
||||
asynStatus status;
|
||||
int set_position, set_bit;
|
||||
//static const char *functionName = "ANG1Axis::setPosition";
|
||||
|
||||
//status = writeReg32(SPD_UPR, velo, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
//distance = position * SOM_OTHER_SCALE_FACTOR;
|
||||
set_position = NINT(position);
|
||||
|
||||
status = pC_->writeReg32(POS_WR_UPR, set_position, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
set_bit = 0x200;
|
||||
status = pC_->writeReg16(CMD_MSW, set_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
set_bit = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, set_bit, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// ENABLE TORQUE
|
||||
asynStatus ANG1Axis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
asynStatus status;
|
||||
int enable = 0x8000;
|
||||
int disable = 0x0000;
|
||||
int cmd;
|
||||
|
||||
printf(" ** setClosedLoop called \n");
|
||||
if (closedLoop) {
|
||||
printf("setting enable %X\n", enable);
|
||||
// Let's reset errors first
|
||||
cmd = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, cmd, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
cmd = 0x400;
|
||||
status = pC_->writeReg16(CMD_MSW, cmd, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
|
||||
cmd = 0x0;
|
||||
status = pC_->writeReg16(CMD_MSW, cmd, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
status = pC_->writeReg16(CMD_LSW, enable, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
setIntegerParam(pC_->motorStatusPowerOn_, 1);
|
||||
|
||||
} else {
|
||||
printf("setting disable %X\n", disable);
|
||||
status = pC_->writeReg16(CMD_LSW, disable, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
setIntegerParam(pC_->motorStatusPowerOn_, 0);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
// POLL
|
||||
/** Polls the axis.
|
||||
* This function reads motor position, limit status, home status, and moving 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 ANG1Axis::poll(bool *moving)
|
||||
{
|
||||
int done;
|
||||
int limit;
|
||||
int enabled;
|
||||
double position;
|
||||
asynStatus status;
|
||||
epicsInt32 read_val; // don't use a pointer here. The _address_ of read_val should be passed to the read function.
|
||||
|
||||
// Force a read operation
|
||||
//printf(" . . . . . Calling pasynInt32SyncIO->write\n");
|
||||
//printf("Calling pasynInt32SyncIO->write(pasynUserForceRead_, 1, TIMEOUT), pasynUserForceRead_->reason=%d\n", pasynUserForceRead_->reason);
|
||||
status = pasynInt32SyncIO->write(pasynUserForceRead_, 1, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
//printf(" . . . . . status = %d\n", status);
|
||||
// if status goto end
|
||||
|
||||
// Read the current motor position
|
||||
//
|
||||
//readReg32(int reg, epicsInt32 *combo, double timeout)
|
||||
status = pC_->readReg32(POS_RD_UPR, &read_val, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
printf("ANG1Axis::poll: Motor position raw: %d\n", read_val);
|
||||
position = (double) read_val;
|
||||
setDoubleParam(pC_->motorPosition_, position);
|
||||
printf("ANG1Axis::poll: Motor position: %f\n", position);
|
||||
|
||||
// Read the moving status of this motor
|
||||
//
|
||||
status = pC_->readReg16(STATUS_1, &read_val, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
//printf("status 1 is 0x%X\n", read_val);
|
||||
|
||||
// Done logic
|
||||
done = ((read_val & 0x8) >> 3); // status word 1 bit 3 set to 1 when the motor is not in motion.
|
||||
setIntegerParam(pC_->motorStatusDone_, done);
|
||||
*moving = done ? false:true;
|
||||
printf("done is %d\n", done);
|
||||
|
||||
// Read the limit status
|
||||
//
|
||||
status = pC_->readReg16(STATUS_2, &read_val, DEFAULT_CONTROLLER_TIMEOUT);
|
||||
printf("status 2 is 0x%X\n", read_val);
|
||||
|
||||
limit = (read_val & 0x1); // a cw limit has been reached
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, limit);
|
||||
//printf("+limit %d\n", limit);
|
||||
if (limit) { // reset error and set position so we can move off of the limit
|
||||
// Reset error
|
||||
setClosedLoop(1);
|
||||
// Reset position
|
||||
//printf(" Reset Position\n");
|
||||
setPosition(position);
|
||||
}
|
||||
|
||||
limit = (read_val & 0x2); // a ccw limit has been reached
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, limit);
|
||||
//printf("-limit %d\n", limit);
|
||||
if (limit) { // reset error and set position so we can move off of the limit
|
||||
// Reset error
|
||||
setClosedLoop(1);
|
||||
// Reset position
|
||||
setPosition(position);
|
||||
}
|
||||
|
||||
// test for home
|
||||
|
||||
// Should be in init routine? Allows CNEN to be used.
|
||||
setIntegerParam(pC_->motorStatusGainSupport_, 1);
|
||||
|
||||
// Check for the torque status and set accordingly.
|
||||
enabled = (read_val & 0x8000);
|
||||
if (enabled)
|
||||
setIntegerParam(pC_->motorStatusPowerOn_, 1);
|
||||
else
|
||||
setIntegerParam(pC_->motorStatusPowerOn_, 0);
|
||||
|
||||
// Notify asynMotorController polling routine that we're ready
|
||||
callParamCallbacks();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg ANG1CreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg ANG1CreateControllerArg1 = {"ANG1 In port name", iocshArgString};
|
||||
static const iocshArg ANG1CreateControllerArg2 = {"ANG1 Out port name", iocshArgString};
|
||||
static const iocshArg ANG1CreateControllerArg3 = {"Number of axes", iocshArgInt};
|
||||
static const iocshArg ANG1CreateControllerArg4 = {"Moving poll period (ms)", iocshArgInt};
|
||||
static const iocshArg ANG1CreateControllerArg5 = {"Idle poll period (ms)", iocshArgInt};
|
||||
static const iocshArg * const ANG1CreateControllerArgs[] = {&ANG1CreateControllerArg0,
|
||||
&ANG1CreateControllerArg1,
|
||||
&ANG1CreateControllerArg2,
|
||||
&ANG1CreateControllerArg3,
|
||||
&ANG1CreateControllerArg4,
|
||||
&ANG1CreateControllerArg5,};
|
||||
static const iocshFuncDef ANG1CreateControllerDef = {"ANG1CreateController", 6, ANG1CreateControllerArgs};
|
||||
static void ANG1CreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
ANG1CreateController(args[0].sval, args[1].sval, args[2].sval, args[3].ival, args[4].ival, args[5].ival);
|
||||
}
|
||||
|
||||
static void ANG1Register(void)
|
||||
{
|
||||
iocshRegister(&ANG1CreateControllerDef, ANG1CreateContollerCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(ANG1Register);
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
FILENAME... ANG1Driver.h
|
||||
USAGE... Motor driver support for the AMCI ANG1 controller.
|
||||
|
||||
Based on MCB-4B driver written by
|
||||
Mark Rivers
|
||||
March 1, 2012
|
||||
|
||||
K. Goetze 2014-03-24
|
||||
|
||||
*/
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#define MAX_ANG1_AXES 1
|
||||
|
||||
#define MAX_INPUT_REGS 10
|
||||
#define MAX_OUTPUT_REGS 10
|
||||
|
||||
// No. of controller-specific parameters
|
||||
#define NUM_ANG1_PARAMS 1
|
||||
|
||||
/** drvInfo strings for extra parameters that the ACR controller supports */
|
||||
#define ANG1JerkString "ANG1_JERK"
|
||||
//#define ACRReadBinaryIOString "ACR_READ_BINARY_IO"
|
||||
//#define ACRBinaryInString "ACR_BINARY_IN"
|
||||
//#define ACRBinaryOutString "ACR_BINARY_OUT"
|
||||
//#define ACRBinaryOutRBVString "ACR_BINARY_OUT_RBV"
|
||||
|
||||
class ANG1Axis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
ANG1Axis(class ANG1Controller *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:
|
||||
ANG1Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
asynStatus sendAccelAndVelocity(double accel, double velocity);
|
||||
asynUser *pasynUserForceRead_;
|
||||
|
||||
friend class ANG1Controller;
|
||||
};
|
||||
|
||||
class ANG1Controller : public asynMotorController {
|
||||
public:
|
||||
ANG1Controller(const char *portName, const char *ANG1InPortName, const char *ANG1OutPortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
ANG1Axis* getAxis(asynUser *pasynUser);
|
||||
ANG1Axis* getAxis(int axisNo);
|
||||
asynUser *pasynUserInReg_[MAX_INPUT_REGS];
|
||||
asynUser *pasynUserOutReg_[MAX_OUTPUT_REGS];
|
||||
// asynUser *pasynUserForceRead_;
|
||||
|
||||
|
||||
/* These are the methods that we override from asynMotorDriver */
|
||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value);
|
||||
//asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value);
|
||||
//void report(FILE *fp, int level);
|
||||
//ACRAxis* getAxis(asynUser *pasynUser);
|
||||
//ACRAxis* getAxis(int axisNo);
|
||||
|
||||
|
||||
/* These are the methods that are new to this class */
|
||||
|
||||
protected:
|
||||
int ANG1Jerk_; /**< Jerk time parameter index */
|
||||
|
||||
|
||||
private:
|
||||
asynStatus writeReg16(int, int, double);
|
||||
asynStatus writeReg32(int, int, double);
|
||||
asynStatus readReg16(int, epicsInt32*, double);
|
||||
asynStatus readReg32(int, epicsInt32*, double);
|
||||
char *inputDriver_;
|
||||
|
||||
friend class ANG1Axis;
|
||||
};
|
||||
@@ -1,2 +0,0 @@
|
||||
#registrar(ANG1MotorRegister)
|
||||
registrar(ANG1Register)
|
||||
@@ -1,30 +0,0 @@
|
||||
TOP=../..
|
||||
|
||||
include $(TOP)/configure/CONFIG
|
||||
#----------------------------------------
|
||||
# ADD MACRO DEFINITIONS AFTER THIS LINE
|
||||
#=============================
|
||||
|
||||
#==================================================
|
||||
# Build an IOC support library
|
||||
|
||||
LIBRARY_IOC += AMCI
|
||||
|
||||
# motorRecord.h will be created from motorRecord.dbd
|
||||
# install devMotorSoft.dbd into <top>/dbd
|
||||
DBD += AMCISupport.dbd
|
||||
DBD += ANG1Support.dbd
|
||||
DBD += ANF2Support.dbd
|
||||
|
||||
# The following are compiled and added to the Support library
|
||||
AMCI_SRCS += ANG1Driver.cpp
|
||||
AMCI_SRCS += ANF2Driver.cpp
|
||||
|
||||
AMCI_LIBS += motor
|
||||
AMCI_LIBS += asyn
|
||||
AMCI_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
#----------------------------------------
|
||||
# ADD RULES AFTER THIS LINE
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
AMCI ANG1
|
||||
=========
|
||||
|
||||
Asyn model 3 driver support for the AMCI ANG1 stepper motor
|
||||
controller/driver.
|
||||
|
||||
Modbus/TCP communication, using Mark Rivers' modbus module
|
||||
|
||||
Currently some basic parameters, such as IP address, motor current,
|
||||
etc., will need to be set up on the controller using AMCI's PC/Win software.
|
||||
Limits and Home also need to be configured with this software: *
|
||||
+ Limit -> ANG1 Input 1
|
||||
- Limit -> ANG1 Input 2
|
||||
Home -> ANG1 Input 3
|
||||
|
||||
ANG1 configuration software is available from AMCI's website:
|
||||
|
||||
www.amci.com/product-software.asp
|
||||
|
||||
Eventually I would like to implement the "Configuration Mode" options
|
||||
down in the driver, making the AMCI PC software necessary only for
|
||||
initial comms (IP) setup.
|
||||
|
||||
The ANG1 controller/driver is available with or without an ethernet
|
||||
port. A group of controller/drivers can contain up to 6 modules, one of
|
||||
which needs to have the ethernet option. A single-channel
|
||||
implementation would need the module with ethernet. This software is
|
||||
intended to support configurations of multiple groups of 1 to 6 modules.
|
||||
Again, each group will need 1 ethernet enabled module (ANG1-E).
|
||||
|
||||
|
||||
|
||||
asyn model 3 driver files:
|
||||
--------------------------
|
||||
ANG1Driver.cpp
|
||||
ANG1Driver.h
|
||||
ANG1Support.dbd
|
||||
|
||||
|
||||
* Note: 1.) At some point I would like to add the capability to set these
|
||||
parameters at boot-time, using the ANG1 "configuration mode".
|
||||
|
||||
2.) VBAS can only be set in configuration mode (which is not
|
||||
currently supported) or by using the PC configuration software.
|
||||
To use VBAS, set the desired value for the axis using the AMCI
|
||||
PC configuration interface, then set the VBAS field in the
|
||||
motor record accordingly. That way this value will be used by
|
||||
the record to correctly calculate acceleration.
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
# AMCI ANF2
|
||||
|
||||
Asyn model 3 driver support for the AMCI ANF2 stepper motor controller
|
||||
|
||||
Modbus/TCP communication, using Mark Rivers' modbus module
|
||||
|
||||
## Supported Controller Models
|
||||
|
||||
The following ANF controller versions are supported:
|
||||
```
|
||||
ANF1E: 1-axis stepper controller, modbus tcp/ip
|
||||
ANF1: 1-axis stepper controller, no network interface
|
||||
ANF2E: 2-axis stepper controller, modbus tcp/ip
|
||||
ANF2: 2-axis stepper controller, no network interface
|
||||
```
|
||||
A stack of controller can contain up to 6 modules, one of
|
||||
which needs to have the ethernet option. A single-channel
|
||||
implementation would need the module with ethernet.
|
||||
|
||||
## Vendor Software
|
||||
|
||||
ANF2 configuration software is available from AMCI's website:
|
||||
|
||||
www.amci.com/product-software.asp
|
||||
|
||||
Note: The AMCI Net Configurator only works (allows a motor to be moved) if
|
||||
the controller is configured for EtherNet/IP, however, the EPICS support
|
||||
requires the device to be configured for Modbus-TCP.
|
||||
|
||||
## Controller Quirks
|
||||
|
||||
* The controller doesn't allow absolute moves when a limit is active;
|
||||
The only way to move a motor off of a limit is by **jogging**.
|
||||
|
||||
* The base speed is set when an axis is configured. This driver corrects
|
||||
the acceleration sent by the motor record (VBAS isn't guaranteed to match
|
||||
the base speed) and sends the acceleration necessary to achieve the desired
|
||||
acceleration time.
|
||||
|
||||
* The controller doesn't remember its configuration after it is power-cycled.
|
||||
|
||||
* Sending the configuration to the controller invalidates the position
|
||||
requiring either a home search or the redefinition of the current position.
|
||||
|
||||
* The configuration can't be read after a configuration is accepted by the
|
||||
controller, after which it automatically switches into command mode.
|
||||
|
||||
* The command to stop an abosolute move generates an error if a jog is in
|
||||
progress. The command to stop a jog doesn't stop an absolute move.
|
||||
|
||||
## Controller Configuration
|
||||
|
||||
The AMCI Net Configurator can be used to:
|
||||
|
||||
* Change the ip address from the default (192.168.0.50)
|
||||
|
||||
* Change the protocol to Modbus-TCP
|
||||
|
||||
* Determine hex config strings for each axis
|
||||
|
||||
### Example axis configuration
|
||||
|
||||
```
|
||||
0x86000000 - Step & Direction pulses, Diagnostic Feedback, No home switch, No limits
|
||||
0x86280000 - Step & Direction pulses, Diagnostic Feedback, No home switch, Active-low CW/CCW limits
|
||||
0x84000000 - Step & Direction pulses, No Feedback, No home switch, No Limits
|
||||
0x84280000 - Step & Direction pulses, No Feedback, No home switch, Active-low CW/CCW limits
|
||||
0x842C0004 - Step & Direction pulses, No Feedback, Active-high home switch, Active-low CW/CCW limits
|
||||
0x85280000 - Step & Direction pulses, Quadrature Feedback, No home switch, Active-low CW/CCW limits
|
||||
```
|
||||
@@ -1,28 +0,0 @@
|
||||
# Database for extra PVs for AMCI ANG1 controllers
|
||||
|
||||
record(bo,"$(P)$(R)ResetErrors") {
|
||||
field(DESC,"Reset Errors")
|
||||
field(PINI, "0")
|
||||
field(VAL,"0")
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))ANF2_RESET_ERRORS")
|
||||
field(ZNAM, "Done")
|
||||
field(ONAM, "Reset")
|
||||
}
|
||||
|
||||
record(bo,"$(P)$(R)GetInfo") {
|
||||
field(DESC,"Get Info")
|
||||
field(PINI, "0")
|
||||
field(VAL,"0")
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))ANF2_GET_INFO")
|
||||
}
|
||||
|
||||
# Reconfig isn't yet implemented in a generally-useful way
|
||||
#record(longout,"$(P)$(R)Reconfig") {
|
||||
# field(DESC,"Reconfig")
|
||||
# field(PINI, "0")
|
||||
# field(VAL,"0")
|
||||
# field(DTYP, "asynInt32")
|
||||
# field(OUT,"@asyn($(PORT),$(ADDR))ANF2_RECONFIG")
|
||||
#}
|
||||
@@ -27,9 +27,6 @@ PC6KSrc_DEPEND_DIRS = MotorSrc
|
||||
DIRS += SmarActMCSSrc
|
||||
SmarActMCSSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
DIRS += AMCISrc
|
||||
AMCISrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
endif
|
||||
|
||||
# Install the edl files
|
||||
|
||||
Reference in New Issue
Block a user