Files
epics-base/src/sequencer/seq_if.c
1996-05-09 19:30:37 +00:00

587 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
seq_if.c,v 1.3 1995/10/10 01:56:49 wright Exp
* DESCRIPTION: Interface functions from state program to run-time sequencer.
* Note: To prevent global name conflicts "seq_" is added by the SNC, e.g.
* pvPut() becomes seq_pvPut().
*
* Author: Andy Kozubal
* Date: 1 March, 1994
*
* Experimental Physics and Industrial Control System (EPICS)
*
* Copyright 1991-1994, 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:
* -----------------
*/
#define ANSI
#include "seq.h"
/* See seqCom.h for function prototypes (ANSI standard) */
/*#define DEBUG*/
/* The following "pv" functions are included here:
seq_pvGet()
seq_pvGetComplete()
seq_pvPut()
seq_pvFlush()
seq_pvConnect()
seq_pvMonitor()
seq_pvStopMonitor()
seq_pvStatus()
seq_pvSeverity()
seq_pvConnected()
seq_pvAssigned()
seq_pvChannelCount()
seq_pvAssignCount()
seq_pvConnectCount()
seq_pvCount()
seq_pvIndex()
seq_pvTimeStamp()
*/
/* Flush outstanding CA requests */
void seq_pvFlush()
{
ca_flush_io();
}
/*
* seq_pvGet() - Get DB value (uses channel access).
*/
long seq_pvGet(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
SSCB *pSS;
CHAN *pDB; /* ptr to channel struct */
int status, sem_status;
extern VOID seq_callback_handler();
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
pDB = pSP->pChan + pvId;
/* Check for channel connected */
if (!pDB->connected)
return ECA_DISCONN;
/* Flag this pvGet() as not completed */
pDB->getComplete = FALSE;
/* If synchronous pvGet then clear the pvGet pend semaphore */
if ((pSP->options & OPT_ASYNC) == 0)
{
pDB->getSemId = pSS->getSemId;
semTake(pSS->getSemId, NO_WAIT);
}
/* Perform the CA get operation with a callback routine specified */
status = ca_array_get_callback(
pDB->getType, /* db request type */
pDB->count, /* element count */
pDB->chid, /* chid */
seq_callback_handler
, /* callback handler */
pDB); /* user arg */
if (status != ECA_NORMAL)
{
pDB->getComplete = TRUE;
SEVCHK(status, "pvGet");
return status;
}
ca_flush_io();
if ((pSP->options & OPT_ASYNC) != 0)
{ /* +a option: return immediately */
return ECA_NORMAL;
}
/* Synchronous (-a option): wait for completion (10s timeout) */
sem_status = semTake(pSS->getSemId, 600);
if (sem_status != OK)
{
logMsg ("semTake error=%d\n", sem_status);
return ECA_TIMEOUT;
}
return ECA_NORMAL;
}
/*
* seq_pvGetComplete() - returns TRUE if the last get completed.
*/
long seq_pvGetComplete(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->getComplete;
}
/*
* seq_pvPut() - Put DB value.
*/
long seq_pvPut(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status, count;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
#ifdef DEBUG
logMsg("seq_pvPut: pv name=%s, pVar=0x%x\n", pDB->dbName, pDB->pVar);
#endif DEBUG
if (!pDB->connected)
return ECA_DISCONN;
count = pDB->count;
if (count > pDB->dbCount)
count = pDB->dbCount; /* don't try to put more than db count */
status = ca_array_put(pDB->putType, count, pDB->chid, pDB->pVar);
#ifdef DEBUG
logMsg("seq_pvPut: status=%d\n", status);
if (status != ECA_NORMAL)
{
seq_log(pSP, "pvPut on \"%s\" failed (%d)\n",
pDB->dbName, status);
seq_log(pSP, " putType=%d\n", pDB->putType);
seq_log(pSP, " size=%d, count=%d\n", pDB->size, count);
}
#endif DEBUG
return status;
}
/*
* seq_pvAssign() - Assign/Connect to a channel.
* Assign to a zero-lth string ("") disconnects/de-assignes.
*/
long seq_pvAssign(SS_ID ssId, long pvId, char *pvName)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status, nchar;
extern VOID seq_conn_handler();
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
#ifdef DEBUG
printf("Assign %s to \"%s\"\n", pDB->pVarName, pvName);
#endif DEBUG
if (pDB->assigned)
{ /* Disconnect this channel */
status = ca_clear_channel(pDB->chid);
if (status != ECA_NORMAL)
return status;
free(pDB->dbName);
pDB->assigned = FALSE;
pSP->assignCount -= 1;
}
if (pDB->connected)
{
pDB->connected = FALSE;
pSP->connCount -= 1;
}
pDB->monitored = FALSE;
nchar = strlen(pvName);
pDB->dbName = (char *)calloc(1, nchar + 1);
strcpy(pDB->dbName, pvName);
/* Connect */
if (nchar > 0)
{
pDB->assigned = TRUE;
pSP->assignCount += 1;
status = ca_build_and_connect(
pDB->dbName, /* DB channel name */
TYPENOTCONN, /* Don't get initial value */
0, /* get count (n/a) */
&(pDB->chid), /* ptr to chid */
0, /* ptr to value (n/a) */
seq_conn_handler, /* connection handler routine */
pDB); /* user ptr is CHAN structure */
if (status != ECA_NORMAL)
{
return status;
}
if (pDB->monFlag)
{
status = seq_pvMonitor(ssId, pvId);
if (status != ECA_NORMAL)
return status;
}
}
ca_flush_io();
return ECA_NORMAL;
}
/*
* seq_pvMonitor() - Initiate a monitor on a channel.
*/
long seq_pvMonitor(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
extern VOID seq_event_handler();
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
#ifdef DEBUG
printf("monitor \"%s\"\n", pDB->dbName);
#endif DEBUG
if (pDB->monitored || !pDB->assigned)
return ECA_NORMAL;
status = ca_add_array_event(
pDB->getType, /* requested type */
pDB->count, /* element count */
pDB->chid, /* chid */
seq_event_handler, /* function to call */
pDB, /* user arg (db struct) */
0.0, /* pos. delta value */
0.0, /* neg. delta value */
0.0, /* timeout */
&pDB->evid); /* where to put event id */
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_add_array_event");
ca_task_exit(); /* this is serious */
return status;
}
ca_flush_io();
pDB->monitored = TRUE;
return ECA_NORMAL;
}
/*
* seq_pvStopMonitor() - Cancel a monitor
*/
long seq_pvStopMonitor(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
if (!pDB->monitored)
return -1;
status = ca_clear_event(pDB->evid);
if (status != ECA_NORMAL)
{
SEVCHK(status, "ca_clear_event");
return status;
}
pDB->monitored = FALSE;
return status;
}
/*
* seq_pvChannelCount() - returns total number of database channels.
*/
long seq_pvChannelCount(SS_ID ssId)
{
SPROG *pSP; /* ptr to state program */
int status;
pSP = ((SSCB *)ssId)->sprog;
return pSP->numChans;
}
/*
* seq_pvConnectCount() - returns number of database channels connected.
*/
long seq_pvConnectCount(SS_ID ssId)
{
SPROG *pSP; /* ptr to state program */
int status;
pSP = ((SSCB *)ssId)->sprog;
return pSP->connCount;
}
/*
* seq_pvAssignCount() - returns number of database channels assigned.
*/
long seq_pvAssignCount(SS_ID ssId)
{
SPROG *pSP; /* ptr to state program */
int status;
pSP = ((SSCB *)ssId)->sprog;
return pSP->assignCount;
}
/*
* seq_pvConnected() - returns TRUE if database channel is connected.
*/
long seq_pvConnected(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB;
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->connected;
}
/*
* seq_pvAssigned() - returns TRUE if database channel is assigned.
*/
long seq_pvAssigned(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB;
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->assigned;
}
/*
* seq_pvCount() - returns number elements in an array, which is the lesser of
* (1) the array size and (2) the element count returned by channel access.
*/
long seq_pvCount(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->dbCount;
}
/*
* seq_pvStatus() - returns channel alarm status.
*/
long seq_pvStatus(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->status;
}
/*
* seq_pvSeverity() - returns channel alarm severity.
*/
long seq_pvSeverity(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->severity;
}
/*
* seq_pvIndex() - returns index of database variable.
*/
long seq_pvIndex(SS_ID ssId, long pvId)
{
return pvId; /* index is same as pvId */
}
/*
* seq_pvTimeStamp() - returns channel time stamp.
*/
TS_STAMP seq_pvTimeStamp(SS_ID ssId, long pvId)
{
SPROG *pSP; /* ptr to state program */
CHAN *pDB; /* ptr to channel struct */
int status;
pSP = ((SSCB *)ssId)->sprog;
pDB = pSP->pChan + pvId;
return pDB->timeStamp;
}
/*
* seq_efSet() - Set an event flag, then wake up each state
* set that might be waiting on that event flag.
*/
VOID seq_efSet(SS_ID ssId, long ev_flag)
{
SPROG *pSP;
SSCB *pSS;
int nss;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
#ifdef DEBUG
logMsg("seq_efSet: pSP=0x%x, pSS=0x%x, ev_flag=0x%x\n", pSP, pSS, ev_flag);
taskDelay(10);
#endif DEBUG
/* Set this bit (apply resource lock) */
semTake(pSP->caSemId, WAIT_FOREVER);
bitSet(pSP->pEvents, ev_flag);
/* Wake up state sets that are waiting for this event flag */
seqWakeup(pSP, ev_flag);
/* Unlock resource */
semGive(pSP->caSemId);
}
/*
* seq_efTest() - Test event flag against outstanding events.
*/
long seq_efTest(SS_ID ssId, long ev_flag)
/* event flag */
{
SPROG *pSP;
SSCB *pSS;
int isSet;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
isSet = bitTest(pSP->pEvents, ev_flag);
#ifdef DEBUG
logMsg("seq_efTest: ev_flag=%d, event=0x%x, isSet=%d\n",
ev_flag, pSP->pEvents[0], isSet);
#endif DEBUG
return isSet;
}
/*
* seq_efClear() - Test event flag against outstanding events, then clear it.
*/
long seq_efClear(SS_ID ssId, long ev_flag)
{
SPROG *pSP;
SSCB *pSS;
int isSet;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
isSet = bitTest(pSP->pEvents, ev_flag);
bitClear(pSP->pEvents, ev_flag);
return isSet;
}
/*
* seq_efTestAndClear() - Test event flag against outstanding events, then clear it.
*/
long seq_efTestAndClear(SS_ID ssId, long ev_flag)
{
SPROG *pSP;
SSCB *pSS;
int isSet;
pSS = (SSCB *)ssId;
pSP = pSS->sprog;
isSet = bitTest(pSP->pEvents, ev_flag);
bitClear(pSP->pEvents, ev_flag);
return isSet;
}
/* seq_delay() - test for delay() time-out expired */
long seq_delay(SS_ID ssId, long delayId)
{
SSCB *pSS;
ULONG timeElapsed;
pSS = (SSCB *)ssId;
/* Calc. elapsed time since state was entered */
timeElapsed = tickGet() - pSS->timeEntered;
/* Check for delay timeout */
if (timeElapsed >= pSS->delay[delayId])
{
pSS->delayExpired[delayId] = TRUE; /* mark as expired */
return TRUE;
}
return FALSE;
}
/*
* seq_delayInit() - initialize delay time (in seconds) on entering a state.
*/
VOID seq_delayInit(SS_ID ssId, long delayId, float delay)
{
SSCB *pSS;
int ndelay;
pSS = (SSCB *)ssId;
/* Convert delay time to tics & save */
pSS->delay[delayId] = delay * 60.0;
ndelay = delayId + 1;
if (ndelay > pSS->numDelays)
pSS->numDelays = ndelay;
}
/*
* seq_optGet: return the value of an option (e.g. "a").
* FALSE means "-" and TRUE means "+".
*/
BOOL seq_optGet(SS_ID ssId, char *opt)
{
SPROG *pSP;
pSP = ((SSCB *)ssId)->sprog;
switch (opt[0])
{
case 'a': return ( (pSP->options & OPT_ASYNC) != 0);
case 'c': return ( (pSP->options & OPT_CONN) != 0);
case 'd': return ( (pSP->options & OPT_DEBUG) != 0);
case 'e': return ( (pSP->options & OPT_NEWEF) != 0);
case 'r': return ( (pSP->options & OPT_REENT) != 0);
case 'v': return ( (pSP->options & OPT_VXWORKS) != 0);
default: return FALSE;
}
}