forked from epics_driver_modules/motorBase
675 lines
24 KiB
C
675 lines
24 KiB
C
/*
|
|
** 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 <vxWorks.h>
|
|
#else
|
|
#define OK 0
|
|
#define ERROR 1
|
|
#endif
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#ifdef vxWorks
|
|
#include <taskLib.h>
|
|
#include <sysLib.h>
|
|
static void epicsThreadSleep (double secs) {
|
|
taskDelay ((int)(sysClkRateGet () * secs));
|
|
}
|
|
#else
|
|
#include <epicsThread.h>
|
|
#endif
|
|
|
|
#include <cadef.h>
|
|
#include <errlog.h>
|
|
|
|
#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, "%.58s.UDF", encoder);
|
|
sprintf (ENC_VAL_name, "%.58s", encoder);
|
|
sprintf (MOT_RRES_name, "%.58s.RRES", myMotor);
|
|
sprintf (MOT_DMOV_name, "%.58s.DMOV", myMotor);
|
|
sprintf (MOT_URIP_name, "%.58s.URIP", myMotor);
|
|
sprintf (MOT_RDBL_name, "%.58s.RDBL", myMotor);
|
|
sprintf (MOT_SSET_name, "%.58s.SSET", myMotor);
|
|
sprintf (MOT_DVAL_name, "%.58s.DVAL", myMotor);
|
|
sprintf (MOT_DLLM_name, "%.58s.DLLM", myMotor);
|
|
sprintf (MOT_DHLM_name, "%.58s.DHLM", myMotor);
|
|
sprintf (MOT_SUSE_name, "%.58s.SUSE", myMotor);
|
|
sprintf (MOT_FOFF_name, "%.58s.FOFF", myMotor);
|
|
sprintf (MOT_ABLE_name, "%.58s_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 $ ----*/
|