Removed Newport support; Added motorNewport submodule

This commit is contained in:
kpetersn
2019-04-03 11:10:51 -05:00
parent 3046799bb3
commit 087faec96d
152 changed files with 11 additions and 119190 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "modules/motorNewport"]
path = modules/motorNewport
url = https://github.com/epics-motor/motorNewport.git
+1 -1
View File
@@ -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.
-118
View File
@@ -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}
}
-2
View File
@@ -1,2 +0,0 @@
sudo modprobe -v ftdi_sio vendor=0x104d product=0x3006
sudo chmod o+rw /dev/ttyUSB*
-2
View File
@@ -1,2 +0,0 @@
sudo modprobe -v ftdi_sio vendor=0x104d product=0x3000
sudo chmod o+rw /dev/ttyUSB*
-11
View File
@@ -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}
}
-39
View File
@@ -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
-40
View File
@@ -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
-45
View File
@@ -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
-15
View File
@@ -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 -93
View File
@@ -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 -64
View File
@@ -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 -40
View File
@@ -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.
-51
View File
@@ -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")
-46
View File
@@ -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")
-54
View File
@@ -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")
-51
View File
@@ -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")
-46
View File
@@ -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")
-30
View File
@@ -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", "#")
-32
View File
@@ -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", "#")
-30
View File
@@ -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", "#")
+1
View File
@@ -3,6 +3,7 @@ include $(TOP)/configure/CONFIG
# Submodules
#SUBMODULES += motorVendor
SUBMODULES += motorNewport
# Allow sites to add extra submodules
-include Makefile.local
-277
View File
@@ -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")
}
-98
View File
@@ -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")
}
-13
View File
@@ -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
-24
View File
@@ -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")
}
-23
View File
@@ -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")
}
-9
View File
@@ -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")
}
-8
View File
@@ -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")
}
-7
View File
@@ -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)")
}
-5
View File
@@ -1,5 +0,0 @@
grecord(longout,"$(P)$(R)")
{
field(DTYP,"asynUInt32Digital")
field(OUT,"@asynMask($(PORT) $(CHAN) 0xffffffff)BINARY_OUTPUT")
}
-131
View File
@@ -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
-44
View File
@@ -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")
}
-33
View File
@@ -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")
}
-59
View File
@@ -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
-41
View File
@@ -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")
}
-3
View File
@@ -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
-545
View File
@@ -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);
}
-80
View File
@@ -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;
};
-449
View File
@@ -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);
}
-68
View File
@@ -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_;
};
-6
View File
@@ -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/
-726
View File
@@ -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);
}
-160
View File
@@ -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);
}
}%
-99
View File
@@ -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
-137
View File
@@ -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"
-50
View File
@@ -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);
-237
View File
@@ -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
-382
View File
@@ -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);
}
-54
View File
@@ -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;
};
-55
View File
@@ -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"
-42
View File
@@ -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 *);
-286
View File
@@ -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';
}
}
-14
View File
@@ -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);
-151
View File
@@ -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);
-10
View File
@@ -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
-104
View File
@@ -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
-141
View File
@@ -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 */
-242
View File
@@ -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;
}
-221
View File
@@ -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, &currentSamples, &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;
}
-7
View File
@@ -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
-254
View File
@@ -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
-107
View File
@@ -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
-327
View File
@@ -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
View File
@@ -1 +0,0 @@
int ReadXPSSocket (int SocketIndex, char valueRtrn[], int returnSize, double timeout);
-299
View File
@@ -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);
}
-344
View File
@@ -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);
}
-349
View File
@@ -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);
}
-28
View File
@@ -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)
-4
View File
@@ -1,4 +0,0 @@
# Newport SNL programs
registrar(MM4005_trajectoryScanRegistrar)
registrar(XPS_trajectoryScanRegistrar)
registrar(xpsSlaveRegistrar)
-316
View File
@@ -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);
}
-746
View File
@@ -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);
}
/*---------------------------------------------------------------------*/
-733
View File
@@ -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);
}
/*---------------------------------------------------------------------*/
-833
View File
@@ -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);
}
-959
View File
@@ -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);
}
-20
View File
@@ -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
-117
View File
@@ -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 */
-687
View File
@@ -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
-28
View File
@@ -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
-703
View File
@@ -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