forked from epics_driver_modules/motorBase
Removed Newport support; Added motorNewport submodule
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
[submodule "modules/motorNewport"]
|
||||
path = modules/motorNewport
|
||||
url = https://github.com/epics-motor/motorNewport.git
|
||||
@@ -13,7 +13,7 @@ To build the iocWithAsyn example;
|
||||
|
||||
Finally, cd <motor>; gnumake clean uninstall; gnumake
|
||||
|
||||
To run this Newport MM4000/5, "asyn" example on a Unix OS;
|
||||
To run this "asyn" example on a Unix OS;
|
||||
- Set the EPICS_HOST_ARCH environment variable correctly.
|
||||
- Edit the st.cmd.unix file for either sun or linux.
|
||||
- Start the ioc from this directory by executing the following command.
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
file "$(TOP)/db/XPSAuxLi.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN, SCAN}
|
||||
{IOC:, XPSAux1Li, XPS_AUX1, 0, "I/O Intr"}
|
||||
{IOC:, XPSAux2Li, XPS_AUX1, 1, "I/O Intr"}
|
||||
{IOC:, XPSAux3Li, XPS_AUX1, 2, "I/O Intr"}
|
||||
{IOC:, XPSAux4Li, XPS_AUX1, 3, "I/O Intr"}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/XPSAuxBi.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN, MASK, SCAN}
|
||||
{IOC:, XPSAux1Bi0, XPS_AUX1, 0, 0x000001, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi1, XPS_AUX1, 0, 0x000002, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi2, XPS_AUX1, 0, 0x000004, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi3, XPS_AUX1, 0, 0x000008, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi4, XPS_AUX1, 0, 0x000010, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi5, XPS_AUX1, 0, 0x000020, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi6, XPS_AUX1, 0, 0x000040, "I/O Intr"}
|
||||
{IOC:, XPSAux1Bi7, XPS_AUX1, 0, 0x000080, "I/O Intr"}
|
||||
{IOC:, XPSAux2Bi0, XPS_AUX1, 1, 0x000001, "I/O Intr"}
|
||||
{IOC:, XPSAux2Bi1, XPS_AUX1, 1, 0x000002, "I/O Intr"}
|
||||
{IOC:, XPSAux2Bi2, XPS_AUX1, 1, 0x000004, "I/O Intr"}
|
||||
{IOC:, XPSAux2Bi3, XPS_AUX1, 1, 0x000008, "I/O Intr"}
|
||||
{IOC:, XPSAux2Bi4, XPS_AUX1, 1, 0x000010, "I/O Intr"}
|
||||
{IOC:, XPSAux2Bi5, XPS_AUX1, 1, 0x000020, "I/O Intr"}
|
||||
{IOC:, XPSAux3Bi0, XPS_AUX1, 2, 0x000001, "I/O Intr"}
|
||||
{IOC:, XPSAux3Bi1, XPS_AUX1, 2, 0x000002, "I/O Intr"}
|
||||
{IOC:, XPSAux3Bi2, XPS_AUX1, 2, 0x000004, "I/O Intr"}
|
||||
{IOC:, XPSAux3Bi3, XPS_AUX1, 2, 0x000008, "I/O Intr"}
|
||||
{IOC:, XPSAux3Bi4, XPS_AUX1, 2, 0x000010, "I/O Intr"}
|
||||
{IOC:, XPSAux3Bi5, XPS_AUX1, 2, 0x000020, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi0, XPS_AUX1, 3, 0x000001, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi1, XPS_AUX1, 3, 0x000002, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi2, XPS_AUX1, 3, 0x000004, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi3, XPS_AUX1, 3, 0x000008, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi4, XPS_AUX1, 3, 0x000010, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi5, XPS_AUX1, 3, 0x000020, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi6, XPS_AUX1, 3, 0x000040, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi7, XPS_AUX1, 3, 0x000080, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi8, XPS_AUX1, 3, 0x000100, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi9, XPS_AUX1, 3, 0x000200, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi10, XPS_AUX1, 3, 0x000400, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi11, XPS_AUX1, 3, 0x000800, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi12, XPS_AUX1, 3, 0x001000, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi13, XPS_AUX1, 3, 0x002000, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi14, XPS_AUX1, 3, 0x004000, "I/O Intr"}
|
||||
{IOC:, XPSAux4Bi15, XPS_AUX1, 3, 0x008000, "I/O Intr"}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/XPSAuxBo.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN, MASK}
|
||||
{IOC:, XPSAux1Bo0, XPS_AUX1, 0, 0x000001}
|
||||
{IOC:, XPSAux1Bo1, XPS_AUX1, 0, 0x000002}
|
||||
{IOC:, XPSAux1Bo2, XPS_AUX1, 0, 0x000004}
|
||||
{IOC:, XPSAux1Bo3, XPS_AUX1, 0, 0x000008}
|
||||
{IOC:, XPSAux1Bo4, XPS_AUX1, 0, 0x000010}
|
||||
{IOC:, XPSAux1Bo5, XPS_AUX1, 0, 0x000020}
|
||||
{IOC:, XPSAux1Bo6, XPS_AUX1, 0, 0x000040}
|
||||
{IOC:, XPSAux1Bo7, XPS_AUX1, 0, 0x000080}
|
||||
{IOC:, XPSAux3Bo0, XPS_AUX1, 1, 0x000001}
|
||||
{IOC:, XPSAux3Bo1, XPS_AUX1, 1, 0x000002}
|
||||
{IOC:, XPSAux3Bo2, XPS_AUX1, 1, 0x000004}
|
||||
{IOC:, XPSAux3Bo3, XPS_AUX1, 1, 0x000008}
|
||||
{IOC:, XPSAux3Bo4, XPS_AUX1, 1, 0x000010}
|
||||
{IOC:, XPSAux3Bo5, XPS_AUX1, 1, 0x000020}
|
||||
{IOC:, XPSAux4Bo0, XPS_AUX1, 2, 0x000001}
|
||||
{IOC:, XPSAux4Bo1, XPS_AUX1, 2, 0x000002}
|
||||
{IOC:, XPSAux4Bo2, XPS_AUX1, 2, 0x000004}
|
||||
{IOC:, XPSAux4Bo3, XPS_AUX1, 2, 0x000008}
|
||||
{IOC:, XPSAux4Bo4, XPS_AUX1, 2, 0x000010}
|
||||
{IOC:, XPSAux4Bo5, XPS_AUX1, 2, 0x000020}
|
||||
{IOC:, XPSAux4Bo6, XPS_AUX1, 2, 0x000040}
|
||||
{IOC:, XPSAux4Bo7, XPS_AUX1, 2, 0x000080}
|
||||
{IOC:, XPSAux4Bo8, XPS_AUX1, 2, 0x000100}
|
||||
{IOC:, XPSAux4Bo9, XPS_AUX1, 2, 0x000200}
|
||||
{IOC:, XPSAux4Bo10, XPS_AUX1, 2, 0x000400}
|
||||
{IOC:, XPSAux4Bo11, XPS_AUX1, 2, 0x000800}
|
||||
{IOC:, XPSAux4Bo12, XPS_AUX1, 2, 0x001000}
|
||||
{IOC:, XPSAux4Bo13, XPS_AUX1, 2, 0x002000}
|
||||
{IOC:, XPSAux4Bo14, XPS_AUX1, 2, 0x004000}
|
||||
{IOC:, XPSAux4Bo15, XPS_AUX1, 2, 0x008000}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/XPSAuxLo.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN}
|
||||
{IOC:, XPSAux1Lo, XPS_AUX1, 0}
|
||||
{IOC:, XPSAux3Lo, XPS_AUX1, 1}
|
||||
{IOC:, XPSAux4Lo, XPS_AUX1, 2}
|
||||
}
|
||||
|
||||
|
||||
file "$(TOP)/db/XPSAuxAi.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN, LOPR, HOPR, PREC, SCAN}
|
||||
{IOC:, XPSAuxAi0, XPS_AUX1, 0, -10.0, 10.0, 4, "1 second"}
|
||||
{IOC:, XPSAuxAi1, XPS_AUX1, 1, -10.0, 10.0, 4, "1 second"}
|
||||
{IOC:, XPSAuxAi2, XPS_AUX1, 2, -10.0, 10.0, 4, "1 second"}
|
||||
{IOC:, XPSAuxAi3, XPS_AUX1, 3, -10.0, 10.0, 4, "1 second"}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/XPSAuxAo.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN, DRVL, LOPR, DRVH, HOPR, PREC}
|
||||
{IOC:, XPSAuxAo0, XPS_AUX1, 0, -10.0, -10.0, 10.0, 10.0, 4}
|
||||
{IOC:, XPSAuxAo1, XPS_AUX1, 1, -10.0, -10.0, 10.0, 10.0, 4}
|
||||
{IOC:, XPSAuxAo2, XPS_AUX1, 2, -10.0, -10.0, 10.0, 10.0, 4}
|
||||
{IOC:, XPSAuxAo3, XPS_AUX1, 3, -10.0, -10.0, 10.0, 10.0 4}
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
sudo modprobe -v ftdi_sio vendor=0x104d product=0x3006
|
||||
sudo chmod o+rw /dev/ttyUSB*
|
||||
@@ -1,2 +0,0 @@
|
||||
sudo modprobe -v ftdi_sio vendor=0x104d product=0x3000
|
||||
sudo chmod o+rw /dev/ttyUSB*
|
||||
@@ -1,11 +0,0 @@
|
||||
dbLoadTemplate("motor.substitutions.hxp")
|
||||
|
||||
HXPCreateController("HXP1", "192.168.1.42", 5001, 200, 1000)
|
||||
# A shorter, idle-poll period is desirable if the motors
|
||||
# are moved using HXP_moveAll.adl, since this period determines
|
||||
# how long it takes for the motor records to see that an
|
||||
# external move has been initiated.
|
||||
#!HXPCreateController("HXP1", "192.168.1.42", 5001, 200, 200)
|
||||
|
||||
#asynSetTraceIOMask("HXP1", 0, 2)
|
||||
#asynSetTraceMask("HXP1", 0, 255)
|
||||
@@ -1,6 +0,0 @@
|
||||
file "$(TOP)/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", Agilis1, 0, "Horizontal", mm, Pos, .5, 0.1, .25, 0, 1, .2, .0001, 4, 28, -1, ""}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
file "$(TOP)/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", Agilis1, 0, "Horizontal", mm, Pos, .5, 0.1, .25, 0, 1, .2, .001, 3, 3, -3, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", Agilis1, 1, "Vertical", mm, Pos, .5, 0.1, .25, 0, 1, .2, .001, 3, 3, -3, ""}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
file "$(TOP)/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}
|
||||
# Newport NSA12 stage, 6.35 microns/full step, 128 micro-steps/s
|
||||
{IOC:, 1, "m$(N)", "asynMotor", CONEX1, 0, "X", mm, Pos, 1., 0.1, .25, 0, 1, .2, 4.9609375e-5, 4, 28, -1, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", CONEX2, 0, "Y", mm, Pos, 1., 0.1, .25, 0, 1, .2, 4.9609375e-5, 4, 28, -1, ""}
|
||||
{IOC:, 3, "m$(N)", "asynMotor", CONEX3, 0, "Z", mm, Pos, 1., 0.1, .25, 0, 1, .2, 4.9609375e-5, 4, 28, -1, ""}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
file "$(TOP)/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", "SMC100_1", 0, "GTS30V", mm, Pos, 1, 0, .2, 0, .5, .2, 0.00001, 6, 25, -5, ""}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
file "$(MOTOR)/motorApp/Db/asyn_motor.db"
|
||||
{
|
||||
pattern
|
||||
{P, M, DTYP, PORT, ADDR, DESC, EGU, DIR, VMAX, VELO, VBAS, ACCL, BDST, BVEL, BACC, MRES, PREC, DHLM, DLLM, INIT, RTRY}
|
||||
{xxx:hxp:c0:, m1, "asynMotor", HXP1, 0, "X", mm, Pos, 15., 3., .05, .5, 0, 1.0, 2, 0.00001, 5, 0, 0, "", 0}
|
||||
{xxx:hxp:c0:, m2, "asynMotor", HXP1, 1, "Y", mm, Pos, 15., 3., .05, .5, 0, 1.0, 2, 0.00001, 5, 0, 0, "", 0}
|
||||
{xxx:hxp:c0:, m3, "asynMotor", HXP1, 2, "Z", mm, Pos, 15., 3., .05, .5, 0, 1.0, 2, 0.00001, 5, 0, 0, "", 0}
|
||||
{xxx:hxp:c0:, m4, "asynMotor", HXP1, 3, "U", degrees, Pos, 15., 3., .05, .5, 0, 1.0, 2, 0.00001, 5, 0, 0, "", 0}
|
||||
{xxx:hxp:c0:, m5, "asynMotor", HXP1, 4, "V", degrees, Pos, 15., 3., .05, .5, 0, 1.0, 2, 0.00001, 5, 0, 0, "", 0}
|
||||
{xxx:hxp:c0:, m6, "asynMotor", HXP1, 5, "W", degrees, Pos, 15., 3., .05, .5, 0, 1.0, 2, 0.00001, 5, 0, 0, "", 0}
|
||||
}
|
||||
|
||||
# Extra HXP controller support (moveAll, status and error PVs)
|
||||
file "$(MOTOR)/motorApp/Db/HXP_extra.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN}
|
||||
{xxx:, hxp:c0:, HXP1, 0}
|
||||
}
|
||||
|
||||
# HXP coordinate-system support (reading and redefining)
|
||||
file "$(MOTOR)/motorApp/Db/HXP_coords.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, CHAN, M1, M2, M3, M4, M5, M6}
|
||||
{xxx:, hxp:c0:, HXP1, 0, m1, m2, m3, m4, m5, m6}
|
||||
}
|
||||
@@ -1,16 +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", XPS1, 0, "motor $(N)", mm, Pos, .3, .1, .2, 0, 1, .2, 0.000048828, 5, 62.5, 50, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", XPS1, 1, "motor $(N)", mm, Pos, .3, .1, .2, 0, 1, .2, 0.000147750, 5, 10, 0, ""}
|
||||
{IOC:, 3, "m$(N)", "asynMotor", XPS1, 2, "motor $(N)", mm, Pos, .3, .1, .2, 0, 1, .2, 0.000048828, 5, 62.5, 50, ""}
|
||||
}
|
||||
file "$(MOTOR)/db/XPS_extra.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, ADDR}
|
||||
{IOC:, m1, XPS1, 0}
|
||||
{IOC:, m2, XPS1 1}
|
||||
{IOC:, m3, XPS1 2}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
file "$(TOP)/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", XPS1, 0, "scanX", mm, Neg, 5., 1, 0.5, 0, 1, .2, 0.000001, 5, 12.4, -12.4, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", XPS1, 1, "scanY", mm, Pos, 5., 1, 0.5, 0, 1, .2, 0.00002, 5, 2.4, -2.4, ""}
|
||||
{IOC:, 3, "m$(N)", "asynMotor", XPS1, 2, "theta", degrees, Pos, 20., 1, 0.5, 0, 1, .2, 0.0005, 4, 150.0, -150.0, ""}
|
||||
{IOC:, 4, "m$(N)", "asynMotor", XPS1, 3, "stageX", mm, Neg, 5., 1, 1.0, 0, 1, .5, 0.0005, 4, 100.0, -100.0, ""}
|
||||
{IOC:, 5, "m$(N)", "asynMotor", XPS1, 4, "stageZ", mm, Neg, 5., 1, 1.0, 0, 1, .5, 0.0005, 4, 100.0, -100.0, ""}
|
||||
{IOC:, 6, "m$(N)", "asynMotor", XPS1, 5, "stageY", mm, Pos, 5., 1, 1.0, 0, 2, .2, 0.0002, 4, 292.0, -8.0, ""}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/XPS_extra.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, ADDR}
|
||||
{IOC:, m1, XPS1, 0}
|
||||
{IOC:, m2, XPS1 1}
|
||||
{IOC:, m3, XPS1 2}
|
||||
{IOC:, m4, XPS1 3}
|
||||
{IOC:, m5, XPS1 4}
|
||||
{IOC:, m6, XPS1 5}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveController.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, NAXES, NPOINTS, NPULSES, TIMEOUT}
|
||||
{IOC:, Prof1:, XPS1, 6, 2000, 2000, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveControllerXPS.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, NAXES, NPOINTS, NPULSES, TIMEOUT}
|
||||
{IOC:, Prof1:, XPS1, 6, 2000, 2000, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveAxis.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, N, M, PORT, ADDR,NPOINTS, NREADBACK, DIR_LINK, OFF_LINK, RES_LINK, PREC, TIMEOUT}
|
||||
{IOC:, Prof1:, 1, "m$(N)", XPS1, 0, 2000, 2000, "IOC:$(M).DIR", "IOC:$(M).OFF", "IOC:$(M).MRES", 5, 1}
|
||||
{IOC:, Prof1:, 2, "m$(N)", XPS1, 1, 2000, 2000, "IOC:$(M).DIR", "IOC:$(M).OFF", "IOC:$(M).MRES", 5, 1}
|
||||
{IOC:, Prof1:, 3, "m$(N)", XPS1, 2, 2000, 2000, "IOC:$(M).DIR", "IOC:$(M).OFF", "IOC:$(M).MRES", 4, 1}
|
||||
{IOC:, Prof1:, 4, "m$(N)", XPS1, 3, 2000, 2000, "IOC:$(M).DIR", "IOC:$(M).OFF", "IOC:$(M).MRES", 4, 1}
|
||||
{IOC:, Prof1:, 5, "m$(N)", XPS1, 4, 2000, 2000, "IOC:$(M).DIR", "IOC:$(M).OFF", "IOC:$(M).MRES", 4, 1}
|
||||
{IOC:, Prof1:, 6, "m$(N)", XPS1, 5, 2000, 2000, "IOC:$(M).DIR", "IOC:$(M).OFF", "IOC:$(M).MRES", 4, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveAxisXPS.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, N, M, PORT, ADDR,NPOINTS, NREADBACK, PREC, TIMEOUT}
|
||||
{IOC:, Prof1:, 1, "m$(N)", XPS1, 0, 2000, 2000, 5, 1}
|
||||
{IOC:, Prof1:, 2, "m$(N)", XPS1, 1, 2000, 2000, 5, 1}
|
||||
{IOC:, Prof1:, 3, "m$(N)", XPS1, 2, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 4, "m$(N)", XPS1, 3, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 5, "m$(N)", XPS1, 4, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 6, "m$(N)", XPS1, 5, 2000, 2000, 4, 1}
|
||||
}
|
||||
@@ -1,62 +0,0 @@
|
||||
file "$(TOP)/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", XPS1, 0, "Phi", degrees, Pos, 15.9, 0.1, 1, 0, 1, .2, .001, 5, 180, -180, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", XPS1, 1, "Kappa", degrees, Pos, 15.9, 0.1, 1, 0, 1, .2, .0002, 5, 180, -180, ""}
|
||||
{IOC:, 3, "m$(N)", "asynMotor", XPS1, 2, "Omega", degrees, Pos, 15.9, 0.1, 1, 0, 1, .2, .0002, 5, 360, -180, ""}
|
||||
{IOC:, 4, "m$(N)", "asynMotor", XPS1, 3, "Psi", degrees, Pos, 3.9, 0.1, .5, 0, 1, .2, .00025, 5, 230, -230, ""}
|
||||
{IOC:, 5, "m$(N)", "asynMotor", XPS1, 4, "2theta", degrees, Pos, 7.9, 0.1, 1, 0, 1, .2, .0001, 5, 190, -10, ""}
|
||||
{IOC:, 6, "m$(N)", "asynMotor", XPS1, 5, "Nu", degrees, Pos, 3.9, 0.1, .5, 0, 1, .2, .00025, 5, 230, -230, ""}
|
||||
}
|
||||
|
||||
|
||||
file "$(TOP)/db/XPS_extra.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, ADDR}
|
||||
{IOC:, m1, XPS1, 0}
|
||||
{IOC:, m2, XPS1 1}
|
||||
{IOC:, m3, XPS1 2}
|
||||
{IOC:, m4, XPS1 3}
|
||||
{IOC:, m5, XPS1 4}
|
||||
{IOC:, m6, XPS1 5}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveController.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, NAXES, NPOINTS, NPULSES, TIMEOUT}
|
||||
{IOC:, Prof1:, XPS1, 6, 2000, 2000, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveControllerXPS.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, NAXES, NPOINTS, NPULSES, TIMEOUT}
|
||||
{IOC:, Prof1:, XPS1, 6, 2000, 2000, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveAxis.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, M, PORT, ADDR,NPOINTS, NREADBACK, MOTOR, PREC, TIMEOUT}
|
||||
{IOC:, Prof1:, 1, XPS1, 0, 2000, 2000, IOC:m1, 5, 1}
|
||||
{IOC:, Prof1:, 2, XPS1, 1, 2000, 2000, IOC:m2, 5, 1}
|
||||
{IOC:, Prof1:, 3, XPS1, 2, 2000, 2000, IOC:m3, 4, 1}
|
||||
{IOC:, Prof1:, 4, XPS1, 3, 2000, 2000, IOC:m4, 4, 1}
|
||||
{IOC:, Prof1:, 5, XPS1, 4, 2000, 2000, IOC:m5, 4, 1}
|
||||
{IOC:, Prof1:, 6, XPS1, 5, 2000, 2000, IOC:m6, 4, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveAxisXPS.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, M, PORT, ADDR,NPOINTS, NREADBACK, PREC, TIMEOUT}
|
||||
{IOC:, Prof1:, 1, XPS1, 0, 2000, 2000, 5, 1}
|
||||
{IOC:, Prof1:, 2, XPS1, 1, 2000, 2000, 5, 1}
|
||||
{IOC:, Prof1:, 3, XPS1, 2, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 4, XPS1, 3, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 5, XPS1, 4, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 6, XPS1, 5, 2000, 2000, 4, 1}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
file "$(TOP)/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", XPS1, 0, "Phi", degrees, Neg, 4.0, 0.1, .25, 0, 1, .2, .001, 3, 180, -180, ""}
|
||||
{IOC:, 2, "m$(N)", "asynMotor", XPS1, 1, "Kappa", degrees, Neg, 6.0, 0.1, .88, 0, 1, .2, .0001, 4, 180, -180, ""}
|
||||
{IOC:, 3, "m$(N)", "asynMotor", XPS1, 2, "Omega", degrees, Neg, 7.0, 0.1, 1.5, 0, 1, .2, .0001, 4, 360, -180, ""}
|
||||
{IOC:, 4, "m$(N)", "asynMotor", XPS1, 3, "Psi", degrees, Neg, 4.0, 0.1, .5, 0, 1, .2, .00025, 4, 190, -190, ""}
|
||||
{IOC:, 5, "m$(N)", "asynMotor", XPS1, 4, "2theta", degrees, Neg, 4.0, 0.1, 1.0, 0, 1, .2, .0001, 4, 196, -17, ""}
|
||||
{IOC:, 6, "m$(N)", "asynMotor", XPS1, 5, "Nu", degrees, Neg, 4.0, 0.1, .5, 0, 1, .2, .00025, 4, 190, -190, ""}
|
||||
{IOC:, 7, "m$(N)", "asynMotor", XPS1, 6, "Dummy1", degrees, Neg, 4.0, 0.1, .5, 0, 1, .2, .00025, 4, 190, -190, ""}
|
||||
{IOC:, 8, "m$(N)", "asynMotor", XPS1, 7, "Dummy2", degrees, Neg, 4.0, 0.1, .5, 0, 1, .2, .00025, 4, 190, -190, ""}
|
||||
}
|
||||
|
||||
|
||||
file "$(TOP)/db/XPS_extra.db"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, ADDR}
|
||||
{IOC:, m1, XPS1, 0}
|
||||
{IOC:, m2, XPS1 1}
|
||||
{IOC:, m3, XPS1 2}
|
||||
{IOC:, m4, XPS1 3}
|
||||
{IOC:, m5, XPS1 4}
|
||||
{IOC:, m6, XPS1 5}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveController.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, NAXES, NPOINTS, NPULSES, TIMEOUT}
|
||||
{IOC:, Prof1:, XPS1, 6, 2000, 2000, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveControllerXPS.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, PORT, NAXES, NPOINTS, NPULSES, TIMEOUT}
|
||||
{IOC:, Prof1:, XPS1, 6, 2000, 2000, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveAxis.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, M, PORT, ADDR,NPOINTS, NREADBACK, MOTOR, PREC, TIMEOUT}
|
||||
{IOC:, Prof1:, 1, XPS1, 0, 2000, 2000, IOC:m1, 3, 1}
|
||||
{IOC:, Prof1:, 2, XPS1, 1, 2000, 2000, IOC:m2, 4, 1}
|
||||
{IOC:, Prof1:, 3, XPS1, 2, 2000, 2000, IOC:m3, 4, 1}
|
||||
{IOC:, Prof1:, 4, XPS1, 3, 2000, 2000, IOC:m4, 4, 1}
|
||||
{IOC:, Prof1:, 5, XPS1, 4, 2000, 2000, IOC:m5, 4, 1}
|
||||
{IOC:, Prof1:, 6, XPS1, 5, 2000, 2000, IOC:m6, 4, 1}
|
||||
{IOC:, Prof1:, 7, XPS1, 6, 2000, 2000, IOC:m6, 4, 1}
|
||||
{IOC:, Prof1:, 8, XPS1, 7, 2000, 2000, IOC:m6, 4, 1}
|
||||
}
|
||||
|
||||
file "$(TOP)/db/profileMoveAxisXPS.template"
|
||||
{
|
||||
pattern
|
||||
{P, R, M, PORT, ADDR,NPOINTS, NREADBACK, PREC, TIMEOUT}
|
||||
{IOC:, Prof1:, 1, XPS1, 0, 2000, 2000, 3, 1}
|
||||
{IOC:, Prof1:, 2, XPS1, 1, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 3, XPS1, 2, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 4, XPS1, 3, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 5, XPS1, 4, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 6, XPS1, 5, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 7, XPS1, 6, 2000, 2000, 4, 1}
|
||||
{IOC:, Prof1:, 8, XPS1, 7, 2000, 2000, 4, 1}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc.
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.AG_CONEX"
|
||||
|
||||
# For Windows
|
||||
#drvAsynSerialPortConfigure("serial1", "COM3", 0, 0, 0)
|
||||
# For Linux
|
||||
drvAsynSerialPortConfigure("serial1", "/dev/ttyUSB0", 0, 0, 0)
|
||||
asynOctetSetInputEos("serial1",0,"\r\n")
|
||||
asynOctetSetOutputEos("serial1",0,"\r\n")
|
||||
asynSetOption("serial1",0,"baud","921600")
|
||||
asynSetOption("serial1",0,"bits","8")
|
||||
asynSetOption("serial1",0,"stop","1")
|
||||
asynSetOption("serial1",0,"parity","none")
|
||||
asynSetOption("serial1",0,"clocal","Y")
|
||||
asynSetOption("serial1",0,"crtscts","N")
|
||||
|
||||
asynSetTraceIOMask("serial1", 0, 2)
|
||||
#asynSetTraceMask("serial1", 0, 9)
|
||||
|
||||
# Load asyn record
|
||||
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=IOC:,R=serial1,PORT=serial1, ADDR=0,OMAX=256,IMAX=256")
|
||||
|
||||
# AG_CONEXCreateController(asyn port, serial port, controllerID,
|
||||
# active poll period (ms), idle poll period (ms))
|
||||
AG_CONEXCreateController("Agilis1", "serial1", 1, 50, 500)
|
||||
asynSetTraceIOMask("Agilis1", 0, 2)
|
||||
#asynSetTraceMask("Agilis1", 0, 255)
|
||||
|
||||
iocInit
|
||||
|
||||
dbpf IOC:m1.RTRY 0
|
||||
dbpf IOC:m1.NTM 0
|
||||
@@ -1,40 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc.
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.AG_UC"
|
||||
|
||||
# For Windows
|
||||
#drvAsynSerialPortConfigure("serial1", "COM3", 0, 0, 0)
|
||||
# For Linux
|
||||
drvAsynSerialPortConfigure("serial1", "/dev/ttyUSB0", 0, 0, 0)
|
||||
asynOctetSetInputEos("serial1",0,"\r\n")
|
||||
asynOctetSetOutputEos("serial1",0,"\r\n")
|
||||
asynSetOption("serial1",0,"baud","921600")
|
||||
asynSetOption("serial1",0,"bits","8")
|
||||
asynSetOption("serial1",0,"stop","1")
|
||||
asynSetOption("serial1",0,"parity","none")
|
||||
asynSetOption("serial1",0,"clocal","Y")
|
||||
asynSetOption("serial1",0,"crtscts","N")
|
||||
|
||||
asynSetTraceIOMask("serial1", 0, 2)
|
||||
#asynSetTraceMask("serial1", 0, 9)
|
||||
|
||||
# Load asynRecord records
|
||||
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=IOC:,R=serial1,PORT=serial1, ADDR=0,OMAX=256,IMAX=256")
|
||||
|
||||
# AG_UCCreateController(asyn port, serial port, number of axes,
|
||||
# active poll period (ms), idle poll period (ms))
|
||||
AG_UCCreateController("Agilis1", "serial1", 2, 50, 500)
|
||||
asynSetTraceIOMask("Agilis1", 0, 2)
|
||||
#asynSetTraceMask("Agilis1", 0, 255)
|
||||
|
||||
# AG_UCCreateAxis((AG_UC controller port, axis, hasLimits, forwardAmplitude, reverseAmplitude)
|
||||
AG_UCCreateAxis("Agilis1", 0, 0, 50, -30)
|
||||
AG_UCCreateAxis("Agilis1", 1, 0, 40, -50)
|
||||
|
||||
iocInit
|
||||
@@ -1,45 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc.
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.CONEX-PP"
|
||||
|
||||
# For Windows
|
||||
drvAsynSerialPortConfigure("serial1", "COM8", 0, 0, 0)
|
||||
# For Linux
|
||||
#drvAsynSerialPortConfigure("serial1", "/dev/ttyUSB0", 0, 0, 0)
|
||||
asynOctetSetInputEos("serial1",0,"\r\n")
|
||||
asynOctetSetOutputEos("serial1",0,"\r\n")
|
||||
asynSetOption("serial1",0,"baud","115200")
|
||||
asynSetOption("serial1",0,"bits","8")
|
||||
asynSetOption("serial1",0,"stop","1")
|
||||
asynSetOption("serial1",0,"parity","none")
|
||||
asynSetOption("serial1",0,"clocal","Y")
|
||||
asynSetOption("serial1",0,"crtscts","N")
|
||||
|
||||
asynSetTraceIOMask("serial1", 0, 2)
|
||||
#asynSetTraceMask("serial1", 0, 9)
|
||||
|
||||
# Load asyn record
|
||||
dbLoadRecords("$(ASYN)/db/asynRecord.db", "P=IOC:,R=serial1,PORT=serial1, ADDR=0,OMAX=256,IMAX=256")
|
||||
|
||||
# AG_CONEXCreateController(asyn port, serial port, controllerID,
|
||||
# active poll period (ms), idle poll period (ms))
|
||||
AG_CONEXCreateController("CONEX1", "serial1", 1, 50, 500)
|
||||
asynSetTraceIOMask("CONEX1", 0, 2)
|
||||
#asynSetTraceMask("CONEX1", 0, 255)
|
||||
AG_CONEXCreateController("CONEX2", "serial1", 2, 50, 500)
|
||||
asynSetTraceIOMask("CONEX2", 0, 2)
|
||||
#asynSetTraceMask("CONEX2", 0, 255)
|
||||
AG_CONEXCreateController("CONEX3", "serial1", 3, 50, 500)
|
||||
asynSetTraceIOMask("CONEX3", 0, 2)
|
||||
#asynSetTraceMask("CONEX3", 0, 255)
|
||||
|
||||
iocInit
|
||||
|
||||
dbpf IOC:m1.RTRY 0
|
||||
dbpf IOC:m1.NTM 0
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.SMC100"
|
||||
|
||||
### Serial port setup
|
||||
drvAsynSerialPortConfigure("serial1", "/dev/ttyS0", 0, 0, 0)
|
||||
asynSetOption(serial1,0,baud,57600)
|
||||
asynOctetSetInputEos("serial1",0,"\r\n")
|
||||
asynOctetSetOutputEos("serial1",0,"\r\n")
|
||||
|
||||
### Newport SMC100 support
|
||||
# (driver port, serial port, axis num, ms mov poll, ms idle poll, egu per step)
|
||||
SMC100CreateController("SMC100_1", "serial1",1, 100, 0, "0.00005")
|
||||
|
||||
iocInit
|
||||
@@ -1,4 +1,4 @@
|
||||
# The is the "ASYN" example for communication to either a Newport MM4000/5 or an
|
||||
# The is the "ASYN" example for communication to an
|
||||
# IMS483 controller. The examples must be configured by including or omitting
|
||||
# comment characters (i.e., #'s) from this file.
|
||||
|
||||
@@ -28,42 +28,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
# Configure the ASYN server code. This MUST be configured too!
|
||||
< st_asynserver.cmd.Vx
|
||||
|
||||
# Newport MM3000 and MM4000/5/6 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!MM3000Setup(1, 10)
|
||||
#!MM4000Setup(1, 10)
|
||||
|
||||
# Newport MM3000 and MM4000/5/6 driver configuration parameters:
|
||||
# (1) controller# being configured
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!MM3000Config(0, "a-Serial[0]")
|
||||
#!drvMM3000debug=4
|
||||
#!MM4000Config(0, "a-Serial[0]")
|
||||
#!drvMM4000debug=4
|
||||
|
||||
# The MM4000 driver does not set end of string (EOS).
|
||||
# for RS232 serial,
|
||||
#!asynOctetSetInputEos( "a-Serial[0]",0,"\r")
|
||||
#!asynOctetSetOutputEos("a-Serial[0]",0,"\r")
|
||||
# for GPIB,
|
||||
#!asynInterposeEosConfig("L0", 10, 1, 1)
|
||||
#!asynOctetSetInputEos( "L0",10,"\r")
|
||||
#!asynOctetSetOutputEos("L0",10,"\r")
|
||||
|
||||
# Newport PM500 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PM500Setup(1, 10)
|
||||
|
||||
# Newport PM500 configuration parameters:
|
||||
# (1) controller# being configured
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!PM500Config(0, "a-Serial[0]")
|
||||
#!drvPM500debug=4
|
||||
|
||||
# IMS IM483 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
@@ -93,18 +57,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
#!asynOctetSetOutputEos("a-Serial[0]",0,"\r")
|
||||
#!drvMCB4BDebug=4
|
||||
|
||||
# Newport ESP300 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!ESP300Setup(1, 10)
|
||||
|
||||
# Newport ESP300 driver configuration parameters:
|
||||
# (1) controller# being configured
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!ESP300Config(0, "a-Serial[0]")
|
||||
#!drvESP300debug = 4
|
||||
|
||||
# MicroMo MVP2001 driver setup parameters:
|
||||
#
|
||||
# NOTE: The 1st controller on each chain should have it's address = 1.
|
||||
@@ -209,34 +161,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
#!MDriveConfig(0, "a-Serial[0]")
|
||||
#!drvMDrivedebug = 4
|
||||
|
||||
# Newport XPS driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
#!XPSSetup(2)
|
||||
|
||||
# Newport XPS driver configuration parameters:
|
||||
# (1) Controller # being configured
|
||||
# (2) IP address or IP name
|
||||
# (3) IP port number that XPS is listening on
|
||||
# (4) Number of axes this controller supports
|
||||
# (5) Time to poll (msec) when an axis is in motion
|
||||
# (6) Time to poll (msec) when an axis is idle. 0 for no polling
|
||||
#!XPSConfig(0, "xxx.xx.xxx.1", 5001, 5, 100, 500)
|
||||
#!XPSConfig(1, "xxx.xx.xxx.2", 5001, 4, 100, 500)
|
||||
|
||||
# Newport XPS group and positioner name configuration:
|
||||
# (1) Controller # being configured
|
||||
# (2) axis number 0-7
|
||||
# (3) groupName.positionerName e.g. Diffractometer.Phi
|
||||
# (4) steps per user unit
|
||||
|
||||
#!XPSConfigAxis(0, 0, "GROUP1.PHI", 10000)
|
||||
#!XPSConfigAxis(0, 1, "GROUP1.KAPPA", 10000)
|
||||
|
||||
#!XPSConfigAxis(1, 0, "GROUP1.Y1_BASE", 1000)
|
||||
#!XPSConfigAxis(1, 1, "GROUP2.Y2_BASE", 1000)
|
||||
#!XPSConfigAxis(1, 2, "GROUP3.Y3_BASE", 1000)
|
||||
|
||||
|
||||
# OMS PC68/78 stand-alone serial driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
@@ -317,28 +241,12 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
# (6) Time to poll (msec) when an axis is idle. 0 for no polling
|
||||
#!EnsembleAsynConfig(0, EnsemblePort, 0, 1, 100, 1000)
|
||||
|
||||
|
||||
# Newport MM4000/5/6 asyn motor driver setup parameter.
|
||||
#!MM4000AsynSetup(1) /* number of MM4000 controllers in system. */
|
||||
|
||||
# Newport MM4000/5/6 asyn motor driver configure parameters.
|
||||
# (1) Controller number being configured
|
||||
# (2) ASYN port name
|
||||
# (3) ASYN address (GPIB only)
|
||||
# (4) Number of axes this controller supports
|
||||
# (5) Time to poll (msec) when an axis is in motion
|
||||
# (6) Time to poll (msec) when an axis is idle. 0 for no polling
|
||||
#!MM4000AsynConfig(0, "a-Serial[1]", 0, 1, 100, 250)
|
||||
|
||||
# Asyn-based Motor Record support
|
||||
# (1) Asyn port
|
||||
# (2) Driver name
|
||||
# (3) Controller index
|
||||
# (4) Max. number of axes
|
||||
#!drvAsynMotorConfigure("MM4", "motorMM4000", 0, 4)
|
||||
#!drvAsynMotorConfigure("ANC150","motorANC150", 0, 2 )
|
||||
#!drvAsynMotorConfigure("XPS1", "motorXPS", 0, 5)
|
||||
#!drvAsynMotorConfigure("XPS2", "motorXPS", 1, 5)
|
||||
#!drvAsynMotorConfigure("AeroE1","motorEnsemble", 0, 1)
|
||||
#!drvAsynMotorConfigure("AeroE2","motorEnsemble", 1, 1)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# The is the ASYN example for communication to a Newport MM4000/5/6.
|
||||
# The is the ASYN example for communication
|
||||
# "#!" marks lines that can be uncommented.
|
||||
|
||||
< envPaths
|
||||
@@ -21,43 +21,6 @@ asynSetOption("L0", -1, "stop", "1")
|
||||
asynSetOption("L0", -1, "clocal", "Y")
|
||||
asynSetOption("L0", -1, "crtscts", "N")
|
||||
|
||||
|
||||
# Newport MM3000 and MM4000/5/6 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!MM3000Setup(1, 10)
|
||||
MM4000Setup(1, 10)
|
||||
|
||||
# Newport MM3000 and MM4000/5/6 driver configuration parameters:
|
||||
# (1) controller# being configured
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!MM3000Config(0, "a-Serial[0]")
|
||||
#!drvMM3000debug=4
|
||||
MM4000Config(0, "L0")
|
||||
#!var drvMM4000debug 4
|
||||
|
||||
# The MM4000 driver does not set end of string (EOS).
|
||||
# for RS232 serial,
|
||||
#!asynOctetSetInputEos( "a-Serial[0]",0,"\r")
|
||||
#!asynOctetSetOutputEos("a-Serial[0]",0,"\r")
|
||||
# for GPIB,
|
||||
#!asynInterposeEosConfig("L0", 10, 1, 1)
|
||||
#!asynOctetSetInputEos( "L0",10,"\r")
|
||||
#!asynOctetSetOutputEos("L0",10,"\r")
|
||||
|
||||
# Newport PM500 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PM500Setup(1, 10)
|
||||
|
||||
# Newport PM500 configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!PM500Config(0, "L0")
|
||||
#!var drvPM500debug 4
|
||||
|
||||
# IMS IM483 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
@@ -87,18 +50,6 @@ MM4000Config(0, "L0")
|
||||
#!asynOctetSetOutputEos("L0",0,"\r")
|
||||
#!var drvMCB4BDebug 4
|
||||
|
||||
# Newport ESP300 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!ESP300Setup(1, 10)
|
||||
|
||||
# Newport ESP300 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!ESP300Config(0, "L0")
|
||||
#!var drvESP300debug 4
|
||||
|
||||
# MicroMo MVP2001 driver setup parameters:
|
||||
#
|
||||
# NOTE: The 1st controller on each chain should have it's address = 1.
|
||||
@@ -217,25 +168,11 @@ MM4000Config(0, "L0")
|
||||
# (2) asyn port name (string)
|
||||
#!EnsembleConfig(0, "a-Serial[0]")
|
||||
|
||||
|
||||
# Newport MM4000/5/6 asyn motor driver setup parameter.
|
||||
#!MM4000AsynSetup(1) /* number of MM4000 controllers in system. */
|
||||
|
||||
# Newport MM4000/5/6 asyn motor driver configure parameters.
|
||||
# (1) Controller number being configured
|
||||
# (2) ASYN port name
|
||||
# (3) ASYN address (GPIB only)
|
||||
# (4) Number of axes this controller supports
|
||||
# (5) Time to poll (msec) when an axis is in motion
|
||||
# (6) Time to poll (msec) when an axis is idle. 0 for no polling
|
||||
#!MM4000AsynConfig(0, "a-Serial[1]", 0, 1, 100, 250)
|
||||
|
||||
# Asyn-based Motor Record support
|
||||
# (1) Asyn port
|
||||
# (2) Driver name
|
||||
# (3) Controller index
|
||||
# (4) Max. number of axes
|
||||
#!drvAsynMotorConfigure("MM4", "motorMM4000", 0, 4)
|
||||
#!drvAsynMotorConfigure("ANC150","motorANC150", 0, 1)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# The is the ASYN example for communication to a Newport MM4000/5/6.
|
||||
# The is the ASYN example for communication
|
||||
# "#!" marks lines that can be uncommented.
|
||||
|
||||
< envPaths
|
||||
@@ -10,33 +10,6 @@ dbLoadRecords("$(MOTOR)/db/motorUtil.db", "P=IOC:")
|
||||
|
||||
# This is for WIN32, local serial ports not supported. Must use IP terminal server.
|
||||
|
||||
# Newport MM3000 and MM4000/5/6 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!MM3000Setup(1, 10)
|
||||
MM4000Setup(1, 10)
|
||||
|
||||
# Newport MM3000 and MM4000/5/6 driver configuration parameters:
|
||||
# (1) controller# being configured
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!MM3000Config(0, "a-Serial[0]")
|
||||
#!drvMM3000debug=4
|
||||
MM4000Config(0, "L0")
|
||||
#!var drvMM4000debug 4
|
||||
|
||||
# Newport PM500 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!PM500Setup(1, 10)
|
||||
|
||||
# Newport PM500 configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!PM500Config(0, "L0")
|
||||
#!var drvPM500debug 4
|
||||
|
||||
# IMS IM483 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
@@ -66,18 +39,6 @@ MM4000Config(0, "L0")
|
||||
#!asynOctetSetOutputEos("L0",0,"\r")
|
||||
#!var drvMCB4BDebug 4
|
||||
|
||||
# Newport ESP300 driver setup parameters:
|
||||
# (1) maximum number of controllers in system
|
||||
# (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
#!ESP300Setup(1, 10)
|
||||
|
||||
# Newport ESP300 driver configuration parameters:
|
||||
# (1) controller# being configured,
|
||||
# (2) ASYN port name
|
||||
# (3) address (GPIB only)
|
||||
#!ESP300Config(0, "L0")
|
||||
#!var drvESP300debug 4
|
||||
|
||||
# MicroMo MVP2001 driver setup parameters:
|
||||
#
|
||||
# NOTE: The 1st controller on each chain should have it's address = 1.
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc. in this build from CARS
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.xps"
|
||||
|
||||
dbLoadTemplate "XPSAux.substitutions"
|
||||
|
||||
# cards (total controllers)
|
||||
XPSSetup(1)
|
||||
|
||||
# card, IP, PORT, number of axes, active poll period (ms), idle poll period (ms)
|
||||
XPSConfig(0, "newport-xps3", 5001, 3, 10, 5000)
|
||||
|
||||
# asynPort, IP address, IP port, poll period (ms)
|
||||
XPSAuxConfig("XPS_AUX1", "newport-xps3", 5001, 50)
|
||||
#asynSetTraceMask("XPS_AUX1", 0, 255)
|
||||
#asynSetTraceIOMask("XPS_AUX1", 0, 2)
|
||||
|
||||
# asyn port, driver name, controller index, max. axes)
|
||||
drvAsynMotorConfigure("XPS1", "motorXPS", 0, 3)
|
||||
XPSInterpose("XPS1")
|
||||
|
||||
# card, axis, groupName.positionerName
|
||||
XPSConfigAxis(0,0,"GROUP1.POSITIONER",20480)
|
||||
XPSConfigAxis(0,1,"GROUP2.POSITIONER1",6768)
|
||||
XPSConfigAxis(0,2,"GROUP2.POSITIONER2",20480)
|
||||
|
||||
#asynSetTraceMask newport-xps3:5001:0 0 255
|
||||
#asynSetTraceIOMask newport-xps3:5001:0 0 2
|
||||
#asynSetTraceMask newport-xps3:5001:1 0 255
|
||||
#asynSetTraceIOMask newport-xps3:5001:1 0 2
|
||||
#asynSetTraceMask XPS1 0 255
|
||||
#asynSetTraceIOMask XPS1 0 2
|
||||
#asynSetTraceMask XPS1 1 255
|
||||
#asynSetTraceIOMask XPS1 1 2
|
||||
#asynSetTraceMask XPS1 2 255
|
||||
#asynSetTraceIOMask XPS1 2 2
|
||||
#asynSetTraceMask newport-xps3:5001:3 0 255
|
||||
#asynSetTraceIOMask newport-xps3:5001:3 0 2
|
||||
|
||||
dbLoadRecords("$(MOTOR)/motorApp/Db/trajectoryScan.db", "P=IOC:,R=traj1,NAXES=2,NELM=2000,NPULSE=2000,DONPV=13LAB:str:EraseStart,DONV=1,DOFFPV=13LAB:str:StopAll,DOFFV=1")
|
||||
|
||||
iocInit
|
||||
|
||||
seq(XPS_trajectoryScan,"P=IOC:,R=traj1,M1=m2,M2=m3,IPADDR=164.54.160.34,PORT=5001,GROUP=GROUP2,P1=POSITIONER1,P2=POSITIONER2")
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc. in this build from CARS
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.xps3"
|
||||
|
||||
dbLoadTemplate "XPSAux.substitutions"
|
||||
|
||||
# asyn port, IP address, IP port, number of axes, active poll period (ms), idle poll period (ms)
|
||||
XPSConfig("XPS1", "164.54.160.180", 5001, 6, 20, 500)
|
||||
|
||||
# asynPort, IP address, IP port, poll period (ms)
|
||||
XPSAuxConfig("XPS_AUX1", "164.54.160.180", 5001, 50)
|
||||
#asynSetTraceMask("XPS_AUX1", 0, 255)
|
||||
#asynSetTraceIOMask("XPS_AUX1", 0, 2)
|
||||
|
||||
# XPS asyn port, axis, groupName.positionerName, stepSize
|
||||
XPSConfigAxis("XPS1",0,"FINE.X", 100000) # VP-25XL
|
||||
XPSConfigAxis("XPS1",1,"FINE.Y", 50000) # VP-5ZA
|
||||
XPSConfigAxis("XPS1",2,"THETA.POSITIONER", 2000) # URS75CC
|
||||
XPSConfigAxis("XPS1",3,"COARSEX.POSITIONER", 2000) # ILS200CC
|
||||
XPSConfigAxis("XPS1",4,"COARSEY.POSITIONER", 2000) # ILS200CC
|
||||
XPSConfigAxis("XPS1",5,"COARSEZ.POSITIONER", 5000) # IMS300CC
|
||||
|
||||
XPSEnableSetPosition(XPS1, 0)
|
||||
XPSSetPositionSettlingTime(XPS1, 200)
|
||||
|
||||
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")
|
||||
dbpf("IOC:m5.RTRY", "0")
|
||||
dbpf("IOC:m5.TWV", "0.1")
|
||||
dbpf("IOC:m6.RTRY", "0")
|
||||
dbpf("IOC:m6.TWV", "0.1")
|
||||
@@ -1,54 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc. in this build from CARS
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.xps4"
|
||||
|
||||
dbLoadTemplate "XPSAux.substitutions"
|
||||
|
||||
# asyn port, IP address, IP port, number of axes,
|
||||
# active poll period (ms), idle poll period (ms),
|
||||
# enable set position, set position settling time (ms)
|
||||
XPSConfig("XPS1", "164.54.160.124", 5001, 6, 10, 500, 0, 500)
|
||||
asynSetTraceIOMask("XPS1", 0, 2)
|
||||
#asynSetTraceMask("XPS1", 0, 255)
|
||||
|
||||
# asynPort, IP address, IP port, poll period (ms)
|
||||
XPSAuxConfig("XPS_AUX1", "164.54.160.124", 5001, 50)
|
||||
#asynSetTraceIOMask("XPS_AUX1", 0, 2)
|
||||
#asynSetTraceMask("XPS_AUX1", 0, 255)
|
||||
|
||||
# XPS asyn port, axis, groupName.positionerName, stepSize
|
||||
XPSConfigAxis("XPS1",0,"GROUP1.PHI", 1000)
|
||||
XPSConfigAxis("XPS1",1,"GROUP1.KAPPA", 5000)
|
||||
XPSConfigAxis("XPS1",2,"GROUP1.OMEGA", 5000)
|
||||
XPSConfigAxis("XPS1",3,"GROUP1.PSI", 4000)
|
||||
XPSConfigAxis("XPS1",4,"GROUP1.2THETA", 10000)
|
||||
XPSConfigAxis("XPS1",5,"GROUP1.NU", 4000)
|
||||
|
||||
# XPS asyn port, max points, FTP username, FTP password
|
||||
# Note: this must be done after configuring axes
|
||||
XPSConfigProfile("XPS1", 2000, "Administrator", "Administrator")
|
||||
|
||||
XPSEnableSetPosition(XPS1, 0)
|
||||
XPSSetPositionSettlingTime(XPS1, 200)
|
||||
|
||||
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")
|
||||
dbpf("IOC:m5.RTRY", "0")
|
||||
dbpf("IOC:m5.TWV", "0.1")
|
||||
dbpf("IOC:m6.RTRY", "0")
|
||||
dbpf("IOC:m6.TWV", "0.1")
|
||||
@@ -1,51 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc. in this build from CARS
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.xps5"
|
||||
|
||||
dbLoadTemplate "XPSAux.substitutions"
|
||||
|
||||
# asyn port, IP address, IP port, number of axes,
|
||||
# active poll period (ms), idle poll period (ms),
|
||||
# enable set position, set position settling time (ms)
|
||||
XPSCreateController("XPS1", "164.54.160.55", 5001, 6, 10, 500, 0, 500)
|
||||
asynSetTraceIOMask("XPS1", 0, 2)
|
||||
#asynSetTraceMask("XPS1", 0, 255)
|
||||
|
||||
# asynPort, IP address, IP port, poll period (ms)
|
||||
XPSAuxConfig("XPS_AUX1", "164.54.160.55", 5001, 50)
|
||||
#asynSetTraceIOMask("XPS_AUX1", 0, 2)
|
||||
#asynSetTraceMask("XPS_AUX1", 0, 255)
|
||||
|
||||
# XPS asyn port, axis, groupName.positionerName, stepSize
|
||||
XPSCreateAxis("XPS1",0,"GROUP.PHI", "1000")
|
||||
XPSCreateAxis("XPS1",1,"GROUP.KAPPA", "10000")
|
||||
XPSCreateAxis("XPS1",2,"GROUP.OMEGA", "10000")
|
||||
XPSCreateAxis("XPS1",3,"GROUP.PSI", "4000")
|
||||
XPSCreateAxis("XPS1",4,"GROUP.THETA", "10000")
|
||||
XPSCreateAxis("XPS1",5,"GROUP.NU", "4000")
|
||||
|
||||
# XPS asyn port, max points, FTP username, FTP password
|
||||
# Note: this must be done after configuring axes
|
||||
XPSCreateProfile("XPS1", 2000, "Administrator", "Administrator")
|
||||
|
||||
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")
|
||||
dbpf("IOC:m5.RTRY", "0")
|
||||
dbpf("IOC:m5.TWV", "0.1")
|
||||
dbpf("IOC:m6.RTRY", "0")
|
||||
dbpf("IOC:m6.TWV", "0.1")
|
||||
@@ -1,46 +0,0 @@
|
||||
#errlogInit(5000)
|
||||
< envPaths
|
||||
# Tell EPICS all about the record types, device-support modules, drivers,
|
||||
# etc. in this build from CARS
|
||||
dbLoadDatabase("../../dbd/WithAsyn.dbd")
|
||||
WithAsyn_registerRecordDeviceDriver(pdbbase)
|
||||
|
||||
### Motors
|
||||
dbLoadTemplate "motor.substitutions.xps6"
|
||||
|
||||
dbLoadTemplate "XPSAux.substitutions"
|
||||
|
||||
# asyn port, IP address, IP port, number of axes,
|
||||
# active poll period (ms), idle poll period (ms),
|
||||
# enable set position, set position settling time (ms)
|
||||
XPSCreateController("XPS1", "164.54.164.24", 5001, 4, 10, 500, 0, 500)
|
||||
asynSetTraceIOMask("XPS1", 0, 2)
|
||||
#asynSetTraceMask("XPS1", 0, 255)
|
||||
|
||||
# asynPort, IP address, IP port, poll period (ms)
|
||||
XPSAuxConfig("XPS_AUX1", "164.54.164.24", 5001, 50)
|
||||
#asynSetTraceIOMask("XPS_AUX1", 0, 2)
|
||||
#asynSetTraceMask("XPS_AUX1", 0, 255)
|
||||
|
||||
# XPS asyn port, axis, groupName.positionerName, stepSize
|
||||
XPSCreateAxis("XPS1",0,"Group1.Pos", "10000")
|
||||
XPSCreateAxis("XPS1",1,"Group2.Pos", "10000")
|
||||
XPSCreateAxis("XPS1",2,"Group3.Pos", "20000")
|
||||
XPSCreateAxis("XPS1",3,"Group4.Pos", "2000")
|
||||
|
||||
# XPS asyn port, max points, FTP username, FTP password
|
||||
# Note: this must be done after configuring axes
|
||||
XPSCreateProfile("XPS1", 2000, "Administrator", "Administrator")
|
||||
|
||||
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")
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
# ### Newport_ESP300.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Default: 0
|
||||
#-
|
||||
#- MAX_CONTROLLERS - Optional: Max number of controllers that will be configured
|
||||
#- Default: 1
|
||||
#-
|
||||
#- POLL_RATE - Optional: Polling increment in 1/60 sec
|
||||
#- Default: 6
|
||||
#- ###################################################
|
||||
|
||||
#- Newport ESP300 driver setup parameters:
|
||||
#- (1) maximum number of controllers in system
|
||||
#- (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
$(ESP300_INIT_COMPLETE="") ESP300Setup($(MAX_CONTROLLERS=1), $(POLL_RATE=10))
|
||||
|
||||
# Newport ESP300 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=9600, BITS=8, STOP=1, PARITY=none")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "")
|
||||
|
||||
#- Newport ESP300 driver configuration parameters:
|
||||
#- (1) controller# being configured
|
||||
#- (2) ASYN port name
|
||||
ESP300Config($(CONTROLLER=0), "$(PORT)")
|
||||
|
||||
epicsEnvSet("ESP300_INIT_COMPLETE", "#")
|
||||
@@ -1,32 +0,0 @@
|
||||
# ### Newport_NM4000.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Default: 0
|
||||
#-
|
||||
#- MAX_CONTROLLERS - Optional: Max number of controllers that will be configured
|
||||
#- Default: 1
|
||||
#-
|
||||
#- POLL_RATE - Optional: Controller poll rate in hertz
|
||||
#- Default: 10
|
||||
#- ###################################################
|
||||
|
||||
|
||||
#- Newport MM4000 driver setup parameters:
|
||||
#- (1) maximum # of controllers,
|
||||
#- (2) motor task polling rate (min=1Hz, max=60Hz)
|
||||
$(MM4000_INIT_COMPLETE="") MM4000Setup($(MAX_CONTROLLERS=1), $(POLL_RATE=10))
|
||||
|
||||
# Newport MM4000 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=38400, BITS=8, STOP=1, PARITY=none")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "\r")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "\r")
|
||||
|
||||
# Newport MM4000 driver configuration parameters:
|
||||
# (1) controller
|
||||
# (2) asyn port name (e.g. serial0 or gpib1)
|
||||
# (3) GPIB address (0 for serial)
|
||||
MM4000Config($(CONTROLLER=0), "$(PORT)", 0)
|
||||
|
||||
epicsEnvSet("MM4000_INIT_COMPLETE", "#")
|
||||
@@ -1,30 +0,0 @@
|
||||
# ### Newport_PM500.iocsh ###
|
||||
|
||||
#- ###################################################
|
||||
#- PORT - Serial port for communications
|
||||
#- CONTROLLER - Optional: Which controller is being configured
|
||||
#- Default: 0
|
||||
#-
|
||||
#- MAX_CONTROLLERS - Optional: Max number of controllers that will be configured
|
||||
#- Default: 1
|
||||
#-
|
||||
#- POLL_RATE - Optional: Controller poll rate in hertz
|
||||
#- Default: 10
|
||||
#- ###################################################
|
||||
|
||||
#- Newport PM500 driver setup parameters:
|
||||
#- (1) maximum number of controllers in system
|
||||
#- (2) motor task polling rate (min=1Hz,max=60Hz)
|
||||
$(PM500_INIT_COMPLETE="") PM500Setup($(MAX_CONTROLLERS=1), $(POLL_RATE=10))
|
||||
|
||||
#- Newport PM500 serial connection settings
|
||||
iocshLoad("$(IP)/iocsh/setSerialParams.iocsh", "PORT=$(PORT), BAUD=9600, BITS=7, STOP=2, PARITY=even, HANDSHAKE=hardware")
|
||||
asynOctetSetInputEos( "$(PORT)", -1, "\r")
|
||||
asynOctetSetOutputEos("$(PORT)", -1, "\r")
|
||||
|
||||
#- Newport PM500 configuration parameters:
|
||||
#- (1) controller
|
||||
#- (2) asyn port name (e.g. serial0 or gpib1)
|
||||
PM500Config($(CONTROLLER=0), "$(PORT)")
|
||||
|
||||
epicsEnvSet("PM500_INIT_COMPLETE", "#")
|
||||
@@ -3,6 +3,7 @@ include $(TOP)/configure/CONFIG
|
||||
|
||||
# Submodules
|
||||
#SUBMODULES += motorVendor
|
||||
SUBMODULES += motorNewport
|
||||
|
||||
# Allow sites to add extra submodules
|
||||
-include Makefile.local
|
||||
|
||||
Submodule
+1
Submodule modules/motorNewport added at 11ea6d08c7
@@ -1,277 +0,0 @@
|
||||
# CS selection menu
|
||||
record(mbbo,"$(P)$(R)CS_TO_SET") {
|
||||
field(DESC,"Coord sys menu")
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT,"@asynMask($(PORT) 0 0xFFFF)HXP_COORD_SYS_TO_SET")
|
||||
field(ZRVL,"0")
|
||||
field(ZRST,"None")
|
||||
field(ONVL,"1")
|
||||
field(ONST,"Work")
|
||||
field(TWVL,"2")
|
||||
field(TWST,"Tool")
|
||||
field(THVL,"3")
|
||||
field(THST,"Base")
|
||||
field(VAL, "0")
|
||||
}
|
||||
|
||||
# CS set button
|
||||
record(bo,"$(P)$(R)SET_CS") {
|
||||
field(DESC,"Set Coord System")
|
||||
field(DTYP,"asynInt32")
|
||||
field(ZNAM,"Done")
|
||||
field(ONAM,"Setting")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET")
|
||||
field(VAL, "0")
|
||||
}
|
||||
|
||||
# Monitor set-CS PV and initiate sync on release of button
|
||||
record(calcout,"$(P)$(R)syncCalc") {
|
||||
field(DESC,"HXP sync calc")
|
||||
field(DTYP,"Soft Channel")
|
||||
field(SCAN,"Passive")
|
||||
field(INPA,"$(P)$(R)SET_CS.VAL CP NMS")
|
||||
field(B, "1.0")
|
||||
field(CALC,"A")
|
||||
field(OCAL,"B")
|
||||
field(ODLY,"0.5")
|
||||
field(OOPT,"Transition To Zero")
|
||||
field(DOPT,"Use OCAL")
|
||||
field(OUT, "$(P)$(R)syncSeq.PROC PP NMS")
|
||||
}
|
||||
|
||||
# Sync target positions and update CS readbacks after setting a CS
|
||||
record(sseq, "$(P)$(R)syncSeq") {
|
||||
field(DESC,"HXP sync seq")
|
||||
field(SCAN,"Passive")
|
||||
field(STR1,"1")
|
||||
field(LNK1,"$(P)$(R)$(M1).SYNC PP NMS")
|
||||
field(STR2,"1")
|
||||
field(LNK2,"$(P)$(R)$(M2).SYNC PP NMS")
|
||||
field(STR3,"1")
|
||||
field(LNK3,"$(P)$(R)$(M3).SYNC PP NMS")
|
||||
field(STR4,"1")
|
||||
field(LNK4,"$(P)$(R)$(M4).SYNC PP NMS")
|
||||
field(STR5,"1")
|
||||
field(LNK5,"$(P)$(R)$(M5).SYNC PP NMS")
|
||||
field(STR6,"1")
|
||||
field(LNK6,"$(P)$(R)$(M6).SYNC PP NMS")
|
||||
field(STR7,"1")
|
||||
field(LNK7,"$(P)$(R)READ_CS.VAL PP NMS")
|
||||
field(DLY8,"0.25")
|
||||
field(STR8,"0")
|
||||
field(LNK8,"$(P)$(R)READ_CS.VAL PP NMS")
|
||||
}
|
||||
|
||||
# CS input fields
|
||||
record(ao,"$(P)$(R)CS_SET_X") {
|
||||
field(DESC,"CS X target")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET_X")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)CS_SET_Y") {
|
||||
field(DESC,"CS Y target")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET_Y")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)CS_SET_Z") {
|
||||
field(DESC,"CS Z target")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET_Z")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)CS_SET_U") {
|
||||
field(DESC,"CS U target")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET_U")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)CS_SET_V") {
|
||||
field(DESC,"CS V target")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET_V")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)CS_SET_W") {
|
||||
field(DESC,"CS W target")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_SET_W")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
#
|
||||
record(bo,"$(P)$(R)READ_CS") {
|
||||
field(DESC,"Read Coord Systems")
|
||||
field(DTYP,"asynInt32")
|
||||
field(ZNAM,"Done")
|
||||
field(ONAM,"Read")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_COORD_SYS_READ_ALL")
|
||||
field(VAL, "1")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
# TOOL CS readbacks
|
||||
record(ai,"$(P)$(R)TOOL:X") {
|
||||
field(DESC,"TOOL coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_TOOL_X")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)TOOL:Y") {
|
||||
field(DESC,"TOOL coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_TOOL_Y")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)TOOL:Z") {
|
||||
field(DESC,"TOOL coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_TOOL_Z")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)TOOL:U") {
|
||||
field(DESC,"TOOL coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_TOOL_U")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)TOOL:V") {
|
||||
field(DESC,"TOOL coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_TOOL_V")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)TOOL:W") {
|
||||
field(DESC,"TOOL coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_TOOL_W")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
# WORK CS readbacks
|
||||
record(ai,"$(P)$(R)WORK:X") {
|
||||
field(DESC,"WORK coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_WORK_X")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)WORK:Y") {
|
||||
field(DESC,"WORK coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_WORK_Y")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)WORK:Z") {
|
||||
field(DESC,"WORK coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_WORK_Z")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)WORK:U") {
|
||||
field(DESC,"WORK coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_WORK_U")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)WORK:V") {
|
||||
field(DESC,"WORK coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_WORK_V")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)WORK:W") {
|
||||
field(DESC,"WORK coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_WORK_W")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
# BASE CS readbacks
|
||||
record(ai,"$(P)$(R)BASE:X") {
|
||||
field(DESC,"BASE coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_BASE_X")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)BASE:Y") {
|
||||
field(DESC,"BASE coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_BASE_Y")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)BASE:Z") {
|
||||
field(DESC,"BASE coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_BASE_Z")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)BASE:U") {
|
||||
field(DESC,"BASE coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_BASE_U")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)BASE:V") {
|
||||
field(DESC,"BASE coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_BASE_V")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)BASE:W") {
|
||||
field(DESC,"BASE coordSys def")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_COORD_SYS_BASE_W")
|
||||
field(PREC,"5")
|
||||
}
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
record(mbbo,"$(P)$(R)CS") {
|
||||
field(DESC,"Coordinate System")
|
||||
field(DTYP,"asynInt32")
|
||||
field(OUT, "@asynMask($(PORT) 0 0xFFFF)HXP_MOVE_COORD_SYS")
|
||||
field(ZRVL,"0")
|
||||
field(ZRST,"Work")
|
||||
field(ONVL,"1")
|
||||
field(ONST,"Tool")
|
||||
field(VAL, "0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)STATUS") {
|
||||
field(DESC,"HXP Group Status")
|
||||
field(DTYP,"asynInt32")
|
||||
field(PINI,"1")
|
||||
field(PREC,"0")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_STATUS")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)ERROR") {
|
||||
field(DESC,"HXP Group Error")
|
||||
field(DTYP,"asynInt32")
|
||||
field(PREC,"0")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_ERROR")
|
||||
}
|
||||
|
||||
record(stringin, "$(P)$(R)ERR_DESC") {
|
||||
field(DESC,"Error Description")
|
||||
field(DTYP,"asynOctetRead")
|
||||
field(SCAN,"I/O Intr")
|
||||
field(INP, "@asyn($(PORT),0)HXP_ERROR_DESC")
|
||||
}
|
||||
|
||||
record(bo,"$(P)$(R)MOVE_ALL") {
|
||||
field(DESC,"Move all motors")
|
||||
field(DTYP,"asynInt32")
|
||||
field(ZNAM,"Off")
|
||||
field(ONAM,"On")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)T1") {
|
||||
field(DESC,"X target pos")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL_TARGET_X")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)T2") {
|
||||
field(DESC,"Y target pos")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL_TARGET_Y")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)T3") {
|
||||
field(DESC,"Z target pos")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL_TARGET_Z")
|
||||
field(PREC,"5")
|
||||
field(VAL, "12.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)T4") {
|
||||
field(DESC,"U target pos")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL_TARGET_U")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)T5") {
|
||||
field(DESC,"V target pos")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL_TARGET_V")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)T6") {
|
||||
field(DESC,"W target pos")
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT, "@asyn($(PORT),0)HXP_MOVE_ALL_TARGET_W")
|
||||
field(PREC,"5")
|
||||
field(VAL, "0.0")
|
||||
field(PINI,"YES")
|
||||
}
|
||||
|
||||
@@ -19,17 +19,6 @@ DB += motor.db
|
||||
DB += basic_motor.db
|
||||
DB += basic_asyn_motor.db
|
||||
DB += IMS_extra.db
|
||||
DB += XPSAuxAi.db
|
||||
DB += XPSAuxAo.db
|
||||
DB += XPSAuxBi.db
|
||||
DB += XPSAuxBo.db
|
||||
DB += XPSAuxLi.db
|
||||
DB += XPSAuxLo.db
|
||||
DB += XPS_extra.db
|
||||
DB += XPSPositionCompare.db
|
||||
DB += XPSTclScript.template
|
||||
DB += HXP_extra.db
|
||||
DB += HXP_coords.db
|
||||
DB += ACRAux.template
|
||||
DB += ACRAuxRead.template
|
||||
DB += ACRAuxLi.template
|
||||
@@ -41,8 +30,6 @@ DB += motorUtil.db
|
||||
DB += asyn_motor.db
|
||||
DB += profileMoveController.template
|
||||
DB += profileMoveAxis.template
|
||||
DB += profileMoveControllerXPS.template
|
||||
DB += profileMoveAxisXPS.template
|
||||
DB += PI_Support.db PI_SupportCtrl.db
|
||||
DB += Phytron_motor.db Phytron_I1AM01.db Phytron_MCM01.db
|
||||
DB += asyn_auto_power.db
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
record(ai,"$(P)$(R)")
|
||||
{
|
||||
field(SCAN,"$(SCAN)")
|
||||
field(DTYP,"asynFloat64Average")
|
||||
field(INP,"@asyn($(PORT) $(CHAN))ANALOG_INPUT")
|
||||
field(HOPR,"$(HOPR)")
|
||||
field(LOPR,"$(LOPR)")
|
||||
field(PREC,"$(PREC)")
|
||||
}
|
||||
|
||||
grecord(mbbo,"$(P)$(R)Gain") {
|
||||
field(DESC,"Input gain")
|
||||
field(DTYP, "asynUInt32Digital")
|
||||
field(OUT,"@asynMask($(PORT) $(CHAN) 0xFFFF)ANALOG_GAIN")
|
||||
field(ZRVL,"1")
|
||||
field(ZRST,"1")
|
||||
field(ONVL,"2")
|
||||
field(ONST,"2")
|
||||
field(TWVL,"4")
|
||||
field(TWST,"4")
|
||||
field(THVL,"8")
|
||||
field(THST,"8")
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
record(ao,"$(P)$(R)") {
|
||||
field(DTYP,"asynFloat64")
|
||||
field(OUT,"@asyn($(PORT) $(CHAN))ANALOG_OUTPUT")
|
||||
field(DRVL,"$(DRVL)")
|
||||
field(LOPR,"$(LOPR)")
|
||||
field(DRVH,"$(DRVH)")
|
||||
field(HOPR,"$(HOPR)")
|
||||
field(PREC,"$(PREC)")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)_tweakVal") {
|
||||
field(PREC,"$(PREC)")
|
||||
}
|
||||
|
||||
record(transform,"$(P)$(R)_tweak") {
|
||||
field(CLCE,"a?d-c:b?d+c:d")
|
||||
field(INPC,"$(P)$(R)_tweakVal.VAL NPP MS")
|
||||
field(INPD,"$(P)$(R).VAL NPP MS")
|
||||
field(OUTE,"$(P)$(R).VAL PP MS")
|
||||
field(OUTF,"$(P)$(R)_tweak.A NPP MS")
|
||||
field(OUTG,"$(P)$(R)_tweak.B NPP MS")
|
||||
field(PREC,"3")
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
grecord(bi,"$(P)$(R)")
|
||||
{
|
||||
field(PINI, "YES")
|
||||
field(DTYP,"asynUInt32Digital")
|
||||
field(INP,"@asynMask($(PORT) $(CHAN) $(MASK))BINARY_INPUT")
|
||||
field(SCAN, "$(SCAN)")
|
||||
field(ZNAM, "Low")
|
||||
field(ONAM, "High")
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
grecord(bo,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynUInt32Digital")
|
||||
field(OUT,"@asynMask($(PORT) $(CHAN) $(MASK))BINARY_OUTPUT")
|
||||
field(VAL, "1")
|
||||
field(ZNAM, "Low")
|
||||
field(ONAM, "High")
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
grecord(longin,"$(P)$(R)")
|
||||
{
|
||||
field(PINI, "YES")
|
||||
field(DTYP,"asynUInt32Digital")
|
||||
field(INP,"@asynMask($(PORT) $(CHAN) 0xffffffff)BINARY_INPUT")
|
||||
field(SCAN, "$(SCAN)")
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
grecord(longout,"$(P)$(R)")
|
||||
{
|
||||
field(DTYP,"asynUInt32Digital")
|
||||
field(OUT,"@asynMask($(PORT) $(CHAN) 0xffffffff)BINARY_OUTPUT")
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
# Database for PositionerPositionCompare functions in Newport XPS
|
||||
# Mark Rivers
|
||||
# March 10, 2015
|
||||
|
||||
record(mbbo,"$(P)$(R)PositionCompareMode") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_MODE")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "Disable")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "Position compare")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "AquadB windowed")
|
||||
field(THVL, "3")
|
||||
field(THST, "AquadB always")
|
||||
}
|
||||
|
||||
record(mbbi,"$(P)$(R)PositionCompareMode_RBV") {
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_MODE")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "Disable")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "Position compare")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "AquadB windowed")
|
||||
field(THVL, "3")
|
||||
field(THST, "AquadB always")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)PositionCompareMinPosition") {
|
||||
field(PINI, "YES")
|
||||
field(PREC,"$(PREC)")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_MIN_POSITION")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)PositionCompareMinPosition_RBV") {
|
||||
field(PREC,"$(PREC)")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_MIN_POSITION")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)PositionCompareMaxPosition") {
|
||||
field(PINI, "YES")
|
||||
field(PREC,"$(PREC)")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_MAX_POSITION")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)PositionCompareMaxPosition_RBV") {
|
||||
field(PREC,"$(PREC)")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_MAX_POSITION")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(ao,"$(P)$(R)PositionCompareStepSize") {
|
||||
field(PINI, "YES")
|
||||
field(PREC,"$(PREC)")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_STEP_SIZE")
|
||||
}
|
||||
|
||||
record(ai,"$(P)$(R)PositionCompareStepSize_RBV") {
|
||||
field(PREC,"$(PREC)")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_STEP_SIZE")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(mbbo,"$(P)$(R)PositionComparePulseWidth") {
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_PULSE_WIDTH")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "0.2")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "1.0")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "2.5")
|
||||
field(THVL, "3")
|
||||
field(THST, "10.0")
|
||||
}
|
||||
|
||||
record(mbbi,"$(P)$(R)PositionComparePulseWidth_RBV") {
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_PULSE_WIDTH")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "0.2")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "1.0")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "2.5")
|
||||
field(THVL, "3")
|
||||
field(THST, "10.0")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
record(mbbo,"$(P)$(R)PositionCompareSettlingTime") {
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_SETTLING_TIME")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "0.075")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "1.0")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "4.0")
|
||||
field(THVL, "3")
|
||||
field(THST, "12.0")
|
||||
}
|
||||
|
||||
record(mbbi,"$(P)$(R)PositionCompareSettlingTime_RBV") {
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynInt32")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_POSITION_COMPARE_SETTLING_TIME")
|
||||
field(ZRVL, "0")
|
||||
field(ZRST, "0.075")
|
||||
field(ONVL, "1")
|
||||
field(ONST, "1.0")
|
||||
field(TWVL, "2")
|
||||
field(TWST, "4.0")
|
||||
field(THVL, "3")
|
||||
field(THST, "12.0")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
$(P)$(R)PositionCompareMode
|
||||
$(p)$(r)pOSITIONcompareMinPosition
|
||||
$(P)$(R)PositionCompareMaxPosition
|
||||
$(P)$(R)PositionCompareStepSize
|
||||
$(P)$(R)PositionComparePulseWidth
|
||||
$(P)$(R)PositionCompareSettlingTime
|
||||
@@ -1,44 +0,0 @@
|
||||
####################################################
|
||||
#
|
||||
# Template for executing TCL script on an XPS.
|
||||
# Uses parameters in model 3 XPS driver (XPSController).
|
||||
#
|
||||
# Matthew Pearson
|
||||
# July 2013
|
||||
#
|
||||
# Macros:
|
||||
# $(P) - PV name prefix
|
||||
# $(R) - PV base record name
|
||||
# $(PORT) - asyn port for the controller
|
||||
# $(ADDR) - asyn address (normally 0)
|
||||
# $(TIMEOUT) - asyn timeout
|
||||
#
|
||||
####################################################
|
||||
|
||||
# ///
|
||||
# /// Name of the TCL script to execute
|
||||
# ///
|
||||
record(waveform, "$(P)$(R)TCLScript")
|
||||
{
|
||||
field(DESC, "Name of the TCL script")
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynOctetWrite")
|
||||
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_TCL_SCRIPT")
|
||||
field(FTVL, "CHAR")
|
||||
field(NELM, "256")
|
||||
info(autosaveFields, "VAL")
|
||||
}
|
||||
|
||||
# ///
|
||||
# /// Execute the TCL script (non blocking)
|
||||
# ///
|
||||
record(bo, "$(P)$(R)TCLScriptExecute")
|
||||
{
|
||||
field(DESC, "Execute TCL Script")
|
||||
field(DTYP, "asynInt32")
|
||||
field(OUT, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_TCL_SCRIPT_EXECUTE")
|
||||
field(ZNAM, "TCL Execute")
|
||||
field(ONAM, "TCL Execute")
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# Database for Newport XPS
|
||||
|
||||
grecord(ao,"$(P)$(R)MIN_JERK_TIME") {
|
||||
field(DESC,"Min jerk time")
|
||||
field(PREC,"3")
|
||||
field(VAL,".01")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_MIN_JERK")
|
||||
}
|
||||
grecord(ao,"$(P)$(R)MAX_JERK_TIME") {
|
||||
field(DESC,"Max jerk time")
|
||||
field(PREC,"3")
|
||||
field(VAL,".03")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(OUT,"@asyn($(PORT),$(ADDR))XPS_MAX_JERK")
|
||||
}
|
||||
grecord(ai,"$(P)$(R)READBACK") {
|
||||
field(DESC,"Readback")
|
||||
field(PREC,"4")
|
||||
field(PINI, "1")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(SCAN, "I/O Intr")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))MOTOR_POSITION")
|
||||
}
|
||||
|
||||
grecord(ai,"$(P)$(R)XPS_STATUS") {
|
||||
field(DESC,"XPS Group Status")
|
||||
field(DTYP, "asynInt32")
|
||||
field(PINI, "1")
|
||||
field(PREC,"0")
|
||||
field(SCAN, "I/O Intr")
|
||||
field(INP,"@asyn($(PORT),$(ADDR))XPS_STATUS")
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
# Database for profile moves with asynMotor
|
||||
# This database defined records specific to each XPS axis
|
||||
#
|
||||
# Mark Rivers
|
||||
# April 3, 2011
|
||||
#
|
||||
#
|
||||
# Macro paramters:
|
||||
# $(P) - PV name prefix
|
||||
# $(R) - PV base record name
|
||||
# $(M) - PV motor name
|
||||
# $(PORT) - asyn port for this controller
|
||||
# $(ADDR) - asyn addr for this axis
|
||||
# $(TIMEOUT) - asyn timeout for this axis
|
||||
# $(PREC) - Precision for this axis
|
||||
|
||||
#
|
||||
# Readback of minimum position
|
||||
#
|
||||
record(ai,"$(P)$(R)M$(M)MinPosition") {
|
||||
field(DESC, "Axis $(ADDR) min position")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_PROFILE_MIN_POSITION")
|
||||
field(PREC, "$(PREC)")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
#
|
||||
# Readback of maximum position
|
||||
#
|
||||
record(ai,"$(P)$(R)M$(M)MaxPosition") {
|
||||
field(DESC, "Axis $(ADDR) max position")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_PROFILE_MAX_POSITION")
|
||||
field(PREC, "$(PREC)")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
#
|
||||
# Readback of maximum velocity
|
||||
#
|
||||
record(ai,"$(P)$(R)M$(M)MaxVelocity") {
|
||||
field(DESC, "Axis $(ADDR) max velocity")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_PROFILE_MAX_VELOCITY")
|
||||
field(PREC, "$(PREC)")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
|
||||
#
|
||||
# Readback of maximum acceleration
|
||||
#
|
||||
record(ai,"$(P)$(R)M$(M)MaxAcceleration") {
|
||||
field(DESC, "Axis $(ADDR) max acceleration")
|
||||
field(DTYP, "asynFloat64")
|
||||
field(INP, "@asyn($(PORT),$(ADDR),$(TIMEOUT))XPS_PROFILE_MAX_ACCELERATION")
|
||||
field(PREC, "$(PREC)")
|
||||
field(SCAN, "I/O Intr")
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
# Database for profile moves with asynMotor
|
||||
# This database defined records specific to the XPS controller
|
||||
#
|
||||
# Mark Rivers
|
||||
# April 3, 2011
|
||||
#
|
||||
#
|
||||
# Macro paramters:
|
||||
# $(P) - PV name prefix
|
||||
# $(R) - PV base record name
|
||||
# $(PORT) - asyn port for this controller
|
||||
# $(TIMEOUT) - asyn timeout
|
||||
|
||||
# Name of the trajectory file that is built and FTP'd to the XPS
|
||||
record(stringout, "$(P)$(R)TrajectoryFile") {
|
||||
field(DESC, "XPS trajectory file")
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynOctetWrite")
|
||||
field(OUT, "@asyn($(PORT),0,$(TIMEOUT))XPS_TRAJECTORY_FILE")
|
||||
field(VAL, "TrajectoryScan.trj")
|
||||
}
|
||||
|
||||
# Group name for XPS trajectory scanning
|
||||
record(stringout, "$(P)$(R)GroupName") {
|
||||
field(DESC, "XPS PVT group name")
|
||||
field(PINI, "YES")
|
||||
field(DTYP, "asynOctetWrite")
|
||||
field(OUT, "@asyn($(PORT),0,$(TIMEOUT))XPS_PROFILE_GROUP_NAME")
|
||||
field(VAL, "Group1")
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
$(P)$(R)TrajectoryFile
|
||||
$(P)$(R)GroupName
|
||||
@@ -1,41 +0,0 @@
|
||||
record(longout, "$(P)$(R):debug")
|
||||
{
|
||||
field(DESC, "Debug level")
|
||||
field(VAL, "5")
|
||||
field(PINI, "YES")
|
||||
}
|
||||
record(bo, "$(P)$(R):ok")
|
||||
{
|
||||
field(DESC, "Slave mode ok?")
|
||||
field(ZNAM, "No")
|
||||
field(ONAM, "Yes")
|
||||
field(VAL, "0")
|
||||
}
|
||||
|
||||
record(bo, "$(P)$(R):init")
|
||||
{
|
||||
field(DESC, "Initialize")
|
||||
field(ZNAM, "Done")
|
||||
field(ONAM, "Initializing")
|
||||
field(VAL, "0")
|
||||
}
|
||||
|
||||
record(bo, "$(P)$(R):on")
|
||||
{
|
||||
field(DESC, "Slave mode")
|
||||
field(ZNAM, "Off")
|
||||
field(ONAM, "On")
|
||||
field(VAL, "0")
|
||||
}
|
||||
|
||||
record(ao, "$(P)$(R):ratio")
|
||||
{
|
||||
field(DESC, "Gear ratio")
|
||||
field(VAL, "1")
|
||||
}
|
||||
|
||||
record(ao, "$(P)$(R):ratioRdbk")
|
||||
{
|
||||
field(DESC, "Gear ratio")
|
||||
field(VAL, "1")
|
||||
}
|
||||
@@ -27,9 +27,6 @@ OmsAsynSrc_DEPEND_DIRS = MotorSrc
|
||||
DIRS += MotorSimSrc
|
||||
MotorSimSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
DIRS += NewportSrc
|
||||
NewportSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
DIRS += ImsSrc
|
||||
ImsSrc_DEPEND_DIRS = MotorSrc
|
||||
|
||||
|
||||
@@ -1,545 +0,0 @@
|
||||
/*
|
||||
FILENAME... AG_CONEX.cpp
|
||||
USAGE... Motor driver support for the Newport CONEX-AGP, CONEX-CC and CONEX-PP series controllers.
|
||||
|
||||
Mark Rivers
|
||||
April 11, 2013
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <asynOctetSyncIO.h>
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include "AG_CONEX.h"
|
||||
|
||||
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||
|
||||
#define CONEX_TIMEOUT 2.0
|
||||
#define LINUX_WRITE_DELAY 0.1
|
||||
|
||||
// We force minus end-of-run home type for Conex-PP for now
|
||||
#define HOME_TYPE_MINUS_EOR 4
|
||||
|
||||
/** Creates a new AG_CONEXController object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] serialPortName The name of the drvAsynSerialPort that was created previously to connect to the CONEX 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
|
||||
*/
|
||||
AG_CONEXController::AG_CONEXController(const char *portName, const char *serialPortName, int controllerID,
|
||||
double movingPollPeriod, double idlePollPeriod)
|
||||
: asynMotorController(portName, 1, NUM_AG_CONEX_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
|
||||
controllerID_(controllerID)
|
||||
|
||||
{
|
||||
asynStatus status;
|
||||
static const char *functionName = "AG_CONEXController::AG_CONEXController";
|
||||
|
||||
/* Connect to CONEX controller */
|
||||
status = pasynOctetSyncIO->connect(serialPortName, 0, &pasynUserController_, NULL);
|
||||
if (status) {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to CONEX controller\n",
|
||||
functionName);
|
||||
return;
|
||||
}
|
||||
|
||||
// Flush any characters that controller has, read firmware version
|
||||
sprintf(outString_, "%dVE", controllerID_);
|
||||
status = writeReadController();
|
||||
if (status) {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot read version information from AG_CONEX controller\n",
|
||||
functionName);
|
||||
return;
|
||||
}
|
||||
strcpy(controllerVersion_, &inString_[4]);
|
||||
|
||||
// Create the axis object
|
||||
new AG_CONEXAxis(this);
|
||||
|
||||
startPoller(movingPollPeriod, idlePollPeriod, 2);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new AG_CONEXController 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] serialPortName The name of the drvAsynIPPPort that was created previously to connect to the CONEX 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 AG_CONEXCreateController(const char *portName, const char *serialPortName, int controllerID,
|
||||
int movingPollPeriod, int idlePollPeriod)
|
||||
{
|
||||
new AG_CONEXController(portName, serialPortName, controllerID, movingPollPeriod/1000., idlePollPeriod/1000.);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
|
||||
/** Writes a string to the controller.
|
||||
* Calls writeCONEX() with a default location of the string to write and a default timeout. */
|
||||
asynStatus AG_CONEXController::writeCONEX()
|
||||
{
|
||||
return writeCONEX(outString_, CONEX_TIMEOUT);
|
||||
}
|
||||
|
||||
/** Writes a string to the controller.
|
||||
* \param[in] output The string to be written.
|
||||
* \param[in] timeout Timeout before returning an error.*/
|
||||
asynStatus AG_CONEXController::writeCONEX(const char *output, double timeout)
|
||||
{
|
||||
size_t nwrite;
|
||||
asynStatus status;
|
||||
// const char *functionName="writeCONEX";
|
||||
|
||||
status = pasynOctetSyncIO->write(pasynUserController_, output,
|
||||
strlen(output), timeout, &nwrite);
|
||||
|
||||
// On Linux it seems to be necessary to delay a short time between writes
|
||||
#ifdef linux
|
||||
epicsThreadSleep(LINUX_WRITE_DELAY);
|
||||
#endif
|
||||
|
||||
return status ;
|
||||
}
|
||||
|
||||
/** 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 AG_CONEXController::report(FILE *fp, int level)
|
||||
{
|
||||
fprintf(fp, "CONEX motor driver %s, controllerID=%d, version=\"%s\n"
|
||||
" moving poll period=%f, idle poll period=%f\n",
|
||||
this->portName, controllerID_, controllerVersion_, movingPollPeriod_, idlePollPeriod_);
|
||||
|
||||
// Call the base class method
|
||||
asynMotorController::report(fp, level);
|
||||
}
|
||||
|
||||
/** Returns a pointer to an AG_CONEXAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
AG_CONEXAxis* AG_CONEXController::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<AG_CONEXAxis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an AG_CONEXAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
AG_CONEXAxis* AG_CONEXController::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<AG_CONEXAxis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
|
||||
// These are the AG_CONEXAxis methods
|
||||
|
||||
/** Creates a new AG_CONEXAxis object.
|
||||
* \param[in] pC Pointer to the AG_CONEXController to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
AG_CONEXAxis::AG_CONEXAxis(AG_CONEXController *pC)
|
||||
: asynMotorAxis(pC, 0),
|
||||
pC_(pC),
|
||||
currentPosition_(0.)
|
||||
{
|
||||
static const char *functionName = "AG_CONEXAxis::AG_CONEXAxis";
|
||||
|
||||
// Figure out what model this is
|
||||
if (strstr(pC->controllerVersion_, "CONEX-AGP")) {
|
||||
conexModel_ = ModelConexAGP;
|
||||
KPMax_ = 3000.;
|
||||
KIMax_ = 3000.;
|
||||
LFMax_ = 1000.;
|
||||
}
|
||||
else if (strstr(pC->controllerVersion_, "CONEX-CC")) {
|
||||
conexModel_ = ModelConexCC;
|
||||
KPMax_ = 1.e6;
|
||||
KIMax_ = 1.e6;
|
||||
KDMax_ = 1.e6;
|
||||
}
|
||||
else if (strstr(pC->controllerVersion_, "Conex PP")) {
|
||||
conexModel_ = ModelConexPP;
|
||||
}
|
||||
else {
|
||||
asynPrint(pC->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: unknown model, firmware string=%s\n",
|
||||
functionName, pC->controllerVersion_);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read the stage ID
|
||||
sprintf(pC_->outString_, "%dID?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
strcpy(stageID_, &pC_->inString_[3]);
|
||||
|
||||
// Read the encoder increment (CC and AGP only)
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
sprintf(pC_->outString_, "%dSU?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
encoderIncrement_ = atof(&pC_->inString_[3]);
|
||||
} else {
|
||||
encoderIncrement_ = 1.;
|
||||
}
|
||||
|
||||
// Read the interpolation factor (AGP only)
|
||||
if (conexModel_ == ModelConexAGP) {
|
||||
sprintf(pC_->outString_, "%dIF?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
interpolationFactor_ = atof(&pC_->inString_[3]);
|
||||
} else {
|
||||
interpolationFactor_ = 1.;
|
||||
}
|
||||
|
||||
if (conexModel_ == ModelConexPP) {
|
||||
sprintf(pC_->outString_, "%dFRM?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
microStepsPerFullStep_ = atoi(&pC_->inString_[4]);
|
||||
sprintf(pC_->outString_, "%dFRS?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
fullStepSize_ = atof(&pC_->inString_[4]);
|
||||
}
|
||||
|
||||
// Compute the minimum step size
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
stepSize_ = encoderIncrement_ / interpolationFactor_;
|
||||
} else {
|
||||
stepSize_ = fullStepSize_ / microStepsPerFullStep_ / 1000.;
|
||||
}
|
||||
|
||||
// Read the low and high software limits
|
||||
sprintf(pC_->outString_, "%dSL?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
lowLimit_ = atof(&pC_->inString_[3]);
|
||||
sprintf(pC_->outString_, "%dSR?", pC->controllerID_);
|
||||
pC_->writeReadController();
|
||||
highLimit_ = atof(&pC_->inString_[3]);
|
||||
|
||||
// Tell the motor record that we have an gain support (CC and AGP only)
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
setIntegerParam(pC_->motorStatusGainSupport_, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 AG_CONEXAxis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
// Read KOP, KI, LF (CC and AGP only)
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
sprintf(pC_->outString_, "%dKP?", pC_->controllerID_);
|
||||
pC_->writeReadController();
|
||||
KP_ = atof(&pC_->inString_[3]);
|
||||
sprintf(pC_->outString_, "%dKI?", pC_->controllerID_);
|
||||
pC_->writeReadController();
|
||||
KI_ = atof(&pC_->inString_[3]);
|
||||
if (conexModel_ == ModelConexAGP) {
|
||||
sprintf(pC_->outString_, "%dLF?", pC_->controllerID_);
|
||||
pC_->writeReadController();
|
||||
LF_ = atof(&pC_->inString_[3]);
|
||||
} else if (conexModel_ == ModelConexCC) {
|
||||
sprintf(pC_->outString_, "%dKD?", pC_->controllerID_);
|
||||
pC_->writeReadController();
|
||||
KD_ = atof(&pC_->inString_[3]);
|
||||
LF_ = KD_; // For printout below
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(fp, " stageID=%s\n"
|
||||
" currentPosition=%f, encoderIncrement=%f\n"
|
||||
" interpolationFactor=%f, stepSize=%f, lowLimit=%f, highLimit=%f\n"
|
||||
" KP=%f, KI=%f, KD/LF=%f\n"
|
||||
" fullStepSize=%f, microStepsPerFullStep=%d\n",
|
||||
stageID_,
|
||||
currentPosition_, encoderIncrement_,
|
||||
interpolationFactor_, stepSize_, lowLimit_, highLimit_,
|
||||
KP_, KI_, LF_,
|
||||
fullStepSize_, microStepsPerFullStep_);
|
||||
}
|
||||
|
||||
// Call the base class method
|
||||
asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "AG_CONEXAxis::move";
|
||||
|
||||
// The CONEX-CC and CONEX-PP support velocity and acceleration, the CONEX-AGP does not
|
||||
if ((conexModel_ == ModelConexCC) || (conexModel_ == ModelConexPP)) {
|
||||
sprintf(pC_->outString_, "%dAC%f", pC_->controllerID_, acceleration*stepSize_);
|
||||
status = pC_->writeCONEX();
|
||||
sprintf(pC_->outString_, "%dVA%f", pC_->controllerID_, maxVelocity*stepSize_);
|
||||
status = pC_->writeCONEX();
|
||||
}
|
||||
|
||||
if (relative) {
|
||||
sprintf(pC_->outString_, "%dPR%f", pC_->controllerID_, position*stepSize_);
|
||||
} else {
|
||||
sprintf(pC_->outString_, "%dPA%f", pC_->controllerID_, position*stepSize_);
|
||||
}
|
||||
status = pC_->writeCONEX();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "AG_CONEXAxis::home";
|
||||
|
||||
// Must go to unreferenced state to home
|
||||
sprintf(pC_->outString_, "%dRS", pC_->controllerID_);
|
||||
status = pC_->writeCONEX();
|
||||
epicsThreadSleep(1.0);
|
||||
|
||||
// The CONEX-CC supports home velocity, but only by going to Configuration state (PW1)
|
||||
// and writing to non-volatile memory with the OH command.
|
||||
// This is time-consuming and can only be done a limited number of times so we don't do it here.
|
||||
|
||||
// The CONEX-PP supports home velocity and home type. We force negative limit switch home type.
|
||||
if (conexModel_ == ModelConexPP) {
|
||||
sprintf(pC_->outString_, "%dOH%f", pC_->controllerID_, maxVelocity);
|
||||
status = pC_->writeCONEX();
|
||||
sprintf(pC_->outString_, "%dHT%d", pC_->controllerID_, HOME_TYPE_MINUS_EOR);
|
||||
status = pC_->writeCONEX();
|
||||
}
|
||||
|
||||
sprintf(pC_->outString_, "%dOR", pC_->controllerID_);
|
||||
status = pC_->writeCONEX();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
double position;
|
||||
//static const char *functionName = "AG_CONEXAxis::moveVelocity";
|
||||
|
||||
// The CONEX does not have a jog command. Move almost to soft limit.
|
||||
if (maxVelocity > 0) position = highLimit_ - stepSize_;
|
||||
else position = lowLimit_ + stepSize_;
|
||||
|
||||
sprintf(pC_->outString_, "%dPA%f", pC_->controllerID_, position);
|
||||
status = pC_->writeCONEX();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::stop(double acceleration )
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "AG_CONEXAxis::stop";
|
||||
|
||||
sprintf(pC_->outString_, "%dST", pC_->controllerID_);
|
||||
status = pC_->writeCONEX();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::setPosition(double position)
|
||||
{
|
||||
//static const char *functionName = "AG_CONEXAxis::setPosition";
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "AG_CONEXAxis::setClosedLoop";
|
||||
|
||||
sprintf(pC_->outString_, "%dMM%d", pC_->controllerID_, closedLoop ? 1 : 0);
|
||||
status = pC_->writeCONEX();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::getClosedLoop(bool *closedLoop)
|
||||
{
|
||||
int status;
|
||||
asynStatus comStatus;
|
||||
|
||||
// Read the status of the motor
|
||||
sprintf(pC_->outString_, "%dMM?", pC_->controllerID_);
|
||||
comStatus = pC_->writeReadController();
|
||||
// The response string is of the form "1MMn"
|
||||
sscanf(pC_->inString_, "%*dMM%x", &status);
|
||||
*closedLoop = (status >= 0x1e) && (status <= 0x34);
|
||||
return comStatus;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::setPGain(double pGain)
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
bool closedLoop;
|
||||
//static const char *functionName = "AG_CONEXAxis::setPGain";
|
||||
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
getClosedLoop(&closedLoop);
|
||||
setClosedLoop(false);
|
||||
// The pGain value from the motor record is between 0 and 1.
|
||||
sprintf(pC_->outString_, "%dKP%f", pC_->controllerID_, pGain*KPMax_);
|
||||
status = pC_->writeCONEX();
|
||||
if (closedLoop) setClosedLoop(true);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::setIGain(double iGain)
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
bool closedLoop;
|
||||
//static const char *functionName = "AG_CONEXAxis::setIGain";
|
||||
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
getClosedLoop(&closedLoop);
|
||||
setClosedLoop(false);
|
||||
// The iGain value from the motor record is between 0 and 1.
|
||||
sprintf(pC_->outString_, "%dKI%f", pC_->controllerID_, iGain*KIMax_);
|
||||
status = pC_->writeCONEX();
|
||||
if (closedLoop) setClosedLoop(true);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_CONEXAxis::setDGain(double dGain)
|
||||
{
|
||||
asynStatus status = asynSuccess;
|
||||
bool closedLoop;
|
||||
//static const char *functionName = "AG_CONEXAxis::setPGain";
|
||||
|
||||
if ((conexModel_ == ModelConexAGP) || (conexModel_ == ModelConexCC)) {
|
||||
getClosedLoop(&closedLoop);
|
||||
setClosedLoop(false);
|
||||
if (conexModel_ == ModelConexCC) {
|
||||
// The dGain value from the motor record is between 0 and 1.
|
||||
sprintf(pC_->outString_, "%dKI%f", pC_->controllerID_, dGain*KDMax_);
|
||||
} else if (conexModel_ == ModelConexAGP) {
|
||||
// We are using the DGain for the Low pass filter frequency.
|
||||
// DGain value is between 0 and 1
|
||||
sprintf(pC_->outString_, "%dLF%f", pC_->controllerID_, dGain*LFMax_);
|
||||
}
|
||||
status = pC_->writeCONEX();
|
||||
if (closedLoop) setClosedLoop(true);
|
||||
}
|
||||
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 AG_CONEXAxis::poll(bool *moving)
|
||||
{
|
||||
int done=1;
|
||||
double position;
|
||||
unsigned int status;
|
||||
unsigned int state;
|
||||
int highLimit=0, lowLimit=0;
|
||||
int count;
|
||||
bool closedLoop;
|
||||
asynStatus comStatus;
|
||||
|
||||
// Read the current motor position
|
||||
sprintf(pC_->outString_, "%dTP", pC_->controllerID_);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// The response string is of the form "1TPxxx"
|
||||
position = atof(&pC_->inString_[3]);
|
||||
currentPosition_ = position /stepSize_;
|
||||
setDoubleParam(pC_->motorPosition_, currentPosition_);
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(pC_->outString_, "%dTS", pC_->controllerID_);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// The response string is of the form "1TSabcdef"
|
||||
count = sscanf(pC_->inString_, "%*dTS%*4c%x", &status);
|
||||
if (count != 1) goto skip;
|
||||
|
||||
state = status & 0xff;
|
||||
if ((state == 0x1e) || (state == 0x28)) done = 0;
|
||||
setIntegerParam(pC_->motorStatusDone_, done);
|
||||
*moving = done ? false:true;
|
||||
|
||||
// The meaning of the error bits is different for the CC, AGP, and PP
|
||||
if ((conexModel_ == ModelConexCC) || (conexModel_ == ModelConexPP)) {
|
||||
if (status & 0x100) lowLimit = 1;
|
||||
if (status & 0x200) highLimit = 1;
|
||||
}
|
||||
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, lowLimit);
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, highLimit);
|
||||
|
||||
// Set the power-on (closed loop) status of the motor
|
||||
comStatus = getClosedLoop(&closedLoop);
|
||||
if (comStatus) goto skip;
|
||||
setIntegerParam(pC_->motorStatusPowerOn_, closedLoop ? 1:0);
|
||||
|
||||
skip:
|
||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
||||
callParamCallbacks();
|
||||
return comStatus ? asynError : asynSuccess;
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg AG_CONEXCreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg AG_CONEXCreateControllerArg1 = {"Serial port name", iocshArgString};
|
||||
static const iocshArg AG_CONEXCreateControllerArg2 = {"Controller ID", iocshArgInt};
|
||||
static const iocshArg AG_CONEXCreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
|
||||
static const iocshArg AG_CONEXCreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
|
||||
static const iocshArg * const AG_CONEXCreateControllerArgs[] = {&AG_CONEXCreateControllerArg0,
|
||||
&AG_CONEXCreateControllerArg1,
|
||||
&AG_CONEXCreateControllerArg2,
|
||||
&AG_CONEXCreateControllerArg3,
|
||||
&AG_CONEXCreateControllerArg4};
|
||||
static const iocshFuncDef AG_CONEXCreateControllerDef = {"AG_CONEXCreateController", 5, AG_CONEXCreateControllerArgs};
|
||||
static void AG_CONEXCreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
AG_CONEXCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
static void AG_CONEXRegister(void)
|
||||
{
|
||||
iocshRegister(&AG_CONEXCreateControllerDef, AG_CONEXCreateContollerCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(AG_CONEXRegister);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
FILENAME... AG_CONEX.h
|
||||
USAGE... Motor driver support for the Newport CONEX-AGP and CONEX-CC series of controllers.
|
||||
|
||||
Mark Rivers
|
||||
April 11, 2013
|
||||
|
||||
*/
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
typedef enum {
|
||||
ModelConexAGP,
|
||||
ModelConexCC,
|
||||
ModelConexPP
|
||||
} ConexModel_t;
|
||||
|
||||
// No controller-specific parameters yet
|
||||
#define NUM_AG_CONEX_PARAMS 0
|
||||
|
||||
class epicsShareClass AG_CONEXAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
AG_CONEXAxis(class AG_CONEXController *pC);
|
||||
void report(FILE *fp, int level);
|
||||
asynStatus move(double position, int relative, double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus moveVelocity(double min_velocity, double max_velocity, double acceleration);
|
||||
asynStatus home(double min_velocity, double max_velocity, double acceleration, int forwards);
|
||||
asynStatus stop(double acceleration);
|
||||
asynStatus poll(bool *moving);
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus setClosedLoop(bool closedLoop);
|
||||
asynStatus setPGain(double pGain);
|
||||
asynStatus setIGain(double iGain);
|
||||
asynStatus setDGain(double dGain);
|
||||
|
||||
private:
|
||||
AG_CONEXController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
asynStatus getClosedLoop(bool *closedLoop);
|
||||
double currentPosition_;
|
||||
double encoderIncrement_;
|
||||
double interpolationFactor_;
|
||||
double stepSize_;
|
||||
double fullStepSize_;
|
||||
int microStepsPerFullStep_;
|
||||
double highLimit_;
|
||||
double lowLimit_;
|
||||
double KP_;
|
||||
double KI_;
|
||||
double KD_;
|
||||
double LF_;
|
||||
double KPMax_;
|
||||
double KDMax_;
|
||||
double KIMax_;
|
||||
double LFMax_;
|
||||
char stageID_[40];
|
||||
ConexModel_t conexModel_;
|
||||
|
||||
friend class AG_CONEXController;
|
||||
};
|
||||
|
||||
class epicsShareClass AG_CONEXController : public asynMotorController {
|
||||
public:
|
||||
AG_CONEXController(const char *portName, const char *serialPortName, int controllerID, double movingPollPeriod, double idlePollPeriod);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
AG_CONEXAxis* getAxis(asynUser *pasynUser);
|
||||
AG_CONEXAxis* getAxis(int axisNo);
|
||||
asynStatus writeCONEX();
|
||||
asynStatus writeCONEX(const char *output, double timeout);
|
||||
|
||||
private:
|
||||
int controllerID_;
|
||||
char controllerVersion_[40];
|
||||
|
||||
friend class AG_CONEXAxis;
|
||||
};
|
||||
@@ -1,449 +0,0 @@
|
||||
/*
|
||||
FILENAME... AG_UC.cpp
|
||||
USAGE... Motor driver support for the Newport Agilis UC series controllers.
|
||||
|
||||
Mark Rivers
|
||||
April 11, 2013
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <asynOctetSyncIO.h>
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include "AG_UC.h"
|
||||
|
||||
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||
|
||||
#define AGILIS_TIMEOUT 2.0
|
||||
#define WRITE_DELAY 0.01
|
||||
|
||||
/** Creates a new AG_UCController object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] serialPortName The name of the drvAsynSerialPort that was created previously to connect to the Agilis 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
|
||||
*/
|
||||
AG_UCController::AG_UCController(const char *portName, const char *serialPortName, int numAxes,
|
||||
double movingPollPeriod, double idlePollPeriod)
|
||||
: asynMotorController(portName, numAxes, NUM_AG_UC_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
|
||||
{
|
||||
asynStatus status;
|
||||
static const char *functionName = "AG_UCController::AG_UCController";
|
||||
|
||||
/* Connect to Agilis controller */
|
||||
status = pasynOctetSyncIO->connect(serialPortName, 0, &pasynUserController_, NULL);
|
||||
if (status) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to Agilis controller\n",
|
||||
functionName);
|
||||
}
|
||||
|
||||
// Reset the controller
|
||||
sprintf(outString_, "RS");
|
||||
status = writeAgilis(0);
|
||||
// Reset takes some time?
|
||||
epicsThreadSleep(0.5);
|
||||
|
||||
// Put the controller in remote mode
|
||||
sprintf(outString_, "MR");
|
||||
status = writeAgilis(0);
|
||||
|
||||
// Flush any characters that controller has, read firmware version
|
||||
sprintf(outString_, "VE");
|
||||
status = writeReadController();
|
||||
// Seems to be necessary to delay a short time between writes
|
||||
epicsThreadSleep(WRITE_DELAY);
|
||||
printf("Agilis controller firmware version = %s\n", inString_);
|
||||
if (status) {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot read version information from Agilis controller\n",
|
||||
functionName);
|
||||
return;
|
||||
}
|
||||
strcpy(controllerVersion_, inString_);
|
||||
// Figure out what model this is
|
||||
if (strstr(controllerVersion_, "AG-UC2")) {
|
||||
AG_UCModel_ = ModelAG_UC2;
|
||||
}
|
||||
else if (strstr(controllerVersion_, "AG-UC8PC")) {
|
||||
AG_UCModel_ = ModelAG_UC8PC;
|
||||
}
|
||||
else if (strstr(controllerVersion_, "AG-UC8")) {
|
||||
AG_UCModel_ = ModelAG_UC8;
|
||||
}
|
||||
else {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: unknown model, firmware string=%s\n",
|
||||
functionName, controllerVersion_);
|
||||
return;
|
||||
}
|
||||
|
||||
startPoller(movingPollPeriod, idlePollPeriod, 2);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new AG_UCController 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] serialPortName The name of the drvAsynIPPPort that was created previously to connect to the Agilis 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 AG_UCCreateController(const char *portName, const char *serialPortName, int numAxes,
|
||||
int movingPollPeriod, int idlePollPeriod)
|
||||
{
|
||||
new AG_UCController(portName, serialPortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000.);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
asynStatus AG_UCCreateAxis(const char *AG_UCName, /* specify which controller by port name */
|
||||
int axis, /* axis number 0-7 */
|
||||
int hasLimits, /* Actuator has limits 0 or 1 */
|
||||
int forwardAmplitude, /* Step amplitude in forward direction */
|
||||
int reverseAmplitude) /* Step amplitude in reverse direction */
|
||||
{
|
||||
AG_UCController *pC;
|
||||
static const char *functionName = "AG_UCCreateAxis";
|
||||
|
||||
pC = (AG_UCController*) findAsynPortDriver(AG_UCName);
|
||||
if (!pC) {
|
||||
printf("%s: Error port %s not found\n",
|
||||
functionName, AG_UCName);
|
||||
return asynError;
|
||||
}
|
||||
pC->lock();
|
||||
new AG_UCAxis(pC, axis, hasLimits ? true:false, forwardAmplitude, reverseAmplitude);
|
||||
pC->unlock();
|
||||
return asynSuccess;
|
||||
}
|
||||
} // extern "C"
|
||||
|
||||
|
||||
/** Writes a string to the controller.
|
||||
* Calls writeAgilis() with a default location of the string to write and a default timeout. */
|
||||
asynStatus AG_UCController::writeAgilis(int channelID)
|
||||
{
|
||||
return writeAgilis(channelID, outString_, AGILIS_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
/** Writes a string to the controller.
|
||||
* \param[in] output The string to be written.
|
||||
* \param[in] timeout Timeout before returning an error.*/
|
||||
asynStatus AG_UCController::writeAgilis(int channelID, const char *output, double timeout)
|
||||
{
|
||||
size_t nwrite;
|
||||
asynStatus status;
|
||||
// const char *functionName="writeAgilis";
|
||||
|
||||
// If channelID is non-zero then we need to send the CC command first
|
||||
|
||||
if (channelID != 0) setChannel(channelID);
|
||||
|
||||
status = pasynOctetSyncIO->write(pasynUserController_, output,
|
||||
strlen(output), timeout, &nwrite);
|
||||
|
||||
// Seems to be necessary to delay a short time between writes
|
||||
epicsThreadSleep(WRITE_DELAY);
|
||||
|
||||
return status ;
|
||||
}
|
||||
|
||||
asynStatus AG_UCController::setChannel(int channelID)
|
||||
{
|
||||
char tempString[40];
|
||||
asynStatus status;
|
||||
|
||||
sprintf(tempString, "CC%d", channelID);
|
||||
status = writeController(tempString, AGILIS_TIMEOUT);
|
||||
// Seems to be necessary to delay a short time between writes
|
||||
epicsThreadSleep(WRITE_DELAY);
|
||||
return status;
|
||||
}
|
||||
|
||||
/** 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 AG_UCController::report(FILE *fp, int level)
|
||||
{
|
||||
fprintf(fp, "Agilis UC motor driver %s, model=%d, numAxes=%d, moving poll period=%f, idle poll period=%f\n",
|
||||
this->portName, AG_UCModel_, numAxes_, movingPollPeriod_, idlePollPeriod_);
|
||||
fprintf(fp, "controller version %s\n",
|
||||
controllerVersion_);
|
||||
|
||||
// Call the base class method
|
||||
asynMotorController::report(fp, level);
|
||||
}
|
||||
|
||||
/** Returns a pointer to an AG_UCAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
AG_UCAxis* AG_UCController::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<AG_UCAxis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an AG_UCAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
AG_UCAxis* AG_UCController::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<AG_UCAxis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
|
||||
// These are the AG_UCAxis methods
|
||||
|
||||
/** Creates a new AG_UCAxis object.
|
||||
* \param[in] pC Pointer to the AG_UCController to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
AG_UCAxis::AG_UCAxis(AG_UCController *pC, int axisNo, bool hasLimits,
|
||||
int forwardAmplitude, int reverseAmplitude)
|
||||
: asynMotorAxis(pC, axisNo),
|
||||
pC_(pC), hasLimits_(hasLimits),
|
||||
forwardAmplitude_(forwardAmplitude), reverseAmplitude_(reverseAmplitude),
|
||||
currentPosition_(0), positionOffset_(0)
|
||||
{
|
||||
axisID_ = (axisNo % 2) + 1; // Either 1 or 2
|
||||
if (pC_->AG_UCModel_ == ModelAG_UC2) {
|
||||
channelID_ = 0;
|
||||
} else {
|
||||
channelID_ = axisNo/2 + 1;
|
||||
}
|
||||
if (forwardAmplitude_ <= 0) forwardAmplitude_ = 50;
|
||||
if (reverseAmplitude_ >= 0) forwardAmplitude_ = -50;
|
||||
sprintf(pC_->outString_, "%dSU%d", axisID_, forwardAmplitude_);
|
||||
writeAgilis();
|
||||
sprintf(pC_->outString_, "%dSU%d", axisID_, reverseAmplitude_);
|
||||
writeAgilis();
|
||||
}
|
||||
|
||||
/** 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 AG_UCAxis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axisID=%d, channelID=%d, hasLimits=%d\n"
|
||||
" forwardAmplitude=%d, reverseAmplitude=%d\n"
|
||||
" currentPosition=%d, positionOffset=%d\n",
|
||||
axisID_, channelID_, hasLimits_,
|
||||
forwardAmplitude_, reverseAmplitude_,
|
||||
currentPosition_, positionOffset_);
|
||||
}
|
||||
|
||||
// Call the base class method
|
||||
asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
asynStatus AG_UCAxis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
int steps = NINT(position);
|
||||
// static const char *functionName = "AG_UCAxis::move";
|
||||
|
||||
if (relative) {
|
||||
sprintf(pC_->outString_, "%dPR%d", axisID_, steps);
|
||||
} else {
|
||||
steps = NINT(position - currentPosition_);
|
||||
sprintf(pC_->outString_, "%dPR%d", axisID_, steps);
|
||||
}
|
||||
status = writeAgilis();
|
||||
return status;
|
||||
}
|
||||
|
||||
int AG_UCAxis::velocityToSpeedCode(double velocity)
|
||||
{
|
||||
int speed;
|
||||
if (fabs(velocity) <= 5) speed = 1;
|
||||
else if (fabs(velocity) <= 100) speed = 2;
|
||||
else if (fabs(velocity) <= 666) speed = 4;
|
||||
else speed = 3;
|
||||
if (velocity < 0) speed = -speed;
|
||||
return speed;
|
||||
}
|
||||
|
||||
asynStatus AG_UCAxis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "AG_UCAxis::home";
|
||||
|
||||
if (!hasLimits_) return asynError;
|
||||
sprintf(pC_->outString_, "%dMV%d", axisID_, velocityToSpeedCode(maxVelocity));
|
||||
status = writeAgilis();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_UCAxis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "AG_UCAxis::moveVelocity";
|
||||
|
||||
sprintf(pC_->outString_, "%dJA%d", axisID_, velocityToSpeedCode(maxVelocity));
|
||||
status = writeAgilis();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_UCAxis::stop(double acceleration )
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "AG_UCAxis::stop";
|
||||
|
||||
sprintf(pC_->outString_, "%dST", axisID_);
|
||||
status = writeAgilis();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus AG_UCAxis::setPosition(double position)
|
||||
{
|
||||
//static const char *functionName = "AG_UCAxis::setPosition";
|
||||
|
||||
positionOffset_ = NINT(position) - currentPosition_;
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
/** 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 AG_UCAxis::poll(bool *moving)
|
||||
{
|
||||
int done;
|
||||
int lim, limit=0;
|
||||
int position;
|
||||
asynStatus comStatus;
|
||||
|
||||
// Select this channel
|
||||
pC_->setChannel(channelID_);
|
||||
|
||||
// Read the current motor position
|
||||
sprintf(pC_->outString_, "%dTP", axisID_);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// Seems to be necessary to delay a short time between writes
|
||||
epicsThreadSleep(WRITE_DELAY);
|
||||
// The response string is of the form "1TPxxx"
|
||||
position = atoi(&pC_->inString_[3]);
|
||||
currentPosition_ = position + positionOffset_;
|
||||
setDoubleParam(pC_->motorPosition_, double(currentPosition_));
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(pC_->outString_, "%dTS", axisID_);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// Seems to be necessary to delay a short time between writes
|
||||
epicsThreadSleep(WRITE_DELAY);
|
||||
// The response string is of the form "1TSn"
|
||||
done = (pC_->inString_[3] == '0') ? 1:0;
|
||||
setIntegerParam(pC_->motorStatusDone_, done);
|
||||
*moving = done ? false:true;
|
||||
|
||||
// Read the limit status
|
||||
sprintf(pC_->outString_, "PH");
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// Seems to be necessary to delay a short time between writes
|
||||
epicsThreadSleep(WRITE_DELAY);
|
||||
// The response string is of the form "PHn"
|
||||
lim = atoi(&pC_->inString_[2]);
|
||||
if ((axisID_ == 1) && (lim == 1 || lim == 3)) limit = 1;
|
||||
if ((axisID_ == 2) && (lim == 3 || lim == 3)) limit = 1;
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, limit);
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, limit);
|
||||
|
||||
skip:
|
||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
||||
callParamCallbacks();
|
||||
return comStatus ? asynError : asynSuccess;
|
||||
}
|
||||
|
||||
/** Writes a string to the controller.
|
||||
* Calls writeAgilis() with a default location of the string to write and a default timeout. */
|
||||
asynStatus AG_UCAxis::writeAgilis()
|
||||
{
|
||||
return pC_->writeAgilis(channelID_, pC_->outString_, AGILIS_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
asynStatus AG_UCAxis::writeAgilis(const char *output, double timeout)
|
||||
{
|
||||
return pC_->writeAgilis(channelID_, output, timeout);
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg AG_UCCreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg AG_UCCreateControllerArg1 = {"Serial port name", iocshArgString};
|
||||
static const iocshArg AG_UCCreateControllerArg2 = {"Number of axes", iocshArgInt};
|
||||
static const iocshArg AG_UCCreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
|
||||
static const iocshArg AG_UCCreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
|
||||
static const iocshArg * const AG_UCCreateControllerArgs[] = {&AG_UCCreateControllerArg0,
|
||||
&AG_UCCreateControllerArg1,
|
||||
&AG_UCCreateControllerArg2,
|
||||
&AG_UCCreateControllerArg3,
|
||||
&AG_UCCreateControllerArg4};
|
||||
static const iocshFuncDef AG_UCCreateControllerDef = {"AG_UCCreateController", 5, AG_UCCreateControllerArgs};
|
||||
static void AG_UCCreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
AG_UCCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
/* AG_UCCreateAxis */
|
||||
static const iocshArg AG_UCCreateAxisArg0 = {"Controller port name", iocshArgString};
|
||||
static const iocshArg AG_UCCreateAxisArg1 = {"Axis number", iocshArgInt};
|
||||
static const iocshArg AG_UCCreateAxisArg2 = {"Has Limits", iocshArgInt};
|
||||
static const iocshArg AG_UCCreateAxisArg3 = {"Forward amplitude", iocshArgInt};
|
||||
static const iocshArg AG_UCCreateAxisArg4 = {"Reverse amplitude", iocshArgInt};
|
||||
static const iocshArg * const AG_UCCreateAxisArgs[] = {&AG_UCCreateAxisArg0,
|
||||
&AG_UCCreateAxisArg1,
|
||||
&AG_UCCreateAxisArg2,
|
||||
&AG_UCCreateAxisArg3,
|
||||
&AG_UCCreateAxisArg4};
|
||||
static const iocshFuncDef AG_UCCreateAxisDef = {"AG_UCCreateAxis", 5, AG_UCCreateAxisArgs};
|
||||
|
||||
static void AG_UCCreateAxisCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
AG_UCCreateAxis(args[0].sval, args[1].ival, args[2].ival, args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
static void AG_UCRegister(void)
|
||||
{
|
||||
iocshRegister(&AG_UCCreateControllerDef, AG_UCCreateContollerCallFunc);
|
||||
iocshRegister(&AG_UCCreateAxisDef, AG_UCCreateAxisCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(AG_UCRegister);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
FILENAME... AG_UC.h
|
||||
USAGE... Motor driver support for the Newport Agilis AG-UC series of controllers.
|
||||
|
||||
Mark Rivers
|
||||
April 11, 2013
|
||||
|
||||
*/
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
typedef enum {
|
||||
ModelAG_UC2,
|
||||
ModelAG_UC8,
|
||||
ModelAG_UC8PC
|
||||
} AG_UCModel_t;
|
||||
|
||||
// No controller-specific parameters yet
|
||||
#define NUM_AG_UC_PARAMS 0
|
||||
|
||||
class epicsShareClass AG_UCAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
AG_UCAxis(class AG_UCController *pC, int axis, bool hasLimits, int forwardAmplitude, int reverseAmplitude);
|
||||
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);
|
||||
|
||||
private:
|
||||
int velocityToSpeedCode(double velocity);
|
||||
asynStatus writeAgilis();
|
||||
asynStatus writeAgilis(const char *output, double timeout);
|
||||
AG_UCController *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
bool hasLimits_;
|
||||
int forwardAmplitude_;
|
||||
int reverseAmplitude_;
|
||||
int currentPosition_;
|
||||
int positionOffset_;
|
||||
int axisID_;
|
||||
int channelID_;
|
||||
|
||||
friend class AG_UCController;
|
||||
};
|
||||
|
||||
class epicsShareClass AG_UCController : public asynMotorController {
|
||||
public:
|
||||
AG_UCController(const char *portName, const char *serialPortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
AG_UCAxis* getAxis(asynUser *pasynUser);
|
||||
AG_UCAxis* getAxis(int axisNo);
|
||||
asynStatus setChannel(int channelID);
|
||||
asynStatus writeAgilis(int channelID);
|
||||
asynStatus writeAgilis(int channelID, const char *output, double timeout);
|
||||
|
||||
friend class AG_UCAxis;
|
||||
|
||||
private:
|
||||
char controllerVersion_[40];
|
||||
AG_UCModel_t AG_UCModel_;
|
||||
};
|
||||
@@ -1,6 +0,0 @@
|
||||
Version 1.4.1 http://www.newport.com/file_store/Software_Drivers/XPS_Firmware-V1_4_1.zip
|
||||
|
||||
Version 1.5.x ftp://mail.newport-fr.com/FTP_SUPPORT/XPS Controller/XPS-C8_Updates/XPS-C8 V1.5.x/
|
||||
|
||||
Version 2.0.x ftp://webmail.newport-fr.com/FTP_SUPPORT/XPS Controller/XPS-C8_Updates/XPS-C8 V2.0.x/
|
||||
|
||||
@@ -1,726 +0,0 @@
|
||||
/*
|
||||
FILENAME... HXPDriver.cpp
|
||||
USAGE... Motor driver support for the Newport Hexapod controller.
|
||||
|
||||
Note: This driver was tested with the v1.3.x of the firmware
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsString.h>
|
||||
|
||||
#include <asynOctetSyncIO.h>
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include "hxp_drivers.h"
|
||||
#include "HXPDriver.h"
|
||||
|
||||
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||
#define NUM_AXES 6
|
||||
#define GROUP "HEXAPOD"
|
||||
#define MRES 0.00001
|
||||
|
||||
static const char *driverName = "HXPDriver";
|
||||
|
||||
/** Creates a new HXPController object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] IPAddress The Newport hexapod controller's ip address
|
||||
* \param[in] IPPort TCP/IP port used to communicate with the hexapod controller
|
||||
* \param[in] movingPollPeriod The time between polls when any axis is moving
|
||||
* \param[in] idlePollPeriod The time between polls when no axis is moving
|
||||
*/
|
||||
HXPController::HXPController(const char *portName, const char *IPAddress, int IPPort,
|
||||
double movingPollPeriod, double idlePollPeriod)
|
||||
: asynMotorController(portName, NUM_AXES, NUM_HXP_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;
|
||||
HXPAxis *pAxis;
|
||||
static const char *functionName = "HXPController::HXPController";
|
||||
|
||||
axisNames_ = epicsStrDup("XYZUVW");
|
||||
|
||||
IPAddress_ = epicsStrDup(IPAddress);
|
||||
IPPort_ = IPPort;
|
||||
|
||||
createParam(HXPMoveCoordSysString, asynParamInt32, &HXPMoveCoordSys_);
|
||||
createParam(HXPStatusString, asynParamInt32, &HXPStatus_);
|
||||
createParam(HXPErrorString, asynParamInt32, &HXPError_);
|
||||
createParam(HXPErrorDescString, asynParamOctet, &HXPErrorDesc_);
|
||||
createParam(HXPMoveAllString, asynParamInt32, &HXPMoveAll_);
|
||||
createParam(HXPMoveAllTargetXString, asynParamFloat64, &HXPMoveAllTargetX_);
|
||||
createParam(HXPMoveAllTargetYString, asynParamFloat64, &HXPMoveAllTargetY_);
|
||||
createParam(HXPMoveAllTargetZString, asynParamFloat64, &HXPMoveAllTargetZ_);
|
||||
createParam(HXPMoveAllTargetUString, asynParamFloat64, &HXPMoveAllTargetU_);
|
||||
createParam(HXPMoveAllTargetVString, asynParamFloat64, &HXPMoveAllTargetV_);
|
||||
createParam(HXPMoveAllTargetWString, asynParamFloat64, &HXPMoveAllTargetW_);
|
||||
createParam(HXPCoordSysReadAllString, asynParamInt32, &HXPCoordSysReadAll_);
|
||||
createParam(HXPCoordSysToolXString, asynParamFloat64, &HXPCoordSysToolX_);
|
||||
createParam(HXPCoordSysToolYString, asynParamFloat64, &HXPCoordSysToolY_);
|
||||
createParam(HXPCoordSysToolZString, asynParamFloat64, &HXPCoordSysToolZ_);
|
||||
createParam(HXPCoordSysToolUString, asynParamFloat64, &HXPCoordSysToolU_);
|
||||
createParam(HXPCoordSysToolVString, asynParamFloat64, &HXPCoordSysToolV_);
|
||||
createParam(HXPCoordSysToolWString, asynParamFloat64, &HXPCoordSysToolW_);
|
||||
createParam(HXPCoordSysWorkXString, asynParamFloat64, &HXPCoordSysWorkX_);
|
||||
createParam(HXPCoordSysWorkYString, asynParamFloat64, &HXPCoordSysWorkY_);
|
||||
createParam(HXPCoordSysWorkZString, asynParamFloat64, &HXPCoordSysWorkZ_);
|
||||
createParam(HXPCoordSysWorkUString, asynParamFloat64, &HXPCoordSysWorkU_);
|
||||
createParam(HXPCoordSysWorkVString, asynParamFloat64, &HXPCoordSysWorkV_);
|
||||
createParam(HXPCoordSysWorkWString, asynParamFloat64, &HXPCoordSysWorkW_);
|
||||
createParam(HXPCoordSysBaseXString, asynParamFloat64, &HXPCoordSysBaseX_);
|
||||
createParam(HXPCoordSysBaseYString, asynParamFloat64, &HXPCoordSysBaseY_);
|
||||
createParam(HXPCoordSysBaseZString, asynParamFloat64, &HXPCoordSysBaseZ_);
|
||||
createParam(HXPCoordSysBaseUString, asynParamFloat64, &HXPCoordSysBaseU_);
|
||||
createParam(HXPCoordSysBaseVString, asynParamFloat64, &HXPCoordSysBaseV_);
|
||||
createParam(HXPCoordSysBaseWString, asynParamFloat64, &HXPCoordSysBaseW_);
|
||||
createParam(HXPCoordSysSetString, asynParamInt32, &HXPCoordSysSet_);
|
||||
createParam(HXPCoordSysToSetString, asynParamInt32, &HXPCoordSysToSet_);
|
||||
createParam(HXPCoordSysSetXString, asynParamFloat64, &HXPCoordSysSetX_);
|
||||
createParam(HXPCoordSysSetYString, asynParamFloat64, &HXPCoordSysSetY_);
|
||||
createParam(HXPCoordSysSetZString, asynParamFloat64, &HXPCoordSysSetZ_);
|
||||
createParam(HXPCoordSysSetUString, asynParamFloat64, &HXPCoordSysSetU_);
|
||||
createParam(HXPCoordSysSetVString, asynParamFloat64, &HXPCoordSysSetV_);
|
||||
createParam(HXPCoordSysSetWString, asynParamFloat64, &HXPCoordSysSetW_);
|
||||
|
||||
// This socket is used for polling by the controller and all axes
|
||||
pollSocket_ = HXPTCP_ConnectToServer((char *)IPAddress, IPPort, HXP_POLL_TIMEOUT);
|
||||
if (pollSocket_ < 0) {
|
||||
printf("%s:%s: error calling TCP_ConnectToServer for pollSocket\n",
|
||||
driverName, functionName);
|
||||
}
|
||||
|
||||
HXPFirmwareVersionGet(pollSocket_, firmwareVersion_);
|
||||
|
||||
for (axis=0; axis<NUM_AXES; axis++) {
|
||||
pAxis = new HXPAxis(this, axis);
|
||||
}
|
||||
|
||||
startPoller(movingPollPeriod, idlePollPeriod, 2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new HXPController 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] HXPPortName The name of the drvAsynIPPPort that was created previously to connect to the Newport hexapod 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 HXPCreateController(const char *portName, const char *IPAddress, int IPPort,
|
||||
int movingPollPeriod, int idlePollPeriod)
|
||||
{
|
||||
HXPController *pHXPController
|
||||
= new HXPController(portName, IPAddress, IPPort, movingPollPeriod/1000., idlePollPeriod/1000.);
|
||||
pHXPController = 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 HXPController::report(FILE *fp, int level)
|
||||
{
|
||||
int coordSys;
|
||||
|
||||
getIntegerParam(HXPMoveCoordSys_, &coordSys);
|
||||
|
||||
fprintf(fp, "Newport hexapod motor driver %s, numAxes=%d, moving poll period=%f, idle poll period=%f, coordSys=%d\n",
|
||||
this->portName, NUM_AXES, movingPollPeriod_, idlePollPeriod_, coordSys);
|
||||
|
||||
// Call the base class method
|
||||
asynMotorController::report(fp, level);
|
||||
}
|
||||
|
||||
/** Returns a pointer to an HXPAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
HXPAxis* HXPController::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<HXPAxis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an HXPAxis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] axisNo Axis index number. */
|
||||
HXPAxis* HXPController::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<HXPAxis*>(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 HXPMoveAll_ then it calls moves all motors with a single command
|
||||
* For all other functions it calls asynMotorController::writeInt32.
|
||||
* Calls any registered callbacks for this pasynUser->reason and address.
|
||||
* \param[in] pasynUser asynUser structure that encodes the reason and address.
|
||||
* \param[in] value Value to write. */
|
||||
asynStatus HXPController::writeInt32(asynUser *pasynUser, epicsInt32 value)
|
||||
{
|
||||
int function = pasynUser->reason;
|
||||
asynStatus status = asynSuccess;
|
||||
HXPAxis *pAxis = getAxis(pasynUser);
|
||||
static const char *functionName = "writeInt32";
|
||||
|
||||
/* Set the parameter and readback in the parameter library. This may be overwritten when we read back the
|
||||
* status at the end, but that's OK */
|
||||
status = setIntegerParam(pAxis->axisNo_, function, value);
|
||||
|
||||
if (function == HXPMoveAll_)
|
||||
{
|
||||
/* if value == 1: motors are moved
|
||||
if value == 0: nothing is done and parameter is simply reset */
|
||||
if (value == 1)
|
||||
{
|
||||
moveAll(pAxis);
|
||||
}
|
||||
}
|
||||
else if (function == HXPCoordSysReadAll_)
|
||||
{
|
||||
if (value == 1)
|
||||
{
|
||||
readAllCS(pAxis);
|
||||
}
|
||||
}
|
||||
else if (function == HXPCoordSysSet_)
|
||||
{
|
||||
if (value == 1)
|
||||
{
|
||||
setCS(pAxis);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Call base class method */
|
||||
status = asynMotorController::writeInt32(pasynUser, value);
|
||||
}
|
||||
|
||||
/* Do callbacks so higher layers see any changes */
|
||||
callParamCallbacks(pAxis->axisNo_);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moves all hexpod axes to new target positions
|
||||
*/
|
||||
int HXPController::moveAll(HXPAxis *pAxis)
|
||||
{
|
||||
int status;
|
||||
double x, y, z, u, v, w;
|
||||
|
||||
getDoubleParam(0, HXPMoveAllTargetX_, &x);
|
||||
getDoubleParam(0, HXPMoveAllTargetY_, &y);
|
||||
getDoubleParam(0, HXPMoveAllTargetZ_, &z);
|
||||
getDoubleParam(0, HXPMoveAllTargetU_, &u);
|
||||
getDoubleParam(0, HXPMoveAllTargetV_, &v);
|
||||
getDoubleParam(0, HXPMoveAllTargetW_, &w);
|
||||
|
||||
status = HXPHexapodMoveAbsolute(pAxis->moveSocket_, GROUP, "Work", x, y, z, u, v, w);
|
||||
|
||||
postError(pAxis, status);
|
||||
|
||||
/* callParamCallback() is called from postError, so it isn't needed here */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the Tool, Work, and Base coordinate-system definitions
|
||||
*/
|
||||
int HXPController::readAllCS(HXPAxis *pAxis)
|
||||
{
|
||||
int status;
|
||||
double x, y, z, u, v, w;
|
||||
|
||||
status = HXPHexapodCoordinateSystemGet(pAxis->moveSocket_, GROUP, "Tool", &x, &y , &z, &u, &v, &w);
|
||||
|
||||
setDoubleParam(0, HXPCoordSysToolX_, x);
|
||||
setDoubleParam(0, HXPCoordSysToolY_, y);
|
||||
setDoubleParam(0, HXPCoordSysToolZ_, z);
|
||||
setDoubleParam(0, HXPCoordSysToolU_, u);
|
||||
setDoubleParam(0, HXPCoordSysToolV_, v);
|
||||
setDoubleParam(0, HXPCoordSysToolW_, w);
|
||||
|
||||
postError(pAxis, status);
|
||||
|
||||
status = HXPHexapodCoordinateSystemGet(pAxis->moveSocket_, GROUP, "Work", &x, &y , &z, &u, &v, &w);
|
||||
|
||||
setDoubleParam(0, HXPCoordSysWorkX_, x);
|
||||
setDoubleParam(0, HXPCoordSysWorkY_, y);
|
||||
setDoubleParam(0, HXPCoordSysWorkZ_, z);
|
||||
setDoubleParam(0, HXPCoordSysWorkU_, u);
|
||||
setDoubleParam(0, HXPCoordSysWorkV_, v);
|
||||
setDoubleParam(0, HXPCoordSysWorkW_, w);
|
||||
|
||||
postError(pAxis, status);
|
||||
|
||||
status = HXPHexapodCoordinateSystemGet(pAxis->moveSocket_, GROUP, "Base", &x, &y , &z, &u, &v, &w);
|
||||
|
||||
setDoubleParam(0, HXPCoordSysBaseX_, x);
|
||||
setDoubleParam(0, HXPCoordSysBaseY_, y);
|
||||
setDoubleParam(0, HXPCoordSysBaseZ_, z);
|
||||
setDoubleParam(0, HXPCoordSysBaseU_, u);
|
||||
setDoubleParam(0, HXPCoordSysBaseV_, v);
|
||||
setDoubleParam(0, HXPCoordSysBaseW_, w);
|
||||
|
||||
postError(pAxis, status);
|
||||
|
||||
/* callParamCallback() is called from postError, so it isn't needed here */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redefine the origins of the hexapod coordinate-systems
|
||||
*/
|
||||
int HXPController::setCS(HXPAxis *pAxis)
|
||||
{
|
||||
int status = 0;
|
||||
int cs; // 0=None,1=Work,2=Tool,3=Base
|
||||
double x, y, z, u, v, w;
|
||||
|
||||
getIntegerParam(0, HXPCoordSysToSet_, &cs);
|
||||
getDoubleParam(0, HXPCoordSysSetX_, &x);
|
||||
getDoubleParam(0, HXPCoordSysSetY_, &y);
|
||||
getDoubleParam(0, HXPCoordSysSetZ_, &z);
|
||||
getDoubleParam(0, HXPCoordSysSetU_, &u);
|
||||
getDoubleParam(0, HXPCoordSysSetV_, &v);
|
||||
getDoubleParam(0, HXPCoordSysSetW_, &w);
|
||||
|
||||
if (cs == 1)
|
||||
{
|
||||
status = HXPHexapodCoordinateSystemSet(pAxis->moveSocket_, GROUP, "Work", x, y, z, u, v, w);
|
||||
}
|
||||
else if (cs == 2)
|
||||
{
|
||||
status = HXPHexapodCoordinateSystemSet(pAxis->moveSocket_, GROUP, "Tool", x, y, z, u, v, w);
|
||||
}
|
||||
else if (cs == 3)
|
||||
{
|
||||
status = HXPHexapodCoordinateSystemSet(pAxis->moveSocket_, GROUP, "Base", x, y, z, u, v, w);
|
||||
}
|
||||
|
||||
postError(pAxis, status);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void HXPController::postError(HXPAxis *pAxis, int status)
|
||||
{
|
||||
/* This is similar to what is done in HXPAxis::move() */
|
||||
if (status < 0)
|
||||
{
|
||||
/* Set the error */
|
||||
setIntegerParam(HXPError_, status);
|
||||
|
||||
/* Get the error string */
|
||||
HXPErrorStringGet(pAxis->moveSocket_, status, pAxis->errorDescFull_);
|
||||
|
||||
/* Trim the error string */
|
||||
strncpy(pAxis->errorDesc_, pAxis->errorDescFull_, 39);
|
||||
pAxis->errorDesc_[39] = 0;
|
||||
|
||||
/* Set the error description */
|
||||
setStringParam(HXPErrorDesc_, pAxis->errorDesc_);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear the error */
|
||||
setIntegerParam(HXPError_, 0);
|
||||
setStringParam(HXPErrorDesc_, "");
|
||||
}
|
||||
callParamCallbacks();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Polls the controller.
|
||||
* 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 HXPController::poll()
|
||||
{
|
||||
int status;
|
||||
//char readResponse[25];
|
||||
|
||||
static const char *functionName = "HXPController::poll";
|
||||
|
||||
status = HXPGroupStatusGet(pollSocket_,
|
||||
GROUP,
|
||||
&groupStatus_);
|
||||
if (status) {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s:%s: [%s]: error calling GroupStatusGet status=%d; pollSocket=%d\n",
|
||||
driverName, functionName, portName, status, pollSocket_);
|
||||
goto done;
|
||||
}
|
||||
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
|
||||
"%s:%s: [%s]: %s groupStatus=%d\n",
|
||||
driverName, functionName, portName, GROUP, groupStatus_);
|
||||
/* Set the status */
|
||||
setIntegerParam(HXPStatus_, groupStatus_);
|
||||
|
||||
/* If the group is not moving then the axis is not moving */
|
||||
if ((groupStatus_ < 43) || (groupStatus_ > 48))
|
||||
moving_ = false;
|
||||
else
|
||||
moving_ = true;
|
||||
|
||||
/* Set the motor done parameter */
|
||||
setIntegerParam(motorStatusDone_, moving_?0:1);
|
||||
|
||||
/*Test for states that mean we cannot move an axis (disabled, uninitialised, etc.)
|
||||
and set problem bit in MSTA.*/
|
||||
if ((groupStatus_ < 10) || ((groupStatus_ >= 20) && (groupStatus_ <= 42)) ||
|
||||
(groupStatus_ == 50) || (groupStatus_ == 64))
|
||||
{
|
||||
/* Don't consider a normal disabled status to be a problem */
|
||||
if ( groupStatus_==20 )
|
||||
{
|
||||
setIntegerParam(motorStatusProblem_, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_FLOW,
|
||||
"%s:%s: [%s]: in unintialised/disabled/not referenced. XPS State Code: %d\n",
|
||||
driverName, functionName, portName, groupStatus_);
|
||||
setIntegerParam(motorStatusProblem_, 1);
|
||||
}
|
||||
|
||||
/* Group status indicates power is off */
|
||||
setIntegerParam(motorStatusPowerOn_, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
setIntegerParam(motorStatusProblem_, 0);
|
||||
setIntegerParam(motorStatusPowerOn_, 1);
|
||||
}
|
||||
|
||||
status = HXPGroupPositionCurrentGet(pollSocket_,
|
||||
GROUP,
|
||||
MAX_HXP_AXES,
|
||||
encoderPosition_);
|
||||
if (status) {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s:%s: [%s]: error calling GroupPositionCurrentGet status=%d\n",
|
||||
driverName, functionName, portName, status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
status = HXPGroupPositionSetpointGet(pollSocket_,
|
||||
GROUP,
|
||||
MAX_HXP_AXES,
|
||||
setpointPosition_);
|
||||
if (status) {
|
||||
asynPrint(pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s:%s: [%s]: error calling GroupPositionSetpointGet status=%d\n",
|
||||
driverName, functionName, portName, status);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
setIntegerParam(motorStatusProblem_, status ? 1:0);
|
||||
callParamCallbacks();
|
||||
return status ? asynError : asynSuccess;
|
||||
}
|
||||
|
||||
|
||||
// These are the HXPAxis methods
|
||||
|
||||
/** Creates a new HXPAxis object.
|
||||
* \param[in] pC Pointer to the HXPController to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
HXPAxis::HXPAxis(HXPController *pC, int axisNo)
|
||||
: asynMotorAxis(pC, axisNo),
|
||||
pC_(pC)
|
||||
{
|
||||
axisName_ = pC_->axisNames_[axisNo];
|
||||
sprintf(positionerName_, "%s.%c", GROUP, (char) axisName_);
|
||||
|
||||
// Couldn't a negative timeout be used here instead?
|
||||
moveSocket_ = HXPTCP_ConnectToServer(pC_->IPAddress_, pC->IPPort_, HXP_POLL_TIMEOUT);
|
||||
|
||||
/* Set the poll rate on the moveSocket to a negative number, which means that SendAndReceive should do only a write, no read */
|
||||
HXPTCP_SetTimeout(moveSocket_, -0.1);
|
||||
pollSocket_ = pC_->pollSocket_;
|
||||
|
||||
/* Enable gain support so that the CNEN field to enable/disable the hexapod */
|
||||
setIntegerParam(pC_->motorStatusGainSupport_, 1);
|
||||
// does the hexapod read encoders from the stages? leave in for now to test relative moves
|
||||
setIntegerParam(pC_->motorStatusHasEncoder_, 1);
|
||||
|
||||
}
|
||||
|
||||
/** 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 HXPAxis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axis %d\n", axisNo_);
|
||||
fprintf(fp, " axisName %c\n", axisName_);
|
||||
}
|
||||
|
||||
// Call the base class method
|
||||
asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
asynStatus HXPAxis::move(double position, int relative, double baseVelocity, double slewVelocity, double acceleration)
|
||||
{
|
||||
int status;
|
||||
double start_pos;
|
||||
double end_pos;
|
||||
double diff_pos;
|
||||
double cur_pos[NUM_AXES];
|
||||
double rel_pos[NUM_AXES] = {};
|
||||
double *pos;
|
||||
int coordSys; // 0 = work, 1 = tool
|
||||
static const char *functionName = "HXPAxis::move";
|
||||
asynStatus retval = asynSuccess;
|
||||
|
||||
pC_->getIntegerParam(pC_->HXPMoveCoordSys_, &coordSys);
|
||||
|
||||
if (relative) {
|
||||
rel_pos[axisNo_] = position * MRES;
|
||||
pos = rel_pos;
|
||||
|
||||
if (coordSys == 0)
|
||||
{
|
||||
status = HXPHexapodMoveIncremental(moveSocket_, GROUP, "Work", pos[0], pos[1], pos[2], pos[3], pos[4], pos[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = HXPHexapodMoveIncremental(moveSocket_, GROUP, "Tool", pos[0], pos[1], pos[2], pos[3], pos[4], pos[5]);
|
||||
}
|
||||
|
||||
if (status != 0 && status != -27) {
|
||||
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
|
||||
"%s:%s: Error performing HexapodMoveIncremental[%s,%d] %d\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, status);
|
||||
/* Error -27 is caused when the motor record changes dir i.e. when it aborts a move! */
|
||||
retval = asynError;
|
||||
}
|
||||
} else {
|
||||
// get current positions before moving (could an error overflow the array?)
|
||||
status = HXPGroupPositionCurrentGet(pollSocket_, GROUP, 6, (double *) &cur_pos);
|
||||
|
||||
// Capture current position for relative move calc
|
||||
start_pos = cur_pos[axisNo_];
|
||||
|
||||
end_pos = position * MRES;
|
||||
|
||||
if (coordSys == 0)
|
||||
{
|
||||
// Update position of axis to be moved
|
||||
cur_pos[axisNo_] = end_pos;
|
||||
pos = cur_pos;
|
||||
|
||||
status = HXPHexapodMoveAbsolute(moveSocket_, GROUP, "Work", pos[0], pos[1], pos[2], pos[3], pos[4], pos[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculate relative move amount (needed for Tool coord-sys moves)
|
||||
diff_pos = end_pos - start_pos;
|
||||
|
||||
// Update position of axis to be moved
|
||||
rel_pos[axisNo_] = diff_pos;
|
||||
pos = rel_pos;
|
||||
|
||||
status = HXPHexapodMoveIncremental(moveSocket_, GROUP, "Tool", pos[0], pos[1], pos[2], pos[3], pos[4], pos[5]);
|
||||
|
||||
}
|
||||
|
||||
if (status != 0 && status != -27) {
|
||||
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
|
||||
"%s:%s: Error performing HexapodMoveAbsolute[%s,%d] %d\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, status);
|
||||
/* Error -27 is caused when the motor record changes dir i.e. when it aborts a move! */
|
||||
retval = asynError;
|
||||
}
|
||||
}
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
/* Set the error */
|
||||
pC_->setIntegerParam(pC_->HXPError_, status);
|
||||
|
||||
/* Get the error string */
|
||||
HXPErrorStringGet(moveSocket_, status, errorDescFull_);
|
||||
|
||||
/* Trim the error string */
|
||||
strncpy(errorDesc_, errorDescFull_, 39);
|
||||
errorDesc_[39] = 0;
|
||||
|
||||
/* Set the error description */
|
||||
pC_->setStringParam(pC_->HXPErrorDesc_, errorDesc_);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Clear the error */
|
||||
pC_->setIntegerParam(pC_->HXPError_, 0);
|
||||
pC_->setStringParam(pC_->HXPErrorDesc_, "");
|
||||
}
|
||||
callParamCallbacks();
|
||||
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
asynStatus HXPAxis::home(double baseVelocity, double slewVelocity, double acceleration, int forwards)
|
||||
{
|
||||
// static const char *functionName = "HXPAxis::home";
|
||||
|
||||
// kill all
|
||||
HXPGroupKill(moveSocket_, GROUP);
|
||||
// initialize
|
||||
HXPGroupInitialize(moveSocket_, GROUP);
|
||||
// home
|
||||
HXPGroupHomeSearch(moveSocket_, GROUP);
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus HXPAxis::stop(double acceleration )
|
||||
{
|
||||
int status;
|
||||
//static const char *functionName = "HXPAxis::stop";
|
||||
|
||||
status = HXPGroupMoveAbort(moveSocket_, GROUP);
|
||||
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
asynStatus HXPAxis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
int status;
|
||||
static const char *functionName = "HXPAxis::setClosedLoop";
|
||||
|
||||
if (closedLoop) {
|
||||
status = HXPGroupMotionEnable(pollSocket_, GROUP);
|
||||
if (status) {
|
||||
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
|
||||
"%s:%s: [%s,%d]: error calling GroupMotionEnable status=%d\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, status);
|
||||
} else {
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s: set XPS %s, axis %d closed loop enable\n",
|
||||
driverName, functionName, pC_->portName, axisNo_);
|
||||
}
|
||||
} else {
|
||||
status = HXPGroupMotionDisable(pollSocket_, GROUP);
|
||||
if (status) {
|
||||
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
|
||||
"%s:%s: [%s,%d]: error calling GroupMotionDisable status=%d\n",
|
||||
driverName, functionName, pC_->portName, axisNo_, status);
|
||||
} else {
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s:%s: motorAxisSetInteger set XPS %s, axis %d closed loop disable\n",
|
||||
driverName, functionName, pC_->portName, axisNo_);
|
||||
}
|
||||
}
|
||||
|
||||
return (asynStatus)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 HXPAxis::poll(bool *moving)
|
||||
{
|
||||
int status;
|
||||
//char readResponse[25];
|
||||
|
||||
static const char *functionName = "HXPAxis::poll";
|
||||
|
||||
/* If the group is not moving then the axis is not moving */
|
||||
moving_ = pC_->moving_;
|
||||
|
||||
/* Set the axis done parameter */
|
||||
*moving = moving_;
|
||||
setIntegerParam(pC_->motorStatusDone_, *moving?0:1);
|
||||
|
||||
encoderPosition_ = pC_->encoderPosition_[axisNo_];
|
||||
setpointPosition_ = pC_->setpointPosition_[axisNo_];
|
||||
|
||||
//setDoubleParam(pC_->motorEncoderPosition_, (encoderPosition_/stepSize_));
|
||||
setDoubleParam(pC_->motorEncoderPosition_, encoderPosition_ / MRES);
|
||||
|
||||
//setDoubleParam(pC_->motorPosition_, (setpointPosition_/stepSize_));
|
||||
setDoubleParam(pC_->motorPosition_, setpointPosition_ / MRES);
|
||||
|
||||
// limit check?
|
||||
|
||||
// dir flag?
|
||||
|
||||
callParamCallbacks();
|
||||
return asynSuccess;
|
||||
}
|
||||
|
||||
/** Code for iocsh registration */
|
||||
static const iocshArg HXPCreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg HXPCreateControllerArg1 = {"IP address", iocshArgString};
|
||||
static const iocshArg HXPCreateControllerArg2 = {"Port", iocshArgInt};
|
||||
static const iocshArg HXPCreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
|
||||
static const iocshArg HXPCreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
|
||||
static const iocshArg * const HXPCreateControllerArgs[] = {&HXPCreateControllerArg0,
|
||||
&HXPCreateControllerArg1,
|
||||
&HXPCreateControllerArg2,
|
||||
&HXPCreateControllerArg3,
|
||||
&HXPCreateControllerArg4};
|
||||
static const iocshFuncDef HXPCreateControllerDef = {"HXPCreateController", 5, HXPCreateControllerArgs};
|
||||
static void HXPCreateControllerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
HXPCreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival);
|
||||
}
|
||||
|
||||
static void HXPRegister(void)
|
||||
{
|
||||
iocshRegister(&HXPCreateControllerDef, HXPCreateControllerCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(HXPRegister);
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
/*
|
||||
FILENAME... HXPDriver.h
|
||||
USAGE... Motor driver support for the Newport Hexapod controller.
|
||||
|
||||
*/
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#define MAX_HXP_AXES 6
|
||||
#define HXP_POLL_TIMEOUT 2.0
|
||||
#define HXP_MOVE_TIMEOUT 100000.0 // "Forever"
|
||||
|
||||
// drvInfo strings for extra parameters that the HXP controller supports
|
||||
#define HXPMoveCoordSysString "HXP_MOVE_COORD_SYS"
|
||||
#define HXPStatusString "HXP_STATUS"
|
||||
#define HXPErrorString "HXP_ERROR"
|
||||
#define HXPErrorDescString "HXP_ERROR_DESC"
|
||||
#define HXPMoveAllString "HXP_MOVE_ALL"
|
||||
#define HXPMoveAllTargetXString "HXP_MOVE_ALL_TARGET_X"
|
||||
#define HXPMoveAllTargetYString "HXP_MOVE_ALL_TARGET_Y"
|
||||
#define HXPMoveAllTargetZString "HXP_MOVE_ALL_TARGET_Z"
|
||||
#define HXPMoveAllTargetUString "HXP_MOVE_ALL_TARGET_U"
|
||||
#define HXPMoveAllTargetVString "HXP_MOVE_ALL_TARGET_V"
|
||||
#define HXPMoveAllTargetWString "HXP_MOVE_ALL_TARGET_W"
|
||||
#define HXPCoordSysReadAllString "HXP_COORD_SYS_READ_ALL"
|
||||
#define HXPCoordSysToolXString "HXP_COORD_SYS_TOOL_X"
|
||||
#define HXPCoordSysToolYString "HXP_COORD_SYS_TOOL_Y"
|
||||
#define HXPCoordSysToolZString "HXP_COORD_SYS_TOOL_Z"
|
||||
#define HXPCoordSysToolUString "HXP_COORD_SYS_TOOL_U"
|
||||
#define HXPCoordSysToolVString "HXP_COORD_SYS_TOOL_V"
|
||||
#define HXPCoordSysToolWString "HXP_COORD_SYS_TOOL_W"
|
||||
#define HXPCoordSysWorkXString "HXP_COORD_SYS_WORK_X"
|
||||
#define HXPCoordSysWorkYString "HXP_COORD_SYS_WORK_Y"
|
||||
#define HXPCoordSysWorkZString "HXP_COORD_SYS_WORK_Z"
|
||||
#define HXPCoordSysWorkUString "HXP_COORD_SYS_WORK_U"
|
||||
#define HXPCoordSysWorkVString "HXP_COORD_SYS_WORK_V"
|
||||
#define HXPCoordSysWorkWString "HXP_COORD_SYS_WORK_W"
|
||||
#define HXPCoordSysBaseXString "HXP_COORD_SYS_BASE_X"
|
||||
#define HXPCoordSysBaseYString "HXP_COORD_SYS_BASE_Y"
|
||||
#define HXPCoordSysBaseZString "HXP_COORD_SYS_BASE_Z"
|
||||
#define HXPCoordSysBaseUString "HXP_COORD_SYS_BASE_U"
|
||||
#define HXPCoordSysBaseVString "HXP_COORD_SYS_BASE_V"
|
||||
#define HXPCoordSysBaseWString "HXP_COORD_SYS_BASE_W"
|
||||
#define HXPCoordSysSetString "HXP_COORD_SYS_SET"
|
||||
#define HXPCoordSysToSetString "HXP_COORD_SYS_TO_SET"
|
||||
#define HXPCoordSysSetXString "HXP_COORD_SYS_SET_X"
|
||||
#define HXPCoordSysSetYString "HXP_COORD_SYS_SET_Y"
|
||||
#define HXPCoordSysSetZString "HXP_COORD_SYS_SET_Z"
|
||||
#define HXPCoordSysSetUString "HXP_COORD_SYS_SET_U"
|
||||
#define HXPCoordSysSetVString "HXP_COORD_SYS_SET_V"
|
||||
#define HXPCoordSysSetWString "HXP_COORD_SYS_SET_W"
|
||||
|
||||
|
||||
class epicsShareClass HXPAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
HXPAxis(class HXPController *pC, int axis);
|
||||
void report(FILE *fp, int level);
|
||||
asynStatus move(double position, int relative, 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);
|
||||
|
||||
private:
|
||||
HXPController *pC_; /* Pointer to the asynMotorController to which this axis belongs.
|
||||
Abbreviated because it is used very frequently */
|
||||
int moveSocket_;
|
||||
int pollSocket_;
|
||||
char axisName_;
|
||||
char positionerName_[12];
|
||||
char errorDesc_[40];
|
||||
char errorDescFull_[1024];
|
||||
double encoderPosition_;
|
||||
double setpointPosition_;
|
||||
int axisStatus_;
|
||||
double mres_;
|
||||
bool moving_;
|
||||
|
||||
friend class HXPController;
|
||||
};
|
||||
|
||||
class epicsShareClass HXPController : public asynMotorController {
|
||||
public:
|
||||
HXPController(const char *portName, const char *HXPPortName, int numAxes, double movingPollPeriod, double idlePollPeriod);
|
||||
|
||||
/* These are the methods that we override from asynMotorDriver */
|
||||
asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value); /* needed for implementation of moveAll */
|
||||
void report(FILE *fp, int level);
|
||||
HXPAxis* getAxis(asynUser *pasynUser);
|
||||
HXPAxis* getAxis(int axisNo);
|
||||
asynStatus poll();
|
||||
|
||||
/* These are the methods that are new to this class */
|
||||
int moveAll(HXPAxis* pAxis);
|
||||
int readAllCS(HXPAxis* pAxis);
|
||||
int setCS(HXPAxis* pAxis);
|
||||
void postError(HXPAxis* pAxis, int status);
|
||||
|
||||
protected:
|
||||
#define FIRST_HXP_PARAM HXPMoveCoordSys_
|
||||
int HXPMoveCoordSys_;
|
||||
int HXPStatus_;
|
||||
int HXPError_;
|
||||
int HXPErrorDesc_;
|
||||
int HXPMoveAll_;
|
||||
int HXPMoveAllTargetX_;
|
||||
int HXPMoveAllTargetY_;
|
||||
int HXPMoveAllTargetZ_;
|
||||
int HXPMoveAllTargetU_;
|
||||
int HXPMoveAllTargetV_;
|
||||
int HXPMoveAllTargetW_;
|
||||
int HXPCoordSysReadAll_;
|
||||
int HXPCoordSysToolX_;
|
||||
int HXPCoordSysToolY_;
|
||||
int HXPCoordSysToolZ_;
|
||||
int HXPCoordSysToolU_;
|
||||
int HXPCoordSysToolV_;
|
||||
int HXPCoordSysToolW_;
|
||||
int HXPCoordSysWorkX_;
|
||||
int HXPCoordSysWorkY_;
|
||||
int HXPCoordSysWorkZ_;
|
||||
int HXPCoordSysWorkU_;
|
||||
int HXPCoordSysWorkV_;
|
||||
int HXPCoordSysWorkW_;
|
||||
int HXPCoordSysBaseX_;
|
||||
int HXPCoordSysBaseY_;
|
||||
int HXPCoordSysBaseZ_;
|
||||
int HXPCoordSysBaseU_;
|
||||
int HXPCoordSysBaseV_;
|
||||
int HXPCoordSysBaseW_;
|
||||
int HXPCoordSysSet_;
|
||||
int HXPCoordSysToSet_;
|
||||
int HXPCoordSysSetX_;
|
||||
int HXPCoordSysSetY_;
|
||||
int HXPCoordSysSetZ_;
|
||||
int HXPCoordSysSetU_;
|
||||
int HXPCoordSysSetV_;
|
||||
int HXPCoordSysSetW_;
|
||||
#define LAST_HXP_PARAM HXPCoordSysSetW_
|
||||
|
||||
#define NUM_HXP_PARAMS ((int) (&LAST_HXP_PARAM - &FIRST_HXP_PARAM + 1))
|
||||
|
||||
private:
|
||||
char *IPAddress_;
|
||||
int IPPort_;
|
||||
int pollSocket_;
|
||||
// only needed for profile moves
|
||||
//int moveSocket_;
|
||||
char firmwareVersion_[100];
|
||||
char *axisNames_;
|
||||
int groupStatus_;
|
||||
double encoderPosition_[MAX_HXP_AXES];
|
||||
double setpointPosition_[MAX_HXP_AXES];
|
||||
bool moving_;
|
||||
|
||||
friend class HXPAxis;
|
||||
};
|
||||
@@ -1,679 +0,0 @@
|
||||
program MM4005_trajectoryScan("P=13IDC:,R=traj1,M1=M1,M2=M2,M3=M3,M4=M4,M5=M5,M6=M6,M7=M7,M8=M8,PORT=serial1")
|
||||
|
||||
/* This sequencer program works with trajectoryScan.db. It implements
|
||||
* coordinated trajectory motion with the Newport MM4005 motor controller.
|
||||
* It can be used with the Newport General Purpose Diffractometer or with any
|
||||
* other set of motors connected to that controller.
|
||||
*
|
||||
* Mark Rivers
|
||||
* August 12, 2000
|
||||
*/
|
||||
|
||||
%% #include <stdlib.h> /* for atof() */
|
||||
%% #include <string.h>
|
||||
%% #include <stdio.h>
|
||||
%% #include <epicsString.h>
|
||||
%% #include <asynOctetSyncIO.h>
|
||||
|
||||
#include <seq_release.h> /* definition of MAGIC */
|
||||
#define VERSION_INT(MAJ,MIN) ((MAJ)*1000000+(MIN)*1000)
|
||||
#define LT_SEQ_VERSION(MAJ,MIN) ((MAGIC) < VERSION_INT(MAJ,MIN))
|
||||
|
||||
/* This program must be compiled with the recursive option */
|
||||
option +r;
|
||||
|
||||
/* Maximum # of trajectory elements. The MM4005 allows 2000, and this is also
|
||||
* the channel access limit with a double data type. However this uses
|
||||
* a lot of memory, the variable motorTrajectory uses MAX_AXES*MAX_ELEMENTS*8
|
||||
* bytes in this SNL program (up to 128KB). Similar memory will be required
|
||||
* for the records in the database. Restrict to 1000 for now.
|
||||
*/
|
||||
#define MAX_ELEMENTS 2000
|
||||
|
||||
/* Maximum # of output pulses. The MM4005 allows 2000, and this is also
|
||||
* the channel access limit with a double data type. However this uses
|
||||
* a lot of memory, the variables motorActual and motorError each use
|
||||
* MAX_AXES*MAX_PULSES*8 bytes (up to 256KB total). Similar memory will be
|
||||
* required for the records in the database. Restrict to 1000 for now.
|
||||
*/
|
||||
#define MAX_PULSES 2000
|
||||
|
||||
/* Note that MAX_AXES, MAX_ELEMENTS, and MAX_PULSES must be defined before
|
||||
* including the trajectoryScan.h */
|
||||
#include "trajectoryScan.h"
|
||||
|
||||
/* Maximum size of string to/from MM4005, typically for TQ command. */
|
||||
#define MAX_MM4000_STRING 256
|
||||
|
||||
/* Buffer sizes */
|
||||
#define NAME_LEN 100
|
||||
|
||||
/* Maximum size of string in EPICS string PVs. This is defined in
|
||||
* epicsTypes.h, but in order to include that file it must be escaped, and then
|
||||
* SNL compiler gives a warning. */
|
||||
#define MAX_STRING_SIZE 40
|
||||
|
||||
/* Time for each "padding" trajectory element added to trajectory because it
|
||||
* is not a multiple of 4 elements */
|
||||
#define PAD_TIME 0.1
|
||||
|
||||
/* Polling interval for waiting for motors to reach their targets */
|
||||
#define POLL_INTERVAL 0.1
|
||||
|
||||
|
||||
char stringOut[MAX_MM4000_STRING];
|
||||
char stringIn[MAX_MM4000_STRING];
|
||||
char *asynPort;
|
||||
char *pasynUser; /* This is really asynUser* */
|
||||
int status;
|
||||
int i;
|
||||
int j;
|
||||
int k;
|
||||
double delay;
|
||||
int anyMoving;
|
||||
int ncomplete;
|
||||
int nextra;
|
||||
int npoints;
|
||||
int dir;
|
||||
double dtime;
|
||||
double dpos;
|
||||
double posActual;
|
||||
double posTheory;
|
||||
double expectedTime;
|
||||
double initialPos[MAX_AXES];
|
||||
char macroBuf[NAME_LEN];
|
||||
char motorName[NAME_LEN];
|
||||
char *p;
|
||||
char *tok_save;
|
||||
|
||||
/* All PVs which will be accessed in local C functions need to have their index
|
||||
* extracted with pvIndex() */
|
||||
int motorCurrentIndex[MAX_AXES];
|
||||
int epicsMotorDoneIndex[MAX_AXES];
|
||||
|
||||
/* Note, this should be time_t, but SNL doesn't understand that. This is
|
||||
* the defininition in vxWorks. */
|
||||
unsigned long startTime;
|
||||
|
||||
/* Define escaped C functions at end of file */
|
||||
%% static int writeOnly(SS_ID ssId, struct UserVar *pVar, char *command);
|
||||
%% static int writeRead(SS_ID ssId, struct UserVar *pVar, char *command);
|
||||
%% static int getMotorPositions(SS_ID ssId, struct UserVar *pVar, double *pos);
|
||||
%% static int getMotorMoving(SS_ID ssId, struct UserVar *pVar);
|
||||
%% static int getEpicsMotorMoving(SS_ID ssId, struct UserVar *pVar);
|
||||
%% static int waitEpicsMotors(SS_ID ssId, struct UserVar *pVar);
|
||||
|
||||
|
||||
ss trajectoryScan {
|
||||
|
||||
/* Initialize things when first starting */
|
||||
state init {
|
||||
when() {
|
||||
/* Force numAxes to be <= MAX_AXES */
|
||||
if (numAxes > MAX_AXES) numAxes = MAX_AXES;
|
||||
for (i=0; i<numAxes; i++) {
|
||||
sprintf(macroBuf, "M%d", i+1);
|
||||
sprintf(motorName, "%s%s.VAL", macValueGet("P"), macValueGet(macroBuf));
|
||||
pvAssign(epicsMotorPos[i], motorName);
|
||||
sprintf(motorName, "%s%s.DIR", macValueGet("P"), macValueGet(macroBuf));
|
||||
pvAssign(epicsMotorDir[i], motorName);
|
||||
sprintf(motorName, "%s%s.OFF", macValueGet("P"), macValueGet(macroBuf));
|
||||
pvAssign(epicsMotorOff[i], motorName);
|
||||
sprintf(motorName, "%s%s.DMOV", macValueGet("P"), macValueGet(macroBuf));
|
||||
pvAssign(epicsMotorDone[i], motorName);
|
||||
}
|
||||
|
||||
asynPort = macValueGet("PORT");
|
||||
%%pVar->status = pasynOctetSyncIO->connect(pVar->asynPort, 0,
|
||||
%% (asynUser **)&pVar->pasynUser,
|
||||
%% NULL);
|
||||
if (status != 0) {
|
||||
printf("trajectoryScan error in pasynOctetSyncIO->connect\n");
|
||||
printf(" status=%d, port=%s\n", status, asynPort);
|
||||
}
|
||||
for (j=0; j<numAxes; j++) {
|
||||
motorCurrentIndex[j] = pvIndex(motorCurrent[j]);
|
||||
epicsMotorDoneIndex[j] = pvIndex(epicsMotorDone[j]);
|
||||
}
|
||||
/* Read the maximum allowable speed error between blocks */
|
||||
for (j=0; j<numAxes; j++) {
|
||||
sprintf(stringOut, "%dGC?", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
/* Parse the return string which is of the form 1GCxxx */
|
||||
motorMDVS[j] = atof(stringIn+3);
|
||||
pvPut(motorMDVS[j]);
|
||||
}
|
||||
/* Clear all event flags */
|
||||
efClear(buildMon);
|
||||
efClear(executeMon);
|
||||
efClear(abortMon);
|
||||
efClear(readbackMon);
|
||||
efClear(nelementsMon);
|
||||
efClear(motorMDVSMon);
|
||||
} state monitor_inputs
|
||||
}
|
||||
|
||||
|
||||
/* Monitor inputs which control what to do (Build, Execute, Read) */
|
||||
state monitor_inputs {
|
||||
when(efTestAndClear(buildMon) && (build==1)) {
|
||||
} state build
|
||||
|
||||
when(efTestAndClear(executeMon) && (execute==1)) {
|
||||
} state execute
|
||||
|
||||
when(efTestAndClear(readbackMon) && (readback==1)) {
|
||||
} state readback
|
||||
|
||||
when(efTestAndClear(nelementsMon) && (nelements>=1)) {
|
||||
/* If nelements changes, then change endPulses to this value,
|
||||
* since this is what the user normally wants. endPulses can be
|
||||
* changed again after changing nelements if this is desired. */
|
||||
endPulses = nelements;
|
||||
pvPut(endPulses);
|
||||
} state monitor_inputs
|
||||
|
||||
when(efTestAndClear(motorMDVSMon)) {
|
||||
/* One of the motorMDVS values has changed. The event flag is on
|
||||
* the array, so we can't tell which one. No harm in writing all
|
||||
* the values to the MM4005. */
|
||||
for (j=0; j<numAxes; j++) {
|
||||
sprintf(stringOut, "%dGC%f", j+1, motorMDVS[j]);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
}
|
||||
} state monitor_inputs
|
||||
}
|
||||
|
||||
|
||||
/* Build and verify trajectory */
|
||||
state build {
|
||||
when() {
|
||||
/* Set busy flag while building */
|
||||
buildState = BUILD_STATE_BUSY;
|
||||
pvPut(buildState);
|
||||
buildStatus=STATUS_UNDEFINED;
|
||||
pvPut(buildStatus);
|
||||
/* Initialize new trajectory */
|
||||
strcpy(stringOut, "NC");
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
/* Define which motors are to be moved */
|
||||
for (i=0; i<numAxes; i++) {
|
||||
sprintf(stringOut, "%dDC%d", i+1, moveAxis[i]);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
}
|
||||
/* Set acceleration time */
|
||||
sprintf(stringOut, "UC%f", accel);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
/* If time mode is TIME_MODE_TOTAL then construct timeTrajectory
|
||||
* and post it */
|
||||
if (timeMode == TIME_MODE_TOTAL) {
|
||||
dtime = time_PV/nelements;
|
||||
for (i=0; i<nelements; i++) timeTrajectory[i] = dtime;
|
||||
pvPut(timeTrajectory);
|
||||
}
|
||||
|
||||
/* Make sure number of trajectory elements is a multiple of 4.
|
||||
* If not, pad with up to 3 entries of PAD_TIME duration each.
|
||||
* Continue the trajectory at the same velocity.
|
||||
* Change nelements and post new value */
|
||||
if (moveMode == MOVE_MODE_RELATIVE) {
|
||||
npoints=nelements;
|
||||
} else {
|
||||
npoints=nelements-1;
|
||||
}
|
||||
nextra = (npoints % 4);
|
||||
if (nextra != 0) {
|
||||
nextra = 4-nextra;
|
||||
/* Compute the increment to move the motors during these
|
||||
* padding elements, keeping velocity constant */
|
||||
for (i=0; i<nextra; i++) {
|
||||
timeTrajectory[npoints+i] = PAD_TIME;
|
||||
for (j=0; j<numAxes; j++) {
|
||||
if (!moveAxis[j]) continue;
|
||||
if (moveMode == MOVE_MODE_RELATIVE) {
|
||||
motorTrajectory[j][nelements+i] =
|
||||
motorTrajectory[j][nelements-1] *
|
||||
PAD_TIME / timeTrajectory[nelements-1];
|
||||
} else {
|
||||
dpos = (motorTrajectory[j][nelements-1] -
|
||||
motorTrajectory[j][nelements-2]) *
|
||||
PAD_TIME / timeTrajectory[nelements-2];
|
||||
motorTrajectory[j][nelements+i] =
|
||||
motorTrajectory[j][nelements-1] +
|
||||
dpos*(i+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
nelements += nextra;
|
||||
npoints += nextra;
|
||||
pvPut(nelements);
|
||||
pvPut(timeTrajectory);
|
||||
/* Post the new trajectory position arrays */
|
||||
for (j=0; j<numAxes; j++) {
|
||||
pvPut(motorTrajectory[j]);
|
||||
}
|
||||
}
|
||||
/* Compute expected time for trajectory */
|
||||
expectedTime=0;
|
||||
for (i=0; i<npoints; i++)
|
||||
expectedTime += timeTrajectory[i];
|
||||
/* Define each element in trajectory */
|
||||
for (i=0; i<npoints; i++) {
|
||||
sprintf(buildMessage, "Building element %d/%d", i+1, nelements);
|
||||
pvPut(buildMessage);
|
||||
sprintf(stringOut, "%dDT%f", i+1, timeTrajectory[i]);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
for (j=0; j<numAxes; j++) {
|
||||
if (!moveAxis[j]) continue;
|
||||
if (moveMode == MOVE_MODE_RELATIVE) {
|
||||
dpos = motorTrajectory[j][i];
|
||||
} else {
|
||||
dpos = motorTrajectory[j][i+1] - motorTrajectory[j][i];
|
||||
}
|
||||
/* Convert from user units to MM4000 units */
|
||||
if (epicsMotorDir[j] == 0) dir=1; else dir=-1;
|
||||
dpos = dpos*dir;
|
||||
sprintf(stringOut, "%dDX%f", j+1, dpos);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
}
|
||||
/* The following command is intended to prevent buffer overflow in
|
||||
* the MM4005 by reading introducing a delay (reading status) when
|
||||
* downloading many-element trajectories */
|
||||
if (((i+1) % 20) == 0) %%writeRead(ssId, pVar, "TB");
|
||||
}
|
||||
/* Define pulse output for trajectory */
|
||||
if (npulses > 0) {
|
||||
/* Check validity, modify values if necessary */
|
||||
if (startPulses < 1) startPulses = 1;
|
||||
if (startPulses > npoints) startPulses = npoints;
|
||||
pvPut(startPulses);
|
||||
if (endPulses < startPulses) endPulses = startPulses;
|
||||
if (endPulses > npoints) endPulses = npoints;
|
||||
pvPut(endPulses);
|
||||
/* There seems to be a bug in the MM4005, it puts out one fewer
|
||||
* pulse than requested. Add one */
|
||||
sprintf(stringOut, "MB%d,ME%d,MN%d",
|
||||
startPulses, endPulses, npulses+1);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
}
|
||||
/* Verify trajectory */
|
||||
strcpy(buildMessage, "Verifying trajectory");
|
||||
pvPut(buildMessage);
|
||||
strcpy(stringOut, "VC");
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
/* Read error code back from MM4000 */
|
||||
%%writeRead(ssId, pVar, "TB");
|
||||
/* Set status and message string */
|
||||
if (stringIn[2] == '@') {
|
||||
buildStatus = STATUS_SUCCESS;
|
||||
strcpy(buildMessage, " ");
|
||||
} else {
|
||||
buildStatus = STATUS_FAILURE;
|
||||
strncpy(buildMessage, stringIn, MAX_STRING_SIZE-1);
|
||||
}
|
||||
/* Read dynamic parameters, post them */
|
||||
for (j=0; j<numAxes; j++) {
|
||||
p = stringIn;
|
||||
/* This query can only be done for axes which are active in the
|
||||
* trajectory */
|
||||
if (!moveAxis[j]) continue;
|
||||
/* We could query all parameters with one nRc, but the parsing
|
||||
* is a pain, much simpler to query one at a time */
|
||||
/* Maximum speed change element and value */
|
||||
sprintf(stringOut, "%dRC1", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
motorMDVE[j] = atoi(p+3);
|
||||
pvPut(motorMDVE[j]);
|
||||
sprintf(stringOut, "%dRC2", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
motorMDVA[j] = atof(p+3);
|
||||
pvPut(motorMDVA[j]);
|
||||
/* Maximum velocity element and value */
|
||||
sprintf(stringOut, "%dRC3", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
motorMVE[j] = atoi(p+3);
|
||||
pvPut(motorMVE[j]);
|
||||
sprintf(stringOut, "%dRC4", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
motorMVA[j] = atof(p+3);
|
||||
pvPut(motorMVA[j]);
|
||||
/* Maximum acceleration element and value */
|
||||
sprintf(stringOut, "%dRC5", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
motorMAE[j] = atoi(p+3);
|
||||
pvPut(motorMAE[j]);
|
||||
sprintf(stringOut, "%dRC6", j+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
motorMAA[j] = atof(p+3);
|
||||
pvPut(motorMAA[j]);
|
||||
}
|
||||
/* Clear busy flag, post status */
|
||||
buildState = BUILD_STATE_DONE;
|
||||
pvPut(buildState);
|
||||
pvPut(buildStatus);
|
||||
pvPut(buildMessage);
|
||||
/* Clear build command, post. This is a "busy" record, don't want
|
||||
* to do this until build is complete. */
|
||||
build=0;
|
||||
pvPut(build);
|
||||
} state monitor_inputs
|
||||
}
|
||||
|
||||
|
||||
state execute {
|
||||
when () {
|
||||
/* Set busy flag */
|
||||
execState = EXECUTE_STATE_MOVE_START;
|
||||
pvPut(execState);
|
||||
/* Set status to INVALID */
|
||||
execStatus = STATUS_UNDEFINED;
|
||||
pvPut(execStatus);
|
||||
/* Get the initial positions of the motors */
|
||||
for (j=0; j<numAxes; j++) initialPos[j] = epicsMotorPos[j];
|
||||
/* Move to start position if required */
|
||||
if (moveMode == MOVE_MODE_ABSOLUTE) {
|
||||
for (j=0; j<numAxes; j++) {
|
||||
if (!moveAxis[j]) continue;
|
||||
epicsMotorPos[j] = motorTrajectory[j][0];
|
||||
pvPut(epicsMotorPos[j]);
|
||||
}
|
||||
%%waitEpicsMotors(ssId, pVar);
|
||||
}
|
||||
/* Send the execute command, along with simulation mode and time
|
||||
* scaling factor */
|
||||
sprintf(stringOut, "LS,%dEC%f",simMode,timeScale);
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
/* Get start time of execute */
|
||||
startTime = time(0);
|
||||
execState = EXECUTE_STATE_EXECUTING;
|
||||
pvPut(execState);
|
||||
/* This is an attempt to fix the problem of TP sometimes not responding */
|
||||
epicsThreadSleep(0.1);
|
||||
} state wait_execute
|
||||
}
|
||||
|
||||
|
||||
/* Wait for trajectory to complete */
|
||||
state wait_execute {
|
||||
when (execStatus == STATUS_ABORT) {
|
||||
/* The trajectory_abort state set has detected an abort. It has
|
||||
* already posted the status and message. Don't execute flyback
|
||||
* return to top */
|
||||
execState = EXECUTE_STATE_DONE;
|
||||
pvPut(execState);
|
||||
/* Clear execute command, post. This is a "busy" record, don't
|
||||
* want to do this until execution is complete. */
|
||||
execute=0;
|
||||
pvPut(execute);
|
||||
} state monitor_inputs
|
||||
|
||||
when(execState==EXECUTE_STATE_EXECUTING) {
|
||||
/* Get the current motor positions, post them */
|
||||
%%getMotorPositions(ssId, pVar, pVar->motorCurrent);
|
||||
for (j=0; j<numAxes; j++) pvPut(motorCurrent[j]);
|
||||
/* Send XC1 command, read last trajectory element done */
|
||||
%%writeRead(ssId, pVar, "XC1");
|
||||
/* Parse response, which is of the form XCnnnn */
|
||||
ncomplete = atoi(&stringIn[2]);
|
||||
sprintf(execMessage, "Executing element %d/%d",
|
||||
ncomplete, nelements);
|
||||
pvPut(execMessage);
|
||||
%%pVar->anyMoving = getMotorMoving(ssId, pVar);
|
||||
if (!anyMoving) {
|
||||
execState = EXECUTE_STATE_FLYBACK;
|
||||
execStatus = STATUS_SUCCESS;
|
||||
strcpy(execMessage, " ");
|
||||
}
|
||||
/* See if the elapsed time is more than twice expected, time out */
|
||||
if (difftime(time(0), startTime) > expectedTime*timeScale*2.) {
|
||||
execState = EXECUTE_STATE_FLYBACK;
|
||||
execStatus = STATUS_TIMEOUT;
|
||||
strcpy(execMessage, "Timeout");
|
||||
}
|
||||
/* Send TB command, read any error messages */
|
||||
%%writeRead(ssId, pVar, "TB");
|
||||
/* Parse the return string, of form "TBx message". If 'x' is '@'
|
||||
then there is no error, else stop with error code */
|
||||
if (stringIn[2] != '@') {
|
||||
execState = EXECUTE_STATE_FLYBACK;
|
||||
execStatus = STATUS_FAILURE;
|
||||
strncpy(execMessage, stringIn, MAX_STRING_SIZE-1);
|
||||
}
|
||||
} state wait_execute
|
||||
|
||||
when(execState==EXECUTE_STATE_FLYBACK) {
|
||||
pvPut(execState);
|
||||
pvPut(execStatus);
|
||||
pvPut(execMessage);
|
||||
/* Get the current motor positions, post them */
|
||||
%%getMotorPositions(ssId, pVar, pVar->motorCurrent);
|
||||
for (j=0; j<numAxes; j++) pvPut(motorCurrent[j]);
|
||||
for (j=0; j<numAxes; j++) {
|
||||
if (!moveAxis[j]) continue;
|
||||
epicsMotorPos[j] = motorCurrent[j];
|
||||
pvPut(epicsMotorPos[j]);
|
||||
}
|
||||
%%waitEpicsMotors(ssId, pVar);
|
||||
execState = EXECUTE_STATE_DONE;
|
||||
pvPut(execState);
|
||||
/* Clear execute command, post. This is a "busy" record, don't
|
||||
* want to do this until execution is complete. */
|
||||
execute=0;
|
||||
pvPut(execute);
|
||||
} state monitor_inputs
|
||||
}
|
||||
|
||||
|
||||
/* Read back actual positions */
|
||||
state readback {
|
||||
when() {
|
||||
/* Set busy flag */
|
||||
readState = READ_STATE_BUSY;
|
||||
pvPut(readState);
|
||||
readStatus=STATUS_UNDEFINED;
|
||||
pvPut(readStatus);
|
||||
/* Erase the readback and error arrays */
|
||||
for (j=0; j<numAxes; j++) {
|
||||
for (i=0; i<MAX_PULSES; i++) {
|
||||
motorReadbacks[j][i] = 0.;
|
||||
motorError[j][i] = 0.;
|
||||
}
|
||||
}
|
||||
/* Read the actual number of trace points */
|
||||
%%writeRead(ssId, pVar, "NQ");
|
||||
/* Parse response, which is of the form NQnnnn */
|
||||
nactual = atoi(&stringIn[2]);
|
||||
pvPut(nactual);
|
||||
/* Read actual positions */
|
||||
for (i=0; i<nactual; i++) {
|
||||
sprintf(readMessage, "Reading point %d/%d", i+1, nactual);
|
||||
pvPut(readMessage);
|
||||
sprintf(stringOut, "%dTQ", i+1);
|
||||
%%writeRead(ssId, pVar, pVar->stringOut);
|
||||
/* Parse the return string which is of the form
|
||||
* 15TQ,1TH2.7,1TP2.65,2TH3.1,2TP3.1 ... */
|
||||
tok_save = 0;
|
||||
/* Skip the first token, which is nnTQ */
|
||||
p = epicsStrtok_r(stringIn, ",", &tok_save);
|
||||
for (j=0; (j<numAxes && p!=0); j++) {
|
||||
p = epicsStrtok_r(0, ",", &tok_save);
|
||||
posTheory = atof(p+3);
|
||||
p = epicsStrtok_r(0, ",", &tok_save);
|
||||
if (epicsMotorDir[j] == 0) dir=1; else dir=-1;
|
||||
posActual = atof(p+3);
|
||||
motorError[j][i] = posActual-posTheory;
|
||||
/* Convert from MM4000 units to user units */
|
||||
posActual = posActual*dir + epicsMotorOff[j];
|
||||
motorReadbacks[j][i] = posActual;
|
||||
}
|
||||
}
|
||||
/* Post the readback and error arrays */
|
||||
for (j=0; j<numAxes; j++) {
|
||||
pvPut(motorReadbacks[j]);
|
||||
pvPut(motorError[j]);
|
||||
}
|
||||
/* Clear busy flag */
|
||||
readState = READ_STATE_DONE;
|
||||
pvPut(readState);
|
||||
/* For now we are not handling read errors */
|
||||
readStatus = STATUS_SUCCESS;
|
||||
pvPut(readStatus);
|
||||
strcpy(readMessage, " ");
|
||||
pvPut(readMessage);
|
||||
/* Clear readback command, post. This is a "busy" record, don't
|
||||
* want to do this until readback is complete. */
|
||||
readback=0;
|
||||
pvPut(readback);
|
||||
} state monitor_inputs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This state set simply monitors the abort input. It is a separate state set
|
||||
* so that it is always active, no matter what the state of the trajectoryScan
|
||||
* state set. If an abort is received it sends the "AB" command to the MM4005,
|
||||
* sets the execStatus to STATUS_ABORT and writes a message to execMessage */
|
||||
ss trajectoryAbort {
|
||||
state monitorAbort {
|
||||
when (efTestAndClear(abortMon) && (abort==1)) {
|
||||
/* Send AB command */
|
||||
strcpy(stringOut,"AB");
|
||||
%%writeOnly(ssId, pVar, pVar->stringOut);
|
||||
execStatus = STATUS_ABORT;
|
||||
pvPut(execStatus);
|
||||
strcpy(execMessage, "Motion aborted");
|
||||
pvPut(execMessage);
|
||||
/* Clear abort command, post. This is a "busy" record, don't
|
||||
* want to do this until abort command has been sent. */
|
||||
abort=0;
|
||||
pvPut(abort);
|
||||
} state monitorAbort
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* C functions */
|
||||
%{
|
||||
|
||||
/* writeOnly sends a command to the MM4005 */
|
||||
static int writeOnly(SS_ID ssId, struct UserVar *pVar, char *command)
|
||||
{
|
||||
asynStatus status;
|
||||
size_t nwrite;
|
||||
char buffer[MAX_MM4000_STRING];
|
||||
|
||||
/* Copy command so we can add terminator */
|
||||
strncpy(buffer, command, MAX_MM4000_STRING-3);
|
||||
strcat(buffer, "\r");
|
||||
status = pasynOctetSyncIO->write((asynUser *)pVar->pasynUser, buffer,
|
||||
strlen(buffer), 1.0, &nwrite);
|
||||
return(status);
|
||||
}
|
||||
|
||||
/* writeRead sends a command to the MM4005 and reads the response
|
||||
* It also writes the response string to another PV so it can be displayed. */
|
||||
static int writeRead(SS_ID ssId, struct UserVar *pVar, char *command)
|
||||
{
|
||||
asynStatus status;
|
||||
size_t nwrite, nread;
|
||||
int eomReason;
|
||||
char buffer[MAX_MM4000_STRING];
|
||||
|
||||
/* Copy command so we can add terminator */
|
||||
strncpy(buffer, command, MAX_MM4000_STRING-3);
|
||||
strcat(buffer, "\r");
|
||||
/* Use 30 second timeout, some commands take a long time to reply */
|
||||
status = pasynOctetSyncIO->writeRead((asynUser *)pVar->pasynUser, buffer,
|
||||
strlen(buffer), pVar->stringIn, MAX_MM4000_STRING,
|
||||
30.0, &nwrite, &nread, &eomReason);
|
||||
return(status);
|
||||
}
|
||||
|
||||
|
||||
/* getMotorPositions returns the positions of each motor */
|
||||
static int getMotorPositions(SS_ID ssId, struct UserVar *pVar, double *pos)
|
||||
{
|
||||
char *p, *tok_save;
|
||||
int j;
|
||||
int dir;
|
||||
|
||||
/* Read the current positions of all the axes */
|
||||
writeRead(ssId, pVar, "TP");
|
||||
/* Parse the return string which is of the form
|
||||
* 1TP2.65,2TP3.1 ... */
|
||||
tok_save = 0;
|
||||
p = epicsStrtok_r(pVar->stringIn, ",", &tok_save);
|
||||
for (j=0; (j<pVar->numAxes && p!=0); j++) {
|
||||
if (pVar->epicsMotorDir[j] == 0) dir=1; else dir=-1;
|
||||
pos[j] = atof(p+3)*dir + pVar->epicsMotorOff[j];
|
||||
p = epicsStrtok_r(0, ",", &tok_save);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* getMotorMoving returns the moving status of each motor, packed into a single
|
||||
* int. Bit 0 = motor 1, bit 1 = motor 2, etc. 0=not moving, 1=moving.
|
||||
* If the entire int is 0 then no motors are moving */
|
||||
static int getMotorMoving(SS_ID ssId, struct UserVar *pVar)
|
||||
{
|
||||
char *p, *tok_save;
|
||||
int j;
|
||||
int result=0, mask=0x01;
|
||||
|
||||
/* Read the current status of all the axes */
|
||||
writeRead(ssId, pVar, "MS");
|
||||
/* Parse the return string which is of the form
|
||||
* 1MSA,2MS@ ... */
|
||||
tok_save = 0;
|
||||
p = epicsStrtok_r(pVar->stringIn, ",", &tok_save);
|
||||
for (j=0; (j<pVar->numAxes && p!=0); j++) {
|
||||
/* The low order bit in the status byte is the MOVING bit */
|
||||
if (*(p+3) & 0x01) result |= mask;
|
||||
mask = mask << 1;
|
||||
p = epicsStrtok_r(0, ",", &tok_save);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/* getEpicsMotorMoving returns the EPICS moving status of each motor, packed into
|
||||
* a single int. Bit 0 = motor 1, bit 1 = motor 2, etc. 0=not moving, 1=moving.
|
||||
* If the entire int is 0 then no motors are moving */
|
||||
static int getEpicsMotorMoving(SS_ID ssId, struct UserVar *pVar)
|
||||
{
|
||||
int j;
|
||||
int result=0, mask=0x01;
|
||||
|
||||
for (j=0; j<pVar->numAxes; j++) {
|
||||
seq_pvGet(ssId, pVar->epicsMotorDoneIndex[j], 0);
|
||||
if (pVar->epicsMotorDone[j] == 0) result |= mask;
|
||||
mask = mask << 1;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/* waitEpicsMotors waits for all motors to stop moving using the EPICS motor
|
||||
* records.. It reads and posts the motor positions during each loop. */
|
||||
static int waitEpicsMotors(SS_ID ssId, struct UserVar *pVar)
|
||||
{
|
||||
int j;
|
||||
|
||||
/* Logic is that we always want to post position motor positions
|
||||
* after the end of move is detected. */
|
||||
while(getEpicsMotorMoving(ssId, pVar)) {
|
||||
/* Get the current motor positions, post them */
|
||||
for (j=0; j<pVar->numAxes; j++) {
|
||||
pVar->motorCurrent[j] = pVar->epicsMotorPos[j];
|
||||
seq_pvPut(ssId, pVar->motorCurrentIndex[j], 0);
|
||||
}
|
||||
epicsThreadSleep(POLL_INTERVAL);
|
||||
}
|
||||
for (j=0; j<pVar->numAxes; j++) {
|
||||
pVar->motorCurrent[j] = pVar->epicsMotorPos[j];
|
||||
seq_pvPut(ssId, pVar->motorCurrentIndex[j], 0);
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
}%
|
||||
@@ -1,99 +0,0 @@
|
||||
# Makefile
|
||||
TOP = ../..
|
||||
include $(TOP)/configure/CONFIG
|
||||
#
|
||||
# Both the following line, and a line in the *.dbd file,
|
||||
# must be uncommented to use diagnostic debugging messages.
|
||||
#!USR_CXXFLAGS += -DDEBUG
|
||||
|
||||
# The Newport XPS_C8_driver.cpp file uses "char *" when they should use "const char *".
|
||||
# Turn off warnings when we call this functions with string constants
|
||||
USR_CPPFLAGS_Linux += -Wno-write-strings
|
||||
|
||||
# Install the XPS header file in case applications in another module need to use it
|
||||
INC += XPS_C8_drivers.h
|
||||
|
||||
DBD += devNewport.dbd
|
||||
ifdef SNCSEQ
|
||||
DBD += devNewportSeq.dbd
|
||||
endif
|
||||
|
||||
LIBRARY_IOC = Newport
|
||||
|
||||
Newport_SRCS += NewportRegister.cc
|
||||
|
||||
# MM3000 (i.e., MM3000) device driver.
|
||||
Newport_SRCS += devMM3000.cc drvMM3000.cc
|
||||
|
||||
# MM4000/5 (i.e., MM4000) device driver.
|
||||
Newport_SRCS += devMM4000.cc drvMM4000.cc
|
||||
Newport_SRCS += drvMM4000Asyn.c
|
||||
ifdef SNCSEQ
|
||||
Newport_SRCS += MM4005_trajectoryScan.st
|
||||
endif
|
||||
|
||||
# PM500 device driver.
|
||||
Newport_SRCS += devPM500.cc drvPM500.cc
|
||||
|
||||
# ESP300 device driver.
|
||||
Newport_SRCS += devESP300.cc drvESP300.cc
|
||||
|
||||
# SMC100 device driver
|
||||
Newport_SRCS += SMC100Driver.cpp
|
||||
|
||||
# Agilis device drivers
|
||||
Newport_SRCS += AG_UC.cpp
|
||||
Newport_SRCS += AG_CONEX.cpp
|
||||
|
||||
# XPS C8 device driver
|
||||
Newport_SRCS += asynOctetSocket.cpp
|
||||
Newport_SRCS += XPS_C8_drivers.cpp
|
||||
Newport_SRCS += drvXPSAsynAux.c
|
||||
Newport_SRCS += xps_ftp.c
|
||||
# This is the model 2 asyn driver
|
||||
Newport_SRCS += drvXPSAsyn.c XPSAsynInterpose.c
|
||||
# This is the model 3 asyn driver
|
||||
Newport_SRCS += XPSController.cpp
|
||||
Newport_SRCS += XPSAxis.cpp
|
||||
ifdef SNCSEQ
|
||||
Newport_SRCS += XPS_trajectoryScan.st
|
||||
Newport_SRCS += xpsSlave.st
|
||||
endif
|
||||
#
|
||||
Newport_SRCS += hxp_drivers.cpp
|
||||
Newport_SRCS += HXPDriver.cpp
|
||||
|
||||
# strtok_r needed on WIN32
|
||||
Newport_SRCS_WIN32 += strtok_r.c
|
||||
|
||||
# XPS Gathering test function
|
||||
Newport_SRCS += XPSGathering.c
|
||||
Newport_SRCS += XPSGatheringRegister.c
|
||||
|
||||
# Function which will run a tcl script on an XPS
|
||||
Newport_SRCS += tclCall.cc
|
||||
|
||||
Newport_LIBS += motor asyn
|
||||
ifdef SNCSEQ
|
||||
Newport_LIBS += seq pv
|
||||
endif
|
||||
Newport_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
Newport_SYS_LIBS_WIN32 += ws2_32
|
||||
|
||||
PROD_IOC += XPSGatheringMain
|
||||
XPSGatheringMain_SRCS += XPSGatheringMain.c
|
||||
XPSGatheringMain_LIBS += Newport motor asyn
|
||||
ifdef SNCSEQ
|
||||
XPSGatheringMain_LIBS += seq pv
|
||||
endif
|
||||
XPSGatheringMain_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
XPSGatheringMain_SYS_LIBS_solaris += socket nsl
|
||||
|
||||
PROD_IOC += XPSGathering2
|
||||
XPSGathering2_SRCS += XPSGathering2.c
|
||||
XPSGathering2_LIBS += Newport motor asyn
|
||||
XPSGathering2_LIBS += $(EPICS_BASE_IOC_LIBS)
|
||||
XPSGathering2_SYS_LIBS_solaris += socket nsl
|
||||
|
||||
include $(TOP)/configure/RULES
|
||||
|
||||
@@ -1,137 +0,0 @@
|
||||
/*
|
||||
FILENAME... NewportRegister.cc
|
||||
USAGE... Register Newport motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <iocsh.h>
|
||||
#include "NewportRegister.h"
|
||||
#include "tclCall.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// Newport Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// Newport Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg configArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
// Newport Asyn Setup arguments
|
||||
static const iocshArg asynSetupArg0 = {"Max. controller count", iocshArgInt};
|
||||
// Newport Asyn Config arguments
|
||||
static const iocshArg asynConfigArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg asynConfigArg1 = {"asyn port name", iocshArgString};
|
||||
static const iocshArg asynConfigArg2 = {"asyn address (GPIB)", iocshArgInt};
|
||||
static const iocshArg asynConfigArg3 = {"Number of Axes", iocshArgInt};
|
||||
static const iocshArg asynConfigArg4 = {"Moving poll rate", iocshArgInt};
|
||||
static const iocshArg asynConfigArg5 = {"Idle poll rate", iocshArgInt};
|
||||
|
||||
static const iocshArg * const NewportSetupArgs[2] = {&setupArg0,
|
||||
&setupArg1};
|
||||
static const iocshArg * const NewportAsynSetupArgs[2] = {&asynSetupArg0};
|
||||
static const iocshArg * const NewportConfigArgs[3] = {&configArg0,
|
||||
&configArg1,
|
||||
&configArg2};
|
||||
static const iocshArg * const NewportAsynConfigArgs[6] = {&asynConfigArg0,
|
||||
&asynConfigArg1,
|
||||
&asynConfigArg2,
|
||||
&asynConfigArg3,
|
||||
&asynConfigArg4,
|
||||
&asynConfigArg5};
|
||||
|
||||
static const iocshFuncDef setupMM3000 = {"MM300Setup", 2, NewportSetupArgs};
|
||||
static const iocshFuncDef setupMM4000 = {"MM4000Setup",2, NewportSetupArgs};
|
||||
static const iocshFuncDef setupMM4000Asyn = {"MM4000AsynSetup",1, NewportAsynSetupArgs};
|
||||
static const iocshFuncDef setupPM500 = {"PM500Setup", 2, NewportSetupArgs};
|
||||
static const iocshFuncDef setupESP300 = {"ESP300Setup",2, NewportSetupArgs};
|
||||
|
||||
static const iocshFuncDef configMM3000 = {"MM3000Config", 3, NewportConfigArgs};
|
||||
static const iocshFuncDef configMM4000 = {"MM4000Config", 3, NewportConfigArgs};
|
||||
static const iocshFuncDef configMM4000Asyn = {"MM4000AsynConfig", 6, NewportAsynConfigArgs};
|
||||
static const iocshFuncDef configPM500 = {"PM500Config", 3, NewportConfigArgs};
|
||||
static const iocshFuncDef configESP300 = {"ESP300Config", 3, NewportConfigArgs};
|
||||
|
||||
static void setupMM3000CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
MM3000Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
static void setupMM4000CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
MM4000Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
static void setupMM4000AsynCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
MM4000AsynSetup(args[0].ival);
|
||||
}
|
||||
|
||||
static void setupPM500CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PM500Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
static void setupESP300CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
ESP300Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
|
||||
static void configMM3000CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
MM3000Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
static void configMM4000CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
MM4000Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
static void configMM4000AsynCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
MM4000AsynConfig(args[0].ival, args[1].sval, args[2].ival,
|
||||
args[3].ival, args[4].ival, args[5].ival);
|
||||
}
|
||||
|
||||
static void configPM500CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
PM500Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
static void configESP300CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
ESP300Config(args[0].ival, args[1].sval, args[2].ival);
|
||||
}
|
||||
|
||||
|
||||
static void NewportRegister(void)
|
||||
{
|
||||
iocshRegister(&setupMM3000, setupMM3000CallFunc);
|
||||
iocshRegister(&setupMM4000, setupMM4000CallFunc);
|
||||
iocshRegister(&setupMM4000Asyn, setupMM4000AsynCallFunc);
|
||||
iocshRegister(&setupPM500, setupPM500CallFunc);
|
||||
iocshRegister(&setupESP300, setupESP300CallFunc);
|
||||
|
||||
iocshRegister(&configMM3000, configMM3000CallFunc);
|
||||
iocshRegister(&configMM4000, configMM4000CallFunc);
|
||||
iocshRegister(&configMM4000Asyn, configMM4000AsynCallFunc);
|
||||
iocshRegister(&configPM500, configPM500CallFunc);
|
||||
iocshRegister(&configESP300, configESP300CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(NewportRegister);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
FILENAME... NewportRegister.h
|
||||
USAGE... This file contains function prototypes for Newport IOC shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 05/19/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
*/
|
||||
|
||||
#include "motor.h"
|
||||
#include "motordrvCom.h"
|
||||
|
||||
#include "drvXPSAsyn.h"
|
||||
#include "drvMM4000Asyn.h"
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS MM3000Setup(int, int);
|
||||
extern RTN_STATUS MM4000Setup(int, int);
|
||||
extern RTN_STATUS PM500Setup(int, int);
|
||||
extern RTN_STATUS ESP300Setup(int, int);
|
||||
extern RTN_STATUS MM3000Config(int, const char *, int);
|
||||
extern RTN_STATUS MM4000Config(int, const char *, int);
|
||||
extern RTN_STATUS PM500Config(int, const char *, int);
|
||||
extern RTN_STATUS ESP300Config(int, const char *, int);
|
||||
@@ -1,237 +0,0 @@
|
||||
Newport ESP300
|
||||
==============
|
||||
|
||||
Serial communication using the GreensSpring XM Octal I/O.
|
||||
---------------------------------------------------------
|
||||
|
||||
The GreensSpring XM Octal I/O has a 16 pin jumper block for each serial port.
|
||||
Assume (the manual does not define this) that the jumper pins are numbered
|
||||
from, top to bottom, and from left to right; i.e.,
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
9 10 11 12
|
||||
13 14 15 16
|
||||
|
||||
Then the "Default jumbering ..." depicted in Fig. 2 of the GreensSpring XM
|
||||
Octal I/O manual is jumpered as follows; 1-5, 2-6, 9-13, 10-14.
|
||||
|
||||
The correct jumpering for the ESP300 is; 1-5, 2-6, 9-13, 10-11, 15-16.
|
||||
|
||||
|
||||
Setting the motor resolution (MRES) and Engineering Units fields to the
|
||||
SAME values as the controller's.
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
For DC motors, set MRES to the ESP300's response to the SU? command.
|
||||
|
||||
If there is no other mechanism (e.g., generic serial record, dumb terminal,
|
||||
etc.) to communicate to the ESP300, the response to the SU? command can be
|
||||
determined by following this procedure;
|
||||
|
||||
1 - uncomment the "USR_CFLAGS += -DDEBUG" line in the NewportSrc/Makefile.Vx
|
||||
file (This selects the diagnostic messages to be compiled).
|
||||
2 - "cd <motor>/motorApp/NewportSrc; gnumake clean; gnumake"; this re-compiles
|
||||
the device drivers with the diagnostic messages selected.
|
||||
3 - Rebuild your IOC; "cd <IOC>; gnumake".
|
||||
4 - Add "drvESP300debug = 4" to the IOC's st.cmd file before "iocInit".
|
||||
5 - Connect to the VxWorks shell and reboot the IOC.
|
||||
|
||||
The VxWorks shell output should contain lines like the following;
|
||||
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
Starting iocInit
|
||||
send_mess(): message = VE?
|
||||
recv_mess(): message = "ESP300 Version 3.08 09/09/02"
|
||||
send_mess(): message = ZU
|
||||
recv_mess(): message = "0H"
|
||||
send_mess(): message = 01ST
|
||||
send_mess(): message = 02ST
|
||||
send_mess(): message = 03ST
|
||||
send_mess(): message = 01SN?
|
||||
recv_mess(): message = "2"
|
||||
send_mess(): message = 01SU?
|
||||
recv_mess(): message = "0.00003539317"
|
||||
send_mess(): message = 01MD
|
||||
recv_mess(): message = "1"
|
||||
send_mess(): message = 01TP
|
||||
recv_mess(): message = "0.00000"
|
||||
send_mess(): message = 01PH
|
||||
recv_mess(): message = "18000606H, 6H"
|
||||
send_mess(): message = 01MO?
|
||||
recv_mess(): message = "0"
|
||||
send_mess(): message = 01TE?
|
||||
recv_mess(): message = "0"
|
||||
send_mess(): message = 02SN?
|
||||
recv_mess(): message = "2"
|
||||
send_mess(): message = 02SU?
|
||||
recv_mess(): message = "0.00009765625"
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
Note the response to the SU? and SN? commands and set MRES to that value.
|
||||
|
||||
All three supported controllers (ESP100/300/301) have the same response
|
||||
to the SN? command; 0 to 10 where
|
||||
0 = encoder count 6 = micro-inches
|
||||
1 = motor step 7 = degree
|
||||
2 = millimeter 8 = gradian
|
||||
3 = micrometer 9 = radian
|
||||
4 = inches 10 = milliradian
|
||||
5 = milli-inches 11 = microradian
|
||||
|
||||
5 - Set the motor record's EGU field to "mm" (based on SN-2) and the MRES field
|
||||
to 3.539317E-5 (based on SU = 0.00003539317).
|
||||
6 - Turn off diagnostic messages. Either set drvESP300debug = 0 in the st.cmd
|
||||
file (there is a very small amount of CPU overhead associated with leaving
|
||||
the diagnostic messages loaded), or go to step #1, and reverse the steps;
|
||||
comment out the "USR_CFLAGS += -DDEBUG" line in the NewportSrc/Makefile.Vx,
|
||||
etc., etc.,
|
||||
|
||||
Setting the motor record's Engineering Units field (EGU) to a value DIFFERENT
|
||||
from the controller's EGU.
|
||||
-------------------------------------------------------------------------------
|
||||
In the above example the controller returned SU = "0.00003539317" and SN = "2"
|
||||
for axis #1. If the user prefers the motor record EGU to be in inches rather
|
||||
than millimeters, then set EGU = "inch" and,
|
||||
MRES = (3.539317E-5 mm / 1 encoder tick) X (1 inch / 25.4 mm)
|
||||
= 1.39343189E-6 inch / 1 encoder tick
|
||||
|
||||
Newport ESP100
|
||||
==============
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
- Unlike the ESP300, the ESP100 must be told what type of motor it is connected
|
||||
to. This is done using the "Set Motor Type" command; QM. "QM" arguments are
|
||||
as follows:
|
||||
0 - motor type undefined (default).
|
||||
1 - DC servo motor.
|
||||
2 - stepper motor.
|
||||
3 - commutated stepper motor.
|
||||
4 - commutated brushless DC servo motor.
|
||||
After setting the motor type, the value must be saved to non-volatile memory
|
||||
using the "SM" command.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Setting and saving an ESP100 for use with a DC servo motor driven stage (e.g.,
|
||||
850G);
|
||||
|
||||
1QM 1<CR>
|
||||
SM<CR>
|
||||
|
||||
|
||||
Newport MM4000
|
||||
==============
|
||||
|
||||
The MM4000 controller has an approximately 50ms delay before it responds to a
|
||||
status query. Hence, it is impossible to get more that a 20 Hz update rate
|
||||
from the MM4000; 7 or 8 Hz is attainable. This 50ms delay exists with both
|
||||
RS232 and GPIB communication interfaces.
|
||||
|
||||
|
||||
Newport PM500
|
||||
=============
|
||||
|
||||
The PM500 has high and low speed loops. Since the EPICS PM500 device driver
|
||||
does not set any of the low speed parameters (i.e., LSIZE, LACCEL, LDECEL, LV),
|
||||
the low speed loop feature may interfere with EPICS setting the slew velocity.
|
||||
I recommend preventing the PM500 from ever using the low speed velocity loop by
|
||||
setting the Low Speed Loop Threshold (LSIZE) to the motor record's Retry
|
||||
Deadband field (RDBD).
|
||||
|
||||
The LSIZE can be set from the EPICS motor record by entering the PM500 command
|
||||
in the record's INIT field. LSIZE is in units of either um or arc-sec. For
|
||||
example, if your RDBD = 0.123 mm, then set the INIT field to "LSIZE 123.0".
|
||||
|
||||
|
||||
Newport SMC100
|
||||
==============
|
||||
The SMC100 controller has a fixed baud rate of 57,600. This means that it
|
||||
cannot be used with the IP-Octal232. If you want to use it from a vxWorks ioc,
|
||||
you will need to connect it via a Moxa or similar. I have tested this code on
|
||||
both Linux and Cygwin soft ioc's. The stage I tested it with is a GTS30V.
|
||||
Initially, the controller needs to be connected to the stage it will be running,
|
||||
and then configured with Newport's software. I used Newport's PC program called
|
||||
"SMC100 User Tool", which allows for the controller to set and keep all of the
|
||||
settings for the stage.
|
||||
|
||||
|
||||
********************************************************************************
|
||||
What's what in this directory
|
||||
-----------------------------
|
||||
|
||||
misc EPICS stuff
|
||||
----------------
|
||||
NewportRegister.cc
|
||||
NewportRegister.h
|
||||
|
||||
Model 2 asyn driver
|
||||
-------------------
|
||||
XPSAsynInterpose.c
|
||||
XPSAsynInterpose.h
|
||||
drvXPSAsyn.c
|
||||
drvXPSAsyn.h
|
||||
tclCall.cc
|
||||
tclCall.h
|
||||
|
||||
asyn-model-independent
|
||||
----------------------
|
||||
drvXPSAsynAux.c (non-motor aspects of XPS controller)
|
||||
|
||||
Model 3 asyn driver
|
||||
-------------------
|
||||
XPSAxis.cpp
|
||||
XPSAxis.h
|
||||
XPSController.cpp
|
||||
XPSController.h
|
||||
SMC100Driver.cpp
|
||||
SMC100Driver.h
|
||||
SMC100Register.cc
|
||||
SMC100Register.h
|
||||
|
||||
support code common to models 2 and 3
|
||||
-------------------------------------
|
||||
XPS_C8_drivers.cpp
|
||||
XPS_C8_drivers.h
|
||||
XPS_C8_errors.h
|
||||
strtok_r.c
|
||||
strtok_r.h
|
||||
Socket.cpp
|
||||
Socket.h
|
||||
asynOctetSocket.cpp
|
||||
|
||||
Model 1 device support
|
||||
----------------------
|
||||
devESP300.cc
|
||||
devMM3000.cc
|
||||
devMM4000.cc
|
||||
devPM500.cc
|
||||
|
||||
|
||||
Model 1 drivers
|
||||
---------------
|
||||
drvESP300.cc
|
||||
drvMM4000Asyn.c
|
||||
drvMM4000Asyn.h
|
||||
drvMM3000.cc
|
||||
drvMM4000.cc
|
||||
drvMMCom.h
|
||||
drvPM500.cc
|
||||
|
||||
other - Note the XPS Model 3 driver has built-in trajectory scanning. XPS_trajectoryScan.st is
|
||||
- for use with the Model 2 XPS driver.
|
||||
-----
|
||||
trajectoryScan.h
|
||||
xps_ftp.c
|
||||
xps_ftp.h
|
||||
XPS_trajectoryScan.st
|
||||
MM4005_trajectoryScan.st
|
||||
|
||||
test code
|
||||
---------
|
||||
XPSGathering.c
|
||||
XPSGathering2.c
|
||||
XPSGatheringMain.c
|
||||
XPSGatheringRegister.c
|
||||
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
FILENAME... SMC100Driver.cpp
|
||||
USAGE... Motor driver support for the Newport SMC100 controller.
|
||||
|
||||
Based on the ACS MCB-4B Model 3 device driver written by:
|
||||
Mark Rivers
|
||||
March 1, 2012
|
||||
|
||||
K. Goetze 2012-03-23 Initial version
|
||||
2013-06-07 Allow motor resolution to be set using "SMC100CreateController" at boot time
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <iocsh.h>
|
||||
#include <epicsThread.h>
|
||||
|
||||
#include <asynOctetSyncIO.h>
|
||||
|
||||
#include <asynMotorController.h>
|
||||
#include <asynMotorAxis.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include "SMC100Driver.h"
|
||||
|
||||
#define NINT(f) (int)((f)>0 ? (f)+0.5 : (f)-0.5)
|
||||
|
||||
/** Creates a new SMC100Controller object.
|
||||
* \param[in] portName The name of the asyn port that will be created for this driver
|
||||
* \param[in] SMC100PortName The name of the drvAsynSerialPort that was created previously to connect to the SMC100 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
|
||||
*/
|
||||
SMC100Controller::SMC100Controller(const char *portName, const char *SMC100PortName, int numAxes,
|
||||
double movingPollPeriod, double idlePollPeriod, double stepSize)
|
||||
: asynMotorController(portName, numAxes, NUM_SMC100_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;
|
||||
SMC100Axis *pAxis;
|
||||
static const char *functionName = "SMC100Controller::SMC100Controller";
|
||||
|
||||
/* Connect to SMC100 controller */
|
||||
status = pasynOctetSyncIO->connect(SMC100PortName, 0, &pasynUserController_, NULL);
|
||||
if (status) {
|
||||
asynPrint(this->pasynUserSelf, ASYN_TRACE_ERROR,
|
||||
"%s: cannot connect to SMC100 controller\n",
|
||||
functionName);
|
||||
}
|
||||
for (axis=0; axis<numAxes; axis++) {
|
||||
//for (axis=1; axis < (numAxes + 1); axis++) {
|
||||
pAxis = new SMC100Axis(this, axis, stepSize);
|
||||
}
|
||||
|
||||
startPoller(movingPollPeriod, idlePollPeriod, 2);
|
||||
}
|
||||
|
||||
|
||||
/** Creates a new SMC100Controller 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] SMC100PortName The name of the drvAsynIPPPort that was created previously to connect to the SMC100 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
|
||||
* \param[in] eguPerStep The stage resolution
|
||||
*/
|
||||
extern "C" int SMC100CreateController(const char *portName, const char *SMC100PortName, int numAxes,
|
||||
int movingPollPeriod, int idlePollPeriod, const char *eguPerStep)
|
||||
{
|
||||
double stepSize;
|
||||
|
||||
stepSize = strtod(eguPerStep, NULL);
|
||||
new SMC100Controller(portName, SMC100PortName, numAxes, movingPollPeriod/1000., idlePollPeriod/1000., stepSize);
|
||||
//printf("\n *** SMC100: stepSize=%f\n", stepSize);
|
||||
if (errno != 0) {
|
||||
printf("SMC100: Error invalid steps per unit=%s\n", eguPerStep);
|
||||
return asynError;
|
||||
}
|
||||
|
||||
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 SMC100Controller::report(FILE *fp, int level)
|
||||
{
|
||||
fprintf(fp, "SMC100 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 SMC100Axis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] pasynUser asynUser structure that encodes the axis index number. */
|
||||
SMC100Axis* SMC100Controller::getAxis(asynUser *pasynUser)
|
||||
{
|
||||
return static_cast<SMC100Axis*>(asynMotorController::getAxis(pasynUser));
|
||||
}
|
||||
|
||||
/** Returns a pointer to an SMC100Axis object.
|
||||
* Returns NULL if the axis number encoded in pasynUser is invalid.
|
||||
* \param[in] No Axis index number. */
|
||||
SMC100Axis* SMC100Controller::getAxis(int axisNo)
|
||||
{
|
||||
return static_cast<SMC100Axis*>(asynMotorController::getAxis(axisNo));
|
||||
}
|
||||
|
||||
|
||||
// These are the SMC100Axis methods
|
||||
|
||||
/** Creates a new SMC100Axis object.
|
||||
* \param[in] pC Pointer to the SMC100Controller to which this axis belongs.
|
||||
* \param[in] axisNo Index number of this axis, range 0 to pC->numAxes_-1.
|
||||
*
|
||||
* Initializes register numbers, etc.
|
||||
*/
|
||||
SMC100Axis::SMC100Axis(SMC100Controller *pC, int axisNo, double stepSize)
|
||||
: asynMotorAxis(pC, axisNo),
|
||||
pC_(pC), stepSize_(stepSize)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/** 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 SMC100Axis::report(FILE *fp, int level)
|
||||
{
|
||||
if (level > 0) {
|
||||
fprintf(fp, " axis %d\n",
|
||||
axisNo_ + 1);
|
||||
}
|
||||
|
||||
// Call the base class method
|
||||
asynMotorAxis::report(fp, level);
|
||||
}
|
||||
|
||||
asynStatus SMC100Axis::sendAccelAndVelocity(double acceleration, double velocity)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "SMC100::sendAccelAndVelocity";
|
||||
|
||||
// Send the velocity in egus
|
||||
sprintf(pC_->outString_, "%1dVA%f", axisNo_ + 1, (velocity*stepSize_));
|
||||
status = pC_->writeController();
|
||||
|
||||
// Send the acceleration in egus/sec/sec
|
||||
//printf("velocity: %f\n", velocity);
|
||||
//printf("acceleration: %f", acceleration);
|
||||
sprintf(pC_->outString_, "%1dAC%f", axisNo_ + 1, (acceleration*stepSize_));
|
||||
status = pC_->writeController();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
asynStatus SMC100Axis::move(double position, int relative, double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "SMC100Axis::move";
|
||||
|
||||
status = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
|
||||
if (relative) {
|
||||
sprintf(pC_->outString_, "%1dPR%f", axisNo_ + 1, (position*stepSize_));
|
||||
} else {
|
||||
sprintf(pC_->outString_, "%1dPA%f", axisNo_ + 1, (position*stepSize_));
|
||||
}
|
||||
status = pC_->writeController();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus SMC100Axis::home(double minVelocity, double maxVelocity, double acceleration, int forwards)
|
||||
{
|
||||
asynStatus status;
|
||||
// static const char *functionName = "SMC100Axis::home";
|
||||
|
||||
// set Home search velocity
|
||||
//sprintf(pC_->outString_, "%1dOH%f", axisNo_ + 1, maxVelocity);
|
||||
//status = pC_->writeController();
|
||||
|
||||
sprintf(pC_->outString_, "%1dOR", axisNo_ + 1);
|
||||
|
||||
status = pC_->writeController();
|
||||
return status;
|
||||
}
|
||||
|
||||
// Jog
|
||||
asynStatus SMC100Axis::moveVelocity(double minVelocity, double maxVelocity, double acceleration)
|
||||
{
|
||||
double high_limit;
|
||||
double low_limit;
|
||||
asynStatus comStatus;
|
||||
static const char *functionName = "SMC100Axis::moveVelocity";
|
||||
|
||||
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
|
||||
"%s: minVelocity=%f, maxVelocity=%f, acceleration=%f\n",
|
||||
functionName, minVelocity, maxVelocity, acceleration);
|
||||
|
||||
comStatus = sendAccelAndVelocity(acceleration, maxVelocity);
|
||||
if (comStatus) goto skip;
|
||||
|
||||
/* SMC100 supports the notion of jog, but only for a remote control keypad */
|
||||
// SMC100 will not allow moves outside of those set with the SL and SR commands
|
||||
// first we query these limits and then make the jog a move to the limit
|
||||
|
||||
// get the high limit
|
||||
sprintf(pC_->outString_, "%1dSR?", axisNo_ + 1);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// The response string is of the form "1SR25.0"
|
||||
high_limit = (atof(&pC_->inString_[3]));
|
||||
|
||||
// get the low limit
|
||||
sprintf(pC_->outString_, "%1dSL?", axisNo_ + 1);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// The response string is of the form "1SL-5.0"
|
||||
low_limit = (atof(&pC_->inString_[3]));
|
||||
|
||||
if (maxVelocity > 0.) {
|
||||
/* This is a positive move in SMC100 coordinates (egus) */
|
||||
sprintf(pC_->outString_, "%1dPA%f", axisNo_ + 1, high_limit);
|
||||
} else {
|
||||
/* This is a negative move in SMC100 coordinates (egus) */
|
||||
sprintf(pC_->outString_, "%1dPA%f", axisNo_ + 1, low_limit);
|
||||
}
|
||||
comStatus = pC_->writeController();
|
||||
if (comStatus) goto skip;
|
||||
|
||||
skip:
|
||||
setIntegerParam(pC_->motorStatusProblem_, comStatus ? 1:0);
|
||||
callParamCallbacks();
|
||||
return comStatus ? asynError : asynSuccess;
|
||||
|
||||
}
|
||||
|
||||
asynStatus SMC100Axis::stop(double acceleration )
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "SMC100Axis::stop";
|
||||
|
||||
sprintf(pC_->outString_, "%1dST", axisNo_ + 1);
|
||||
status = pC_->writeController();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus SMC100Axis::setPosition(double position)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "SMC100Axis::setPosition";
|
||||
|
||||
// ? not sure yet
|
||||
//sprintf(pC_->outString_, "#%02dP=%+d", axisNo_ + 1, NINT(position));
|
||||
status = pC_->writeReadController();
|
||||
return status;
|
||||
}
|
||||
|
||||
asynStatus SMC100Axis::setClosedLoop(bool closedLoop)
|
||||
{
|
||||
asynStatus status;
|
||||
//static const char *functionName = "SMC100Axis::setClosedLoop";
|
||||
|
||||
// ? not sure yet
|
||||
//sprintf(pC_->outString_, "#%02dW=%d", axisNo_ + 1, closedLoop ? 1:0);
|
||||
status = pC_->writeReadController();
|
||||
return status;
|
||||
}
|
||||
|
||||
/** 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 SMC100Axis::poll(bool *moving)
|
||||
{
|
||||
int done;
|
||||
//int driveOn;
|
||||
int limit;
|
||||
double position;
|
||||
asynStatus comStatus;
|
||||
|
||||
// Read the current motor position
|
||||
sprintf(pC_->outString_, "%1dTP", axisNo_ + 1);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// The response string is of the form "1TP-0.123"
|
||||
position = (atof(&pC_->inString_[3]) / stepSize_);
|
||||
//printf("\n * * * * SMC100 stepSize_ : %f \n", stepSize_);
|
||||
setDoubleParam(pC_->motorPosition_, position);
|
||||
|
||||
// Read the moving status of this motor
|
||||
sprintf(pC_->outString_, "%1dTS", axisNo_ + 1);
|
||||
comStatus = pC_->writeReadController();
|
||||
if (comStatus) goto skip;
|
||||
// The response string is of the form "1TS000028"
|
||||
// May need to add logic for moving while homing
|
||||
done = ((pC_->inString_[7] == '2') && (pC_->inString_[8] == '8')) ? 0:1;
|
||||
setIntegerParam(pC_->motorStatusDone_, done);
|
||||
*moving = done ? false:true;
|
||||
|
||||
// Read the limit status
|
||||
// The response string is of the form "1TS001328"
|
||||
//
|
||||
// The stage I tested this with is a GTS30V vertical jack. When the controller is initialized
|
||||
// for this device using Newport's software, +25 and -5 limits get set. The controller does not
|
||||
// let you set limits outside these values, so I never was able to run into a "hard" limit.
|
||||
// The controller also does not allow position settings outside these limits, and does not give
|
||||
// an indication. So, my recommendation is to leave the controller's travel limits set to the
|
||||
// Newport defaults, and use the motor record's soft limits, set to the controller's limits or within.
|
||||
//
|
||||
// Should a hard limit be actually encounted, this code *should* report it to the motor record
|
||||
limit = (pC_->inString_[6] == '2') ? 1:0;
|
||||
setIntegerParam(pC_->motorStatusHighLimit_, limit);
|
||||
limit = (pC_->inString_[6] == '1') ? 1:0;
|
||||
setIntegerParam(pC_->motorStatusLowLimit_, limit);
|
||||
limit = ((pC_->inString_[7] == '3') && (pC_->inString_[8] == '2')) ? 1:0;
|
||||
setIntegerParam(pC_->motorStatusAtHome_, limit);
|
||||
|
||||
// Read the drive power on status
|
||||
//sprintf(pC_->outString_, "#%02dE", axisNo_ + 1);
|
||||
//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 SMC100CreateControllerArg0 = {"Port name", iocshArgString};
|
||||
static const iocshArg SMC100CreateControllerArg1 = {"SMC100 port name", iocshArgString};
|
||||
static const iocshArg SMC100CreateControllerArg2 = {"Number of axes", iocshArgInt};
|
||||
static const iocshArg SMC100CreateControllerArg3 = {"Moving poll period (ms)", iocshArgInt};
|
||||
static const iocshArg SMC100CreateControllerArg4 = {"Idle poll period (ms)", iocshArgInt};
|
||||
static const iocshArg SMC100CreateControllerArg5 = {"EGUs per step", iocshArgString};
|
||||
static const iocshArg * const SMC100CreateControllerArgs[] = {&SMC100CreateControllerArg0,
|
||||
&SMC100CreateControllerArg1,
|
||||
&SMC100CreateControllerArg2,
|
||||
&SMC100CreateControllerArg3,
|
||||
&SMC100CreateControllerArg4,
|
||||
&SMC100CreateControllerArg5};
|
||||
static const iocshFuncDef SMC100CreateControllerDef = {"SMC100CreateController", 6, SMC100CreateControllerArgs};
|
||||
static void SMC100CreateContollerCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
SMC100CreateController(args[0].sval, args[1].sval, args[2].ival, args[3].ival, args[4].ival, args[5].sval);
|
||||
}
|
||||
|
||||
static void SMC100Register(void)
|
||||
{
|
||||
iocshRegister(&SMC100CreateControllerDef, SMC100CreateContollerCallFunc);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
epicsExportRegistrar(SMC100Register);
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
FILENAME... SMC100Driver.h
|
||||
USAGE... Motor driver support for the Newport SMC100 controller.
|
||||
|
||||
Based on the ACS MCB-4B Model 3 device driver written by:
|
||||
Mark Rivers
|
||||
March 1, 2012
|
||||
|
||||
K. Goetze 2012-03-23
|
||||
|
||||
*/
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
#define MAX_SMC100_AXES 1
|
||||
|
||||
// No controller-specific parameters yet
|
||||
#define NUM_SMC100_PARAMS 0
|
||||
|
||||
class epicsShareClass SMC100Axis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
SMC100Axis(class SMC100Controller *pC, int axis, double stepSize);
|
||||
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:
|
||||
SMC100Controller *pC_; /**< Pointer to the asynMotorController to which this axis belongs.
|
||||
* Abbreviated because it is used very frequently */
|
||||
asynStatus sendAccelAndVelocity(double accel, double velocity);
|
||||
double stepSize_; /**< Encoder increment value obtained with SU? command _or_ resolution, set at boot time */
|
||||
/* with SMC100CreateController command */
|
||||
|
||||
friend class SMC100Controller;
|
||||
};
|
||||
|
||||
class SMC100Controller : public asynMotorController {
|
||||
public:
|
||||
SMC100Controller(const char *portName, const char *SMC100PortName, int numAxes, double movingPollPeriod, double idlePollPeriod, double stepSize);
|
||||
|
||||
void report(FILE *fp, int level);
|
||||
SMC100Axis* getAxis(asynUser *pasynUser);
|
||||
SMC100Axis* getAxis(int axisNo);
|
||||
|
||||
friend class SMC100Axis;
|
||||
};
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
FILENAME... SMC100Register.cc
|
||||
USAGE... Register SMC100 motor device driver shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*****************************************************************
|
||||
COPYRIGHT NOTIFICATION
|
||||
*****************************************************************
|
||||
|
||||
(C) COPYRIGHT 1993 UNIVERSITY OF CHICAGO
|
||||
|
||||
This software was developed under a United States Government license
|
||||
described on the COPYRIGHT_UniversityOfChicago file included as part
|
||||
of this distribution.
|
||||
**********************************************************************/
|
||||
|
||||
#include <iocsh.h>
|
||||
#include "SMC100Register.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
// SMC100 Setup arguments
|
||||
static const iocshArg setupArg0 = {"Max. controller count", iocshArgInt};
|
||||
static const iocshArg setupArg1 = {"Polling rate", iocshArgInt};
|
||||
// SMC100 Config arguments
|
||||
static const iocshArg configArg0 = {"Card being configured", iocshArgInt};
|
||||
static const iocshArg configArg1 = {"asyn port name", iocshArgString};
|
||||
|
||||
static const iocshArg * const SMC100SetupArgs[2] = {&setupArg0, &setupArg1};
|
||||
static const iocshArg * const SMC100ConfigArgs[2] = {&configArg0, &configArg1};
|
||||
|
||||
static const iocshFuncDef setupSMC100 = {"SMC100Setup", 2, SMC100SetupArgs};
|
||||
static const iocshFuncDef configSMC100 = {"SMC100Config", 2, SMC100ConfigArgs};
|
||||
|
||||
static void setupSMC100CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
SMC100Setup(args[0].ival, args[1].ival);
|
||||
}
|
||||
static void configSMC100CallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
SMC100Config(args[0].ival, args[1].sval);
|
||||
}
|
||||
|
||||
static void SMC100Register(void)
|
||||
{
|
||||
iocshRegister(&setupSMC100, setupSMC100CallFunc);
|
||||
iocshRegister(&configSMC100, configSMC100CallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(SMC100Register);
|
||||
|
||||
} // extern "C"
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
FILENAME... SMC100Register.h
|
||||
USAGE... This file contains function prototypes for SMC100 IOC shell commands.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 05/19/03
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
*/
|
||||
|
||||
#include "motor.h"
|
||||
#include "motordrvCom.h"
|
||||
|
||||
/* Function prototypes. */
|
||||
extern RTN_STATUS SMC100Setup(int, int);
|
||||
extern RTN_STATUS SMC100Config(int, const char *);
|
||||
|
||||
@@ -1,286 +0,0 @@
|
||||
/*///////////////////////////////////////////////////////////////////////////////
|
||||
* Socket.cpp
|
||||
*/
|
||||
#include "Socket.h"
|
||||
|
||||
#define TIMEOUT 300
|
||||
#define SMALL_BUFFER_SIZE 256
|
||||
#define MAX_NB_SOCKETS 100
|
||||
|
||||
void Delay(double timedelay);
|
||||
|
||||
CAsyncSocket m_sConnectSocket[MAX_NB_SOCKETS];
|
||||
BOOL UsedSocket[MAX_NB_SOCKETS] = { FALSE};
|
||||
double TimeoutSocket[MAX_NB_SOCKETS];
|
||||
int NbSockets = 0;
|
||||
|
||||
/***************************************************************************************/
|
||||
int ConnectToServer(char *Ip_Address, int Ip_Port, double TimeOut)
|
||||
{
|
||||
int flag = 1;
|
||||
int socketID = 0;
|
||||
DWORD sockPendingFlag = 1;
|
||||
|
||||
if (!AfxSocketInit())
|
||||
{
|
||||
AfxMessageBox("Fatal Error: MFC Socket initialization failed");
|
||||
return -1;
|
||||
}
|
||||
/* Select a socket number */
|
||||
if (NbSockets < MAX_NB_SOCKETS)
|
||||
{
|
||||
while ((UsedSocket[socketID] == TRUE) && (socketID < MAX_NB_SOCKETS))
|
||||
socketID++;
|
||||
|
||||
if (socketID == MAX_NB_SOCKETS)
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
UsedSocket[socketID] = TRUE;
|
||||
NbSockets++;
|
||||
|
||||
/* Socket creation */
|
||||
if ((m_sConnectSocket[socketID].Create() == 0)
|
||||
|| (m_sConnectSocket[socketID].SetSockOpt(TCP_NODELAY,(char *)&flag,(int)sizeof( flag ),IPPROTO_TCP) == 0))
|
||||
{
|
||||
UsedSocket[socketID] = FALSE;
|
||||
NbSockets--;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
if (m_sConnectSocket[socketID].Connect(Ip_Address,Ip_Port) == 0)
|
||||
{
|
||||
int SocketError = m_sConnectSocket[socketID].GetLastError();
|
||||
if (SocketError != WSAEWOULDBLOCK)
|
||||
{
|
||||
UsedSocket[socketID] = FALSE;
|
||||
NbSockets--;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set timeout */
|
||||
if (TimeOut > 0)
|
||||
{
|
||||
if (TimeOut < 1e-3)
|
||||
TimeoutSocket[socketID] = 1e-3;
|
||||
else
|
||||
TimeoutSocket[socketID] = TimeOut;
|
||||
}
|
||||
else
|
||||
TimeoutSocket[socketID] = TIMEOUT;
|
||||
|
||||
/* Socket array */
|
||||
struct fd_set *Sockets = new struct fd_set;
|
||||
FD_ZERO(Sockets);
|
||||
FD_SET(m_sConnectSocket[socketID], Sockets);
|
||||
|
||||
/* Time structure */
|
||||
struct timeval *TimeOutStruct = new struct timeval;
|
||||
TimeOutStruct->tv_sec = (long) TimeoutSocket[socketID];
|
||||
TimeOutStruct->tv_usec = (long) ((TimeoutSocket[socketID] - (long)TimeoutSocket[socketID])* 1e9);
|
||||
|
||||
/* Checking connection is ok */
|
||||
int SelectReturn = select(0, NULL, Sockets, NULL, TimeOutStruct);
|
||||
if (SelectReturn == SOCKET_ERROR
|
||||
|| SelectReturn == 0)
|
||||
{
|
||||
UsedSocket[socketID] = FALSE;
|
||||
NbSockets--;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Force no pending */
|
||||
if (m_sConnectSocket[socketID].IOCtl(FIONBIO,&sockPendingFlag) == 0)
|
||||
{
|
||||
m_sConnectSocket[socketID].Close();
|
||||
UsedSocket[socketID] = FALSE;
|
||||
NbSockets--;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Delay unless -1 return for the first API */
|
||||
Sleep(10);
|
||||
|
||||
/* Return socket ID */
|
||||
return socketID;
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void SetTCPTimeout(int SocketIndex, double TimeOut)
|
||||
{
|
||||
if ((SocketIndex >= 0) && (SocketIndex < MAX_NB_SOCKETS) && (UsedSocket[SocketIndex] == TRUE))
|
||||
{
|
||||
if (TimeOut > 0)
|
||||
{
|
||||
if (TimeOut < 1e-3)
|
||||
TimeoutSocket[SocketIndex] = 1e-3;
|
||||
else
|
||||
TimeoutSocket[SocketIndex] = TimeOut;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void SendAndReceive(int socketID, char sSendString[], char sReturnString[], int iReturnStringSize)
|
||||
{
|
||||
char sSocketBuffer[SMALL_BUFFER_SIZE + 1] = {'\0'};
|
||||
int iReceiveByteNumber = 0;
|
||||
int iErrorNo = 0;
|
||||
fd_set readFds;
|
||||
int iSelectStatus;
|
||||
double dTimeout;
|
||||
struct timeval cTimeout;
|
||||
clock_t start, stop;
|
||||
|
||||
if ((socketID >= 0) && (socketID < MAX_NB_SOCKETS) && (UsedSocket[socketID] == TRUE))
|
||||
{
|
||||
/* Clear receive buffer */
|
||||
do
|
||||
{
|
||||
iReceiveByteNumber = m_sConnectSocket[socketID].Receive(sSocketBuffer,SMALL_BUFFER_SIZE);
|
||||
}
|
||||
while (iReceiveByteNumber != SOCKET_ERROR);
|
||||
sReturnString[0] = '\0';
|
||||
|
||||
/* Send String to controller and wait for response */
|
||||
m_sConnectSocket[socketID].Send(sSendString,strlen(sSendString));
|
||||
|
||||
/* Get reply with timeout */
|
||||
dTimeout = TimeoutSocket[socketID];
|
||||
do
|
||||
{
|
||||
/* Get time */
|
||||
start = clock();
|
||||
|
||||
/* Check reply */
|
||||
iReceiveByteNumber = m_sConnectSocket[socketID].Receive(sSocketBuffer,SMALL_BUFFER_SIZE);
|
||||
iErrorNo = GetLastError() & 0xffff;
|
||||
|
||||
/* Wait for reply */
|
||||
if ((iReceiveByteNumber == SOCKET_ERROR) && (iErrorNo == WSAEWOULDBLOCK))
|
||||
{
|
||||
FD_ZERO(&readFds);
|
||||
FD_SET(m_sConnectSocket[socketID].m_hSocket, &readFds);
|
||||
cTimeout.tv_sec = (long)dTimeout;
|
||||
cTimeout.tv_usec = (long)((dTimeout - (long)dTimeout) * 1e6);
|
||||
iSelectStatus = select(FD_SETSIZE, (fd_set *)&readFds, (fd_set *) NULL, (fd_set *) NULL, &cTimeout);
|
||||
if ((iSelectStatus > 0) && (FD_ISSET(m_sConnectSocket[socketID].m_hSocket, &readFds)))
|
||||
iReceiveByteNumber = m_sConnectSocket[socketID].Receive(sSocketBuffer,SMALL_BUFFER_SIZE);
|
||||
else
|
||||
{
|
||||
iErrorNo = GetLastError() & 0xffff;
|
||||
sprintf(sSocketBuffer,"-2,%s,EndOfAPI",sSendString);
|
||||
strncpyWithEOS(sReturnString, sSocketBuffer, strlen(sSocketBuffer), iReturnStringSize);
|
||||
iReceiveByteNumber = SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Concatenation */
|
||||
if ((iReceiveByteNumber >= 0) && (iReceiveByteNumber <= SMALL_BUFFER_SIZE))
|
||||
{
|
||||
sSocketBuffer[iReceiveByteNumber] = '\0';
|
||||
strncat(sReturnString, sSocketBuffer, iReturnStringSize - strlen(sReturnString) - 1);
|
||||
}
|
||||
|
||||
/* Calculate new timeout */
|
||||
stop = clock();
|
||||
dTimeout = dTimeout - (double)(stop - start) / CLOCKS_PER_SEC;
|
||||
if (dTimeout < 1e-3)
|
||||
dTimeout = 1e-3;
|
||||
}
|
||||
while ((iReceiveByteNumber != SOCKET_ERROR) && (strstr(sReturnString, "EndOfAPI") == NULL));
|
||||
}
|
||||
else
|
||||
sReturnString[0] = '\0';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void CloseSocket(int socketID)
|
||||
{
|
||||
if ((socketID >= 0) && (socketID < MAX_NB_SOCKETS))
|
||||
{
|
||||
if (UsedSocket[socketID] == TRUE)
|
||||
{
|
||||
m_sConnectSocket[socketID].Close();
|
||||
UsedSocket[socketID] = FALSE;
|
||||
TimeoutSocket[socketID] = TIMEOUT;
|
||||
NbSockets--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
char * GetError(int socketID)
|
||||
{
|
||||
if ((socketID >= 0) && (socketID < MAX_NB_SOCKETS))
|
||||
{
|
||||
int error = m_sConnectSocket[socketID].GetLastError();
|
||||
switch (error)
|
||||
{
|
||||
case WSANOTINITIALISED:
|
||||
return (_T("A successful AfxSocketInit must occur before using this API."));
|
||||
case WSAENETDOWN:
|
||||
return(_T("The Windows Sockets implementation detected that the network subsystem failed."));
|
||||
case WSAEADDRINUSE:
|
||||
return(_T("The specified address is already in use."));
|
||||
case WSAEINPROGRESS:
|
||||
return(_T("A blocking Windows Sockets call is in progress."));
|
||||
case WSAEADDRNOTAVAIL:
|
||||
return(_T("The specified address is not available from the local machine."));
|
||||
case WSAEAFNOSUPPORT:
|
||||
return(_T("Addresses in the specified family cannot be used with this socket."));
|
||||
case WSAECONNREFUSED:
|
||||
return(_T("The attempt to connect was rejected."));
|
||||
case WSAEDESTADDRREQ:
|
||||
return(_T("A destination address is required."));
|
||||
case WSAEFAULT:
|
||||
return(_T("The nSockAddrLen argument is incorrect."));
|
||||
case WSAEINVAL:
|
||||
return(_T("Invalid host address."));
|
||||
case WSAEISCONN:
|
||||
return(_T("The socket is already connected."));
|
||||
case WSAEMFILE:
|
||||
return(_T("No more file descriptors are available."));
|
||||
case WSAENETUNREACH:
|
||||
return(_T("The network cannot be reached from this host at this time."));
|
||||
case WSAENOBUFS:
|
||||
return(_T("No buffer space is available. The socket cannot be connected."));
|
||||
case WSAENOTSOCK:
|
||||
return(_T("The descriptor is not a socket."));
|
||||
case WSAETIMEDOUT:
|
||||
return(_T("Attempt to connect timed out without establishing a connection."));
|
||||
case WSAEWOULDBLOCK:
|
||||
return(_T("The socket is marked as nonblocking and the connection cannot be completed immediately."));
|
||||
case WSAEPROTONOSUPPORT:
|
||||
return(_T("The specified port is not supported."));
|
||||
case WSAEPROTOTYPE:
|
||||
return(_T("The specified port is the wrong type for this socket."));
|
||||
case WSAESOCKTNOSUPPORT:
|
||||
return(_T("The specified socket type is not supported in this address family."));
|
||||
}
|
||||
return(_T(""));
|
||||
}
|
||||
else
|
||||
return(_T(""));
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void strncpyWithEOS(char * szStringOut, const char * szStringIn, int nNumberOfCharToCopy, int nStringOutSize)
|
||||
{
|
||||
if (nNumberOfCharToCopy < nStringOutSize)
|
||||
{
|
||||
strncpy (szStringOut, szStringIn, nNumberOfCharToCopy);
|
||||
szStringOut[nNumberOfCharToCopy] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (szStringOut, szStringIn, nStringOutSize - 1);
|
||||
szStringOut[nStringOutSize - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
/*///////////////////////////////////////////////////////////////////////////////
|
||||
* Socket.h
|
||||
*/
|
||||
|
||||
#ifdef _WIN
|
||||
#include <afxsock.h> // MFC socket extensions
|
||||
#endif
|
||||
|
||||
int ConnectToServer (char *Ip_Address, int Ip_Port, double TimeOut);
|
||||
void SetTCPTimeout (int SocketID, double Timeout);
|
||||
void SendAndReceive(int socketID, char sSendString[], char sReturnString[], int iReturnStringSize);
|
||||
void CloseSocket (int SocketID);
|
||||
char * GetError (int SocketID);
|
||||
void strncpyWithEOS(char * szStringOut, const char * szStringIn, int nNumberOfCharToCopy, int nStringOutSize);
|
||||
@@ -1,151 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <cantProceed.h>
|
||||
#include <epicsString.h>
|
||||
#include <errlog.h>
|
||||
#include <iocsh.h>
|
||||
#include <asynDriver.h>
|
||||
#include <asynDrvUser.h>
|
||||
#include <XPSAsynInterpose.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
typedef struct {
|
||||
XPSCommand command;
|
||||
char *commandString;
|
||||
} XPSCommandStruct;
|
||||
|
||||
static XPSCommandStruct XPSCommands[XPS_NUM_PARAMS] = {
|
||||
{minJerkTime, "XPS_MIN_JERK"},
|
||||
{maxJerkTime, "XPS_MAX_JERK"},
|
||||
{XPSStatus, "XPS_STATUS"}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
char *portName;
|
||||
asynInterface drvUser;
|
||||
asynDrvUser *drvUserPrev;
|
||||
void *drvUserPrevPvt;
|
||||
} XPSInterposePvt;
|
||||
|
||||
static asynStatus drvUserCreate (void *drvPvt, asynUser *pasynUser,
|
||||
const char *drvInfo,
|
||||
const char **pptypeName, size_t *psize);
|
||||
static asynStatus drvUserGetType (void *drvPvt, asynUser *pasynUser,
|
||||
const char **pptypeName, size_t *psize);
|
||||
static asynStatus drvUserDestroy (void *drvPvt, asynUser *pasynUser);
|
||||
|
||||
|
||||
|
||||
static asynDrvUser XPSDrvUser = {
|
||||
drvUserCreate,
|
||||
drvUserGetType,
|
||||
drvUserDestroy
|
||||
};
|
||||
|
||||
int XPSInterpose(const char *portName)
|
||||
{
|
||||
XPSInterposePvt *pPvt;
|
||||
asynInterface *drvUserPrev;
|
||||
asynStatus status;
|
||||
|
||||
pPvt = callocMustSucceed(1, sizeof(*pPvt), "XPSInterpose");
|
||||
pPvt->portName = epicsStrDup(portName);
|
||||
|
||||
pPvt->drvUser.interfaceType = asynDrvUserType;
|
||||
pPvt->drvUser.pinterface = (void *)&XPSDrvUser;
|
||||
pPvt->drvUser.drvPvt = pPvt;
|
||||
|
||||
status = pasynManager->interposeInterface(portName, -1, &pPvt->drvUser, &drvUserPrev);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSInterpose ERROR: calling interpose interface.\n");
|
||||
return -1;
|
||||
}
|
||||
pPvt->drvUserPrev = drvUserPrev->pinterface;
|
||||
pPvt->drvUserPrevPvt = drvUserPrev->drvPvt;
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
|
||||
/* asynDrvUser routines */
|
||||
static asynStatus drvUserCreate(void *drvPvt, asynUser *pasynUser,
|
||||
const char *drvInfo,
|
||||
const char **pptypeName, size_t *psize)
|
||||
{
|
||||
XPSInterposePvt *pPvt = (XPSInterposePvt *) drvPvt;
|
||||
int i;
|
||||
char *pstring;
|
||||
int ncommands = sizeof(XPSCommands)/sizeof(XPSCommands[0]);
|
||||
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"XPSInterpose::drvUserCreate, drvInfo=%s, pptypeName=%p, psize=%p, pasynUser=%p\n",
|
||||
drvInfo, pptypeName, psize, pasynUser);
|
||||
|
||||
for (i=0; i < ncommands; i++) {
|
||||
pstring = XPSCommands[i].commandString;
|
||||
if (epicsStrCaseCmp(drvInfo, pstring) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < ncommands) {
|
||||
pasynUser->reason = XPSCommands[i].command;
|
||||
if (pptypeName) {
|
||||
*pptypeName = epicsStrDup(pstring);
|
||||
}
|
||||
if (psize) {
|
||||
*psize = sizeof(XPSCommands[i].command);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"XPSInterpose::drvUserCreate, command=%s\n", pstring);
|
||||
return(asynSuccess);
|
||||
} else {
|
||||
/* This command is not recognized, call the previous driver's routine */
|
||||
return(pPvt->drvUserPrev->create(pPvt->drvUserPrevPvt, pasynUser, drvInfo, pptypeName, psize));
|
||||
}
|
||||
}
|
||||
|
||||
static asynStatus drvUserGetType(void *drvPvt, asynUser *pasynUser,
|
||||
const char **pptypeName, size_t *psize)
|
||||
{
|
||||
XPSInterposePvt *pPvt = (XPSInterposePvt *) drvPvt;
|
||||
XPSCommand command = pasynUser->reason;
|
||||
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"XPSInterpose::drvUserGetType entered");
|
||||
|
||||
if ((command >= minJerkTime) &&
|
||||
(command <= maxJerkTime)) {
|
||||
*pptypeName = NULL;
|
||||
*psize = 0;
|
||||
if (pptypeName)
|
||||
*pptypeName = epicsStrDup(XPSCommands[command-MOTOR_AXIS_NUM_PARAMS].commandString);
|
||||
if (psize) *psize = sizeof(command);
|
||||
return(asynSuccess);
|
||||
} else {
|
||||
return(pPvt->drvUserPrev->getType(pPvt->drvUserPrevPvt, pasynUser,
|
||||
pptypeName, psize));
|
||||
}
|
||||
}
|
||||
|
||||
static asynStatus drvUserDestroy(void *drvPvt, asynUser *pasynUser)
|
||||
{
|
||||
XPSInterposePvt *pPvt = (XPSInterposePvt *) drvPvt;
|
||||
|
||||
return(pPvt->drvUserPrev->destroy(pPvt->drvUserPrevPvt, pasynUser));
|
||||
}
|
||||
|
||||
static const iocshArg XPSInterposeArg0 = {"Port Name", iocshArgString};
|
||||
static const iocshArg * const XPSInterposeArgs[1] = {&XPSInterposeArg0};
|
||||
|
||||
static const iocshFuncDef XPSInterposeDef = {"XPSInterpose", 1, XPSInterposeArgs};
|
||||
|
||||
static void XPSInterposeCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
XPSInterpose(args[0].sval);
|
||||
}
|
||||
|
||||
|
||||
static void XPSInterposeRegister(void)
|
||||
{
|
||||
iocshRegister(&XPSInterposeDef, XPSInterposeCallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(XPSInterposeRegister);
|
||||
@@ -1,10 +0,0 @@
|
||||
#include "motor_interface.h"
|
||||
|
||||
typedef enum {
|
||||
minJerkTime = MOTOR_AXIS_NUM_PARAMS,
|
||||
maxJerkTime,
|
||||
XPSStatus
|
||||
} XPSCommand;
|
||||
|
||||
#define XPS_NUM_PARAMS 3
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
FILENAME... XPSMotorDriver.cpp
|
||||
USAGE... Newport XPS EPICS asyn motor device driver
|
||||
*/
|
||||
#ifndef XPSMotorAxis_H
|
||||
#define XPSMotorAxis_H
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
|
||||
/** Struct that contains information about the XPS corrector loop.*/
|
||||
typedef struct
|
||||
{
|
||||
bool ClosedLoopStatus;
|
||||
double KP; /**< Main proportional term from PID loop.*/
|
||||
double KI; /**< Main integral term from PID loop.*/
|
||||
double KD; /**< Main differential term from PID loop.*/
|
||||
double KS;
|
||||
double IntegrationTime;
|
||||
double DerivativeFilterCutOffFrequency;
|
||||
double GKP;
|
||||
double GKI;
|
||||
double GKD;
|
||||
double KForm;
|
||||
double FeedForwardGainVelocity;
|
||||
double FeedForwardGainAcceleration;
|
||||
double Friction;
|
||||
} xpsCorrectorInfo_t;
|
||||
|
||||
class XPSController;
|
||||
|
||||
class epicsShareClass XPSAxis : public asynMotorAxis
|
||||
{
|
||||
public:
|
||||
/* These are the methods we override from the base class */
|
||||
XPSAxis(XPSController *pController, int axisNo, const char *positionerName, double stepSize);
|
||||
void report(FILE *fp, int details);
|
||||
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 doMoveToHome();
|
||||
asynStatus setPosition(double position);
|
||||
asynStatus setLowLimit(double limit);
|
||||
asynStatus setHighLimit(double limit);
|
||||
asynStatus setPGain(double gain);
|
||||
asynStatus setIGain(double gain);
|
||||
asynStatus setDGain(double gain);
|
||||
asynStatus setClosedLoop(bool closedLoop);
|
||||
asynStatus setPositionCompare();
|
||||
asynStatus getPositionCompare();
|
||||
|
||||
virtual asynStatus defineProfile(double *positions, size_t numPoints);
|
||||
virtual asynStatus readbackProfile();
|
||||
|
||||
private:
|
||||
XPSController *pC_;
|
||||
char *getXPSError(int status, char *buffer);
|
||||
int isInGroup();
|
||||
asynStatus setPID(const double * value, int pidoption);
|
||||
asynStatus getPID();
|
||||
asynStatus setPIDValue(const double * value, int pidoption);
|
||||
double motorRecPositionToXPSPosition(double motorRecPosition);
|
||||
double XPSPositionToMotorRecPosition(double XPSPosition);
|
||||
double motorRecStepToXPSStep(double motorRecStep);
|
||||
double XPSStepToMotorRecStep(double XPSStep);
|
||||
|
||||
/* Wrapper functions for the verbose PositionerCorrector functions. */
|
||||
asynStatus PositionerCorrectorPIPositionGet();
|
||||
asynStatus PositionerCorrectorPIDFFVelocityGet();
|
||||
asynStatus PositionerCorrectorPIDFFAccelerationGet();
|
||||
asynStatus PositionerCorrectorPIDDualFFVoltageGet();
|
||||
asynStatus PositionerCorrectorPIPositionSet();
|
||||
asynStatus PositionerCorrectorPIDFFVelocitySet();
|
||||
asynStatus PositionerCorrectorPIDFFAccelerationSet();
|
||||
asynStatus PositionerCorrectorPIDDualFFVoltageSet();
|
||||
|
||||
int pollSocket_;
|
||||
int moveSocket_;
|
||||
double setpointPosition_;
|
||||
double encoderPosition_;
|
||||
double currentVelocity_;
|
||||
double velocity_;
|
||||
double accel_;
|
||||
double highLimit_;
|
||||
double lowLimit_;
|
||||
double stepSize_;
|
||||
char *positionerName_;
|
||||
char *groupName_;
|
||||
int positionerError_;
|
||||
int axisStatus_;
|
||||
bool moving_;
|
||||
double profilePreDistance_;
|
||||
double profilePostDistance_;
|
||||
xpsCorrectorInfo_t xpsCorrectorInfo_;
|
||||
double deferredPosition_;
|
||||
bool deferredMove_;
|
||||
bool deferredRelative_;
|
||||
|
||||
friend class XPSController;
|
||||
};
|
||||
|
||||
#endif /* XPSMotorAxis_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,141 +0,0 @@
|
||||
/*
|
||||
FILENAME... XPSMotorDriver.cpp
|
||||
USAGE... Newport XPS EPICS asyn motor device driver
|
||||
*/
|
||||
|
||||
#ifndef XPSController_H
|
||||
#define XPSController_H
|
||||
|
||||
#include "asynMotorController.h"
|
||||
#include "asynMotorAxis.h"
|
||||
#include "XPSAxis.h"
|
||||
|
||||
#define XPS_MAX_AXES 8
|
||||
#define XPS_POLL_TIMEOUT 2.0
|
||||
#define XPS_MOVE_TIMEOUT 100000.0 // "Forever"
|
||||
#define XPS_MIN_PROFILE_ACCEL_TIME 0.25
|
||||
|
||||
/* Constants used for FTP to the XPS */
|
||||
#define XPS_C8_TRAJECTORY_DIRECTORY "/Admin/Public/Trajectories"
|
||||
#define XPS_Q8_TRAJECTORY_DIRECTORY "/Public/Trajectories"
|
||||
#define MAX_FILENAME_LEN 256
|
||||
#define MAX_MESSAGE_LEN 256
|
||||
#define MAX_GROUPNAME_LEN 64
|
||||
|
||||
#define MAX_PULSE_WIDTHS 4
|
||||
#define MAX_SETTLING_TIMES 4
|
||||
static const double positionComparePulseWidths[MAX_PULSE_WIDTHS] = {0.2, 1.0, 2.5, 10.0};
|
||||
static const double positionCompareSettlingTimes[MAX_SETTLING_TIMES] = {0.075, 1.0, 4.0, 12.0};
|
||||
typedef enum {
|
||||
XPSPositionCompareModeDisable,
|
||||
XPSPositionCompareModePulse,
|
||||
XPSPositionCompareModeAquadBWindowed,
|
||||
XPSPositionCompareModeAquadBAlways
|
||||
} XPSPositionCompareMode_t;
|
||||
|
||||
// drvInfo strings for extra parameters that the XPS controller supports
|
||||
#define XPSMinJerkString "XPS_MIN_JERK"
|
||||
#define XPSMaxJerkString "XPS_MAX_JERK"
|
||||
#define XPSPositionCompareModeString "XPS_POSITION_COMPARE_MODE"
|
||||
#define XPSPositionCompareMinPositionString "XPS_POSITION_COMPARE_MIN_POSITION"
|
||||
#define XPSPositionCompareMaxPositionString "XPS_POSITION_COMPARE_MAX_POSITION"
|
||||
#define XPSPositionCompareStepSizeString "XPS_POSITION_COMPARE_STEP_SIZE"
|
||||
#define XPSPositionComparePulseWidthString "XPS_POSITION_COMPARE_PULSE_WIDTH"
|
||||
#define XPSPositionCompareSettlingTimeString "XPS_POSITION_COMPARE_SETTLING_TIME"
|
||||
#define XPSProfileMaxVelocityString "XPS_PROFILE_MAX_VELOCITY"
|
||||
#define XPSProfileMaxAccelerationString "XPS_PROFILE_MAX_ACCELERATION"
|
||||
#define XPSProfileMinPositionString "XPS_PROFILE_MIN_POSITION"
|
||||
#define XPSProfileMaxPositionString "XPS_PROFILE_MAX_POSITION"
|
||||
#define XPSProfileGroupNameString "XPS_PROFILE_GROUP_NAME"
|
||||
#define XPSTrajectoryFileString "XPS_TRAJECTORY_FILE"
|
||||
#define XPSStatusString "XPS_STATUS"
|
||||
#define XPSStatusStringString "XPS_STATUS_STRING"
|
||||
#define XPSTclScriptString "XPS_TCL_SCRIPT"
|
||||
#define XPSTclScriptExecuteString "XPS_TCL_SCRIPT_EXECUTE"
|
||||
|
||||
class epicsShareClass XPSController : public asynMotorController {
|
||||
|
||||
public:
|
||||
XPSController(const char *portName, const char *IPAddress, int IPPort,
|
||||
int numAxes, double movingPollPeriod, double idlePollPeriod,
|
||||
int enableSetPosition, double setPositionSettlingTime);
|
||||
|
||||
/* 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);
|
||||
XPSAxis* getAxis(asynUser *pasynUser);
|
||||
XPSAxis* getAxis(int axisNo);
|
||||
asynStatus poll();
|
||||
asynStatus setDeferredMoves(bool deferMoves);
|
||||
|
||||
/* These are the functions for profile moves */
|
||||
asynStatus initializeProfile(size_t maxPoints, const char* ftpUsername, const char* ftpPassword);
|
||||
asynStatus buildProfile();
|
||||
asynStatus executeProfile();
|
||||
asynStatus abortProfile();
|
||||
asynStatus readbackProfile();
|
||||
|
||||
/* These are the methods that are new to this class */
|
||||
void profileThread();
|
||||
asynStatus runProfile();
|
||||
asynStatus waitMotors();
|
||||
|
||||
/* Deferred moves functions.*/
|
||||
asynStatus processDeferredMovesInGroup(char * groupName);
|
||||
|
||||
/*Disable automatic enable of axes.*/
|
||||
asynStatus disableAutoEnable();
|
||||
/* Function to disable the MSTA problem bit in the event of an XPS Disable state 20 */
|
||||
asynStatus noDisableError();
|
||||
|
||||
/* Function to enable a mode where the XPSAxis poller will check the moveSocket response
|
||||
to determine motion done. */
|
||||
asynStatus enableMovingMode();
|
||||
|
||||
|
||||
protected:
|
||||
XPSAxis **pAxes_; /**< Array of pointers to axis objects */
|
||||
|
||||
#define FIRST_XPS_PARAM XPSMinJerk_
|
||||
int XPSMinJerk_;
|
||||
int XPSMaxJerk_;
|
||||
int XPSPositionCompareMode_;
|
||||
int XPSPositionCompareMinPosition_;
|
||||
int XPSPositionCompareMaxPosition_;
|
||||
int XPSPositionCompareStepSize_;
|
||||
int XPSPositionComparePulseWidth_;
|
||||
int XPSPositionCompareSettlingTime_;
|
||||
int XPSProfileMaxVelocity_;
|
||||
int XPSProfileMaxAcceleration_;
|
||||
int XPSProfileMinPosition_;
|
||||
int XPSProfileMaxPosition_;
|
||||
int XPSProfileGroupName_;
|
||||
int XPSTrajectoryFile_;
|
||||
int XPSStatus_;
|
||||
int XPSStatusString_;
|
||||
int XPSTclScript_;
|
||||
int XPSTclScriptExecute_;
|
||||
#define LAST_XPS_PARAM XPSTclScriptExecute_
|
||||
|
||||
private:
|
||||
bool enableSetPosition_; /**< Enable/disable setting the position from EPICS */
|
||||
double setPositionSettlingTime_; /**< The settling (sleep) time used when setting position. */
|
||||
char *IPAddress_;
|
||||
int IPPort_;
|
||||
char *ftpUsername_;
|
||||
char *ftpPassword_;
|
||||
int pollSocket_;
|
||||
int moveSocket_;
|
||||
char firmwareVersion_[100];
|
||||
bool movesDeferred_;
|
||||
epicsEventId profileExecuteEvent_;
|
||||
int autoEnable_;
|
||||
int noDisableError_;
|
||||
bool enableMovingMode_;
|
||||
|
||||
friend class XPSAxis;
|
||||
};
|
||||
#define NUM_XPS_PARAMS ((int)(&LAST_XPS_PARAM - &FIRST_XPS_PARAM + 1))
|
||||
#endif /* XPSController_H */
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
/* Prog to test the XPS position gathering and trigger during a trajectory scan */
|
||||
/**/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include <shareLib.h>
|
||||
#include "XPS_C8_drivers.h"
|
||||
#include "Socket.h"
|
||||
#include "xps_ftp.h"
|
||||
|
||||
#define XPS_ADDRESS "164.54.160.34"
|
||||
#define NUM_ELEMENTS 10
|
||||
#define NUM_AXES 2
|
||||
#define PULSE_TIME 1.0
|
||||
#define POLL_TIMEOUT 1.0
|
||||
#define DRIVE_TIMEOUT 100.0
|
||||
#define USERNAME "Administrator"
|
||||
#define PASSWORD "Administrator"
|
||||
#define TRAJECTORY_DIRECTORY "/Admin/public/Trajectories"
|
||||
#define TRAJECTORY_FILE "test_trajectory"
|
||||
#define GATHERING_DIRECTORY "/Admin/public/"
|
||||
#define GATHERING_FILE "Gathering.dat"
|
||||
|
||||
epicsShareFunc void xps_gathering()
|
||||
{
|
||||
int status,poll_socket,drive_socket,end=0;
|
||||
SOCKET ftpSocket;
|
||||
char *gatheringData = "GROUP2.POSITIONER1.SetpointPosition;"
|
||||
"GROUP2.POSITIONER1.CurrentPosition;"
|
||||
"GROUP2.POSITIONER1.CurrentVelocity;"
|
||||
"GROUP2.POSITIONER2.SetpointPosition;"
|
||||
"GROUP2.POSITIONER2.CurrentPosition;"
|
||||
"GROUP2.POSITIONER2.CurrentVelocity";
|
||||
char *positioner[NUM_AXES] = {"GROUP2.POSITIONER1", "GROUP2.POSITIONER2"};
|
||||
char group[] = "GROUP2";
|
||||
char outputfilename[500];
|
||||
double maxp, minp, maxv, maxa;
|
||||
char buffer[1000];
|
||||
int nitems;
|
||||
double setpoint, actual, velocity;
|
||||
int i,j;
|
||||
int groupStatus;
|
||||
FILE *gatheringFile;
|
||||
int eventID;
|
||||
time_t start_time, end_time;
|
||||
|
||||
poll_socket = TCP_ConnectToServer(XPS_ADDRESS, 5001, POLL_TIMEOUT);
|
||||
drive_socket = TCP_ConnectToServer(XPS_ADDRESS, 5001, DRIVE_TIMEOUT);
|
||||
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
printf("Initial group status=%d\n", groupStatus);
|
||||
/* If group not initialized, then initialize it */
|
||||
if (groupStatus >= 0 && groupStatus <= 9) {
|
||||
printf("Calling GroupInitialize ...\n");
|
||||
status = GroupInitialize(drive_socket, group);
|
||||
if (status) {
|
||||
printf("Error calling GroupInitialize error=%d\n", status);
|
||||
return;
|
||||
}
|
||||
printf("Calling GroupHomeSearch ...\n");
|
||||
status = GroupHomeSearch(drive_socket, group);
|
||||
if (status) {
|
||||
printf("Error calling GroupHomeSearch error=%d\n", status);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
printf("FTPing trajectory file to XPS ...\n");
|
||||
/* FTP the trajectory file from the local directory to the XPS */
|
||||
status = ftpConnect(XPS_ADDRESS, USERNAME, PASSWORD, &ftpSocket);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpConnect, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
status = ftpChangeDir(ftpSocket, TRAJECTORY_DIRECTORY);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpChangeDir, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
status = ftpStoreFile(ftpSocket, TRAJECTORY_FILE);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpStoreFile, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Define trajectory output pulses */
|
||||
printf("Defining output pulses ...\n");
|
||||
status = MultipleAxesPVTPulseOutputSet(poll_socket, group, 1,
|
||||
NUM_ELEMENTS, PULSE_TIME);
|
||||
|
||||
/*************************** Verify trajectory **********************/
|
||||
printf("Verifying trajectory ...\n");
|
||||
status = MultipleAxesPVTVerification(drive_socket, group, TRAJECTORY_FILE);
|
||||
if (status != 0) {
|
||||
printf("Error performing MultipleAxesPVTVerification, status=%d\n",status);
|
||||
end = 1;
|
||||
}
|
||||
|
||||
printf("Reading verify results ...\n");
|
||||
printf(" MultipleAxesPVTVerificationResultGet\n");
|
||||
for (i=0; i<NUM_AXES; i++) {
|
||||
status = MultipleAxesPVTVerificationResultGet(poll_socket,positioner[i],
|
||||
outputfilename,
|
||||
&minp, &maxp, &maxv, &maxa);
|
||||
printf(" positioner 1%d, status %d, Max. pos. %g, Min. pos. %g, Max. vel. %g, Max. accel. %g\n",
|
||||
i, status, maxp, minp, maxv, maxa);
|
||||
}
|
||||
|
||||
if (end == 1) return;
|
||||
|
||||
/***********************Configure Gathering and Timer******************/
|
||||
printf("Reseting gathering ...\n");
|
||||
status = GatheringReset(poll_socket);
|
||||
if (status != 0) {
|
||||
printf("Error performing GatheringReset, status=%d\n",status);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Defining gathering ...\n");
|
||||
status = GatheringConfigurationSet(poll_socket, NUM_AXES*3, gatheringData);
|
||||
if (status != 0) {
|
||||
printf("Error performing GatheringConfigurationSet, status=%d\n",status);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Defining trigger ...\n");
|
||||
status = EventExtendedConfigurationTriggerSet(poll_socket, 2,
|
||||
"Always;GROUP2.PVT.TrajectoryPulse",
|
||||
"","","","");
|
||||
if (status != 0) {
|
||||
printf("Error performing EventExtendedConfigurationTriggerSet, status=%d\n",
|
||||
status);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Defining action ...\n");
|
||||
status = EventExtendedConfigurationActionSet(poll_socket, 1, "GatheringOneData",
|
||||
"", "", "", "");
|
||||
if (status != 0) {
|
||||
printf("Error performing EventExtendedConfigurationActionSet, status=%d\n",
|
||||
status);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Starting gathering ...\n");
|
||||
status= EventExtendedStart(poll_socket, &eventID);
|
||||
if (status != 0) {
|
||||
printf("Error performing EventExtendedStart, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/********************* Run trajectory ****************************/
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
if (status != 0) {
|
||||
printf("Error performing GroupStatusGet, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
printf("Group status before executing trajectory=%d\n", groupStatus);
|
||||
printf("Executing trajectory ...\n");
|
||||
start_time = time(NULL);
|
||||
status = MultipleAxesPVTExecution(drive_socket, group, TRAJECTORY_FILE, 1);
|
||||
end_time = time(NULL);
|
||||
printf("Time to execute trajectory=%f\n", difftime(end_time, start_time));
|
||||
if (status != 0) {
|
||||
printf("Error performing MultipleAxesPVTExecution, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
if (status != 0) {
|
||||
printf("Error performing GroupStatusGet, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
printf("Group status after executing trajectory=%d\n", groupStatus);
|
||||
|
||||
/* Remove the event */
|
||||
printf("Removing event ...\n");
|
||||
status = EventExtendedRemove(poll_socket, eventID);
|
||||
if (status != 0) {
|
||||
printf("Error performing ExtendedEventRemove, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
/***********************Save the gathered data ***************/
|
||||
printf("Stopping gathering ...\n");
|
||||
start_time = time(NULL);
|
||||
status = GatheringStopAndSave(drive_socket);
|
||||
end_time = time(NULL);
|
||||
printf("Time to save gathering data=%f\n", difftime(end_time, start_time));
|
||||
if (status != 0) {
|
||||
printf("Error performing GatheringExternalStopAndSave, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
if (status != 0) {
|
||||
printf("Error performing GroupStatusGet, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
printf("Group status after stopping gathering=%d\n", groupStatus);
|
||||
|
||||
/* FTP the gathering file from the XPS to the local directory */
|
||||
printf("FTPing gathering file from XPS ...\n");
|
||||
status = ftpChangeDir(ftpSocket, GATHERING_DIRECTORY);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpChangeDir, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
status = ftpRetrieveFile(ftpSocket, GATHERING_FILE);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpRetrieveFile, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
status = ftpDisconnect(ftpSocket);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpDisconnect, status=%d\n", status);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("Opening gathering file ...\n");
|
||||
gatheringFile = fopen(GATHERING_FILE, "r");
|
||||
if (gatheringFile == NULL) {
|
||||
perror("Errror opening gathering file");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Read 1st 2 lines */
|
||||
for (i=0; i<2; i++) {
|
||||
fgets (buffer, 1000, gatheringFile);
|
||||
printf("Line %d of gathering file = %s\n", i, buffer);
|
||||
}
|
||||
for (i=0; i<NUM_ELEMENTS; i++) {
|
||||
for (j=0; j<NUM_AXES; j++) {
|
||||
nitems = fscanf(gatheringFile,"%lf %lf %lf ", &setpoint, &actual, &velocity);
|
||||
if (nitems != 3) printf("nitems=%d, should be 3\n", nitems);
|
||||
printf("Point=%d, axis=%d, setpoint=%f, actual=%f, error=%f, velocity=%f\n",
|
||||
i+1, j+1, setpoint, actual, actual-setpoint, velocity);
|
||||
}
|
||||
}
|
||||
fclose (gatheringFile);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,221 +0,0 @@
|
||||
/* Program to test the XPS position gathering and trigger during a trajectory scan */
|
||||
/**/
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#define epicsExportSharedSymbols
|
||||
#include <shareLib.h>
|
||||
#include "XPS_C8_drivers.h"
|
||||
#include "Socket.h"
|
||||
#include "xps_ftp.h"
|
||||
|
||||
#define XPS_ADDRESS "164.54.160.124"
|
||||
#define NUM_TRAJECTORY_ELEMENTS 6
|
||||
#define NUM_GATHERING_POINTS 100
|
||||
#define NUM_GATHERING_ITEMS 2
|
||||
#define NUM_AXES 6
|
||||
#define PULSE_TIME 0.01
|
||||
#define POLL_TIMEOUT 1.0
|
||||
#define DRIVE_TIMEOUT 100.0
|
||||
#define USERNAME "Administrator"
|
||||
#define PASSWORD "Administrator"
|
||||
#define TRAJECTORY_DIRECTORY "/Admin/public/Trajectories"
|
||||
#define TRAJECTORY_FILE "TrajectoryScan.trj"
|
||||
#define BUFFER_SIZE 32767
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int status,poll_socket,drive_socket,end=0;
|
||||
SOCKET ftpSocket;
|
||||
char *gatheringData = "GROUP1.PHI.SetpointPosition;"
|
||||
"GROUP1.PHI.CurrentPosition;"
|
||||
"GROUP1.KAPPA.SetpointPosition;"
|
||||
"GROUP1.KAPPA.CurrentPosition;"
|
||||
"GROUP1.OMEGA.SetpointPosition;"
|
||||
"GROUP1.OMEGA.CurrentPosition;"
|
||||
"GROUP1.PSI.SetpointPosition;"
|
||||
"GROUP1.PSI.CurrentPosition;"
|
||||
"GROUP1.2THETA.SetpointPosition;"
|
||||
"GROUP1.2THETA.CurrentPosition;"
|
||||
"GROUP1.NU.SetpointPosition;"
|
||||
"GROUP1.NU.CurrentPosition";
|
||||
char *positioner[NUM_AXES] = {"GROUP1.PHI", "GROUP1.KAPPA", "GROUP1.OMEGA", "GROUP1.PSI", "GROUP1.2THETA", "GROUP1.NU"};
|
||||
char group[] = "GROUP1";
|
||||
char outputfilename[500];
|
||||
double maxp, minp, maxv, maxa;
|
||||
char buffer[BUFFER_SIZE];
|
||||
int currentSamples, maxSamples;
|
||||
int i;
|
||||
int groupStatus;
|
||||
int eventID;
|
||||
time_t start_time, end_time;
|
||||
|
||||
poll_socket = TCP_ConnectToServer(XPS_ADDRESS, 5001, POLL_TIMEOUT);
|
||||
drive_socket = TCP_ConnectToServer(XPS_ADDRESS, 5001, DRIVE_TIMEOUT);
|
||||
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
printf("Initial group status=%d\n", groupStatus);
|
||||
/* If group not initialized, then initialize it */
|
||||
if (groupStatus >= 0 && groupStatus <= 9) {
|
||||
printf("Calling GroupInitialize ...\n");
|
||||
status = GroupInitialize(drive_socket, group);
|
||||
if (status) {
|
||||
printf("Error calling GroupInitialize error=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
printf("Calling GroupHomeSearch ...\n");
|
||||
status = GroupHomeSearch(drive_socket, group);
|
||||
if (status) {
|
||||
printf("Error calling GroupHomeSearch error=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
printf("FTPing trajectory file to XPS ...\n");
|
||||
/* FTP the trajectory file from the local directory to the XPS */
|
||||
status = ftpConnect(XPS_ADDRESS, USERNAME, PASSWORD, &ftpSocket);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpConnect, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = ftpChangeDir(ftpSocket, TRAJECTORY_DIRECTORY);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpChangeDir, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = ftpStoreFile(ftpSocket, TRAJECTORY_FILE);
|
||||
if (status != 0) {
|
||||
printf("Error calling ftpStoreFile, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Define trajectory output pulses */
|
||||
printf("Defining output pulses ...\n");
|
||||
status = MultipleAxesPVTPulseOutputSet(poll_socket, group, 2,
|
||||
NUM_TRAJECTORY_ELEMENTS-1, PULSE_TIME);
|
||||
|
||||
/*************************** Verify trajectory **********************/
|
||||
printf("Verifying trajectory ...\n");
|
||||
status = MultipleAxesPVTVerification(drive_socket, group, TRAJECTORY_FILE);
|
||||
if (status != 0) {
|
||||
printf("Error performing MultipleAxesPVTVerification, status=%d\n",status);
|
||||
end = 1;
|
||||
}
|
||||
|
||||
printf("Reading verify results ...\n");
|
||||
printf(" MultipleAxesPVTVerificationResultGet\n");
|
||||
for (i=0; i<NUM_AXES; i++) {
|
||||
status = MultipleAxesPVTVerificationResultGet(poll_socket,positioner[i],
|
||||
outputfilename,
|
||||
&minp, &maxp, &maxv, &maxa);
|
||||
printf(" positioner %d, status %d, Max. pos. %g, Min. pos. %g, Max. vel. %g, Max. accel. %g\n",
|
||||
i, status, maxp, minp, maxv, maxa);
|
||||
}
|
||||
|
||||
if (end == 1) return -1;
|
||||
|
||||
/***********************Configure Gathering and Timer******************/
|
||||
printf("Reseting gathering ...\n");
|
||||
status = GatheringReset(poll_socket);
|
||||
if (status != 0) {
|
||||
printf("Error performing GatheringReset, status=%d\n",status);
|
||||
return status;
|
||||
}
|
||||
|
||||
printf("Defining gathering ...\n");
|
||||
status = GatheringConfigurationSet(poll_socket, NUM_AXES*NUM_GATHERING_ITEMS, gatheringData);
|
||||
if (status != 0) {
|
||||
printf("Error performing GatheringConfigurationSet, status=%d\n",status);
|
||||
return status;
|
||||
}
|
||||
|
||||
printf("Defining trigger ...\n");
|
||||
status = EventExtendedConfigurationTriggerSet(poll_socket, 2,
|
||||
"Always;GROUP1.PVT.TrajectoryPulse",
|
||||
"","","","");
|
||||
if (status != 0) {
|
||||
printf("Error performing EventExtendedConfigurationTriggerSet, status=%d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
printf("Defining action ...\n");
|
||||
status = EventExtendedConfigurationActionSet(poll_socket, 1, "GatheringOneData",
|
||||
"", "", "", "");
|
||||
if (status != 0) {
|
||||
printf("Error performing EventExtendedConfigurationActionSet, status=%d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
printf("Starting gathering ...\n");
|
||||
status= EventExtendedStart(poll_socket, &eventID);
|
||||
if (status != 0) {
|
||||
printf("Error performing EventExtendedStart, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/********************* Run trajectory ****************************/
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
if (status != 0) {
|
||||
printf("Error performing GroupStatusGet, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
printf("Group status before executing trajectory=%d\n", groupStatus);
|
||||
printf("Executing trajectory ...\n");
|
||||
start_time = time(NULL);
|
||||
status = MultipleAxesPVTExecution(drive_socket, group, TRAJECTORY_FILE, 1);
|
||||
end_time = time(NULL);
|
||||
printf("Time to execute trajectory=%f\n", difftime(end_time, start_time));
|
||||
if (status != 0) {
|
||||
printf("Error performing MultipleAxesPVTExecution, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
if (status != 0) {
|
||||
printf("Error performing GroupStatusGet, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
printf("Group status after executing trajectory=%d\n", groupStatus);
|
||||
|
||||
/* Remove the event */
|
||||
printf("Removing event ...\n");
|
||||
status = EventExtendedRemove(poll_socket, eventID);
|
||||
if (status != 0) {
|
||||
printf("Error performing ExtendedEventRemove, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
|
||||
/***********************Save the gathered data ***************/
|
||||
printf("Stopping gathering ...\n");
|
||||
start_time = time(NULL);
|
||||
status = GatheringStop(drive_socket);
|
||||
end_time = time(NULL);
|
||||
printf("Time to stop gathering=%f\n", difftime(end_time, start_time));
|
||||
if (status != 0) {
|
||||
printf("Error performing GatheringExternalStop, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
status = GroupStatusGet(poll_socket, group, &groupStatus);
|
||||
if (status != 0) {
|
||||
printf("Error performing GroupStatusGet, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
printf("Group status after stopping gathering=%d\n", groupStatus);
|
||||
|
||||
/* Read the number of lines of gathering */
|
||||
status = GatheringCurrentNumberGet(drive_socket, ¤tSamples, &maxSamples);
|
||||
if (status != 0) {
|
||||
printf("Error calling GatherCurrentNumberGet, status=%d\n", status);
|
||||
return status;
|
||||
}
|
||||
if (currentSamples != NUM_GATHERING_POINTS) {
|
||||
printf("readGathering: warning, NUM_GATHERING_POINTS=%d, currentSamples=%d\n",
|
||||
NUM_GATHERING_POINTS, currentSamples);
|
||||
}
|
||||
status = GatheringDataMultipleLinesGet(drive_socket, 0, currentSamples, buffer);
|
||||
printf("GatheringDataMultipleLinesGet, status=%d, currentSamples=%d\n", status, currentSamples);
|
||||
printf("Buffer length=%ld, buffer=\n%s\n", (long)strlen(buffer), buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
void xps_gathering();
|
||||
|
||||
int main(int arvgc, char **argv) {
|
||||
xps_gathering();
|
||||
return(0);
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#include <iocsh.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
void xps_gathering();
|
||||
|
||||
static const iocshArg XPSGatheringArg0 = {"Interelement period", iocshArgInt};
|
||||
static const iocshArg * const XPSGatheringArgs[1] = {&XPSGatheringArg0};
|
||||
static const iocshFuncDef XPSGathering = {"XPSGathering", 1, XPSGatheringArgs};
|
||||
static void XPSGatheringCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
xps_gathering(args[0].ival);
|
||||
}
|
||||
static void XPSGatheringRegister(void)
|
||||
{
|
||||
iocshRegister(&XPSGathering, XPSGatheringCallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(XPSGatheringRegister);
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,254 +0,0 @@
|
||||
/*************************************************
|
||||
* XPS_API.h *
|
||||
* *
|
||||
* Description: *
|
||||
* XPS functions *
|
||||
*************************************************/
|
||||
|
||||
#define DLL epicsShareFunc
|
||||
|
||||
#if !defined(_WIN32) && !defined(CYGWIN32)
|
||||
#define __stdcall
|
||||
#endif
|
||||
|
||||
#ifdef __rtems__
|
||||
#include "strtok_r.h"
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#else
|
||||
typedef int bool; /* C does not know bool, only C++ */
|
||||
#endif
|
||||
|
||||
|
||||
DLL int __stdcall TCP_ConnectToServer(char *Ip_Address, int Ip_Port, double TimeOut);
|
||||
DLL void __stdcall TCP_SetTimeout(int SocketIndex, double Timeout);
|
||||
DLL void __stdcall TCP_CloseSocket(int SocketIndex);
|
||||
DLL char * __stdcall TCP_GetError(int SocketIndex);
|
||||
DLL char * __stdcall GetLibraryVersion(void);
|
||||
DLL int __stdcall ControllerMotionKernelTimeLoadGet (int SocketIndex, double * CPUTotalLoadRatio, double * CPUCorrectorLoadRatio, double * CPUProfilerLoadRatio, double * CPUServitudesLoadRatio); /* Get controller motion kernel time load */
|
||||
DLL int __stdcall ControllerStatusGet (int SocketIndex, int * ControllerStatus); /* Read controller current status */
|
||||
DLL int __stdcall ControllerStatusStringGet (int SocketIndex, int ControllerStatusCode, char * ControllerStatusString); /* Return the controller status string corresponding to the controller status code */
|
||||
DLL int __stdcall ElapsedTimeGet (int SocketIndex, double * ElapsedTime); /* Return elapsed time from controller power on */
|
||||
DLL int __stdcall ErrorStringGet (int SocketIndex, int ErrorCode, char * ErrorString); /* Return the error string corresponding to the error code */
|
||||
DLL int __stdcall FirmwareVersionGet (int SocketIndex, char * Version); /* Return firmware version */
|
||||
DLL int __stdcall TCLScriptExecute (int SocketIndex, char * TCLFileName, char * TaskName, char * ParametersList); /* Execute a TCL script from a TCL file */
|
||||
DLL int __stdcall TCLScriptExecuteAndWait (int SocketIndex, char * TCLFileName, char * TaskName, char * InputParametersList, char * OutputParametersList); /* Execute a TCL script from a TCL file and wait the end of execution to return */
|
||||
DLL int __stdcall TCLScriptExecuteWithPriority (int SocketIndex, char * TCLFileName, char * TaskName, char * TaskPriorityLevel, char * ParametersList); /* Execute a TCL script with defined priority */
|
||||
DLL int __stdcall TCLScriptKill (int SocketIndex, char * TaskName); /* Kill TCL Task */
|
||||
DLL int __stdcall TimerGet (int SocketIndex, char * TimerName, int * FrequencyTicks); /* Get a timer */
|
||||
DLL int __stdcall TimerSet (int SocketIndex, char * TimerName, int FrequencyTicks); /* Set a timer */
|
||||
DLL int __stdcall Reboot (int SocketIndex); /* Reboot the controller */
|
||||
DLL int __stdcall Login (int SocketIndex, char * Name, char * Password); /* Log in */
|
||||
DLL int __stdcall CloseAllOtherSockets (int SocketIndex); /* Close all socket beside the one used to send this command */
|
||||
DLL int __stdcall HardwareDateAndTimeGet (int SocketIndex, char * DateAndTime); /* Return hardware date and time */
|
||||
DLL int __stdcall HardwareDateAndTimeSet (int SocketIndex, char * DateAndTime); /* Set hardware date and time */
|
||||
DLL int __stdcall EventAdd (int SocketIndex, char * PositionerName, char * EventName, char * EventParameter, char * ActionName, char * ActionParameter1, char * ActionParameter2, char * ActionParameter3); /* ** OBSOLETE ** Add an event */
|
||||
DLL int __stdcall EventGet (int SocketIndex, char * PositionerName, char * EventsAndActionsList); /* ** OBSOLETE ** Read events and actions list */
|
||||
DLL int __stdcall EventRemove (int SocketIndex, char * PositionerName, char * EventName, char * EventParameter); /* ** OBSOLETE ** Delete an event */
|
||||
DLL int __stdcall EventWait (int SocketIndex, char * PositionerName, char * EventName, char * EventParameter); /* ** OBSOLETE ** Wait an event */
|
||||
DLL int __stdcall EventExtendedConfigurationTriggerSet (int SocketIndex, int NbElements, char * ExtendedEventNameList, char * EventParameter1List, char * EventParameter2List, char * EventParameter3List, char * EventParameter4List); /* Configure one or several events */
|
||||
DLL int __stdcall EventExtendedConfigurationTriggerGet (int SocketIndex, char * EventTriggerConfiguration); /* Read the event configuration */
|
||||
DLL int __stdcall EventExtendedConfigurationActionSet (int SocketIndex, int NbElements, char * ExtendedActionNameList, char * ActionParameter1List, char * ActionParameter2List, char * ActionParameter3List, char * ActionParameter4List); /* Configure one or several actions */
|
||||
DLL int __stdcall EventExtendedConfigurationActionGet (int SocketIndex, char * ActionConfiguration); /* Read the action configuration */
|
||||
DLL int __stdcall EventExtendedStart (int SocketIndex, int * ID); /* Launch the last event and action configuration and return an ID */
|
||||
DLL int __stdcall EventExtendedAllGet (int SocketIndex, char * EventActionConfigurations); /* Read all event and action configurations */
|
||||
DLL int __stdcall EventExtendedGet (int SocketIndex, int ID, char * EventTriggerConfiguration, char * ActionConfiguration); /* Read the event and action configuration defined by ID */
|
||||
DLL int __stdcall EventExtendedRemove (int SocketIndex, int ID); /* Remove the event and action configuration defined by ID */
|
||||
DLL int __stdcall EventExtendedWait (int SocketIndex); /* Wait events from the last event configuration */
|
||||
DLL int __stdcall GatheringConfigurationGet (int SocketIndex, char * Type); /*Read different mnemonique type */
|
||||
DLL int __stdcall GatheringConfigurationSet (int SocketIndex, int NbElements, char * TypeList); /* Configuration acquisition */
|
||||
DLL int __stdcall GatheringCurrentNumberGet (int SocketIndex, int * CurrentNumber, int * MaximumSamplesNumber); /* Maximum number of samples and current number during acquisition */
|
||||
DLL int __stdcall GatheringStopAndSave (int SocketIndex); /* Stop acquisition and save data */
|
||||
DLL int __stdcall GatheringDataAcquire (int SocketIndex); /* Acquire a configured data */
|
||||
DLL int __stdcall GatheringDataGet (int SocketIndex, int IndexPoint, char * DataBufferLine); /* Get a data line from gathering buffer */
|
||||
DLL int __stdcall GatheringDataMultipleLinesGet (int SocketIndex, int IndexPoint, int NumberOfLines, char * DataBufferLine); /* Get multiple data lines from gathering buffer */
|
||||
DLL int __stdcall GatheringReset (int SocketIndex); /* Empty the gathered data in memory to start new gathering from scratch */
|
||||
DLL int __stdcall GatheringRun (int SocketIndex, int DataNumber, int Divisor); /* Start a new gathering */
|
||||
DLL int __stdcall GatheringRunAppend (int SocketIndex); /* Re-start the stopped gathering to add new data */
|
||||
DLL int __stdcall GatheringStop (int SocketIndex); /* Stop the data gathering (without saving to file) */
|
||||
DLL int __stdcall GatheringExternalConfigurationSet (int SocketIndex, int NbElements, char * TypeList); /* Configuration acquisition */
|
||||
DLL int __stdcall GatheringExternalConfigurationGet (int SocketIndex, char * Type); /* Read different mnemonique type */
|
||||
DLL int __stdcall GatheringExternalCurrentNumberGet (int SocketIndex, int * CurrentNumber, int * MaximumSamplesNumber); /* Maximum number of samples and current number during acquisition */
|
||||
DLL int __stdcall GatheringExternalDataGet (int SocketIndex, int IndexPoint, char * DataBufferLine); /* Get a data line from external gathering buffer */
|
||||
DLL int __stdcall GatheringExternalStopAndSave (int SocketIndex); /* Stop acquisition and save data */
|
||||
DLL int __stdcall GlobalArrayGet (int SocketIndex, int Number, char * ValueString); /* Get global array value */
|
||||
DLL int __stdcall GlobalArraySet (int SocketIndex, int Number, char * ValueString); /* Set global array value */
|
||||
DLL int __stdcall DoubleGlobalArrayGet (int SocketIndex, int Number, double * DoubleValue); /* Get double global array value */
|
||||
DLL int __stdcall DoubleGlobalArraySet (int SocketIndex, int Number, double DoubleValue); /* Set double global array value */
|
||||
DLL int __stdcall GPIOAnalogGet (int SocketIndex, int NbElements, char * GPIONameList, double AnalogValue[]); /* Read analog input or analog output for one or few input */
|
||||
DLL int __stdcall GPIOAnalogSet (int SocketIndex, int NbElements, char * GPIONameList, double AnalogOutputValue[]); /* Set analog output for one or few output */
|
||||
DLL int __stdcall GPIOAnalogGainGet (int SocketIndex, int NbElements, char * GPIONameList, int AnalogInputGainValue[]); /* Read analog input gain (1, 2, 4 or 8) for one or few input */
|
||||
DLL int __stdcall GPIOAnalogGainSet (int SocketIndex, int NbElements, char * GPIONameList, int AnalogInputGainValue[]); /* Set analog input gain (1, 2, 4 or 8) for one or few input */
|
||||
DLL int __stdcall GPIODigitalGet (int SocketIndex, char * GPIOName, unsigned short * DigitalValue); /* Read digital output or digital input */
|
||||
DLL int __stdcall GPIODigitalSet (int SocketIndex, char * GPIOName, unsigned short Mask, unsigned short DigitalOutputValue); /* Set Digital Output for one or few output TTL */
|
||||
DLL int __stdcall GroupAccelerationSetpointGet (int SocketIndex, char * GroupName, int NbElements, double SetpointAcceleration[]); /* Return setpoint accelerations */
|
||||
DLL int __stdcall GroupAnalogTrackingModeEnable (int SocketIndex, char * GroupName, char * Type); /* Enable Analog Tracking mode on selected group */
|
||||
DLL int __stdcall GroupAnalogTrackingModeDisable (int SocketIndex, char * GroupName); /* Disable Analog Tracking mode on selected group */
|
||||
DLL int __stdcall GroupCorrectorOutputGet (int SocketIndex, char * GroupName, int NbElements, double CorrectorOutput[]); /* Return corrector outputs */
|
||||
DLL int __stdcall GroupCurrentFollowingErrorGet (int SocketIndex, char * GroupName, int NbElements, double CurrentFollowingError[]); /* Return current following errors */
|
||||
DLL int __stdcall GroupHomeSearch (int SocketIndex, char * GroupName); /* Start home search sequence */
|
||||
DLL int __stdcall GroupHomeSearchAndRelativeMove (int SocketIndex, char * GroupName, int NbElements, double TargetDisplacement[]); /* Start home search sequence and execute a displacement */
|
||||
DLL int __stdcall GroupInitialize (int SocketIndex, char * GroupName); /* Start the initialization */
|
||||
DLL int __stdcall GroupInitializeWithEncoderCalibration (int SocketIndex, char * GroupName); /* Start the initialization with encoder calibration */
|
||||
DLL int __stdcall GroupJogParametersSet (int SocketIndex, char * GroupName, int NbElements, double Velocity[], double Acceleration[]); /* Modify Jog parameters on selected group and activate the continuous move */
|
||||
DLL int __stdcall GroupJogParametersGet (int SocketIndex, char * GroupName, int NbElements, double Velocity[], double Acceleration[]); /* Get Jog parameters on selected group */
|
||||
DLL int __stdcall GroupJogCurrentGet (int SocketIndex, char * GroupName, int NbElements, double Velocity[], double Acceleration[]); /* Get Jog current on selected group */
|
||||
DLL int __stdcall GroupJogModeEnable (int SocketIndex, char * GroupName); /* Enable Jog mode on selected group */
|
||||
DLL int __stdcall GroupJogModeDisable (int SocketIndex, char * GroupName); /* Disable Jog mode on selected group */
|
||||
DLL int __stdcall GroupKill (int SocketIndex, char * GroupName); /* Kill the group */
|
||||
DLL int __stdcall GroupMoveAbort (int SocketIndex, char * GroupName); /* Abort a move */
|
||||
DLL int __stdcall GroupMoveAbsolute (int SocketIndex, char * GroupName, int NbElements, double TargetPosition[]); /* Do an absolute move */
|
||||
DLL int __stdcall GroupMoveRelative (int SocketIndex, char * GroupName, int NbElements, double TargetDisplacement[]); /* Do a relative move */
|
||||
DLL int __stdcall GroupMotionDisable (int SocketIndex, char * GroupName); /* Set Motion disable on selected group */
|
||||
DLL int __stdcall GroupMotionEnable (int SocketIndex, char * GroupName); /* Set Motion enable on selected group */
|
||||
DLL int __stdcall GroupPositionCorrectedProfilerGet (int SocketIndex, char * GroupName, double PositionX, double PositionY, double * CorrectedProfilerPositionX, double * CorrectedProfilerPositionY); /* Return corrected profiler positions */
|
||||
DLL int __stdcall GroupPositionCurrentGet (int SocketIndex, char * GroupName, int NbElements, double CurrentEncoderPosition[]); /* Return current positions */
|
||||
DLL int __stdcall GroupPositionPCORawEncoderGet (int SocketIndex, char * GroupName, double PositionX, double PositionY, double * PCORawPositionX, double * PCORawPositionY); /* Return PCO raw encoder positions */
|
||||
DLL int __stdcall GroupPositionSetpointGet (int SocketIndex, char * GroupName, int NbElements, double SetPointPosition[]); /* Return setpoint positions */
|
||||
DLL int __stdcall GroupPositionTargetGet (int SocketIndex, char * GroupName, int NbElements, double TargetPosition[]); /* Return target positions */
|
||||
DLL int __stdcall GroupReferencingActionExecute (int SocketIndex, char * PositionerName, char * ReferencingAction, char * ReferencingSensor, double ReferencingParameter); /* Execute an action in referencing mode */
|
||||
DLL int __stdcall GroupReferencingStart (int SocketIndex, char * GroupName); /* Enter referencing mode */
|
||||
DLL int __stdcall GroupReferencingStop (int SocketIndex, char * GroupName); /* Exit referencing mode */
|
||||
DLL int __stdcall GroupStatusGet (int SocketIndex, char * GroupName, int * Status); /* Return group status */
|
||||
DLL int __stdcall GroupStatusStringGet (int SocketIndex, int GroupStatusCode, char * GroupStatusString); /* Return the group status string corresponding to the group status code */
|
||||
DLL int __stdcall GroupVelocityCurrentGet (int SocketIndex, char * GroupName, int NbElements, double CurrentVelocity[]); /* Return current velocities */
|
||||
DLL int __stdcall KillAll (int SocketIndex); /* Put all groups in 'Not initialized' state */
|
||||
DLL int __stdcall PositionerAnalogTrackingPositionParametersGet (int SocketIndex, char * PositionerName, char * GPIOName, double * Offset, double * Scale, double * Velocity, double * Acceleration); /* Read dynamic parameters for one axe of a group for a future analog tracking position */
|
||||
DLL int __stdcall PositionerAnalogTrackingPositionParametersSet (int SocketIndex, char * PositionerName, char * GPIOName, double Offset, double Scale, double Velocity, double Acceleration); /* Update dynamic parameters for one axe of a group for a future analog tracking position */
|
||||
DLL int __stdcall PositionerAnalogTrackingVelocityParametersGet (int SocketIndex, char * PositionerName, char * GPIOName, double * Offset, double * Scale, double * DeadBandThreshold, int * Order, double * Velocity, double * Acceleration); /* Read dynamic parameters for one axe of a group for a future analog tracking velocity */
|
||||
DLL int __stdcall PositionerAnalogTrackingVelocityParametersSet (int SocketIndex, char * PositionerName, char * GPIOName, double Offset, double Scale, double DeadBandThreshold, int Order, double Velocity, double Acceleration); /* Update dynamic parameters for one axe of a group for a future analog tracking velocity */
|
||||
DLL int __stdcall PositionerBacklashGet (int SocketIndex, char * PositionerName, double * BacklashValue, char * BacklaskStatus); /* Read backlash value and status */
|
||||
DLL int __stdcall PositionerBacklashSet (int SocketIndex, char * PositionerName, double BacklashValue); /* Set backlash value */
|
||||
DLL int __stdcall PositionerBacklashEnable (int SocketIndex, char * PositionerName); /* Enable the backlash */
|
||||
DLL int __stdcall PositionerBacklashDisable (int SocketIndex, char * PositionerName); /* Disable the backlash */
|
||||
DLL int __stdcall PositionerCorrectorNotchFiltersSet (int SocketIndex, char * PositionerName, double NotchFrequency1, double NotchBandwith1, double NotchGain1, double NotchFrequency2, double NotchBandwith2, double NotchGain2); /* Update filters parameters */
|
||||
DLL int __stdcall PositionerCorrectorNotchFiltersGet (int SocketIndex, char * PositionerName, double * NotchFrequency1, double * NotchBandwith1, double * NotchGain1, double * NotchFrequency2, double * NotchBandwith2, double * NotchGain2); /* Read filters parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIDFFAccelerationSet (int SocketIndex, char * PositionerName, bool ClosedLoopStatus, double KP, double KI, double KD, double KS, double IntegrationTime, double DerivativeFilterCutOffFrequency, double GKP, double GKI, double GKD, double KForm, double FeedForwardGainAcceleration); /* Update corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIDFFAccelerationGet (int SocketIndex, char * PositionerName, bool * ClosedLoopStatus, double * KP, double * KI, double * KD, double * KS, double * IntegrationTime, double * DerivativeFilterCutOffFrequency, double * GKP, double * GKI, double * GKD, double * KForm, double * FeedForwardGainAcceleration); /* Read corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIDFFVelocitySet (int SocketIndex, char * PositionerName, bool ClosedLoopStatus, double KP, double KI, double KD, double KS, double IntegrationTime, double DerivativeFilterCutOffFrequency, double GKP, double GKI, double GKD, double KForm, double FeedForwardGainVelocity); /* Update corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIDFFVelocityGet (int SocketIndex, char * PositionerName, bool * ClosedLoopStatus, double * KP, double * KI, double * KD, double * KS, double * IntegrationTime, double * DerivativeFilterCutOffFrequency, double * GKP, double * GKI, double * GKD, double * KForm, double * FeedForwardGainVelocity); /* Read corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIDDualFFVoltageSet (int SocketIndex, char * PositionerName, bool ClosedLoopStatus, double KP, double KI, double KD, double KS, double IntegrationTime, double DerivativeFilterCutOffFrequency, double GKP, double GKI, double GKD, double KForm, double FeedForwardGainVelocity, double FeedForwardGainAcceleration, double Friction); /* Update corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIDDualFFVoltageGet (int SocketIndex, char * PositionerName, bool * ClosedLoopStatus, double * KP, double * KI, double * KD, double * KS, double * IntegrationTime, double * DerivativeFilterCutOffFrequency, double * GKP, double * GKI, double * GKD, double * KForm, double * FeedForwardGainVelocity, double * FeedForwardGainAcceleration, double * Friction); /* Read corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIPositionSet (int SocketIndex, char * PositionerName, bool ClosedLoopStatus, double KP, double KI, double IntegrationTime); /* Update corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorPIPositionGet (int SocketIndex, char * PositionerName, bool * ClosedLoopStatus, double * KP, double * KI, double * IntegrationTime); /* Read corrector parameters */
|
||||
DLL int __stdcall PositionerCorrectorTypeGet (int SocketIndex, char * PositionerName, char * CorrectorType); /* Read corrector type */
|
||||
DLL int __stdcall PositionerCurrentVelocityAccelerationFiltersGet (int SocketIndex, char * PositionerName, double * CurrentVelocityCutOffFrequency, double * CurrentAccelerationCutOffFrequency); /* Get current velocity and acceleration cutoff frequencies */
|
||||
DLL int __stdcall PositionerCurrentVelocityAccelerationFiltersSet (int SocketIndex, char * PositionerName, double CurrentVelocityCutOffFrequency, double CurrentAccelerationCutOffFrequency); /* Set current velocity and acceleration cutoff frequencies */
|
||||
DLL int __stdcall PositionerDriverFiltersGet (int SocketIndex, char * PositionerName, double * KI, double * NotchFrequency, double * NotchBandwidth, double * NotchGain, double * LowpassFrequency); /* Get driver filters parameters */
|
||||
DLL int __stdcall PositionerDriverFiltersSet (int SocketIndex, char * PositionerName, double KI, double NotchFrequency, double NotchBandwidth, double NotchGain, double LowpassFrequency); /* Set driver filters parameters */
|
||||
DLL int __stdcall PositionerDriverPositionOffsetsGet (int SocketIndex, char * PositionerName, double * StagePositionOffset, double * GagePositionOffset); /* Get driver stage and gage position offset */
|
||||
DLL int __stdcall PositionerDriverStatusGet (int SocketIndex, char * PositionerName, int * DriverStatus); /* Read positioner driver status */
|
||||
DLL int __stdcall PositionerDriverStatusStringGet (int SocketIndex, int PositionerDriverStatus, char * PositionerDriverStatusString); /* Return the positioner driver status string corresponding to the positioner error code */
|
||||
DLL int __stdcall PositionerEncoderAmplitudeValuesGet (int SocketIndex, char * PositionerName, double * CalibrationSinusAmplitude, double * CurrentSinusAmplitude, double * CalibrationCosinusAmplitude, double * CurrentCosinusAmplitude); /* Read analog interpolated encoder amplitude values */
|
||||
DLL int __stdcall PositionerEncoderCalibrationParametersGet (int SocketIndex, char * PositionerName, double * SinusOffset, double * CosinusOffset, double * DifferentialGain, double * PhaseCompensation); /* Read analog interpolated encoder calibration parameters */
|
||||
DLL int __stdcall PositionerErrorGet (int SocketIndex, char * PositionerName, int * ErrorCode); /* Read and clear positioner error code */
|
||||
DLL int __stdcall PositionerErrorRead (int SocketIndex, char * PositionerName, int * ErrorCode); /* Read only positioner error code without clear it */
|
||||
DLL int __stdcall PositionerErrorStringGet (int SocketIndex, int PositionerErrorCode, char * PositionerErrorString); /* Return the positioner status string corresponding to the positioner error code */
|
||||
DLL int __stdcall PositionerExcitationSignalGet (int SocketIndex, char * PositionerName, int * Mode, double * Frequency, double * Amplitude, double * Time); /* Read disturbing signal parameters */
|
||||
DLL int __stdcall PositionerExcitationSignalSet (int SocketIndex, char * PositionerName, int Mode, double Frequency, double Amplitude, double Time); /* Update disturbing signal parameters */
|
||||
DLL int __stdcall PositionerExternalLatchPositionGet (int SocketIndex, char * PositionerName, double * Position); /* Read external latch position */
|
||||
DLL int __stdcall PositionerHardwareStatusGet (int SocketIndex, char * PositionerName, int * HardwareStatus); /* Read positioner hardware status */
|
||||
DLL int __stdcall PositionerHardwareStatusStringGet (int SocketIndex, int PositionerHardwareStatus, char * PositionerHardwareStatusString); /* Return the positioner hardware status string corresponding to the positioner error code */
|
||||
DLL int __stdcall PositionerHardInterpolatorFactorGet (int SocketIndex, char * PositionerName, int * InterpolationFactor); /* Get hard interpolator parameters */
|
||||
DLL int __stdcall PositionerHardInterpolatorFactorSet (int SocketIndex, char * PositionerName, int InterpolationFactor); /* Set hard interpolator parameters */
|
||||
DLL int __stdcall PositionerMaximumVelocityAndAccelerationGet (int SocketIndex, char * PositionerName, double * MaximumVelocity, double * MaximumAcceleration); /* Return maximum velocity and acceleration of the positioner */
|
||||
DLL int __stdcall PositionerMotionDoneGet (int SocketIndex, char * PositionerName, double * PositionWindow, double * VelocityWindow, double * CheckingTime, double * MeanPeriod, double * TimeOut); /* Read motion done parameters */
|
||||
DLL int __stdcall PositionerMotionDoneSet (int SocketIndex, char * PositionerName, double PositionWindow, double VelocityWindow, double CheckingTime, double MeanPeriod, double TimeOut); /* Update motion done parameters */
|
||||
DLL int __stdcall PositionerPositionCompareAquadBAlwaysEnable (int SocketIndex, char * PositionerName); /* Enable AquadB signal in always mode */
|
||||
DLL int __stdcall PositionerPositionCompareAquadBWindowedGet (int SocketIndex, char * PositionerName, double * MinimumPosition, double * MaximumPosition, bool * EnableState); /* Read position compare AquadB windowed parameters */
|
||||
DLL int __stdcall PositionerPositionCompareAquadBWindowedSet (int SocketIndex, char * PositionerName, double MinimumPosition, double MaximumPosition); /* Set position compare AquadB windowed parameters */
|
||||
DLL int __stdcall PositionerPositionCompareGet (int SocketIndex, char * PositionerName, double * MinimumPosition, double * MaximumPosition, double * PositionStep, bool * EnableState); /* Read position compare parameters */
|
||||
DLL int __stdcall PositionerPositionCompareSet (int SocketIndex, char * PositionerName, double MinimumPosition, double MaximumPosition, double PositionStep); /* Set position compare parameters */
|
||||
DLL int __stdcall PositionerPositionCompareEnable (int SocketIndex, char * PositionerName); /* Enable position compare */
|
||||
DLL int __stdcall PositionerPositionCompareDisable (int SocketIndex, char * PositionerName); /* Disable position compare */
|
||||
DLL int __stdcall PositionerPositionComparePulseParametersGet (int SocketIndex, char * PositionerName, double * PCOPulseWidth, double * EncoderSettlingTime); /* Get position compare PCO pulse parameters */
|
||||
DLL int __stdcall PositionerPositionComparePulseParametersSet (int SocketIndex, char * PositionerName, double PCOPulseWidth, double EncoderSettlingTime); /* Set position compare PCO pulse parameters */
|
||||
DLL int __stdcall PositionerRawEncoderPositionGet (int SocketIndex, char * PositionerName, double UserEncoderPosition, double * RawEncoderPosition); /* Get the raw encoder position */
|
||||
DLL int __stdcall PositionersEncoderIndexDifferenceGet (int SocketIndex, char * PositionerName, double * distance); /* Return the difference between index of primary axis and secondary axis (only after homesearch) */
|
||||
DLL int __stdcall PositionerSGammaExactVelocityAjustedDisplacementGet (int SocketIndex, char * PositionerName, double DesiredDisplacement, double * AdjustedDisplacement); /* Return adjusted displacement to get exact velocity */
|
||||
DLL int __stdcall PositionerSGammaParametersGet (int SocketIndex, char * PositionerName, double * Velocity, double * Acceleration, double * MinimumTjerkTime, double * MaximumTjerkTime); /* Read dynamic parameters for one axe of a group for a future displacement */
|
||||
DLL int __stdcall PositionerSGammaParametersSet (int SocketIndex, char * PositionerName, double Velocity, double Acceleration, double MinimumTjerkTime, double MaximumTjerkTime); /* Update dynamic parameters for one axe of a group for a future displacement */
|
||||
DLL int __stdcall PositionerSGammaPreviousMotionTimesGet (int SocketIndex, char * PositionerName, double * SettingTime, double * SettlingTime); /* Read SettingTime and SettlingTime */
|
||||
DLL int __stdcall PositionerStageParameterGet (int SocketIndex, char * PositionerName, char * ParameterName, char * ParameterValue); /* Return the stage parameter */
|
||||
DLL int __stdcall PositionerStageParameterSet (int SocketIndex, char * PositionerName, char * ParameterName, char * ParameterValue); /* Save the stage parameter */
|
||||
DLL int __stdcall PositionerTimeFlasherGet (int SocketIndex, char * PositionerName, double * MinimumPosition, double * MaximumPosition, double * PositionStep, bool * EnableState); /* Read time flasher parameters */
|
||||
DLL int __stdcall PositionerTimeFlasherSet (int SocketIndex, char * PositionerName, double MinimumPosition, double MaximumPosition, double TimeInterval); /* Set time flasher parameters */
|
||||
DLL int __stdcall PositionerTimeFlasherEnable (int SocketIndex, char * PositionerName); /* Enable time flasher */
|
||||
DLL int __stdcall PositionerTimeFlasherDisable (int SocketIndex, char * PositionerName); /* Disable time flasher */
|
||||
DLL int __stdcall PositionerUserTravelLimitsGet (int SocketIndex, char * PositionerName, double * UserMinimumTarget, double * UserMaximumTarget); /* Read UserMinimumTarget and UserMaximumTarget */
|
||||
DLL int __stdcall PositionerUserTravelLimitsSet (int SocketIndex, char * PositionerName, double UserMinimumTarget, double UserMaximumTarget); /* Update UserMinimumTarget and UserMaximumTarget */
|
||||
DLL int __stdcall PositionerDACOffsetGet (int SocketIndex, char * PositionerName, short * DACOffset1, short * DACOffset2); /* Get DAC offsets */
|
||||
DLL int __stdcall PositionerDACOffsetSet (int SocketIndex, char * PositionerName, short DACOffset1, short DACOffset2); /* Set DAC offsets */
|
||||
DLL int __stdcall PositionerDACOffsetDualGet (int SocketIndex, char * PositionerName, short * PrimaryDACOffset1, short * PrimaryDACOffset2, short * SecondaryDACOffset1, short * SecondaryDACOffset2); /* Get dual DAC offsets */
|
||||
DLL int __stdcall PositionerDACOffsetDualSet (int SocketIndex, char * PositionerName, short PrimaryDACOffset1, short PrimaryDACOffset2, short SecondaryDACOffset1, short SecondaryDACOffset2); /* Set dual DAC offsets */
|
||||
DLL int __stdcall PositionerCorrectorAutoTuning (int SocketIndex, char * PositionerName, int TuningMode, double * KP, double * KI, double * KD); /* Astrom&Hagglund based auto-tuning */
|
||||
DLL int __stdcall PositionerAccelerationAutoScaling (int SocketIndex, char * PositionerName, double * Scaling); /* Astrom&Hagglund based auto-scaling */
|
||||
DLL int __stdcall MultipleAxesPVTVerification (int SocketIndex, char * GroupName, char * TrajectoryFileName); /* Multiple axes PVT trajectory verification */
|
||||
DLL int __stdcall MultipleAxesPVTVerificationResultGet (int SocketIndex, char * PositionerName, char * FileName, double * MinimumPosition, double * MaximumPosition, double * MaximumVelocity, double * MaximumAcceleration); /* Multiple axes PVT trajectory verification result get */
|
||||
DLL int __stdcall MultipleAxesPVTExecution (int SocketIndex, char * GroupName, char * TrajectoryFileName, int ExecutionNumber); /* Multiple axes PVT trajectory execution */
|
||||
DLL int __stdcall MultipleAxesPVTParametersGet (int SocketIndex, char * GroupName, char * FileName, int * CurrentElementNumber); /* Multiple axes PVT trajectory get parameters */
|
||||
DLL int __stdcall MultipleAxesPVTPulseOutputSet (int SocketIndex, char * GroupName, int StartElement, int EndElement, double TimeInterval); /* Configure pulse output on trajectory */
|
||||
DLL int __stdcall MultipleAxesPVTPulseOutputGet (int SocketIndex, char * GroupName, int * StartElement, int * EndElement, double * TimeInterval); /* Get pulse output on trajectory configuration */
|
||||
DLL int __stdcall SingleAxisSlaveModeEnable (int SocketIndex, char * GroupName); /* Enable the slave mode */
|
||||
DLL int __stdcall SingleAxisSlaveModeDisable (int SocketIndex, char * GroupName); /* Disable the slave mode */
|
||||
DLL int __stdcall SingleAxisSlaveParametersSet (int SocketIndex, char * GroupName, char * PositionerName, double Ratio); /* Set slave parameters */
|
||||
DLL int __stdcall SingleAxisSlaveParametersGet (int SocketIndex, char * GroupName, char * PositionerName, double * Ratio); /* Get slave parameters */
|
||||
DLL int __stdcall SpindleSlaveModeEnable (int SocketIndex, char * GroupName); /* Enable the slave mode */
|
||||
DLL int __stdcall SpindleSlaveModeDisable (int SocketIndex, char * GroupName); /* Disable the slave mode */
|
||||
DLL int __stdcall SpindleSlaveParametersSet (int SocketIndex, char * GroupName, char * PositionerName, double Ratio); /* Set slave parameters */
|
||||
DLL int __stdcall SpindleSlaveParametersGet (int SocketIndex, char * GroupName, char * PositionerName, double * Ratio); /* Get slave parameters */
|
||||
DLL int __stdcall GroupSpinParametersSet (int SocketIndex, char * GroupName, double Velocity, double Acceleration); /* Modify Spin parameters on selected group and activate the continuous move */
|
||||
DLL int __stdcall GroupSpinParametersGet (int SocketIndex, char * GroupName, double * Velocity, double * Acceleration); /* Get Spin parameters on selected group */
|
||||
DLL int __stdcall GroupSpinCurrentGet (int SocketIndex, char * GroupName, double * Velocity, double * Acceleration); /* Get Spin current on selected group */
|
||||
DLL int __stdcall GroupSpinModeStop (int SocketIndex, char * GroupName, double Acceleration); /* Stop Spin mode on selected group with specified acceleration */
|
||||
DLL int __stdcall XYLineArcVerification (int SocketIndex, char * GroupName, char * TrajectoryFileName); /* XY trajectory verification */
|
||||
DLL int __stdcall XYLineArcVerificationResultGet (int SocketIndex, char * PositionerName, char * FileName, double * MinimumPosition, double * MaximumPosition, double * MaximumVelocity, double * MaximumAcceleration); /* XY trajectory verification result get */
|
||||
DLL int __stdcall XYLineArcExecution (int SocketIndex, char * GroupName, char * TrajectoryFileName, double Velocity, double Acceleration, int ExecutionNumber); /* XY trajectory execution */
|
||||
DLL int __stdcall XYLineArcParametersGet (int SocketIndex, char * GroupName, char * FileName, double * Velocity, double * Acceleration, int * CurrentElementNumber); /* XY trajectory get parameters */
|
||||
DLL int __stdcall XYLineArcPulseOutputSet (int SocketIndex, char * GroupName, double StartLength, double EndLength, double PathLengthInterval); /* Configure pulse output on trajectory */
|
||||
DLL int __stdcall XYLineArcPulseOutputGet (int SocketIndex, char * GroupName, double * StartLength, double * EndLength, double * PathLengthInterval); /* Get pulse output on trajectory configuration */
|
||||
DLL int __stdcall XYZGroupPositionCorrectedProfilerGet (int SocketIndex, char * GroupName, double PositionX, double PositionY, double PositionZ, double * CorrectedProfilerPositionX, double * CorrectedProfilerPositionY, double * CorrectedProfilerPositionZ); /* Return corrected profiler positions */
|
||||
DLL int __stdcall XYZSplineVerification (int SocketIndex, char * GroupName, char * TrajectoryFileName); /* XYZ trajectory verifivation */
|
||||
DLL int __stdcall XYZSplineVerificationResultGet (int SocketIndex, char * PositionerName, char * FileName, double * MinimumPosition, double * MaximumPosition, double * MaximumVelocity, double * MaximumAcceleration); /* XYZ trajectory verification result get */
|
||||
DLL int __stdcall XYZSplineExecution (int SocketIndex, char * GroupName, char * TrajectoryFileName, double Velocity, double Acceleration); /* XYZ trajectory execution */
|
||||
DLL int __stdcall XYZSplineParametersGet (int SocketIndex, char * GroupName, char * FileName, double * Velocity, double * Acceleration, int * CurrentElementNumber); /* XYZ trajectory get parameters */
|
||||
DLL int __stdcall OptionalModuleExecute (int SocketIndex, char * ModuleFileName, char * TaskName); /* Execute an optional module */
|
||||
DLL int __stdcall OptionalModuleKill (int SocketIndex, char * TaskName); /* Kill an optional module */
|
||||
DLL int __stdcall EEPROMCIESet (int SocketIndex, int CardNumber, char * ReferenceString); /* Set CIE EEPROM reference string */
|
||||
DLL int __stdcall EEPROMDACOffsetCIESet (int SocketIndex, int PlugNumber, double DAC1Offset, double DAC2Offset); /* Set CIE DAC offsets */
|
||||
DLL int __stdcall EEPROMDriverSet (int SocketIndex, int PlugNumber, char * ReferenceString); /* Set Driver EEPROM reference string */
|
||||
DLL int __stdcall EEPROMINTSet (int SocketIndex, int CardNumber, char * ReferenceString); /* Set INT EEPROM reference string */
|
||||
DLL int __stdcall CPUCoreAndBoardSupplyVoltagesGet (int SocketIndex, double * VoltageCPUCore, double * SupplyVoltage1P5V, double * SupplyVoltage3P3V, double * SupplyVoltage5V, double * SupplyVoltage12V, double * SupplyVoltageM12V, double * SupplyVoltageM5V, double * SupplyVoltage5VSB); /* Get power informations */
|
||||
DLL int __stdcall CPUTemperatureAndFanSpeedGet (int SocketIndex, double * CPUTemperature, double * CPUFanSpeed); /* Get CPU temperature and fan speed */
|
||||
DLL int __stdcall ActionListGet (int SocketIndex, char * ActionList); /* Action list */
|
||||
DLL int __stdcall ActionExtendedListGet (int SocketIndex, char * ActionList); /* Action extended list */
|
||||
DLL int __stdcall APIExtendedListGet (int SocketIndex, char * Method); /* API method list */
|
||||
DLL int __stdcall APIListGet (int SocketIndex, char * Method); /* API method list without extended API */
|
||||
DLL int __stdcall ControllerStatusListGet (int SocketIndex, char * ControllerStatusList); /* Controller status list */
|
||||
DLL int __stdcall ErrorListGet (int SocketIndex, char * ErrorsList); /* Error list */
|
||||
DLL int __stdcall EventListGet (int SocketIndex, char * EventList); /* General event list */
|
||||
DLL int __stdcall GatheringListGet (int SocketIndex, char * list); /* Gathering type list */
|
||||
DLL int __stdcall GatheringExtendedListGet (int SocketIndex, char * list); /* Gathering type extended list */
|
||||
DLL int __stdcall GatheringExternalListGet (int SocketIndex, char * list); /* External Gathering type list */
|
||||
DLL int __stdcall GroupStatusListGet (int SocketIndex, char * GroupStatusList); /* Group status list */
|
||||
DLL int __stdcall HardwareInternalListGet (int SocketIndex, char * InternalHardwareList); /* Internal hardware list */
|
||||
DLL int __stdcall HardwareDriverAndStageGet (int SocketIndex, int PlugNumber, char * DriverName, char * StageName); /* Smart hardware */
|
||||
DLL int __stdcall ObjectsListGet (int SocketIndex, char * ObjectsList); /* Group name and positioner name */
|
||||
DLL int __stdcall PositionerErrorListGet (int SocketIndex, char * PositionerErrorList); /* Positioner error list */
|
||||
DLL int __stdcall PositionerHardwareStatusListGet (int SocketIndex, char * PositionerHardwareStatusList); /* Positioner hardware status list */
|
||||
DLL int __stdcall PositionerDriverStatusListGet (int SocketIndex, char * PositionerDriverStatusList); /* Positioner driver status list */
|
||||
DLL int __stdcall ReferencingActionListGet (int SocketIndex, char * list); /* Get referencing action list */
|
||||
DLL int __stdcall ReferencingSensorListGet (int SocketIndex, char * list); /* Get referencing sensor list */
|
||||
DLL int __stdcall GatheringUserDatasGet (int SocketIndex, double * UserData1, double * UserData2, double * UserData3, double * UserData4, double * UserData5, double * UserData6, double * UserData7, double * UserData8); /* Return user data values */
|
||||
DLL int __stdcall ControllerMotionKernelPeriodMinMaxGet (int SocketIndex, double * MinimumCorrectorPeriod, double * MaximumCorrectorPeriod, double * MinimumProfilerPeriod, double * MaximumProfilerPeriod, double * MinimumServitudesPeriod, double * MaximumServitudesPeriod); /* Get controller motion kernel min/max periods */
|
||||
DLL int __stdcall ControllerMotionKernelPeriodMinMaxReset (int SocketIndex); /* Reset controller motion kernel min/max periods */
|
||||
DLL int __stdcall SocketsStatusGet (int SocketIndex, char * SocketsStatus); /* Get sockets current status */
|
||||
DLL int __stdcall TestTCP (int SocketIndex, char * InputString, char * ReturnString); /* Test TCP/IP transfert */
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,107 +0,0 @@
|
||||
/*///////////////////////////////////////////////////////////////////
|
||||
* Created header file XPS_C8_errors.h for XPS function errors
|
||||
*/
|
||||
|
||||
/* TCL interpretor error */
|
||||
#define ERR_TCL_INTERPRETOR_ERROR 1
|
||||
|
||||
/* No error */
|
||||
#define SUCCESS 0
|
||||
|
||||
/* XPS errors */
|
||||
#define ERR_BUSY_SOCKET -1
|
||||
#define ERR_TCP_TIMEOUT -2
|
||||
#define ERR_STRING_TOO_LONG -3
|
||||
#define ERR_UNKNOWN_COMMAND -4
|
||||
#define ERR_POSITIONER_ERROR -5
|
||||
#define ERR_WRONG_FORMAT -7
|
||||
#define ERR_WRONG_OBJECT_TYPE -8
|
||||
#define ERR_WRONG_PARAMETERS_NUMBER -9
|
||||
#define ERR_WRONG_TYPE -10
|
||||
#define ERR_WRONG_TYPE_BIT_WORD -11
|
||||
#define ERR_WRONG_TYPE_BOOL -12
|
||||
#define ERR_WRONG_TYPE_CHAR -13
|
||||
#define ERR_WRONG_TYPE_DOUBLE -14
|
||||
#define ERR_WRONG_TYPE_INT -15
|
||||
#define ERR_WRONG_TYPE_UNSIGNEDINT -16
|
||||
#define ERR_PARAMETER_OUT_OF_RANGE -17
|
||||
#define ERR_POSITIONER_NAME -18
|
||||
#define ERR_GROUP_NAME -19
|
||||
#define ERR_FATAL_INIT -20
|
||||
#define ERR_IN_INITIALIZATION -21
|
||||
#define ERR_NOT_ALLOWED_ACTION -22
|
||||
#define ERR_POSITION_COMPARE_NOT_SET -23
|
||||
#define ERR_UNCOMPATIBLE -24
|
||||
#define ERR_FOLLOWING_ERROR -25
|
||||
#define ERR_EMERGENCY_SIGNAL -26
|
||||
#define ERR_GROUP_ABORT_MOTION -27
|
||||
#define ERR_GROUP_HOME_SEARCH_TIMEOUT -28
|
||||
#define ERR_MNEMOTYPEGATHERING -29
|
||||
#define ERR_GATHERING_NOT_STARTED -30
|
||||
#define ERR_HOME_OUT_RANGE -31
|
||||
#define ERR_GATHERING_NOT_CONFIGURED -32
|
||||
#define ERR_GROUP_MOTION_DONE_TIMEOUT -33
|
||||
#define ERR_TRAVEL_LIMITS -35
|
||||
#define ERR_UNKNOWN_TCL_FILE -36
|
||||
#define ERR_TCL_SCRIPT_KILL -38
|
||||
#define ERR_TCL_INTERPRETOR -37
|
||||
#define ERR_MNEMO_ACTION -39
|
||||
#define ERR_MNEMO_EVENT -40
|
||||
#define ERR_SLAVE_CONFIGURATION -41
|
||||
#define ERR_JOG_OUT_OF_RANGE -42
|
||||
#define ERR_GATHERING_RUNNING -43
|
||||
#define ERR_SLAVE -44
|
||||
#define ERR_END_OF_RUN -45
|
||||
#define ERR_NOT_ALLOWED_BACKLASH -46
|
||||
#define ERR_WRONG_TCL_TASKNAME -47
|
||||
#define ERR_BASE_VELOCITY -48
|
||||
#define ERR_GROUP_HOME_SEARCH_ZM_ERROR -49
|
||||
#define ERR_MOTOR_INITIALIZATION_ERROR -50
|
||||
#define ERR_SPIN_OUT_OF_RANGE -51
|
||||
#define ERR_WRITE_FILE -60
|
||||
#define ERR_READ_FILE -61
|
||||
#define ERR_TRAJ_ELEM_TYPE -62
|
||||
#define ERR_TRAJ_ELEM_RADIUS -63
|
||||
#define ERR_TRAJ_ELEM_SWEEP -64
|
||||
#define ERR_TRAJ_ELEM_LINE -65
|
||||
#define ERR_TRAJ_EMPTY -66
|
||||
#define ERR_TRAJ_VEL_LIMIT -68
|
||||
#define ERR_TRAJ_ACC_LIMIT -69
|
||||
#define ERR_TRAJ_FINAL_VELOCITY -70
|
||||
#define ERR_MSG_QUEUE -71
|
||||
#define ERR_TRAJ_INITIALIZATION -72
|
||||
#define ERR_END_OF_FILE -73
|
||||
#define ERR_READ_FILE_PARAMETER_KEY -74
|
||||
#define ERR_TRAJ_TIME -75
|
||||
#define ERR_EVENTS_NOT_CONFIGURED -80
|
||||
#define ERR_ACTIONS_NOT_CONFIGURED -81
|
||||
#define ERR_EVENT_BUFFER_FULL -82
|
||||
#define ERR_EVENT_ID_UNDEFINED -83
|
||||
#define ERR_HOME_SEARCH_GANTRY_TOLERANCE_ERROR -85
|
||||
#define ERR_FOCUS_RESERVED_SOCKET -90
|
||||
#define ERR_FOCUS_BUSY_EVENT_SCHEDULER -91
|
||||
#define ERR_OPTIONAL_EXTERNAL_MODULE_FILE -94
|
||||
#define ERR_OPTIONAL_EXTERNAL_MODULE_EXECUTE -95
|
||||
#define ERR_OPTIONAL_EXTERNAL_MODULE_KILL -96
|
||||
#define ERR_OPTIONAL_EXTERNAL_MODULE_LOAD -97
|
||||
#define ERR_OPTIONAL_EXTERNAL_MODULE_UNLOAD -98
|
||||
#define ERR_FATAL_EXTERNAL_MODULE_LOAD -99
|
||||
#define ERR_INTERNAL_ERROR -100
|
||||
#define ERR_RELAY_FEEDBACK_TEST_NO_OSCILLATION -101
|
||||
#define ERR_RELAY_FEEDBACK_TEST_SIGNAL_NOISY -102
|
||||
#define ERR_SIGNAL_POINTS_NOT_ENOUGH -103
|
||||
#define ERR_PID_TUNING_INITIALIZATION -104
|
||||
#define ERR_SCALING_CALIBRATION -105
|
||||
#define ERR_WRONG_USERNAME_OR_PASSWORD -106
|
||||
#define ERR_NEED_ADMINISTRATOR_RIGHTS -107
|
||||
#define ERR_SOCKET_CLOSED_BY_ADMIN -108
|
||||
#define ERR_NEED_TO_BE_HOMED_AT_LEAST_ONCE -109
|
||||
#define ERR_NOT_ALLOWED_FOR_GANTRY -110
|
||||
#define ERR_GATHERING_BUFFER_FULL -111
|
||||
#define ERR_EXCITATION_SIGNAL_INITIALIZATION -112
|
||||
#define ERR_BOTH_ENDS_OF_RUNS_ACTIVATED -113
|
||||
#define ERR_GROUP_CLAMPING_TIMEOUT -114
|
||||
#define ERR_HARDWARE_FUNCTION_NOT_SUPPORTED -115
|
||||
#define ERR_EXTERNAL_DRIVER_INIT -116
|
||||
#define ERR_FUNCTION_ONLY_ALLOWED_IN_DISABLED_STATE -117
|
||||
#define ERR_NOT_ALLOWED_DRIVER_NOT_INITIALIZED -118
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,327 +0,0 @@
|
||||
/* This script was adapted from the Newport Socket.cpp code
|
||||
to provide TCP/IP sockets for the XPSC8 motion controller
|
||||
using EPICS asynOctetSyncIO.cc
|
||||
|
||||
By Jon Kelly July 2005
|
||||
Re-written by Mark Rivers March 2006
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#ifdef vxWorks
|
||||
#else
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
typedef int BOOL;
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsString.h>
|
||||
#include <asynDriver.h>
|
||||
#include <asynOctetSyncIO.h>
|
||||
#include <asynCommonSyncIO.h>
|
||||
#include <drvAsynIPPort.h>
|
||||
#include <epicsExport.h>
|
||||
|
||||
|
||||
/* The maximum number of sockets to XPS controllers. The driver uses
|
||||
* one socket per motor plus one per controller, so a maximum of 9 per controller.
|
||||
* This number is used to create an array because the Newport code uses integers for
|
||||
* the socket ID. */
|
||||
#define MAX_SOCKETS 1000
|
||||
#define PORT_NAME_SIZE 100
|
||||
#define ERROR_STRING_SIZE 100
|
||||
#define DEFAULT_TIMEOUT 0.2
|
||||
#define XPS_TERMINATOR ",EndOfAPI"
|
||||
|
||||
#define MAX_RETRIES 2
|
||||
|
||||
static int nextSocket = 0;
|
||||
|
||||
/* Pointer to the connection info for each socket
|
||||
the asynUser structure is defined in asynDriver.h */
|
||||
typedef struct {
|
||||
asynUser *pasynUser;
|
||||
asynUser *pasynUserCommon;
|
||||
double timeout;
|
||||
char errorString[ERROR_STRING_SIZE];
|
||||
int connected;
|
||||
epicsMutexId mutexId;
|
||||
} socketStruct;
|
||||
static socketStruct socketStructs[MAX_SOCKETS];
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
int ConnectToServer(char *IpAddress, int IpPort, double timeout)
|
||||
{
|
||||
|
||||
char portName[PORT_NAME_SIZE];
|
||||
char ipString[PORT_NAME_SIZE];
|
||||
asynUser *pasynUser, *pasynUserCommon;
|
||||
socketStruct *psock;
|
||||
int status;
|
||||
|
||||
if (nextSocket >= MAX_SOCKETS) {
|
||||
printf("ConnectToServer: too many open sockets, max=%d\n", MAX_SOCKETS);
|
||||
return -1;
|
||||
}
|
||||
/* Create a new asyn port */
|
||||
epicsSnprintf(ipString, PORT_NAME_SIZE, "%s:%d TCP", IpAddress, IpPort);
|
||||
epicsSnprintf(portName, PORT_NAME_SIZE, "%s:%d:%d", IpAddress, IpPort, nextSocket);
|
||||
/* Create port with autoConnect and noProcessEos options */
|
||||
drvAsynIPPortConfigure(portName, ipString, 0, 0, 1);
|
||||
|
||||
/* Connect to driver with asynOctet interface */
|
||||
status = pasynOctetSyncIO->connect(portName, 0, &pasynUser, NULL);
|
||||
if (status != asynSuccess) {
|
||||
printf("ConnectToServer, error calling pasynOctetSyncIO->connect %s\n", pasynUser->errorMessage);
|
||||
return -1;
|
||||
}
|
||||
psock = &socketStructs[nextSocket];
|
||||
psock->pasynUser = pasynUser;
|
||||
|
||||
/* Connect to driver with asynCommon interface */
|
||||
status = pasynCommonSyncIO->connect(portName, 0, &pasynUserCommon, NULL);
|
||||
if (status != asynSuccess) {
|
||||
printf("ConnectToServer, error calling pasynCommonSyncIO->connect %s\n",
|
||||
pasynUserCommon->errorMessage);
|
||||
return -1;
|
||||
}
|
||||
psock->pasynUserCommon = pasynUserCommon;
|
||||
|
||||
/* Create a mutex to prevent more than 1 thread using socket at once
|
||||
* Normally the SyncIO-.writeRead function takes care of this, but for long responses
|
||||
* we can't use a single write/read operation */
|
||||
psock->mutexId = epicsMutexMustCreate();
|
||||
|
||||
psock->timeout = timeout;
|
||||
psock->connected = 1;
|
||||
strcpy(psock->errorString, "");
|
||||
|
||||
nextSocket++;
|
||||
return nextSocket-1;
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void SetTCPTimeout(int SocketIndex, double TimeOut)
|
||||
{
|
||||
if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) {
|
||||
printf("SetTCPTimeout, SocketIndex=%d, must be >=0 and < %d\n", SocketIndex, nextSocket);
|
||||
return;
|
||||
}
|
||||
socketStructs[SocketIndex].timeout = TimeOut;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
void SendAndReceive (int SocketIndex, char buffer[], char valueRtrn[], int returnSize)
|
||||
{
|
||||
size_t nbytesOut;
|
||||
size_t nbytesIn;
|
||||
int eomReason;
|
||||
int bufferLength;
|
||||
socketStruct *psock;
|
||||
int status;
|
||||
int retries;
|
||||
int errStat;
|
||||
size_t nread;
|
||||
|
||||
/* Check to see if the Socket is valid! */
|
||||
|
||||
bufferLength = (int)strlen(buffer);
|
||||
if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) {
|
||||
printf("SendAndReceive: invalid SocketIndex %d\n", SocketIndex);
|
||||
strcpy(valueRtrn,"-22");
|
||||
return;
|
||||
}
|
||||
psock = &socketStructs[SocketIndex];
|
||||
if (!psock->connected) {
|
||||
printf("SendAndReceive: socket not connected %d\n", SocketIndex);
|
||||
strcpy(valueRtrn,"-22");
|
||||
return;
|
||||
}
|
||||
|
||||
epicsMutexMustLock(psock->mutexId);
|
||||
/* If timeout > 0. then we do a write read. If < 0. then write. */
|
||||
|
||||
if (psock->timeout > 0.0) {
|
||||
status = pasynOctetSyncIO->writeRead(psock->pasynUser,
|
||||
(char const *)buffer,
|
||||
bufferLength,
|
||||
valueRtrn,
|
||||
returnSize,
|
||||
psock->timeout,
|
||||
&nbytesOut,
|
||||
&nbytesIn,
|
||||
&eomReason);
|
||||
if ( status != asynSuccess ) {
|
||||
asynPrint(psock->pasynUser, ASYN_TRACE_ERROR,
|
||||
"SendAndReceive error calling writeRead, output=%s status=%d, error=%s\n",
|
||||
buffer, status, psock->pasynUser->errorMessage);
|
||||
}
|
||||
asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"SendAndReceive, sent: '%s', received: '%s'\n",
|
||||
buffer, valueRtrn);
|
||||
nread = nbytesIn;
|
||||
/* Loop until we the response contains ",EndOfAPI" or we get an error */
|
||||
while ((status==asynSuccess) &&
|
||||
(strcmp(valueRtrn + nread - strlen(XPS_TERMINATOR), XPS_TERMINATOR) != 0)) {
|
||||
status = pasynOctetSyncIO->read(psock->pasynUser,
|
||||
&valueRtrn[nread],
|
||||
returnSize-nread,
|
||||
psock->timeout,
|
||||
&nbytesIn,
|
||||
&eomReason);
|
||||
asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"SendAndReceive, received: nread=%d, returnSize-nread=%d, nbytesIn=%d\n",
|
||||
(int)nread, returnSize-nread, (int)nbytesIn);
|
||||
nread += nbytesIn;
|
||||
}
|
||||
} else {
|
||||
/* This is typically used for the "Move" commands, and we don't want to wait for the response */
|
||||
/* Fake the response by putting "-1" (for error) or "0" (for success) in the return string */
|
||||
for (retries=0; retries<MAX_RETRIES; retries++) {
|
||||
status = pasynOctetSyncIO->writeRead(psock->pasynUser,
|
||||
(char const *)buffer,
|
||||
bufferLength,
|
||||
valueRtrn,
|
||||
returnSize,
|
||||
-psock->timeout,
|
||||
&nbytesOut,
|
||||
&nbytesIn,
|
||||
&eomReason);
|
||||
if (status == asynError) {
|
||||
asynPrint(psock->pasynUser, ASYN_TRACE_ERROR,
|
||||
"SendAndReceive error calling write, output=%s status=%d, error=%s\n",
|
||||
buffer, status, psock->pasynUser->errorMessage);
|
||||
strcpy(valueRtrn, "-1");
|
||||
break;
|
||||
}
|
||||
asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"SendAndReceive, sent: '%s'\n", buffer);
|
||||
/* A timeout is OK */
|
||||
if (status == asynTimeout) {
|
||||
asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"SendAndReceive, timeout on read\n");
|
||||
strcpy(valueRtrn, "0");
|
||||
break;
|
||||
} else {
|
||||
asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"SendAndReceive, read: '%s'\n", valueRtrn);
|
||||
errStat = atoi(valueRtrn);
|
||||
if (errStat == 0) break; /* All done */
|
||||
if (errStat == -1) continue; /* Error that previous command not complete */
|
||||
asynPrint(psock->pasynUser, ASYN_TRACE_ERROR,
|
||||
"SendAndReceive unexpected response =%s\n",
|
||||
valueRtrn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (retries == MAX_RETRIES) strcpy(valueRtrn, "0");
|
||||
}
|
||||
epicsMutexUnlock(psock->mutexId);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
int ReadXPSSocket (int SocketIndex, char valueRtrn[], int returnSize, double timeout)
|
||||
{
|
||||
size_t nbytesIn;
|
||||
int eomReason;
|
||||
socketStruct *psock;
|
||||
int status;
|
||||
size_t nread=0;
|
||||
|
||||
/* Check to see if the Socket is valid! */
|
||||
if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) {
|
||||
printf("ReadXPSSocket: invalid SocketIndex %d\n", SocketIndex);
|
||||
strcpy(valueRtrn,"-22");
|
||||
return -1;
|
||||
}
|
||||
psock = &socketStructs[SocketIndex];
|
||||
if (!psock->connected) {
|
||||
printf("ReadXPSSocket: socket not connected %d\n", SocketIndex);
|
||||
strcpy(valueRtrn,"-22");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Loop until we the response contains ",EndOfAPI" or we get an error */
|
||||
do {
|
||||
status = pasynOctetSyncIO->read(psock->pasynUser,
|
||||
&valueRtrn[nread],
|
||||
returnSize-nread,
|
||||
timeout,
|
||||
&nbytesIn,
|
||||
&eomReason);
|
||||
asynPrint(psock->pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"ReadXPSSocket, received: nread=%d, returnSize-nread=%d, nbytesIn=%d\n",
|
||||
(int)nread, returnSize-nread, (int)nbytesIn);
|
||||
nread += nbytesIn;
|
||||
} while ((status==asynSuccess) &&
|
||||
(strcmp(valueRtrn + nread - strlen(XPS_TERMINATOR), XPS_TERMINATOR) != 0));
|
||||
return (int)nread;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************************/
|
||||
void CloseSocket(int SocketIndex)
|
||||
{
|
||||
socketStruct *psock;
|
||||
asynUser *pasynUser;
|
||||
int status;
|
||||
|
||||
if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) {
|
||||
printf("CloseSocket: invalid SocketIndex %d\n", SocketIndex);
|
||||
return;
|
||||
}
|
||||
psock = &socketStructs[SocketIndex];
|
||||
pasynUser = psock->pasynUserCommon;
|
||||
status = pasynCommonSyncIO->disconnectDevice(pasynUser);
|
||||
if (status != asynSuccess ) {
|
||||
asynPrint(pasynUser, ASYN_TRACE_ERROR,
|
||||
"CloseSocket: error calling pasynCommonSyncIO->disconnect, status=%d, %s\n",
|
||||
status, pasynUser->errorMessage);
|
||||
return;
|
||||
}
|
||||
psock->connected = 0;
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void closeXPSSockets(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i<nextSocket; i++) {
|
||||
if (socketStructs[i].connected) CloseSocket(i);
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
char * GetError(int SocketIndex)
|
||||
{
|
||||
if ((SocketIndex < 0) || (SocketIndex >= nextSocket)) {
|
||||
printf("GetError: invalid SocketIndex %d\n", SocketIndex);
|
||||
return (char *)"Invalid socket";
|
||||
}
|
||||
return socketStructs[SocketIndex].errorString;
|
||||
}
|
||||
|
||||
/***************************************************************************************/
|
||||
void strncpyWithEOS(char * szStringOut, const char * szStringIn, int nNumberOfCharToCopy, int nStringOutSize)
|
||||
{
|
||||
if (nNumberOfCharToCopy < nStringOutSize)
|
||||
{
|
||||
strncpy (szStringOut, szStringIn, nNumberOfCharToCopy);
|
||||
szStringOut[nNumberOfCharToCopy] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy (szStringOut, szStringIn, nStringOutSize - 1);
|
||||
szStringOut[nStringOutSize - 1] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
int ReadXPSSocket (int SocketIndex, char valueRtrn[], int returnSize, double timeout);
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
FILENAME... devESP300.cc
|
||||
USAGE... Motor record device level support for Newport ESP300.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 02/19/03
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 05-23-03 rls Converted to R3.14.x.
|
||||
* .02 10-28-03 rls User must set MRES to drive resolution.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
extern struct driver_table ESP300_access;
|
||||
|
||||
/* ----------------Create the dsets for devESP300----------------- */
|
||||
/* static long report(); */
|
||||
static struct driver_table *drvtabptr;
|
||||
static long ESP300_init(int);
|
||||
static long ESP300_init_record(void *);
|
||||
static long ESP300_start_trans(struct motorRecord *);
|
||||
static RTN_STATUS ESP300_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
static RTN_STATUS ESP300_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devESP300 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) ESP300_init, (DEVSUPFUN) ESP300_init_record, NULL},
|
||||
motor_update_values,
|
||||
ESP300_start_trans,
|
||||
ESP300_build_trans,
|
||||
ESP300_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devESP300);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types ESP300_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **ESP300_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for ESP300 stepper motor */
|
||||
static long ESP300_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &ESP300_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &ESP300_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
static long ESP300_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
long rtnval;
|
||||
|
||||
rtnval = motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, ESP300_cards);
|
||||
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
static long ESP300_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
return(motor_start_trans_com(mr, ESP300_cards));
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
static RTN_STATUS ESP300_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
char *msgptr;
|
||||
size_t last;
|
||||
|
||||
/* Remove trailing ';'s from message. */
|
||||
motor_call = &(trans->motor_call);
|
||||
msgptr = motor_call->message;
|
||||
last = strlen(msgptr) - 1;
|
||||
if (msgptr[last] == ';')
|
||||
msgptr[last] = (char) NULL;
|
||||
|
||||
return(motor_end_trans_com(mr, drvtabptr));
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
static RTN_STATUS ESP300_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
char buff[80];
|
||||
int axis, card;
|
||||
size_t size;
|
||||
double dval, cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
axis = motor_call->signal + 1;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
cntrl_units = dval * cntrl->drive_resolution[axis - 1];
|
||||
|
||||
if (ESP300_table[command] > motor_call->type)
|
||||
motor_call->type = ESP300_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->init);
|
||||
strcat(motor_call->message, "\r");
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "%.2dPA%f;", axis, cntrl_units);
|
||||
break;
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "%.2dPR%f;", axis, cntrl_units);
|
||||
break;
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
sprintf(buff, "%.2dOR;", axis);
|
||||
break;
|
||||
case LOAD_POS:
|
||||
sprintf(buff, "%.2dDH%f", axis, cntrl_units);
|
||||
break;
|
||||
case SET_VEL_BASE:
|
||||
sprintf(buff, "%.2dVB%f;", axis, cntrl_units);
|
||||
break;
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "%.2dVA%f;", axis, cntrl_units);
|
||||
break;
|
||||
case SET_ACCEL:
|
||||
sprintf(buff, "%.2dAC%f;%.2dAG%f;", axis, cntrl_units, axis, cntrl_units);
|
||||
break;
|
||||
case GO:
|
||||
/*
|
||||
* The ESP300 starts moving immediately on move commands, GO command
|
||||
* does nothing
|
||||
*/
|
||||
break;
|
||||
case SET_ENC_RATIO:
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "%.2dST;", axis);
|
||||
break;
|
||||
case JOG:
|
||||
sprintf(buff, "%.2dVA%f;", axis, fabs(cntrl_units));
|
||||
strcat(motor_call->message, buff);
|
||||
if (cntrl_units > 0)
|
||||
sprintf(buff, "%.2dMV+;", axis);
|
||||
else
|
||||
sprintf(buff, "%.2dMV-;", axis);
|
||||
break;
|
||||
case SET_PGAIN:
|
||||
sprintf(buff, "%dKP%f;%dUF;", axis, cntrl_units, axis);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
sprintf(buff, "%dKI%f;%dUF;", axis, cntrl_units, axis);
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
sprintf(buff, "%dKD%f;%dUF;", axis, cntrl_units, axis);
|
||||
break;
|
||||
case ENABLE_TORQUE:
|
||||
sprintf(buff, "%.2dMO;", axis);
|
||||
break;
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "%.2dMF;", axis);
|
||||
break;
|
||||
case SET_HIGH_LIMIT:
|
||||
sprintf(buff, "%.2dSR%f;", axis, cntrl_units);
|
||||
break;
|
||||
case SET_LOW_LIMIT:
|
||||
sprintf(buff, "%.2dSL%f;", axis, cntrl_units);
|
||||
break;
|
||||
default:
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("ESP300_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
strcat(motor_call->message, buff);
|
||||
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,344 +0,0 @@
|
||||
/*
|
||||
FILENAME... devMM3000.cc
|
||||
USAGE... Motor record device level support for Newport MM3000.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Date: 10/16/97
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 10-16-97 mlr initialized from devOms58
|
||||
* .01 07-19-99 rls initialized from drvMM4000
|
||||
* .02 04-21-01 rls Added jog velocity motor command.
|
||||
* .03 05-22-03 rls Converted to R3.14.x.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include <math.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define STATIC static
|
||||
|
||||
extern struct driver_table MM3000_access;
|
||||
|
||||
/* ----------------Create the dsets for devMM3000----------------- */
|
||||
/* static long report(); */
|
||||
STATIC struct driver_table *drvtabptr;
|
||||
STATIC long MM3000_init(int);
|
||||
STATIC long MM3000_init_record(void *);
|
||||
STATIC long MM3000_start_trans(struct motorRecord *);
|
||||
STATIC RTN_STATUS MM3000_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
STATIC RTN_STATUS MM3000_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devMM3000 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) MM3000_init, (DEVSUPFUN) MM3000_init_record, NULL},
|
||||
motor_update_values,
|
||||
MM3000_start_trans,
|
||||
MM3000_build_trans,
|
||||
MM3000_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devMM3000);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types MM3000_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **MM3000_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for MM3000 stepper motor */
|
||||
STATIC long MM3000_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &MM3000_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MM3000_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
STATIC long MM3000_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, MM3000_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
STATIC long MM3000_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
return(motor_start_trans_com(mr, MM3000_cards));
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
STATIC RTN_STATUS MM3000_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
char *msgptr;
|
||||
size_t last;
|
||||
|
||||
/* Remove trailing ';'s from message. */
|
||||
motor_call = &(trans->motor_call);
|
||||
msgptr = motor_call->message;
|
||||
last = strlen(msgptr) - 1;
|
||||
if (msgptr[last] == ';')
|
||||
msgptr[last] = (char) NULL;
|
||||
|
||||
return(motor_end_trans_com(mr, drvtabptr));
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
STATIC RTN_STATUS MM3000_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
char buff[30];
|
||||
int axis, card;
|
||||
size_t size;
|
||||
int intval;
|
||||
RTN_STATUS rtnval;
|
||||
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
axis = motor_call->signal + 1;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
|
||||
if (MM3000_table[command] > motor_call->type)
|
||||
motor_call->type = MM3000_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->init);
|
||||
strcat(motor_call->message, "\r");
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case SET_PGAIN:
|
||||
case SET_IGAIN:
|
||||
case SET_DGAIN:
|
||||
{
|
||||
double temp_dbl;
|
||||
|
||||
temp_dbl = parms[0] * 32767.0;
|
||||
intval = NINT(temp_dbl);
|
||||
break;
|
||||
}
|
||||
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
default:
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
intval = (parms == NULL) ? 0 : NINT(parms[0]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "%dPA%d;", axis, intval);
|
||||
break;
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "%dPR%d;", axis, intval);
|
||||
break;
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
sprintf(buff, "%dOR1;", axis);
|
||||
break;
|
||||
case LOAD_POS:
|
||||
if (*parms == 0.0)
|
||||
sprintf(buff, "%dDH", axis);
|
||||
else
|
||||
rtnval = ERROR;
|
||||
break;
|
||||
case SET_VEL_BASE:
|
||||
if (cntrl->type[axis - 1] == STEPPER)
|
||||
{
|
||||
if (intval < 100)
|
||||
intval = 100;
|
||||
sprintf(buff, "%dVB%d;", axis, intval);
|
||||
}
|
||||
break;
|
||||
case SET_VELOCITY:
|
||||
if (cntrl->type[axis - 1] == STEPPER && intval < 100)
|
||||
intval = 100;
|
||||
sprintf(buff, "%dVA%d;", axis, intval);
|
||||
break;
|
||||
case SET_ACCEL:
|
||||
/*
|
||||
* The value passed is in steps/sec/sec.
|
||||
* Convert to user units/sec/sec
|
||||
*/
|
||||
if (cntrl->type[axis - 1] == STEPPER && intval < 15000)
|
||||
intval = 15000;
|
||||
if (cntrl->type[axis - 1] == DC && intval < 250)
|
||||
intval = 250;
|
||||
sprintf(buff, "%dAC%d;", axis, intval);
|
||||
break;
|
||||
case GO:
|
||||
/*
|
||||
* The MM3000 starts moving immediately on move commands, GO command
|
||||
* does nothing
|
||||
*/
|
||||
break;
|
||||
case SET_ENC_RATIO:
|
||||
/* The motor record no longer passes unsigned values */
|
||||
parms[0] = fabs(parms[0]);
|
||||
parms[1] = fabs(parms[1]);
|
||||
|
||||
/* MM3000 valid encoder ratio values < 10,000. */
|
||||
while (parms[0] > 10000.0 || parms[1] > 10000.0)
|
||||
{
|
||||
parms[0] /= 10;
|
||||
parms[1] /= 10;
|
||||
}
|
||||
if (cntrl->type[axis - 1] == STEPPER)
|
||||
sprintf(buff, "%dER%d:%d", axis, (int) parms[0], (int) parms[1]);
|
||||
break;
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "%dST;", axis);
|
||||
break;
|
||||
case JOG:
|
||||
/*
|
||||
* MM3000 does not have a jog command. Simulate with move absolute
|
||||
* to the appropriate software limit. We can move to MM3000 soft limits.
|
||||
* If the record soft limits are set tighter than the MM3000 limits
|
||||
* the record will prevent JOG motion beyond its soft limits
|
||||
*/
|
||||
sprintf(buff, "%dVA%d;", axis, abs(intval));
|
||||
strcat(motor_call->message, buff);
|
||||
if (intval > 0)
|
||||
sprintf(buff, "%dPA%d;", axis, (int) (mr->dhlm / mr->mres));
|
||||
else
|
||||
sprintf(buff, "%dPA%d;", axis, (int) (mr->dllm / mr->mres));
|
||||
break;
|
||||
case SET_PGAIN:
|
||||
sprintf(buff, "%dKP%d;%dUF;", axis, intval, axis);
|
||||
break;
|
||||
case SET_IGAIN:
|
||||
sprintf(buff, "%dKI%d;%dUF;", axis, intval, axis);
|
||||
break;
|
||||
case SET_DGAIN:
|
||||
sprintf(buff, "%dKD%d;%dUF;", axis, intval, axis);
|
||||
break;
|
||||
case ENABLE_TORQUE:
|
||||
sprintf(buff, "MO;");
|
||||
break;
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "MF;");
|
||||
break;
|
||||
case SET_HIGH_LIMIT:
|
||||
case SET_LOW_LIMIT:
|
||||
sprintf(buff, "%dSL%d;", axis, intval);
|
||||
break;
|
||||
default:
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("MM3000_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
strcat(motor_call->message, buff);
|
||||
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,349 +0,0 @@
|
||||
/*
|
||||
FILENAME... devMM4000.cc
|
||||
USAGE... Motor record device level support for Newport MM4000.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Date: 10/20/97
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-20-97 mlr initialized from drvOms58
|
||||
* .02 10-30-97 mlr Replaced driver calls with gpipIO functions
|
||||
* .03 10-30-98 mlr Minor code cleanup, improved formatting
|
||||
* .04 02-01-99 mlr Added temporary fix to delay reading motor
|
||||
* positions at the end of a move.
|
||||
* .05 04-21-01 rls Added jog velocity motor command.
|
||||
* .06 05-19-03 rls Converted to R3.14.x.
|
||||
* .07 07-07-08 rls Support individual axis power on/off for MM4005/6.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define STATIC static
|
||||
|
||||
extern struct driver_table MM4000_access;
|
||||
|
||||
/* ----------------Create the dsets for devMM4000----------------- */
|
||||
STATIC struct driver_table *drvtabptr;
|
||||
STATIC long MM4000_init(int);
|
||||
STATIC long MM4000_init_record(void *);
|
||||
STATIC long MM4000_start_trans(struct motorRecord *);
|
||||
STATIC RTN_STATUS MM4000_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
STATIC RTN_STATUS MM4000_end_trans(struct motorRecord *);
|
||||
|
||||
struct motor_dset devMM4000 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) MM4000_init, (DEVSUPFUN) MM4000_init_record, NULL},
|
||||
motor_update_values,
|
||||
MM4000_start_trans,
|
||||
MM4000_build_trans,
|
||||
MM4000_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devMM4000);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
/* WARNING! this must match "motor_cmnd" in motor.h */
|
||||
|
||||
static msg_types MM4000_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **MM4000_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* initialize device support for MM4000 stepper motor */
|
||||
STATIC long MM4000_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &MM4000_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &MM4000_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
STATIC long MM4000_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, MM4000_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
STATIC long MM4000_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
return(motor_start_trans_com(mr, MM4000_cards));
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
STATIC RTN_STATUS MM4000_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
return(motor_end_trans_com(mr, drvtabptr));
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
STATIC RTN_STATUS MM4000_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct mess_info *motor_info;
|
||||
struct MMcontroller *cntrl;
|
||||
char buff[110];
|
||||
int axis, card, maxdigits;
|
||||
size_t size;
|
||||
double dval, cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
axis = motor_call->signal + 1;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
cntrl_units = dval * cntrl->drive_resolution[axis - 1];
|
||||
maxdigits = cntrl->res_decpts[axis - 1];
|
||||
|
||||
if (MM4000_table[command] > motor_call->type)
|
||||
motor_call->type = MM4000_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->init);
|
||||
strcat(motor_call->message, "\r");
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "%dPA%.*f;", axis, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "%dPR%.*f;", axis, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
sprintf(buff, "%dOR;", axis);
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
if (cntrl->model == MM4000)
|
||||
sprintf(buff, "%dSH%.*f;%dDH;%dSH%.*f", axis, maxdigits, cntrl_units,
|
||||
axis, axis, maxdigits, cntrl->home_preset[axis - 1]);
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
break; /* MM4000 does not use base velocity */
|
||||
|
||||
case SET_VELOCITY:
|
||||
sprintf(buff, "%dVA%.*f;", axis, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/*
|
||||
* The value passed is in steps/sec/sec.
|
||||
* Convert to user units/sec/sec
|
||||
*/
|
||||
sprintf(buff, "%dAC%.*f;", axis, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case GO:
|
||||
/*
|
||||
* The MM4000 starts moving immediately on move commands, GO command
|
||||
* does nothing
|
||||
*/
|
||||
break;
|
||||
|
||||
case SET_ENC_RATIO:
|
||||
/*
|
||||
* The MM4000 does not have the concept of encoder ratio, ignore this
|
||||
* command
|
||||
*/
|
||||
break;
|
||||
|
||||
case GET_INFO:
|
||||
/* These commands are not actually done by sending a message, but
|
||||
rather they will indirectly cause the driver to read the status
|
||||
of all motors */
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "%dST;", axis);
|
||||
break;
|
||||
|
||||
case JOG:
|
||||
/*
|
||||
* MM4000 does not have a jog command. Simulate with move absolute
|
||||
* to the appropriate software limit. We can move to MM4000 soft limits.
|
||||
* If the record soft limits are set tighter than the MM4000 limits
|
||||
* the record will prevent JOG motion beyond its soft limits
|
||||
*/
|
||||
sprintf(buff, "%dVA%.*f;", axis, maxdigits, fabs(cntrl_units));
|
||||
strcat(motor_call->message, buff);
|
||||
if (dval > 0.)
|
||||
sprintf(buff, "%dPA%.*f;", axis, maxdigits, mr->dhlm);
|
||||
else
|
||||
sprintf(buff, "%dPA%.*f;", axis, maxdigits, mr->dllm);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
sprintf(buff, "%dKP%f;%dUF;", axis, dval, axis);
|
||||
break;
|
||||
|
||||
case SET_IGAIN:
|
||||
sprintf(buff, "%dKI%f;%dUF;", axis, dval, axis);
|
||||
break;
|
||||
|
||||
case SET_DGAIN:
|
||||
sprintf(buff, "%dKD%f;%dUF;", axis, dval, axis);
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
if (cntrl->model == MM4000)
|
||||
sprintf(buff, "MO;");
|
||||
else
|
||||
sprintf(buff, "%dMO;", axis);
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
if (cntrl->model == MM4000)
|
||||
sprintf(buff, "MF;");
|
||||
else
|
||||
sprintf(buff, "%dMF;", axis);
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
motor_info = &(*trans->tabptr->card_array)[card]->motor_info[axis - 1];
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
|
||||
if (cntrl_units > motor_info->high_limit)
|
||||
{
|
||||
mr->dhlm = motor_info->high_limit;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
case SET_LOW_LIMIT:
|
||||
motor_info = &(*trans->tabptr->card_array)[card]->motor_info[axis - 1];
|
||||
trans->state = IDLE_STATE; /* No command sent to the controller. */
|
||||
|
||||
if (cntrl_units < motor_info->low_limit)
|
||||
{
|
||||
mr->dllm = motor_info->low_limit;
|
||||
rtnval = ERROR;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("MM4000_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
strcat(motor_call->message, buff);
|
||||
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
# Newport MM3000, MM4000/5, PM500 and ESP300 Device Driver support.
|
||||
device(motor,VME_IO,devMM3000,"MM3000")
|
||||
device(motor,VME_IO,devMM4000,"MM4000")
|
||||
device(motor,VME_IO,devPM500, "PM500")
|
||||
device(motor,VME_IO,devESP300,"ESP300")
|
||||
driver(drvMM3000)
|
||||
driver(drvMM4000)
|
||||
driver(drvPM500)
|
||||
driver(drvESP300)
|
||||
driver(motorXPS)
|
||||
driver(motorMM4000)
|
||||
registrar(NewportRegister)
|
||||
registrar(XPSGatheringRegister)
|
||||
registrar(XPSRegister)
|
||||
registrar(XPSRegister3)
|
||||
registrar(HXPRegister)
|
||||
registrar(XPSInterposeRegister)
|
||||
registrar(drvXPSAsynAuxRegister)
|
||||
registrar(AG_UCRegister)
|
||||
registrar(AG_CONEXRegister)
|
||||
registrar(SMC100Register)
|
||||
#variable(devXPSC8Debug)
|
||||
#variable(drvXPSC8Debug)
|
||||
#variable(drvESP300debug)
|
||||
#variable(drvMM3000debug)
|
||||
#variable(drvMM4000debug)
|
||||
#variable(drvPM500debug)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Newport SNL programs
|
||||
registrar(MM4005_trajectoryScanRegistrar)
|
||||
registrar(XPS_trajectoryScanRegistrar)
|
||||
registrar(xpsSlaveRegistrar)
|
||||
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
FILENAME... devPM500.cc
|
||||
USAGE... Motor record device level support for the Newport PM500 motor
|
||||
controller.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .00 10-25-98 mlr initialized from devPM500
|
||||
* .01 06-02-00 rls integrated into standard motor record
|
||||
* .02 04-21-01 rls Added jog velocity motor command.
|
||||
* .03 05-23-03 rls Converted to R3.14.x.
|
||||
* .04 08-24-09 rls Queries added to some commands to prevent comm. response
|
||||
* timeouts.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <errlog.h>
|
||||
#include "motorRecord.h"
|
||||
#include "motor.h"
|
||||
#include "motordevCom.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define STATIC static
|
||||
|
||||
extern struct driver_table PM500_access;
|
||||
|
||||
/* ----------------Create the dsets for devPM500----------------- */
|
||||
STATIC struct driver_table *drvtabptr;
|
||||
STATIC long PM500_init(int);
|
||||
STATIC long PM500_init_record(void *);
|
||||
STATIC long PM500_start_trans(struct motorRecord *);
|
||||
STATIC RTN_STATUS PM500_build_trans(motor_cmnd, double *, struct motorRecord *);
|
||||
STATIC RTN_STATUS PM500_end_trans(struct motorRecord *);
|
||||
|
||||
static char PM500_axis_names[] = {'X', 'Y', 'Z', 'A', 'B', 'C', 'D', 'E', 'F',
|
||||
'G', 'H', 'I'};
|
||||
|
||||
struct motor_dset devPM500 =
|
||||
{
|
||||
{8, NULL, (DEVSUPFUN) PM500_init, (DEVSUPFUN) PM500_init_record, NULL},
|
||||
motor_update_values,
|
||||
PM500_start_trans,
|
||||
PM500_build_trans,
|
||||
PM500_end_trans
|
||||
};
|
||||
|
||||
extern "C" {epicsExportAddress(dset,devPM500);}
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
/* This table is used to define the command types */
|
||||
|
||||
static msg_types PM500_table[] = {
|
||||
MOTION, /* MOVE_ABS */
|
||||
MOTION, /* MOVE_REL */
|
||||
MOTION, /* HOME_FOR */
|
||||
MOTION, /* HOME_REV */
|
||||
IMMEDIATE, /* LOAD_POS */
|
||||
IMMEDIATE, /* SET_VEL_BASE */
|
||||
IMMEDIATE, /* SET_VELOCITY */
|
||||
IMMEDIATE, /* SET_ACCEL */
|
||||
IMMEDIATE, /* GO */
|
||||
IMMEDIATE, /* SET_ENC_RATIO */
|
||||
INFO, /* GET_INFO */
|
||||
MOVE_TERM, /* STOP_AXIS */
|
||||
VELOCITY, /* JOG */
|
||||
IMMEDIATE, /* SET_PGAIN */
|
||||
IMMEDIATE, /* SET_IGAIN */
|
||||
IMMEDIATE, /* SET_DGAIN */
|
||||
IMMEDIATE, /* ENABLE_TORQUE */
|
||||
IMMEDIATE, /* DISABL_TORQUE */
|
||||
IMMEDIATE, /* PRIMITIVE */
|
||||
IMMEDIATE, /* SET_HIGH_LIMIT */
|
||||
IMMEDIATE, /* SET_LOW_LIMIT */
|
||||
VELOCITY /* JOG_VELOCITY */
|
||||
};
|
||||
|
||||
|
||||
static struct board_stat **PM500_cards;
|
||||
|
||||
/* --------------------------- program data --------------------- */
|
||||
|
||||
|
||||
/* Initialize device support for PM500 controller. */
|
||||
STATIC long PM500_init(int after)
|
||||
{
|
||||
long rtnval;
|
||||
|
||||
if (!after)
|
||||
{
|
||||
drvtabptr = &PM500_access;
|
||||
(drvtabptr->init)();
|
||||
}
|
||||
|
||||
rtnval = motor_init_com(after, *drvtabptr->cardcnt_ptr, drvtabptr, &PM500_cards);
|
||||
return(rtnval);
|
||||
}
|
||||
|
||||
|
||||
/* initialize a record instance */
|
||||
STATIC long PM500_init_record(void *arg)
|
||||
{
|
||||
struct motorRecord *mr = (struct motorRecord *) arg;
|
||||
return(motor_init_record_com(mr, *drvtabptr->cardcnt_ptr, drvtabptr, PM500_cards));
|
||||
}
|
||||
|
||||
|
||||
/* start building a transaction */
|
||||
STATIC long PM500_start_trans(struct motorRecord *mr)
|
||||
{
|
||||
return(motor_start_trans_com(mr, PM500_cards));
|
||||
}
|
||||
|
||||
|
||||
/* end building a transaction */
|
||||
STATIC RTN_STATUS PM500_end_trans(struct motorRecord *mr)
|
||||
{
|
||||
return(motor_end_trans_com(mr, drvtabptr));
|
||||
}
|
||||
|
||||
|
||||
/* add a part to the transaction */
|
||||
STATIC RTN_STATUS PM500_build_trans(motor_cmnd command, double *parms, struct motorRecord *mr)
|
||||
{
|
||||
struct motor_trans *trans = (struct motor_trans *) mr->dpvt;
|
||||
struct mess_node *motor_call;
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
char axis_name;
|
||||
char buff[110];
|
||||
int axis, card, maxdigits;
|
||||
size_t size;
|
||||
double dval, cntrl_units;
|
||||
RTN_STATUS rtnval;
|
||||
|
||||
rtnval = OK;
|
||||
buff[0] = '\0';
|
||||
|
||||
/* Protect against NULL pointer with WRTITE_MSG(GO/STOP_AXIS/GET_INFO, NULL). */
|
||||
dval = (parms == NULL) ? 0.0 : *parms;
|
||||
|
||||
motor_call = &(trans->motor_call);
|
||||
card = motor_call->card;
|
||||
axis = motor_call->signal + 1;
|
||||
brdptr = (*trans->tabptr->card_array)[card];
|
||||
if (brdptr == NULL)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
axis_name = PM500_axis_names[axis - 1];
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
cntrl_units = dval * cntrl->drive_resolution[axis - 1];
|
||||
maxdigits = cntrl->res_decpts[axis - 1];
|
||||
|
||||
if (PM500_table[command] > motor_call->type)
|
||||
motor_call->type = PM500_table[command];
|
||||
|
||||
if (trans->state != BUILD_STATE)
|
||||
return(rtnval = ERROR);
|
||||
|
||||
if (command == PRIMITIVE && mr->init != NULL && strlen(mr->init) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->init);
|
||||
strcat(motor_call->message, "\r");
|
||||
}
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
case MOVE_REL:
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
case JOG:
|
||||
if (strlen(mr->prem) != 0)
|
||||
{
|
||||
strcat(motor_call->message, mr->prem);
|
||||
strcat(motor_call->message, ";");
|
||||
}
|
||||
if (strlen(mr->post) != 0)
|
||||
motor_call->postmsgptr = (char *) &mr->post;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
switch (command)
|
||||
{
|
||||
case MOVE_ABS:
|
||||
sprintf(buff, "%cG%.*f;", axis_name, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case MOVE_REL:
|
||||
sprintf(buff, "%cR%.*f;", axis_name, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case HOME_FOR:
|
||||
case HOME_REV:
|
||||
sprintf(buff, "%cF0;", axis_name);
|
||||
break;
|
||||
|
||||
case LOAD_POS:
|
||||
break;
|
||||
|
||||
case SET_VEL_BASE:
|
||||
break; /* PM500 does not use base velocity */
|
||||
|
||||
case SET_VELOCITY:
|
||||
/* PM500 uses mm/sec and karc-sec/sec for velocity, but microns and
|
||||
* arc-sec for position. Divide by 1000 here.
|
||||
*/
|
||||
cntrl_units /= 1000.0;
|
||||
sprintf(buff, "%cV%.*f;", axis_name, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_ACCEL:
|
||||
/* PM500 uses mm/sec^2 and karc-sec/sec^2 for acceleration, but
|
||||
* microns and arc-sec for position. Divide by 1000 here.
|
||||
*/
|
||||
cntrl_units /= 1000.0;
|
||||
sprintf(buff, "%cACCEL%.*f;", axis_name, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case GO:
|
||||
/*
|
||||
* The PM500 starts moving immediately on move commands, GO command
|
||||
* does nothing
|
||||
*/
|
||||
break;
|
||||
|
||||
case SET_ENC_RATIO:
|
||||
/*
|
||||
* The PM500 does not have the concept of encoder ratio, ignore this
|
||||
* command
|
||||
*/
|
||||
break;
|
||||
|
||||
case GET_INFO:
|
||||
sprintf(buff, "%cR;", axis_name);
|
||||
break;
|
||||
|
||||
case STOP_AXIS:
|
||||
sprintf(buff, "%cT;%cR", axis_name, axis_name);
|
||||
break;
|
||||
|
||||
case JOG:
|
||||
/* PM500 uses mm/sec and karc-sec/sec for velocity, but microns and
|
||||
* arc-sec for position. Divide by 1000 here.
|
||||
*/
|
||||
cntrl_units /= 1000.0;
|
||||
sprintf(buff, "%cS%f;", axis_name, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_PGAIN:
|
||||
case SET_IGAIN:
|
||||
case SET_DGAIN:
|
||||
break;
|
||||
|
||||
case ENABLE_TORQUE:
|
||||
sprintf(buff, "%cT;%cM?", axis_name, axis_name);
|
||||
break;
|
||||
|
||||
case DISABL_TORQUE:
|
||||
sprintf(buff, "%cM;%cM?", axis_name, axis_name);
|
||||
break;
|
||||
|
||||
case SET_HIGH_LIMIT:
|
||||
sprintf(buff, "%cPSLIM%.*f;", axis_name, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
case SET_LOW_LIMIT:
|
||||
sprintf(buff, "%cNSLIM%.*f;", axis_name, maxdigits, cntrl_units);
|
||||
break;
|
||||
|
||||
default:
|
||||
rtnval = ERROR;
|
||||
}
|
||||
|
||||
size = strlen(buff);
|
||||
if (size > sizeof(buff) || (strlen(motor_call->message) + size) > MAX_MSG_SIZE)
|
||||
errlogMessage("PM500_build_trans(): buffer overflow.\n");
|
||||
else
|
||||
strcat(motor_call->message, buff);
|
||||
|
||||
return(rtnval);
|
||||
}
|
||||
@@ -1,746 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvESP300.cc
|
||||
USAGE... Motor record driver level support for Newport ESP300/100.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Ron Sluiter
|
||||
* Date: 02/19/03
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
* NOTES
|
||||
* -----
|
||||
* - This driver works with the following models: ESP100, ESP300 and ESP301.
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 02-19-03 rls copied from drvMM3000
|
||||
* .02 05-23-03 rls Converted to R3.14.x.
|
||||
* .03 10-28-03 rls initialize "drive_resolution".
|
||||
* .04 02-03-04 rls Eliminate erroneous "Motor motion timeout ERROR".
|
||||
* .05 07/09/04 rls removed unused <driver>Setup() argument.
|
||||
* .06 07/28/04 rls "epicsExport" debug variable.
|
||||
* .07 09/21/04 rls support for 32axes/controller.
|
||||
* .08 12/21/04 rls - retry on initial communication.
|
||||
* - using asyn's set[Out/In]putEos().
|
||||
* - make debug variables always available.
|
||||
* - MS Visual C compatibility; make all epicsExportAddress
|
||||
* extern "C" linkage.
|
||||
* .09 08/07/06 rls - GPIB under ASYN only allows 1 input EOS character.
|
||||
* No output EOS. Adjustments accordingly.
|
||||
* .10 05/19/14 rls - Print controller's error code and set RA_PROBLEM.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <errlog.h>
|
||||
#include <stdlib.h>
|
||||
#include "motor.h"
|
||||
#include "NewportRegister.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define READ_POSITION "%.2dTP"
|
||||
#define STOP_AXIS "%.2dST"
|
||||
#define GET_IDENT "VE?"
|
||||
|
||||
#define ESP300_NUM_CARDS 4
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from ESP300 */
|
||||
|
||||
/* The ESP300 does not respond for 2 to 5 seconds after hitting a travel limit. */
|
||||
#define SERIAL_TIMEOUT 5.0 /* Command timeout in sec. */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
|
||||
volatile int drvESP300debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvESP300debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvESP300debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int ESP300_num_cards = 0;
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table ESP300_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct drvESP300_drvet
|
||||
{
|
||||
long number;
|
||||
#ifdef __cplusplus
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
#else
|
||||
DRVSUPFUN report;
|
||||
DRVSUPFUN init;
|
||||
#endif
|
||||
} drvESP300 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvESP300);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &ESP300_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (ESP300_num_cards <=0)
|
||||
printf(" No ESP300 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < ESP300_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" ESP300 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
printf(" ESP300 controller %d port=%s, address=%d, id: %s \n",
|
||||
card, cntrl->asyn_port, cntrl->asyn_address,
|
||||
brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (ESP300_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): ESP300 driver disabled. ESP300Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* Parse status and position strings for a card and signal
|
||||
* set_status()
|
||||
************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
register struct mess_info *motor_info;
|
||||
/* Message parsing variables */
|
||||
char *cptr, *tok_save;
|
||||
char inbuff[BUFF_SIZE], outbuff[BUFF_SIZE];
|
||||
int rtn_state, charcnt, errcode;
|
||||
long mstatus;
|
||||
double motorData;
|
||||
bool power, plusdir, ls_active = false;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
sprintf(outbuff, "%.2dMD", signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
|
||||
if (charcnt == 1 && (inbuff[0] == '0' || inbuff[0] == '1'))
|
||||
{
|
||||
cntrl->status = NORMAL;
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
{
|
||||
cntrl->status = RETRY;
|
||||
rtn_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
cntrl->status = COMM_ERR;
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
status.Bits.RA_DONE = (inbuff[0] == '1') ? 1 : 0;
|
||||
|
||||
/* Get motor position. */
|
||||
sprintf(outbuff, READ_POSITION, signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
|
||||
motorData = atof(inbuff) / cntrl->drive_resolution[signal];
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
epicsInt32 newposition;
|
||||
|
||||
newposition = NINT(motorData);
|
||||
status.Bits.RA_DIRECTION = (newposition >= motor_info->position) ? 1 : 0;
|
||||
motor_info->position = newposition;
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
/* Get travel limit switch status. */
|
||||
sprintf(outbuff, "%.2dPH", signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
cptr = strchr(inbuff, 'H');
|
||||
if (cptr == NULL)
|
||||
{
|
||||
Debug(2, "set_status(): PH error = %s\n", inbuff);
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
mstatus = strtol(inbuff, &cptr, 16);
|
||||
|
||||
/* Set Travel limit switch status bits. */
|
||||
if (((mstatus >> signal) & 0x01) == false)
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
|
||||
if (((mstatus >> (signal + 8)) & 0x01) == false)
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
|
||||
/* Set home switch status. */
|
||||
cptr += 2;
|
||||
tok_save = strchr(inbuff, 'H');
|
||||
mstatus = strtol(cptr, &tok_save, 16);
|
||||
|
||||
status.Bits.RA_HOME = ((mstatus >> signal) & 0x01) ? 1 : 0;
|
||||
|
||||
/* Get motor power on/off status. */
|
||||
sprintf(outbuff, "%.2dMO?", signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
power = atoi(inbuff) ? true : false;
|
||||
|
||||
status.Bits.EA_POSITION = (power == true) ? 1 : 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
/* Get error code. */
|
||||
sprintf(outbuff, "%.2dTE?", signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
errcode = atoi(inbuff);
|
||||
if (errcode != 0)
|
||||
{
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
printf("ESP300 controller error = %d.\n", errcode);
|
||||
}
|
||||
else
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(outbuff, nodeptr->postmsgptr);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the ESP300 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
size_t size;
|
||||
size_t nwrite;
|
||||
|
||||
size = strlen(com);
|
||||
|
||||
if (size > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvESP300:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (size == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvESP300:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
errlogPrintf("drvESP300:send_mess() - invalid argument = %s\n", name);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", com);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), SERIAL_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION... recv_mess(int card, char *com, int flag)
|
||||
*
|
||||
* INPUT ARGUMENTS...
|
||||
* card - controller card # (0,1,...).
|
||||
* *com - caller's response buffer.
|
||||
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
|
||||
* | !FLUSH = retrieve response into caller's buffer; set timeout.
|
||||
*
|
||||
* LOGIC...
|
||||
* Initialize:
|
||||
* - receive timeout to zero
|
||||
* - received string length to zero.
|
||||
*
|
||||
* IF controller card does not exist.
|
||||
* ERROR RETURN.
|
||||
* ENDIF
|
||||
*
|
||||
* SWITCH on port type.
|
||||
* CASE port type is GPIB.
|
||||
* BREAK.
|
||||
* CASE port type is RS232.
|
||||
* IF input "flag" indicates NOT flushing the input buffer.
|
||||
* Set receive timeout nonzero.
|
||||
* ENDIF
|
||||
* Call pasynOctetSyncIO->read().
|
||||
*
|
||||
* NOTE: The ESP300 sometimes responds to an MS command with an error
|
||||
* message (see ESP300 User's Manual Appendix A). This is an
|
||||
* unconfirmed ESP300 bug. Retry read if this is a Hard Travel
|
||||
* limit switch error. This effectively flushes the error message.
|
||||
*
|
||||
* IF input "com" buffer length is > 3 characters, AND, the 1st
|
||||
* character is an "E" (Maybe this an unsolicited error
|
||||
* message response?).
|
||||
* Call pasynOctetSyncIO->read().
|
||||
* ENDIF
|
||||
* BREAK
|
||||
* ENDSWITCH
|
||||
*
|
||||
* NORMAL RETURN.
|
||||
*/
|
||||
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
double timeout = 0.;
|
||||
int flush = 1;
|
||||
size_t nread = 0;
|
||||
asynStatus status;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag != FLUSH)
|
||||
{
|
||||
flush = 0;
|
||||
timeout = SERIAL_TIMEOUT;
|
||||
}
|
||||
if (flush)
|
||||
status = pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
if (nread > 3 && com[0] == 'E')
|
||||
{
|
||||
long error;
|
||||
|
||||
error = strtol(&com[1], NULL, 0);
|
||||
if (error >= 35 && error <= 42)
|
||||
{
|
||||
if (flush)
|
||||
status = pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
}
|
||||
}
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0) || (com[nread - 1] != '\r'))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ESP300 responses are always terminated with CR/LF combination (see
|
||||
* ESP300 User' Manual Sec. 3.4 NOTE). ASYN strips LF; this code strips
|
||||
* CR from buffer before returning to caller.
|
||||
*/
|
||||
nread--;
|
||||
com[nread] = '\0'; /* Strip trailing CR. */
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return((int)nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* ESP300Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
ESP300Setup(int num_cards, /* maximum number of controllers in system. */
|
||||
int scan_rate) /* polling rate - 1/60 sec units. */
|
||||
{
|
||||
int itera;
|
||||
|
||||
if (num_cards < 1 || num_cards > ESP300_NUM_CARDS)
|
||||
ESP300_num_cards = ESP300_NUM_CARDS;
|
||||
else
|
||||
ESP300_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before ESP300Config is called, so it cannot be done in motor_init()
|
||||
* This means that we must allocate space for a card without knowing
|
||||
* if it really exists, which is not a serious problem
|
||||
*/
|
||||
motor_state = (struct controller **) malloc(ESP300_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < ESP300_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* ESP300Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
ESP300Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int address) /* asyn address (GPIB) */
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
if (card < 0 || card >= ESP300_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct MMcontroller));
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = address;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int total_axis = 0;
|
||||
int status=0;
|
||||
asynStatus success_rtn;
|
||||
static const char output_terminator[] = "\r";
|
||||
static const char input_terminator[] = "\n";
|
||||
static const char errmsg[] = "drvESP300.c:motor_init: ASYN";
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (ESP300_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < ESP300_num_cards; card_index++)
|
||||
{
|
||||
if (!motor_state[card_index])
|
||||
continue;
|
||||
|
||||
brdptr = motor_state[card_index];
|
||||
brdptr->cmnd_response = false;
|
||||
total_cards = card_index + 1;
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
|
||||
cntrl->asyn_address, &cntrl->pasynUser, NULL);
|
||||
if (success_rtn != asynSuccess)
|
||||
{
|
||||
errlogPrintf("%s connect error = %d\n", errmsg, (int) success_rtn);
|
||||
goto errexit;
|
||||
}
|
||||
|
||||
success_rtn = pasynOctetSyncIO->setOutputEos(cntrl->pasynUser,
|
||||
output_terminator, (int)strlen(output_terminator));
|
||||
/* Ignore output EOS error in case this is a GPIB port. */
|
||||
|
||||
success_rtn = pasynOctetSyncIO->setInputEos(cntrl->pasynUser,
|
||||
input_terminator, (int)strlen(input_terminator));
|
||||
if (success_rtn != asynSuccess)
|
||||
{
|
||||
errlogPrintf("%s setInputEos error = %d\n", errmsg, (int) success_rtn);
|
||||
goto errexit;
|
||||
}
|
||||
else
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
/* Send a message to the board, see if it exists */
|
||||
/* flush any junk at input port - should not be any data available */
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
|
||||
do
|
||||
{
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
retry++;
|
||||
/* Return value is length of response string */
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
errexit:
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
strcpy(brdptr->ident, &buff[1]); /* Skip "\n" */
|
||||
|
||||
send_mess(card_index, "ZU", (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
total_axis = buff[0] >> 4;
|
||||
if (total_axis > 4)
|
||||
{
|
||||
Debug(2, "motor_init(): ZU = %s\n", buff);
|
||||
total_axis = 4;
|
||||
}
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
sprintf(buff, STOP_AXIS, motor_index + 1); /* Stop motor */
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
/* Initialize. */
|
||||
brdptr->motor_info[motor_index].motor_motion = NULL;
|
||||
}
|
||||
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
int feedback;
|
||||
double fullStep;
|
||||
int microStep;
|
||||
|
||||
/* Get controller's EGU for the user (see README). */
|
||||
sprintf(buff, "%.2dSN?", motor_index + 1);
|
||||
send_mess(card_index, buff, 0);
|
||||
recv_mess(card_index, buff, 1);
|
||||
|
||||
/* Set axis resolution. */
|
||||
/* Read the feedback status */
|
||||
sprintf(buff, "%.2dZB?", motor_index + 1);
|
||||
send_mess(card_index, buff, 0);
|
||||
recv_mess(card_index, buff, 1);
|
||||
feedback = strtol(buff,0,16);
|
||||
/* If stepper closed loop positioning is enabled (bit 9=1) and encoder feedback is disabled (bit 8=0)
|
||||
* then use the full-step resolution (FR) and microstepping (QS) to determine drive_resolution.
|
||||
* If not then use SU (encoder resolution) for drive_resolution. */
|
||||
if ((feedback & 0x300) == 0x200) {
|
||||
sprintf(buff, "%.2dFR?", motor_index + 1);
|
||||
send_mess(card_index, buff, 0);
|
||||
recv_mess(card_index, buff, 1);
|
||||
fullStep = atof(buff);
|
||||
sprintf(buff, "%.2dQS?", motor_index + 1);
|
||||
send_mess(card_index, buff, 0);
|
||||
recv_mess(card_index, buff, 1);
|
||||
microStep = strtol(buff, 0, 10);
|
||||
cntrl->drive_resolution[motor_index] = fullStep / microStep;
|
||||
} else {
|
||||
sprintf(buff, "%.2dSU?", motor_index + 1);
|
||||
send_mess(card_index, buff, 0);
|
||||
recv_mess(card_index, buff, 1);
|
||||
cntrl->drive_resolution[motor_index] = atof(&buff[0]);
|
||||
}
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
motor_info->encoder_present = YES;
|
||||
|
||||
if (motor_info->encoder_present == YES)
|
||||
{
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = YES;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
}
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "ESP300_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
@@ -1,733 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvMM3000.cc
|
||||
USAGE... Motor record driver level support for Newport MM3000.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Date: 10/20/97
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-20-97 mlr initialized from drvOms58
|
||||
* .02 10-30-97 mlr Replaced driver calls with gpipIO functions
|
||||
* .03 10-30-98 mlr Minor code cleanup, improved formatting
|
||||
* .04 02-01-99 mlr Added temporary fix to delay reading motor positions at
|
||||
* the end of a move.
|
||||
* .05 04-18-00 rls MM3000 takes 2 to 5 seconds to respond to queries after
|
||||
* hitting a hard travel limit. Adjusted GPIB and SERIAL
|
||||
* timeouts accordingly. Deleted communication retries.
|
||||
* Reworked travel limit processing so that direction
|
||||
* status bit matches limit switch. Copied recv_mess()
|
||||
* logic from drvMM4000.c. Use TPE command to determine
|
||||
* if motor has an encoder.
|
||||
* .06 10/02/01 rls - allow one retry after a communication error.
|
||||
* - use motor status response bit-field.
|
||||
* .07 05-22-03 rls - Converted to R3.14.2.
|
||||
* .08 10/23/03 rls - recv_mess() eats the controller error response, outputs
|
||||
* an error message and retries.
|
||||
* .09 02/03/04 rls - Eliminate erroneous "Motor motion timeout ERROR".
|
||||
* .10 07/09/04 rls - removed unused <driver>Setup() argument.
|
||||
* .11 07/28/04 rls - "epicsExport" debug variable.
|
||||
* .12 09/21/04 rls - support for 32axes/controller.
|
||||
* .13 12/21/04 rls - MS Visual C compatibility; make all epicsExportAddress
|
||||
* extern "C" linkage.
|
||||
* - make debug variables always available.
|
||||
* .14 01/13/10 rls - Bug fix for this error message; "drvMM3000:motor_init()
|
||||
* - invalid RC response = dc" on the last axis.
|
||||
* - Bug fix for report() breaking out of "for loop" after 1st
|
||||
* report printed.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsString.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motor.h"
|
||||
#include "NewportRegister.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define STATIC static
|
||||
|
||||
#define READ_RESOLUTION "TU;"
|
||||
#define READ_STATUS "MS;"
|
||||
#define READ_POSITION "TP;"
|
||||
#define STOP_ALL "ST"
|
||||
#define MOTOR_ON "MO;"
|
||||
#define REMOTE_MODE "MR;"
|
||||
#define GET_IDENT "VE"
|
||||
|
||||
/* Status byte bits */
|
||||
#define M_AXIS_MOVING 0x01
|
||||
#define M_MOTOR_POWER 0x02
|
||||
#define M_MOTOR_DIRECTION 0x04
|
||||
#define M_PLUS_LIMIT 0x08
|
||||
#define M_MINUS_LIMIT 0x10
|
||||
#define M_HOME_SIGNAL 0x20
|
||||
|
||||
#define MM3000_NUM_CARDS 4
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from MM3000 */
|
||||
|
||||
/* The MM3000 does not respond for 2 to 5 seconds after hitting a travel limit. */
|
||||
#define SERIAL_TIMEOUT 5.0 /* Command timeout in sec. */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvMM3000debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvMM3000debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvMM3000debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int MM3000_num_cards = 0;
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
STATIC int recv_mess(int, char *, int);
|
||||
STATIC RTN_STATUS send_mess(int, char const *, char *);
|
||||
STATIC int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
STATIC int motor_init();
|
||||
STATIC void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table MM3000_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct drvMM3000_drvet
|
||||
{
|
||||
long number;
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
} drvMM3000 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvMM3000);}
|
||||
|
||||
STATIC struct thread_args targs = {SCAN_RATE, &MM3000_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (MM3000_num_cards <=0)
|
||||
printf(" No MM3000 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < MM3000_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" MM3000 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
printf(" MM3000 controller %d asyn port= %s, address=%d, id: %s \n",
|
||||
card, cntrl->asyn_port, cntrl->asyn_address,
|
||||
brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (MM3000_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): MM3000 driver disabled. MM3000Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
STATIC void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* Parse status and position strings for a card and signal
|
||||
* set_status()
|
||||
************************************************************/
|
||||
|
||||
STATIC int set_status(int card, int signal)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
register struct mess_info *motor_info;
|
||||
/* Message parsing variables */
|
||||
char *cptr, *tok_save;
|
||||
char inbuff[BUFF_SIZE], outbuff[BUFF_SIZE];
|
||||
MOTOR_STATUS mstat;
|
||||
int rtn_state, charcnt;
|
||||
double motorData;
|
||||
bool plusdir, ls_active = false;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
sprintf(outbuff, "%dMS", signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
if (charcnt > 0)
|
||||
{
|
||||
cntrl->status = NORMAL;
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
{
|
||||
cntrl->status = RETRY;
|
||||
rtn_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
cntrl->status = COMM_ERR;
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
mstat.All = inbuff[0];
|
||||
Debug(5, "set_status(): status byte = %x\n", mstat.All);
|
||||
|
||||
nodeptr = motor_info->motor_motion;
|
||||
|
||||
status.Bits.RA_DIRECTION = (mstat.Bits.direction == false) ? 0 : 1;
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
status.Bits.RA_DONE = (mstat.Bits.inmotion == false) ? 1 : 0;
|
||||
|
||||
/* Set Travel limit switch status bits. */
|
||||
if (mstat.Bits.plustTL == false)
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
|
||||
if (mstat.Bits.minusTL == false)
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
|
||||
status.Bits.RA_HOME = (mstat.Bits.homels == false) ? 0 : 1;
|
||||
|
||||
status.Bits.EA_POSITION = (mstat.Bits.NOT_power == false) ? 1 : 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
sprintf(outbuff, "%dTP", signal + 1);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
charcnt = recv_mess(card, inbuff, 1);
|
||||
if (charcnt > 0)
|
||||
{
|
||||
cntrl->status = NORMAL;
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
{
|
||||
cntrl->status = RETRY;
|
||||
rtn_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
cntrl->status = COMM_ERR;
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
tok_save = NULL;
|
||||
cptr = epicsStrtok_r(inbuff, " ", &tok_save);
|
||||
motorData = atof(cptr);
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
motor_info->position = (epicsInt32) motorData;
|
||||
if (motor_state[card]->motor_info[signal].encoder_present == YES)
|
||||
motor_info->encoder_position = (epicsInt32) motorData;
|
||||
else
|
||||
motor_info->encoder_position = 0;
|
||||
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(outbuff, nodeptr->postmsgptr);
|
||||
send_mess(card, outbuff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the MM3000 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
STATIC RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
size_t size;
|
||||
size_t nwrite;
|
||||
|
||||
size = strlen(com);
|
||||
|
||||
if (size > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvMM3000:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (size == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvMM3000:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
errlogPrintf("drvMM3000:send_mess() - invalid argument = %s\n", name);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", com);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), SERIAL_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION... recv_mess(int card, char *com, int flag)
|
||||
*
|
||||
* INPUT ARGUMENTS...
|
||||
* card - controller card # (0,1,...).
|
||||
* *com - caller's response buffer.
|
||||
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
|
||||
* | !FLUSH = retrieve response into caller's buffer; set timeout.
|
||||
*
|
||||
* LOGIC...
|
||||
* Initialize:
|
||||
* - receive timeout to zero
|
||||
* - received string length to zero.
|
||||
*
|
||||
* IF controller card does not exist.
|
||||
* ERROR RETURN.
|
||||
* ENDIF
|
||||
*
|
||||
* SWITCH on port type.
|
||||
* CASE port type is GPIB.
|
||||
* BREAK.
|
||||
* CASE port type is RS232.
|
||||
* IF input "flag" indicates NOT flushing the input buffer.
|
||||
* Set receive timeout nonzero.
|
||||
* ENDIF
|
||||
* Call pasynOctetSyncIO->read().
|
||||
*
|
||||
* NOTE: The MM3000 sometimes responds to an MS command with an error
|
||||
* message (see MM3000 User's Manual Appendix A). This is an
|
||||
* unconfirmed MM3000 bug. Retry read if this is a Hard Travel
|
||||
* limit switch error. This effectively flushes the error message.
|
||||
*
|
||||
* IF input "com" buffer length is > 3 characters, AND, the 1st
|
||||
* character is an "E" (Maybe this an unsolicited error
|
||||
* message response?).
|
||||
* Call pasynOctetSyncIO->read().
|
||||
* ENDIF
|
||||
* BREAK
|
||||
* ENDSWITCH
|
||||
*
|
||||
* NORMAL RETURN.
|
||||
*/
|
||||
|
||||
STATIC int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
double timeout = 0.;
|
||||
int flush = 1;
|
||||
size_t nread = 0;
|
||||
int eomReason;
|
||||
asynStatus status;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag != FLUSH)
|
||||
{
|
||||
flush = 0;
|
||||
timeout = SERIAL_TIMEOUT;
|
||||
}
|
||||
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
if (nread > 3 && com[0] == 'E')
|
||||
{
|
||||
long error;
|
||||
|
||||
error = strtol(&com[1], NULL, 0);
|
||||
if (error >= 35 && error <= 42)
|
||||
{
|
||||
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
}
|
||||
}
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Test for "system error" response. */
|
||||
if (com[0] == 'E')
|
||||
{
|
||||
errPrintf( -1, __FILE__, __LINE__, "%s\n", com);
|
||||
return(recv_mess(card, com, flag));
|
||||
}
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return((int)nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* MM3000Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
MM3000Setup(int num_cards, /* maximum number of controllers in system. */
|
||||
int scan_rate) /* polling rate - 1/60 sec units. */
|
||||
{
|
||||
int itera;
|
||||
|
||||
if (num_cards < 1 || num_cards > MM3000_NUM_CARDS)
|
||||
MM3000_num_cards = MM3000_NUM_CARDS;
|
||||
else
|
||||
MM3000_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before MM3000Config is called, so it cannot be done in motor_init()
|
||||
* This means that we must allocate space for a card without knowing
|
||||
* if it really exists, which is not a serious problem
|
||||
*/
|
||||
motor_state = (struct controller **) malloc(MM3000_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < MM3000_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* MM3000Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
MM3000Config(int card, /* card being configured */
|
||||
const char *port, /* asyn port name */
|
||||
int address) /* asyn address (GPIB) */
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
if (card < 0 || card >= MM3000_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct MMcontroller));
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, port);
|
||||
cntrl->asyn_address = address;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
STATIC int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char axis_pos[BUFF_SIZE];
|
||||
char buff[BUFF_SIZE];
|
||||
char *tok_save, *bufptr;
|
||||
int total_axis = 0;
|
||||
int status=0;
|
||||
asynStatus success_rtn;
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (MM3000_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
tok_save = NULL;
|
||||
|
||||
for (card_index = 0; card_index < MM3000_num_cards; card_index++)
|
||||
{
|
||||
if (!motor_state[card_index])
|
||||
continue;
|
||||
|
||||
brdptr = motor_state[card_index];
|
||||
brdptr->cmnd_response = false;
|
||||
total_cards = card_index + 1;
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
|
||||
cntrl->asyn_address, &cntrl->pasynUser, NULL);
|
||||
if (success_rtn == asynSuccess)
|
||||
{
|
||||
/* Send a message to the board, see if it exists */
|
||||
/* flush any junk at input port - should not be any data available */
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL);
|
||||
status = recv_mess(card_index, axis_pos, 1);
|
||||
/* Return value is length of response string */
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
send_mess(card_index, STOP_ALL, (char*) NULL); /* Stop all motors */
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL); /* Read controller ID string */
|
||||
recv_mess(card_index, buff, 1);
|
||||
strncpy(brdptr->ident, &buff[0], MAX_IDENT_LEN); /* Skip "VE" */
|
||||
|
||||
send_mess(card_index, "RC", (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
bufptr = epicsStrtok_r(buff, "=", &tok_save);
|
||||
bufptr = epicsStrtok_r(NULL, " ", &tok_save);
|
||||
|
||||
/* The return string will tell us how many axes this controller has */
|
||||
for (total_axis = 0; bufptr != NULL; total_axis++)
|
||||
{
|
||||
if (strncmp(bufptr, "unused", 6) == 0)
|
||||
{
|
||||
cntrl->type[total_axis] = UNUSED;
|
||||
bufptr = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strncmp(bufptr, "stepper1.5M",11) == 0)
|
||||
cntrl->type[total_axis] = STEPPER;
|
||||
else if (strncmp(bufptr, "dc", 2) == 0)
|
||||
cntrl->type[total_axis] = DC;
|
||||
else
|
||||
errlogPrintf("drvMM3000:motor_init() - invalid RC response = %s\n",
|
||||
bufptr);
|
||||
|
||||
bufptr = epicsStrtok_r(NULL, "=", &tok_save);
|
||||
bufptr = epicsStrtok_r(NULL, " ", &tok_save);
|
||||
}
|
||||
|
||||
/* Initialize. */
|
||||
brdptr->motor_info[total_axis].motor_motion = NULL;
|
||||
}
|
||||
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
|
||||
if (cntrl->type[total_axis] == DC)
|
||||
motor_info->encoder_present = YES;
|
||||
else
|
||||
{
|
||||
sprintf(buff, "%dTPE", motor_index + 1);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
|
||||
if (strcmp(buff, "E01") == 0)
|
||||
motor_info->encoder_present = NO;
|
||||
else
|
||||
motor_info->encoder_present = YES;
|
||||
}
|
||||
|
||||
if (motor_info->encoder_present == YES)
|
||||
{
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = YES;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
}
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "MM3000_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
/*---------------------------------------------------------------------*/
|
||||
@@ -1,833 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvMM4000.cc
|
||||
USAGE... Motor record driver level support for Newport MM4000.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Date: 10/20/97
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
*
|
||||
* NOTES
|
||||
* -----
|
||||
* Verified with firmware:
|
||||
*
|
||||
* - MM4000 2.04
|
||||
* - MM4005 2.40
|
||||
* - MM4005 2.42
|
||||
* - MM4005 3.14b
|
||||
* - MM4006 7.01c date 04-02-2004
|
||||
*
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 10-20-97 mlr initialized from drvOms58
|
||||
* .02 10-30-97 mlr Replaced driver calls with gpipIO functions
|
||||
* .03 10-30-98 mlr Minor code cleanup, improved formatting
|
||||
* .04 02-01-99 mlr Added temporary fix to delay reading motor positions at
|
||||
* the end of a move.
|
||||
* .05 10-13-99 rls modified for standardized motor record.
|
||||
* .06 09-17-01 rls
|
||||
* - created a bit-field for motor status response.
|
||||
* - start_status() allows one retry after a communication error.
|
||||
* - set_status() sets RA_PROBLEM along with CNTRL_COMM_ERR to terminate node.
|
||||
* .07 05-19-03 rls Converted to R3.14.x.
|
||||
* .08 11-04-03 mlr Added a final poll of motor status if drvMM4000ReadbackDelay is
|
||||
* non-zero. This is required to work around a bug in the firmware
|
||||
* (versions 2.40 and 2.44) that the motor is reported as done moving
|
||||
* on the first poll after a move is begun with the motor power off.
|
||||
* .09 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR".
|
||||
* .10 07/09/04 rls removed unused <driver>Setup() argument.
|
||||
* .11 07/28/04 rls "epicsExport" debug variable.
|
||||
* .12 09/21/04 rls support for 32axes/controller.
|
||||
* .13 12/21/04 rls
|
||||
* - support for MM4006.
|
||||
* - MS Visual C compatibility; make all epicsExportAddress extern "C" linkage.
|
||||
* - make debug variables always available.
|
||||
* .14 02/18/09 rls Check for controller error.
|
||||
* .15 02/17/10 rls Bug fix controller error check overwriting position buffer.
|
||||
* .16 08/25/11 kmp Bug fix for drvMM4000Readback delay. The first call after the
|
||||
* readback delay now gets and sets the status properly. Also, the delay
|
||||
* was changed from a double (seconds) to an int (milliseconds) because
|
||||
* of problems passing floating-point values from the VxWorks shell.
|
||||
* .17 08/25/11 rls - Added feedback position.
|
||||
* - Increased max. # of cards to 10 and buffer size to 160 bytes.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsString.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motor.h"
|
||||
#include "NewportRegister.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define READ_RESOLUTION "TU;"
|
||||
#define READ_STATUS "MS;"
|
||||
#define READ_POSITION "TH;"
|
||||
#define READ_FEEDBACK "TP;"
|
||||
#define STOP_ALL "ST;"
|
||||
#define MOTOR_ON "MO;"
|
||||
#define GET_IDENT "VE;"
|
||||
|
||||
/* Status byte bits */
|
||||
#define M_AXIS_MOVING 0x01
|
||||
#define M_MOTOR_POWER 0x02
|
||||
#define M_MOTOR_DIRECTION 0x04
|
||||
#define M_PLUS_LIMIT 0x08
|
||||
#define M_MINUS_LIMIT 0x10
|
||||
#define M_HOME_SIGNAL 0x20
|
||||
|
||||
#define MM4000_NUM_CARDS 10
|
||||
#define BUFF_SIZE 160 /* Maximum length of string to/from MM4000 */
|
||||
|
||||
#define TIMEOUT 2.0 /* Command timeout in sec. */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvMM4000debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvMM4000debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvMM4000debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int MM4000_num_cards = 0;
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/* This is a temporary fix to introduce a delayed reading of the motor
|
||||
* position after a move completes. drvMM4000ReadbackDelay is in milliseconds
|
||||
*/
|
||||
volatile int drvMM4000ReadbackDelay = 0;
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *name);
|
||||
static void start_status(int card);
|
||||
static int set_status(int card, int signal);
|
||||
static long report(int level);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table MM4000_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
start_status,
|
||||
&initialized,
|
||||
NULL
|
||||
};
|
||||
|
||||
struct drvMM4000_drvet
|
||||
{
|
||||
long number;
|
||||
#ifdef __cplusplus
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
#else
|
||||
DRVSUPFUN report;
|
||||
DRVSUPFUN init;
|
||||
#endif
|
||||
} drvMM4000 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvMM4000);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &MM4000_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (MM4000_num_cards <=0)
|
||||
printf(" No MM4000 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < MM4000_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" MM4000 controller %d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
printf(" MM4000 controller %d, port=%s, address=%d, id: %s \n",
|
||||
card, cntrl->asyn_port, cntrl->asyn_address,
|
||||
brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (MM4000_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): MM4000 driver disabled. MM4000Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************
|
||||
* Read the status and position of all motors on a card
|
||||
* start_status(int card)
|
||||
* if card == -1 then start all cards
|
||||
*********************************************************/
|
||||
static void start_status(int card)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
int itera, status;
|
||||
|
||||
if (card >= 0)
|
||||
{
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
send_mess(card, READ_STATUS, (char*) NULL);
|
||||
status = recv_mess(card, cntrl->status_string, 1);
|
||||
if (status > 0)
|
||||
{
|
||||
cntrl->status = NORMAL;
|
||||
send_mess(card, READ_POSITION, (char*) NULL);
|
||||
recv_mess(card, cntrl->position_string, 1);
|
||||
send_mess(card, READ_FEEDBACK, (char*) NULL);
|
||||
recv_mess(card, cntrl->feedback_string, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
cntrl->status = RETRY;
|
||||
else
|
||||
cntrl->status = COMM_ERR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* For efficiency we send messages to all cards, then read all
|
||||
* responses. This minimizes the latency due to processing on each card
|
||||
*/
|
||||
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
|
||||
send_mess(itera, READ_STATUS, (char*) NULL);
|
||||
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
|
||||
{
|
||||
cntrl = (struct MMcontroller *) motor_state[itera]->DevicePrivate;
|
||||
status = recv_mess(itera, cntrl->status_string, 1);
|
||||
if (status > 0)
|
||||
{
|
||||
cntrl->status = NORMAL;
|
||||
send_mess(itera, READ_FEEDBACK, (char*) NULL);
|
||||
recv_mess(itera, cntrl->feedback_string, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
cntrl->status = RETRY;
|
||||
else
|
||||
cntrl->status = COMM_ERR;
|
||||
}
|
||||
}
|
||||
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
|
||||
send_mess(itera, READ_POSITION, (char*) NULL);
|
||||
for (itera = 0; (itera < total_cards) && motor_state[itera]; itera++)
|
||||
{
|
||||
cntrl = (struct MMcontroller *) motor_state[itera]->DevicePrivate;
|
||||
recv_mess(itera, cntrl->position_string, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* Parse status and position strings for a card and signal
|
||||
* set_status()
|
||||
************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
register struct mess_info *motor_info;
|
||||
/* Message parsing variables */
|
||||
char *p, *tok_save;
|
||||
char buff[BUFF_SIZE];
|
||||
int itera, pos;
|
||||
MOTOR_STATUS mstat;
|
||||
int rtn_state;
|
||||
double motorData;
|
||||
bool plusdir, ls_active = false;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
if (cntrl->status != NORMAL)
|
||||
{
|
||||
if (cntrl->status == COMM_ERR)
|
||||
{
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtn_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
|
||||
nodeptr = motor_info->motor_motion;
|
||||
|
||||
/*
|
||||
* Parse the status string
|
||||
* Status string format: 1MSx,2MSy,3MSz,... where x, y and z are the status
|
||||
* bytes for the motors
|
||||
*/
|
||||
pos = signal*5 + 3; /* Offset in status string */
|
||||
mstat.All = cntrl->status_string[pos];
|
||||
Debug(5, "set_status(): status byte = %x on card #%d\n", mstat.All, card);
|
||||
|
||||
status.Bits.RA_DIRECTION = (mstat.Bits.direction == false) ? 0 : 1;
|
||||
|
||||
plusdir = (status.Bits.RA_DIRECTION) ? true : false;
|
||||
|
||||
if (mstat.Bits.inmotion == false)
|
||||
{
|
||||
status.Bits.RA_DONE = 1;
|
||||
/* TEMPORARY FIX, Mark Rivers, 2/1/99. The MM4000 has reported that the
|
||||
* motor is done moving, which means that the "jerk time" is done. However,
|
||||
* the axis can still be settling. For now we put in a delay and poll the
|
||||
* motor position again. This is not a good long-term solution.
|
||||
*
|
||||
* Another TEMPORARY FIX, Mark Rivers, 4/13/03. The MM4000 has reported that
|
||||
* the motor is done moving. However, if the motor power was off, and the firmware
|
||||
* version is 2.43 or 2.44 then the controller "lies" and says the motor is done
|
||||
* on the first poll, when it is really moving. We work around this by reading
|
||||
* the status again after the delay, in case it is really still moving.
|
||||
*/
|
||||
if (motor_info->pid_present == YES && drvMM4000ReadbackDelay != 0)
|
||||
{
|
||||
epicsThreadSleep((double) drvMM4000ReadbackDelay/1000.0);
|
||||
send_mess(card, READ_STATUS, (char*) NULL);
|
||||
recv_mess(card, cntrl->status_string, 1);
|
||||
pos = signal*5 + 3; /* Offset in status string */
|
||||
mstat.All = cntrl->status_string[pos];
|
||||
if (mstat.Bits.inmotion == true)
|
||||
status.Bits.RA_DONE = 0;
|
||||
send_mess(card, READ_POSITION, 0);
|
||||
recv_mess(card, cntrl->position_string, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
status.Bits.RA_DONE = 0;
|
||||
|
||||
/* Set Travel limit switch status bits. */
|
||||
if (mstat.Bits.plustTL == false)
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
if (plusdir == true)
|
||||
ls_active = true;
|
||||
}
|
||||
|
||||
if (mstat.Bits.minusTL == false)
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
if (plusdir == false)
|
||||
ls_active = true;
|
||||
}
|
||||
|
||||
status.Bits.RA_HOME = (mstat.Bits.homels == false) ? 0 : 1;
|
||||
status.Bits.EA_POSITION = (mstat.Bits.NOT_power == false) ? 1 : 0;
|
||||
|
||||
/* encoder status */
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
/*
|
||||
* Parse motor position
|
||||
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
|
||||
* Skip to substring for this motor, convert to double
|
||||
*/
|
||||
|
||||
strcpy(buff, cntrl->position_string);
|
||||
tok_save = NULL;
|
||||
p = epicsStrtok_r(buff, ",", &tok_save);
|
||||
for (itera = 0; itera < signal; itera++)
|
||||
p = epicsStrtok_r(NULL, ",", &tok_save);
|
||||
Debug(6, "set_status(): position substring = %s on card #%d\n", p, card);
|
||||
motorData = atof(p+3) / cntrl->drive_resolution[signal];
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
motor_info->position = NINT(motorData);
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
if (motor_state[card]->motor_info[signal].encoder_present == YES)
|
||||
{
|
||||
strcpy(buff, cntrl->feedback_string);
|
||||
tok_save = NULL;
|
||||
p = epicsStrtok_r(buff, ",", &tok_save);
|
||||
for (itera = 0; itera < signal; itera++)
|
||||
p = epicsStrtok_r(NULL, ",", &tok_save);
|
||||
Debug(6, "set_status(): feedback substring = %s on card #%d\n", p, card);
|
||||
motorData = atof(p+3) / cntrl->drive_resolution[signal];
|
||||
motor_info->encoder_position = (epicsInt32) motorData;
|
||||
}
|
||||
else
|
||||
motor_info->encoder_position = 0;
|
||||
|
||||
|
||||
/* Check for controller error. */
|
||||
send_mess(card, "TE;", (char*) NULL);
|
||||
recv_mess(card, buff, 1);
|
||||
if (buff[2] == '@')
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
else
|
||||
{
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the MM4000 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
size_t size;
|
||||
size_t nwrite;
|
||||
|
||||
size = strlen(com);
|
||||
|
||||
if (size > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvMM4000.c:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (size == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvMM4000.c:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
if (name != NULL)
|
||||
{
|
||||
errlogPrintf("drvMM4000.c:send_mess() - invalid argument = %s\n", name);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s on card #%d\n", com, card);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION... recv_mess(int card, char *com, int flag)
|
||||
*
|
||||
* INPUT ARGUMENTS...
|
||||
* card - controller card # (0,1,...).
|
||||
* *com - caller's response buffer.
|
||||
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
|
||||
* | !FLUSH = retrieve response into caller's buffer; set timeout.
|
||||
*
|
||||
* LOGIC...
|
||||
* IF controller card does not exist.
|
||||
* ERROR RETURN.
|
||||
* ENDIF
|
||||
* NORMAL RETURN.
|
||||
*/
|
||||
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
double timeout = 0.;
|
||||
size_t nread = 0;
|
||||
asynStatus status;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
timeout = TIMEOUT;
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\" on card #%d\n", com, card);
|
||||
return((int)nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* MM4000Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
MM4000Setup(int num_cards, /* maximum number of controllers in system. */
|
||||
int scan_rate) /* polling rate - 1/60 sec units. */
|
||||
{
|
||||
int itera;
|
||||
|
||||
if (num_cards < 1 || num_cards > MM4000_NUM_CARDS)
|
||||
{
|
||||
epicsThreadSleep(5.0);
|
||||
errlogPrintf("\n*** ERROR *** Number specified (%d) exceeds maximum allowed (%d).\n\n", num_cards, MM4000_NUM_CARDS);
|
||||
epicsThreadSleep(5.0);
|
||||
MM4000_num_cards = MM4000_NUM_CARDS;
|
||||
}
|
||||
else
|
||||
MM4000_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before MM4000Config is called, so it cannot be done in motor_init()
|
||||
* This means that we must allocate space for a card without knowing
|
||||
* if it really exists, which is not a serious problem
|
||||
*/
|
||||
motor_state = (struct controller **) malloc(MM4000_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < MM4000_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* MM4000Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
MM4000Config(int card, /* card being configured */
|
||||
const char *name, /* asyn port name */
|
||||
int addr) /* asyn address (GPIB) */
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
if (card < 0 || card >= MM4000_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct MMcontroller));
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = addr;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char axis_pos[BUFF_SIZE];
|
||||
char buff[BUFF_SIZE];
|
||||
char *tok_save, *pos_ptr;
|
||||
int total_axis = 0;
|
||||
int status=0, model_num, digits;
|
||||
asynStatus success_rtn;
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (MM4000_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < MM4000_num_cards; card_index++)
|
||||
{
|
||||
if (!motor_state[card_index])
|
||||
continue;
|
||||
|
||||
brdptr = motor_state[card_index];
|
||||
brdptr->cmnd_response = false;
|
||||
total_cards = card_index + 1;
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
|
||||
cntrl->asyn_address, &cntrl->pasynUser, NULL);
|
||||
|
||||
if (success_rtn == asynSuccess)
|
||||
{
|
||||
int retry = 0;
|
||||
|
||||
/* Send a message to the board, see if it exists */
|
||||
/* flush any junk at input port - should not be any data available */
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
|
||||
do
|
||||
{
|
||||
send_mess(card_index, READ_POSITION, (char*) NULL);
|
||||
status = recv_mess(card_index, axis_pos, 1);
|
||||
retry++;
|
||||
/* Return value is length of response string */
|
||||
} while (status == 0 && retry < 3);
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
send_mess(card_index, STOP_ALL, (char*) NULL); /* Stop all motors */
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL); /* Read controller ID string */
|
||||
recv_mess(card_index, buff, 1);
|
||||
strcpy(brdptr->ident, &buff[2]); /* Skip "VE" */
|
||||
|
||||
/* Set Motion Master model indicator. */
|
||||
pos_ptr = strstr(brdptr->ident, "MM");
|
||||
if (pos_ptr == NULL)
|
||||
{
|
||||
errlogPrintf("drvMM4000.c:motor_init() - invalid model = %s\n", brdptr->ident);
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
continue;
|
||||
}
|
||||
model_num = atoi(pos_ptr + 2);
|
||||
if (model_num == 4000)
|
||||
cntrl->model = MM4000;
|
||||
else if (model_num == 4005 || model_num == 4006)
|
||||
cntrl->model = MM4005;
|
||||
else
|
||||
{
|
||||
errlogPrintf("drvMM4000.c:motor_init() - invalid model = %s\n", brdptr->ident);
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
send_mess(card_index, READ_POSITION, (char*) NULL);
|
||||
recv_mess(card_index, axis_pos, 1);
|
||||
|
||||
/* The return string will tell us how many axes this controller has */
|
||||
for (total_axis = 0, tok_save = NULL, pos_ptr = epicsStrtok_r(axis_pos, ",", &tok_save);
|
||||
pos_ptr != 0; pos_ptr = epicsStrtok_r(NULL, ",", &tok_save), total_axis++)
|
||||
brdptr->motor_info[total_axis].motor_motion = NULL;
|
||||
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
start_status(card_index);
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
int loop_state;
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
/* Determine if encoder present based on open/closed loop mode. */
|
||||
sprintf(buff, "%dTC", motor_index + 1);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
loop_state = atoi(&buff[3]); /* Skip first 3 characters */
|
||||
if (loop_state != 0)
|
||||
{
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = YES;
|
||||
}
|
||||
|
||||
/* Determine drive resolution. */
|
||||
sprintf(buff, "%dTU", motor_index + 1);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
cntrl->drive_resolution[motor_index] = atof(&buff[3]);
|
||||
|
||||
digits = (int) -log10(cntrl->drive_resolution[motor_index]) + 2;
|
||||
if (digits < 1)
|
||||
digits = 1;
|
||||
cntrl->res_decpts[motor_index] = digits;
|
||||
|
||||
/* Save home preset position. */
|
||||
sprintf(buff, "%dXH", motor_index + 1);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
cntrl->home_preset[motor_index] = atof(&buff[3]);
|
||||
|
||||
/* Determine low limit */
|
||||
sprintf(buff, "%dTL", motor_index + 1);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
motor_info->low_limit = atof(&buff[3]);
|
||||
|
||||
/* Determine high limit */
|
||||
sprintf(buff, "%dTR", motor_index + 1);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
motor_info->high_limit = atof(&buff[3]);
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "MM4000_motor",
|
||||
epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
@@ -1,959 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvMM4000Asyn.cc
|
||||
USAGE... Motor record asyn driver level support for Newport MM4000.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Date: 05/03/06
|
||||
* Current Author: Mark Rivers
|
||||
*
|
||||
-----------------------------------------------------------------------------
|
||||
COPYRIGHT NOTICE
|
||||
-----------------------------------------------------------------------------
|
||||
Copyright (c) 2002 The University of Chicago, as Operator of Argonne
|
||||
National Laboratory.
|
||||
Copyright (c) 2002 The Regents of the University of California, as
|
||||
Operator of Los Alamos National Laboratory.
|
||||
Synapps Versions 4-5
|
||||
and higher are distributed subject to a Software License Agreement found
|
||||
in file LICENSE that is included with this distribution.
|
||||
-----------------------------------------------------------------------------
|
||||
*
|
||||
* NOTES
|
||||
* -----
|
||||
* Verified with firmware:
|
||||
*
|
||||
* - MM4000 2.04
|
||||
* - MM4005 2.40
|
||||
* - MM4005 2.42
|
||||
* - MM4005 3.14b
|
||||
* - MM4006 7.01c date 04-02-2004
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
*
|
||||
* .01 09-09-08 rls Default to motorAxisHasClosedLoop on from motorAxisInit(),
|
||||
* so that CNEN functions.
|
||||
* .02 01-29-09 rls Copied Matthew Pearson's (Diamond) fix on XPS for;
|
||||
* - idle polling interfering with setting position.
|
||||
* - auto save/restore not working.
|
||||
* .03 02-18-09 rls - Intermittent "set position" problem; set position cmnd.
|
||||
* sometimes occurred during polling causing motor record
|
||||
* to get old position value. Lock/Unlock all controller's
|
||||
* axis during status update.
|
||||
* - Check for controller error.
|
||||
* .04 06-11-09 rls - Matthew Pearson's fix for record seeing motorAxisDone True
|
||||
* on 1st status update after a move; set motorAxisDone False
|
||||
* in motorAxisDrvSET_t functions that start motion
|
||||
* (motorAxisHome, motorAxisMove, motorAxisVelocityMove) and
|
||||
* force a status update with a call to callCallback().
|
||||
* - bug fix; limit commands reversed.
|
||||
* - set motorAxisDirection.
|
||||
* .05 11-19-09 rls - bug fix for sendOnly() passing null pointer
|
||||
* (pController->pasynUser) if any communication error occurs
|
||||
* at bootup.
|
||||
* .06 04-15-10 rls - Apply Matthew Pearson's fix to motorAxisSetInteger().
|
||||
* - Allow MM4005 models to enable/disable torque.
|
||||
* - Reformat some 'if' statements.
|
||||
* .07 11-29-11 rls - 8 axis with max. precision can overflow comm. buffers.
|
||||
* increased from 100 to 160 bytes.
|
||||
* - Wait for power on status response.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include "epicsThread.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "drvMM4000Asyn.h"
|
||||
#include "paramLib.h"
|
||||
|
||||
#include "epicsFindSymbol.h"
|
||||
#include "epicsTime.h"
|
||||
#include "epicsThread.h"
|
||||
#include "epicsEvent.h"
|
||||
#include "epicsString.h"
|
||||
#include "epicsMutex.h"
|
||||
#include "ellLib.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include "errlog.h"
|
||||
|
||||
#include "drvSup.h"
|
||||
#include "epicsExport.h"
|
||||
#define DEFINE_MOTOR_PROTOTYPES 1
|
||||
#include "motor_interface.h"
|
||||
|
||||
motorAxisDrvSET_t motorMM4000 =
|
||||
{
|
||||
14,
|
||||
motorAxisReport, /**< Standard EPICS driver report function (optional) */
|
||||
motorAxisInit, /**< Standard EPICS dirver initialisation function (optional) */
|
||||
motorAxisSetLog, /**< Defines an external logging function (optional) */
|
||||
motorAxisOpen, /**< Driver open function */
|
||||
motorAxisClose, /**< Driver close function */
|
||||
motorAxisSetCallback, /**< Provides a callback function the driver can call when the status updates */
|
||||
motorAxisSetDouble, /**< Pointer to function to set a double value */
|
||||
motorAxisSetInteger, /**< Pointer to function to set an integer value */
|
||||
motorAxisGetDouble, /**< Pointer to function to get a double value */
|
||||
motorAxisGetInteger, /**< Pointer to function to get an integer value */
|
||||
motorAxisHome, /**< Pointer to function to execute a more to reference or home */
|
||||
motorAxisMove, /**< Pointer to function to execute a position move */
|
||||
motorAxisVelocityMove, /**< Pointer to function to execute a velocity mode move */
|
||||
motorAxisStop, /**< Pointer to function to stop motion */
|
||||
motorAxisforceCallback, /**< Pointer to function to request a poller status update */
|
||||
motorAxisProfileMove, /**< Pointer to function to execute a profile move */
|
||||
motorAxisTriggerProfile /**< Pointer to function to trigger a profile move */
|
||||
};
|
||||
|
||||
epicsExportAddress(drvet, motorMM4000);
|
||||
|
||||
typedef enum {
|
||||
MM4000,
|
||||
MM4005
|
||||
} MM_model;
|
||||
|
||||
typedef struct {
|
||||
epicsMutexId MM4000Lock;
|
||||
asynUser *pasynUser;
|
||||
int numAxes;
|
||||
char firmwareVersion[100];
|
||||
MM_model model;
|
||||
double movingPollPeriod;
|
||||
double idlePollPeriod;
|
||||
epicsEventId pollEventId;
|
||||
AXIS_HDL pAxis; /* array of axes */
|
||||
} MM4000Controller;
|
||||
|
||||
typedef struct motorAxisHandle
|
||||
{
|
||||
MM4000Controller *pController;
|
||||
PARAMS params;
|
||||
double currentPosition;
|
||||
double stepSize;
|
||||
double highLimit;
|
||||
double lowLimit;
|
||||
double homePreset;
|
||||
int closedLoop;
|
||||
int axisStatus;
|
||||
int card;
|
||||
int axis;
|
||||
int maxDigits;
|
||||
motorAxisLogFunc print;
|
||||
void *logParam;
|
||||
epicsMutexId mutexId;
|
||||
} motorAxis;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
AXIS_HDL pFirst;
|
||||
epicsThreadId motorThread;
|
||||
motorAxisLogFunc print;
|
||||
void *logParam;
|
||||
epicsTimeStamp now;
|
||||
} motorMM4000_t;
|
||||
|
||||
|
||||
static int motorMM4000LogMsg(void * param, const motorAxisLogMask_t logMask, const char *pFormat, ...);
|
||||
static int sendOnly(MM4000Controller *pController, char *outputString);
|
||||
static asynStatus sendAndReceive(MM4000Controller *pController, char *outputString, char *inputString, int inputSize);
|
||||
|
||||
#define PRINT (drv.print)
|
||||
#define FLOW motorAxisTraceFlow
|
||||
#define MOTOR_ERROR motorAxisTraceError
|
||||
#define IODRIVER motorAxisTraceIODriver
|
||||
|
||||
#define MM4000_MAX_AXES 8
|
||||
#define BUFFER_SIZE 160 /* Size of input and output buffers */
|
||||
#define TIMEOUT 2.0 /* Timeout for I/O in seconds */
|
||||
|
||||
#define MM4000_HOME 0x20 /* Home LS. */
|
||||
#define MM4000_LOW_LIMIT 0x10 /* Minus Travel Limit. */
|
||||
#define MM4000_HIGH_LIMIT 0x08 /* Plus Travel Limit. */
|
||||
#define MM4000_DIRECTION 0x04 /* Motor direction: 0 - minus; 1 - plus. */
|
||||
#define MM4000_POWER_OFF 0x02 /* Motor power 0 - ON; 1 - OFF. */
|
||||
#define MM4000_MOVING 0x01 /* In-motion indicator. */
|
||||
|
||||
|
||||
#define TCP_TIMEOUT 2.0
|
||||
static motorMM4000_t drv={ NULL, NULL, motorMM4000LogMsg, 0, { 0, 0 } };
|
||||
static int numMM4000Controllers;
|
||||
/* Pointer to array of controller strutures */
|
||||
static MM4000Controller *pMM4000Controller=NULL;
|
||||
|
||||
#define MAX(a,b) ((a)>(b)? (a): (b))
|
||||
#define MIN(a,b) ((a)<(b)? (a): (b))
|
||||
|
||||
static void motorAxisReportAxis(AXIS_HDL pAxis, int level)
|
||||
{
|
||||
if (level > 0)
|
||||
{
|
||||
printf("Axis %d\n", pAxis->axis);
|
||||
printf(" axisStatus: 0x%x\n", pAxis->axisStatus);
|
||||
printf(" high limit: %f\n", pAxis->highLimit);
|
||||
printf(" low limit: %f\n", pAxis->lowLimit);
|
||||
printf(" home preset: %f\n", pAxis->homePreset);
|
||||
printf(" step size: %f\n", pAxis->stepSize);
|
||||
printf(" max digits: %d\n", pAxis->maxDigits);
|
||||
}
|
||||
}
|
||||
|
||||
static void motorAxisReport(int level)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for(i=0; i<numMM4000Controllers; i++) {
|
||||
printf("Controller %d firmware version: %s\n", i, pMM4000Controller[i].firmwareVersion);
|
||||
if (level) {
|
||||
printf(" model: %d\n", pMM4000Controller[i].model);
|
||||
printf(" moving poll period: %f\n", pMM4000Controller[i].movingPollPeriod);
|
||||
printf(" idle poll period: %f\n", pMM4000Controller[i].idlePollPeriod);
|
||||
printf("Controller %d firmware version: %s\n", i, pMM4000Controller[i].firmwareVersion);
|
||||
}
|
||||
for(j=0; j<pMM4000Controller[i].numAxes; j++) {
|
||||
motorAxisReportAxis(&pMM4000Controller[i].pAxis[j], level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int motorAxisInit(void)
|
||||
{
|
||||
int controller, axis;
|
||||
|
||||
for (controller = 0; controller < numMM4000Controllers; controller++)
|
||||
{
|
||||
AXIS_HDL pAxis;
|
||||
for (axis = 0; axis < pMM4000Controller[controller].numAxes; axis++)
|
||||
{
|
||||
pAxis = &pMM4000Controller[controller].pAxis[axis];
|
||||
if (!pAxis->mutexId)
|
||||
break;
|
||||
epicsMutexLock(pAxis->mutexId);
|
||||
|
||||
/*Set GAIN_SUPPORT on so that at least, CNEN functions. */
|
||||
motorParam->setInteger(pAxis->params, motorAxisHasClosedLoop, 1);
|
||||
|
||||
motorParam->callCallback(pAxis->params);
|
||||
epicsMutexUnlock(pAxis->mutexId);
|
||||
}
|
||||
}
|
||||
return(MOTOR_AXIS_OK);
|
||||
}
|
||||
|
||||
static int motorAxisSetLog( AXIS_HDL pAxis, motorAxisLogFunc logFunc, void * param )
|
||||
{
|
||||
if (pAxis == NULL)
|
||||
{
|
||||
if (logFunc == NULL)
|
||||
{
|
||||
drv.print=motorMM4000LogMsg;
|
||||
drv.logParam = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
drv.print=logFunc;
|
||||
drv.logParam = param;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (logFunc == NULL)
|
||||
{
|
||||
pAxis->print=motorMM4000LogMsg;
|
||||
pAxis->logParam = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
pAxis->print=logFunc;
|
||||
pAxis->logParam = param;
|
||||
}
|
||||
}
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
static AXIS_HDL motorAxisOpen(int card, int axis, char * param)
|
||||
{
|
||||
AXIS_HDL pAxis;
|
||||
|
||||
if (card > numMM4000Controllers)
|
||||
return(NULL);
|
||||
if (axis > pMM4000Controller[card].numAxes)
|
||||
return(NULL);
|
||||
pAxis = &pMM4000Controller[card].pAxis[axis];
|
||||
return pAxis;
|
||||
}
|
||||
|
||||
static int motorAxisClose(AXIS_HDL pAxis)
|
||||
{
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
static int motorAxisGetInteger(AXIS_HDL pAxis, motorAxisParam_t function, int * value)
|
||||
{
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
else
|
||||
return motorParam->getInteger(pAxis->params, (paramIndex) function, value);
|
||||
}
|
||||
|
||||
static int motorAxisGetDouble(AXIS_HDL pAxis, motorAxisParam_t function, double * value)
|
||||
{
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
else
|
||||
return motorParam->getDouble(pAxis->params, (paramIndex) function, value);
|
||||
}
|
||||
|
||||
static int motorAxisSetCallback(AXIS_HDL pAxis, motorAxisCallbackFunc callback, void * param)
|
||||
{
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
else
|
||||
return motorParam->setCallback(pAxis->params, callback, param);
|
||||
}
|
||||
|
||||
static int motorAxisSetDouble(AXIS_HDL pAxis, motorAxisParam_t function, double value)
|
||||
{
|
||||
int ret_status = MOTOR_AXIS_ERROR;
|
||||
double deviceValue;
|
||||
char buff[100];
|
||||
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
else
|
||||
{
|
||||
epicsMutexLock(pAxis->mutexId);
|
||||
switch (function)
|
||||
{
|
||||
case motorAxisPosition:
|
||||
{
|
||||
deviceValue = value*pAxis->stepSize;
|
||||
sprintf(buff, "%dSH%.*f;%dDH;%dSH%.*f", pAxis->axis+1, pAxis->maxDigits, deviceValue,
|
||||
pAxis->axis+1, pAxis->axis+1, pAxis->maxDigits, pAxis->homePreset);
|
||||
ret_status = sendOnly(pAxis->pController, buff);
|
||||
break;
|
||||
}
|
||||
case motorAxisEncoderRatio:
|
||||
{
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "motorAxisSetDouble: MM4000 does not support setting encoder ratio\n");
|
||||
break;
|
||||
}
|
||||
case motorAxisResolution:
|
||||
{
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "motorAxisSetDouble: MM4000 does not support setting resolution\n");
|
||||
break;
|
||||
}
|
||||
case motorAxisLowLimit:
|
||||
{
|
||||
deviceValue = value*pAxis->stepSize;
|
||||
sprintf(buff, "%dSL%.*f", pAxis->axis+1, pAxis->maxDigits, deviceValue);
|
||||
ret_status = sendOnly(pAxis->pController, buff);
|
||||
break;
|
||||
}
|
||||
case motorAxisHighLimit:
|
||||
{
|
||||
deviceValue = value*pAxis->stepSize;
|
||||
sprintf(buff, "%dSR%.*f", pAxis->axis+1, pAxis->maxDigits, deviceValue);
|
||||
ret_status = sendOnly(pAxis->pController, buff);
|
||||
break;
|
||||
}
|
||||
case motorAxisPGain:
|
||||
{
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000 does not support setting proportional gain\n");
|
||||
break;
|
||||
}
|
||||
case motorAxisIGain:
|
||||
{
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000 does not support setting integral gain\n");
|
||||
break;
|
||||
}
|
||||
case motorAxisDGain:
|
||||
{
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000 does not support setting derivative gain\n");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "motorAxisSetDouble: unknown function %d\n", function);
|
||||
break;
|
||||
}
|
||||
if (ret_status == MOTOR_AXIS_OK )
|
||||
{
|
||||
motorParam->setDouble(pAxis->params, function, value);
|
||||
motorParam->callCallback(pAxis->params);
|
||||
}
|
||||
epicsMutexUnlock(pAxis->mutexId);
|
||||
}
|
||||
return ret_status;
|
||||
}
|
||||
|
||||
static int motorAxisSetInteger(AXIS_HDL pAxis, motorAxisParam_t function, int value)
|
||||
{
|
||||
int ret_status = MOTOR_AXIS_ERROR;
|
||||
char buff[100];
|
||||
|
||||
if (pAxis == NULL)
|
||||
return(MOTOR_AXIS_ERROR);
|
||||
|
||||
epicsMutexLock(pAxis->mutexId);
|
||||
|
||||
switch (function)
|
||||
{
|
||||
case motorAxisClosedLoop:
|
||||
/* The MM4000 only allows turning on and off ALL motors (MO and MF commands), */
|
||||
/* not individual axes. Don't implement */
|
||||
if (pAxis->pController->model == MM4000)
|
||||
ret_status = MOTOR_AXIS_OK;
|
||||
else
|
||||
{
|
||||
if (value == 0)
|
||||
{
|
||||
int axisStatus, powerOn = 0;
|
||||
int offset = (pAxis->axis * 5) + 3; /* Offset in status string */
|
||||
|
||||
sprintf(buff, "%dMF", pAxis->axis + 1);
|
||||
ret_status = sendOnly(pAxis->pController, buff);
|
||||
|
||||
/* Wait for Power to come on. */
|
||||
while (powerOn == 0)
|
||||
{
|
||||
ret_status = sendAndReceive(pAxis->pController, "MS;", buff, sizeof(buff));
|
||||
axisStatus = buff[offset];
|
||||
if (!(axisStatus & MM4000_POWER_OFF))
|
||||
powerOn = 1;
|
||||
else
|
||||
epicsThreadSleep(0.1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(buff, "%dMO", pAxis->axis+1);
|
||||
ret_status = sendOnly(pAxis->pController, buff);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "motorAxisSetInteger: unknown function %d\n", function);
|
||||
break;
|
||||
}
|
||||
if (ret_status != MOTOR_AXIS_ERROR)
|
||||
{
|
||||
motorParam->setInteger(pAxis->params, function, value);
|
||||
motorParam->callCallback(pAxis->params);
|
||||
}
|
||||
epicsMutexUnlock(pAxis->mutexId);
|
||||
return(ret_status);
|
||||
}
|
||||
|
||||
|
||||
static int motorAxisMove(AXIS_HDL pAxis, double position, int relative,
|
||||
double min_velocity, double max_velocity, double acceleration)
|
||||
{
|
||||
int status;
|
||||
char buff[100];
|
||||
char *moveCommand;
|
||||
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
|
||||
PRINT(pAxis->logParam, FLOW, "Set card %d, axis %d move to %f, min vel=%f, max_vel=%f, accel=%f\n",
|
||||
pAxis->card, pAxis->axis, position, min_velocity, max_velocity, acceleration);
|
||||
|
||||
if (relative) {
|
||||
moveCommand = "PR";
|
||||
} else {
|
||||
moveCommand = "PA";
|
||||
}
|
||||
sprintf(buff, "%dAC%.*f;%dVA%.*f;%d%s%.*f;",
|
||||
pAxis->axis+1, pAxis->maxDigits, acceleration * pAxis->stepSize,
|
||||
pAxis->axis+1, pAxis->maxDigits, max_velocity * pAxis->stepSize,
|
||||
pAxis->axis+1, moveCommand, pAxis->maxDigits, position * pAxis->stepSize);
|
||||
status = sendOnly(pAxis->pController, buff);
|
||||
if (status)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
|
||||
if (epicsMutexLock(pAxis->mutexId) == epicsMutexLockOK)
|
||||
{
|
||||
/* Insure that the motor record's next status update sees motorAxisDone = False. */
|
||||
motorParam->setInteger(pAxis->params, motorAxisDone, 0);
|
||||
motorParam->callCallback(pAxis->params);
|
||||
epicsMutexUnlock(pAxis->mutexId);
|
||||
}
|
||||
|
||||
/* Send a signal to the poller task which will make it do a poll, and switch to the moving poll rate */
|
||||
epicsEventSignal(pAxis->pController->pollEventId);
|
||||
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
static int motorAxisHome(AXIS_HDL pAxis, double min_velocity, double max_velocity, double acceleration, int forwards)
|
||||
{
|
||||
int status;
|
||||
char buff[100];
|
||||
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
|
||||
PRINT(pAxis->logParam, FLOW, "motorAxisHome: set card %d, axis %d to home\n",
|
||||
pAxis->card, pAxis->axis);
|
||||
|
||||
sprintf(buff, "%dAC%.*f; %dVA%.*f;%dOR;",
|
||||
pAxis->axis+1, pAxis->maxDigits, acceleration * pAxis->stepSize,
|
||||
pAxis->axis+1, pAxis->maxDigits, max_velocity * pAxis->stepSize,
|
||||
pAxis->axis+1);
|
||||
status = sendOnly(pAxis->pController, buff);
|
||||
if (status)
|
||||
return(MOTOR_AXIS_ERROR);
|
||||
|
||||
if (epicsMutexLock(pAxis->mutexId) == epicsMutexLockOK)
|
||||
{
|
||||
/* Insure that the motor record's next status update sees motorAxisDone = False. */
|
||||
motorParam->setInteger(pAxis->params, motorAxisDone, 0);
|
||||
motorParam->callCallback(pAxis->params);
|
||||
epicsMutexUnlock(pAxis->mutexId);
|
||||
}
|
||||
|
||||
/* Send a signal to the poller task which will make it do a poll, and switch to the moving poll rate */
|
||||
epicsEventSignal(pAxis->pController->pollEventId);
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
|
||||
static int motorAxisVelocityMove(AXIS_HDL pAxis, double min_velocity, double velocity, double acceleration)
|
||||
{
|
||||
int status;
|
||||
|
||||
if (pAxis == NULL)
|
||||
return(MOTOR_AXIS_ERROR);
|
||||
|
||||
/* MM4000 does not have a jog command. Simulate with move absolute
|
||||
* to the appropriate software limit. We can move to MM4000 soft limits.
|
||||
* If the record soft limits are set tighter than the MM4000 limits
|
||||
* the record will prevent JOG motion beyond its soft limits
|
||||
*/
|
||||
if (velocity > 0.)
|
||||
status = motorAxisMove(pAxis, pAxis->highLimit/pAxis->stepSize, 0, min_velocity, velocity, acceleration);
|
||||
else
|
||||
status = motorAxisMove(pAxis, pAxis->lowLimit/pAxis->stepSize, 0, min_velocity, -velocity, acceleration);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int motorAxisProfileMove(AXIS_HDL pAxis, int npoints, double positions[], double times[], int relative, int trigger)
|
||||
{
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
|
||||
static int motorAxisTriggerProfile(AXIS_HDL pAxis)
|
||||
{
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
|
||||
static int motorAxisStop(AXIS_HDL pAxis, double acceleration)
|
||||
{
|
||||
int status;
|
||||
char buff[100];
|
||||
|
||||
if (pAxis == NULL)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
|
||||
PRINT(pAxis->logParam, FLOW, "Set card %d, axis %d to stop with accel=%f\n",
|
||||
pAxis->card, pAxis->axis, acceleration);
|
||||
|
||||
sprintf(buff, "%dAC%.*f;%dST;",
|
||||
pAxis->axis+1, pAxis->maxDigits, acceleration * pAxis->stepSize,
|
||||
pAxis->axis+1);
|
||||
status = sendOnly(pAxis->pController, buff);
|
||||
if (status)
|
||||
return MOTOR_AXIS_ERROR;
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
static int motorAxisforceCallback(AXIS_HDL pAxis)
|
||||
{
|
||||
if (pAxis == NULL)
|
||||
return (MOTOR_AXIS_ERROR);
|
||||
|
||||
PRINT(pAxis->logParam, FLOW, "motorAxisforceCallback: request card %d, axis %d status update\n",
|
||||
pAxis->card, pAxis->axis);
|
||||
|
||||
/* Force a status update. */
|
||||
motorParam->forceCallback(pAxis->params);
|
||||
|
||||
/* Send a signal to the poller task which will make it do a status update */
|
||||
epicsEventSignal(pAxis->pController->pollEventId);
|
||||
return (MOTOR_AXIS_OK);
|
||||
}
|
||||
|
||||
|
||||
static void MM4000Poller(MM4000Controller *pController)
|
||||
{
|
||||
/* This is the task that polls the MM4000 */
|
||||
double timeout;
|
||||
AXIS_HDL pAxis;
|
||||
int status;
|
||||
int itera, j;
|
||||
int axisDone;
|
||||
int offset;
|
||||
int anyMoving;
|
||||
int comStatus;
|
||||
int forcedFastPolls=0;
|
||||
char *p, *tokSave;
|
||||
char statusAllString[BUFFER_SIZE];
|
||||
char positionAllString[BUFFER_SIZE];
|
||||
char buff[BUFFER_SIZE];
|
||||
|
||||
timeout = pController->idlePollPeriod;
|
||||
epicsEventSignal(pController->pollEventId); /* Force on poll at startup */
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (timeout != 0.)
|
||||
status = epicsEventWaitWithTimeout(pController->pollEventId, timeout);
|
||||
else
|
||||
status = epicsEventWait(pController->pollEventId);
|
||||
|
||||
if (status == epicsEventWaitOK)
|
||||
{
|
||||
/* We got an event, rather than a timeout. This is because other software
|
||||
* knows that an axis should have changed state (started moving, etc.).
|
||||
* Force a minimum number of fast polls, because the controller status
|
||||
* might not have changed the first few polls
|
||||
*/
|
||||
forcedFastPolls = 10;
|
||||
}
|
||||
|
||||
anyMoving = 0;
|
||||
|
||||
/* Lock all the controller's axis. */
|
||||
for (itera = 0; itera < pController->numAxes; itera++)
|
||||
{
|
||||
pAxis = &pController->pAxis[itera];
|
||||
if (!pAxis->mutexId)
|
||||
break;
|
||||
epicsMutexLock(pAxis->mutexId);
|
||||
}
|
||||
|
||||
comStatus = sendAndReceive(pController, "MS;", statusAllString, sizeof(statusAllString));
|
||||
if (comStatus == 0)
|
||||
comStatus = sendAndReceive(pController, "TP;", positionAllString, sizeof(positionAllString));
|
||||
|
||||
for (itera=0; itera < pController->numAxes; itera++)
|
||||
{
|
||||
pAxis = &pController->pAxis[itera];
|
||||
if (!pAxis->mutexId)
|
||||
break;
|
||||
if (comStatus != 0)
|
||||
{
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000Poller: error reading status=%d\n", comStatus);
|
||||
motorParam->setInteger(pAxis->params, motorAxisCommError, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
PARAMS params = pAxis->params;
|
||||
int intval, axisStatus;
|
||||
|
||||
motorParam->setInteger(params, motorAxisCommError, 0);
|
||||
/*
|
||||
* Parse the status string
|
||||
* Status string format: 1MSx,2MSy,3MSz,... where x, y and z are the status
|
||||
* bytes for the motors
|
||||
*/
|
||||
offset = pAxis->axis*5 + 3; /* Offset in status string */
|
||||
axisStatus = pAxis->axisStatus = statusAllString[offset];
|
||||
if (axisStatus & MM4000_MOVING)
|
||||
{
|
||||
axisDone = 0;
|
||||
anyMoving = 1;
|
||||
}
|
||||
else
|
||||
axisDone = 1;
|
||||
motorParam->setInteger(params, motorAxisDone, axisDone);
|
||||
|
||||
motorParam->setInteger(params, motorAxisHomeSignal, (axisStatus & MM4000_HOME));
|
||||
motorParam->setInteger(params, motorAxisHighHardLimit, (axisStatus & MM4000_HIGH_LIMIT));
|
||||
motorParam->setInteger(params, motorAxisLowHardLimit, (axisStatus & MM4000_LOW_LIMIT));
|
||||
motorParam->setInteger(params, motorAxisDirection, (axisStatus & MM4000_DIRECTION));
|
||||
motorParam->setInteger(params, motorAxisPowerOn, !(axisStatus & MM4000_POWER_OFF));
|
||||
|
||||
/*
|
||||
* Parse motor position
|
||||
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
|
||||
* Skip to substring for this motor, convert to double
|
||||
*/
|
||||
|
||||
strcpy(buff, positionAllString);
|
||||
tokSave = NULL;
|
||||
p = epicsStrtok_r(buff, ",", &tokSave);
|
||||
for (j=0; j < pAxis->axis; j++)
|
||||
p = epicsStrtok_r(NULL, ",", &tokSave);
|
||||
pAxis->currentPosition = atof(p+3);
|
||||
motorParam->setDouble(params, motorAxisPosition, (pAxis->currentPosition/pAxis->stepSize));
|
||||
motorParam->setDouble(params, motorAxisEncoderPosn, (pAxis->currentPosition/pAxis->stepSize));
|
||||
PRINT(pAxis->logParam, IODRIVER, "MM4000Poller: axis %d axisStatus=%x, position=%f\n",
|
||||
pAxis->axis, pAxis->axisStatus, pAxis->currentPosition);
|
||||
|
||||
/* We would like a way to query the actual velocity, but this is not possible. If we could we could
|
||||
* set the direction, and Moving flags */
|
||||
|
||||
/* Check for controller error. */
|
||||
comStatus = sendAndReceive(pController, "TE;", buff, sizeof(statusAllString));
|
||||
if (buff[2] == '@')
|
||||
intval = 0;
|
||||
else
|
||||
{
|
||||
intval = 1;
|
||||
PRINT(pAxis->logParam, MOTOR_ERROR, "MM4000Poller: controller error %s\n", buff);
|
||||
}
|
||||
motorParam->setInteger(params, motorAxisProblem, intval);
|
||||
}
|
||||
|
||||
motorParam->callCallback(pAxis->params);
|
||||
} /* Next axis */
|
||||
|
||||
/* UnLock all the controller's axis. */
|
||||
for (itera = 0; itera < pController->numAxes; itera++)
|
||||
{
|
||||
pAxis = &pController->pAxis[itera];
|
||||
if (!pAxis->mutexId)
|
||||
break;
|
||||
epicsMutexUnlock(pAxis->mutexId);
|
||||
}
|
||||
|
||||
if (forcedFastPolls > 0)
|
||||
{
|
||||
timeout = pController->movingPollPeriod;
|
||||
forcedFastPolls--;
|
||||
}
|
||||
else if (anyMoving)
|
||||
timeout = pController->movingPollPeriod;
|
||||
else
|
||||
timeout = pController->idlePollPeriod;
|
||||
} /* End while */
|
||||
}
|
||||
|
||||
static int motorMM4000LogMsg(void * param, const motorAxisLogMask_t mask, const char *pFormat, ...)
|
||||
{
|
||||
|
||||
va_list pvar;
|
||||
int nchar;
|
||||
|
||||
va_start(pvar, pFormat);
|
||||
nchar = vfprintf(stdout,pFormat,pvar);
|
||||
va_end (pvar);
|
||||
printf("\n");
|
||||
return(nchar);
|
||||
}
|
||||
|
||||
|
||||
int MM4000AsynSetup(int num_controllers) /* number of MM4000 controllers in system. */
|
||||
{
|
||||
|
||||
if (num_controllers < 1) {
|
||||
printf("MM4000Setup, num_controllers must be > 0\n");
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
numMM4000Controllers = num_controllers;
|
||||
pMM4000Controller = (MM4000Controller *)calloc(numMM4000Controllers, sizeof(MM4000Controller));
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
|
||||
int MM4000AsynConfig(int card, /* Controller number */
|
||||
const char *portName, /* asyn port name of serial or GPIB port */
|
||||
int asynAddress, /* asyn subaddress for GPIB */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod) /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
|
||||
{
|
||||
AXIS_HDL pAxis;
|
||||
int axis;
|
||||
MM4000Controller *pController;
|
||||
char threadName[20];
|
||||
int status;
|
||||
int totalAxes;
|
||||
int loopState;
|
||||
int digits;
|
||||
int modelNum;
|
||||
int retry = 0;
|
||||
char *p, *tokSave;
|
||||
char inputBuff[BUFFER_SIZE];
|
||||
char outputBuff[BUFFER_SIZE];
|
||||
|
||||
if (numMM4000Controllers < 1) {
|
||||
printf("MM4000Config: no MM4000 controllers allocated, call MM4000Setup first\n");
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
if ((card < 0) || (card >= numMM4000Controllers)) {
|
||||
printf("MM4000Config: card must in range 0 to %d\n", numMM4000Controllers-1);
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
if ((numAxes < 1) || (numAxes > MM4000_MAX_AXES)) {
|
||||
printf("MM4000Config: numAxes must in range 1 to %d\n", MM4000_MAX_AXES);
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
|
||||
pController = &pMM4000Controller[card];
|
||||
pController->pAxis = (AXIS_HDL) calloc(numAxes, sizeof(motorAxis));
|
||||
pController->numAxes = numAxes;
|
||||
pController->movingPollPeriod = movingPollPeriod/1000.;
|
||||
pController->idlePollPeriod = idlePollPeriod/1000.;
|
||||
|
||||
status = pasynOctetSyncIO->connect(portName, asynAddress, &pController->pasynUser, NULL);
|
||||
|
||||
if (status != asynSuccess) {
|
||||
printf("MM4000AsynConfig: cannot connect to asyn port %s\n", portName);
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
status = sendAndReceive(pController, "VE;", inputBuff, sizeof(inputBuff));
|
||||
retry++;
|
||||
/* Return value is length of response string */
|
||||
} while (status != asynSuccess && retry < 3);
|
||||
|
||||
if (status != asynSuccess)
|
||||
return (MOTOR_AXIS_ERROR);
|
||||
|
||||
strcpy(pController->firmwareVersion, &inputBuff[2]); /* Skip "VE" */
|
||||
|
||||
/* Set Motion Master model indicator. */
|
||||
p = strstr(pController->firmwareVersion, "MM");
|
||||
if (p == NULL) {
|
||||
printf("MM4000AsynConfig: invalid model = %s\n", pController->firmwareVersion);
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
modelNum = atoi(p+2);
|
||||
if (modelNum == 4000)
|
||||
pController->model = MM4000;
|
||||
else if (modelNum == 4005 || modelNum == 4006)
|
||||
pController->model = MM4005;
|
||||
else
|
||||
{
|
||||
printf("MM4000AsynConfig: invalid model = %s\n", pController->firmwareVersion);
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
|
||||
sendAndReceive(pController, "TP;", inputBuff, sizeof(inputBuff));
|
||||
|
||||
/* The return string will tell us how many axes this controller has */
|
||||
for (totalAxes = 0, tokSave = NULL, p = epicsStrtok_r(inputBuff, ",", &tokSave);
|
||||
p != 0; p = epicsStrtok_r(NULL, ",", &tokSave), totalAxes++)
|
||||
;
|
||||
|
||||
if (totalAxes < numAxes)
|
||||
{
|
||||
printf("MM4000AsynConfig: actual number of axes=%d < numAxes=%d\n", totalAxes, numAxes);
|
||||
return MOTOR_AXIS_ERROR;
|
||||
}
|
||||
|
||||
for (axis=0; axis<numAxes; axis++) {
|
||||
pAxis = &pController->pAxis[axis];
|
||||
pAxis->pController = pController;
|
||||
pAxis->card = card;
|
||||
pAxis->axis = axis;
|
||||
pAxis->mutexId = epicsMutexMustCreate();
|
||||
pAxis->params = motorParam->create(0, MOTOR_AXIS_NUM_PARAMS);
|
||||
|
||||
/* Determine if encoder present based on open/closed loop mode. */
|
||||
sprintf(outputBuff, "%dTC", axis+1);
|
||||
sendAndReceive(pController, outputBuff, inputBuff, sizeof(inputBuff));
|
||||
loopState = atoi(&inputBuff[3]); /* Skip first 3 characters */
|
||||
if (loopState != 0)
|
||||
pAxis->closedLoop = 1;
|
||||
|
||||
/* Determine drive resolution. */
|
||||
sprintf(outputBuff, "%dTU", axis+1);
|
||||
sendAndReceive(pController, outputBuff, inputBuff, sizeof(inputBuff));
|
||||
pAxis->stepSize = atof(&inputBuff[3]);
|
||||
digits = (int) -log10(pAxis->stepSize) + 2;
|
||||
if (digits < 1)
|
||||
digits = 1;
|
||||
pAxis->maxDigits = digits;
|
||||
|
||||
/* Save home preset position. */
|
||||
sprintf(outputBuff, "%dXH", axis+1);
|
||||
sendAndReceive(pController, outputBuff, inputBuff, sizeof(inputBuff));
|
||||
pAxis->homePreset = atof(&inputBuff[3]);
|
||||
|
||||
/* Determine low limit */
|
||||
sprintf(outputBuff, "%dTL", axis+1);
|
||||
sendAndReceive(pController, outputBuff, inputBuff, sizeof(inputBuff));
|
||||
pAxis->lowLimit = atof(&inputBuff[3]);
|
||||
|
||||
/* Determine high limit */
|
||||
sprintf(outputBuff, "%dTR", axis+1);
|
||||
sendAndReceive(pController, outputBuff, inputBuff, sizeof(inputBuff));
|
||||
pAxis->highLimit = atof(&inputBuff[3]);
|
||||
}
|
||||
|
||||
pController->pollEventId = epicsEventMustCreate(epicsEventEmpty);
|
||||
|
||||
/* Create the poller thread for this controller */
|
||||
epicsSnprintf(threadName, sizeof(threadName), "MM4000:%d", card);
|
||||
epicsThreadCreate(threadName,
|
||||
epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) MM4000Poller, (void *) pController);
|
||||
|
||||
return MOTOR_AXIS_OK;
|
||||
}
|
||||
|
||||
static int sendOnly(MM4000Controller *pController, char *outputBuff)
|
||||
{
|
||||
size_t nRequested=strlen(outputBuff);
|
||||
size_t nActual;
|
||||
asynStatus status;
|
||||
|
||||
if (pController->pasynUser == NULL)
|
||||
{
|
||||
status = asynError;
|
||||
errPrintf(-1, __FILE__, __LINE__, "*** Configuration error ***: pasynUser=NULL\n");
|
||||
epicsThreadSleep(5.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
status = pasynOctetSyncIO->write(pController->pasynUser, outputBuff,
|
||||
nRequested, TIMEOUT, &nActual);
|
||||
if (nActual != nRequested)
|
||||
status = asynError;
|
||||
if (status != asynSuccess)
|
||||
{
|
||||
asynPrint(pController->pasynUser, ASYN_TRACE_ERROR,
|
||||
"drvMM4000Asyn:sendOnly: error sending command %s, sent=%d, status=%d\n",
|
||||
outputBuff, nActual, status);
|
||||
}
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
|
||||
static asynStatus sendAndReceive(MM4000Controller *pController, char *outputBuff, char *inputBuff, int inputSize)
|
||||
{
|
||||
size_t nWriteRequested=strlen(outputBuff);
|
||||
size_t nWrite, nRead;
|
||||
int eomReason;
|
||||
asynStatus status;
|
||||
|
||||
status = pasynOctetSyncIO->writeRead(pController->pasynUser,
|
||||
outputBuff, nWriteRequested,
|
||||
inputBuff, inputSize,
|
||||
TIMEOUT, &nWrite, &nRead, &eomReason);
|
||||
if (nWrite != nWriteRequested) status = asynError;
|
||||
if (status != asynSuccess) {
|
||||
asynPrint(pController->pasynUser, ASYN_TRACE_ERROR,
|
||||
"drvMM4000Asyn:sendAndReceive error calling writeRead, output=%s status=%d, error=%s\n",
|
||||
outputBuff, status, pController->pasynUser->errorMessage);
|
||||
}
|
||||
return(status);
|
||||
}
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
#ifndef DRV_MOTOR_MM4000_ASYN_H
|
||||
#define DRV_MOTOR_MM4000_ASYN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int MM4000AsynSetup(int numControllers); /* number of XPS controllers in system. */
|
||||
|
||||
int MM4000AsynConfig(int card, /* Controller number */
|
||||
const char *portName, /* asyn port name of serial or GPIB port */
|
||||
int asynAddress, /* asyn subaddress for GPIB */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod); /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvMMCom.h
|
||||
USAGE... This file contains Newport Motion Master (MM) driver "include"
|
||||
information that is specific to Motion Master models 3000/4000.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Current Author: Mark Rivers
|
||||
* Date: 10/16/97
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 01-18-93 mlr initialized from drvOms58
|
||||
* .02 06-16-03 rls Converted to R3.14.x.
|
||||
*/
|
||||
|
||||
#ifndef INCdrvMMComh
|
||||
#define INCdrvMMComh 1
|
||||
|
||||
#include "motor.h"
|
||||
#include "motordrvCom.h"
|
||||
#include "asynDriver.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
|
||||
enum MM_model
|
||||
{
|
||||
MM4000,
|
||||
MM4005
|
||||
};
|
||||
|
||||
enum MM_motor_type
|
||||
{
|
||||
UNUSED,
|
||||
STEPPER,
|
||||
DC
|
||||
};
|
||||
|
||||
#ifndef __cplusplus
|
||||
typedef enum MM_model MM_model;
|
||||
typedef enum MM_motor_type MM_motor_type;
|
||||
#endif
|
||||
|
||||
/* Motion Master specific data is stored in this structure. */
|
||||
struct MMcontroller
|
||||
{
|
||||
asynUser *pasynUser; /* For RS-232 */
|
||||
int asyn_address; /* Use for GPIB or other address with asyn */
|
||||
char asyn_port[80]; /* asyn port name */
|
||||
char status_string[80]; /* String containing status of motors */
|
||||
char position_string[160]; /* String containing commanded/theorectical position of motors */
|
||||
char feedback_string[160]; /* String containing encoder position of motors */
|
||||
MM_model model; /* Motion Master Model. */
|
||||
MM_motor_type type[4]; /* For MM3000 only; Motor type array. */
|
||||
/* For MM4000/5 only; controller resolution array (from TU command).
|
||||
* Units are in [Controller EGU's / Record RAW units].
|
||||
*/
|
||||
double drive_resolution[MAX_AXIS];
|
||||
int res_decpts[MAX_AXIS]; /* Drive resolution significant dec. pts. */
|
||||
double home_preset[MAX_AXIS]; /* Controller's home preset position (XF command). */
|
||||
CommStatus status; /* Controller communication status. */
|
||||
};
|
||||
|
||||
|
||||
/* Motor status response for MM[3000/4000/4005]. */
|
||||
typedef union
|
||||
{
|
||||
epicsUInt8 All;
|
||||
struct
|
||||
{
|
||||
#ifdef MSB_First
|
||||
bool bit7 :1; /* Bit #7 N/A. */
|
||||
bool bit6 :1; /* Bit #6 N/A. */
|
||||
bool homels :1; /* Home LS. */
|
||||
bool minusTL :1; /* Minus Travel Limit. */
|
||||
bool plustTL :1; /* Plus Travel Limit. */
|
||||
bool direction :1; /* Motor direction: 0 - minus; 1 - plus. */
|
||||
bool NOT_power :1; /* Motor power 0 - ON; 1 - OFF. */
|
||||
bool inmotion :1; /* In-motion indicator. */
|
||||
#else
|
||||
bool inmotion :1; /* In-motion indicator. */
|
||||
bool NOT_power :1; /* Motor power 0 - ON; 1 - OFF. */
|
||||
bool direction :1; /* Motor direction: 0 - minus; 1 - plus. */
|
||||
bool plustTL :1; /* Plus Travel Limit. */
|
||||
bool minusTL :1; /* Minus Travel Limit. */
|
||||
bool homels :1; /* Home LS. */
|
||||
bool bit6 :1; /* Bit #6 N/A. */
|
||||
bool bit7 :1; /* Bit #7 N/A. */
|
||||
#endif
|
||||
} Bits;
|
||||
} MOTOR_STATUS;
|
||||
|
||||
|
||||
#endif /* INCdrvMMComh */
|
||||
|
||||
@@ -1,687 +0,0 @@
|
||||
/*
|
||||
FILENAME... drvPM500.cc
|
||||
USAGE... Motor record driver level support for Newport PM500.
|
||||
|
||||
*/
|
||||
|
||||
/* Device Driver Support routines for PM500 motor controller */
|
||||
/*
|
||||
* Original Author: Mark Rivers
|
||||
* Current Author: Ron Sluiter
|
||||
*
|
||||
* Experimental Physics and Industrial Control System (EPICS)
|
||||
*
|
||||
* Copyright 1991, the Regents of the University of California,
|
||||
* and the University of Chicago Board of Governors.
|
||||
*
|
||||
* This software was produced under U.S. Government contracts:
|
||||
* (W-7405-ENG-36) at the Los Alamos National Laboratory,
|
||||
* and (W-31-109-ENG-38) at Argonne National Laboratory.
|
||||
*
|
||||
* Initial development by:
|
||||
* The Controls and Automation Group (AT-8)
|
||||
* Ground Test Accelerator
|
||||
* Accelerator Technology Division
|
||||
* Los Alamos National Laboratory
|
||||
*
|
||||
* Co-developed with
|
||||
* The Controls and Computing Group
|
||||
* Accelerator Systems Division
|
||||
* Advanced Photon Source
|
||||
* Argonne National Laboratory
|
||||
*
|
||||
* Modification Log:
|
||||
* -----------------
|
||||
* .01 11-19-98 mlr Initial development, based on drvMM4000.c
|
||||
* .02 06-02-00 rls integrated into standard motor record
|
||||
* .03 10/02/01 rls allow one retry after a communication error.
|
||||
* .04 05-23-03 rls Converted to R3.14.x.
|
||||
* .05 02/03/04 rls Eliminate erroneous "Motor motion timeout ERROR".
|
||||
* .06 07/09/04 rls removed unused <driver>Setup() argument.
|
||||
* .07 07/28/04 rls "epicsExport" debug variable.
|
||||
* .08 09/21/04 rls support for 32axes/controller.
|
||||
* .09 12/21/04 rls - MS Visual C compatibility; make all epicsExportAddress
|
||||
* extern "C" linkage.
|
||||
* - make debug variables always available.
|
||||
* .10 01/17/07 rls Bug fix for driver not issuing the correct command when it
|
||||
* queried for the number of axes at boot up.
|
||||
* .11 08/20/09 rls - Bad motor_init() initialization; EA_PRESENT and
|
||||
* GAIN_SUPPORT cleared.
|
||||
* - Added MSTA.EA_POSITION support query to set_status().
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <epicsThread.h>
|
||||
#include <drvSup.h>
|
||||
#include <stdlib.h>
|
||||
#include <errlog.h>
|
||||
#include "motor.h"
|
||||
#include "NewportRegister.h"
|
||||
#include "drvMMCom.h"
|
||||
#include "asynOctetSyncIO.h"
|
||||
#include "epicsExport.h"
|
||||
|
||||
#define READ_RESOLUTION ""
|
||||
#define READ_STATUS ""
|
||||
#define READ_POSITION ""
|
||||
#define MOTOR_ON ""
|
||||
#define GET_IDENT "SVN?"
|
||||
|
||||
/* Status byte bits */
|
||||
#define M_AXIS_MOVING 0x01
|
||||
#define M_MOTOR_POWER 0x02
|
||||
#define M_MOTOR_DIRECTION 0x04
|
||||
#define M_PLUS_LIMIT 0x08
|
||||
#define M_MINUS_LIMIT 0x10
|
||||
#define M_HOME_SIGNAL 0x20
|
||||
|
||||
#define PM500_NUM_CARDS 4
|
||||
#define PM500_NUM_CHANNELS 12
|
||||
#define BUFF_SIZE 100 /* Maximum length of string to/from PM500 */
|
||||
|
||||
#define SERIAL_TIMEOUT 2.0 /* Command timeout in sec. */
|
||||
|
||||
/*----------------debugging-----------------*/
|
||||
volatile int drvPM500debug = 0;
|
||||
extern "C" {epicsExportAddress(int, drvPM500debug);}
|
||||
static inline void Debug(int level, const char *format, ...) {
|
||||
#ifdef DEBUG
|
||||
if (level < drvPM500debug) {
|
||||
va_list pVar;
|
||||
va_start(pVar, format);
|
||||
vprintf(format, pVar);
|
||||
va_end(pVar);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* --- Local data. --- */
|
||||
int PM500_num_cards = 0;
|
||||
static char *PM500_axis_names[] = {"X", "Y", "Z", "A", "B", "C", "D", "E", "F",
|
||||
"G", "H", "I"};
|
||||
|
||||
/* Local data required for every driver; see "motordrvComCode.h" */
|
||||
#include "motordrvComCode.h"
|
||||
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
static int recv_mess(int, char *, int);
|
||||
static RTN_STATUS send_mess(int, char const *, char *);
|
||||
static int set_status(int, int);
|
||||
static long report(int);
|
||||
static long init();
|
||||
static int motor_init();
|
||||
static void query_done(int, int, struct mess_node *);
|
||||
|
||||
/*----------------functions-----------------*/
|
||||
|
||||
struct driver_table PM500_access =
|
||||
{
|
||||
motor_init,
|
||||
motor_send,
|
||||
motor_free,
|
||||
motor_card_info,
|
||||
motor_axis_info,
|
||||
&mess_queue,
|
||||
&queue_lock,
|
||||
&free_list,
|
||||
&freelist_lock,
|
||||
&motor_sem,
|
||||
&motor_state,
|
||||
&total_cards,
|
||||
&any_motor_in_motion,
|
||||
send_mess,
|
||||
recv_mess,
|
||||
set_status,
|
||||
query_done,
|
||||
NULL,
|
||||
&initialized,
|
||||
PM500_axis_names
|
||||
};
|
||||
|
||||
struct drvP500_drvet
|
||||
{
|
||||
long number;
|
||||
#ifdef __cplusplus
|
||||
long (*report) (int);
|
||||
long (*init) (void);
|
||||
#else
|
||||
DRVSUPFUN report;
|
||||
DRVSUPFUN init;
|
||||
#endif
|
||||
} drvPM500 = {2, report, init};
|
||||
|
||||
extern "C" {epicsExportAddress(drvet, drvPM500);}
|
||||
|
||||
static struct thread_args targs = {SCAN_RATE, &PM500_access, 0.0};
|
||||
|
||||
/*********************************************************
|
||||
* Print out driver status report
|
||||
*********************************************************/
|
||||
static long report(int level)
|
||||
{
|
||||
int card;
|
||||
|
||||
if (PM500_num_cards <=0)
|
||||
printf(" No PM500 controllers configured.\n");
|
||||
else
|
||||
{
|
||||
for (card = 0; card < PM500_num_cards; card++)
|
||||
{
|
||||
struct controller *brdptr = motor_state[card];
|
||||
|
||||
if (brdptr == NULL)
|
||||
printf(" PM500 controller #%d connection failed.\n", card);
|
||||
else
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
printf(" PM500 controller %d port=%s, address=%d, id: %s \n",
|
||||
card, cntrl->asyn_port, cntrl->asyn_address,
|
||||
brdptr->ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
static long init()
|
||||
{
|
||||
/*
|
||||
* We cannot call motor_init() here, because that function can do GPIB I/O,
|
||||
* and hence requires that the drvGPIB have already been initialized.
|
||||
* That cannot be guaranteed, so we need to call motor_init from device
|
||||
* support
|
||||
*/
|
||||
/* Check for setup */
|
||||
if (PM500_num_cards <= 0)
|
||||
{
|
||||
Debug(1, "init(): PM500 driver disabled. PM500Setup() missing from startup script.\n");
|
||||
}
|
||||
return((long) 0);
|
||||
}
|
||||
|
||||
|
||||
static void query_done(int card, int axis, struct mess_node *nodeptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************
|
||||
* Parse status and position strings for a card and signal
|
||||
* set_status()
|
||||
************************************************************/
|
||||
|
||||
static int set_status(int card, int signal)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
struct mess_node *nodeptr;
|
||||
struct mess_info *motor_info;
|
||||
/* Message parsing variables */
|
||||
char *axis_name, status_char, dir_char, buff[BUFF_SIZE], response[BUFF_SIZE];
|
||||
int rtnval, rtn_state = 0;
|
||||
double motorData;
|
||||
bool ls_active;
|
||||
msta_field status;
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
motor_info = &(motor_state[card]->motor_info[signal]);
|
||||
nodeptr = motor_info->motor_motion;
|
||||
axis_name = PM500_axis_names[signal];
|
||||
status.All = motor_info->status.All;
|
||||
|
||||
/* Request the status and position of this motor */
|
||||
sprintf(buff, "%sR", axis_name);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
rtnval = recv_mess(card, response, 1);
|
||||
if (rtnval > 0)
|
||||
{
|
||||
cntrl->status = NORMAL;
|
||||
status.Bits.CNTRL_COMM_ERR = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cntrl->status == NORMAL)
|
||||
{
|
||||
cntrl->status = RETRY;
|
||||
rtn_state = 0;
|
||||
goto exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
cntrl->status = COMM_ERR;
|
||||
status.Bits.CNTRL_COMM_ERR = 1;
|
||||
status.Bits.RA_PROBLEM = 1;
|
||||
rtn_state = 1;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
status_char = response[1];
|
||||
dir_char = response[2];
|
||||
motorData = atof(&response[2]) / cntrl->drive_resolution[signal];
|
||||
|
||||
status.Bits.RA_DONE = (status_char == 'B') ? 0 : 1;
|
||||
status.Bits.RA_PROBLEM = (status_char == 'E') ? 1 : 0;
|
||||
status.Bits.RA_DIRECTION = (dir_char == '+') ? 1 : 0;
|
||||
|
||||
if (status_char == 'L')
|
||||
{
|
||||
ls_active = true;
|
||||
if (dir_char == '+')
|
||||
status.Bits.RA_PLUS_LS = 1;
|
||||
else
|
||||
status.Bits.RA_MINUS_LS = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
ls_active = false;
|
||||
status.Bits.RA_PLUS_LS = 0;
|
||||
status.Bits.RA_MINUS_LS = 0;
|
||||
}
|
||||
|
||||
/* Set Motor On/Off status */
|
||||
sprintf(buff, "%sM?", axis_name);
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
rtnval = recv_mess(card, response, 1);
|
||||
status.Bits.EA_POSITION = (int) atof(&response[2]);
|
||||
|
||||
status.Bits.RA_HOME = 0;
|
||||
status.Bits.EA_SLIP = 0;
|
||||
status.Bits.EA_SLIP_STALL = 0;
|
||||
status.Bits.EA_HOME = 0;
|
||||
|
||||
/*
|
||||
* Parse motor position
|
||||
* Position string format: 1TP5.012,2TP1.123,3TP-100.567,...
|
||||
* Skip to substring for this motor, convert to double
|
||||
*/
|
||||
|
||||
if (motorData == motor_info->position)
|
||||
{
|
||||
if (nodeptr != 0) /* Increment counter only if motor is moving. */
|
||||
motor_info->no_motion_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
motor_info->position = NINT(motorData);
|
||||
if (motor_state[card]->motor_info[signal].encoder_present == YES)
|
||||
motor_info->encoder_position = (epicsInt32) motorData;
|
||||
else
|
||||
motor_info->encoder_position = 0;
|
||||
|
||||
motor_info->no_motion_count = 0;
|
||||
}
|
||||
|
||||
status.Bits.RA_PROBLEM = 0;
|
||||
|
||||
/* Parse motor velocity? */
|
||||
/* NEEDS WORK */
|
||||
|
||||
motor_info->velocity = 0;
|
||||
|
||||
if (!status.Bits.RA_DIRECTION)
|
||||
motor_info->velocity *= -1;
|
||||
|
||||
rtn_state = (!motor_info->no_motion_count || ls_active == true ||
|
||||
status.Bits.RA_DONE | status.Bits.RA_PROBLEM) ? 1 : 0;
|
||||
|
||||
/* Test for post-move string. */
|
||||
if ((status.Bits.RA_DONE || ls_active == true) && nodeptr != 0 &&
|
||||
nodeptr->postmsgptr != 0)
|
||||
{
|
||||
strcpy(buff, nodeptr->postmsgptr);
|
||||
strcat(buff, "\r");
|
||||
send_mess(card, buff, (char*) NULL);
|
||||
nodeptr->postmsgptr = NULL;
|
||||
}
|
||||
|
||||
exit:
|
||||
motor_info->status.All = status.All;
|
||||
return(rtn_state);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* send a message to the PM500 board */
|
||||
/* send_mess() */
|
||||
/*****************************************************/
|
||||
static RTN_STATUS send_mess(int card, char const *com, char *name)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
size_t size;
|
||||
size_t nwrite;
|
||||
|
||||
size = strlen(com);
|
||||
|
||||
if (size > MAX_MSG_SIZE)
|
||||
{
|
||||
errlogMessage("drvPM500.c:send_mess(); message size violation.\n");
|
||||
return(ERROR);
|
||||
}
|
||||
else if (size == 0) /* Normal exit on empty input message. */
|
||||
return(OK);
|
||||
|
||||
if (!motor_state[card])
|
||||
{
|
||||
errlogPrintf("drvPM500.c:send_mess() - invalid card #%d\n", card);
|
||||
return(ERROR);
|
||||
}
|
||||
|
||||
Debug(2, "send_mess(): message = %s\n", com);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
pasynOctetSyncIO->write(cntrl->pasynUser, com, strlen(com), SERIAL_TIMEOUT, &nwrite);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTION... recv_mess(int card, char *com, int flag)
|
||||
*
|
||||
* INPUT ARGUMENTS...
|
||||
* card - controller card # (0,1,...).
|
||||
* *com - caller's response buffer.
|
||||
* flag | FLUSH = flush controller's output buffer; set timeout = 0.
|
||||
* | !FLUSH = retrieve response into caller's buffer; set timeout.
|
||||
*
|
||||
* LOGIC...
|
||||
* IF controller card does not exist.
|
||||
* ERROR RETURN.
|
||||
* ENDIF
|
||||
* NORMAL RETURN.
|
||||
*/
|
||||
|
||||
static int recv_mess(int card, char *com, int flag)
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
double timeout = 0.;
|
||||
int flush=1;
|
||||
size_t nread = 0;
|
||||
asynStatus status;
|
||||
int eomReason;
|
||||
|
||||
/* Check that card exists */
|
||||
if (!motor_state[card])
|
||||
return(ERROR);
|
||||
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
if (flag != FLUSH)
|
||||
{
|
||||
flush=0;
|
||||
timeout = SERIAL_TIMEOUT;
|
||||
}
|
||||
if (flush) status = pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
status = pasynOctetSyncIO->read(cntrl->pasynUser, com, BUFF_SIZE,
|
||||
timeout, &nread, &eomReason);
|
||||
|
||||
if ((status != asynSuccess) || (nread <= 0))
|
||||
{
|
||||
com[0] = '\0';
|
||||
nread = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Test for "system error" response. */
|
||||
if (strncmp(com, "SE", 2) == 0)
|
||||
errlogMessage("recv_mess(): PM500 system error.\n");
|
||||
}
|
||||
|
||||
Debug(2, "recv_mess(): message = \"%s\"\n", com);
|
||||
return((int)nread);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Setup system configuration */
|
||||
/* PM500Setup() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PM500Setup(int num_cards, /* maximum number of controllers in system. */
|
||||
int scan_rate) /* polling rate - 1/60 sec units. */
|
||||
{
|
||||
int itera;
|
||||
|
||||
if (num_cards < 1 || num_cards > PM500_NUM_CARDS)
|
||||
PM500_num_cards = PM500_NUM_CARDS;
|
||||
else
|
||||
PM500_num_cards = num_cards;
|
||||
|
||||
/* Set motor polling task rate */
|
||||
if (scan_rate >= 1 && scan_rate <= 60)
|
||||
targs.motor_scan_rate = scan_rate;
|
||||
else
|
||||
targs.motor_scan_rate = SCAN_RATE;
|
||||
|
||||
/*
|
||||
* Allocate space for motor_state structures. Note this must be done
|
||||
* before PM500Config is called, so it cannot be done in motor_init()
|
||||
* This means that we must allocate space for a card without knowing
|
||||
* if it really exists, which is not a serious problem
|
||||
*/
|
||||
motor_state = (struct controller **) malloc(PM500_num_cards *
|
||||
sizeof(struct controller *));
|
||||
|
||||
for (itera = 0; itera < PM500_num_cards; itera++)
|
||||
motor_state[itera] = (struct controller *) NULL;
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* Configure a controller */
|
||||
/* PM500Config() */
|
||||
/*****************************************************/
|
||||
RTN_STATUS
|
||||
PM500Config(int card, /* card being configured */
|
||||
const char *name, /*asyn port name */
|
||||
int address) /*asyn address (GPIB) */
|
||||
{
|
||||
struct MMcontroller *cntrl;
|
||||
|
||||
if (card < 0 || card >= PM500_num_cards)
|
||||
return(ERROR);
|
||||
|
||||
motor_state[card] = (struct controller *) malloc(sizeof(struct controller));
|
||||
motor_state[card]->DevicePrivate = malloc(sizeof(struct MMcontroller));
|
||||
cntrl = (struct MMcontroller *) motor_state[card]->DevicePrivate;
|
||||
|
||||
strcpy(cntrl->asyn_port, name);
|
||||
cntrl->asyn_address = address;
|
||||
return(OK);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*****************************************************/
|
||||
/* initialize all software and hardware */
|
||||
/* This is called from the initialization routine in */
|
||||
/* device support. */
|
||||
/* motor_init() */
|
||||
/*****************************************************/
|
||||
static int motor_init()
|
||||
{
|
||||
struct controller *brdptr;
|
||||
struct MMcontroller *cntrl;
|
||||
int card_index, motor_index;
|
||||
char buff[BUFF_SIZE];
|
||||
int total_axis = 0;
|
||||
int status=0, digits;
|
||||
asynStatus success_rtn;
|
||||
|
||||
initialized = true; /* Indicate that driver is initialized. */
|
||||
|
||||
/* Check for setup */
|
||||
if (PM500_num_cards <= 0)
|
||||
return(ERROR);
|
||||
|
||||
for (card_index = 0; card_index < PM500_num_cards; card_index++)
|
||||
{
|
||||
if (!motor_state[card_index])
|
||||
continue;
|
||||
|
||||
brdptr = motor_state[card_index];
|
||||
brdptr->cmnd_response = true;
|
||||
total_cards = card_index + 1;
|
||||
cntrl = (struct MMcontroller *) brdptr->DevicePrivate;
|
||||
|
||||
/* Initialize communications channel */
|
||||
success_rtn = pasynOctetSyncIO->connect(cntrl->asyn_port,
|
||||
cntrl->asyn_address, &cntrl->pasynUser, NULL);
|
||||
|
||||
if (success_rtn == asynSuccess)
|
||||
{
|
||||
/* flush any junk at input port - should not be any data available */
|
||||
pasynOctetSyncIO->flush(cntrl->pasynUser);
|
||||
|
||||
/* Send a SCUM 1 command to put device in this mode. */
|
||||
send_mess(card_index, "SCUM 1", (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
|
||||
/* Set up basic controller parameters
|
||||
* "ENAINT $AF" means the following:
|
||||
* Bit 0=1, only affected axis halts on limit
|
||||
* Bit 1=1, No message when moving axis beyond limit
|
||||
* Bit 2=1, No query echo, prepends status character to axis.
|
||||
* Bit 3=1, NO status character inserted in responses.
|
||||
* Bit 4=0, No acknowledgement when command is received
|
||||
* Bit 5=1, Disable sign-on message at power-up
|
||||
* Bit 6=0, No echo
|
||||
* Bit 7=1, CR terminator only on commands and responses
|
||||
* Bit 8=0, CR terminator only on commands and responses
|
||||
* Bit 9=0, No EOI sent
|
||||
* Bit 10=0, CR terminator only on commands and responses
|
||||
* Bit 11=0, CR terminator only on commands and responses
|
||||
* Bit 12=0, Decimal number format
|
||||
* Bit 13=0, Eearly serial poll mapping
|
||||
* Bit 14=0, No SRQ assertion
|
||||
*/
|
||||
send_mess(card_index, "SENAINT $AF", (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
|
||||
/* Send a message and read response from controller to see if
|
||||
* it exists */
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL);
|
||||
status = recv_mess(card_index, buff, 1);
|
||||
/* Return value is length of response string */
|
||||
}
|
||||
|
||||
if (success_rtn == asynSuccess && status > 0)
|
||||
{
|
||||
brdptr->localaddr = (char *) NULL;
|
||||
brdptr->motor_in_motion = 0;
|
||||
send_mess(card_index, GET_IDENT, (char*) NULL); /* Read controller ID string */
|
||||
recv_mess(card_index, buff, 1);
|
||||
strncpy(brdptr->ident, &buff[2], 50); /* Skip "XD" */
|
||||
|
||||
/* Figure out how many axes this controller has.
|
||||
* Do this by querying status of each axis in order */
|
||||
for (total_axis = 0; total_axis < PM500_NUM_CHANNELS; total_axis++)
|
||||
{
|
||||
int axis_name = (int) *PM500_axis_names[total_axis];
|
||||
brdptr->motor_info[total_axis].motor_motion = NULL;
|
||||
sprintf(buff, "%cSTAT?", axis_name);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
if (buff[1] == 'E')
|
||||
break;
|
||||
/* Determine axis type and resolution.
|
||||
* This is a real pain, since the only way to get this
|
||||
* information is to ask for the axis firmware and use a
|
||||
* lookup table. We only have translators, so I don't
|
||||
* really know how to tell them apart. Our translators
|
||||
* return 302 (50nm stages) or 309 (25nm stages) at the end of
|
||||
* the configuration string.
|
||||
* I assume rotators return something different, but I don't
|
||||
* know what it is.
|
||||
*/
|
||||
}
|
||||
|
||||
brdptr->total_axis = total_axis;
|
||||
|
||||
for (motor_index = 0; motor_index < total_axis; motor_index++)
|
||||
{
|
||||
struct mess_info *motor_info = &brdptr->motor_info[motor_index];
|
||||
char *firmware, *axis_name = PM500_axis_names[motor_index];
|
||||
double res = 0.0;
|
||||
|
||||
sprintf(buff, "%sCONFIG?", axis_name);
|
||||
send_mess(card_index, buff, (char*) NULL);
|
||||
recv_mess(card_index, buff, 1);
|
||||
firmware = &buff[8];
|
||||
Debug(3, "motor_init: firmware = %s\n", firmware);
|
||||
if (!strcmp(firmware, "302"))
|
||||
{
|
||||
/* 50 nm translator */
|
||||
res = .01;
|
||||
Debug(3, "motor_init: axis %d is a 50 nm translator\n", motor_index);
|
||||
}
|
||||
else if (!strcmp(firmware, "309"))
|
||||
{
|
||||
/* 25 nm translator */
|
||||
res = .01;
|
||||
Debug(3, "motor_init: axis %d is a 25 nm translator\n", motor_index);
|
||||
}
|
||||
else if (!strcmp(firmware, "300"))
|
||||
{
|
||||
/* ????? translator ?????? */
|
||||
res = .01;
|
||||
Debug(3, "motor_init: axis %d is a ?????? translator\n", motor_index);
|
||||
}
|
||||
else if (!strcmp(firmware, "XXX"))
|
||||
{
|
||||
/* Rotator */
|
||||
res = .01;
|
||||
}
|
||||
|
||||
/* Set drive resolution. */
|
||||
cntrl->drive_resolution[motor_index] = res;
|
||||
|
||||
digits = (int) -log10(cntrl->drive_resolution[motor_index]) + 2;
|
||||
if (digits < 1)
|
||||
digits = 1;
|
||||
cntrl->res_decpts[motor_index] = digits;
|
||||
|
||||
motor_info->status.All = 0;
|
||||
motor_info->no_motion_count = 0;
|
||||
motor_info->encoder_position = 0;
|
||||
motor_info->position = 0;
|
||||
|
||||
/* PM500 only supports DC motors. */
|
||||
motor_info->encoder_present = YES;
|
||||
motor_info->status.Bits.EA_PRESENT = 1;
|
||||
motor_info->pid_present = YES;
|
||||
motor_info->status.Bits.GAIN_SUPPORT = 1;
|
||||
|
||||
cntrl->home_preset[motor_index] = 0;
|
||||
|
||||
set_status(card_index, motor_index); /* Read status of each motor */
|
||||
}
|
||||
}
|
||||
else
|
||||
motor_state[card_index] = (struct controller *) NULL;
|
||||
}
|
||||
|
||||
any_motor_in_motion = 0;
|
||||
|
||||
mess_queue.head = (struct mess_node *) NULL;
|
||||
mess_queue.tail = (struct mess_node *) NULL;
|
||||
|
||||
free_list.head = (struct mess_node *) NULL;
|
||||
free_list.tail = (struct mess_node *) NULL;
|
||||
|
||||
epicsThreadCreate((char *) "PM500_motor", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC) motor_task, (void *) &targs);
|
||||
|
||||
return(OK);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,28 +0,0 @@
|
||||
#ifndef DRV_MOTOR_XPS_ASYN_H
|
||||
#define DRV_MOTOR_XPS_ASYN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int XPSSetup(int numControllers); /* number of XPS controllers in system. */
|
||||
|
||||
int XPSConfig(int card, /* Controller number */
|
||||
const char *ip, /* XPS IP address or IP name */
|
||||
int port, /* IP port number that XPS is listening on */
|
||||
int numAxes, /* Number of axes this controller supports */
|
||||
int movingPollPeriod, /* Time to poll (msec) when an axis is in motion */
|
||||
int idlePollPeriod); /* Time to poll (msec) when an axis is idle. 0 for no polling */
|
||||
|
||||
int XPSConfigAxis(int card, /* specify which controller 0-up*/
|
||||
int axis, /* axis number 0-7 */
|
||||
const char *positionerName, /* groupName.positionerName e.g. Diffractometer.Phi */
|
||||
const char *stepsPerUnit, /* steps per user unit */
|
||||
int noDisabledError); /* If 1 then don't report disabled state as error */
|
||||
|
||||
void XPSDisablePoll(int disablePollVal);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,703 +0,0 @@
|
||||
/* drvXPSAsynAux.c */
|
||||
|
||||
/* This driver implements "auxilliary" commands for the XPS controller, i.e.
|
||||
* commands beyond those for the motor record. These include support for
|
||||
* analog and digital I/O. */
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <cantProceed.h> /* !! for callocMustSucceed() */
|
||||
|
||||
#include <epicsExit.h>
|
||||
#include <epicsMutex.h>
|
||||
#include <epicsEvent.h>
|
||||
#include <epicsThread.h>
|
||||
#include <epicsString.h>
|
||||
#include <errlog.h>
|
||||
#include <iocsh.h>
|
||||
|
||||
#include <asynDriver.h>
|
||||
#include <asynFloat64.h>
|
||||
#include <asynUInt32Digital.h>
|
||||
#include <asynDrvUser.h>
|
||||
|
||||
#include <epicsExport.h>
|
||||
#include <XPS_C8_drivers.h>
|
||||
|
||||
typedef struct {
|
||||
char *portName;
|
||||
int socketID;
|
||||
epicsMutexId lock;
|
||||
epicsEventId pollerEventId;
|
||||
double pollerTimeout;
|
||||
asynInterface common;
|
||||
asynInterface float64;
|
||||
void *float64InterruptPvt;
|
||||
asynInterface uint32D;
|
||||
void *uint32DInterruptPvt;
|
||||
asynInterface drvUser;
|
||||
asynUser *pasynUser;
|
||||
int shuttingDown;
|
||||
} drvXPSAsynAuxPvt;
|
||||
|
||||
typedef enum {
|
||||
analogInput,
|
||||
analogOutput,
|
||||
analogGain,
|
||||
binaryInput,
|
||||
binaryOutput
|
||||
} drvXPSAsynAuxCommand;
|
||||
|
||||
typedef struct {
|
||||
drvXPSAsynAuxCommand command;
|
||||
char *commandString;
|
||||
} drvXPSAsynAuxCommandStruct;
|
||||
|
||||
static drvXPSAsynAuxCommandStruct drvXPSAsynAuxCommands[] = {
|
||||
{analogInput, "ANALOG_INPUT"},
|
||||
{analogOutput, "ANALOG_OUTPUT"},
|
||||
{analogGain, "ANALOG_GAIN"},
|
||||
{binaryInput, "BINARY_INPUT"},
|
||||
{binaryOutput, "BINARY_OUTPUT"}
|
||||
};
|
||||
|
||||
#define TCP_TIMEOUT 1.0
|
||||
|
||||
#define MAX_ANALOG_INPUTS 4
|
||||
#define MAX_ANALOG_OUTPUTS 4
|
||||
#define MAX_DIGITAL_INPUTS 4
|
||||
#define MAX_DIGITAL_OUTPUTS 3
|
||||
|
||||
static char *analogInputNames[MAX_ANALOG_INPUTS] = {
|
||||
"GPIO2.ADC1", /* Analog Input # 1 of the I/O board connector # 2 */
|
||||
"GPIO2.ADC2", /* Analog Input # 2 of the I/O board connector # 2 */
|
||||
"GPIO2.ADC3", /* Analog Input # 3 of the I/O board connector # 2 */
|
||||
"GPIO2.ADC4", /* Analog Input # 4 of the I/O board connector # 2 */
|
||||
};
|
||||
static char *analogOutputNames[MAX_ANALOG_OUTPUTS] = {
|
||||
"GPIO2.DAC1", /* Analog Output # 1 of the I/O board connector # 2 */
|
||||
"GPIO2.DAC2", /* Analog Output # 2 of the I/O board connector # 2 */
|
||||
"GPIO2.DAC3", /* Analog Output # 3 of the I/O board connector # 2 */
|
||||
"GPIO2.DAC4", /* Analog Output # 4 of the I/O board connector # 2 */
|
||||
};
|
||||
static char *digitalInputNames[MAX_DIGITAL_INPUTS] = {
|
||||
"GPIO1.DI", /* Digital Input of the I/O board connector # 1 (8 bits) */
|
||||
"GPIO2.DI", /* Digital Input of the I/O board connector # 2 (6 bits) */
|
||||
"GPIO3.DI", /* Digital Input of the I/O board connector # 3 (6 bits) */
|
||||
"GPIO4.DI", /* Digital Input of the I/O board connector # 4 (16 bits) */
|
||||
};
|
||||
static char *digitalOutputNames[MAX_DIGITAL_OUTPUTS] = {
|
||||
"GPIO1.DO", /* Digital Output of the I/O board connector # 1 (8 bits) */
|
||||
"GPIO3.DO", /* Digital Output of the I/O board connector # 3 (6 bits) */
|
||||
"GPIO4.DO", /* Digital Output of the I/O board connector # 4 (16 bits) */
|
||||
};
|
||||
|
||||
/* These functions are used by the interfaces */
|
||||
static asynStatus readFloat64 (void *drvPvt, asynUser *pasynUser,
|
||||
epicsFloat64 *value);
|
||||
static asynStatus writeFloat64 (void *drvPvt, asynUser *pasynUser,
|
||||
epicsFloat64 value);
|
||||
static asynStatus readUInt32D (void *drvPvt, asynUser *pasynUser,
|
||||
epicsUInt32 *value, epicsUInt32 mask);
|
||||
static asynStatus writeUInt32D (void *drvPvt, asynUser *pasynUser,
|
||||
epicsUInt32 value, epicsUInt32 mask);
|
||||
static asynStatus drvUserCreate (void *drvPvt, asynUser *pasynUser,
|
||||
const char *drvInfo,
|
||||
const char **pptypeName, size_t *psize);
|
||||
static asynStatus drvUserGetType (void *drvPvt, asynUser *pasynUser,
|
||||
const char **pptypeName, size_t *psize);
|
||||
static asynStatus drvUserDestroy (void *drvPvt, asynUser *pasynUser);
|
||||
|
||||
static void report (void *drvPvt, FILE *fp, int details);
|
||||
static asynStatus connect (void *drvPvt, asynUser *pasynUser);
|
||||
static asynStatus disconnect (void *drvPvt, asynUser *pasynUser);
|
||||
|
||||
|
||||
static asynCommon drvXPSAsynAuxCommon = {
|
||||
report,
|
||||
connect,
|
||||
disconnect
|
||||
};
|
||||
|
||||
static asynFloat64 drvXPSAsynAuxFloat64 = {
|
||||
writeFloat64,
|
||||
readFloat64
|
||||
};
|
||||
|
||||
static asynUInt32Digital drvXPSAsynAuxUInt32D = {
|
||||
writeUInt32D,
|
||||
readUInt32D,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
|
||||
static asynDrvUser drvXPSAsynAuxDrvUser = {
|
||||
drvUserCreate,
|
||||
drvUserGetType,
|
||||
drvUserDestroy
|
||||
};
|
||||
|
||||
static void XPSAuxPoller(drvXPSAsynAuxPvt *pPvt);
|
||||
|
||||
static void shutdownCallback(drvXPSAsynAuxPvt *pPvt);
|
||||
|
||||
|
||||
int XPSAuxConfig(const char *portName, /* asyn port name */
|
||||
const char *ip, /* XPS IP address or IP name */
|
||||
int port, /* IP port number that XPS is listening on */
|
||||
int pollPeriod) /* Time to poll (msec) analog and digital inputs */
|
||||
|
||||
{
|
||||
drvXPSAsynAuxPvt *pPvt;
|
||||
asynStatus status;
|
||||
epicsThreadId threadId;
|
||||
|
||||
pPvt = callocMustSucceed(1, sizeof(*pPvt), "XPSAuxConfig");
|
||||
pPvt->portName = epicsStrDup(portName);
|
||||
pPvt->lock = epicsMutexCreate();
|
||||
pPvt->pollerEventId = epicsEventCreate(epicsEventEmpty);
|
||||
|
||||
pPvt->socketID = TCP_ConnectToServer((char *)ip, port, TCP_TIMEOUT);
|
||||
if (pPvt->socketID < 0) {
|
||||
printf("drvXPSAsynAuxConfig: error calling TCP_ConnectToServer\n");
|
||||
return -1;
|
||||
}
|
||||
pPvt->pollerTimeout = pollPeriod/1000.;
|
||||
|
||||
/* Register a shutdown callback */
|
||||
epicsAtExit((void *)shutdownCallback, pPvt);
|
||||
|
||||
/* Link with higher level routines */
|
||||
pPvt->common.interfaceType = asynCommonType;
|
||||
pPvt->common.pinterface = (void *)&drvXPSAsynAuxCommon;
|
||||
pPvt->common.drvPvt = pPvt;
|
||||
pPvt->float64.interfaceType = asynFloat64Type;
|
||||
pPvt->float64.pinterface = (void *)&drvXPSAsynAuxFloat64;
|
||||
pPvt->float64.drvPvt = pPvt;
|
||||
pPvt->uint32D.interfaceType = asynUInt32DigitalType;
|
||||
pPvt->uint32D.pinterface = (void *)&drvXPSAsynAuxUInt32D;
|
||||
pPvt->uint32D.drvPvt = pPvt;
|
||||
pPvt->drvUser.interfaceType = asynDrvUserType;
|
||||
pPvt->drvUser.pinterface = (void *)&drvXPSAsynAuxDrvUser;
|
||||
pPvt->drvUser.drvPvt = pPvt;
|
||||
status = pasynManager->registerPort(portName,
|
||||
ASYN_MULTIDEVICE, /*is multiDevice*/
|
||||
1, /* autoconnect */
|
||||
0, /* medium priority */
|
||||
0); /* default stack size */
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register port\n");
|
||||
return -1;
|
||||
}
|
||||
status = pasynManager->registerInterface(portName,&pPvt->common);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register common.\n");
|
||||
return -1;
|
||||
}
|
||||
status = pasynFloat64Base->initialize(pPvt->portName,&pPvt->float64);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register float64\n");
|
||||
return -1;
|
||||
}
|
||||
status = pasynManager->registerInterruptSource(pPvt->portName, &pPvt->float64,
|
||||
&pPvt->float64InterruptPvt);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register float64 interrupts\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = pasynUInt32DigitalBase->initialize(pPvt->portName,&pPvt->uint32D);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register uint32D\n");
|
||||
return -1;
|
||||
}
|
||||
status = pasynManager->registerInterruptSource(pPvt->portName, &pPvt->uint32D,
|
||||
&pPvt->uint32DInterruptPvt);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register uint32D interrupts\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = pasynManager->registerInterface(portName,&pPvt->drvUser);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig ERROR: Can't register drvUser.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create asynUser for debugging */
|
||||
pPvt->pasynUser = pasynManager->createAsynUser(0, 0);
|
||||
|
||||
/* Connect to device */
|
||||
status = pasynManager->connectDevice(pPvt->pasynUser, portName, -1);
|
||||
if (status != asynSuccess) {
|
||||
errlogPrintf("XPSAuxConfig, connectDevice failed\n");
|
||||
return -1;
|
||||
}
|
||||
threadId = epicsThreadCreate("XPSAuxPoller", epicsThreadPriorityMedium,
|
||||
epicsThreadGetStackSize(epicsThreadStackMedium),
|
||||
(EPICSTHREADFUNC)XPSAuxPoller,
|
||||
pPvt);
|
||||
if (threadId == NULL) {
|
||||
errlogPrintf("XPSAuxConfig, epicsThreadCreate failed\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static asynStatus readFloat64(void *drvPvt, asynUser *pasynUser,
|
||||
epicsFloat64 *value)
|
||||
{
|
||||
drvXPSAsynAuxPvt *pPvt = (drvXPSAsynAuxPvt *)drvPvt;
|
||||
int channel;
|
||||
drvXPSAsynAuxCommand command = pasynUser->reason;
|
||||
char *GPIOName;
|
||||
int status;
|
||||
|
||||
if (pPvt->shuttingDown) return asynError;
|
||||
|
||||
pasynManager->getAddr(pasynUser, &channel);
|
||||
|
||||
switch(command) {
|
||||
case analogInput:
|
||||
if ((channel < 0) || (channel >= MAX_ANALOG_INPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readFloat64 channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
GPIOName = analogInputNames[channel];
|
||||
break;
|
||||
case analogOutput:
|
||||
if ((channel < 0) || (channel >= MAX_ANALOG_OUTPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readFloat64 channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
GPIOName = analogOutputNames[channel];
|
||||
break;
|
||||
default:
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readFloat64 invalid command=%d",
|
||||
command);
|
||||
return(asynError);
|
||||
}
|
||||
status = GPIOAnalogGet(pPvt->socketID, 1, GPIOName, value);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readFloat64 error calling GPIOAnalogGet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"drvXPSAsynAux::readFloat64, value=%f\n", *value);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
|
||||
static asynStatus writeFloat64(void *drvPvt, asynUser *pasynUser,
|
||||
epicsFloat64 value)
|
||||
{
|
||||
drvXPSAsynAuxPvt *pPvt = (drvXPSAsynAuxPvt *)drvPvt;
|
||||
int channel;
|
||||
drvXPSAsynAuxCommand command = pasynUser->reason;
|
||||
char *GPIOName;
|
||||
int status;
|
||||
|
||||
if (pPvt->shuttingDown) return asynError;
|
||||
|
||||
pasynManager->getAddr(pasynUser, &channel);
|
||||
|
||||
switch(command) {
|
||||
case analogOutput:
|
||||
if ((channel < 0) || (channel >= MAX_ANALOG_OUTPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeFloat64 channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
GPIOName = analogOutputNames[channel];
|
||||
break;
|
||||
default:
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeFloat64 invalid command=%d",
|
||||
command);
|
||||
return(asynError);
|
||||
}
|
||||
status = GPIOAnalogSet(pPvt->socketID, 1, GPIOName, &value);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeFloat64 error calling GPIOAnalogSet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"drvXPSAsynAux::writeFloat64, value=%f\n", value);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
static asynStatus readUInt32D(void *drvPvt, asynUser *pasynUser,
|
||||
epicsUInt32 *value, epicsUInt32 mask)
|
||||
{
|
||||
drvXPSAsynAuxPvt *pPvt = (drvXPSAsynAuxPvt *)drvPvt;
|
||||
int channel;
|
||||
drvXPSAsynAuxCommand command = pasynUser->reason;
|
||||
int status;
|
||||
unsigned short rawValue;
|
||||
|
||||
if (pPvt->shuttingDown) return asynError;
|
||||
|
||||
pasynManager->getAddr(pasynUser, &channel);
|
||||
|
||||
switch(command) {
|
||||
case binaryInput:
|
||||
if ((channel < 0) || (channel >= MAX_DIGITAL_INPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readUInt32D readBi channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
status = GPIODigitalGet(pPvt->socketID, digitalInputNames[channel], &rawValue);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readUInt32D error calling GPIODigitalGet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
*value = rawValue & mask;
|
||||
break;
|
||||
case binaryOutput:
|
||||
if ((channel < 0) || (channel >= MAX_DIGITAL_OUTPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readUInt32D readBo channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
status = GPIODigitalGet(pPvt->socketID, digitalOutputNames[channel], &rawValue);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readUInt32D error calling GPIODigitalGet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
*value = rawValue & mask;
|
||||
break;
|
||||
case analogGain:
|
||||
if ((channel < 0) || (channel >= MAX_ANALOG_OUTPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readUInt32D channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
status = GPIOAnalogGainGet(pPvt->socketID, 1, analogInputNames[channel], (int*)value);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeUInt32D error calling GPIOAnalogGainSet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::readUInt32D invalid command=%d",
|
||||
command);
|
||||
return(asynError);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"drvXPSAsynAux::readUInt32D, value=%x\n", *value);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
static asynStatus writeUInt32D(void *drvPvt, asynUser *pasynUser,
|
||||
epicsUInt32 value, epicsUInt32 mask)
|
||||
{
|
||||
drvXPSAsynAuxPvt *pPvt = (drvXPSAsynAuxPvt *)drvPvt;
|
||||
int channel;
|
||||
drvXPSAsynAuxCommand command = pasynUser->reason;
|
||||
char *GPIOName;
|
||||
int status;
|
||||
|
||||
if (pPvt->shuttingDown) return asynError;
|
||||
|
||||
pasynManager->getAddr(pasynUser, &channel);
|
||||
|
||||
switch(command) {
|
||||
case binaryOutput:
|
||||
if ((channel < 0) || (channel >= MAX_DIGITAL_OUTPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeUInt32D channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
GPIOName = digitalOutputNames[channel];
|
||||
status = GPIODigitalSet(pPvt->socketID, GPIOName, mask, value);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeUInt32D error calling GPIODigitalSet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"drvXPSAsynAux::writeUInt32D, set binary output value=%d\n", value);
|
||||
break;
|
||||
case analogGain:
|
||||
if ((channel < 0) || (channel >= MAX_ANALOG_OUTPUTS)) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeUInt32D channel out of range=%d",
|
||||
channel);
|
||||
return(asynError);
|
||||
}
|
||||
GPIOName = analogInputNames[channel];
|
||||
status = GPIOAnalogGainSet(pPvt->socketID, 1, GPIOName, (int*)&value);
|
||||
if (status) {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeUInt32D error calling GPIOAnalogGainSet=%d",
|
||||
status);
|
||||
return(asynError);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
|
||||
"drvXPSAsynAux::writeUInt32D, set gain value=%d\n", value);
|
||||
break;
|
||||
default:
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::writeUInt32D invalid command=%d",
|
||||
command);
|
||||
return(asynError);
|
||||
}
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
static void shutdownCallback(drvXPSAsynAuxPvt *pPvt)
|
||||
{
|
||||
epicsMutexMustLock(pPvt->lock);
|
||||
pPvt->shuttingDown = 1;
|
||||
epicsMutexUnlock(pPvt->lock);
|
||||
}
|
||||
|
||||
static void XPSAuxPoller(drvXPSAsynAuxPvt *pPvt)
|
||||
{
|
||||
char analogNames[100] = "";
|
||||
double analogValues[MAX_ANALOG_INPUTS];
|
||||
unsigned short digitalValues[MAX_DIGITAL_INPUTS];
|
||||
unsigned short digitalValuesPrev[MAX_DIGITAL_INPUTS];
|
||||
ELLLIST *pclientList;
|
||||
interruptNode *pnode;
|
||||
asynUInt32DigitalInterrupt *pUInt32DigitalInterrupt;
|
||||
asynFloat64Interrupt *pfloat64Interrupt;
|
||||
int firstTime = 1;
|
||||
int i;
|
||||
int status;
|
||||
asynUser *pasynUser;
|
||||
int addr, reason, mask, changedBits;
|
||||
|
||||
/* Build strings with the names of the analog and digital inputs */
|
||||
for (i=0; i<MAX_ANALOG_INPUTS; i++) {
|
||||
strcat(analogNames, analogInputNames[i]);
|
||||
strcat(analogNames, ";");
|
||||
}
|
||||
|
||||
while(1) {
|
||||
status = epicsEventWaitWithTimeout(pPvt->pollerEventId, pPvt->pollerTimeout);
|
||||
epicsMutexMustLock(pPvt->lock);
|
||||
if (pPvt->shuttingDown) break;
|
||||
status = GPIOAnalogGet(pPvt->socketID, MAX_ANALOG_INPUTS, analogNames, analogValues);
|
||||
if (status) {
|
||||
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
|
||||
"drvXPSAsynAux::XPSAuxPoller error calling GPIOAnalogGet=%d\n", status);
|
||||
}
|
||||
for (i=0; i<MAX_DIGITAL_INPUTS; i++) {
|
||||
status = GPIODigitalGet(pPvt->socketID, digitalInputNames[i], &digitalValues[i]);
|
||||
if (status) {
|
||||
asynPrint(pPvt->pasynUser, ASYN_TRACE_ERROR,
|
||||
"drvXPSAsynAux::XPSAuxPoller error calling GPIODigitalGet=%d\n", status);
|
||||
}
|
||||
}
|
||||
|
||||
/* Call back any clients who have registered for callbacks on changed digital bits */
|
||||
pasynManager->interruptStart(pPvt->uint32DInterruptPvt, &pclientList);
|
||||
pnode = (interruptNode *)ellFirst(pclientList);
|
||||
while (pnode) {
|
||||
pUInt32DigitalInterrupt = pnode->drvPvt;
|
||||
pasynUser = pUInt32DigitalInterrupt->pasynUser;
|
||||
pasynManager->getAddr(pasynUser, &addr);
|
||||
reason = pasynUser->reason;
|
||||
mask = pUInt32DigitalInterrupt->mask;
|
||||
changedBits = digitalValues[addr] ^ digitalValuesPrev[addr];
|
||||
if (firstTime) changedBits = 0xffff;
|
||||
if ((mask & changedBits) && (reason == binaryInput)) {
|
||||
pUInt32DigitalInterrupt->callback(pUInt32DigitalInterrupt->userPvt, pasynUser,
|
||||
mask & digitalValues[addr]);
|
||||
}
|
||||
pnode = (interruptNode *)ellNext(&pnode->node);
|
||||
}
|
||||
pasynManager->interruptEnd(pPvt->uint32DInterruptPvt);
|
||||
for (i=0; i<MAX_DIGITAL_INPUTS; i++) {
|
||||
digitalValuesPrev[i] = digitalValues[i];
|
||||
}
|
||||
|
||||
/* Pass float64 interrupts for analog inputs*/
|
||||
pasynManager->interruptStart(pPvt->float64InterruptPvt, &pclientList);
|
||||
pnode = (interruptNode *)ellFirst(pclientList);
|
||||
while (pnode) {
|
||||
pfloat64Interrupt = pnode->drvPvt;
|
||||
addr = pfloat64Interrupt->addr;
|
||||
reason = pfloat64Interrupt->pasynUser->reason;
|
||||
if (reason == analogInput) {
|
||||
pfloat64Interrupt->callback(pfloat64Interrupt->userPvt,
|
||||
pfloat64Interrupt->pasynUser,
|
||||
analogValues[addr]);
|
||||
}
|
||||
pnode = (interruptNode *)ellNext(&pnode->node);
|
||||
}
|
||||
pasynManager->interruptEnd(pPvt->float64InterruptPvt);
|
||||
epicsMutexUnlock(pPvt->lock);
|
||||
firstTime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* asynDrvUser routines */
|
||||
static asynStatus drvUserCreate(void *drvPvt, asynUser *pasynUser,
|
||||
const char *drvInfo,
|
||||
const char **pptypeName, size_t *psize)
|
||||
{
|
||||
int i;
|
||||
char *pstring;
|
||||
int ncommands = sizeof(drvXPSAsynAuxCommands)/sizeof(drvXPSAsynAuxCommands[0]);
|
||||
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"drvXPSAsynAux::drvUserCreate, drvInfo=%s, pptypeName=%p, psize=%p, pasynUser=%p\n",
|
||||
drvInfo, pptypeName, psize, pasynUser);
|
||||
|
||||
for (i=0; i < ncommands; i++) {
|
||||
pstring = drvXPSAsynAuxCommands[i].commandString;
|
||||
if (epicsStrCaseCmp(drvInfo, pstring) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < ncommands) {
|
||||
pasynUser->reason = drvXPSAsynAuxCommands[i].command;
|
||||
if (pptypeName) {
|
||||
*pptypeName = epicsStrDup(pstring);
|
||||
}
|
||||
if (psize) {
|
||||
*psize = sizeof(drvXPSAsynAuxCommands[i].command);
|
||||
}
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"drvXPSAsynAux::drvUserCreate, command=%d string=%s\n",
|
||||
pasynUser->reason, pstring);
|
||||
return(asynSuccess);
|
||||
} else {
|
||||
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
|
||||
"drvXPSAsynAux::drvUserCreate, unknown command=%s", drvInfo);
|
||||
return(asynError);
|
||||
}
|
||||
}
|
||||
|
||||
static asynStatus drvUserGetType(void *drvPvt, asynUser *pasynUser,
|
||||
const char **pptypeName, size_t *psize)
|
||||
{
|
||||
drvXPSAsynAuxCommand command = pasynUser->reason;
|
||||
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"drvXPSAsynAux::drvUserGetType entered");
|
||||
|
||||
*pptypeName = NULL;
|
||||
*psize = 0;
|
||||
if (pptypeName)
|
||||
*pptypeName = epicsStrDup(drvXPSAsynAuxCommands[command].commandString);
|
||||
if (psize) *psize = sizeof(command);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
static asynStatus drvUserDestroy(void *drvPvt, asynUser *pasynUser)
|
||||
{
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"drvXPSAsynAux::drvUserDestroy, drvPvt=%p, pasynUser=%p\n",
|
||||
drvPvt, pasynUser);
|
||||
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
/* asynCommon routines */
|
||||
|
||||
/* Report parameters */
|
||||
static void report(void *drvPvt, FILE *fp, int details)
|
||||
{
|
||||
drvXPSAsynAuxPvt *pPvt = (drvXPSAsynAuxPvt *)drvPvt;
|
||||
interruptNode *pnode;
|
||||
ELLLIST *pclientList;
|
||||
|
||||
fprintf(fp, "Port: %s\n", pPvt->portName);
|
||||
if (details >= 1) {
|
||||
/* Report uint32D interrupts */
|
||||
pasynManager->interruptStart(pPvt->uint32DInterruptPvt, &pclientList);
|
||||
pnode = (interruptNode *)ellFirst(pclientList);
|
||||
while (pnode) {
|
||||
asynUInt32DigitalInterrupt *puint32DInterrupt = pnode->drvPvt;
|
||||
fprintf(fp, " int32 callback client address=%p, addr=%d, reason=%d\n",
|
||||
puint32DInterrupt->callback, puint32DInterrupt->addr,
|
||||
puint32DInterrupt->pasynUser->reason);
|
||||
pnode = (interruptNode *)ellNext(&pnode->node);
|
||||
}
|
||||
pasynManager->interruptEnd(pPvt->uint32DInterruptPvt);
|
||||
|
||||
/* Report float64 interrupts */
|
||||
pasynManager->interruptStart(pPvt->float64InterruptPvt, &pclientList);
|
||||
pnode = (interruptNode *)ellFirst(pclientList);
|
||||
while (pnode) {
|
||||
asynFloat64Interrupt *pfloat64Interrupt = pnode->drvPvt;
|
||||
fprintf(fp, " float64 callback client address=%p, addr=%d, reason=%d\n",
|
||||
pfloat64Interrupt->callback, pfloat64Interrupt->addr,
|
||||
pfloat64Interrupt->pasynUser->reason);
|
||||
pnode = (interruptNode *)ellNext(&pnode->node);
|
||||
}
|
||||
pasynManager->interruptEnd(pPvt->float64InterruptPvt);
|
||||
}
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
static asynStatus connect(void *drvPvt, asynUser *pasynUser)
|
||||
{
|
||||
pasynManager->exceptionConnect(pasynUser);
|
||||
|
||||
asynPrint(pasynUser, ASYN_TRACE_FLOW,
|
||||
"drvXPSAsynAux::connect, pasynUser=%p\n", pasynUser);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
/* Disconnect */
|
||||
static asynStatus disconnect(void *drvPvt, asynUser *pasynUser)
|
||||
{
|
||||
pasynManager->exceptionDisconnect(pasynUser);
|
||||
return(asynSuccess);
|
||||
}
|
||||
|
||||
static const iocshArg configArg0 = { "portName",iocshArgString};
|
||||
static const iocshArg configArg1 = { "IP address",iocshArgString};
|
||||
static const iocshArg configArg2 = { "IP port",iocshArgInt};
|
||||
static const iocshArg configArg3 = { "polling period",iocshArgInt};
|
||||
static const iocshArg * const configArgs[4] = {&configArg0,
|
||||
&configArg1,
|
||||
&configArg2,
|
||||
&configArg3};
|
||||
static const iocshFuncDef configFuncDef = {"XPSAuxConfig",4,configArgs};
|
||||
static void configCallFunc(const iocshArgBuf *args)
|
||||
{
|
||||
XPSAuxConfig(args[0].sval, args[1].sval, args[2].ival, args[3].ival);
|
||||
}
|
||||
|
||||
void drvXPSAsynAuxRegister(void)
|
||||
{
|
||||
iocshRegister(&configFuncDef,configCallFunc);
|
||||
}
|
||||
|
||||
epicsExportRegistrar(drvXPSAsynAuxRegister);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user