Merge ~bfrk/epics-base:write-filters into ~epics-core/epics-base/+git/epics-base:7.0
- Git
- lp:~bfrk/epics-base
- write-filters
- Merge into 7.0
Status: | Superseded |
---|---|
Proposed branch: | ~bfrk/epics-base:write-filters |
Merge into: | ~epics-core/epics-base/+git/epics-base:7.0 |
Diff against target: |
3074 lines (+1008/-798) 27 files modified
documentation/RELEASE_NOTES.md (+9/-0) modules/database/src/ioc/db/dbAccess.c (+467/-439) modules/database/src/ioc/db/dbAccessDefs.h (+1/-1) modules/database/src/ioc/db/dbChannel.c (+2/-59) modules/database/src/ioc/db/dbChannel.h (+3/-3) modules/database/src/ioc/db/dbDbLink.c (+86/-53) modules/database/src/ioc/db/dbDbLink.h (+1/-1) modules/database/src/ioc/db/dbEvent.c (+73/-40) modules/database/src/ioc/db/dbEvent.h (+1/-0) modules/database/src/ioc/db/dbExtractArray.c (+20/-49) modules/database/src/ioc/db/dbExtractArray.h (+16/-5) modules/database/src/ioc/db/dbLink.c (+1/-1) modules/database/src/ioc/db/dbLink.h (+2/-1) modules/database/src/ioc/db/dbLock.c (+3/-3) modules/database/src/ioc/db/dbTest.c (+16/-16) modules/database/src/ioc/db/dbUnitTest.c (+2/-2) modules/database/src/ioc/db/db_field_log.h (+30/-30) modules/database/src/std/dev/devAiSoft.c (+2/-1) modules/database/src/std/filters/arr.c (+52/-70) modules/database/src/std/filters/ts.c (+27/-9) modules/database/test/ioc/db/dbChArrTest.cpp (+2/-1) modules/database/test/std/filters/arrTest.cpp (+8/-7) modules/database/test/std/filters/dbndTest.c (+3/-6) modules/database/test/std/rec/Makefile (+7/-0) modules/database/test/std/rec/linkFilterTest.c (+157/-0) modules/database/test/std/rec/linkFilterTest.db (+16/-0) modules/database/test/std/rec/regressTest.c (+1/-1) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
EPICS Core Developers | Pending | ||
Review via email: mp+381125@code.launchpad.net |
Commit message
Description of the change
This is just the initial refactor, no new features yet.
Ben Franksen (bfrk) wrote : | # |
Andrew Johnson (anj) wrote : | # |
Yes, please hit the "Resubmit proposal" towards the top right of the window and enter Dirk's branch as a prerequisite. That way launchpad doesn't mix your changes in with his and we can review and comment on them separately.
Unmerged commits
- 13fb313... by Ben Franksen
-
refactor db_field_log and filters to get rid of dbfl_type_rec
This refactor simplifies and streamlines the code associated with server
side filters. Apart from immediate benefits (clearer code, less duplication)
it is also hoped that this will make it easier to add write filters.The data pointer dbfl_ref.field can now either point to a copy owned by a
filter, or it can point to the original data owned by a record. In the
latter case, the dbfl_ref.dtor is NULL. This required adding
db_field_log.offset as a new member. It gets initialized, together with the
no_elements member, by a call to the rset.get_array_info, so we can continue
to support the wrap-around/ring-buffer feature for array fields. It turned out that dbGetField was always called with a NULL pointer as its
db_field_log* argument, which is why I removed this parameter. This makes
sense because the extra db_field_log parameter of dbGet is an internal
implementation detail that should not affect the external API. Nowadays,
even dbGetField is no longer quite appropriate for user code, which should
rather call dbChannelGetField in order to profit from filters and long
strings (the "PV$" notation). - 6aeddc3... by Ben Franksen
-
reformat modules/
database/ src/ioc/ db/dbAccess. c - e2d9953... by Ben Franksen
-
Merge branch 'dbChannelForDB
Links' into write-filters - e419914... by Dirk Zimoch
-
Release notes updated
- ed0b4d4... by Dirk Zimoch
-
set number of planned link filter tests
- fc61f20... by Dirk Zimoch
-
removed unnecessary recGblSetSevr call
- 8a8de85... by Dirk Zimoch
-
re-order link filter tests to alternate between success and failure
- 1324246... by Dirk Zimoch
-
unused variable removed
- 2986080... by Dirk Zimoch
-
Revert "fix crash in PINI: use local db_field_log"
This reverts commit a590151accb1d18
7562c515a48e013 244dd98a45. Conflicts:
modules/database/ src/ioc/ db/dbDbLink. c - 4960efa... by Dirk Zimoch
-
initialize free lists when starting dbChannel
Preview Diff
1 | diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md |
2 | index bdd2468..681495e 100644 |
3 | --- a/documentation/RELEASE_NOTES.md |
4 | +++ b/documentation/RELEASE_NOTES.md |
5 | @@ -36,6 +36,15 @@ As long as all support modules and IOCs are rebuilt from source after updating |
6 | them to use this release of EPICS Base, these changes should not have any |
7 | affect. |
8 | |
9 | +### Filters in database links |
10 | + |
11 | +Input links can now use filters, most importantly array element and sub array |
12 | +access, even if they are not channel access links. |
13 | + |
14 | +### ai Soft Channel support |
15 | + |
16 | +The Soft Channel device support for ai records now returns failure when |
17 | +fetching the INP link fails. |
18 | |
19 | ### logClient reliability |
20 | |
21 | diff --git a/modules/database/src/ioc/db/dbAccess.c b/modules/database/src/ioc/db/dbAccess.c |
22 | index 19f6038..a6c31f2 100644 |
23 | --- a/modules/database/src/ioc/db/dbAccess.c |
24 | +++ b/modules/database/src/ioc/db/dbAccess.c |
25 | @@ -34,7 +34,7 @@ |
26 | #include "errlog.h" |
27 | #include "errMdef.h" |
28 | |
29 | -#include "epicsExport.h" /* #define epicsExportSharedSymbols */ |
30 | +#include "epicsExport.h" /* #define epicsExportSharedSymbols */ |
31 | #include "caeventmask.h" |
32 | #include "callback.h" |
33 | #include "dbAccessDefs.h" |
34 | @@ -63,7 +63,7 @@ |
35 | #include "special.h" |
36 | |
37 | epicsShareDef struct dbBase *pdbbase = 0; |
38 | -epicsShareDef volatile int interruptAccept=FALSE; |
39 | +epicsShareDef volatile int interruptAccept = FALSE; |
40 | |
41 | epicsShareDef int dbAccessDebugPUTF = 0; |
42 | epicsExportAddress(int, dbAccessDebugPUTF); |
43 | @@ -73,24 +73,24 @@ epicsExportAddress(int, dbAccessDebugPUTF); |
44 | epicsShareDef DB_LOAD_RECORDS_HOOK_ROUTINE dbLoadRecordsHook = NULL; |
45 | |
46 | static short mapDBFToDBR[DBF_NTYPES] = { |
47 | - /* DBF_STRING => */ DBR_STRING, |
48 | - /* DBF_CHAR => */ DBR_CHAR, |
49 | - /* DBF_UCHAR => */ DBR_UCHAR, |
50 | - /* DBF_SHORT => */ DBR_SHORT, |
51 | - /* DBF_USHORT => */ DBR_USHORT, |
52 | - /* DBF_LONG => */ DBR_LONG, |
53 | - /* DBF_ULONG => */ DBR_ULONG, |
54 | - /* DBF_INT64 => */ DBR_INT64, |
55 | - /* DBF_UINT64 => */ DBR_UINT64, |
56 | - /* DBF_FLOAT => */ DBR_FLOAT, |
57 | - /* DBF_DOUBLE => */ DBR_DOUBLE, |
58 | - /* DBF_ENUM, => */ DBR_ENUM, |
59 | - /* DBF_MENU, => */ DBR_ENUM, |
60 | - /* DBF_DEVICE => */ DBR_ENUM, |
61 | - /* DBF_INLINK => */ DBR_STRING, |
62 | - /* DBF_OUTLINK => */ DBR_STRING, |
63 | - /* DBF_FWDLINK => */ DBR_STRING, |
64 | - /* DBF_NOACCESS => */ DBR_NOACCESS |
65 | + /* DBF_STRING => */ DBR_STRING, |
66 | + /* DBF_CHAR => */ DBR_CHAR, |
67 | + /* DBF_UCHAR => */ DBR_UCHAR, |
68 | + /* DBF_SHORT => */ DBR_SHORT, |
69 | + /* DBF_USHORT => */ DBR_USHORT, |
70 | + /* DBF_LONG => */ DBR_LONG, |
71 | + /* DBF_ULONG => */ DBR_ULONG, |
72 | + /* DBF_INT64 => */ DBR_INT64, |
73 | + /* DBF_UINT64 => */ DBR_UINT64, |
74 | + /* DBF_FLOAT => */ DBR_FLOAT, |
75 | + /* DBF_DOUBLE => */ DBR_DOUBLE, |
76 | + /* DBF_ENUM, => */ DBR_ENUM, |
77 | + /* DBF_MENU, => */ DBR_ENUM, |
78 | + /* DBF_DEVICE => */ DBR_ENUM, |
79 | + /* DBF_INLINK => */ DBR_STRING, |
80 | + /* DBF_OUTLINK => */ DBR_STRING, |
81 | + /* DBF_FWDLINK => */ DBR_STRING, |
82 | + /* DBF_NOACCESS => */ DBR_NOACCESS |
83 | }; |
84 | |
85 | /* |
86 | @@ -109,217 +109,219 @@ void dbSpcAsRegisterCallback(SPC_ASCALLBACK func) |
87 | spcAsCallback = func; |
88 | } |
89 | |
90 | -long dbPutSpecial(DBADDR *paddr,int pass) |
91 | +long dbPutSpecial(DBADDR *paddr, int pass) |
92 | { |
93 | - long int (*pspecial)()=NULL; |
94 | - rset *prset; |
95 | - dbCommon *precord = paddr->precord; |
96 | - long status=0; |
97 | - long special=paddr->special; |
98 | + long int (*pspecial) () = NULL; |
99 | + rset *prset; |
100 | + dbCommon *precord = paddr->precord; |
101 | + long status = 0; |
102 | + long special = paddr->special; |
103 | |
104 | prset = dbGetRset(paddr); |
105 | - if(special<100) { /*global processing*/ |
106 | - if((special==SPC_NOMOD) && (pass==0)) { |
107 | - status = S_db_noMod; |
108 | - recGblDbaddrError(status,paddr,"dbPut"); |
109 | - return(status); |
110 | - }else if(special==SPC_SCAN){ |
111 | - if(pass==0) |
112 | - scanDelete(precord); |
113 | - else |
114 | - scanAdd(precord); |
115 | - }else if((special==SPC_AS) && (pass==1)) { |
116 | - if(spcAsCallback) (*spcAsCallback)(precord); |
117 | - } |
118 | - }else { |
119 | - if( prset && (pspecial = (prset->special))) { |
120 | - status=(*pspecial)(paddr,pass); |
121 | - if(status) return(status); |
122 | - } else if(pass==0){ |
123 | - recGblRecSupError(S_db_noSupport,paddr,"dbPut", "special"); |
124 | - return(S_db_noSupport); |
125 | - } |
126 | + if (special < 100) { /*global processing */ |
127 | + if ((special == SPC_NOMOD) && (pass == 0)) { |
128 | + status = S_db_noMod; |
129 | + recGblDbaddrError(status, paddr, "dbPut"); |
130 | + return (status); |
131 | + } else if (special == SPC_SCAN) { |
132 | + if (pass == 0) |
133 | + scanDelete(precord); |
134 | + else |
135 | + scanAdd(precord); |
136 | + } else if ((special == SPC_AS) && (pass == 1)) { |
137 | + if (spcAsCallback) |
138 | + (*spcAsCallback) (precord); |
139 | + } |
140 | + } else { |
141 | + if (prset && (pspecial = (prset->special))) { |
142 | + status = (*pspecial) (paddr, pass); |
143 | + if (status) |
144 | + return (status); |
145 | + } else if (pass == 0) { |
146 | + recGblRecSupError(S_db_noSupport, paddr, "dbPut", "special"); |
147 | + return (S_db_noSupport); |
148 | + } |
149 | } |
150 | - return(0); |
151 | + return (0); |
152 | } |
153 | |
154 | static void get_enum_strs(DBADDR *paddr, char **ppbuffer, |
155 | - rset *prset,long *options) |
156 | + rset * prset, long *options) |
157 | { |
158 | - short field_type=paddr->field_type; |
159 | - dbFldDes *pdbFldDes = paddr->pfldDes; |
160 | - dbMenu *pdbMenu; |
161 | - dbDeviceMenu *pdbDeviceMenu; |
162 | - char **papChoice; |
163 | - unsigned long no_str; |
164 | - char *ptemp; |
165 | - struct dbr_enumStrs *pdbr_enumStrs=(struct dbr_enumStrs*)(*ppbuffer); |
166 | + short field_type = paddr->field_type; |
167 | + dbFldDes *pdbFldDes = paddr->pfldDes; |
168 | + dbMenu *pdbMenu; |
169 | + dbDeviceMenu *pdbDeviceMenu; |
170 | + char **papChoice; |
171 | + unsigned long no_str; |
172 | + char *ptemp; |
173 | + struct dbr_enumStrs *pdbr_enumStrs = (struct dbr_enumStrs *)(*ppbuffer); |
174 | unsigned int i; |
175 | |
176 | - memset(pdbr_enumStrs,'\0',dbr_enumStrs_size); |
177 | - switch(field_type) { |
178 | - case DBF_ENUM: |
179 | - if( prset && prset->get_enum_strs ) { |
180 | - (*prset->get_enum_strs)(paddr,pdbr_enumStrs); |
181 | - } else { |
182 | - *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/ |
183 | - } |
184 | - break; |
185 | - case DBF_MENU: |
186 | - pdbMenu = (dbMenu *)pdbFldDes->ftPvt; |
187 | - no_str = pdbMenu->nChoice; |
188 | - papChoice= pdbMenu->papChoiceValue; |
189 | - goto choice_common; |
190 | - case DBF_DEVICE: |
191 | - pdbDeviceMenu = (dbDeviceMenu *)pdbFldDes->ftPvt; |
192 | - if(!pdbDeviceMenu) { |
193 | - *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/ |
194 | - break; |
195 | - } |
196 | - no_str = pdbDeviceMenu->nChoice; |
197 | - papChoice = pdbDeviceMenu->papChoice; |
198 | - goto choice_common; |
199 | -choice_common: |
200 | - i = sizeof(pdbr_enumStrs->strs)/ |
201 | - sizeof(pdbr_enumStrs->strs[0]); |
202 | - if(i<no_str) no_str = i; |
203 | - pdbr_enumStrs->no_str = no_str; |
204 | - ptemp = &(pdbr_enumStrs->strs[0][0]); |
205 | - for (i=0; i<no_str; i++) { |
206 | - if(papChoice[i]==NULL) *ptemp=0; |
207 | - else { |
208 | - strncpy(ptemp,papChoice[i], |
209 | - sizeof(pdbr_enumStrs->strs[0])); |
210 | - *(ptemp+sizeof(pdbr_enumStrs->strs[0])-1) = 0; |
211 | - } |
212 | - ptemp += sizeof(pdbr_enumStrs->strs[0]); |
213 | - } |
214 | - break; |
215 | - default: |
216 | - *options = (*options)^DBR_ENUM_STRS;/*Turn off option*/ |
217 | - break; |
218 | - } |
219 | - *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size; |
220 | - return; |
221 | + memset(pdbr_enumStrs, '\0', dbr_enumStrs_size); |
222 | + switch (field_type) { |
223 | + case DBF_ENUM: |
224 | + if (prset && prset->get_enum_strs) { |
225 | + (*prset->get_enum_strs) (paddr, pdbr_enumStrs); |
226 | + } else { |
227 | + *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */ |
228 | + } |
229 | + break; |
230 | + case DBF_MENU: |
231 | + pdbMenu = (dbMenu *) pdbFldDes->ftPvt; |
232 | + no_str = pdbMenu->nChoice; |
233 | + papChoice = pdbMenu->papChoiceValue; |
234 | + goto choice_common; |
235 | + case DBF_DEVICE: |
236 | + pdbDeviceMenu = (dbDeviceMenu *) pdbFldDes->ftPvt; |
237 | + if (!pdbDeviceMenu) { |
238 | + *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */ |
239 | + break; |
240 | + } |
241 | + no_str = pdbDeviceMenu->nChoice; |
242 | + papChoice = pdbDeviceMenu->papChoice; |
243 | + goto choice_common; |
244 | + choice_common: |
245 | + i = sizeof(pdbr_enumStrs->strs) / sizeof(pdbr_enumStrs->strs[0]); |
246 | + if (i < no_str) |
247 | + no_str = i; |
248 | + pdbr_enumStrs->no_str = no_str; |
249 | + ptemp = &(pdbr_enumStrs->strs[0][0]); |
250 | + for (i = 0; i < no_str; i++) { |
251 | + if (papChoice[i] == NULL) |
252 | + *ptemp = 0; |
253 | + else { |
254 | + strncpy(ptemp, papChoice[i], sizeof(pdbr_enumStrs->strs[0])); |
255 | + *(ptemp + sizeof(pdbr_enumStrs->strs[0]) - 1) = 0; |
256 | + } |
257 | + ptemp += sizeof(pdbr_enumStrs->strs[0]); |
258 | + } |
259 | + break; |
260 | + default: |
261 | + *options = (*options) ^ DBR_ENUM_STRS; /*Turn off option */ |
262 | + break; |
263 | + } |
264 | + *ppbuffer = ((char *)*ppbuffer) + dbr_enumStrs_size; |
265 | + return; |
266 | } |
267 | |
268 | static void get_graphics(DBADDR *paddr, char **ppbuffer, |
269 | - rset *prset,long *options) |
270 | + rset * prset, long *options) |
271 | { |
272 | - struct dbr_grDouble grd; |
273 | - int got_data=FALSE; |
274 | - |
275 | - grd.upper_disp_limit = grd.lower_disp_limit = 0.0; |
276 | - if( prset && prset->get_graphic_double ) { |
277 | - (*prset->get_graphic_double)(paddr,&grd); |
278 | - got_data=TRUE; |
279 | - } |
280 | - if( (*options) & (DBR_GR_LONG) ) { |
281 | - char *pbuffer=*ppbuffer; |
282 | - |
283 | - if(got_data) { |
284 | - struct dbr_grLong *pgr=(struct dbr_grLong*)pbuffer; |
285 | - pgr->upper_disp_limit = (epicsInt32)grd.upper_disp_limit; |
286 | - pgr->lower_disp_limit = (epicsInt32)grd.lower_disp_limit; |
287 | - } else { |
288 | - memset(pbuffer,'\0',dbr_grLong_size); |
289 | - *options = (*options) ^ DBR_GR_LONG; /*Turn off option*/ |
290 | - } |
291 | - *ppbuffer = ((char *)*ppbuffer) + dbr_grLong_size; |
292 | - } |
293 | - if( (*options) & (DBR_GR_DOUBLE) ) { |
294 | - char *pbuffer=*ppbuffer; |
295 | - |
296 | - if(got_data) { |
297 | - struct dbr_grDouble *pgr=(struct dbr_grDouble*)pbuffer; |
298 | - pgr->upper_disp_limit = grd.upper_disp_limit; |
299 | - pgr->lower_disp_limit = grd.lower_disp_limit; |
300 | - } else { |
301 | - memset(pbuffer,'\0',dbr_grDouble_size); |
302 | - *options = (*options) ^ DBR_GR_DOUBLE; /*Turn off option*/ |
303 | - } |
304 | - *ppbuffer = ((char *)*ppbuffer) + dbr_grDouble_size; |
305 | - } |
306 | - return; |
307 | + struct dbr_grDouble grd; |
308 | + int got_data = FALSE; |
309 | + |
310 | + grd.upper_disp_limit = grd.lower_disp_limit = 0.0; |
311 | + if (prset && prset->get_graphic_double) { |
312 | + (*prset->get_graphic_double) (paddr, &grd); |
313 | + got_data = TRUE; |
314 | + } |
315 | + if ((*options) & (DBR_GR_LONG)) { |
316 | + char *pbuffer = *ppbuffer; |
317 | + |
318 | + if (got_data) { |
319 | + struct dbr_grLong *pgr = (struct dbr_grLong *)pbuffer; |
320 | + pgr->upper_disp_limit = (epicsInt32) grd.upper_disp_limit; |
321 | + pgr->lower_disp_limit = (epicsInt32) grd.lower_disp_limit; |
322 | + } else { |
323 | + memset(pbuffer, '\0', dbr_grLong_size); |
324 | + *options = (*options) ^ DBR_GR_LONG; /*Turn off option */ |
325 | + } |
326 | + *ppbuffer = ((char *)*ppbuffer) + dbr_grLong_size; |
327 | + } |
328 | + if ((*options) & (DBR_GR_DOUBLE)) { |
329 | + char *pbuffer = *ppbuffer; |
330 | + |
331 | + if (got_data) { |
332 | + struct dbr_grDouble *pgr = (struct dbr_grDouble *)pbuffer; |
333 | + pgr->upper_disp_limit = grd.upper_disp_limit; |
334 | + pgr->lower_disp_limit = grd.lower_disp_limit; |
335 | + } else { |
336 | + memset(pbuffer, '\0', dbr_grDouble_size); |
337 | + *options = (*options) ^ DBR_GR_DOUBLE; /*Turn off option */ |
338 | + } |
339 | + *ppbuffer = ((char *)*ppbuffer) + dbr_grDouble_size; |
340 | + } |
341 | + return; |
342 | } |
343 | |
344 | static void get_control(DBADDR *paddr, char **ppbuffer, |
345 | - rset *prset,long *options) |
346 | + rset * prset, long *options) |
347 | { |
348 | - struct dbr_ctrlDouble ctrld; |
349 | - int got_data=FALSE; |
350 | - |
351 | - ctrld.upper_ctrl_limit = ctrld.lower_ctrl_limit = 0.0; |
352 | - if( prset && prset->get_control_double ) { |
353 | - (*prset->get_control_double)(paddr,&ctrld); |
354 | - got_data=TRUE; |
355 | - } |
356 | - if( (*options) & (DBR_CTRL_LONG) ) { |
357 | - char *pbuffer=*ppbuffer; |
358 | - |
359 | - if(got_data) { |
360 | - struct dbr_ctrlLong *pctrl=(struct dbr_ctrlLong*)pbuffer; |
361 | - pctrl->upper_ctrl_limit = (epicsInt32)ctrld.upper_ctrl_limit; |
362 | - pctrl->lower_ctrl_limit = (epicsInt32)ctrld.lower_ctrl_limit; |
363 | - } else { |
364 | - memset(pbuffer,'\0',dbr_ctrlLong_size); |
365 | - *options = (*options) ^ DBR_CTRL_LONG; /*Turn off option*/ |
366 | - } |
367 | - *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlLong_size; |
368 | - } |
369 | - if( (*options) & (DBR_CTRL_DOUBLE) ) { |
370 | - char *pbuffer=*ppbuffer; |
371 | - |
372 | - if(got_data) { |
373 | - struct dbr_ctrlDouble *pctrl=(struct dbr_ctrlDouble*)pbuffer; |
374 | - pctrl->upper_ctrl_limit = ctrld.upper_ctrl_limit; |
375 | - pctrl->lower_ctrl_limit = ctrld.lower_ctrl_limit; |
376 | - } else { |
377 | - memset(pbuffer,'\0',dbr_ctrlDouble_size); |
378 | - *options = (*options) ^ DBR_CTRL_DOUBLE; /*Turn off option*/ |
379 | - } |
380 | - *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlDouble_size; |
381 | - } |
382 | - return; |
383 | + struct dbr_ctrlDouble ctrld; |
384 | + int got_data = FALSE; |
385 | + |
386 | + ctrld.upper_ctrl_limit = ctrld.lower_ctrl_limit = 0.0; |
387 | + if (prset && prset->get_control_double) { |
388 | + (*prset->get_control_double) (paddr, &ctrld); |
389 | + got_data = TRUE; |
390 | + } |
391 | + if ((*options) & (DBR_CTRL_LONG)) { |
392 | + char *pbuffer = *ppbuffer; |
393 | + |
394 | + if (got_data) { |
395 | + struct dbr_ctrlLong *pctrl = (struct dbr_ctrlLong *)pbuffer; |
396 | + pctrl->upper_ctrl_limit = (epicsInt32) ctrld.upper_ctrl_limit; |
397 | + pctrl->lower_ctrl_limit = (epicsInt32) ctrld.lower_ctrl_limit; |
398 | + } else { |
399 | + memset(pbuffer, '\0', dbr_ctrlLong_size); |
400 | + *options = (*options) ^ DBR_CTRL_LONG; /*Turn off option */ |
401 | + } |
402 | + *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlLong_size; |
403 | + } |
404 | + if ((*options) & (DBR_CTRL_DOUBLE)) { |
405 | + char *pbuffer = *ppbuffer; |
406 | + |
407 | + if (got_data) { |
408 | + struct dbr_ctrlDouble *pctrl = (struct dbr_ctrlDouble *)pbuffer; |
409 | + pctrl->upper_ctrl_limit = ctrld.upper_ctrl_limit; |
410 | + pctrl->lower_ctrl_limit = ctrld.lower_ctrl_limit; |
411 | + } else { |
412 | + memset(pbuffer, '\0', dbr_ctrlDouble_size); |
413 | + *options = (*options) ^ DBR_CTRL_DOUBLE; /*Turn off option */ |
414 | + } |
415 | + *ppbuffer = ((char *)*ppbuffer) + dbr_ctrlDouble_size; |
416 | + } |
417 | + return; |
418 | } |
419 | |
420 | static void get_alarm(DBADDR *paddr, char **ppbuffer, |
421 | - rset *prset, long *options) |
422 | + rset * prset, long *options) |
423 | { |
424 | char *pbuffer = *ppbuffer; |
425 | - struct dbr_alDouble ald = {epicsNAN, epicsNAN, epicsNAN, epicsNAN}; |
426 | + struct dbr_alDouble ald = { epicsNAN, epicsNAN, epicsNAN, epicsNAN }; |
427 | long no_data = TRUE; |
428 | |
429 | if (prset && prset->get_alarm_double) |
430 | no_data = prset->get_alarm_double(paddr, &ald); |
431 | |
432 | if (*options & DBR_AL_LONG) { |
433 | - struct dbr_alLong *pal = (struct dbr_alLong*) pbuffer; |
434 | + struct dbr_alLong *pal = (struct dbr_alLong *)pbuffer; |
435 | |
436 | - pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ? |
437 | + pal->upper_alarm_limit = finite(ald.upper_alarm_limit) ? |
438 | (epicsInt32) ald.upper_alarm_limit : 0; |
439 | pal->upper_warning_limit = finite(ald.upper_warning_limit) ? |
440 | (epicsInt32) ald.upper_warning_limit : 0; |
441 | pal->lower_warning_limit = finite(ald.lower_warning_limit) ? |
442 | (epicsInt32) ald.lower_warning_limit : 0; |
443 | - pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ? |
444 | + pal->lower_alarm_limit = finite(ald.lower_alarm_limit) ? |
445 | (epicsInt32) ald.lower_alarm_limit : 0; |
446 | |
447 | if (no_data) |
448 | - *options ^= DBR_AL_LONG; /*Turn off option*/ |
449 | + *options ^= DBR_AL_LONG; /*Turn off option */ |
450 | |
451 | *ppbuffer += dbr_alLong_size; |
452 | } |
453 | if (*options & DBR_AL_DOUBLE) { |
454 | - struct dbr_alDouble *pal = (struct dbr_alDouble*) pbuffer; |
455 | + struct dbr_alDouble *pal = (struct dbr_alDouble *)pbuffer; |
456 | |
457 | - pal->upper_alarm_limit = ald.upper_alarm_limit; |
458 | + pal->upper_alarm_limit = ald.upper_alarm_limit; |
459 | pal->upper_warning_limit = ald.upper_warning_limit; |
460 | pal->lower_warning_limit = ald.lower_warning_limit; |
461 | - pal->lower_alarm_limit = ald.lower_alarm_limit; |
462 | + pal->lower_alarm_limit = ald.lower_alarm_limit; |
463 | |
464 | if (no_data) |
465 | - *options ^= DBR_AL_DOUBLE; /*Turn off option*/ |
466 | + *options ^= DBR_AL_DOUBLE; /*Turn off option */ |
467 | |
468 | *ppbuffer += dbr_alDouble_size; |
469 | } |
470 | @@ -330,88 +332,89 @@ static void get_alarm(DBADDR *paddr, char **ppbuffer, |
471 | * blocks only changing the buffer pointer in a way that does not break alignment. |
472 | */ |
473 | static void getOptions(DBADDR *paddr, char **poriginal, long *options, |
474 | - void *pflin) |
475 | + void *pflin) |
476 | { |
477 | - db_field_log *pfl= (db_field_log *)pflin; |
478 | - rset *prset; |
479 | - short field_type; |
480 | - dbCommon *pcommon; |
481 | - char *pbuffer = *poriginal; |
482 | - |
483 | - if (!pfl || pfl->type == dbfl_type_rec) |
484 | - field_type = paddr->field_type; |
485 | - else |
486 | - field_type = pfl->field_type; |
487 | - prset=dbGetRset(paddr); |
488 | - /* Process options */ |
489 | - pcommon = paddr->precord; |
490 | - if( (*options) & DBR_STATUS ) { |
491 | - unsigned short *pushort = (unsigned short *)pbuffer; |
492 | - |
493 | - if (!pfl || pfl->type == dbfl_type_rec) { |
494 | - *pushort++ = pcommon->stat; |
495 | - *pushort++ = pcommon->sevr; |
496 | - } else { |
497 | - *pushort++ = pfl->stat; |
498 | - *pushort++ = pfl->sevr; |
499 | - } |
500 | - *pushort++ = pcommon->acks; |
501 | - *pushort++ = pcommon->ackt; |
502 | - pbuffer = (char *)pushort; |
503 | - } |
504 | - if( (*options) & DBR_UNITS ) { |
505 | - memset(pbuffer,'\0',dbr_units_size); |
506 | - if( prset && prset->get_units ){ |
507 | - (*prset->get_units)(paddr, pbuffer); |
508 | - pbuffer[DB_UNITS_SIZE-1] = '\0'; |
509 | - } else { |
510 | - *options ^= DBR_UNITS; /*Turn off DBR_UNITS*/ |
511 | - } |
512 | - pbuffer += dbr_units_size; |
513 | - } |
514 | - if( (*options) & DBR_PRECISION ) { |
515 | - memset(pbuffer, '\0', dbr_precision_size); |
516 | - if((field_type==DBF_FLOAT || field_type==DBF_DOUBLE) |
517 | - && prset && prset->get_precision ){ |
518 | - (*prset->get_precision)(paddr,(long *)pbuffer); |
519 | - } else { |
520 | - *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION*/ |
521 | - } |
522 | - pbuffer += dbr_precision_size; |
523 | - } |
524 | - if( (*options) & DBR_TIME ) { |
525 | - epicsUInt32 *ptime = (epicsUInt32 *)pbuffer; |
526 | - |
527 | - if (!pfl || pfl->type == dbfl_type_rec) { |
528 | - *ptime++ = pcommon->time.secPastEpoch; |
529 | - *ptime++ = pcommon->time.nsec; |
530 | - } else { |
531 | - *ptime++ = pfl->time.secPastEpoch; |
532 | - *ptime++ = pfl->time.nsec; |
533 | - } |
534 | - pbuffer = (char *)ptime; |
535 | - } |
536 | - if( (*options) & DBR_ENUM_STRS ) |
537 | - get_enum_strs(paddr, &pbuffer, prset, options); |
538 | - if( (*options) & (DBR_GR_LONG|DBR_GR_DOUBLE )) |
539 | - get_graphics(paddr, &pbuffer, prset, options); |
540 | - if((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE )) |
541 | - get_control(paddr, &pbuffer, prset, options); |
542 | - if((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE )) |
543 | - get_alarm(paddr, &pbuffer, prset, options); |
544 | - *poriginal = pbuffer; |
545 | + db_field_log *pfl = (db_field_log *) pflin; |
546 | + rset *prset; |
547 | + short field_type; |
548 | + dbCommon *pcommon; |
549 | + char *pbuffer = *poriginal; |
550 | + |
551 | + if (!pfl) |
552 | + field_type = paddr->field_type; |
553 | + else |
554 | + field_type = pfl->field_type; |
555 | + prset = dbGetRset(paddr); |
556 | + /* Process options */ |
557 | + pcommon = paddr->precord; |
558 | + if ((*options) & DBR_STATUS) { |
559 | + unsigned short *pushort = (unsigned short *)pbuffer; |
560 | + |
561 | + if (!pfl) { |
562 | + *pushort++ = pcommon->stat; |
563 | + *pushort++ = pcommon->sevr; |
564 | + } else { |
565 | + *pushort++ = pfl->stat; |
566 | + *pushort++ = pfl->sevr; |
567 | + } |
568 | + *pushort++ = pcommon->acks; |
569 | + *pushort++ = pcommon->ackt; |
570 | + pbuffer = (char *)pushort; |
571 | + } |
572 | + if ((*options) & DBR_UNITS) { |
573 | + memset(pbuffer, '\0', dbr_units_size); |
574 | + if (prset && prset->get_units) { |
575 | + (*prset->get_units) (paddr, pbuffer); |
576 | + pbuffer[DB_UNITS_SIZE - 1] = '\0'; |
577 | + } else { |
578 | + *options ^= DBR_UNITS; /*Turn off DBR_UNITS */ |
579 | + } |
580 | + pbuffer += dbr_units_size; |
581 | + } |
582 | + if ((*options) & DBR_PRECISION) { |
583 | + memset(pbuffer, '\0', dbr_precision_size); |
584 | + if ((field_type == DBF_FLOAT || field_type == DBF_DOUBLE) |
585 | + && prset && prset->get_precision) { |
586 | + (*prset->get_precision) (paddr, (long *)pbuffer); |
587 | + } else { |
588 | + *options ^= DBR_PRECISION; /*Turn off DBR_PRECISION */ |
589 | + } |
590 | + pbuffer += dbr_precision_size; |
591 | + } |
592 | + if ((*options) & DBR_TIME) { |
593 | + epicsUInt32 *ptime = (epicsUInt32 *) pbuffer; |
594 | + |
595 | + if (!pfl) { |
596 | + *ptime++ = pcommon->time.secPastEpoch; |
597 | + *ptime++ = pcommon->time.nsec; |
598 | + } else { |
599 | + *ptime++ = pfl->time.secPastEpoch; |
600 | + *ptime++ = pfl->time.nsec; |
601 | + } |
602 | + pbuffer = (char *)ptime; |
603 | + } |
604 | + if ((*options) & DBR_ENUM_STRS) |
605 | + get_enum_strs(paddr, &pbuffer, prset, options); |
606 | + if ((*options) & (DBR_GR_LONG | DBR_GR_DOUBLE)) |
607 | + get_graphics(paddr, &pbuffer, prset, options); |
608 | + if ((*options) & (DBR_CTRL_LONG | DBR_CTRL_DOUBLE)) |
609 | + get_control(paddr, &pbuffer, prset, options); |
610 | + if ((*options) & (DBR_AL_LONG | DBR_AL_DOUBLE)) |
611 | + get_alarm(paddr, &pbuffer, prset, options); |
612 | + *poriginal = pbuffer; |
613 | } |
614 | |
615 | -rset * dbGetRset(const struct dbAddr *paddr) |
616 | +rset *dbGetRset(const struct dbAddr *paddr) |
617 | { |
618 | - struct dbFldDes *pfldDes = paddr->pfldDes; |
619 | + struct dbFldDes *pfldDes = paddr->pfldDes; |
620 | |
621 | - if(!pfldDes) return(0); |
622 | - return(pfldDes->pdbRecordType->prset); |
623 | + if (!pfldDes) |
624 | + return (0); |
625 | + return (pfldDes->pdbRecordType->prset); |
626 | } |
627 | |
628 | -long dbPutAttribute( |
629 | - const char *recordTypename, const char *name, const char *value) |
630 | +long dbPutAttribute(const char *recordTypename, const char *name, |
631 | + const char *value) |
632 | { |
633 | DBENTRY dbEntry; |
634 | DBENTRY *pdbEntry = &dbEntry; |
635 | @@ -430,7 +433,7 @@ long dbPutAttribute( |
636 | if (!status) |
637 | status = dbPutRecordAttribute(pdbEntry, name, value); |
638 | dbFinishEntry(pdbEntry); |
639 | -done: |
640 | + done: |
641 | if (status) |
642 | errMessage(status, "dbPutAttribute failure"); |
643 | return status; |
644 | @@ -458,7 +461,7 @@ int dbGetFieldIndex(const struct dbAddr *paddr) |
645 | * 5. Run the process routine specific to the record type. |
646 | * 6. Check to see if record contents should be automatically printed. |
647 | */ |
648 | -long dbProcess(dbCommon *precord) |
649 | +long dbProcess(dbCommon * precord) |
650 | { |
651 | rset *prset = precord->rset; |
652 | dbRecordType *pdbRecordType = precord->rdes; |
653 | @@ -466,7 +469,7 @@ long dbProcess(dbCommon *precord) |
654 | char context[40] = ""; |
655 | long status = 0; |
656 | int *ptrace; |
657 | - int set_trace = FALSE; |
658 | + int set_trace = FALSE; |
659 | dbFldDes *pdbFldDes; |
660 | int callNotifyCompletion = FALSE; |
661 | |
662 | @@ -492,7 +495,7 @@ long dbProcess(dbCommon *precord) |
663 | goto all_done; |
664 | } |
665 | |
666 | - /* check for trace processing*/ |
667 | + /* check for trace processing */ |
668 | if (tpro) { |
669 | if (!*ptrace) { |
670 | *ptrace = 1; |
671 | @@ -519,19 +522,17 @@ long dbProcess(dbCommon *precord) |
672 | |
673 | /* raise scan alarm after MAX_LOCK times */ |
674 | if ((precord->stat == SCAN_ALARM) || |
675 | - (precord->lcnt++ < MAX_LOCK) || |
676 | - (precord->sevr >= INVALID_ALARM)) goto all_done; |
677 | + (precord->lcnt++ < MAX_LOCK) || (precord->sevr >= INVALID_ALARM)) |
678 | + goto all_done; |
679 | |
680 | recGblSetSevr(precord, SCAN_ALARM, INVALID_ALARM); |
681 | monitor_mask = recGblResetAlarms(precord); |
682 | - monitor_mask |= DBE_VALUE|DBE_LOG; |
683 | + monitor_mask |= DBE_VALUE | DBE_LOG; |
684 | pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes]; |
685 | db_post_events(precord, |
686 | - (void *)(((char *)precord) + pdbFldDes->offset), |
687 | - monitor_mask); |
688 | + (void *)(((char *)precord) + pdbFldDes->offset), monitor_mask); |
689 | goto all_done; |
690 | - } |
691 | - else |
692 | + } else |
693 | precord->lcnt = 0; |
694 | |
695 | /* |
696 | @@ -547,7 +548,7 @@ long dbProcess(dbCommon *precord) |
697 | printf("%s: dbProcess of Disabled '%s'\n", |
698 | context, precord->name); |
699 | |
700 | - /*take care of caching and notifyCompletion*/ |
701 | + /*take care of caching and notifyCompletion */ |
702 | precord->rpro = FALSE; |
703 | precord->putf = FALSE; |
704 | callNotifyCompletion = TRUE; |
705 | @@ -564,8 +565,8 @@ long dbProcess(dbCommon *precord) |
706 | db_post_events(precord, &precord->sevr, DBE_VALUE); |
707 | pdbFldDes = pdbRecordType->papFldDes[pdbRecordType->indvalFlddes]; |
708 | db_post_events(precord, |
709 | - (void *)(((char *)precord) + pdbFldDes->offset), |
710 | - DBE_VALUE|DBE_ALARM); |
711 | + (void *)(((char *)precord) + pdbFldDes->offset), |
712 | + DBE_VALUE | DBE_ALARM); |
713 | goto all_done; |
714 | } |
715 | |
716 | @@ -573,7 +574,7 @@ long dbProcess(dbCommon *precord) |
717 | /* FIXME: put this in iocInit() !!! */ |
718 | if (!prset || !prset->process) { |
719 | callNotifyCompletion = TRUE; |
720 | - precord->pact = 1;/*set pact so error is issued only once*/ |
721 | + precord->pact = 1; /*set pact so error is issued only once */ |
722 | recGblRecordError(S_db_noRSET, (void *)precord, "dbProcess"); |
723 | status = S_db_noRSET; |
724 | if (*ptrace) |
725 | @@ -592,7 +593,7 @@ long dbProcess(dbCommon *precord) |
726 | dbPrint(precord); |
727 | } |
728 | |
729 | -all_done: |
730 | + all_done: |
731 | if (set_trace) |
732 | *ptrace = 0; |
733 | if (callNotifyCompletion && precord->ppn) |
734 | @@ -601,7 +602,7 @@ all_done: |
735 | return status; |
736 | } |
737 | |
738 | -long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr) |
739 | +long dbEntryToAddr(const DBENTRY * pdbentry, DBADDR *paddr) |
740 | { |
741 | dbFldDes *pflddes = pdbentry->pflddes; |
742 | short dbfType = pflddes->field_type; |
743 | @@ -610,9 +611,9 @@ long dbEntryToAddr(const DBENTRY *pdbentry, DBADDR *paddr) |
744 | paddr->pfield = pdbentry->pfield; |
745 | paddr->pfldDes = pflddes; |
746 | paddr->no_elements = 1; |
747 | - paddr->field_type = dbfType; |
748 | - paddr->field_size = pflddes->size; |
749 | - paddr->special = pflddes->special; |
750 | + paddr->field_type = dbfType; |
751 | + paddr->field_size = pflddes->size; |
752 | + paddr->special = pflddes->special; |
753 | paddr->dbr_field_type = mapDBFToDBR[dbfType]; |
754 | |
755 | if (paddr->special == SPC_DBADDR) { |
756 | @@ -643,16 +644,20 @@ long dbNameToAddr(const char *pname, DBADDR *paddr) |
757 | |
758 | dbInitEntry(pdbbase, &dbEntry); |
759 | status = dbFindRecordPart(&dbEntry, &pname); |
760 | - if (status) goto finish; |
761 | + if (status) |
762 | + goto finish; |
763 | |
764 | - if (*pname == '.') ++pname; |
765 | + if (*pname == '.') |
766 | + ++pname; |
767 | status = dbFindFieldPart(&dbEntry, &pname); |
768 | if (status == S_dbLib_fieldNotFound) |
769 | status = dbGetAttributePart(&dbEntry, &pname); |
770 | - if (status) goto finish; |
771 | + if (status) |
772 | + goto finish; |
773 | |
774 | status = dbEntryToAddr(&dbEntry, paddr); |
775 | - if (status) goto finish; |
776 | + if (status) |
777 | + goto finish; |
778 | |
779 | /* Handle field modifiers */ |
780 | if (*pname++ == '$') { |
781 | @@ -664,29 +669,27 @@ long dbNameToAddr(const char *pname, DBADDR *paddr) |
782 | paddr->field_type = DBF_CHAR; |
783 | paddr->field_size = 1; |
784 | paddr->dbr_field_type = DBR_CHAR; |
785 | - } |
786 | - else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) { |
787 | + } else if (dbfType >= DBF_INLINK && dbfType <= DBF_FWDLINK) { |
788 | /* Clients see a char array, but keep original dbfType */ |
789 | paddr->no_elements = PVLINK_STRINGSZ; |
790 | paddr->field_size = 1; |
791 | paddr->dbr_field_type = DBR_CHAR; |
792 | - } |
793 | - else { |
794 | + } else { |
795 | status = S_dbLib_fieldNotFound; |
796 | } |
797 | } |
798 | |
799 | -finish: |
800 | + finish: |
801 | dbFinishEntry(&dbEntry); |
802 | return status; |
803 | } |
804 | |
805 | -void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry) |
806 | +void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY * pdbentry) |
807 | { |
808 | struct dbCommon *prec = paddr->precord; |
809 | dbCommonPvt *ppvt = dbRec2Pvt(prec); |
810 | |
811 | - memset((char *)pdbentry,'\0',sizeof(DBENTRY)); |
812 | + memset((char *)pdbentry, '\0', sizeof(DBENTRY)); |
813 | |
814 | pdbentry->pdbbase = pdbbase; |
815 | pdbentry->precordType = prec->rdes; |
816 | @@ -696,24 +699,24 @@ void dbInitEntryFromAddr(struct dbAddr *paddr, DBENTRY *pdbentry) |
817 | pdbentry->indfield = paddr->pfldDes->indRecordType; |
818 | } |
819 | |
820 | -void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY *pdbentry) |
821 | +void dbInitEntryFromRecord(struct dbCommon *prec, DBENTRY * pdbentry) |
822 | { |
823 | dbCommonPvt *ppvt = dbRec2Pvt(prec); |
824 | |
825 | - memset((char *)pdbentry,'\0',sizeof(DBENTRY)); |
826 | + memset((char *)pdbentry, '\0', sizeof(DBENTRY)); |
827 | |
828 | pdbentry->pdbbase = pdbbase; |
829 | pdbentry->precordType = prec->rdes; |
830 | pdbentry->precnode = ppvt->recnode; |
831 | } |
832 | |
833 | -struct link* dbGetDevLink(struct dbCommon* prec) |
834 | +struct link *dbGetDevLink(struct dbCommon *prec) |
835 | { |
836 | DBLINK *plink = 0; |
837 | DBENTRY entry; |
838 | dbInitEntryFromRecord(prec, &entry); |
839 | - if(dbFindField(&entry, "INP")==0 || dbFindField(&entry, "OUT")==0) { |
840 | - plink = (DBLINK*)entry.pfield; |
841 | + if (dbFindField(&entry, "INP") == 0 || dbFindField(&entry, "OUT") == 0) { |
842 | + plink = (DBLINK *) entry.pfield; |
843 | } |
844 | dbFinishEntry(&entry); |
845 | return plink; |
846 | @@ -723,41 +726,53 @@ long dbValueSize(short dbr_type) |
847 | { |
848 | /* sizes for value associated with each DBR request type */ |
849 | static long size[] = { |
850 | - MAX_STRING_SIZE, /* STRING */ |
851 | - sizeof(epicsInt8), /* CHAR */ |
852 | - sizeof(epicsUInt8), /* UCHAR */ |
853 | - sizeof(epicsInt16), /* SHORT */ |
854 | - sizeof(epicsUInt16), /* USHORT */ |
855 | - sizeof(epicsInt32), /* LONG */ |
856 | - sizeof(epicsUInt32), /* ULONG */ |
857 | - sizeof(epicsInt64), /* INT64 */ |
858 | - sizeof(epicsUInt64), /* UINT64 */ |
859 | - sizeof(epicsFloat32), /* FLOAT */ |
860 | - sizeof(epicsFloat64), /* DOUBLE */ |
861 | - sizeof(epicsEnum16)}; /* ENUM */ |
862 | - |
863 | - return(size[dbr_type]); |
864 | + MAX_STRING_SIZE, /* STRING */ |
865 | + sizeof(epicsInt8), /* CHAR */ |
866 | + sizeof(epicsUInt8), /* UCHAR */ |
867 | + sizeof(epicsInt16), /* SHORT */ |
868 | + sizeof(epicsUInt16), /* USHORT */ |
869 | + sizeof(epicsInt32), /* LONG */ |
870 | + sizeof(epicsUInt32), /* ULONG */ |
871 | + sizeof(epicsInt64), /* INT64 */ |
872 | + sizeof(epicsUInt64), /* UINT64 */ |
873 | + sizeof(epicsFloat32), /* FLOAT */ |
874 | + sizeof(epicsFloat64), /* DOUBLE */ |
875 | + sizeof(epicsEnum16) |
876 | + }; /* ENUM */ |
877 | + |
878 | + return (size[dbr_type]); |
879 | } |
880 | |
881 | - |
882 | long dbBufferSize(short dbr_type, long options, long no_elements) |
883 | { |
884 | - long nbytes=0; |
885 | + long nbytes = 0; |
886 | |
887 | nbytes += dbValueSize(dbr_type) * no_elements; |
888 | - if (options & DBR_STATUS) nbytes += dbr_status_size; |
889 | - if (options & DBR_UNITS) nbytes += dbr_units_size; |
890 | - if (options & DBR_PRECISION) nbytes += dbr_precision_size; |
891 | - if (options & DBR_TIME) nbytes += dbr_time_size; |
892 | - if (options & DBR_ENUM_STRS) nbytes += dbr_enumStrs_size; |
893 | - if (options & DBR_GR_LONG) nbytes += dbr_grLong_size; |
894 | - if (options & DBR_GR_DOUBLE) nbytes += dbr_grDouble_size; |
895 | - if (options & DBR_CTRL_LONG) nbytes += dbr_ctrlLong_size; |
896 | - if (options & DBR_CTRL_DOUBLE) nbytes += dbr_ctrlDouble_size; |
897 | - if (options & DBR_AL_LONG) nbytes += dbr_alLong_size; |
898 | - if (options & DBR_AL_DOUBLE) nbytes += dbr_alDouble_size; |
899 | - return(nbytes); |
900 | + if (options & DBR_STATUS) |
901 | + nbytes += dbr_status_size; |
902 | + if (options & DBR_UNITS) |
903 | + nbytes += dbr_units_size; |
904 | + if (options & DBR_PRECISION) |
905 | + nbytes += dbr_precision_size; |
906 | + if (options & DBR_TIME) |
907 | + nbytes += dbr_time_size; |
908 | + if (options & DBR_ENUM_STRS) |
909 | + nbytes += dbr_enumStrs_size; |
910 | + if (options & DBR_GR_LONG) |
911 | + nbytes += dbr_grLong_size; |
912 | + if (options & DBR_GR_DOUBLE) |
913 | + nbytes += dbr_grDouble_size; |
914 | + if (options & DBR_CTRL_LONG) |
915 | + nbytes += dbr_ctrlLong_size; |
916 | + if (options & DBR_CTRL_DOUBLE) |
917 | + nbytes += dbr_ctrlDouble_size; |
918 | + if (options & DBR_AL_LONG) |
919 | + nbytes += dbr_alLong_size; |
920 | + if (options & DBR_AL_DOUBLE) |
921 | + nbytes += dbr_alDouble_size; |
922 | + return (nbytes); |
923 | } |
924 | + |
925 | int dbLoadDatabase(const char *file, const char *path, const char *subs) |
926 | { |
927 | if (!file) { |
928 | @@ -767,7 +782,7 @@ int dbLoadDatabase(const char *file, const char *path, const char *subs) |
929 | return dbReadDatabase(&pdbbase, file, path, subs); |
930 | } |
931 | |
932 | -int dbLoadRecords(const char* file, const char* subs) |
933 | +int dbLoadRecords(const char *file, const char *subs) |
934 | { |
935 | int status; |
936 | |
937 | @@ -781,7 +796,6 @@ int dbLoadRecords(const char* file, const char* subs) |
938 | return status; |
939 | } |
940 | |
941 | - |
942 | static long getLinkValue(DBADDR *paddr, short dbrType, |
943 | char *pbuf, long *nRequest) |
944 | { |
945 | @@ -797,7 +811,7 @@ static long getLinkValue(DBADDR *paddr, short dbrType, |
946 | * valid DBADDR, so no point to check again. |
947 | * Request for zero elements always succeeds |
948 | */ |
949 | - if(!nReq) |
950 | + if (!nReq) |
951 | return 0; |
952 | |
953 | switch (dbrType) { |
954 | @@ -806,8 +820,9 @@ static long getLinkValue(DBADDR *paddr, short dbrType, |
955 | nReq = 1; |
956 | break; |
957 | |
958 | - case DBR_DOUBLE: /* Needed for dbCa links */ |
959 | - if (nRequest) *nRequest = 1; |
960 | + case DBR_DOUBLE: /* Needed for dbCa links */ |
961 | + if (nRequest) |
962 | + *nRequest = 1; |
963 | *(double *)pbuf = epicsNAN; |
964 | return 0; |
965 | |
966 | @@ -821,27 +836,30 @@ static long getLinkValue(DBADDR *paddr, short dbrType, |
967 | |
968 | dbInitEntry(pdbbase, &dbEntry); |
969 | status = dbFindRecord(&dbEntry, precord->name); |
970 | - if (!status) status = dbFindField(&dbEntry, pfldDes->name); |
971 | + if (!status) |
972 | + status = dbFindField(&dbEntry, pfldDes->name); |
973 | if (!status) { |
974 | const char *rtnString = dbGetString(&dbEntry); |
975 | |
976 | - strncpy(pbuf, rtnString, maxlen-1); |
977 | - pbuf[maxlen-1] = 0; |
978 | - if(dbrType!=DBR_STRING) |
979 | - nReq = strlen(pbuf)+1; |
980 | - if(nRequest) *nRequest = nReq; |
981 | + strncpy(pbuf, rtnString, maxlen - 1); |
982 | + pbuf[maxlen - 1] = 0; |
983 | + if (dbrType != DBR_STRING) |
984 | + nReq = strlen(pbuf) + 1; |
985 | + if (nRequest) |
986 | + *nRequest = nReq; |
987 | } |
988 | dbFinishEntry(&dbEntry); |
989 | return status; |
990 | } |
991 | |
992 | static long getAttrValue(DBADDR *paddr, short dbrType, |
993 | - char *pbuf, long *nRequest) |
994 | + char *pbuf, long *nRequest) |
995 | { |
996 | int maxlen; |
997 | long nReq = nRequest ? *nRequest : 1; |
998 | |
999 | - if (!paddr->pfield) return S_db_badField; |
1000 | + if (!paddr->pfield) |
1001 | + return S_db_badField; |
1002 | |
1003 | switch (dbrType) { |
1004 | case DBR_STRING: |
1005 | @@ -859,22 +877,23 @@ static long getAttrValue(DBADDR *paddr, short dbrType, |
1006 | return S_db_badDbrtype; |
1007 | } |
1008 | |
1009 | - strncpy(pbuf, paddr->pfield, maxlen-1); |
1010 | - pbuf[maxlen-1] = 0; |
1011 | - if(dbrType!=DBR_STRING) |
1012 | - nReq = strlen(pbuf)+1; |
1013 | - if(nRequest) *nRequest = nReq; |
1014 | + strncpy(pbuf, paddr->pfield, maxlen - 1); |
1015 | + pbuf[maxlen - 1] = 0; |
1016 | + if (dbrType != DBR_STRING) |
1017 | + nReq = strlen(pbuf) + 1; |
1018 | + if (nRequest) |
1019 | + *nRequest = nReq; |
1020 | return 0; |
1021 | } |
1022 | |
1023 | -long dbGetField(DBADDR *paddr,short dbrType, |
1024 | - void *pbuffer, long *options, long *nRequest, void *pflin) |
1025 | +long dbGetField(DBADDR *paddr, short dbrType, |
1026 | + void *pbuffer, long *options, long *nRequest) |
1027 | { |
1028 | dbCommon *precord = paddr->precord; |
1029 | long status = 0; |
1030 | |
1031 | dbScanLock(precord); |
1032 | - status = dbGet(paddr, dbrType, pbuffer, options, nRequest, pflin); |
1033 | + status = dbGet(paddr, dbrType, pbuffer, options, nRequest, NULL); |
1034 | dbScanUnlock(precord); |
1035 | return status; |
1036 | } |
1037 | @@ -884,7 +903,7 @@ long dbGet(DBADDR *paddr, short dbrType, |
1038 | { |
1039 | char *pbuf = pbuffer; |
1040 | void *pfieldsave = paddr->pfield; |
1041 | - db_field_log *pfl = (db_field_log *)pflin; |
1042 | + db_field_log *pfl = (db_field_log *) pflin; |
1043 | short field_type; |
1044 | long capacity, no_elements, offset; |
1045 | rset *prset; |
1046 | @@ -895,7 +914,7 @@ long dbGet(DBADDR *paddr, short dbrType, |
1047 | if (nRequest && *nRequest == 0) |
1048 | return 0; |
1049 | |
1050 | - if (!pfl || pfl->type == dbfl_type_rec) { |
1051 | + if (!pfl) { |
1052 | field_type = paddr->field_type; |
1053 | no_elements = capacity = paddr->no_elements; |
1054 | |
1055 | @@ -903,15 +922,14 @@ long dbGet(DBADDR *paddr, short dbrType, |
1056 | * may modify paddr->pfield |
1057 | */ |
1058 | if (paddr->pfldDes->special == SPC_DBADDR && |
1059 | - (prset = dbGetRset(paddr)) && |
1060 | - prset->get_array_info) { |
1061 | + (prset = dbGetRset(paddr)) && prset->get_array_info) { |
1062 | status = prset->get_array_info(paddr, &no_elements, &offset); |
1063 | } else |
1064 | offset = 0; |
1065 | } else { |
1066 | field_type = pfl->field_type; |
1067 | no_elements = capacity = pfl->no_elements; |
1068 | - offset = 0; |
1069 | + offset = pfl->offset; |
1070 | } |
1071 | |
1072 | if (field_type >= DBF_INLINK && field_type <= DBF_FWDLINK) { |
1073 | @@ -937,19 +955,25 @@ long dbGet(DBADDR *paddr, short dbrType, |
1074 | if (offset == 0 && (!nRequest || no_elements == 1)) { |
1075 | if (nRequest) |
1076 | *nRequest = 1; |
1077 | - if (!pfl || pfl->type == dbfl_type_rec) { |
1078 | + if (!pfl) { |
1079 | status = dbFastGetConvertRoutine[field_type][dbrType] |
1080 | (paddr->pfield, pbuf, paddr); |
1081 | } else { |
1082 | - DBADDR localAddr = *paddr; /* Structure copy */ |
1083 | + DBADDR localAddr = *paddr; /* Structure copy */ |
1084 | + |
1085 | + if (pfl->no_elements < 1) { |
1086 | + status = S_db_badField; |
1087 | + goto done; |
1088 | + } |
1089 | |
1090 | localAddr.field_type = pfl->field_type; |
1091 | localAddr.field_size = pfl->field_size; |
1092 | + /* not used by dbFastConvert: */ |
1093 | localAddr.no_elements = pfl->no_elements; |
1094 | if (pfl->type == dbfl_type_val) |
1095 | - localAddr.pfield = (char *) &pfl->u.v.field; |
1096 | + localAddr.pfield = (char *)&pfl->u.v.field; |
1097 | else |
1098 | - localAddr.pfield = (char *) pfl->u.r.field; |
1099 | + localAddr.pfield = (char *)pfl->u.r.field; |
1100 | status = dbFastGetConvertRoutine[field_type][dbrType] |
1101 | (localAddr.pfield, pbuf, &localAddr); |
1102 | } |
1103 | @@ -969,52 +993,55 @@ long dbGet(DBADDR *paddr, short dbrType, |
1104 | char message[80]; |
1105 | |
1106 | sprintf(message, "dbGet: Missing conversion for [%d][%d]\n", |
1107 | - field_type, dbrType); |
1108 | + field_type, dbrType); |
1109 | recGblDbaddrError(S_db_badDbrtype, paddr, message); |
1110 | status = S_db_badDbrtype; |
1111 | goto done; |
1112 | } |
1113 | /* convert data into the caller's buffer */ |
1114 | if (n <= 0) { |
1115 | - ;/*do nothing*/ |
1116 | - } else if (!pfl || pfl->type == dbfl_type_rec) { |
1117 | + ; /*do nothing */ |
1118 | + } else if (!pfl) { |
1119 | status = convert(paddr, pbuf, n, capacity, offset); |
1120 | } else { |
1121 | - DBADDR localAddr = *paddr; /* Structure copy */ |
1122 | + DBADDR localAddr = *paddr; /* Structure copy */ |
1123 | |
1124 | localAddr.field_type = pfl->field_type; |
1125 | localAddr.field_size = pfl->field_size; |
1126 | + /* not used by dbConvert, it uses the passed capacity instead: */ |
1127 | localAddr.no_elements = pfl->no_elements; |
1128 | if (pfl->type == dbfl_type_val) |
1129 | - localAddr.pfield = (char *) &pfl->u.v.field; |
1130 | + localAddr.pfield = (char *)&pfl->u.v.field; |
1131 | else |
1132 | - localAddr.pfield = (char *) pfl->u.r.field; |
1133 | + localAddr.pfield = (char *)pfl->u.r.field; |
1134 | status = convert(&localAddr, pbuf, n, capacity, offset); |
1135 | } |
1136 | |
1137 | - if(!status && dbrType==DBF_CHAR && nRequest && |
1138 | - paddr->pfldDes && paddr->pfldDes->field_type==DBF_STRING) |
1139 | - { |
1140 | + if (!status && dbrType == DBF_CHAR && nRequest && |
1141 | + paddr->pfldDes && paddr->pfldDes->field_type == DBF_STRING) { |
1142 | /* long string ensure nil and truncate to actual length */ |
1143 | long nReq = *nRequest; |
1144 | - pbuf[nReq-1] = '\0'; |
1145 | - *nRequest = strlen(pbuf)+1; |
1146 | + pbuf[nReq - 1] = '\0'; |
1147 | + *nRequest = strlen(pbuf) + 1; |
1148 | } |
1149 | } |
1150 | -done: |
1151 | + done: |
1152 | paddr->pfield = pfieldsave; |
1153 | return status; |
1154 | } |
1155 | |
1156 | -devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp) { |
1157 | - return (devSup *)ellNth(&prdes->devList, dtyp+1); |
1158 | +devSup *dbDTYPtoDevSup(dbRecordType * prdes, int dtyp) |
1159 | +{ |
1160 | + return (devSup *) ellNth(&prdes->devList, dtyp + 1); |
1161 | } |
1162 | |
1163 | -devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) { |
1164 | - devSup *pdevSup = (devSup *)ellFirst(&prdes->devList); |
1165 | +devSup *dbDSETtoDevSup(dbRecordType * prdes, dset * pdset) |
1166 | +{ |
1167 | + devSup *pdevSup = (devSup *) ellFirst(&prdes->devList); |
1168 | while (pdevSup) { |
1169 | - if (pdset == pdevSup->pdset) return pdevSup; |
1170 | - pdevSup = (devSup *)ellNext(&pdevSup->node); |
1171 | + if (pdset == pdevSup->pdset) |
1172 | + return pdevSup; |
1173 | + pdevSup = (devSup *) ellNext(&pdevSup->node); |
1174 | } |
1175 | return NULL; |
1176 | } |
1177 | @@ -1022,24 +1049,24 @@ devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset) { |
1178 | static long dbPutFieldLink(DBADDR *paddr, |
1179 | short dbrType, const void *pbuffer, long nRequest) |
1180 | { |
1181 | - dbLinkInfo link_info; |
1182 | - DBADDR *pdbaddr = NULL; |
1183 | - dbCommon *precord = paddr->precord; |
1184 | - dbCommon *lockrecs[2]; |
1185 | - dbLocker locker; |
1186 | - dbFldDes *pfldDes = paddr->pfldDes; |
1187 | - long special = paddr->special; |
1188 | + dbLinkInfo link_info; |
1189 | + dbChannel *chan = NULL; |
1190 | + dbCommon *precord = paddr->precord; |
1191 | + dbCommon *lockrecs[2]; |
1192 | + dbLocker locker; |
1193 | + dbFldDes *pfldDes = paddr->pfldDes; |
1194 | + long special = paddr->special; |
1195 | struct link *plink = (struct link *)paddr->pfield; |
1196 | - const char *pstring = (const char *)pbuffer; |
1197 | + const char *pstring = (const char *)pbuffer; |
1198 | struct dsxt *old_dsxt = NULL; |
1199 | dset *new_dset = NULL; |
1200 | struct dsxt *new_dsxt = NULL; |
1201 | - devSup *new_devsup = NULL; |
1202 | - long status; |
1203 | - int isDevLink; |
1204 | - short scan; |
1205 | + devSup *new_devsup = NULL; |
1206 | + long status; |
1207 | + int isDevLink; |
1208 | + short scan; |
1209 | |
1210 | - STATIC_ASSERT(DBLOCKER_NALLOC>=2); |
1211 | + STATIC_ASSERT(DBLOCKER_NALLOC >= 2); |
1212 | |
1213 | switch (dbrType) { |
1214 | case DBR_CHAR: |
1215 | @@ -1061,25 +1088,20 @@ static long dbPutFieldLink(DBADDR *paddr, |
1216 | |
1217 | if (link_info.ltype == PV_LINK && |
1218 | (link_info.modifiers & (pvlOptCA | pvlOptCP | pvlOptCPP)) == 0) { |
1219 | - DBADDR tempaddr; |
1220 | - |
1221 | - if (dbNameToAddr(link_info.target, &tempaddr)==0) { |
1222 | - /* This will become a DB link. */ |
1223 | - pdbaddr = malloc(sizeof(*pdbaddr)); |
1224 | - if (!pdbaddr) { |
1225 | - status = S_db_noMemory; |
1226 | - goto cleanup; |
1227 | - } |
1228 | - *pdbaddr = tempaddr; /* struct copy */ |
1229 | + chan = dbChannelCreate(link_info.target); |
1230 | + if (chan && dbChannelOpen(chan) != 0) { |
1231 | + errlogPrintf |
1232 | + ("ERROR: dbPutFieldLink %s.%s=%s: dbChannelOpen() failed\n", |
1233 | + precord->name, pfldDes->name, link_info.target); |
1234 | + goto cleanup; |
1235 | } |
1236 | } |
1237 | |
1238 | - isDevLink = ellCount(&precord->rdes->devList) > 0 && |
1239 | - pfldDes->isDevLink; |
1240 | + isDevLink = ellCount(&precord->rdes->devList) > 0 && pfldDes->isDevLink; |
1241 | |
1242 | memset(&locker, 0, sizeof(locker)); |
1243 | lockrecs[0] = precord; |
1244 | - lockrecs[1] = pdbaddr ? pdbaddr->precord : NULL; |
1245 | + lockrecs[1] = chan ? dbChannelRecord(chan) : NULL; |
1246 | dbLockerPrepare(&locker, lockrecs, 2); |
1247 | |
1248 | dbScanLockMany(&locker); |
1249 | @@ -1130,17 +1152,19 @@ static long dbPutFieldLink(DBADDR *paddr, |
1250 | |
1251 | if (dbLinkIsDefined(plink)) { |
1252 | dbRemoveLink(&locker, plink); /* Clear out old link */ |
1253 | - } |
1254 | - else if (!isDevLink) { |
1255 | + } else if (!isDevLink) { |
1256 | status = S_db_badHWaddr; |
1257 | goto restoreScan; |
1258 | } |
1259 | |
1260 | - if (special) status = dbPutSpecial(paddr, 0); |
1261 | + if (special) |
1262 | + status = dbPutSpecial(paddr, 0); |
1263 | |
1264 | - if (!status) status = dbSetLink(plink, &link_info, new_devsup); |
1265 | + if (!status) |
1266 | + status = dbSetLink(plink, &link_info, new_devsup); |
1267 | |
1268 | - if (!status && special) status = dbPutSpecial(paddr, 1); |
1269 | + if (!status && special) |
1270 | + status = dbPutSpecial(paddr, 1); |
1271 | |
1272 | if (status) { |
1273 | if (isDevLink) { |
1274 | @@ -1163,19 +1187,20 @@ static long dbPutFieldLink(DBADDR *paddr, |
1275 | } |
1276 | } |
1277 | |
1278 | - switch (plink->type) { /* New link type */ |
1279 | + switch (plink->type) { /* New link type */ |
1280 | case PV_LINK: |
1281 | case CONSTANT: |
1282 | case JSON_LINK: |
1283 | - dbAddLink(&locker, plink, pfldDes->field_type, pdbaddr); |
1284 | + dbAddLink(&locker, plink, pfldDes->field_type, chan); |
1285 | + chan = NULL; /* don't clean it up */ |
1286 | break; |
1287 | |
1288 | case DB_LINK: |
1289 | case CA_LINK: |
1290 | case MACRO_LINK: |
1291 | - break; /* should never get here */ |
1292 | + break; /* should never get here */ |
1293 | |
1294 | - default: /* Hardware address */ |
1295 | + default: /* Hardware address */ |
1296 | if (!isDevLink) { |
1297 | status = S_db_badHWaddr; |
1298 | goto postScanEvent; |
1299 | @@ -1184,19 +1209,20 @@ static long dbPutFieldLink(DBADDR *paddr, |
1300 | } |
1301 | db_post_events(precord, plink, DBE_VALUE | DBE_LOG); |
1302 | |
1303 | -restoreScan: |
1304 | - if (isDevLink && |
1305 | - scan == menuScanI_O_Intr) { /* undo scanDelete() */ |
1306 | + restoreScan: |
1307 | + if (isDevLink && scan == menuScanI_O_Intr) { /* undo scanDelete() */ |
1308 | precord->scan = scan; |
1309 | scanAdd(precord); |
1310 | } |
1311 | -postScanEvent: |
1312 | + postScanEvent: |
1313 | if (scan != precord->scan) |
1314 | db_post_events(precord, &precord->scan, DBE_VALUE | DBE_LOG); |
1315 | -unlock: |
1316 | + unlock: |
1317 | dbScanUnlockMany(&locker); |
1318 | dbLockerFinalize(&locker); |
1319 | -cleanup: |
1320 | + cleanup: |
1321 | + if (chan) |
1322 | + dbChannelDelete(chan); |
1323 | free(link_info.target); |
1324 | return status; |
1325 | } |
1326 | @@ -1204,16 +1230,16 @@ cleanup: |
1327 | long dbPutField(DBADDR *paddr, short dbrType, |
1328 | const void *pbuffer, long nRequest) |
1329 | { |
1330 | - long status = 0; |
1331 | - long special = paddr->special; |
1332 | - dbFldDes *pfldDes = paddr->pfldDes; |
1333 | - dbCommon *precord = paddr->precord; |
1334 | - short dbfType = paddr->field_type; |
1335 | + long status = 0; |
1336 | + long special = paddr->special; |
1337 | + dbFldDes *pfldDes = paddr->pfldDes; |
1338 | + dbCommon *precord = paddr->precord; |
1339 | + short dbfType = paddr->field_type; |
1340 | |
1341 | if (special == SPC_ATTRIBUTE) |
1342 | return S_db_noMod; |
1343 | |
1344 | - /*check for putField disabled*/ |
1345 | + /*check for putField disabled */ |
1346 | if (precord->disp && paddr->pfield != &precord->disp) |
1347 | return S_db_putDisabled; |
1348 | |
1349 | @@ -1225,8 +1251,7 @@ long dbPutField(DBADDR *paddr, short dbrType, |
1350 | if (status == 0) { |
1351 | if (paddr->pfield == &precord->proc || |
1352 | (pfldDes->process_passive && |
1353 | - precord->scan == 0 && |
1354 | - dbrType < DBR_PUT_ACKT)) { |
1355 | + precord->scan == 0 && dbrType < DBR_PUT_ACKT)) { |
1356 | if (precord->pact) { |
1357 | if (dbAccessDebugPUTF && precord->tpro) |
1358 | printf("%s: dbPutField to Active '%s', setting RPRO=1\n", |
1359 | @@ -1249,11 +1274,11 @@ static long putAckt(DBADDR *paddr, const void *pbuffer, long nRequest, |
1360 | dbCommon *precord = paddr->precord; |
1361 | const unsigned short *ptrans = pbuffer; |
1362 | |
1363 | - if (*ptrans == precord->ackt) return 0; |
1364 | + if (*ptrans == precord->ackt) |
1365 | + return 0; |
1366 | precord->ackt = *ptrans; |
1367 | db_post_events(precord, &precord->ackt, DBE_VALUE | DBE_ALARM); |
1368 | - if (!precord->ackt && |
1369 | - precord->acks > precord->sevr) { |
1370 | + if (!precord->ackt && precord->acks > precord->sevr) { |
1371 | precord->acks = precord->sevr; |
1372 | db_post_events(precord, &precord->acks, DBE_VALUE | DBE_ALARM); |
1373 | } |
1374 | @@ -1275,14 +1300,13 @@ static long putAcks(DBADDR *paddr, const void *pbuffer, long nRequest, |
1375 | return 0; |
1376 | } |
1377 | |
1378 | -long dbPut(DBADDR *paddr, short dbrType, |
1379 | - const void *pbuffer, long nRequest) |
1380 | +long dbPut(DBADDR *paddr, short dbrType, const void *pbuffer, long nRequest) |
1381 | { |
1382 | dbCommon *precord = paddr->precord; |
1383 | - short field_type = paddr->field_type; |
1384 | - long no_elements = paddr->no_elements; |
1385 | - long special = paddr->special; |
1386 | - void *pfieldsave = paddr->pfield; |
1387 | + short field_type = paddr->field_type; |
1388 | + long no_elements = paddr->no_elements; |
1389 | + long special = paddr->special; |
1390 | + void *pfieldsave = paddr->pfield; |
1391 | rset *prset = dbGetRset(paddr); |
1392 | long status = 0; |
1393 | long offset; |
1394 | @@ -1306,7 +1330,8 @@ long dbPut(DBADDR *paddr, short dbrType, |
1395 | |
1396 | if (special) { |
1397 | status = dbPutSpecial(paddr, 0); |
1398 | - if (status) return status; |
1399 | + if (status) |
1400 | + return status; |
1401 | } |
1402 | |
1403 | if (paddr->pfldDes->special == SPC_DBADDR && |
1404 | @@ -1315,18 +1340,19 @@ long dbPut(DBADDR *paddr, short dbrType, |
1405 | |
1406 | status = prset->get_array_info(paddr, &dummy, &offset); |
1407 | /* paddr->pfield may be modified */ |
1408 | - if (status) goto done; |
1409 | + if (status) |
1410 | + goto done; |
1411 | } else |
1412 | offset = 0; |
1413 | |
1414 | if (no_elements <= 1) { |
1415 | - status = dbFastPutConvertRoutine[dbrType][field_type](pbuffer, |
1416 | + status = dbFastPutConvertRoutine[dbrType][field_type] (pbuffer, |
1417 | paddr->pfield, paddr); |
1418 | nRequest = 1; |
1419 | } else { |
1420 | if (no_elements < nRequest) |
1421 | nRequest = no_elements; |
1422 | - status = dbPutConvertRoutine[dbrType][field_type](paddr, pbuffer, |
1423 | + status = dbPutConvertRoutine[dbrType][field_type] (paddr, pbuffer, |
1424 | nRequest, no_elements, offset); |
1425 | } |
1426 | |
1427 | @@ -1340,17 +1366,19 @@ long dbPut(DBADDR *paddr, short dbrType, |
1428 | /* Always do special processing if needed */ |
1429 | if (special) { |
1430 | long status2 = dbPutSpecial(paddr, 1); |
1431 | - if (status2) goto done; |
1432 | + if (status2) |
1433 | + goto done; |
1434 | } |
1435 | - if (status) goto done; |
1436 | + if (status) |
1437 | + goto done; |
1438 | |
1439 | /* Propagate monitor events for this field, */ |
1440 | /* unless the field is VAL and PP is true. */ |
1441 | pfldDes = paddr->pfldDes; |
1442 | isValueField = dbIsValueField(pfldDes); |
1443 | - if (isValueField) precord->udf = FALSE; |
1444 | - if (precord->mlis.count && |
1445 | - !(isValueField && pfldDes->process_passive)) |
1446 | + if (isValueField) |
1447 | + precord->udf = FALSE; |
1448 | + if (precord->mlis.count && !(isValueField && pfldDes->process_passive)) |
1449 | db_post_events(precord, pfieldsave, DBE_VALUE | DBE_LOG); |
1450 | /* If this field is a property (metadata) field, |
1451 | * then post a property change event (even if the field |
1452 | @@ -1358,7 +1386,7 @@ long dbPut(DBADDR *paddr, short dbrType, |
1453 | */ |
1454 | if (precord->mlis.count && pfldDes->prop) |
1455 | db_post_events(precord, NULL, DBE_PROPERTY); |
1456 | -done: |
1457 | + done: |
1458 | paddr->pfield = pfieldsave; |
1459 | return status; |
1460 | } |
1461 | diff --git a/modules/database/src/ioc/db/dbAccessDefs.h b/modules/database/src/ioc/db/dbAccessDefs.h |
1462 | index 805dfd4..4a95989 100644 |
1463 | --- a/modules/database/src/ioc/db/dbAccessDefs.h |
1464 | +++ b/modules/database/src/ioc/db/dbAccessDefs.h |
1465 | @@ -243,7 +243,7 @@ epicsShareFunc devSup* dbDTYPtoDevSup(dbRecordType *prdes, int dtyp); |
1466 | epicsShareFunc devSup* dbDSETtoDevSup(dbRecordType *prdes, dset *pdset); |
1467 | epicsShareFunc long dbGetField( |
1468 | struct dbAddr *,short dbrType,void *pbuffer,long *options, |
1469 | - long *nRequest,void *pfl); |
1470 | + long *nRequest); |
1471 | epicsShareFunc long dbGet( |
1472 | struct dbAddr *,short dbrType,void *pbuffer,long *options, |
1473 | long *nRequest,void *pfl); |
1474 | diff --git a/modules/database/src/ioc/db/dbChannel.c b/modules/database/src/ioc/db/dbChannel.c |
1475 | index bc3c8e4..e361f3b 100644 |
1476 | --- a/modules/database/src/ioc/db/dbChannel.c |
1477 | +++ b/modules/database/src/ioc/db/dbChannel.c |
1478 | @@ -49,14 +49,12 @@ typedef struct parseContext { |
1479 | |
1480 | static void *dbChannelFreeList; |
1481 | static void *chFilterFreeList; |
1482 | -static void *dbchStringFreeList; |
1483 | |
1484 | void dbChannelExit(void) |
1485 | { |
1486 | freeListCleanup(dbChannelFreeList); |
1487 | freeListCleanup(chFilterFreeList); |
1488 | - freeListCleanup(dbchStringFreeList); |
1489 | - dbChannelFreeList = chFilterFreeList = dbchStringFreeList = NULL; |
1490 | + dbChannelFreeList = chFilterFreeList = NULL; |
1491 | } |
1492 | |
1493 | void dbChannelInit (void) |
1494 | @@ -66,7 +64,7 @@ void dbChannelInit (void) |
1495 | |
1496 | freeListInitPvt(&dbChannelFreeList, sizeof(dbChannel), 128); |
1497 | freeListInitPvt(&chFilterFreeList, sizeof(chFilter), 64); |
1498 | - freeListInitPvt(&dbchStringFreeList, sizeof(epicsOldString), 128); |
1499 | + db_init_event_freelists(); |
1500 | } |
1501 | |
1502 | static void chf_value(parseContext *parser, parse_result *presult) |
1503 | @@ -445,28 +443,6 @@ static long parseArrayRange(dbChannel* chan, const char *pname, const char **ppn |
1504 | return status; |
1505 | } |
1506 | |
1507 | -/* Stolen from dbAccess.c: */ |
1508 | -static short mapDBFToDBR[DBF_NTYPES] = |
1509 | - { |
1510 | - /* DBF_STRING => */DBR_STRING, |
1511 | - /* DBF_CHAR => */DBR_CHAR, |
1512 | - /* DBF_UCHAR => */DBR_UCHAR, |
1513 | - /* DBF_SHORT => */DBR_SHORT, |
1514 | - /* DBF_USHORT => */DBR_USHORT, |
1515 | - /* DBF_LONG => */DBR_LONG, |
1516 | - /* DBF_ULONG => */DBR_ULONG, |
1517 | - /* DBF_INT64 => */DBR_INT64, |
1518 | - /* DBF_UINT64 => */DBR_UINT64, |
1519 | - /* DBF_FLOAT => */DBR_FLOAT, |
1520 | - /* DBF_DOUBLE => */DBR_DOUBLE, |
1521 | - /* DBF_ENUM, => */DBR_ENUM, |
1522 | - /* DBF_MENU, => */DBR_ENUM, |
1523 | - /* DBF_DEVICE => */DBR_ENUM, |
1524 | - /* DBF_INLINK => */DBR_STRING, |
1525 | - /* DBF_OUTLINK => */DBR_STRING, |
1526 | - /* DBF_FWDLINK => */DBR_STRING, |
1527 | - /* DBF_NOACCESS => */DBR_NOACCESS }; |
1528 | - |
1529 | dbChannel * dbChannelCreate(const char *name) |
1530 | { |
1531 | const char *pname = name; |
1532 | @@ -735,39 +711,6 @@ void dbChannelDelete(dbChannel *chan) |
1533 | freeListFree(dbChannelFreeList, chan); |
1534 | } |
1535 | |
1536 | -static void freeArray(db_field_log *pfl) { |
1537 | - if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) { |
1538 | - freeListFree(dbchStringFreeList, pfl->u.r.field); |
1539 | - } else { |
1540 | - free(pfl->u.r.field); |
1541 | - } |
1542 | -} |
1543 | - |
1544 | -void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan) |
1545 | -{ |
1546 | - void *p; |
1547 | - struct dbCommon *prec = dbChannelRecord(chan); |
1548 | - |
1549 | - if (pfl->type != dbfl_type_rec) return; |
1550 | - |
1551 | - pfl->type = dbfl_type_ref; |
1552 | - pfl->stat = prec->stat; |
1553 | - pfl->sevr = prec->sevr; |
1554 | - pfl->time = prec->time; |
1555 | - pfl->field_type = chan->addr.field_type; |
1556 | - pfl->no_elements = chan->addr.no_elements; |
1557 | - pfl->field_size = chan->addr.field_size; |
1558 | - pfl->u.r.dtor = freeArray; |
1559 | - pfl->u.r.pvt = pvt; |
1560 | - if (pfl->field_type == DBF_STRING && pfl->no_elements == 1) { |
1561 | - p = freeListCalloc(dbchStringFreeList); |
1562 | - } else { |
1563 | - p = calloc(pfl->no_elements, pfl->field_size); |
1564 | - } |
1565 | - if (p) dbGet(&chan->addr, mapDBFToDBR[pfl->field_type], p, NULL, &pfl->no_elements, NULL); |
1566 | - pfl->u.r.field = p; |
1567 | -} |
1568 | - |
1569 | /* FIXME: Do these belong in a different file? */ |
1570 | |
1571 | void dbRegisterFilter(const char *name, const chFilterIf *fif, void *puser) |
1572 | diff --git a/modules/database/src/ioc/db/dbChannel.h b/modules/database/src/ioc/db/dbChannel.h |
1573 | index fab9c66..6e98dee 100644 |
1574 | --- a/modules/database/src/ioc/db/dbChannel.h |
1575 | +++ b/modules/database/src/ioc/db/dbChannel.h |
1576 | @@ -64,8 +64,9 @@ typedef struct dbChannel { |
1577 | /* Prototype for the channel event function that is called in filter stacks |
1578 | * |
1579 | * When invoked the scan lock for the record associated with 'chan' _may_ be locked. |
1580 | - * If pLog->type==dbfl_type_rec then dbScanLock() must be called before copying |
1581 | - * data out of the associated record. |
1582 | + * If pLog->type==dbfl_type_ref and pLog->u.r.dtor is NULL, then dbScanLock() must |
1583 | + * be called before accessing the data, as this indicates the data is owned by the |
1584 | + * record. |
1585 | * |
1586 | * This function has ownership of the field log pLog, if it wishes to discard |
1587 | * this update it should free the field log with db_delete_field_log() and |
1588 | @@ -224,7 +225,6 @@ epicsShareFunc void dbRegisterFilter(const char *key, const chFilterIf *fif, voi |
1589 | epicsShareFunc db_field_log* dbChannelRunPreChain(dbChannel *chan, db_field_log *pLogIn); |
1590 | epicsShareFunc db_field_log* dbChannelRunPostChain(dbChannel *chan, db_field_log *pLogIn); |
1591 | epicsShareFunc const chFilterPlugin * dbFindFilter(const char *key, size_t len); |
1592 | -epicsShareFunc void dbChannelMakeArrayCopy(void *pvt, db_field_log *pfl, dbChannel *chan); |
1593 | |
1594 | #ifdef __cplusplus |
1595 | } |
1596 | diff --git a/modules/database/src/ioc/db/dbDbLink.c b/modules/database/src/ioc/db/dbDbLink.c |
1597 | index f2cb0c5..8677add 100644 |
1598 | --- a/modules/database/src/ioc/db/dbDbLink.c |
1599 | +++ b/modules/database/src/ioc/db/dbDbLink.c |
1600 | @@ -60,6 +60,7 @@ |
1601 | #include "dbConvertFast.h" |
1602 | #include "dbConvert.h" |
1603 | #include "db_field_log.h" |
1604 | +#include "db_access_routines.h" |
1605 | #include "dbFldTypes.h" |
1606 | #include "dbLink.h" |
1607 | #include "dbLockPvt.h" |
1608 | @@ -73,7 +74,7 @@ |
1609 | #include "recSup.h" |
1610 | #include "special.h" |
1611 | #include "dbDbLink.h" |
1612 | - |
1613 | +#include "dbChannel.h" |
1614 | |
1615 | /***************************** Database Links *****************************/ |
1616 | |
1617 | @@ -82,45 +83,51 @@ static lset dbDb_lset; |
1618 | |
1619 | static long processTarget(dbCommon *psrc, dbCommon *pdst); |
1620 | |
1621 | +#define linkChannel(plink) ((dbChannel *) (plink)->value.pv_link.pvt) |
1622 | + |
1623 | long dbDbInitLink(struct link *plink, short dbfType) |
1624 | { |
1625 | - DBADDR dbaddr; |
1626 | long status; |
1627 | - DBADDR *pdbAddr; |
1628 | + dbChannel *chan; |
1629 | + dbCommon *precord; |
1630 | |
1631 | - status = dbNameToAddr(plink->value.pv_link.pvname, &dbaddr); |
1632 | + chan = dbChannelCreate(plink->value.pv_link.pvname); |
1633 | + if (!chan) |
1634 | + return S_db_notFound; |
1635 | + status = dbChannelOpen(chan); |
1636 | if (status) |
1637 | return status; |
1638 | |
1639 | + precord = dbChannelRecord(chan); |
1640 | + |
1641 | plink->lset = &dbDb_lset; |
1642 | plink->type = DB_LINK; |
1643 | - pdbAddr = dbCalloc(1, sizeof(struct dbAddr)); |
1644 | - *pdbAddr = dbaddr; /* structure copy */ |
1645 | - plink->value.pv_link.pvt = pdbAddr; |
1646 | - ellAdd(&dbaddr.precord->bklnk, &plink->value.pv_link.backlinknode); |
1647 | + plink->value.pv_link.pvt = chan; |
1648 | + ellAdd(&precord->bklnk, &plink->value.pv_link.backlinknode); |
1649 | /* merging into the same lockset is deferred to the caller. |
1650 | * cf. initPVLinks() |
1651 | */ |
1652 | - dbLockSetMerge(NULL, plink->precord, dbaddr.precord); |
1653 | - assert(plink->precord->lset->plockSet == dbaddr.precord->lset->plockSet); |
1654 | + dbLockSetMerge(NULL, plink->precord, precord); |
1655 | + assert(plink->precord->lset->plockSet == precord->lset->plockSet); |
1656 | return 0; |
1657 | } |
1658 | |
1659 | void dbDbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, |
1660 | - DBADDR *ptarget) |
1661 | + dbChannel *chan) |
1662 | { |
1663 | plink->lset = &dbDb_lset; |
1664 | plink->type = DB_LINK; |
1665 | - plink->value.pv_link.pvt = ptarget; |
1666 | - ellAdd(&ptarget->precord->bklnk, &plink->value.pv_link.backlinknode); |
1667 | + plink->value.pv_link.pvt = chan; |
1668 | + ellAdd(&dbChannelRecord(chan)->bklnk, &plink->value.pv_link.backlinknode); |
1669 | |
1670 | /* target record is already locked in dbPutFieldLink() */ |
1671 | - dbLockSetMerge(locker, plink->precord, ptarget->precord); |
1672 | + dbLockSetMerge(locker, plink->precord, dbChannelRecord(chan)); |
1673 | } |
1674 | |
1675 | static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink) |
1676 | { |
1677 | - DBADDR *pdbAddr = (DBADDR *) plink->value.pv_link.pvt; |
1678 | + dbChannel *chan = linkChannel(plink); |
1679 | + dbCommon *precord = dbChannelRecord(chan); |
1680 | |
1681 | plink->type = PV_LINK; |
1682 | |
1683 | @@ -130,10 +137,10 @@ static void dbDbRemoveLink(struct dbLocker *locker, struct link *plink) |
1684 | plink->value.pv_link.getCvt = 0; |
1685 | plink->value.pv_link.pvlMask = 0; |
1686 | plink->value.pv_link.lastGetdbrType = 0; |
1687 | - ellDelete(&pdbAddr->precord->bklnk, &plink->value.pv_link.backlinknode); |
1688 | - dbLockSetSplit(locker, plink->precord, pdbAddr->precord); |
1689 | + ellDelete(&precord->bklnk, &plink->value.pv_link.backlinknode); |
1690 | + dbLockSetSplit(locker, plink->precord, precord); |
1691 | } |
1692 | - free(pdbAddr); |
1693 | + dbChannelDelete(chan); |
1694 | } |
1695 | |
1696 | static int dbDbIsConnected(const struct link *plink) |
1697 | @@ -143,16 +150,14 @@ static int dbDbIsConnected(const struct link *plink) |
1698 | |
1699 | static int dbDbGetDBFtype(const struct link *plink) |
1700 | { |
1701 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1702 | - |
1703 | - return paddr->field_type; |
1704 | + dbChannel *chan = linkChannel(plink); |
1705 | + return dbChannelFinalFieldType(chan); |
1706 | } |
1707 | |
1708 | static long dbDbGetElements(const struct link *plink, long *nelements) |
1709 | { |
1710 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1711 | - |
1712 | - *nelements = paddr->no_elements; |
1713 | + dbChannel *chan = linkChannel(plink); |
1714 | + *nelements = dbChannelFinalElements(chan); |
1715 | return 0; |
1716 | } |
1717 | |
1718 | @@ -160,30 +165,52 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, |
1719 | long *pnRequest) |
1720 | { |
1721 | struct pv_link *ppv_link = &plink->value.pv_link; |
1722 | - DBADDR *paddr = ppv_link->pvt; |
1723 | + dbChannel *chan = linkChannel(plink); |
1724 | + DBADDR *paddr = &chan->addr; |
1725 | dbCommon *precord = plink->precord; |
1726 | long status; |
1727 | |
1728 | /* scan passive records if link is process passive */ |
1729 | if (ppv_link->pvlMask & pvlOptPP) { |
1730 | - status = dbScanPassive(precord, paddr->precord); |
1731 | + status = dbScanPassive(precord, dbChannelRecord(chan)); |
1732 | if (status) |
1733 | return status; |
1734 | } |
1735 | |
1736 | - if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) { |
1737 | - status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); |
1738 | + /* If filters are involved in a read, create field log and run filters */ |
1739 | + if (ellCount(&chan->filters)) { |
1740 | + db_field_log *pfl; |
1741 | + |
1742 | + /* |
1743 | + * For the moment, empty arrays are not supported by EPICS. |
1744 | + * See the remark in src/std/filters/arr.c for details. |
1745 | + */ |
1746 | + if (dbChannelFinalElements(chan) <= 0) /* empty array request */ |
1747 | + return S_db_badField; |
1748 | + pfl = db_create_read_log(chan); |
1749 | + if (!pfl) |
1750 | + return S_db_noMemory; |
1751 | + pfl = dbChannelRunPreChain(chan, pfl); |
1752 | + pfl = dbChannelRunPostChain(chan, pfl); |
1753 | + status = dbChannelGet(chan, dbrType, pbuffer, NULL, pnRequest, pfl); |
1754 | + db_delete_field_log(pfl); |
1755 | + if (status) |
1756 | + return status; |
1757 | + if (pnRequest && *pnRequest <= 0) /* empty array result */ |
1758 | + return S_db_badField; |
1759 | + } else if (ppv_link->getCvt && ppv_link->lastGetdbrType == dbrType) { |
1760 | + status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr); |
1761 | } else { |
1762 | - unsigned short dbfType = paddr->field_type; |
1763 | + unsigned short dbfType = dbChannelFinalFieldType(chan); |
1764 | |
1765 | if (dbrType < 0 || dbrType > DBR_ENUM || dbfType > DBF_DEVICE) |
1766 | return S_db_badDbrtype; |
1767 | |
1768 | - if (paddr->no_elements == 1 && (!pnRequest || *pnRequest == 1) |
1769 | - && paddr->special != SPC_DBADDR |
1770 | - && paddr->special != SPC_ATTRIBUTE) { |
1771 | + if (dbChannelFinalElements(chan) == 1 && (!pnRequest || *pnRequest == 1) |
1772 | + && dbChannelSpecial(chan) != SPC_DBADDR |
1773 | + && dbChannelSpecial(chan) != SPC_ATTRIBUTE) { |
1774 | ppv_link->getCvt = dbFastGetConvertRoutine[dbfType][dbrType]; |
1775 | - status = ppv_link->getCvt(paddr->pfield, pbuffer, paddr); |
1776 | + status = ppv_link->getCvt(dbChannelField(chan), pbuffer, paddr); |
1777 | } else { |
1778 | ppv_link->getCvt = NULL; |
1779 | status = dbGet(paddr, dbrType, pbuffer, NULL, pnRequest, NULL); |
1780 | @@ -191,16 +218,18 @@ static long dbDbGetValue(struct link *plink, short dbrType, void *pbuffer, |
1781 | ppv_link->lastGetdbrType = dbrType; |
1782 | } |
1783 | |
1784 | - if (!status && precord != paddr->precord) |
1785 | + if (!status && precord != dbChannelRecord(chan)) |
1786 | recGblInheritSevr(plink->value.pv_link.pvlMask & pvlOptMsMode, |
1787 | - plink->precord, paddr->precord->stat, paddr->precord->sevr); |
1788 | + plink->precord, |
1789 | + dbChannelRecord(chan)->stat, dbChannelRecord(chan)->sevr); |
1790 | return status; |
1791 | } |
1792 | |
1793 | static long dbDbGetControlLimits(const struct link *plink, double *low, |
1794 | double *high) |
1795 | { |
1796 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1797 | + dbChannel *chan = linkChannel(plink); |
1798 | + DBADDR *paddr = &chan->addr; |
1799 | struct buffer { |
1800 | DBRctrlDouble |
1801 | double value; |
1802 | @@ -221,7 +250,8 @@ static long dbDbGetControlLimits(const struct link *plink, double *low, |
1803 | static long dbDbGetGraphicLimits(const struct link *plink, double *low, |
1804 | double *high) |
1805 | { |
1806 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1807 | + dbChannel *chan = linkChannel(plink); |
1808 | + DBADDR *paddr = &chan->addr; |
1809 | struct buffer { |
1810 | DBRgrDouble |
1811 | double value; |
1812 | @@ -242,7 +272,8 @@ static long dbDbGetGraphicLimits(const struct link *plink, double *low, |
1813 | static long dbDbGetAlarmLimits(const struct link *plink, double *lolo, |
1814 | double *low, double *high, double *hihi) |
1815 | { |
1816 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1817 | + dbChannel *chan = linkChannel(plink); |
1818 | + DBADDR *paddr = &chan->addr; |
1819 | struct buffer { |
1820 | DBRalDouble |
1821 | double value; |
1822 | @@ -264,7 +295,8 @@ static long dbDbGetAlarmLimits(const struct link *plink, double *lolo, |
1823 | |
1824 | static long dbDbGetPrecision(const struct link *plink, short *precision) |
1825 | { |
1826 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1827 | + dbChannel *chan = linkChannel(plink); |
1828 | + DBADDR *paddr = &chan->addr; |
1829 | struct buffer { |
1830 | DBRprecision |
1831 | double value; |
1832 | @@ -283,7 +315,8 @@ static long dbDbGetPrecision(const struct link *plink, short *precision) |
1833 | |
1834 | static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize) |
1835 | { |
1836 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1837 | + dbChannel *chan = linkChannel(plink); |
1838 | + DBADDR *paddr = &chan->addr; |
1839 | struct buffer { |
1840 | DBRunits |
1841 | double value; |
1842 | @@ -303,20 +336,20 @@ static long dbDbGetUnits(const struct link *plink, char *units, int unitsSize) |
1843 | static long dbDbGetAlarm(const struct link *plink, epicsEnum16 *status, |
1844 | epicsEnum16 *severity) |
1845 | { |
1846 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1847 | - |
1848 | + dbChannel *chan = linkChannel(plink); |
1849 | + dbCommon *precord = dbChannelRecord(chan); |
1850 | if (status) |
1851 | - *status = paddr->precord->stat; |
1852 | + *status = precord->stat; |
1853 | if (severity) |
1854 | - *severity = paddr->precord->sevr; |
1855 | + *severity = precord->sevr; |
1856 | return 0; |
1857 | } |
1858 | |
1859 | static long dbDbGetTimeStamp(const struct link *plink, epicsTimeStamp *pstamp) |
1860 | { |
1861 | - DBADDR *paddr = (DBADDR *) plink->value.pv_link.pvt; |
1862 | - |
1863 | - *pstamp = paddr->precord->time; |
1864 | + dbChannel *chan = linkChannel(plink); |
1865 | + dbCommon *precord = dbChannelRecord(chan); |
1866 | + *pstamp = precord->time; |
1867 | return 0; |
1868 | } |
1869 | |
1870 | @@ -324,9 +357,10 @@ static long dbDbPutValue(struct link *plink, short dbrType, |
1871 | const void *pbuffer, long nRequest) |
1872 | { |
1873 | struct pv_link *ppv_link = &plink->value.pv_link; |
1874 | + dbChannel *chan = linkChannel(plink); |
1875 | struct dbCommon *psrce = plink->precord; |
1876 | - DBADDR *paddr = (DBADDR *) ppv_link->pvt; |
1877 | - dbCommon *pdest = paddr->precord; |
1878 | + DBADDR *paddr = &chan->addr; |
1879 | + dbCommon *pdest = dbChannelRecord(chan); |
1880 | long status = dbPut(paddr, dbrType, pbuffer, nRequest); |
1881 | |
1882 | recGblInheritSevr(ppv_link->pvlMask & pvlOptMsMode, pdest, psrce->nsta, |
1883 | @@ -334,7 +368,7 @@ static long dbDbPutValue(struct link *plink, short dbrType, |
1884 | if (status) |
1885 | return status; |
1886 | |
1887 | - if (paddr->pfield == (void *) &pdest->proc || |
1888 | + if (dbChannelField(chan) == (void *) &pdest->proc || |
1889 | (ppv_link->pvlMask & pvlOptPP && pdest->scan == 0)) { |
1890 | status = processTarget(psrce, pdest); |
1891 | } |
1892 | @@ -345,9 +379,8 @@ static long dbDbPutValue(struct link *plink, short dbrType, |
1893 | static void dbDbScanFwdLink(struct link *plink) |
1894 | { |
1895 | dbCommon *precord = plink->precord; |
1896 | - dbAddr *paddr = (dbAddr *) plink->value.pv_link.pvt; |
1897 | - |
1898 | - dbScanPassive(precord, paddr->precord); |
1899 | + dbChannel *chan = linkChannel(plink); |
1900 | + dbScanPassive(precord, dbChannelRecord(chan)); |
1901 | } |
1902 | |
1903 | static long doLocked(struct link *plink, dbLinkUserCallback rtn, void *priv) |
1904 | diff --git a/modules/database/src/ioc/db/dbDbLink.h b/modules/database/src/ioc/db/dbDbLink.h |
1905 | index c367720..27972d8 100644 |
1906 | --- a/modules/database/src/ioc/db/dbDbLink.h |
1907 | +++ b/modules/database/src/ioc/db/dbDbLink.h |
1908 | @@ -26,7 +26,7 @@ struct dbLocker; |
1909 | |
1910 | epicsShareFunc long dbDbInitLink(struct link *plink, short dbfType); |
1911 | epicsShareFunc void dbDbAddLink(struct dbLocker *locker, struct link *plink, |
1912 | - short dbfType, DBADDR *ptarget); |
1913 | + short dbfType, dbChannel *ptarget); |
1914 | |
1915 | #ifdef __cplusplus |
1916 | } |
1917 | diff --git a/modules/database/src/ioc/db/dbEvent.c b/modules/database/src/ioc/db/dbEvent.c |
1918 | index 0d96e12..532c2ba 100644 |
1919 | --- a/modules/database/src/ioc/db/dbEvent.c |
1920 | +++ b/modules/database/src/ioc/db/dbEvent.c |
1921 | @@ -251,18 +251,15 @@ int dbel ( const char *pname, unsigned level ) |
1922 | } |
1923 | |
1924 | /* |
1925 | - * DB_INIT_EVENTS() |
1926 | + * DB_INIT_EVENT_FREELISTS() |
1927 | * |
1928 | * |
1929 | - * Initialize the event facility for this task. Must be called at least once |
1930 | - * by each task which uses the db event facility |
1931 | + * Initialize the free lists used by the event facility. |
1932 | + * Safe to be called multiple times. |
1933 | * |
1934 | - * returns: ptr to event user block or NULL if memory can't be allocated |
1935 | */ |
1936 | -dbEventCtx db_init_events (void) |
1937 | +void db_init_event_freelists (void) |
1938 | { |
1939 | - struct event_user * evUser; |
1940 | - |
1941 | if (!dbevEventUserFreeList) { |
1942 | freeListInitPvt(&dbevEventUserFreeList, |
1943 | sizeof(struct event_user),8); |
1944 | @@ -279,6 +276,22 @@ dbEventCtx db_init_events (void) |
1945 | freeListInitPvt(&dbevFieldLogFreeList, |
1946 | sizeof(struct db_field_log),2048); |
1947 | } |
1948 | +} |
1949 | + |
1950 | +/* |
1951 | + * DB_INIT_EVENTS() |
1952 | + * |
1953 | + * |
1954 | + * Initialize the event facility for this task. Must be called at least once |
1955 | + * by each task which uses the db event facility |
1956 | + * |
1957 | + * returns: ptr to event user block or NULL if memory can't be allocated |
1958 | + */ |
1959 | +dbEventCtx db_init_events (void) |
1960 | +{ |
1961 | + struct event_user * evUser; |
1962 | + |
1963 | + db_init_event_freelists(); |
1964 | |
1965 | evUser = (struct event_user *) |
1966 | freeListCalloc(dbevEventUserFreeList); |
1967 | @@ -654,27 +667,22 @@ int db_post_extra_labor (dbEventCtx ctx) |
1968 | return DB_EVENT_OK; |
1969 | } |
1970 | |
1971 | -/* |
1972 | - * DB_CREATE_EVENT_LOG() |
1973 | - * |
1974 | - * NOTE: This assumes that the db scan lock is already applied |
1975 | - * (as it copies data from the record) |
1976 | - */ |
1977 | -db_field_log* db_create_event_log (struct evSubscrip *pevent) |
1978 | +static db_field_log* db_create_field_log (struct dbChannel *chan, int use_val) |
1979 | { |
1980 | db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList); |
1981 | |
1982 | if (pLog) { |
1983 | - struct dbChannel *chan = pevent->chan; |
1984 | struct dbCommon *prec = dbChannelRecord(chan); |
1985 | - pLog->ctx = dbfl_context_event; |
1986 | - if (pevent->useValque) { |
1987 | + pLog->stat = prec->stat; |
1988 | + pLog->sevr = prec->sevr; |
1989 | + pLog->time = prec->time; |
1990 | + pLog->field_type = dbChannelFieldType(chan); |
1991 | + pLog->field_size = dbChannelFieldSize(chan); |
1992 | + pLog->no_elements = dbChannelElements(chan); |
1993 | + pLog->offset = 0; |
1994 | + |
1995 | + if (use_val) { |
1996 | pLog->type = dbfl_type_val; |
1997 | - pLog->stat = prec->stat; |
1998 | - pLog->sevr = prec->sevr; |
1999 | - pLog->time = prec->time; |
2000 | - pLog->field_type = dbChannelFieldType(chan); |
2001 | - pLog->no_elements = dbChannelElements(chan); |
2002 | /* |
2003 | * use memcpy to avoid a bus error on |
2004 | * union copy of char in the db at an odd |
2005 | @@ -684,23 +692,62 @@ db_field_log* db_create_event_log (struct evSubscrip *pevent) |
2006 | dbChannelField(chan), |
2007 | dbChannelFieldSize(chan)); |
2008 | } else { |
2009 | - pLog->type = dbfl_type_rec; |
2010 | + rset *prset; |
2011 | + |
2012 | + pLog->type = dbfl_type_ref; |
2013 | + |
2014 | + if (dbChannelSpecial(chan) == SPC_DBADDR && |
2015 | + (prset = dbGetRset(&chan->addr)) && |
2016 | + prset->get_array_info) |
2017 | + /* This condition implies !use_val, see db_add_event */ |
2018 | + { |
2019 | + void *pfieldsave = dbChannelField(chan); |
2020 | + prec = dbChannelRecord(chan); |
2021 | + prset->get_array_info(&chan->addr, &pLog->no_elements, &pLog->offset); |
2022 | + /* don't make a copy yet, just reference the field value */ |
2023 | + pLog->u.r.field = dbChannelField(chan); |
2024 | + dbChannelField(chan) = pfieldsave; |
2025 | + } |
2026 | + else { |
2027 | + /* don't make a copy yet, just reference the field value */ |
2028 | + pLog->u.r.field = dbChannelField(chan); |
2029 | + } |
2030 | + /* indicate field value still owned by record */ |
2031 | + pLog->u.r.dtor = NULL; |
2032 | + /* no private data yet, may be set by a filter */ |
2033 | + pLog->u.r.pvt = NULL; |
2034 | } |
2035 | } |
2036 | return pLog; |
2037 | } |
2038 | |
2039 | /* |
2040 | + * DB_CREATE_EVENT_LOG() |
2041 | + * |
2042 | + * NOTE: This assumes that the db scan lock is already applied |
2043 | + * (as it calls rset->get_array_info) |
2044 | + */ |
2045 | +db_field_log* db_create_event_log (struct evSubscrip *pevent) |
2046 | +{ |
2047 | + db_field_log *pLog = db_create_field_log(pevent->chan, pevent->useValque); |
2048 | + if (pLog) { |
2049 | + pLog->ctx = dbfl_context_event; |
2050 | + } |
2051 | + return pLog; |
2052 | +} |
2053 | + |
2054 | +/* |
2055 | * DB_CREATE_READ_LOG() |
2056 | * |
2057 | */ |
2058 | db_field_log* db_create_read_log (struct dbChannel *chan) |
2059 | { |
2060 | - db_field_log *pLog = (db_field_log *) freeListCalloc(dbevFieldLogFreeList); |
2061 | - |
2062 | + db_field_log *pLog = db_create_field_log(chan, |
2063 | + dbChannelElements(chan) == 1 && |
2064 | + dbChannelSpecial(chan) != SPC_DBADDR && |
2065 | + dbChannelFieldSize(chan) <= sizeof(union native_value)); |
2066 | if (pLog) { |
2067 | pLog->ctx = dbfl_context_read; |
2068 | - pLog->type = dbfl_type_rec; |
2069 | } |
2070 | return pLog; |
2071 | } |
2072 | @@ -724,20 +771,6 @@ static void db_queue_event_log (evSubscrip *pevent, db_field_log *pLog) |
2073 | LOCKEVQUE (ev_que); |
2074 | |
2075 | /* |
2076 | - * if we have an event on the queue and both the last |
2077 | - * event on the queue and the current event are emtpy |
2078 | - * (i.e. of type dbfl_type_rec), simply ignore duplicate |
2079 | - * events (saving empty events serves no purpose) |
2080 | - */ |
2081 | - if (pevent->npend > 0u && |
2082 | - (*pevent->pLastLog)->type == dbfl_type_rec && |
2083 | - pLog->type == dbfl_type_rec) { |
2084 | - db_delete_field_log(pLog); |
2085 | - UNLOCKEVQUE (ev_que); |
2086 | - return; |
2087 | - } |
2088 | - |
2089 | - /* |
2090 | * add to task local event que |
2091 | */ |
2092 | |
2093 | diff --git a/modules/database/src/ioc/db/dbEvent.h b/modules/database/src/ioc/db/dbEvent.h |
2094 | index 374e849..175b0e4 100644 |
2095 | --- a/modules/database/src/ioc/db/dbEvent.h |
2096 | +++ b/modules/database/src/ioc/db/dbEvent.h |
2097 | @@ -50,6 +50,7 @@ epicsShareFunc int db_post_events ( |
2098 | typedef void * dbEventCtx; |
2099 | |
2100 | typedef void EXTRALABORFUNC (void *extralabor_arg); |
2101 | +void db_init_event_freelists (void); |
2102 | epicsShareFunc dbEventCtx db_init_events (void); |
2103 | epicsShareFunc int db_start_events ( |
2104 | dbEventCtx ctx, const char *taskname, void (*init_func)(void *), |
2105 | diff --git a/modules/database/src/ioc/db/dbExtractArray.c b/modules/database/src/ioc/db/dbExtractArray.c |
2106 | index e16ab4c..f0ab281 100644 |
2107 | --- a/modules/database/src/ioc/db/dbExtractArray.c |
2108 | +++ b/modules/database/src/ioc/db/dbExtractArray.c |
2109 | @@ -13,11 +13,12 @@ |
2110 | /* |
2111 | * Author: Ralph Lange <Ralph.Lange@bessy.de> |
2112 | * |
2113 | - * based on dbConvert.c |
2114 | + * based on dbConvert.c, see copyNoConvert |
2115 | * written by: Bob Dalesio, Marty Kraimer |
2116 | */ |
2117 | |
2118 | #include <string.h> |
2119 | +#include <assert.h> |
2120 | |
2121 | #include "epicsTypes.h" |
2122 | |
2123 | @@ -25,61 +26,31 @@ |
2124 | #include "dbAddr.h" |
2125 | #include "dbExtractArray.h" |
2126 | |
2127 | -void dbExtractArrayFromRec(const dbAddr *paddr, void *pto, |
2128 | - long nRequest, long no_elements, long offset, long increment) |
2129 | +void dbExtractArray(const void *pfrom, void *pto, |
2130 | + short field_size, short field_type, |
2131 | + long nRequest, long no_elements, long offset, long increment) |
2132 | { |
2133 | char *pdst = (char *) pto; |
2134 | - char *psrc = (char *) paddr->pfield; |
2135 | - long nUpperPart; |
2136 | - int i; |
2137 | - short srcSize = paddr->field_size; |
2138 | - short dstSize = srcSize; |
2139 | - char isString = (paddr->field_type == DBF_STRING); |
2140 | + const char *psrc = (char *) pfrom; |
2141 | |
2142 | - if (nRequest > no_elements) nRequest = no_elements; |
2143 | - if (isString && srcSize > MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE; |
2144 | + /* assert preconditions */ |
2145 | + assert(nRequest >= 0); |
2146 | + assert(no_elements >= 0); |
2147 | + assert(increment > 0); |
2148 | + assert(0 <= offset); |
2149 | + assert(offset < no_elements); |
2150 | |
2151 | - if (increment == 1 && dstSize == srcSize) { |
2152 | - nUpperPart = nRequest < no_elements - offset ? nRequest : no_elements - offset; |
2153 | - memcpy(pdst, &psrc[offset * srcSize], dstSize * nUpperPart); |
2154 | + if (increment == 1) { |
2155 | + long nUpperPart = |
2156 | + nRequest < no_elements - offset ? nRequest : no_elements - offset; |
2157 | + memcpy(pdst, psrc + (offset * field_size), field_size * nUpperPart); |
2158 | if (nRequest > nUpperPart) |
2159 | - memcpy(&pdst[dstSize * nUpperPart], psrc, dstSize * (nRequest - nUpperPart)); |
2160 | - if (isString) |
2161 | - for (i = 1; i <= nRequest; i++) |
2162 | - pdst[dstSize*i-1] = '\0'; |
2163 | + memcpy(pdst + (field_size * nUpperPart), psrc, |
2164 | + field_size * (nRequest - nUpperPart)); |
2165 | } else { |
2166 | - for (; nRequest > 0; nRequest--, pdst += dstSize, offset += increment) { |
2167 | + for (; nRequest > 0; nRequest--, pdst += field_size, offset += increment) { |
2168 | offset %= no_elements; |
2169 | - memcpy(pdst, &psrc[offset*srcSize], dstSize); |
2170 | - if (isString) pdst[dstSize-1] = '\0'; |
2171 | - } |
2172 | - } |
2173 | -} |
2174 | - |
2175 | -void dbExtractArrayFromBuf(const void *pfrom, void *pto, |
2176 | - short field_size, short field_type, |
2177 | - long nRequest, long no_elements, long offset, long increment) |
2178 | -{ |
2179 | - char *pdst = (char *) pto; |
2180 | - char *psrc = (char *) pfrom; |
2181 | - int i; |
2182 | - short srcSize = field_size; |
2183 | - short dstSize = srcSize; |
2184 | - char isString = (field_type == DBF_STRING); |
2185 | - |
2186 | - if (nRequest > no_elements) nRequest = no_elements; |
2187 | - if (offset > no_elements - 1) offset = no_elements - 1; |
2188 | - if (isString && dstSize >= MAX_STRING_SIZE) dstSize = MAX_STRING_SIZE - 1; |
2189 | - |
2190 | - if (increment == 1) { |
2191 | - memcpy(pdst, &psrc[offset * srcSize], dstSize * nRequest); |
2192 | - if (isString) |
2193 | - for (i = 1; i <= nRequest; i++) |
2194 | - pdst[dstSize*i] = '\0'; |
2195 | - } else { |
2196 | - for (; nRequest > 0; nRequest--, pdst += srcSize, offset += increment) { |
2197 | - memcpy(pdst, &psrc[offset*srcSize], dstSize); |
2198 | - if (isString) pdst[dstSize] = '\0'; |
2199 | + memcpy(pdst, psrc + (offset * field_size), field_size); |
2200 | } |
2201 | } |
2202 | } |
2203 | diff --git a/modules/database/src/ioc/db/dbExtractArray.h b/modules/database/src/ioc/db/dbExtractArray.h |
2204 | index 7ed3584..9680660 100644 |
2205 | --- a/modules/database/src/ioc/db/dbExtractArray.h |
2206 | +++ b/modules/database/src/ioc/db/dbExtractArray.h |
2207 | @@ -21,11 +21,22 @@ |
2208 | extern "C" { |
2209 | #endif |
2210 | |
2211 | -epicsShareFunc void dbExtractArrayFromRec(const DBADDR *paddr, void *pto, |
2212 | - long nRequest, long no_elements, long offset, long increment); |
2213 | -epicsShareFunc void dbExtractArrayFromBuf(const void *pfrom, void *pto, |
2214 | - short field_size, short field_type, |
2215 | - long nRequest, long no_elements, long offset, long increment); |
2216 | +/* |
2217 | + * This function does not do any conversion. This means we don't have to |
2218 | + * truncate the field_size to MAX_STRING_SIZE or add extra null terminators |
2219 | + * for string values. All of this is done by the dbConvert routines which |
2220 | + * will be called whether or not a filter is active. |
2221 | + * |
2222 | + * Checked preconditions: |
2223 | + * - nRequest >= 0, no_elements >= 0, increment > 0 |
2224 | + * - 0 <= offset < no_elements |
2225 | + * Unchecked preconditions: |
2226 | + * - pto points to a buffer with at least field_size*nRequest bytes |
2227 | + * - pfrom points to a buffer with at least field_size*no_elements bytes |
2228 | + */ |
2229 | +epicsShareFunc void dbExtractArray(const void *pfrom, void *pto, |
2230 | + short field_size, short field_type, |
2231 | + long nRequest, long no_elements, long offset, long increment); |
2232 | |
2233 | #ifdef __cplusplus |
2234 | } |
2235 | diff --git a/modules/database/src/ioc/db/dbLink.c b/modules/database/src/ioc/db/dbLink.c |
2236 | index 7c37058..aa72dc8 100644 |
2237 | --- a/modules/database/src/ioc/db/dbLink.c |
2238 | +++ b/modules/database/src/ioc/db/dbLink.c |
2239 | @@ -143,7 +143,7 @@ void dbInitLink(struct link *plink, short dbfType) |
2240 | } |
2241 | |
2242 | void dbAddLink(struct dbLocker *locker, struct link *plink, short dbfType, |
2243 | - DBADDR *ptarget) |
2244 | + dbChannel *ptarget) |
2245 | { |
2246 | struct dbCommon *precord = plink->precord; |
2247 | |
2248 | diff --git a/modules/database/src/ioc/db/dbLink.h b/modules/database/src/ioc/db/dbLink.h |
2249 | index 94e1f32..4255a56 100644 |
2250 | --- a/modules/database/src/ioc/db/dbLink.h |
2251 | +++ b/modules/database/src/ioc/db/dbLink.h |
2252 | @@ -20,6 +20,7 @@ |
2253 | #include "epicsTypes.h" |
2254 | #include "epicsTime.h" |
2255 | #include "dbAddr.h" |
2256 | +#include "dbChannel.h" |
2257 | |
2258 | #ifdef __cplusplus |
2259 | extern "C" { |
2260 | @@ -368,7 +369,7 @@ epicsShareFunc const char * dbLinkFieldName(const struct link *plink); |
2261 | |
2262 | epicsShareFunc void dbInitLink(struct link *plink, short dbfType); |
2263 | epicsShareFunc void dbAddLink(struct dbLocker *locker, struct link *plink, |
2264 | - short dbfType, DBADDR *ptarget); |
2265 | + short dbfType, dbChannel *ptarget); |
2266 | |
2267 | epicsShareFunc void dbLinkOpen(struct link *plink); |
2268 | epicsShareFunc void dbRemoveLink(struct dbLocker *locker, struct link *plink); |
2269 | diff --git a/modules/database/src/ioc/db/dbLock.c b/modules/database/src/ioc/db/dbLock.c |
2270 | index 8df755b..19cb1c0 100644 |
2271 | --- a/modules/database/src/ioc/db/dbLock.c |
2272 | +++ b/modules/database/src/ioc/db/dbLock.c |
2273 | @@ -743,14 +743,14 @@ void dbLockSetSplit(dbLocker *locker, dbCommon *pfirst, dbCommon *psecond) |
2274 | for(i=0; i<rtype->no_links; i++) { |
2275 | dbFldDes *pdesc = rtype->papFldDes[rtype->link_ind[i]]; |
2276 | DBLINK *plink = (DBLINK*)((char*)prec + pdesc->offset); |
2277 | - DBADDR *ptarget; |
2278 | + dbChannel *chan; |
2279 | lockRecord *lr; |
2280 | |
2281 | if(plink->type!=DB_LINK) |
2282 | continue; |
2283 | |
2284 | - ptarget = plink->value.pv_link.pvt; |
2285 | - lr = ptarget->precord->lset; |
2286 | + chan = plink->value.pv_link.pvt; |
2287 | + lr = dbChannelRecord(chan)->lset; |
2288 | assert(lr); |
2289 | |
2290 | if(lr->precord==pfirst) { |
2291 | diff --git a/modules/database/src/ioc/db/dbTest.c b/modules/database/src/ioc/db/dbTest.c |
2292 | index 1193954..206d6c9 100644 |
2293 | --- a/modules/database/src/ioc/db/dbTest.c |
2294 | +++ b/modules/database/src/ioc/db/dbTest.c |
2295 | @@ -341,14 +341,14 @@ long dbgf(const char *pname) |
2296 | no_elements = MIN(addr.no_elements, sizeof(buffer)/addr.field_size); |
2297 | if (addr.dbr_field_type == DBR_ENUM) { |
2298 | long status = dbGetField(&addr, DBR_STRING, pbuffer, |
2299 | - &options, &no_elements, NULL); |
2300 | + &options, &no_elements); |
2301 | |
2302 | printBuffer(status, DBR_STRING, pbuffer, 0L, 0L, |
2303 | no_elements, &msg_Buff, 10); |
2304 | } |
2305 | else { |
2306 | long status = dbGetField(&addr, addr.dbr_field_type, pbuffer, |
2307 | - &options, &no_elements, NULL); |
2308 | + &options, &no_elements); |
2309 | |
2310 | printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L, |
2311 | no_elements, &msg_Buff, 10); |
2312 | @@ -487,7 +487,7 @@ long dbtgf(const char *pname) |
2313 | ret_options = req_options; |
2314 | no_elements = 0; |
2315 | status = dbGetField(&addr, addr.dbr_field_type, pbuffer, |
2316 | - &ret_options, &no_elements, NULL); |
2317 | + &ret_options, &no_elements); |
2318 | printBuffer(status, addr.dbr_field_type, pbuffer, |
2319 | req_options, ret_options, no_elements, pMsgBuff, tab_size); |
2320 | |
2321 | @@ -496,62 +496,62 @@ long dbtgf(const char *pname) |
2322 | |
2323 | dbr_type = DBR_STRING; |
2324 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/MAX_STRING_SIZE)); |
2325 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2326 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2327 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2328 | |
2329 | dbr_type = DBR_CHAR; |
2330 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt8))); |
2331 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2332 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2333 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2334 | |
2335 | dbr_type = DBR_UCHAR; |
2336 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt8))); |
2337 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2338 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2339 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2340 | |
2341 | dbr_type = DBR_SHORT; |
2342 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt16))); |
2343 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2344 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2345 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2346 | |
2347 | dbr_type = DBR_USHORT; |
2348 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt16))); |
2349 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2350 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2351 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2352 | |
2353 | dbr_type = DBR_LONG; |
2354 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt32))); |
2355 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2356 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2357 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2358 | |
2359 | dbr_type = DBR_ULONG; |
2360 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt32))); |
2361 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2362 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2363 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2364 | |
2365 | dbr_type = DBR_INT64; |
2366 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsInt64))); |
2367 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2368 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2369 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2370 | |
2371 | dbr_type = DBR_UINT64; |
2372 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsUInt64))); |
2373 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2374 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2375 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2376 | |
2377 | dbr_type = DBR_FLOAT; |
2378 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat32))); |
2379 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2380 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2381 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2382 | |
2383 | dbr_type = DBR_DOUBLE; |
2384 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsFloat64))); |
2385 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2386 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2387 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2388 | |
2389 | dbr_type = DBR_ENUM; |
2390 | no_elements = MIN(addr.no_elements,((sizeof(buffer))/sizeof(epicsEnum16))); |
2391 | - status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements,NULL); |
2392 | + status = dbGetField(&addr,dbr_type,pbuffer,&ret_options,&no_elements); |
2393 | printBuffer(status,dbr_type,pbuffer,0L,0L,no_elements,pMsgBuff,tab_size); |
2394 | |
2395 | pmsg[0] = '\0'; |
2396 | @@ -651,7 +651,7 @@ long dbtpf(const char *pname, const char *pvalue) |
2397 | |
2398 | printf("Put as DBR_%-6s Ok, result as ", dbr[put_type]); |
2399 | status = dbGetField(&addr, addr.dbr_field_type, pbuffer, |
2400 | - &options, &no_elements, NULL); |
2401 | + &options, &no_elements); |
2402 | printBuffer(status, addr.dbr_field_type, pbuffer, 0L, 0L, |
2403 | no_elements, pMsgBuff, tab_size); |
2404 | } |
2405 | diff --git a/modules/database/src/ioc/db/dbUnitTest.c b/modules/database/src/ioc/db/dbUnitTest.c |
2406 | index 6846ef5..458a28b 100644 |
2407 | --- a/modules/database/src/ioc/db/dbUnitTest.c |
2408 | +++ b/modules/database/src/ioc/db/dbUnitTest.c |
2409 | @@ -197,7 +197,7 @@ void testdbVGetFieldEqual(const char* pv, short dbrType, va_list ap) |
2410 | return; |
2411 | } |
2412 | |
2413 | - status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq, NULL); |
2414 | + status = dbGetField(&addr, dbrType, pod.bytes, NULL, &nReq); |
2415 | if (status) { |
2416 | testFail("dbGetField(\"%s\", %d, ...) -> %#lx (%s)", pv, dbrType, status, errSymMsg(status)); |
2417 | return; |
2418 | @@ -270,7 +270,7 @@ void testdbGetArrFieldEqual(const char* pv, short dbfType, long nRequest, unsign |
2419 | return; |
2420 | } |
2421 | |
2422 | - status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest, NULL); |
2423 | + status = dbGetField(&addr, dbfType, gbuf, NULL, &nRequest); |
2424 | if (status) { |
2425 | testFail("dbGetField(\"%s\", %d, ...) -> %#lx", pv, dbfType, status); |
2426 | |
2427 | diff --git a/modules/database/src/ioc/db/db_field_log.h b/modules/database/src/ioc/db/db_field_log.h |
2428 | index 1534517..4b3b82d 100644 |
2429 | --- a/modules/database/src/ioc/db/db_field_log.h |
2430 | +++ b/modules/database/src/ioc/db/db_field_log.h |
2431 | @@ -56,20 +56,31 @@ union native_value { |
2432 | struct db_field_log; |
2433 | typedef void (dbfl_freeFunc)(struct db_field_log *pfl); |
2434 | |
2435 | -/* Types of db_field_log: rec = use record, val = val inside, ref = reference inside */ |
2436 | +/* |
2437 | + * A db_field_log has one of two types: |
2438 | + * |
2439 | + * dbfl_type_ref - Reference to value |
2440 | + * Used for variable size (array) data types. Meta-data |
2441 | + * is stored in the field log, but value data is stored externally. |
2442 | + * Only the dbfl_ref side of the data union is valid. |
2443 | + * |
2444 | + * dbfl_type_val - Internal value |
2445 | + * Used to store small scalar data. Meta-data and value are |
2446 | + * present in this structure and no external references are used. |
2447 | + * Only the dbfl_val side of the data union is valid. |
2448 | + */ |
2449 | typedef enum dbfl_type { |
2450 | - dbfl_type_rec = 0, |
2451 | dbfl_type_val, |
2452 | dbfl_type_ref |
2453 | } dbfl_type; |
2454 | |
2455 | /* Context of db_field_log: event = subscription update, read = read reply */ |
2456 | typedef enum dbfl_context { |
2457 | - dbfl_context_read = 0, |
2458 | + dbfl_context_read, |
2459 | dbfl_context_event |
2460 | } dbfl_context; |
2461 | |
2462 | -#define dbflTypeStr(t) (t==dbfl_type_val?"val":t==dbfl_type_rec?"rec":"ref") |
2463 | +#define dbflTypeStr(t) (t==dbfl_type_val?"val":"ref") |
2464 | |
2465 | struct dbfl_val { |
2466 | union native_value field; /* Field value */ |
2467 | @@ -81,6 +92,8 @@ struct dbfl_val { |
2468 | * db_delete_field_log(). Any code which changes a dbfl_type_ref |
2469 | * field log to another type, or to reference different data, |
2470 | * must explicitly call the dtor function. |
2471 | + * If the dtor is NULL, then this means the array data is still owned |
2472 | + * by a record. |
2473 | */ |
2474 | struct dbfl_ref { |
2475 | dbfl_freeFunc *dtor; /* Callback to free filter-allocated resources */ |
2476 | @@ -88,8 +101,17 @@ struct dbfl_ref { |
2477 | void *field; /* Field value */ |
2478 | }; |
2479 | |
2480 | +/* |
2481 | + * Note: The offset member is understood to apply an implicit index mapping |
2482 | + * |
2483 | + * i' = (i + offset) % no_elements |
2484 | + * |
2485 | + * of request index i. The resulting i' is used to to index into u.r.field. |
2486 | + * |
2487 | + * Also note that field_size may be larger than MAX_STRING_SIZE. |
2488 | + */ |
2489 | typedef struct db_field_log { |
2490 | - unsigned int type:2; /* type (union) selector */ |
2491 | + unsigned int type:1; /* type (union) selector */ |
2492 | /* ctx is used for all types */ |
2493 | unsigned int ctx:1; /* context (operation type) */ |
2494 | /* the following are used for value and reference types */ |
2495 | @@ -97,37 +119,15 @@ typedef struct db_field_log { |
2496 | unsigned short stat; /* Alarm Status */ |
2497 | unsigned short sevr; /* Alarm Severity */ |
2498 | short field_type; /* DBF type of data */ |
2499 | - short field_size; /* Data size */ |
2500 | - long no_elements; /* No of array elements */ |
2501 | + short field_size; /* Size of a single element */ |
2502 | + long no_elements; /* No of valid array elements */ |
2503 | + long offset; /* See above */ |
2504 | union { |
2505 | struct dbfl_val v; |
2506 | struct dbfl_ref r; |
2507 | } u; |
2508 | } db_field_log; |
2509 | |
2510 | -/* |
2511 | - * A db_field_log will in one of three types: |
2512 | - * |
2513 | - * dbfl_type_rec - Reference to record |
2514 | - * The field log stores no data itself. Data must instead be taken |
2515 | - * via the dbChannel* which must always be provided when along |
2516 | - * with the field log. |
2517 | - * For this type only the 'type' and 'ctx' members are used. |
2518 | - * |
2519 | - * dbfl_type_ref - Reference to outside value |
2520 | - * Used for variable size (array) data types. Meta-data |
2521 | - * is stored in the field log, but value data is stored externally |
2522 | - * (see struct dbfl_ref). |
2523 | - * For this type all meta-data members are used. The dbfl_ref side of the |
2524 | - * data union is used. |
2525 | - * |
2526 | - * dbfl_type_val - Internal value |
2527 | - * Used to store small scalar data. Meta-data and value are |
2528 | - * present in this structure and no external references are used. |
2529 | - * For this type all meta-data members are used. The dbfl_val side of the |
2530 | - * data union is used. |
2531 | - */ |
2532 | - |
2533 | #ifdef __cplusplus |
2534 | } |
2535 | #endif |
2536 | diff --git a/modules/database/src/std/dev/devAiSoft.c b/modules/database/src/std/dev/devAiSoft.c |
2537 | index 0ecc1b1..5f9923e 100644 |
2538 | --- a/modules/database/src/std/dev/devAiSoft.c |
2539 | +++ b/modules/database/src/std/dev/devAiSoft.c |
2540 | @@ -96,9 +96,10 @@ static long read_ai(aiRecord *prec) |
2541 | |
2542 | prec->udf = FALSE; |
2543 | prec->dpvt = &devAiSoft; /* Any non-zero value */ |
2544 | + return 2; |
2545 | } |
2546 | else |
2547 | prec->dpvt = NULL; |
2548 | |
2549 | - return 2; |
2550 | + return status; |
2551 | } |
2552 | diff --git a/modules/database/src/std/filters/arr.c b/modules/database/src/std/filters/arr.c |
2553 | index f91708a..b90335e 100644 |
2554 | --- a/modules/database/src/std/filters/arr.c |
2555 | +++ b/modules/database/src/std/filters/arr.c |
2556 | @@ -12,16 +12,13 @@ |
2557 | |
2558 | #include <stdio.h> |
2559 | |
2560 | -#include <freeList.h> |
2561 | -#include <dbAccess.h> |
2562 | -#include <dbExtractArray.h> |
2563 | -#include <db_field_log.h> |
2564 | -#include <dbLock.h> |
2565 | -#include <recSup.h> |
2566 | -#include <epicsExit.h> |
2567 | -#include <special.h> |
2568 | -#include <chfPlugin.h> |
2569 | -#include <epicsExport.h> |
2570 | +#include "chfPlugin.h" |
2571 | +#include "dbExtractArray.h" |
2572 | +#include "db_field_log.h" |
2573 | +#include "dbLock.h" |
2574 | +#include "epicsExit.h" |
2575 | +#include "freeList.h" |
2576 | +#include "epicsExport.h" |
2577 | |
2578 | typedef struct myStruct { |
2579 | epicsInt32 start; |
2580 | @@ -45,6 +42,8 @@ static void * allocPvt(void) |
2581 | myStruct *my = (myStruct*) freeListCalloc(myStructFreeList); |
2582 | if (!my) return NULL; |
2583 | |
2584 | + /* defaults */ |
2585 | + my->start = 0; |
2586 | my->incr = 1; |
2587 | my->end = -1; |
2588 | return (void *) my; |
2589 | @@ -93,78 +92,61 @@ static long wrapArrayIndices(long *start, const long increment, long *end, |
2590 | static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) |
2591 | { |
2592 | myStruct *my = (myStruct*) pvt; |
2593 | - struct dbCommon *prec; |
2594 | - rset *prset; |
2595 | + int must_lock; |
2596 | long start = my->start; |
2597 | long end = my->end; |
2598 | - long nTarget = 0; |
2599 | - long offset = 0; |
2600 | - long nSource = dbChannelElements(chan); |
2601 | - long capacity = nSource; |
2602 | - void *pdst; |
2603 | + long nTarget; |
2604 | + void *pTarget; |
2605 | + /* initial values for the source array */ |
2606 | + long offset = pfl->offset; |
2607 | + long nSource = pfl->no_elements; |
2608 | |
2609 | switch (pfl->type) { |
2610 | case dbfl_type_val: |
2611 | - /* Only filter arrays */ |
2612 | + /* TODO Treat scalars as arrays with 1 element */ |
2613 | break; |
2614 | |
2615 | - case dbfl_type_rec: |
2616 | - /* Extract from record */ |
2617 | - if (dbChannelSpecial(chan) == SPC_DBADDR && |
2618 | - nSource > 1 && |
2619 | - (prset = dbGetRset(&chan->addr)) && |
2620 | - prset->get_array_info) |
2621 | - { |
2622 | - void *pfieldsave = dbChannelField(chan); |
2623 | - prec = dbChannelRecord(chan); |
2624 | - dbScanLock(prec); |
2625 | - prset->get_array_info(&chan->addr, &nSource, &offset); |
2626 | - nTarget = wrapArrayIndices(&start, my->incr, &end, nSource); |
2627 | - pfl->type = dbfl_type_ref; |
2628 | - pfl->stat = prec->stat; |
2629 | - pfl->sevr = prec->sevr; |
2630 | - pfl->time = prec->time; |
2631 | - pfl->field_type = dbChannelFieldType(chan); |
2632 | - pfl->field_size = dbChannelFieldSize(chan); |
2633 | - pfl->no_elements = nTarget; |
2634 | - if (nTarget) { |
2635 | - pdst = freeListCalloc(my->arrayFreeList); |
2636 | - if (pdst) { |
2637 | - pfl->u.r.dtor = freeArray; |
2638 | - pfl->u.r.pvt = my->arrayFreeList; |
2639 | - offset = (offset + start) % dbChannelElements(chan); |
2640 | - dbExtractArrayFromRec(&chan->addr, pdst, nTarget, capacity, |
2641 | - offset, my->incr); |
2642 | - pfl->u.r.field = pdst; |
2643 | - } |
2644 | - } |
2645 | - dbScanUnlock(prec); |
2646 | - dbChannelField(chan) = pfieldsave; |
2647 | - } |
2648 | - break; |
2649 | - |
2650 | - /* Extract from buffer */ |
2651 | case dbfl_type_ref: |
2652 | - pdst = NULL; |
2653 | - nSource = pfl->no_elements; |
2654 | + must_lock = !pfl->u.r.dtor; |
2655 | + if (must_lock) |
2656 | + dbScanLock(dbChannelRecord(chan)); |
2657 | nTarget = wrapArrayIndices(&start, my->incr, &end, nSource); |
2658 | - pfl->no_elements = nTarget; |
2659 | - if (nTarget) { |
2660 | - /* Copy the data out */ |
2661 | - void *psrc = pfl->u.r.field; |
2662 | - |
2663 | - pdst = freeListCalloc(my->arrayFreeList); |
2664 | - if (!pdst) break; |
2665 | - offset = start; |
2666 | - dbExtractArrayFromBuf(psrc, pdst, pfl->field_size, pfl->field_type, |
2667 | - nTarget, nSource, offset, my->incr); |
2668 | - } |
2669 | - if (pfl->u.r.dtor) pfl->u.r.dtor(pfl); |
2670 | - if (nTarget) { |
2671 | + /* |
2672 | + * Side note: it would be nice if we could avoid the copying in |
2673 | + * the case of my->incr==1. This is currently not possible due to |
2674 | + * the way the offset member is interpreted (namely as shifting the |
2675 | + * array in a ring-buffer style). |
2676 | + */ |
2677 | + if (nTarget > 0) { |
2678 | + /* copy the data */ |
2679 | + void *pSource = pfl->u.r.field; |
2680 | + pTarget = freeListCalloc(my->arrayFreeList); |
2681 | + if (!pTarget) break; |
2682 | + offset = (offset + start) % nSource; |
2683 | + dbExtractArray(pSource, pTarget, pfl->field_size, |
2684 | + pfl->field_type, nTarget, nSource, offset, my->incr); |
2685 | + if (pfl->u.r.dtor) pfl->u.r.dtor(pfl); |
2686 | + pfl->u.r.field = pTarget; |
2687 | pfl->u.r.dtor = freeArray; |
2688 | pfl->u.r.pvt = my->arrayFreeList; |
2689 | - pfl->u.r.field = pdst; |
2690 | } |
2691 | + /* adjust offset and no_elements to refer to the new pTarget */ |
2692 | + pfl->offset = 0; |
2693 | + /* |
2694 | + * Setting pfl->no_elements outside of the "if" clause above is |
2695 | + * done to make requests fail if nTarget is zero, that is, if all |
2696 | + * elements selected by the filter are outside the array bounds. |
2697 | + * TODO: |
2698 | + * It would be possible to lift this restriction by interpreting |
2699 | + * a request with *no* number of elements (NULL pointer) as scalar |
2700 | + * (meaning: fail if we get less than one element); in contrast, |
2701 | + * a request that explicitly specifies one element would be |
2702 | + * interpreted as an array request, for which zero elements would |
2703 | + * be a normal expected result. |
2704 | + */ |
2705 | + pfl->no_elements = nTarget; |
2706 | + if (must_lock) |
2707 | + dbScanUnlock(dbChannelRecord(chan)); |
2708 | break; |
2709 | } |
2710 | return pfl; |
2711 | diff --git a/modules/database/src/std/filters/ts.c b/modules/database/src/std/filters/ts.c |
2712 | index 5925b0b..56c9f5b 100644 |
2713 | --- a/modules/database/src/std/filters/ts.c |
2714 | +++ b/modules/database/src/std/filters/ts.c |
2715 | @@ -11,21 +11,39 @@ |
2716 | */ |
2717 | |
2718 | #include <stdio.h> |
2719 | +#include <stdlib.h> |
2720 | +#include <string.h> |
2721 | |
2722 | -#include <chfPlugin.h> |
2723 | -#include <dbLock.h> |
2724 | -#include <db_field_log.h> |
2725 | -#include <epicsExport.h> |
2726 | +#include "chfPlugin.h" |
2727 | +#include "db_field_log.h" |
2728 | +#include "dbLock.h" |
2729 | +#include "epicsExport.h" |
2730 | + |
2731 | +/* |
2732 | + * The size of the data is different for each channel, and can even |
2733 | + * change at runtime, so a freeList doesn't make much sense here. |
2734 | + */ |
2735 | +static void freeArray(db_field_log *pfl) { |
2736 | + free(pfl->u.r.field); |
2737 | +} |
2738 | |
2739 | static db_field_log* filter(void* pvt, dbChannel *chan, db_field_log *pfl) { |
2740 | epicsTimeStamp now; |
2741 | epicsTimeGetCurrent(&now); |
2742 | |
2743 | - /* If string or array, must make a copy (to ensure coherence between time and data) */ |
2744 | - if (pfl->type == dbfl_type_rec) { |
2745 | - dbScanLock(dbChannelRecord(chan)); |
2746 | - dbChannelMakeArrayCopy(pvt, pfl, chan); |
2747 | - dbScanUnlock(dbChannelRecord(chan)); |
2748 | + /* If reference and not already copied, |
2749 | + must make a copy (to ensure coherence between time and data) */ |
2750 | + if (pfl->type == dbfl_type_ref && !pfl->u.r.dtor) { |
2751 | + void *pTarget = calloc(pfl->no_elements, pfl->field_size); |
2752 | + void *pSource = pfl->u.r.field; |
2753 | + if (pTarget) { |
2754 | + dbScanLock(dbChannelRecord(chan)); |
2755 | + memcpy(pTarget, pSource, pfl->field_size * pfl->no_elements); |
2756 | + pfl->u.r.field = pTarget; |
2757 | + pfl->u.r.dtor = freeArray; |
2758 | + pfl->u.r.pvt = pvt; |
2759 | + dbScanUnlock(dbChannelRecord(chan)); |
2760 | + } |
2761 | } |
2762 | |
2763 | pfl->time = now; |
2764 | diff --git a/modules/database/test/ioc/db/dbChArrTest.cpp b/modules/database/test/ioc/db/dbChArrTest.cpp |
2765 | index 8255fdc..ff74e01 100644 |
2766 | --- a/modules/database/test/ioc/db/dbChArrTest.cpp |
2767 | +++ b/modules/database/test/ioc/db/dbChArrTest.cpp |
2768 | @@ -130,7 +130,7 @@ static void check(short dbr_type) { |
2769 | memset(buf, 0, sizeof(buf)); \ |
2770 | (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \ |
2771 | pfl = db_create_read_log(pch); \ |
2772 | - testOk(pfl && pfl->type == dbfl_type_rec, "Valid pfl, type = rec"); \ |
2773 | + testOk(pfl && pfl->type == dbfl_type_ref, "Valid pfl, type = ref"); \ |
2774 | testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \ |
2775 | testOk(req == Size, "Got %ld elements (expected %d)", req, Size); \ |
2776 | if (!testOk(!memcmp(buf, Expected, sizeof(Expected)), "Data correct")) \ |
2777 | @@ -178,6 +178,7 @@ static void check(short dbr_type) { |
2778 | pfl->field_type = DBF_CHAR; \ |
2779 | pfl->field_size = 1; \ |
2780 | pfl->no_elements = 26; \ |
2781 | + pfl->offset = 0; \ |
2782 | pfl->u.r.dtor = freeArray; \ |
2783 | pfl->u.r.field = epicsStrDup("abcdefghijklmnopqrsstuvwxyz"); \ |
2784 | testOk(!dbChannelGetField(pch, DBR_LONG, buf, NULL, &req, pfl), "Got Field value"); \ |
2785 | diff --git a/modules/database/test/std/filters/arrTest.cpp b/modules/database/test/std/filters/arrTest.cpp |
2786 | index 1ec16b3..08ba07b 100644 |
2787 | --- a/modules/database/test/std/filters/arrTest.cpp |
2788 | +++ b/modules/database/test/std/filters/arrTest.cpp |
2789 | @@ -56,25 +56,26 @@ const char *server_port = CA_SERVER_PORT; |
2790 | |
2791 | static int fl_equals_array(short type, const db_field_log *pfl1, void *p2) { |
2792 | for (int i = 0; i < pfl1->no_elements; i++) { |
2793 | + int j = (i + pfl1->offset) % pfl1->no_elements; |
2794 | switch (type) { |
2795 | case DBR_DOUBLE: |
2796 | - if (((epicsFloat64*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) { |
2797 | + if (((epicsFloat64*)pfl1->u.r.field)[j] != ((epicsInt32*)p2)[i]) { |
2798 | testDiag("at index=%d: field log has %g, should be %d", |
2799 | - i, ((epicsFloat64*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]); |
2800 | + i, ((epicsFloat64*)pfl1->u.r.field)[j], ((epicsInt32*)p2)[i]); |
2801 | return 0; |
2802 | } |
2803 | break; |
2804 | case DBR_LONG: |
2805 | - if (((epicsInt32*)pfl1->u.r.field)[i] != ((epicsInt32*)p2)[i]) { |
2806 | + if (((epicsInt32*)pfl1->u.r.field)[j] != ((epicsInt32*)p2)[i]) { |
2807 | testDiag("at index=%d: field log has %d, should be %d", |
2808 | - i, ((epicsInt32*)pfl1->u.r.field)[i], ((epicsInt32*)p2)[i]); |
2809 | + i, ((epicsInt32*)pfl1->u.r.field)[j], ((epicsInt32*)p2)[i]); |
2810 | return 0; |
2811 | } |
2812 | break; |
2813 | case DBR_STRING: |
2814 | - if (strtol(&((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], NULL, 0) != ((epicsInt32*)p2)[i]) { |
2815 | + if (strtol(&((const char*)pfl1->u.r.field)[j*pfl1->field_size], NULL, 0) != ((epicsInt32*)p2)[i]) { |
2816 | testDiag("at index=%d: field log has '%s', should be '%d'", |
2817 | - i, &((const char*)pfl1->u.r.field)[i*MAX_STRING_SIZE], ((epicsInt32*)p2)[i]); |
2818 | + i, &((const char*)pfl1->u.r.field)[j*pfl1->field_size], ((epicsInt32*)p2)[i]); |
2819 | return 0; |
2820 | } |
2821 | break; |
2822 | @@ -119,7 +120,7 @@ static void testHead (const char *title, const char *typ = "") { |
2823 | off = Offset; \ |
2824 | (void) dbPutField(&offaddr, DBR_LONG, &off, 1); \ |
2825 | pfl = db_create_read_log(pch); \ |
2826 | - testOk(pfl->type == dbfl_type_rec, "original field log has type rec"); \ |
2827 | + testOk(pfl->type == dbfl_type_ref, "original field log has type ref"); \ |
2828 | pfl2 = dbChannelRunPostChain(pch, pfl); \ |
2829 | testOk(pfl2 == pfl, "call does not drop or replace field_log"); \ |
2830 | testOk(pfl->type == dbfl_type_ref, "filtered field log has type ref"); \ |
2831 | diff --git a/modules/database/test/std/filters/dbndTest.c b/modules/database/test/std/filters/dbndTest.c |
2832 | index 4d70f83..fd4a472 100644 |
2833 | --- a/modules/database/test/std/filters/dbndTest.c |
2834 | +++ b/modules/database/test/std/filters/dbndTest.c |
2835 | @@ -129,7 +129,7 @@ MAIN(dbndTest) |
2836 | dbEventCtx evtctx; |
2837 | int logsFree, logsFinal; |
2838 | |
2839 | - testPlan(77); |
2840 | + testPlan(72); |
2841 | |
2842 | testdbPrepare(); |
2843 | |
2844 | @@ -170,12 +170,9 @@ MAIN(dbndTest) |
2845 | "dbnd has one filter with argument in pre chain"); |
2846 | testOk((ellCount(&pch->post_chain) == 0), "dbnd has no filter in post chain"); |
2847 | |
2848 | - /* Field logs of type ref and rec: pass any update */ |
2849 | - |
2850 | - testHead("Field logs of type ref and rec"); |
2851 | - fl1.type = dbfl_type_rec; |
2852 | - mustPassTwice(pch, &fl1, "abs field_log=rec", 0., 0); |
2853 | + /* Field logs of type ref: pass any update */ |
2854 | |
2855 | + testHead("Field logs of type ref"); |
2856 | fl1.type = dbfl_type_ref; |
2857 | mustPassTwice(pch, &fl1, "abs field_log=ref", 0., 0); |
2858 | |
2859 | diff --git a/modules/database/test/std/rec/Makefile b/modules/database/test/std/rec/Makefile |
2860 | index 8c087b3..3d7cff9 100644 |
2861 | --- a/modules/database/test/std/rec/Makefile |
2862 | +++ b/modules/database/test/std/rec/Makefile |
2863 | @@ -156,6 +156,13 @@ asyncproctest_SRCS += asyncproctest_registerRecordDeviceDriver.cpp |
2864 | TESTFILES += $(COMMON_DIR)/asyncproctest.dbd ../asyncproctest.db |
2865 | TESTS += asyncproctest |
2866 | |
2867 | +TESTPROD_HOST += linkFilterTest |
2868 | +linkFilterTest_SRCS += linkFilterTest.c |
2869 | +linkFilterTest_SRCS += recTestIoc_registerRecordDeviceDriver.cpp |
2870 | +testHarness_SRCS += linkFilterTest.c |
2871 | +TESTFILES += ../linkFilterTest.db |
2872 | +TESTS += linkFilterTest |
2873 | + |
2874 | # dbHeader* is only a compile test |
2875 | # no need to actually run |
2876 | TESTPROD += dbHeaderTest |
2877 | diff --git a/modules/database/test/std/rec/linkFilterTest.c b/modules/database/test/std/rec/linkFilterTest.c |
2878 | new file mode 100644 |
2879 | index 0000000..6f38d24 |
2880 | --- /dev/null |
2881 | +++ b/modules/database/test/std/rec/linkFilterTest.c |
2882 | @@ -0,0 +1,157 @@ |
2883 | +/*************************************************************************\ |
2884 | +* Copyright (c) 2020 Dirk Zimoch |
2885 | +* EPICS BASE is distributed subject to a Software License Agreement found |
2886 | +* in file LICENSE that is included with this distribution. |
2887 | +\*************************************************************************/ |
2888 | + |
2889 | +#include <string.h> |
2890 | + |
2891 | +#include "dbAccess.h" |
2892 | +#include "devSup.h" |
2893 | +#include "alarm.h" |
2894 | +#include "dbUnitTest.h" |
2895 | +#include "errlog.h" |
2896 | +#include "epicsThread.h" |
2897 | + |
2898 | +#include "longinRecord.h" |
2899 | + |
2900 | +#include "testMain.h" |
2901 | + |
2902 | +void recTestIoc_registerRecordDeviceDriver(struct dbBase *); |
2903 | + |
2904 | +static void startTestIoc(const char *dbfile) |
2905 | +{ |
2906 | + testdbPrepare(); |
2907 | + testdbReadDatabase("recTestIoc.dbd", NULL, NULL); |
2908 | + recTestIoc_registerRecordDeviceDriver(pdbbase); |
2909 | + testdbReadDatabase(dbfile, NULL, NULL); |
2910 | + |
2911 | + eltc(0); |
2912 | + testIocInitOk(); |
2913 | + eltc(1); |
2914 | +} |
2915 | + |
2916 | +static void expectProcSuccess(const char *rec) |
2917 | +{ |
2918 | + char fieldname[20]; |
2919 | + testDiag("expecting success from %s", rec); |
2920 | + sprintf(fieldname, "%s.PROC", rec); |
2921 | + testdbPutFieldOk(fieldname, DBF_LONG, 1); |
2922 | + sprintf(fieldname, "%s.SEVR", rec); |
2923 | + testdbGetFieldEqual(fieldname, DBF_LONG, NO_ALARM); |
2924 | + sprintf(fieldname, "%s.STAT", rec); |
2925 | + testdbGetFieldEqual(fieldname, DBF_LONG, NO_ALARM); |
2926 | +} |
2927 | + |
2928 | +static void expectProcFailure(const char *rec) |
2929 | +{ |
2930 | + char fieldname[20]; |
2931 | + testDiag("expecting failure S_db_badField %#x from %s", S_db_badField, rec); |
2932 | + sprintf(fieldname, "%s.PROC", rec); |
2933 | + testdbPutFieldFail(S_db_badField, fieldname, DBF_LONG, 1); |
2934 | + sprintf(fieldname, "%s.SEVR", rec); |
2935 | + testdbGetFieldEqual(fieldname, DBF_LONG, INVALID_ALARM); |
2936 | + sprintf(fieldname, "%s.STAT", rec); |
2937 | + testdbGetFieldEqual(fieldname, DBF_LONG, LINK_ALARM); |
2938 | +} |
2939 | + |
2940 | +static void changeRange(long start, long stop, long step) |
2941 | +{ |
2942 | + char linkstring[60]; |
2943 | + if (step) |
2944 | + sprintf(linkstring, "src.[%ld:%ld:%ld]", start, step, stop); |
2945 | + else if (stop) |
2946 | + sprintf(linkstring, "src.[%ld:%ld]", start, stop); |
2947 | + else |
2948 | + sprintf(linkstring, "src.[%ld]", start); |
2949 | + testDiag("modifying link: %s", linkstring); |
2950 | + testdbPutFieldOk("ai.INP", DBF_STRING, linkstring); |
2951 | + testdbPutFieldOk("wf.INP", DBF_STRING, linkstring); |
2952 | +} |
2953 | + |
2954 | +static double buf[] = {1, 2, 3, 4, 5, 6, 7, 8, 0, 0, 2, 4, 6}; |
2955 | + |
2956 | +static void expectRange(long start, long end) |
2957 | +{ |
2958 | + long n = end-start+1; |
2959 | + testdbGetFieldEqual("ai.VAL", DBF_DOUBLE, buf[start]); |
2960 | + testdbGetFieldEqual("wf.NORD", DBF_LONG, n); |
2961 | + testdbGetArrFieldEqual("wf.VAL", DBF_DOUBLE, n+2, n, buf+start); |
2962 | +} |
2963 | + |
2964 | +#if 0 |
2965 | +static void expectEmptyArray(void) |
2966 | +{ |
2967 | + /* empty arrays are now allowed at the moment */ |
2968 | + testDiag("expecting empty array"); |
2969 | + testdbGetFieldEqual("wf.NORD", DBF_LONG, 0); |
2970 | +} |
2971 | +#endif |
2972 | + |
2973 | +MAIN(linkFilterTest) |
2974 | +{ |
2975 | + testPlan(98); |
2976 | + startTestIoc("linkFilterTest.db"); |
2977 | + |
2978 | + testDiag("PINI"); |
2979 | + expectRange(2,4); |
2980 | + |
2981 | + testDiag("modify range"); |
2982 | + changeRange(3,6,0); |
2983 | + expectProcSuccess("ai"); |
2984 | + expectProcSuccess("wf"); |
2985 | + expectRange(3,6); |
2986 | + |
2987 | + testDiag("backward range"); |
2988 | + changeRange(5,3,0); |
2989 | + expectProcFailure("ai"); |
2990 | + expectProcFailure("wf"); |
2991 | + |
2992 | + testDiag("step 2"); |
2993 | + changeRange(1,6,2); |
2994 | + expectProcSuccess("ai"); |
2995 | + expectProcSuccess("wf"); |
2996 | + expectRange(10,12); |
2997 | + |
2998 | + testDiag("range start beyond src.NORD"); |
2999 | + changeRange(8,9,0); |
3000 | + expectProcFailure("ai"); |
3001 | + expectProcFailure("wf"); |
3002 | + |
3003 | + testDiag("range end beyond src.NORD"); |
3004 | + changeRange(3,9,0); |
3005 | + expectProcSuccess("ai"); |
3006 | + expectProcSuccess("wf"); |
3007 | + expectRange(3,7); /* clipped range */ |
3008 | + |
3009 | + testDiag("range start beyond src.NELM"); |
3010 | + changeRange(11,12,0); |
3011 | + expectProcFailure("ai"); |
3012 | + expectProcFailure("wf"); |
3013 | + |
3014 | + testDiag("range end beyond src.NELM"); |
3015 | + changeRange(4,12,0); |
3016 | + expectProcSuccess("ai"); |
3017 | + expectProcSuccess("wf"); |
3018 | + expectRange(4,7); /* clipped range */ |
3019 | + |
3020 | + testDiag("single value beyond src.NORD"); |
3021 | + changeRange(8,0,0); |
3022 | + expectProcFailure("ai"); |
3023 | + expectProcFailure("wf"); |
3024 | + |
3025 | + testDiag("single value"); |
3026 | + changeRange(5,0,0); |
3027 | + expectProcSuccess("ai"); |
3028 | + expectProcSuccess("wf"); |
3029 | + expectRange(5,5); |
3030 | + |
3031 | + testDiag("single beyond rec.NELM"); |
3032 | + changeRange(12,0,0); |
3033 | + expectProcFailure("ai"); |
3034 | + expectProcFailure("wf"); |
3035 | + |
3036 | + testIocShutdownOk(); |
3037 | + testdbCleanup(); |
3038 | + return testDone(); |
3039 | +} |
3040 | diff --git a/modules/database/test/std/rec/linkFilterTest.db b/modules/database/test/std/rec/linkFilterTest.db |
3041 | new file mode 100644 |
3042 | index 0000000..5ee371e |
3043 | --- /dev/null |
3044 | +++ b/modules/database/test/std/rec/linkFilterTest.db |
3045 | @@ -0,0 +1,16 @@ |
3046 | +record(waveform, "src") { |
3047 | + field(NELM, "10") |
3048 | + field(FTVL, "SHORT") |
3049 | + field(INP, [1, 2, 3, 4, 5, 6, 7, 8]) |
3050 | +} |
3051 | +record(ai, "ai") { |
3052 | + field(INP, "src.[2]") # expect 3 |
3053 | + field(PINI, "YES") |
3054 | +} |
3055 | +record(waveform, "wf") { |
3056 | + field(NELM, "5") |
3057 | + field(FTVL, "DOUBLE") |
3058 | + field(INP, "src.[2:4]") # expect 3,4,5 |
3059 | + field(PINI, "YES") |
3060 | +} |
3061 | + |
3062 | diff --git a/modules/database/test/std/rec/regressTest.c b/modules/database/test/std/rec/regressTest.c |
3063 | index 6614639..fd4f0a8 100644 |
3064 | --- a/modules/database/test/std/rec/regressTest.c |
3065 | +++ b/modules/database/test/std/rec/regressTest.c |
3066 | @@ -132,7 +132,7 @@ void testCADisconn(void) |
3067 | |
3068 | startRegressTestIoc("badCaLink.db"); |
3069 | |
3070 | - testdbPutFieldOk("ai:disconn.PROC", DBF_LONG, 1); |
3071 | + testdbPutFieldFail(-1, "ai:disconn.PROC", DBF_LONG, 1); |
3072 | testdbGetFieldEqual("ai:disconn.SEVR", DBF_LONG, INVALID_ALARM); |
3073 | testdbGetFieldEqual("ai:disconn.STAT", DBF_LONG, LINK_ALARM); |
3074 | } |
Note that I have based this on Dirk's addition of filters for DB links.
I wonder if I should have listed Dirk's repo+branch as a requisite when creating the merge request.
Is it possible to do that after the fact or do I have to re-submit?