forked from epics_driver_modules/motorBase
PSI setup
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
O.*
|
||||
.*ignore
|
||||
+45
@@ -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
|
||||
@@ -0,0 +1,3 @@
|
||||
registrar(motorRegister)
|
||||
registrar(asynMotorControllerRegister)
|
||||
device(motor,INST_IO,devMotorAsyn,"asynMotor")
|
||||
@@ -0,0 +1,4 @@
|
||||
registrar(motorUtilRegister)
|
||||
variable(motorRecordDebug)
|
||||
variable(motordrvComdebug)
|
||||
variable(motorUtil_debug)
|
||||
+674
@@ -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 <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, "%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 $ ----*/
|
||||
@@ -0,0 +1,3 @@
|
||||
# Soft Channel driver support.
|
||||
device(motor,CONSTANT,devMotorSoft,"Soft Channel")
|
||||
variable(devSoftdebug)
|
||||
Reference in New Issue
Block a user