diff --git a/.cvsignore b/.cvsignore new file mode 100644 index 00000000..fcc9dee8 --- /dev/null +++ b/.cvsignore @@ -0,0 +1,2 @@ +O.* +.*ignore diff --git a/GNUmakefile b/GNUmakefile new file mode 100644 index 00000000..a3aec07b --- /dev/null +++ b/GNUmakefile @@ -0,0 +1,45 @@ +include /ioc/tools/driver.makefile +MODULE = motorBase + +EXCLUDE_VERSIONS=3.13 +BUILDCLASSES+=vxWorks Linux WIN32 + +SOURCES += motorApp/MotorSrc/motorRecord.cc +DBDS += motorApp/MotorSrc/motorRecord.dbd + +HEADERS += motorApp/MotorSrc/motor.h +HEADERS += motorApp/MotorSrc/motor_interface.h + +HEADERS += motorApp/MotorSrc/motordrvComCode.h +HEADERS += motorApp/MotorSrc/motordrvCom.h +SOURCES += motorApp/MotorSrc/motordrvCom.cc + +HEADERS += motorApp/MotorSrc/motordevComCode.h +HEADERS += motorApp/MotorSrc/motordevCom.h +SOURCES += motorApp/MotorSrc/motordevCom.cc + +SOURCES += motorApp/MotorSrc/motorUtil.cc +SOURCES += motorApp/MotorSrc/motorUtilAux.cc +DBDS += motorBaseSupport.dbd + +SOURCES += motorApp/MotorSrc/paramLib.c +HEADERS += motorApp/MotorSrc/paramLib.h + +# Soft +SOURCES += motorApp/SoftMotorSrc/devSoft.cc +SOURCES += motorApp/SoftMotorSrc/devSoftAux.cc +DBDS += softMotorSupport.dbd + +# asynMotor +SOURCES += motorApp/MotorSrc/drvMotorAsyn.c +SOURCES += motorApp/MotorSrc/devMotorAsyn.c +HEADERS += motorApp/MotorSrc/asynMotorAxis.h +SOURCES += motorApp/MotorSrc/asynMotorAxis.cpp +HEADERS += motorApp/MotorSrc/asynMotorController.h +SOURCES += motorApp/MotorSrc/asynMotorController.cpp +DBDS += asynMotorSupport.dbd + +# Initialization +SOURCES += motorInit.c + +USR_CPPFLAGS += -DDEBUG diff --git a/asynMotorSupport.dbd b/asynMotorSupport.dbd new file mode 100644 index 00000000..a8174682 --- /dev/null +++ b/asynMotorSupport.dbd @@ -0,0 +1,3 @@ +registrar(motorRegister) +registrar(asynMotorControllerRegister) +device(motor,INST_IO,devMotorAsyn,"asynMotor") diff --git a/motorBaseSupport.dbd b/motorBaseSupport.dbd new file mode 100644 index 00000000..fe9707d2 --- /dev/null +++ b/motorBaseSupport.dbd @@ -0,0 +1,4 @@ +registrar(motorUtilRegister) +variable(motorRecordDebug) +variable(motordrvComdebug) +variable(motorUtil_debug) diff --git a/motorInit.c b/motorInit.c new file mode 100644 index 00000000..43ef246d --- /dev/null +++ b/motorInit.c @@ -0,0 +1,674 @@ +/* +** motorInit.c +** =========== +** +** Program to initialise a motor record from an encoder at ioc boot time. +** +** Note that, under EPICS 3.14, there are problems with ca_context_destroy +** if any of the channels could not be connected, e.g. if the encoder is +** on a remote IOC which is "down". In such a case, motorInit will not exit +** but go into an idle loop. For this reason, the program has been written +** so that it is reentrant, i.e. it has no global variables. +** +** Usage: +** On host: +** cc -c ... motorInit.c +** On ioc: +** ld < motorInit.o +** motorInit, "motor", "encoder" +** +** Repository: +** $Source: /cvs/G/DRV/motor/EPICS-R3-14/motorR6-2-2/motorApp/snl/motorInit.c,v $ +** +** $Revision: 1.7 $ $Date: 2008/05/06 11:44:48 $ +** +** +--------------------------------------------------------------+ +** | Paul Scherrer Institute | +** | SLS Controls Software Group | +** | | +** | This software may be used freely by non-profit organizations.| +** | It may be copied provided that the name of PSI and of the | +** | author is included. Neither PSI nor the author assume any | +** | responsibility for the use of this software outside of PSI. | +** +--------------------------------------------------------------+ +*/ + +#ifdef vxWorks + #include +#else + #define OK 0 + #define ERROR 1 +#endif +#include +#include +#include +#include +#ifdef vxWorks + #include + #include + static void epicsThreadSleep (double secs) { + taskDelay ((int)(sysClkRateGet () * secs)); + } +#else + #include +#endif + +#include +#include + +#define DESTROY {if (pVar->connectingCounter > 0) { \ + printf ("motorInit: pending connection -- cannot exit!\n"); \ + motorInitSuspend (pVar); \ + } \ + if (pVar->debug) printf ("Calling ca_context_destroy ...\n"); \ + ca_context_destroy (); \ + return ERROR;} +/* Function Prototypes +*/ + struct UserVar { + int connectingCounter; + int debug; + }; + + static void caConnectCallback ( + struct connection_handler_args args); + static void motorInitSuspend ( + struct UserVar *pVar); + static int myGetw ( + char *chanName, + chid chId, + chtype type, + void *pVal, + double secs, + int debug); + static int myPutw ( + char *chanName, + chid chId, + chtype type, + void *pVal, + double secs, + int debug); + static int mySearchw ( + char *chanName, + chid *pChId, + double secs, + struct UserVar *pVar); + static int startCaSearch ( + char *chanName, + chid *pChId, + struct UserVar *pVar); + static int waitAllConnected ( + double secs, + struct UserVar *pVar); +/*-------------------------------------------------------------------------------- +** motorInitSuspend -- Simply do nothing forever, unless connectingCounter +** should happen to go to zero, in which case we can +** return. +*/ + static void motorInitSuspend ( +/* ================ +*/ struct UserVar *pVar) { + + while (pVar->connectingCounter > 0) { + epicsThreadSleep (1); + } + } +/*-------------------------------------------------------------------------------- +*/ + static void caConnectCallback ( +/* ================= +*/ struct connection_handler_args myArgs) { /* The arguments */ + + struct UserVar *pVar; + + if (myArgs.op != CA_OP_CONN_UP) { + errlogPrintf ("caConnectCallback: Connection failed, probably!\n"); + } else { + pVar = (struct UserVar *) ca_puser (myArgs.chid); + if (pVar->debug) errlogPrintf ("caConnectCallback: Connection up.\n"); + pVar->connectingCounter--; + } + } +/*-------------------------------------------------------------------------------- +*/ + static int myGetw ( +/* ====== +*/ char *chanName, /* Name of channel to be read */ + chid chId, /* Channel ID of channel */ + chtype type, /* Type of variable to be returned */ + void *pVal, /* Pointer to value to be returned */ + double secs, /* Time-out in secs */ + int debug) { /* If non-zero, be verbose */ + +/* Read a value from an EPICS channel and wait till we've got it. +*/ + int status; + + if (debug) printf ("Reading %s, type %s ...\n", chanName, dbr_type_to_text (type)); + + status = ca_get (type, chId, pVal); + if (status != ECA_NORMAL) { + errlogPrintf ("Error return from ca_get of %s: %d\n", chanName, status); + return ERROR; + } + status = ca_pend_io (secs); + switch (status) { + case ECA_NORMAL: + if (debug) printf ("ca_get OK.\n"); + return OK; + case ECA_TIMEOUT: + errlogPrintf ("Time-out from ca_pend_io for ca_get from channel %s\n", chanName); + return ERROR; + default: + errlogPrintf ("Error return from ca_pend_io for ca_get from channel %s: %d\n", chanName, status); + return ERROR; + } + return OK; + } +/*-------------------------------------------------------------------------------- +*/ + static int myPutw ( +/* ====== +*/ char *chanName, /* Name of channel to be read */ + chid chId, /* Channel ID of channel */ + chtype type, /* Type of variable to be written */ + void *pVal, /* Pointer to value to be written */ + double secs, /* Time-out in secs */ + int debug) { /* If non-zero, be verbose */ + +/* Read a value from an EPICS channel and wait till we've got it. +*/ + int status, i; + char *pChar; + + if (debug) { + printf ("Writing %s, type %s\n", chanName, dbr_type_to_text (type)); + pChar = (char *) pVal; + for (i = 0; i < 8; i++) printf (" %d", pChar[i]); + printf ("\n"); + } + + status = ca_put (type, chId, pVal); + if (status != ECA_NORMAL) { + errlogPrintf ("Error return from ca_put of %s: %d\n", chanName, status); + return ERROR; + } + status = ca_pend_io (secs); + switch (status) { + case ECA_NORMAL: + if (debug) printf ("ca_put OK.\n"); + return OK; + case ECA_TIMEOUT: + errlogPrintf ("Time-out from ca_pend_io for ca_put to channel %s\n", chanName); + return ERROR; + default: + errlogPrintf ("Error return from ca_pend_io for ca_put to channel %s: %d\n", chanName, status); + return ERROR; + } + return OK; + } +/*-------------------------------------------------------------------------------- +*/ + static int mySearchw ( +/* ========= +*/ char *chanName, /* Name of channel to be connected */ + chid *pChId, /* Channel ID to be returned */ + double secs, /* Time-out in secs */ + struct UserVar *pVar) { /* User data structure */ + +/* Search for an EPICS channel and wait until we have +** connected to it. +*/ + int status; + + if (pVar->debug) printf ("mySearchw: %s ...\n", chanName); + status = startCaSearch (chanName, pChId, pVar); + if (status != OK) { + errlogPrintf ("Error return from startCaSearch for %s: %d\n", chanName, status); + return ERROR; + } + if (pVar->debug) printf ("mySearchw: waiting for connection to complete ...\n"); + if (waitAllConnected (secs, pVar) != OK) return ERROR; + return OK; + } +/*-------------------------------------------------------------------------------- +*/ + static int startCaSearch ( +/* ============= +*/ char *chanName, + chid *pChId, + struct UserVar *pVar) { + int status; + + if (pVar->debug) printf ("Connecting to %s\n", chanName); + status = ca_create_channel (chanName, caConnectCallback, pVar, 0, pChId); + if (status != ECA_NORMAL) { + errlogPrintf ("Error return from ca_search of %s: %d\n", chanName, status); + return ERROR; + } + pVar->connectingCounter++; + return OK; + } +/*-------------------------------------------------------------------------------- +*/ + static int waitAllConnected ( +/* ================ +*/ double secs, + struct UserVar *pVar) { + + if (secs <= 0.0) secs = 5.0; + while (pVar->connectingCounter & (secs >= 0)) { + epicsThreadSleep (0.1); + secs = secs - 0.1; + } + if (pVar->connectingCounter) { + errlogPrintf ("Time-out waiting for connection(s) to be established.\n"); + return ERROR; + } + return OK; + } +/*-------------------------------------------------------------------------------- +*/ + int motorInit ( +/* ========= +*/ char *motor, + char *encoder, + int debug) { + + char *usage = "Usage: motorInit \"motor\", \"encoder\" [, debug]"; + char myMotor[64], myEncoder[64], *pDot; + int status, cntr; + size_t rdblLen; + double tmo = 5.0; + epicsInt32 foff_save = 0, able_save = 0; + double setVal; + struct UserVar *pVar; + /*------------------------------------------------------- + ** Here are the channel id's of all the channels we need. + */ + chid ca_ENC_UDF; /* != 0 if encoder value undefined */ + epicsInt32 ENC_UDF = 0; + char ENC_UDF_name[64]; + + chid ca_ENC_VAL; /* The encoder value */ + double ENC_VAL; + char ENC_VAL_name[64]; + + chid ca_MOT_RRES; /* Motor "Readback resolution" */ + double MOT_RRES; + char MOT_RRES_name[64]; + + chid ca_MOT_DMOV; /* DMOV == 1 if motor finished moving */ + epicsInt32 MOT_DMOV = 0; + char MOT_DMOV_name[64]; + + chid ca_MOT_URIP; /* Motor "Use Readout If Present" */ + epicsInt32 MOT_URIP = 0; + char MOT_URIP_name[64]; + + chid ca_MOT_RDBL; /* Motor Readback Link */ + char MOT_RDBL[64]; + char MOT_RDBL_name[64]; + + chid ca_MOT_SSET; /* Motor "Set SET Mode" */ + epicsInt32 MOT_SSET = 0; + char MOT_SSET_name[64]; + + chid ca_MOT_DVAL; /* Motor "Dial Value" */ + double MOT_DVAL; + char MOT_DVAL_name[64]; + + chid ca_MOT_DLLM; /* Motor Dial Low Limit */ + double MOT_DLLM; + char MOT_DLLM_name[64]; + + chid ca_MOT_DHLM; /* Motor Dial High Limit */ + double MOT_DHLM; + char MOT_DHLM_name[64]; + + chid ca_MOT_SUSE; /* Motor "Set USE Mode" */ + epicsInt32 MOT_SUSE = 0; + char MOT_SUSE_name[64]; + + chid ca_MOT_FOFF; /* Motor "Offset-Freeze" if == 1 */ + epicsInt32 MOT_FOFF = 0; + char MOT_FOFF_name[64]; + + chid ca_MOT_ABLE; /* Motor "Enable/Disable" */ + epicsInt32 MOT_ABLE = 0; + char MOT_ABLE_name[64]; + /*------------------------------------------------------- + */ + pVar = calloc (1, sizeof (struct UserVar)); + if (debug) printf ("Address of connectingCounter = %p\n", &pVar->connectingCounter); + + pVar->debug = debug; + pVar->connectingCounter = 0; + + if ((motor == NULL) || + (encoder == NULL)) { + printf ("%s\n", usage); + return ERROR; + } + if (((strlen (motor) < 2) || (strlen (motor) > 40)) || + ((strlen (encoder) < 2) || (strlen (encoder) > 40))) { + printf ("%s\n", usage); + return ERROR; + } + + strcpy (myMotor, motor); + pDot = strchr (myMotor, '.'); + if (pDot) { + *pDot = '\000'; + printf ("Motor name has been truncated to \"%s\".\n", myMotor); + } + + strcpy (myEncoder, encoder); + pDot = strchr (myEncoder, '.'); + if (pDot) { + *pDot = '\000'; + printf ("Encoder name has been truncated to \"%s\".\n", myEncoder); + } + + status = ca_context_create (ca_enable_preemptive_callback); + if (status != ECA_NORMAL) { + errlogPrintf ("Error return from ca_context_create: %d", status); + return ERROR; + } + printf ("Synchronising %s and %s ...\n", myMotor, encoder); + + sprintf (ENC_UDF_name, "%s.UDF", encoder); + sprintf (ENC_VAL_name, "%s", encoder); + sprintf (MOT_RRES_name, "%s.RRES", myMotor); + sprintf (MOT_DMOV_name, "%s.DMOV", myMotor); + sprintf (MOT_URIP_name, "%s.URIP", myMotor); + sprintf (MOT_RDBL_name, "%s.RDBL", myMotor); + sprintf (MOT_SSET_name, "%s.SSET", myMotor); + sprintf (MOT_DVAL_name, "%s.DVAL", myMotor); + sprintf (MOT_DLLM_name, "%s.DLLM", myMotor); + sprintf (MOT_DHLM_name, "%s.DHLM", myMotor); + sprintf (MOT_SUSE_name, "%s.SUSE", myMotor); + sprintf (MOT_FOFF_name, "%s.FOFF", myMotor); + sprintf (MOT_ABLE_name, "%s_able", myMotor); + if (debug) { + printf ("Channels to be used are:\n"); + printf (" %s\n", ENC_UDF_name); + printf (" %s\n", ENC_VAL_name); + printf (" %s\n", MOT_RRES_name); + printf (" %s\n", MOT_DMOV_name); + printf (" %s\n", MOT_URIP_name); + printf (" %s\n", MOT_RDBL_name); + printf (" %s\n", MOT_SSET_name); + printf (" %s\n", MOT_DVAL_name); + printf (" %s\n", MOT_DLLM_name); + printf (" %s\n", MOT_DHLM_name); + printf (" %s\n", MOT_SUSE_name); + printf (" %s\n", MOT_FOFF_name); + printf (" %s\n", MOT_ABLE_name); + } + /*--------------------------------------------------- + ** Start by getting the RDBL field of the motor and + ** checking that it matches the given encoder name. + */ + status = mySearchw (MOT_RDBL_name, &ca_MOT_RDBL, tmo, pVar); + if (status != OK) { + ca_clear_channel (ca_MOT_RDBL); DESTROY; + } + status = myGetw ( + MOT_RDBL_name, ca_MOT_RDBL, DBR_STRING, &MOT_RDBL, tmo, debug); + if (status != OK) { + ca_context_destroy (); + return ERROR; + } + + rdblLen = strcspn (MOT_RDBL, " "); MOT_RDBL[rdblLen] = '\0'; + if (strcmp (MOT_RDBL, encoder) != 0) { + errlogPrintf ("\007RDBL field of %s is not %s.\n", myMotor, encoder); + errlogPrintf ("Synchronisation abandoned!\n"); + ca_context_destroy (); + return ERROR; + } + /*--------------------------------------------------- + ** Next, check that the encoder channel exists. + */ + if (mySearchw (ENC_VAL_name, &ca_ENC_VAL, tmo, pVar) != OK) { + errlogPrintf ("Synchronisation abandoned!\n"); + DESTROY; + } + + status = myGetw ( + ENC_VAL_name, ca_ENC_VAL, DBR_DOUBLE, &ENC_VAL, tmo, debug); + if (status != OK) { + errlogPrintf ("Synchronisation abandoned!\n"); + ca_context_destroy (); + return ERROR; + } + /*--------------------------------------------------- + ** Preliminary checks OK, so connect to all channels. + */ + if (startCaSearch (ENC_UDF_name, &ca_ENC_UDF, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_RRES_name, &ca_MOT_RRES, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_DMOV_name, &ca_MOT_DMOV, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_URIP_name, &ca_MOT_URIP, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_SSET_name, &ca_MOT_SSET, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_DVAL_name, &ca_MOT_DVAL, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_DLLM_name, &ca_MOT_DLLM, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_DHLM_name, &ca_MOT_DHLM, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_SUSE_name, &ca_MOT_SUSE, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_FOFF_name, &ca_MOT_FOFF, pVar) != OK) {ca_context_destroy (); return ERROR;} + if (startCaSearch (MOT_ABLE_name, &ca_MOT_ABLE, pVar) != OK) {ca_context_destroy (); return ERROR;} + + if (waitAllConnected (tmo, pVar) != OK) { + DESTROY; + } + if (pVar->debug) printf ("All channels connected.\n"); + /*--------------------------------------------------- + ** Wait for encoder value to become valid. Immediately + ** after iocInit, this could, in principle, take a + ** bit of time. + */ + if (debug) printf ("Ensuring that %s is valid ...\n", myEncoder); + cntr = 50; + if (myGetw ( + ENC_UDF_name, ca_ENC_UDF, DBR_INT, &ENC_UDF, tmo, debug) != OK) { + DESTROY; + } + while (ENC_UDF != 0) { + cntr--; + if (cntr <= 0) { + errlogPrintf ("\007Time-out waiting for encoder value to become valid.\n"); + errlogPrintf ("Synchronisation abandoned!\n"); + DESTROY; + } + epicsThreadSleep (0.1); + if (myGetw ( + ENC_UDF_name, ca_ENC_UDF, DBR_INT, &ENC_UDF, tmo, debug) != OK) { + DESTROY; + } + } + if (debug) printf ("%s is OK\n", myEncoder); + /*--------------------------------------------------- + ** Get the enable/disable state of the motor and then + ** ensure that it is enabled. + */ + if (myGetw ( + MOT_ABLE_name, ca_MOT_ABLE, DBR_LONG, &able_save, tmo, debug) != OK) { + DESTROY; + } + if (debug) printf ("%-27s = %10d\n", MOT_ABLE_name, able_save); + if (able_save != 0) { + MOT_ABLE = 0; + if (myPutw ( + MOT_ABLE_name, ca_MOT_ABLE, DBR_LONG, &MOT_ABLE, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("Motor enabled\n"); + epicsThreadSleep (1.0); + } + } + /*--------------------------------------------------- + ** Get the values we need or which need saving. + */ + if (myGetw ( + MOT_FOFF_name, ca_MOT_FOFF, DBR_LONG, &foff_save, tmo, debug) != OK) { + DESTROY; + } + if (myGetw ( + MOT_DLLM_name, ca_MOT_DLLM, DBR_DOUBLE, &MOT_DLLM, tmo, debug) != OK) { + DESTROY; + } + if (myGetw ( + MOT_DHLM_name, ca_MOT_DHLM, DBR_DOUBLE, &MOT_DHLM, tmo, debug) != OK) { + DESTROY; + } + if (myGetw ( + MOT_RRES_name, ca_MOT_RRES, DBR_DOUBLE, &MOT_RRES, tmo, debug) != OK) { + DESTROY; + } + if (myGetw ( + ENC_VAL_name, ca_ENC_VAL, DBR_DOUBLE, &ENC_VAL, tmo, debug) != OK) { + DESTROY; + } + if (debug) printf ("%-27s = %10d\n", MOT_FOFF_name, foff_save); + if (debug) printf ("%-27s = %10.5f\n", MOT_DLLM_name, MOT_DLLM); + if (debug) printf ("%-27s = %10.5f\n", MOT_DHLM_name, MOT_DHLM); + if (debug) printf ("%-27s = %10.5f\n", MOT_RRES_name, MOT_RRES); + if (debug) printf ("%-27s = %10.5f\n", ENC_VAL_name, ENC_VAL); + + setVal = MOT_RRES * ENC_VAL; + printf ("Value of encoder = %10.5f\n", setVal); + /*--------------------------------------------------- + ** Freeze the offsets + */ + MOT_FOFF = 1; + if (myPutw ( + MOT_FOFF_name, ca_MOT_FOFF, DBR_LONG, &MOT_FOFF, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("Fixed offset.\n"); + epicsThreadSleep (1.0); + } + /*--------------------------------------------------- + ** Tell motor to use encoder + */ + MOT_URIP = 1; + if (myPutw ( + MOT_URIP_name, ca_MOT_URIP, DBR_LONG, &MOT_URIP, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("URIP set to 1.\n"); + epicsThreadSleep (1.0); + } + /*--------------------------------------------------- + ** Go to "Set" mode + */ + MOT_SSET = 1; + if (myPutw ( + MOT_SSET_name, ca_MOT_SSET, DBR_LONG, &MOT_SSET, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("\"Set\" mode has been set.\n"); + epicsThreadSleep (1.0); + } + /*--------------------------------------------------- + ** If the motor soft limits are set (i.e. not both zero), + ** See if encoder has a valid value. + ** If so, use it, otherwise set a middle point. + */ + if ((MOT_DLLM != 0.0) || (MOT_DHLM != 0.0)) { + if ((setVal < MOT_DLLM) || (setVal > MOT_DHLM)) { + printf ("\007Warning -- motor seems to be outside its soft limits!\n"); + setVal = 0.5 * (MOT_DLLM + MOT_DHLM); + } + } + /* Force motor record update */ + MOT_DVAL = setVal; + if (myPutw ( + MOT_DVAL_name, ca_MOT_DVAL, DBR_DOUBLE, &MOT_DVAL, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("Dial value has been set to %f\n", MOT_DVAL); + } + /*--------------------------------------------------- + ** The update can take some time. Wait for the + ** motor's DMOV field to get set. + */ + if (debug) printf ("Waiting for update to complete ...\n"); + cntr = 50; + if (myGetw ( + MOT_DMOV_name, ca_MOT_DMOV, DBR_INT, &MOT_DMOV, tmo, debug) != OK) { + DESTROY; + } + while (MOT_DMOV == 0) { + cntr--; + if (cntr <= 0) { + errlogPrintf ("\007Time-out waiting for update to complete.\n"); + errlogPrintf ("Synchronisation abandoned!\n"); + DESTROY; + } + epicsThreadSleep (0.1); + if (myGetw ( + MOT_DMOV_name, ca_MOT_DMOV, DBR_INT, &MOT_DMOV, tmo, debug) != OK) { + DESTROY; + } + } + if (debug) printf ("Update completed.\n"); + /*--------------------------------------------------- + ** Go back to "Use" mode. + */ + MOT_SUSE = 1; + if (myPutw ( + MOT_SUSE_name, ca_MOT_SUSE, DBR_LONG, &MOT_SUSE, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("\"Use\" mode has been set.\n"); + epicsThreadSleep (1.0); + } + /*--------------------------------------------------- + ** Restore FOFF state. + */ + MOT_FOFF = foff_save; + if (myPutw ( + MOT_FOFF_name, ca_MOT_FOFF, DBR_LONG, &MOT_FOFF, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("Offset state (fixed/variable) restored.\n"); + epicsThreadSleep (1.0); + } + /*--------------------------------------------------- + ** Restore "Enable" state. + */ + MOT_ABLE = able_save; + if (myPutw ( + MOT_ABLE_name, ca_MOT_ABLE, DBR_LONG, &MOT_ABLE, tmo, debug) != OK) { + DESTROY; + } + if (debug) { + printf ("Motor enable/disable state restored.\n"); + epicsThreadSleep (1.0); + } + /*--------------------------------------------------- + */ + ca_context_destroy (); /* Close down channel access */ + free (pVar); + printf ("%s and %s have been synchronised\n", myMotor, myEncoder); + return OK; + } +/*--------------------------------------------------*/ +/* emacs setup - force text mode to prevent emacs */ +/* from helping with the indentation */ +/* and tell emacs to use spaces when */ +/* tabbing. */ +/* Local Variables: */ +/* mode:text */ +/* indent-tabs-mode:nil */ +/* End: */ +/*--------------------------------------------------*/ +/*--------------------------------- End of $RCSfile: motorInit.c,v $ ----*/ diff --git a/softMotorSupport.dbd b/softMotorSupport.dbd new file mode 100644 index 00000000..041247ad --- /dev/null +++ b/softMotorSupport.dbd @@ -0,0 +1,3 @@ +# Soft Channel driver support. +device(motor,CONSTANT,devMotorSoft,"Soft Channel") +variable(devSoftdebug)