This is Unofficial EPICS BASE Doxygen Site
arr.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2010 Brookhaven National Laboratory.
3 * Copyright (c) 2010 Helmholtz-Zentrum Berlin
4 * fuer Materialien und Energie GmbH.
5 * EPICS BASE is distributed subject to a Software License Agreement found
6 * in file LICENSE that is included with this distribution.
7 \*************************************************************************/
8 
9 /*
10  * Author: Ralph Lange <Ralph.Lange@bessy.de>
11  */
12 
13 #include <stdio.h>
14 
15 #include <freeList.h>
16 #include <dbAccess.h>
17 #include <dbExtractArray.h>
18 #include <db_field_log.h>
19 #include <dbLock.h>
20 #include <recSup.h>
21 #include <epicsExit.h>
22 #include <special.h>
23 #include <chfPlugin.h>
24 #include <epicsExport.h>
25 
26 typedef struct myStruct {
32 } myStruct;
33 
34 static void *myStructFreeList;
35 
36 static const chfPluginArgDef opts[] = {
37  chfInt32 (myStruct, start, "s", 0, 1),
38  chfInt32 (myStruct, incr, "i", 0, 1),
39  chfInt32 (myStruct, end, "e", 0, 1),
40  chfPluginArgEnd
41 };
42 
43 static void * allocPvt(void)
44 {
45  myStruct *my = (myStruct*) freeListCalloc(myStructFreeList);
46  if (!my) return NULL;
47 
48  my->incr = 1;
49  my->end = -1;
50  return (void *) my;
51 }
52 
53 static void freePvt(void *pvt)
54 {
55  myStruct *my = (myStruct*) pvt;
56 
58  freeListFree(myStructFreeList, pvt);
59 }
60 
61 static int parse_ok(void *pvt)
62 {
63  myStruct *my = (myStruct*) pvt;
64 
65  if (my->incr <= 0) my->incr = 1;
66  return 0;
67 }
68 
69 static void freeArray(db_field_log *pfl)
70 {
71  if (pfl->type == dbfl_type_ref) {
72  freeListFree(pfl->u.r.pvt, pfl->u.r.field);
73  }
74 }
75 
76 static long wrapArrayIndices(long *start, const long increment, long *end,
77  const long no_elements)
78 {
79  long len = 0;
80 
81  if (*start < 0) *start = no_elements + *start;
82  if (*start < 0) *start = 0;
83  if (*start > no_elements) *start = no_elements;
84 
85  if (*end < 0) *end = no_elements + *end;
86  if (*end < 0) *end = 0;
87  if (*end >= no_elements) *end = no_elements - 1;
88 
89  if (*end - *start >= 0) len = 1 + (*end - *start) / increment;
90  return len;
91 }
92 
93 static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl)
94 {
95  myStruct *my = (myStruct*) pvt;
96  struct dbCommon *prec;
97  rset *prset;
98  long start = my->start;
99  long end = my->end;
100  long nTarget = 0;
101  long offset = 0;
102  long nSource = dbChannelElements(chan);
103  long capacity = nSource;
104  void *pdst;
105 
106  switch (pfl->type) {
107  case dbfl_type_val:
108  /* Only filter arrays */
109  break;
110 
111  case dbfl_type_rec:
112  /* Extract from record */
113  if (dbChannelSpecial(chan) == SPC_DBADDR &&
114  nSource > 1 &&
115  (prset = dbGetRset(&chan->addr)) &&
116  prset->get_array_info)
117  {
118  void *pfieldsave = dbChannelField(chan);
119  prec = dbChannelRecord(chan);
120  dbScanLock(prec);
121  prset->get_array_info(&chan->addr, &nSource, &offset);
122  nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
123  pfl->type = dbfl_type_ref;
124  pfl->stat = prec->stat;
125  pfl->sevr = prec->sevr;
126  pfl->time = prec->time;
127  pfl->field_type = dbChannelFieldType(chan);
128  pfl->field_size = dbChannelFieldSize(chan);
129  pfl->no_elements = nTarget;
130  if (nTarget) {
131  pdst = freeListCalloc(my->arrayFreeList);
132  if (pdst) {
133  pfl->u.r.dtor = freeArray;
134  pfl->u.r.pvt = my->arrayFreeList;
135  offset = (offset + start) % dbChannelElements(chan);
136  dbExtractArrayFromRec(&chan->addr, pdst, nTarget, capacity,
137  offset, my->incr);
138  pfl->u.r.field = pdst;
139  }
140  }
141  dbScanUnlock(prec);
142  dbChannelField(chan) = pfieldsave;
143  }
144  break;
145 
146  /* Extract from buffer */
147  case dbfl_type_ref:
148  pdst = NULL;
149  nSource = pfl->no_elements;
150  nTarget = wrapArrayIndices(&start, my->incr, &end, nSource);
151  pfl->no_elements = nTarget;
152  if (nTarget) {
153  /* Copy the data out */
154  void *psrc = pfl->u.r.field;
155 
156  pdst = freeListCalloc(my->arrayFreeList);
157  if (!pdst) break;
158  offset = start;
159  dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type,
160  nTarget, nSource, offset, my->incr);
161  }
162  if (pfl->u.r.dtor) pfl->u.r.dtor(pfl);
163  if (nTarget) {
164  pfl->u.r.dtor = freeArray;
165  pfl->u.r.pvt = my->arrayFreeList;
166  pfl->u.r.field = pdst;
167  }
168  break;
169  }
170  return pfl;
171 }
172 
173 static void channelRegisterPost(dbChannel *chan, void *pvt,
174  chPostEventFunc **cb_out, void **arg_out, db_field_log *probe)
175 {
176  myStruct *my = (myStruct*) pvt;
177  long start = my->start;
178  long end = my->end;
179  long max = 0;
180 
181  if (probe->no_elements <= 1) return; /* array data only */
182 
183  max = wrapArrayIndices(&start, my->incr, &end, probe->no_elements);
184  if (max) {
185  if (!my->arrayFreeList)
186  freeListInitPvt(&my->arrayFreeList, max * probe->field_size, 2);
187  if (!my->arrayFreeList) return;
188  }
189  probe->no_elements = my->no_elements = max;
190  *cb_out = filter;
191  *arg_out = pvt;
192 }
193 
194 static void channel_report(dbChannel *chan, void *pvt, int level,
195  const unsigned short indent)
196 {
197  myStruct *my = (myStruct*) pvt;
198  printf("%*sArray (arr): start=%d, incr=%d, end=%d\n", indent, "",
199  my->start, my->incr, my->end);
200 }
201 
202 static chfPluginIf pif = {
203  allocPvt,
204  freePvt,
205 
206  NULL, /* parse_error, */
207  parse_ok,
208 
209  NULL, /* channel_open, */
210  NULL, /* channelRegisterPre, */
211  channelRegisterPost,
212  channel_report,
213  NULL /* channel_close */
214 };
215 
216 static void arrShutdown(void* ignore)
217 {
218  if(myStructFreeList)
219  freeListCleanup(myStructFreeList);
220  myStructFreeList = NULL;
221 }
222 
223 static void arrInitialize(void)
224 {
225  if (!myStructFreeList)
226  freeListInitPvt(&myStructFreeList, sizeof(myStruct), 64);
227 
228  chfPluginRegister("arr", &pif, opts);
229  epicsAtExit(arrShutdown, NULL);
230 }
231 
232 epicsExportRegistrar(arrInitialize);
LIBCOM_API void *epicsStdCall freeListCalloc(void *pvt)
Definition: freeListLib.c:60
long(* get_array_info)()
Definition: recSup.h:76
#define max(x, y)
Definition: flexdef.h:81
Definition: arr.c:26
struct myStruct myStruct
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
LIBCOM_API void epicsStdCall freeListInitPvt(void **ppvt, int size, int nmalloc)
Definition: freeListLib.c:44
epicsInt32 start
Definition: arr.c:27
LIBCOM_API void epicsStdCall freeListCleanup(void *pvt)
Definition: freeListLib.c:152
LIBCOM_API void epicsStdCall freeListFree(void *pvt, void *pmem)
Definition: freeListLib.c:131
Extended replacement for the Posix exit and atexit routines.
epicsExportRegistrar(arrInitialize)
long no_elements
Definition: arr.c:31
void * arrayFreeList
Definition: arr.c:30
epicsInt32 incr
Definition: arr.c:28
#define SPC_DBADDR
Definition: special.h:27
Definition: recSup.h:67
#define epicsAtExit(F, A)
Convenience macro to register a function and context value to be run when the process exits...
Definition: epicsExit.h:70
int prec
Definition: reader.c:29
int epicsInt32
Definition: epicsTypes.h:42
epicsInt32 end
Definition: arr.c:29
Exporting IOC objects.