This is Unofficial EPICS BASE Doxygen Site
asCa.c
Go to the documentation of this file.
1 /*asCa.c*/
2 /*************************************************************************\
3 * Copyright (c) 2008 UChicago Argonne LLC, as Operator of Argonne
4 * National Laboratory.
5 * Copyright (c) 2002 The Regents of the University of California, as
6 * Operator of Los Alamos National Laboratory.
7 * EPICS BASE is distributed subject to a Software License Agreement found
8 * in file LICENSE that is included with this distribution.
9 \*************************************************************************/
10 /* Author: Marty Kraimer Date: 10-15-93 */
11 
12 /*This module is separate from asDbLib because CA uses old database access*/
13 #include <stdlib.h>
14 #include <stddef.h>
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include "alarm.h"
19 #include "asLib.h"
20 #include "cantProceed.h"
21 #include "db_access.h"
22 #include "dbDefs.h"
23 #include "ellLib.h"
24 #include "epicsEvent.h"
25 #include "epicsMutex.h"
26 #include "epicsStdio.h"
27 #include "epicsThread.h"
28 #include "errlog.h"
29 #include "taskwd.h"
30 
31 #include "cadef.h"
32 #include "caerr.h"
33 #include "caeventmask.h"
34 
35 #define epicsExportSharedSymbols
36 #include "asCa.h"
37 #include "asDbLib.h"
38 #include "callback.h"
39 #include "epicsExport.h"
40 
41 int asCaDebug = 0;
43 static int firstTime = TRUE;
44 static epicsThreadId threadid=0;
45 static int caInitializing=FALSE;
46 static epicsMutexId asCaTaskLock; /*lock access to task */
47 static epicsEventId asCaTaskWait; /*Wait for task to respond*/
48 static epicsEventId asCaTaskAddChannels; /*Tell asCaTask to add channels*/
49 static epicsEventId asCaTaskClearChannels; /*Tell asCaTask to clear channels*/
50 
51 typedef struct {
52  struct dbr_sts_double rtndata;
54 } CAPVT;
55 
56 static void exceptionCallback(struct exception_handler_args args)
57 {
58  chid chid = args.chid;
59  long stat = args.stat; /* Channel access status code*/
60  const char *channel;
61  const char *context;
62  static char *unknown = "unknown";
63  const char *nativeType;
64  const char *requestType;
65  long nativeCount;
66  long requestCount;
67  int readAccess;
68  int writeAccess;
69 
70  channel = (chid ? ca_name(chid) : unknown);
71  context = (args.ctx ? args.ctx : unknown);
72  nativeType = dbr_type_to_text((chid ? ca_field_type(chid) : -1));
73  requestType = dbr_type_to_text(args.type);
74  nativeCount = (chid ? ca_element_count(chid) : 0);
75  requestCount = args.count;
76  readAccess = (chid ? ca_read_access(chid) : 0);
77  writeAccess = (chid ? ca_write_access(chid) : 0);
78 
79  errlogPrintf("dbCa:exceptionCallback stat \"%s\" channel \"%s\""
80  " context \"%s\"\n"
81  " nativeType %s requestType %s"
82  " nativeCount %ld requestCount %ld %s %s\n",
83  ca_message(stat),channel,context,
84  nativeType,requestType,
85  nativeCount,requestCount,
86  (readAccess ? "readAccess" : "noReadAccess"),
87  (writeAccess ? "writeAccess" : "noWriteAccess"));
88 }
89 
90 /*connectCallback only handles disconnects*/
91 static void connectCallback(struct connection_handler_args arg)
92 {
93  chid chid = arg.chid;
94  ASGINP *pasginp = (ASGINP *)ca_puser(chid);
95  ASG *pasg = pasginp->pasg;
96 
97  if(ca_state(chid)!=cs_conn) {
98  if(!(pasg->inpBad & (1<<pasginp->inpIndex))) {
99  /*was good so lets make it bad*/
100  pasg->inpBad |= (1<<pasginp->inpIndex);
101  if(!caInitializing) asComputeAsg(pasg);
102  if(asCaDebug) printf("as connectCallback disconnect %s\n",
103  ca_name(chid));
104  }
105  }
106 }
107 
108 static void eventCallback(struct event_handler_args arg)
109 {
110  int caStatus = arg.status;
111  chid chid = arg.chid;
112  ASGINP *pasginp = (ASGINP *)arg.usr;
113  ASG *pasg;
114  CAPVT *pcapvt;
115  const struct dbr_sts_double *pdata;
116 
117  if(caStatus!=ECA_NORMAL) {
118  if(chid) {
119  epicsPrintf("asCa: eventCallback error %s channel %s\n",
120  ca_message(caStatus),ca_name(chid));
121  } else {
122  epicsPrintf("asCa: eventCallback error %s chid is null\n",
123  ca_message(caStatus));
124  }
125  return;
126  }
127  pasg = pasginp->pasg;
128  pcapvt = (CAPVT *)pasginp->capvt;
129  if(chid!=pcapvt->chid) {
130  epicsPrintf("asCa: eventCallback error pcapvt->chid != arg.chid\n");
131  return;
132  }
133  if(ca_state(chid)!=cs_conn || !ca_read_access(chid)) {
134  if(!(pasg->inpBad & (1<<pasginp->inpIndex))) {
135  /*was good so lets make it bad*/
136  pasg->inpBad |= (1<<pasginp->inpIndex);
137  if(!caInitializing) asComputeAsg(pasg);
138  if(asCaDebug) {
139  printf("as eventCallback %s inpBad ca_state %d"
140  " ca_read_access %d\n",
141  ca_name(chid),ca_state(chid),ca_read_access(chid));
142  }
143  }
144  return;
145  }
146  pdata = arg.dbr;
147  pcapvt->rtndata = *pdata; /*structure copy*/
148  if(pdata->severity==INVALID_ALARM) {
149  pasg->inpBad |= (1<<pasginp->inpIndex);
150  if(asCaDebug)
151  printf("as eventCallback %s inpBad because INVALID_ALARM\n",
152  ca_name(chid));
153  } else {
154  pasg->inpBad &= ~((1<<pasginp->inpIndex));
155  pasg->pavalue[pasginp->inpIndex] = pdata->value;
156  if(asCaDebug)
157  printf("as eventCallback %s inpGood data %f\n",
158  ca_name(chid),pdata->value);
159  }
160  pasg->inpChanged |= (1<<pasginp->inpIndex);
161  if(!caInitializing) asComputeAsg(pasg);
162 }
163 
164 static void asCaTask(void)
165 {
166  ASG *pasg;
167  ASGINP *pasginp;
168  CAPVT *pcapvt;
169  int status;
170 
173  "asCaTask calling ca_context_create");
174  SEVCHK(ca_add_exception_event(exceptionCallback,NULL),
175  "ca_add_exception_event");
176  while(TRUE) {
177  epicsEventMustWait(asCaTaskAddChannels);
178  caInitializing = TRUE;
179  pasg = (ASG *)ellFirst(&pasbase->asgList);
180  while(pasg) {
181  pasginp = (ASGINP *)ellFirst(&pasg->inpList);
182  while(pasginp) {
183  pasg->inpBad |= (1<<pasginp->inpIndex);
184  pcapvt = pasginp->capvt = asCalloc(1,sizeof(CAPVT));
185  /*Note calls connectCallback immediately for local Pvs*/
186  status = ca_search_and_connect(pasginp->inp,&pcapvt->chid,
187  connectCallback,pasginp);
188  if(status!=ECA_NORMAL) {
189  epicsPrintf("asCa ca_search_and_connect error %s\n",
190  ca_message(status));
191  }
192  /*Note calls eventCallback immediately for local Pvs*/
193  status = ca_add_event(DBR_STS_DOUBLE,pcapvt->chid,
194  eventCallback,pasginp,0);
195  if(status!=ECA_NORMAL) {
196  epicsPrintf("asCa ca_add_event error %s\n",
197  ca_message(status));
198  }
199  pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
200  }
201  pasg = (ASG *)ellNext((ELLNODE *)pasg);
202  }
203  SEVCHK(ca_flush_io(),"asCaTask");
204  caInitializing = FALSE;
205  asComputeAllAsg();
206  if(asCaDebug) printf("asCaTask initialized\n");
207  epicsEventSignal(asCaTaskWait);
208  epicsEventMustWait(asCaTaskClearChannels);
209  pasg = (ASG *)ellFirst(&pasbase->asgList);
210  while(pasg) {
211  pasginp = (ASGINP *)ellFirst(&pasg->inpList);
212  while(pasginp) {
213  pcapvt = (CAPVT *)pasginp->capvt;
214  status = ca_clear_channel(pcapvt->chid);
215  if(status!=ECA_NORMAL) {
216  epicsPrintf("asCa ca_clear_channel error %s\n",
217  ca_message(status));
218  }
219  free(pasginp->capvt);
220  pasginp->capvt = 0;
221  pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
222  }
223  pasg = (ASG *)ellNext((ELLNODE *)pasg);
224  }
225  if(asCaDebug) printf("asCaTask has cleared all channels\n");
226  epicsEventSignal(asCaTaskWait);
227  }
228 }
229 
230 void asCaStart(void)
231 {
232  if(asCaDebug) printf("asCaStart called\n");
233  if(firstTime) {
234  firstTime = FALSE;
235  asCaTaskLock=epicsMutexMustCreate();
237  asCaTaskAddChannels=epicsEventMustCreate(epicsEventEmpty);
238  asCaTaskClearChannels=epicsEventMustCreate(epicsEventEmpty);
239  threadid = epicsThreadCreate("asCaTask",
242  (EPICSTHREADFUNC)asCaTask,0);
243  if(threadid==0) {
244  errMessage(0,"asCaStart: taskSpawn Failure\n");
245  }
246  }
247  epicsMutexMustLock(asCaTaskLock);
248  epicsEventSignal(asCaTaskAddChannels);
249  epicsEventMustWait(asCaTaskWait);
250  if(asCaDebug) printf("asCaStart done\n");
251  epicsMutexUnlock(asCaTaskLock);
252 }
253 
254 void asCaStop(void)
255 {
256  if(threadid==0) return;
257  if(asCaDebug) printf("asCaStop called\n");
258  epicsMutexMustLock(asCaTaskLock);
259  epicsEventSignal(asCaTaskClearChannels);
260  epicsEventMustWait(asCaTaskWait);
261  if(asCaDebug) printf("asCaStop done\n");
262  epicsMutexUnlock(asCaTaskLock);
263 }
264 
265 int ascar(int level) { return ascarFP(stdout,level);}
266 
267 int ascarFP(FILE *fp,int level)
268 {
269  ASG *pasg;
270  int n=0,nbad=0;
271  enum channel_state state;
272 
273  if(!pasbase) {
274  fprintf(fp,"access security not started\n");
275  return(0);
276  }
277  pasg = (ASG *)ellFirst(&pasbase->asgList);
278  while(pasg) {
279  ASGINP *pasginp;
280  pasginp = (ASGINP *)ellFirst(&pasg->inpList);
281  while(pasginp) {
282  CAPVT *pcapvt = (CAPVT *)pasginp->capvt;
283  chid chid = pcapvt->chid;
284  pcapvt = pasginp->capvt;
285  ++n;
286  state = ca_state(chid);
287  if(state!=cs_conn) ++nbad;
288  if(level>1 || (level==1 && state!=cs_conn)) {
289  fprintf(fp,"connected:");
290  if(state==cs_never_conn) fprintf(fp,"never ");
291  else if(state==cs_prev_conn) fprintf(fp,"prev ");
292  else if(state==cs_conn) fprintf(fp,"yes ");
293  else if(state==cs_closed) fprintf(fp,"closed");
294  else fprintf(fp,"unknown");
295  fprintf(fp," read:%s write:%s",
296  (ca_read_access(chid) ? "yes" : "no "),
297  (ca_write_access(chid) ? "yes" : "no "));
298  fprintf(fp," %s %s\n", ca_name(chid),ca_host_name(chid));
299  }
300  pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
301  }
302  pasg = (ASG *)ellNext((ELLNODE *)pasg);
303  }
304  fprintf(fp,"%d channels %d not connected\n",n,nbad);
305  return(0);
306 }
307 
308 void ascaStats(int *pchans, int *pdiscon)
309 {
310  ASG *pasg;
311  int n = 0;
312  int nbad = 0;
313 
314  if(!pasbase) {
315  if (pchans) *pchans = n;
316  if (pdiscon) *pdiscon = nbad;
317  return;
318  }
319  pasg = (ASG *)ellFirst(&pasbase->asgList);
320  while (pasg) {
321  ASGINP *pasginp;
322  pasginp = (ASGINP *)ellFirst(&pasg->inpList);
323  while (pasginp) {
324  CAPVT *pcapvt = (CAPVT *)pasginp->capvt;
325  chid chid = pcapvt->chid;
326  ++n;
327  if (ca_state(chid) != cs_conn) ++nbad;
328  pasginp = (ASGINP *)ellNext((ELLNODE *)pasginp);
329  }
330  pasg = (ASG *)ellNext((ELLNODE *)pasg);
331  }
332  if (pchans) *pchans = n;
333  if (pdiscon) *pdiscon = nbad;
334 }
335 
char * inp
Definition: asLib.h:205
void taskwdInsert(epicsThreadId tid, TASKWDFUNC callback, void *usr)
Definition: taskwd.c:176
LIBCA_API unsigned epicsStdCall ca_write_access(chid chan)
void asCaStart(void)
Definition: asCa.c:230
void * capvt
Definition: asLib.h:206
#define FALSE
Definition: dbDefs.h:32
const void * dbr
Definition: cadef.h:89
LIBCOM_API volatile ASBASE * pasbase
Definition: asLibRoutines.c:38
LIBCA_API unsigned long epicsStdCall ca_element_count(chid chan)
LIBCA_API enum channel_state epicsStdCall ca_state(chid chan)
int epicsStdCall ca_search_and_connect(const char *name_str, chid *chanptr, caCh *conn_func, void *puser)
Definition: access.cpp:279
const char * ctx
Definition: cadef.h:108
LIBCA_API const char *epicsStdCall ca_host_name(chid channel)
#define printf
Definition: epicsStdio.h:41
int asCaDebug
Definition: asCa.c:41
LIBCA_API void *epicsStdCall ca_puser(chid chan)
#define epicsMutexMustCreate()
Create an epicsMutex semaphore for use from C code.
Definition: epicsMutex.h:179
#define NULL
Definition: catime.c:38
#define errMessage(S, PM)
Definition: errlog.h:48
void asCaStop(void)
Definition: asCa.c:254
Definition: cadef.h:166
unsigned long inpBad
Definition: asLib.h:218
ELLLIST asgList
Definition: asLib.h:155
LIBCOM_API epicsEventId epicsEventMustCreate(epicsEventInitialState initialState)
Create an epicsEvent for use from C code.
Definition: epicsEvent.cpp:106
channel_state
Definition: cadef.h:166
void epicsStdCall epicsMutexUnlock(epicsMutexId pmutexNode)
Release the semaphore.
Definition: epicsMutex.cpp:140
int ascar(int level)
Definition: asCa.c:265
LIBCOM_API long epicsStdCall asComputeAsg(ASG *pasg)
Miscellaneous macro definitions.
LIBCA_API short epicsStdCall ca_field_type(chid chan)
LIBCOM_API unsigned int epicsStdCall epicsThreadGetStackSize(epicsThreadStackSizeClass size)
Definition: osdThread.c:466
LIBCOM_API void epicsEventMustWait(epicsEventId id)
Wait for an event (see epicsEventWait()).
Definition: epicsEvent.cpp:123
epicsThreadId epicsStdCall epicsThreadCreate(const char *name, unsigned int priority, unsigned int stackSize, EPICSTHREADFUNC funptr, void *parm)
Definition: epicsThread.cpp:33
#define dbr_type_to_text(type)
Definition: db_access.h:687
A doubly-linked list library.
int epicsStdCall ca_context_create(ca_preemptive_callback_select premptiveCallbackSelect)
Definition: access.cpp:172
epicsExportAddress(int, asCaDebug)
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
dbr_short_t status
Definition: db_access.h:351
#define ECA_NORMAL
Definition: caerr.h:77
#define epicsEventSignal(ID)
A synonym for epicsEventTrigger().
Definition: epicsEvent.h:172
APIs for the epicsMutex mutual exclusion semaphore.
int epicsStdCall ca_add_exception_event(caExceptionHandler *pfunc, void *arg)
Definition: access.cpp:402
int epicsStdCall ca_flush_io()
Definition: access.cpp:509
#define SEVCHK(CA_ERROR_CODE, MESSAGE_STRING)
Definition: cadef.h:137
#define epicsPrintf
Definition: errlog.h:51
LIBCA_API const char *epicsStdCall ca_name(chid chan)
LIBCA_API unsigned epicsStdCall ca_read_access(chid chan)
struct asg * pasg
Definition: asLib.h:207
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
#define stdout
Definition: epicsStdio.h:30
List node type.
Definition: ellLib.h:45
int epicsStdCall ca_clear_channel(chid pChan)
Definition: access.cpp:363
#define DBR_STS_DOUBLE
Definition: db_access.h:84
APIs for the epicsEvent binary semaphore.
int inpIndex
Definition: asLib.h:208
Definition: asCa.c:51
const char *epicsStdCall ca_message(long ca_status)
Definition: access.cpp:561
chanId chid
Definition: cadef.h:86
void ascaStats(int *pchans, int *pdiscon)
Definition: asCa.c:308
Definition: asLib.h:211
#define TRUE
Definition: dbDefs.h:27
if(yy_init)
Definition: scan.c:972
#define epicsThreadPriorityScanLow
Definition: epicsThread.h:82
LIBCOM_API void *epicsStdCall asCalloc(size_t nobj, size_t size)
Routines for code that can&#39;t continue or return after an error.
chid chid
Definition: asCa.c:53
ELLLIST inpList
Definition: asLib.h:214
LIBCOM_API long epicsStdCall asComputeAllAsg(void)
int ascarFP(FILE *fp, int level)
Definition: asCa.c:267
C++ and C descriptions for a thread.
#define epicsMutexMustLock(ID)
Claim a semaphore (see epicsMutexLock()).
Definition: epicsMutex.h:214
#define INVALID_ALARM
Definition: alarm.h:53
#define ca_add_event(type, chan, pFunc, pArg, pEventID)
Definition: cadef.h:866
void * usr
Definition: cadef.h:85
void(* EPICSTHREADFUNC)(void *parm)
Definition: epicsThread.h:66
Definition: asLib.h:203
Exporting IOC objects.
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89
LIBCOM_API epicsThreadId epicsStdCall epicsThreadGetIdSelf(void)
Definition: osdThread.c:810