SDDS ToolKit Programs and Libraries for C and Python
All Classes Files Functions Variables Macros Pages
pvaSDDS.cc
Go to the documentation of this file.
1/**
2 * @file pvaSDDS.cc
3 * @brief Functions for managing and interacting with Process Variable Array (PVA) structures.
4 *
5 * @details
6 * This file includes a set of functions to allocate, reallocate, free, connect, monitor, and
7 * extract values for Process Variable Arrays (PVA) using EPICS PVAccess and PVData libraries.
8 * It provides utilities for managing PVAs in scenarios where EPICS Channel Access (CA) and
9 * PVAccess (PVA) protocols are used to interact with control system process variables.
10 *
11 * The file also defines types and utilities for handling multimap-based structures and
12 * formatting channel names and field requests.
13 *
14 * Key functionalities:
15 * - Memory allocation and reallocation for PVA structures.
16 * - Connection to PV channels using PvaClientMultiChannel.
17 * - Monitoring and polling for events on PVs.
18 * - Extracting and preparing values for PVs.
19 * - Support for scalar, array, and enumerated types within PVs.
20 * - Utilities for interacting with PV metadata such as units and alarm severity.
21 *
22 * Dependencies:
23 * - EPICS PVAccess
24 * - EPICS PVData
25 * - <unordered_map>, <string>, <vector>, <map>, <set>, and other C++ standard library components.
26 *
27 * @see https://epics.anl.gov
28 * @see PvaClientMultiChannel documentation for details on channel operations.
29 * @see https://docs.epics-controls.org/projects/pvaclient-cpp/en/latest/
30 *
31 * @copyright
32 * - (c) 2002 The University of Chicago, as Operator of Argonne National Laboratory.
33 * - (c) 2002 The Regents of the University of California, as Operator of Los Alamos National Laboratory.
34 *
35 * @license
36 * This file is distributed under the terms of the Software License Agreement
37 * found in the file LICENSE included with this distribution.
38 *
39 * @authors
40 * R. Soliday,
41 */
42
43#include "pvaSDDS.h"
44#include <unordered_map>
45
46typedef std::unordered_multimap<std::string, long> Mymap;
47typedef std::unordered_multimap<std::string, long>::iterator MymapIterator;
48
49/*
50 Allocate memory for the pva structure.
51 repeats is currently only used for "get" requests where you plan to do statistics over a few readings.
52*/
53void allocPVA(PVA_OVERALL *pva, long PVs) {
54 allocPVA(pva, PVs, 0);
55}
56
57void allocPVA(PVA_OVERALL *pva, long PVs, long repeats) {
58 long i, j;
59 pva->numPVs = PVs;
60 pva->prevNumPVs = 0;
61 pva->pvaData = (PVA_DATA_ALL_READINGS *)malloc(sizeof(PVA_DATA_ALL_READINGS) * pva->numPVs);
62 if (repeats < 2) {
63 for (j = 0; j < pva->numPVs; j++) {
64 pva->pvaData[j].getData = (PVA_DATA *)malloc(sizeof(PVA_DATA));
65 pva->pvaData[j].getData[0].values = NULL;
66 pva->pvaData[j].getData[0].stringValues = NULL;
67 }
68 } else {
69 for (j = 0; j < pva->numPVs; j++) {
70 pva->pvaData[j].getData = (PVA_DATA *)malloc(sizeof(PVA_DATA) * repeats);
71 for (i = 0; i < repeats; i++) {
72 pva->pvaData[j].getData[i].values = NULL;
73 pva->pvaData[j].getData[i].stringValues = NULL;
74 }
75 }
76 }
77 for (j = 0; j < pva->numPVs; j++) {
78 pva->pvaData[j].putData = (PVA_DATA *)malloc(sizeof(PVA_DATA));
79 pva->pvaData[j].monitorData = (PVA_DATA *)malloc(sizeof(PVA_DATA));
80 pva->pvaData[j].putData[0].values = NULL;
81 pva->pvaData[j].putData[0].stringValues = NULL;
82 pva->pvaData[j].monitorData[0].values = NULL;
83 pva->pvaData[j].monitorData[0].stringValues = NULL;
84 }
85 for (j = 0; j < pva->numPVs; j++) {
86 pva->pvaData[j].numGetElements = 0;
87 pva->pvaData[j].numPutElements = 0;
88 pva->pvaData[j].numMonitorElements = 0;
89 pva->pvaData[j].numGetReadings = 0;
90 pva->pvaData[j].numMonitorReadings = 0; // Don't expect this to ever be greater than 1
91 pva->pvaData[j].numeric = false;
92 pva->pvaData[j].nonnumeric = false;
93 pva->pvaData[j].pvEnumeratedStructure = false;
94 pva->pvaData[j].haveGetPtr = false;
95 pva->pvaData[j].havePutPtr = false;
96 pva->pvaData[j].haveMonitorPtr = false;
97 pva->pvaData[j].units = NULL;
98 pva->pvaData[j].alarmSeverity = 0;
99 pva->pvaData[j].L1Ptr = j;
100 pva->pvaData[j].L2Ptr = j;
101 pva->pvaData[j].skip = false;
102 }
103 pva->numNotConnected = PVs;
104 pva->limitGetReadings = false;
105 pva->useStateChangeCallbacks = false;
106 pva->useGetCallbacks = false;
107 pva->useMonitorCallbacks = false;
108 pva->usePutCallbacks = false;
109 pva->includeAlarmSeverity = false;
110
111 pva->numMultiChannels = 1;
112 pva->pvaClientMultiChannelPtr.resize(pva->numMultiChannels);
113
114 pva->pvaClientGetPtr.resize(pva->numPVs);
115 pva->pvaClientPutPtr.resize(pva->numPVs);
116 pva->pvaClientMonitorPtr.resize(pva->numPVs);
117
118 return;
119}
120
121void reallocPVA(PVA_OVERALL *pva, long PVs) {
122 reallocPVA(pva, PVs, 0);
123}
124
125void reallocPVA(PVA_OVERALL *pva, long PVs, long repeats) {
126 long i, j;
127 pva->prevNumPVs = pva->numPVs;
128 pva->numPVs = PVs;
129 pva->pvaData = (PVA_DATA_ALL_READINGS *)realloc(pva->pvaData, sizeof(PVA_DATA_ALL_READINGS) * pva->numPVs);
130 pva->pvaChannelNames.resize(pva->numPVs);
131 pva->pvaProvider.resize(pva->numPVs);
132
133 if (repeats < 2) {
134 for (j = pva->prevNumPVs; j < pva->numPVs; j++) {
135 pva->pvaData[j].getData = (PVA_DATA *)malloc(sizeof(PVA_DATA));
136 pva->pvaData[j].getData[0].values = NULL;
137 pva->pvaData[j].getData[0].stringValues = NULL;
138 }
139 } else {
140 for (j = pva->prevNumPVs; j < pva->numPVs; j++) {
141 pva->pvaData[j].getData = (PVA_DATA *)malloc(sizeof(PVA_DATA) * repeats);
142 for (i = 0; i < repeats; i++) {
143 pva->pvaData[j].getData[i].values = NULL;
144 pva->pvaData[j].getData[i].stringValues = NULL;
145 }
146 }
147 }
148 for (j = pva->prevNumPVs; j < pva->numPVs; j++) {
149 pva->pvaData[j].putData = (PVA_DATA *)malloc(sizeof(PVA_DATA));
150 pva->pvaData[j].monitorData = (PVA_DATA *)malloc(sizeof(PVA_DATA));
151 pva->pvaData[j].putData[0].values = NULL;
152 pva->pvaData[j].putData[0].stringValues = NULL;
153 pva->pvaData[j].monitorData[0].values = NULL;
154 pva->pvaData[j].monitorData[0].stringValues = NULL;
155 }
156 for (j = pva->prevNumPVs; j < pva->numPVs; j++) {
157 pva->pvaData[j].numGetElements = 0;
158 pva->pvaData[j].numPutElements = 0;
159 pva->pvaData[j].numMonitorElements = 0;
160 pva->pvaData[j].numGetReadings = 0;
161 pva->pvaData[j].numMonitorReadings = 0; // Don't expect this to ever be greater than 1
162 pva->pvaData[j].numeric = false;
163 pva->pvaData[j].nonnumeric = false;
164 pva->pvaData[j].pvEnumeratedStructure = false;
165 pva->pvaData[j].haveGetPtr = false;
166 pva->pvaData[j].havePutPtr = false;
167 pva->pvaData[j].haveMonitorPtr = false;
168 pva->pvaData[j].units = NULL;
169 pva->pvaData[j].alarmSeverity = 0;
170 pva->pvaData[j].L1Ptr = j;
171 pva->pvaData[j].L2Ptr = j;
172 pva->pvaData[j].skip = false;
173 }
174 pva->numNotConnected += pva->numPVs - pva->prevNumPVs;
175
176 pva->numMultiChannels++;
177 pva->pvaClientMultiChannelPtr.resize(pva->numMultiChannels);
178
179 pva->pvaClientGetPtr.resize(pva->numPVs);
180 pva->pvaClientPutPtr.resize(pva->numPVs);
181 pva->pvaClientMonitorPtr.resize(pva->numPVs);
182
183 return;
184}
185
186/*
187 Free memory for the pva structure.
188*/
189void freePVA(PVA_OVERALL *pva) {
190 long i, j, k;
191
192 if (pva == NULL) {
193 return;
194 }
195 for (i = 0; i < pva->numPVs; i++) {
196 //get variables
197 for (j = 0; j < pva->pvaData[i].numGetReadings; j++) {
198 if (pva->pvaData[i].getData[j].values) {
199 free(pva->pvaData[i].getData[j].values);
200 }
201 if (pva->pvaData[i].getData[j].stringValues) {
202 for (k = 0; k < pva->pvaData[i].numGetElements; k++) {
203 if (pva->pvaData[i].getData[j].stringValues[k])
204 free(pva->pvaData[i].getData[j].stringValues[k]);
205 }
206 free(pva->pvaData[i].getData[j].stringValues);
207 }
208 }
209 //monitor variables
210 if (pva->pvaData[i].monitorData[0].values) {
211 free(pva->pvaData[i].monitorData[0].values);
212 }
213 if (pva->pvaData[i].monitorData[0].stringValues) {
214 for (k = 0; k < pva->pvaData[i].numMonitorElements; k++) {
215 if (pva->pvaData[i].monitorData[0].stringValues[k])
216 free(pva->pvaData[i].monitorData[0].stringValues[k]);
217 }
218 free(pva->pvaData[i].monitorData[0].stringValues);
219 }
220 //put variables
221 if (pva->pvaData[i].putData[0].values) {
222 free(pva->pvaData[i].putData[0].values);
223 }
224 if (pva->pvaData[i].putData[0].stringValues) {
225 //Do not free the individual strings here. They are freed in PutPVAValues
226 free(pva->pvaData[i].putData[0].stringValues);
227 }
228 //pva client pointers
229 if (pva->pvaData[i].haveGetPtr == false) {
230 pva->pvaClientGetPtr[i].reset();
231 }
232 if (pva->pvaData[i].havePutPtr == false) {
233 pva->pvaClientPutPtr[i].reset();
234 }
235 if (pva->pvaData[i].haveMonitorPtr == false) {
236 pva->pvaClientMonitorPtr[i].reset();
237 }
238
239 free(pva->pvaData[i].getData);
240 free(pva->pvaData[i].putData);
241 free(pva->pvaData[i].monitorData);
242 if (pva->pvaData[i].units) {
243 free(pva->pvaData[i].units);
244 }
245 }
246 free(pva->pvaData);
247
248 return;
249}
250
251/*
252 Free the "get" readings
253*/
254void freePVAGetReadings(PVA_OVERALL *pva) {
255 long i, j, k;
256 if (pva == NULL) {
257 return;
258 }
259 for (i = 0; i < pva->numPVs; i++) {
260 if (pva->pvaData[i].skip == true) {
261 continue;
262 }
263 for (j = 0; j < pva->pvaData[i].numGetReadings; j++) {
264 if (pva->limitGetReadings == false) {
265 if (pva->pvaData[i].getData[j].values) {
266 free(pva->pvaData[i].getData[j].values);
267 pva->pvaData[i].getData[j].values = NULL;
268 }
269 }
270 if (pva->pvaData[i].getData[j].stringValues) {
271 for (k = 0; k < pva->pvaData[i].numGetElements; k++) {
272 if (pva->pvaData[i].getData[j].stringValues[k]) {
273 free(pva->pvaData[i].getData[j].stringValues[k]);
274 pva->pvaData[i].getData[j].stringValues[k] = NULL;
275 }
276 }
277 if (pva->limitGetReadings == false) {
278 free(pva->pvaData[i].getData[j].stringValues);
279 pva->pvaData[i].getData[j].stringValues = NULL;
280 }
281 }
282 }
283 if (pva->limitGetReadings == false) {
284 pva->pvaData[i].numGetReadings = 0;
285 }
286 }
287 return;
288}
289
290/*
291 Free the "monitor" readings
292*/
293void freePVAMonitorReadings(PVA_OVERALL *pva) {
294 long i, k;
295 if (pva == NULL) {
296 return;
297 }
298 for (i = 0; i < pva->numPVs; i++) {
299 if (pva->pvaData[i].skip == true) {
300 continue;
301 }
302 if (pva->pvaData[i].monitorData[0].values) {
303 free(pva->pvaData[i].monitorData[0].values);
304 pva->pvaData[i].monitorData[0].values = NULL;
305 }
306 if (pva->pvaData[i].monitorData[0].stringValues) {
307 for (k = 0; k < pva->pvaData[i].numMonitorElements; k++) {
308 if (pva->pvaData[i].monitorData[0].stringValues[k])
309 free(pva->pvaData[i].monitorData[0].stringValues[k]);
310 }
311 free(pva->pvaData[i].monitorData[0].stringValues);
312 pva->pvaData[i].monitorData[0].stringValues = NULL;
313 }
314 pva->pvaData[i].numMonitorReadings = 0;
315 }
316 return;
317}
318
319/*
320 Connect to the PVs using PvaClientMultiChannel
321*/
322void ConnectPVA(PVA_OVERALL *pva, double pendIOTime) {
323 long i, j, n, num = 0, numInternalPVs;
324 size_t pos;
325 epics::pvData::shared_vector<std::string> namesTmp(pva->numPVs);
326 epics::pvData::shared_vector<std::string> subnames(pva->numPVs);
327 epics::pvData::Status status;
328 epics::pvaClient::PvaClientChannelArray pvaClientChannelArray;
329 epics::pvData::shared_vector<epics::pvData::boolean> connected(pva->numPVs);
330 Mymap m;
331 MymapIterator mIter;
332
333 i = n = 0;
334 for (j = 0; j < pva->numPVs; j++) {
335 if (pva->pvaProvider[j].compare("pva") == 0) {
336 pos = pva->pvaChannelNames[j].find('.');
337 if (pos == std::string::npos) {
338 namesTmp[j] = pva->pvaChannelNames[j];
339 subnames[j] = "";
340 } else {
341 namesTmp[j] = pva->pvaChannelNames[j].substr(0, pos);
342 subnames[j] = pva->pvaChannelNames[j].substr(pos + 1);
343 }
344 } else {
345 namesTmp[j] = pva->pvaChannelNames[j];
346 subnames[j] = "";
347 }
348 mIter = m.find(namesTmp[j]);
349 if (mIter == m.end()) {
350 m.insert(Mymap::value_type(namesTmp[j], j));
351 pva->pvaData[j].L1Ptr = j;
352 pva->pvaData[j].L2Ptr = i;
353 i++;
354 } else {
355 pva->pvaData[j].L1Ptr = mIter->second;
356 pva->pvaData[j].L2Ptr = pva->pvaData[pva->pvaData[j].L1Ptr].L2Ptr;
357 }
358 }
359
360 if (pva->numMultiChannels == 1) {
361 pva->numInternalPVs = numInternalPVs = i;
362 epics::pvData::shared_vector<std::string> names(pva->numInternalPVs);
363 epics::pvData::shared_vector<std::string> provider(pva->numInternalPVs);
364 epics::pvData::shared_vector<const std::string> constProvider;
365
366 for (j = 0; j < pva->numPVs; j++) {
367 names[pva->pvaData[j].L2Ptr] = namesTmp[j];
368 provider[pva->pvaData[j].L2Ptr] = pva->pvaProvider[j];
369 }
370 pva->pvaChannelNamesTop = freeze(names);
371 pva->pvaChannelNamesSub = freeze(subnames);
372 constProvider = freeze(provider);
373 //Connect to PVs all at once
374 pva->pvaClientPtr = epics::pvaClient::PvaClient::get("pva ca");
375 //pva->pvaClientPtr->setDebug(true);
376 pva->pvaClientMultiChannelPtr[0] = epics::pvaClient::PvaClientMultiChannel::create(pva->pvaClientPtr, pva->pvaChannelNamesTop, "pva", numInternalPVs, constProvider);
377 status = pva->pvaClientMultiChannelPtr[0]->connect(pendIOTime);
378
379 pva->isInternalConnected = pva->pvaClientMultiChannelPtr[0]->getIsConnected();
380
381 pvaClientChannelArray = pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray();
382 } else {
383 //This will execute if we are adding additional PVs. It is sort of a hack
384 pva->prevNumInternalPVs = pva->numInternalPVs;
385 pva->numInternalPVs = i;
386 numInternalPVs = pva->numInternalPVs - pva->prevNumInternalPVs;
387 epics::pvData::shared_vector<std::string> names(pva->numInternalPVs);
388 epics::pvData::shared_vector<std::string> newnames(numInternalPVs);
389 epics::pvData::shared_vector<std::string> provider(numInternalPVs);
390 epics::pvData::shared_vector<const std::string> constNames;
391
392 epics::pvData::shared_vector<const std::string> constProvider;
393
394 for (j = 0; j < pva->numPVs; j++) {
395 names[pva->pvaData[j].L2Ptr] = namesTmp[j];
396 if (pva->pvaData[j].L2Ptr >= pva->prevNumInternalPVs) {
397 newnames[pva->pvaData[j].L2Ptr - pva->prevNumInternalPVs] = namesTmp[j];
398 provider[pva->pvaData[j].L2Ptr - pva->prevNumInternalPVs] = pva->pvaProvider[j];
399 }
400 }
401 pva->pvaChannelNamesTop = freeze(names);
402 pva->pvaChannelNamesSub = freeze(subnames);
403 constNames = freeze(newnames);
404 constProvider = freeze(provider);
405
406 pva->pvaClientMultiChannelPtr[pva->numMultiChannels - 1] = epics::pvaClient::PvaClientMultiChannel::create(pva->pvaClientPtr, constNames, "pva", numInternalPVs, constProvider);
407 status = pva->pvaClientMultiChannelPtr[pva->numMultiChannels - 1]->connect(pendIOTime);
408
409 pva->isInternalConnected = pva->pvaClientMultiChannelPtr[0]->getIsConnected();
410 for (j = 1; j < pva->numMultiChannels; j++) {
411 epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
412 isConnected = pva->pvaClientMultiChannelPtr[j]->getIsConnected();
413 std::copy(isConnected.begin(), isConnected.end(), std::back_inserter(pva->isInternalConnected));
414 }
415 pvaClientChannelArray = pva->pvaClientMultiChannelPtr[pva->numMultiChannels - 1]->getPvaClientChannelArray();
416 }
417
418 for (j = 0; j < pva->numPVs; j++) {
419 connected[j] = pva->isInternalConnected[pva->pvaData[j].L2Ptr];
420 if (connected[j] == false) {
421 num++;
422 }
423 }
424 pva->isConnected = connected;
425 pva->numNotConnected = num;
426 for (j = 0; j < numInternalPVs; j++) {
427 if (pva->useStateChangeCallbacks) {
428 pvaClientChannelArray[j]->setStateChangeRequester((epics::pvaClient::PvaClientChannelStateChangeRequesterPtr)pva->stateChangeReqPtr);
429 }
430 }
431}
432
433/*
434 Read the PV values over the network and place the values in the pva structure.
435*/
436long GetPVAValues(PVA_OVERALL *pva) {
437 long result;
438 PVA_OVERALL **pvaArray;
439 pvaArray = (PVA_OVERALL **)malloc(sizeof(PVA_OVERALL *));
440 pvaArray[0] = pva;
441 result = GetPVAValues(pvaArray, 1);
442 free(pvaArray);
443 return (result);
444}
445
446long GetPVAValuesOld(PVA_OVERALL **pva, long count) {
447 long i, num = 0, n;
448 epics::pvData::Status status;
449 epics::pvaClient::PvaClientChannelArray pvaClientChannelArray;
450
451 for (n = 0; n < count; n++) {
452 if (pva[n] != NULL) {
453 pva[n]->isInternalConnected = pva[n]->pvaClientMultiChannelPtr[0]->getIsConnected();
454 pvaClientChannelArray = pva[n]->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray();
455 for (i = 1; i < pva[n]->numMultiChannels; i++) {
456 epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
457 epics::pvaClient::PvaClientChannelArray pvaClientChannelArrayAdd;
458 isConnected = pva[n]->pvaClientMultiChannelPtr[i]->getIsConnected();
459 std::copy(isConnected.begin(), isConnected.end(), std::back_inserter(pva[n]->isInternalConnected));
460 pvaClientChannelArrayAdd = pva[n]->pvaClientMultiChannelPtr[i]->getPvaClientChannelArray();
461 std::copy(pvaClientChannelArrayAdd.begin(), pvaClientChannelArrayAdd.end(), std::back_inserter(pvaClientChannelArray));
462 }
463 for (i = 0; i < pva[n]->numPVs; i++) {
464 if (pva[n]->pvaData[i].skip == true) {
465 continue;
466 }
467 pva[n]->isConnected[i] = pva[n]->isInternalConnected[pva[n]->pvaData[i].L2Ptr];
468 if (pva[n]->isConnected[i]) {
469 if (pva[n]->pvaData[i].haveGetPtr == false) {
470 pva[n]->pvaClientGetPtr[i] = pvaClientChannelArray[pva[n]->pvaData[i].L2Ptr]->createGet(pva[n]->pvaChannelNamesSub[i]);
471 pva[n]->pvaData[i].haveGetPtr = true;
472 if (pva[n]->useGetCallbacks) {
473 pva[n]->pvaClientGetPtr[i]->setRequester((epics::pvaClient::PvaClientGetRequesterPtr)pva[n]->getReqPtr);
474 }
475 }
476 try {
477 pva[n]->pvaClientGetPtr[i]->issueGet();
478 } catch (std::exception &e) {
479 num++;
480 pva[n]->isConnected[i] = false;
481 //std::cerr << "Error: invalid sub-field name: " + pva[n]->pvaChannelNamesSub[i] + "\n";
482 //return 1;
483 }
484 } else {
485 num++;
486 }
487 }
488 pva[n]->numNotConnected = num;
489 }
490 }
491
492 for (n = 0; n < count; n++) {
493 if ((pva[n] != NULL) && (pva[n]->useGetCallbacks == false)) {
494 for (i = 0; i < pva[n]->numPVs; i++) {
495 if (pva[n]->pvaData[i].skip == true) {
496 continue;
497 }
498 if (pva[n]->isConnected[i]) {
499 status = pva[n]->pvaClientGetPtr[i]->waitGet();
500 if (!status.isSuccess()) {
501 fprintf(stderr, "error: %s did not respond to the \"get\" request\n", pva[n]->pvaChannelNames[i].c_str());
502 pva[n]->isConnected[i] = false;
503 pva[n]->numNotConnected++;
504 //return (1);
505 }
506 }
507 }
508 }
509 }
510 for (n = 0; n < count; n++) {
511 if ((pva[n] != NULL) && (pva[n]->useGetCallbacks == false)) {
512 if (ExtractPVAValues(pva[n]) == 1) {
513 return (1);
514 }
515 }
516 }
517 return (0);
518}
519
520std::string convertToProperRequestFormat(const std::vector<std::string>& input) {
521 std::map<std::string, std::set<std::string>> prefixMap;
522
523 // Populate the map with prefixes and their associated suffixes
524 for (const auto& str : input) {
525 size_t pos = str.find('.');
526 if (pos != std::string::npos) {
527 std::string prefix = str.substr(0, pos);
528 std::string suffix = str.substr(pos + 1);
529 prefixMap[prefix].insert(suffix);
530 } else {
531 prefixMap[str]; // Ensure even elements without a suffix are added
532 }
533 }
534
535 // Construct the final string
536 std::ostringstream result;
537 bool first = true;
538
539 for (const auto& pair : prefixMap) {
540 if (!first) {
541 result << ',';
542 }
543 first = false;
544 result << pair.first;
545 if (!pair.second.empty()) {
546 result << '{';
547 bool firstSuffix = true;
548 for (const auto& suffix : pair.second) {
549 if (!firstSuffix) {
550 result << ',';
551 }
552 firstSuffix = false;
553 result << suffix;
554 }
555 result << '}';
556 }
557 }
558
559 return result.str();
560}
561
562long GetPVAValues(PVA_OVERALL **pva, long count) {
563 long i, ii, num = 0, n;
564 epics::pvData::Status status;
565 epics::pvaClient::PvaClientChannelArray pvaClientChannelArray;
566 std::ostringstream pvaFields;
567
568 for (n = 0; n < count; n++) {
569 if (pva[n] != NULL) {
570 std::vector<bool> isInternalGetIssued(pva[n]->numInternalPVs, false);
571 std::vector<long> InternalGetIndex(pva[n]->numInternalPVs, 0);
572 pva[n]->isInternalConnected = pva[n]->pvaClientMultiChannelPtr[0]->getIsConnected();
573 pvaClientChannelArray = pva[n]->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray();
574 for (i = 1; i < pva[n]->numMultiChannels; i++) {
575 epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
576 epics::pvaClient::PvaClientChannelArray pvaClientChannelArrayAdd;
577 isConnected = pva[n]->pvaClientMultiChannelPtr[i]->getIsConnected();
578 std::copy(isConnected.begin(), isConnected.end(), std::back_inserter(pva[n]->isInternalConnected));
579 pvaClientChannelArrayAdd = pva[n]->pvaClientMultiChannelPtr[i]->getPvaClientChannelArray();
580 std::copy(pvaClientChannelArrayAdd.begin(), pvaClientChannelArrayAdd.end(), std::back_inserter(pvaClientChannelArray));
581 }
582 for (i = 0; i < pva[n]->numPVs; i++) {
583 if (pva[n]->pvaData[i].skip == true) {
584 continue;
585 }
586 pva[n]->isConnected[i] = pva[n]->isInternalConnected[pva[n]->pvaData[i].L2Ptr];
587 if (pva[n]->isConnected[i]) {
588 if (pva[n]->pvaProvider[i].compare("pva") != 0) {
589 // CA PVs
590 if (pva[n]->pvaData[i].haveGetPtr == false) {
591 pva[n]->pvaClientGetPtr[i] = pvaClientChannelArray[pva[n]->pvaData[i].L2Ptr]->createGet(pva[n]->pvaChannelNamesSub[i]);
592 pva[n]->pvaData[i].haveGetPtr = true;
593 if (pva[n]->useGetCallbacks) {
594 pva[n]->pvaClientGetPtr[i]->setRequester((epics::pvaClient::PvaClientGetRequesterPtr)pva[n]->getReqPtr);
595 }
596 }
597 } else {
598 //PVA PVs
599 if (pva[n]->pvaData[i].haveGetPtr == false) {
600 if (isInternalGetIssued[pva[n]->pvaData[i].L2Ptr] == false) {
601 std::vector<std::string> stringArray;
602 stringArray.push_back(pva[n]->pvaChannelNamesSub[i]);
603 for (ii = i+1; ii < pva[n]->numPVs; ii++) {
604 if (pva[n]->pvaData[ii].skip == true) {
605 continue;
606 }
607 if (pva[n]->pvaData[i].L2Ptr ==pva[n]->pvaData[ii].L2Ptr) {
608 stringArray.push_back(pva[n]->pvaChannelNamesSub[ii]);
609 }
610 }
611 std::string fieldNames = convertToProperRequestFormat(stringArray);
612 pva[n]->pvaClientGetPtr[i] = pvaClientChannelArray[pva[n]->pvaData[i].L2Ptr]->createGet(fieldNames);
613 isInternalGetIssued[pva[n]->pvaData[i].L2Ptr] = true;
614 InternalGetIndex[pva[n]->pvaData[i].L2Ptr] = i;
615 pva[n]->pvaData[i].haveGetPtr = true;
616 if (pva[n]->useGetCallbacks) {
617 // This need to be tested now that we are sharing a get requests for a single PVA PV
618 pva[n]->pvaClientGetPtr[i]->setRequester((epics::pvaClient::PvaClientGetRequesterPtr)pva[n]->getReqPtr);
619 }
620 } else {
621 //pva[n]->pvaData[i].haveGetPtr = false;
622 pva[n]->pvaClientGetPtr[i] = pva[n]->pvaClientGetPtr[InternalGetIndex[pva[n]->pvaData[i].L2Ptr]];
623 }
624 } else {
625 //If we call GetPVAValues a second time, this is needed
626 //This code will not work if subsequent calls require more fields than the original call
627 isInternalGetIssued[pva[n]->pvaData[i].L2Ptr] = true;
628 InternalGetIndex[pva[n]->pvaData[i].L2Ptr] = i;
629 }
630 }
631
632 if (pva[n]->pvaData[i].haveGetPtr) {
633 try {
634 pva[n]->pvaClientGetPtr[i]->issueGet();
635 } catch (std::exception &e) {
636 num++;
637 pva[n]->isConnected[i] = false;
638 }
639 }
640 } else {
641 //Not connected
642 num++;
643 }
644 }
645 pva[n]->numNotConnected = num;
646 }
647 }
648 for (n = 0; n < count; n++) {
649 if ((pva[n] != NULL) && (pva[n]->useGetCallbacks == false)) {
650 for (i = 0; i < pva[n]->numPVs; i++) {
651 if (pva[n]->pvaData[i].skip == true) {
652 continue;
653 }
654 if (pva[n]->isConnected[i] && pva[n]->pvaData[i].haveGetPtr) {
655 status = pva[n]->pvaClientGetPtr[i]->waitGet();
656 if (!status.isSuccess()) {
657 fprintf(stderr, "error: %s did not respond to the \"get\" request\n", pva[n]->pvaChannelNames[i].c_str());
658 pva[n]->isConnected[i] = false;
659 pva[n]->numNotConnected++;
660 //return (1);
661 }
662 }
663 }
664 }
665 }
666 for (n = 0; n < count; n++) {
667 if ((pva[n] != NULL) && (pva[n]->useGetCallbacks == false)) {
668 if (ExtractPVAValues(pva[n]) == 1) {
669 return (1);
670 }
671 }
672 }
673 return (0);
674}
675
676long ExtractScalarValue(PVA_OVERALL *pva, long index, epics::pvData::PVFieldPtr PVFieldPtr, bool monitorMode) {
677 epics::pvData::ScalarConstPtr scalarConstPtr;
678 epics::pvData::PVScalarPtr pvScalarPtr;
679 long i = 0;
680 scalarConstPtr = std::tr1::static_pointer_cast<const epics::pvData::Scalar>(PVFieldPtr->getField());
681 pvScalarPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalar>(PVFieldPtr);
682
683 if (monitorMode) {
684 i = 0;
685 if (pva->pvaData[index].numMonitorReadings == 0) {
686 pva->pvaData[index].fieldType = scalarConstPtr->getType(); //should always be epics::pvData::scalar
687 pva->pvaData[index].scalarType = scalarConstPtr->getScalarType();
688 pva->pvaData[index].numMonitorElements = 1;
689 } else {
690 if (pva->pvaData[index].nonnumeric) {
691 if (pva->pvaData[index].monitorData[0].stringValues[0])
692 free(pva->pvaData[index].monitorData[0].stringValues[0]);
693 }
694 }
695 } else {
696 i = pva->pvaData[index].numGetReadings;
697 if (pva->pvaData[index].numGetReadings == 0) {
698 pva->pvaData[index].fieldType = scalarConstPtr->getType(); //should always be epics::pvData::scalar
699 pva->pvaData[index].scalarType = scalarConstPtr->getScalarType();
700 pva->pvaData[index].numGetElements = 1;
701 } else if (pva->limitGetReadings) {
702 i = 0;
703 }
704 }
705 switch (pva->pvaData[index].scalarType) {
706 case epics::pvData::pvDouble:
707 case epics::pvData::pvFloat:
708 case epics::pvData::pvLong:
709 case epics::pvData::pvULong:
710 case epics::pvData::pvInt:
711 case epics::pvData::pvUInt:
712 case epics::pvData::pvShort:
713 case epics::pvData::pvUShort:
714 case epics::pvData::pvByte:
715 case epics::pvData::pvUByte: {
716 if (monitorMode) {
717 if (pva->pvaData[index].monitorData[0].values == NULL) {
718 pva->pvaData[index].monitorData[0].values = (double *)malloc(sizeof(double));
719 pva->pvaData[index].numeric = true;
720 }
721 pva->pvaData[index].monitorData[0].values[0] = pvScalarPtr->getAs<double>();
722 } else {
723 if (pva->pvaData[index].getData[i].values == NULL) {
724 pva->pvaData[index].getData[i].values = (double *)malloc(sizeof(double));
725 pva->pvaData[index].numeric = true;
726 }
727 pva->pvaData[index].getData[i].values[0] = pvScalarPtr->getAs<double>();
728 }
729 break;
730 }
731 case epics::pvData::pvString:
732 case epics::pvData::pvBoolean: {
733 std::string s = pvScalarPtr->getAs<std::string>();
734 if (monitorMode) {
735 if (pva->pvaData[index].monitorData[0].stringValues == NULL) {
736 pva->pvaData[index].monitorData[0].stringValues = (char **)malloc(sizeof(char *) * 1);
737 }
738 pva->pvaData[index].monitorData[0].stringValues[0] = (char *)malloc(sizeof(char) * (s.length() + 1));
739 strcpy(pva->pvaData[index].monitorData[0].stringValues[0], s.c_str());
740 if (pva->pvaData[index].numMonitorReadings == 0) {
741 pva->pvaData[index].nonnumeric = true;
742 }
743 } else {
744 if (pva->pvaData[index].getData[i].stringValues == NULL) {
745 pva->pvaData[index].getData[i].stringValues = (char **)malloc(sizeof(char *) * 1);
746 }
747 pva->pvaData[index].getData[i].stringValues[0] = (char *)malloc(sizeof(char) * (s.length() + 1));
748 strcpy(pva->pvaData[index].getData[i].stringValues[0], s.c_str());
749 if (pva->pvaData[index].numGetReadings == 0) {
750 pva->pvaData[index].nonnumeric = true;
751 }
752 }
753 break;
754 }
755 default: {
756 std::cerr << "ERROR: Need code to handle scalar type " << pva->pvaData[index].scalarType << std::endl;
757 return (1);
758 }
759 }
760 if (monitorMode) {
761 pva->pvaData[index].numMonitorReadings = 1;
762 } else {
763 if (pva->limitGetReadings) {
764 pva->pvaData[index].numGetReadings = 1;
765 } else {
766 pva->pvaData[index].numGetReadings++;
767 }
768 }
769 return (0);
770}
771
772long ExtractNTScalarValue(PVA_OVERALL *pva, long index, epics::pvData::PVStructurePtr pvStructurePtr, bool monitorMode) {
773 long j, fieldCount;
774 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
775 std::string fieldName;
776 PVFieldPtrArray = pvStructurePtr->getPVFields();
777 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
778 for (j = 0; j < fieldCount; j++) {
779 fieldName = PVFieldPtrArray[j]->getFieldName();
780 if (fieldName == "value") {
781 if (ExtractScalarValue(pva, index, PVFieldPtrArray[j], monitorMode)) {
782 return (1);
783 }
784 return (0);
785 }
786 }
787 std::cerr << "ERROR: Value field is missing." << std::endl;
788 return (1);
789}
790
791long ExtractScalarArrayValue(PVA_OVERALL *pva, long index, epics::pvData::PVFieldPtr PVFieldPtr, bool monitorMode) {
792 epics::pvData::ScalarArrayConstPtr scalarArrayConstPtr;
793 epics::pvData::PVScalarArrayPtr pvScalarArrayPtr;
794 long i = 0;
795 scalarArrayConstPtr = std::tr1::static_pointer_cast<const epics::pvData::ScalarArray>(PVFieldPtr->getField());
796 pvScalarArrayPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalarArray>(PVFieldPtr);
797
798 if (monitorMode) {
799 i = 0;
800 if (pva->pvaData[index].numMonitorReadings == 0) {
801 pva->pvaData[index].fieldType = scalarArrayConstPtr->getType(); //should always be epics::pvData::scalar
802 pva->pvaData[index].scalarType = scalarArrayConstPtr->getElementType();
803 pva->pvaData[index].numMonitorElements = pvScalarArrayPtr->getLength();
804 } else {
805 if (pva->pvaData[index].nonnumeric) {
806 for (long k = 0; k < pva->pvaData[index].numMonitorElements; k++) {
807 if (pva->pvaData[index].monitorData[0].stringValues[k])
808 free(pva->pvaData[index].monitorData[0].stringValues[k]);
809 }
810 }
811 }
812 } else {
813 i = pva->pvaData[index].numGetReadings;
814 if (pva->pvaData[index].numGetReadings == 0) {
815 pva->pvaData[index].fieldType = scalarArrayConstPtr->getType(); //should always be epics::pvData::scalar
816 pva->pvaData[index].scalarType = scalarArrayConstPtr->getElementType();
817 pva->pvaData[index].numGetElements = pvScalarArrayPtr->getLength();
818 } else if (pva->limitGetReadings) {
819 i = 0;
820 }
821 }
822 switch (pva->pvaData[index].scalarType) {
823 case epics::pvData::pvDouble:
824 case epics::pvData::pvFloat:
825 case epics::pvData::pvLong:
826 case epics::pvData::pvULong:
827 case epics::pvData::pvInt:
828 case epics::pvData::pvUInt:
829 case epics::pvData::pvShort:
830 case epics::pvData::pvUShort: {
831 epics::pvData::PVDoubleArray::const_svector dataVector;
832 pvScalarArrayPtr->PVScalarArray::getAs<double>(dataVector);
833 if (monitorMode) {
834 if (pva->pvaData[index].monitorData[0].values == NULL) {
835 pva->pvaData[index].monitorData[0].values = (double *)malloc(sizeof(double) * pva->pvaData[index].numMonitorElements);
836 pva->pvaData[index].numeric = true;
837 }
838 std::copy(dataVector.begin(), dataVector.begin() + pva->pvaData[index].numMonitorElements, pva->pvaData[index].monitorData[0].values);
839 } else {
840 if (pva->pvaData[index].getData[i].values == NULL) {
841 pva->pvaData[index].getData[i].values = (double *)malloc(sizeof(double) * pva->pvaData[index].numGetElements);
842 pva->pvaData[index].numeric = true;
843 }
844 std::copy(dataVector.begin(), dataVector.begin() + pva->pvaData[index].numGetElements, pva->pvaData[index].getData[i].values);
845 }
846 break;
847 }
848 case epics::pvData::pvByte:
849 case epics::pvData::pvUByte: {
850 //Special code for byte arrays which are usutally strings
851 epics::pvData::PVDoubleArray::const_svector dataVector;
852 int nLength;
853 pvScalarArrayPtr->PVScalarArray::getAs<double>(dataVector);
854 nLength = dataVector.size();
855 if (nLength < 256) {
856 nLength = 256;
857 }
858 if (monitorMode) {
859 if (pva->pvaData[index].monitorData[0].values == NULL) {
860 pva->pvaData[index].monitorData[0].values = (double *)malloc(sizeof(double) * nLength);
861 pva->pvaData[index].numeric = true;
862 }
863 std::copy(dataVector.begin(), dataVector.end(), pva->pvaData[index].monitorData[0].values);
864 for (long k = dataVector.size(); k < 256; k++) {
865 pva->pvaData[index].monitorData[0].values[k] = 0;
866 }
867 } else {
868 if (pva->pvaData[index].getData[i].values == NULL) {
869 pva->pvaData[index].getData[i].values = (double *)malloc(sizeof(double) * nLength);
870 pva->pvaData[index].numeric = true;
871 }
872 std::copy(dataVector.begin(), dataVector.end(), pva->pvaData[index].getData[i].values);
873 for (long k = dataVector.size(); k < 256; k++) {
874 pva->pvaData[index].getData[i].values[k] = 0;
875 }
876 }
877 if (pvScalarArrayPtr->isCapacityMutable() && (pvScalarArrayPtr->getCapacity() <= 256)) {
878 pvScalarArrayPtr->setCapacity(256);
879 pvScalarArrayPtr->setLength(256);
880 if (monitorMode) {
881 pva->pvaData[index].numMonitorElements = 256;
882 } else {
883 pva->pvaData[index].numGetElements = 256;
884 }
885 }
886 break;
887 }
888 case epics::pvData::pvString:
889 case epics::pvData::pvBoolean: {
890 epics::pvData::PVStringArray::const_svector dataVector;
891 pvScalarArrayPtr->PVScalarArray::getAs<std::string>(dataVector);
892 if (monitorMode) {
893 if (pva->pvaData[index].monitorData[0].stringValues == NULL) {
894 pva->pvaData[index].monitorData[0].stringValues = (char **)malloc(sizeof(char *) * pva->pvaData[index].numMonitorElements);
895 pva->pvaData[index].nonnumeric = true;
896 }
897 for (long k = 0; k < pva->pvaData[index].numMonitorElements; k++) {
898 pva->pvaData[index].monitorData[0].stringValues[k] = (char *)malloc(sizeof(char) * (dataVector[k].length() + 1));
899 strcpy(pva->pvaData[index].monitorData[0].stringValues[k], dataVector[k].c_str());
900 }
901 } else {
902 if (pva->pvaData[index].getData[i].stringValues == NULL) {
903 pva->pvaData[index].getData[i].stringValues = (char **)malloc(sizeof(char *) * pva->pvaData[index].numGetElements);
904 pva->pvaData[index].nonnumeric = true;
905 }
906 for (long k = 0; k < pva->pvaData[index].numGetElements; k++) {
907 pva->pvaData[index].getData[i].stringValues[k] = (char *)malloc(sizeof(char) * (dataVector[k].length() + 1));
908 strcpy(pva->pvaData[index].getData[i].stringValues[k], dataVector[k].c_str());
909 }
910 }
911 break;
912 }
913 default: {
914 std::cerr << "ERROR: Need code to handle scalar array type " << pva->pvaData[index].scalarType << std::endl;
915 return (1);
916 }
917 }
918 if (monitorMode) {
919 pva->pvaData[index].numMonitorReadings = 1;
920 } else {
921 if (pva->limitGetReadings) {
922 pva->pvaData[index].numGetReadings = 1;
923 } else {
924 pva->pvaData[index].numGetReadings++;
925 }
926 }
927 return (0);
928}
929
930long ExtractNTScalarArrayValue(PVA_OVERALL *pva, long index, epics::pvData::PVStructurePtr pvStructurePtr, bool monitorMode) {
931 long j, fieldCount;
932 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
933 std::string fieldName;
934 PVFieldPtrArray = pvStructurePtr->getPVFields();
935 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
936 for (j = 0; j < fieldCount; j++) {
937 fieldName = PVFieldPtrArray[j]->getFieldName();
938 if (fieldName == "value") {
939 if (ExtractScalarArrayValue(pva, index, PVFieldPtrArray[j], monitorMode)) {
940 return (1);
941 }
942 return (0);
943 }
944 }
945 std::cerr << "ERROR: Value field is missing." << std::endl;
946 return (1);
947}
948
949long ExtractNTEnumValue(PVA_OVERALL *pva, long index, epics::pvData::PVStructurePtr pvStructurePtr, bool monitorMode) {
950 long i, j, fieldCount;
951 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
952 std::string fieldName;
953 PVFieldPtrArray = pvStructurePtr->getPVFields();
954 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
955 for (j = 0; j < fieldCount; j++) {
956 fieldName = PVFieldPtrArray[j]->getFieldName();
957 if (fieldName == "value") {
958 epics::pvData::PVStructurePtr pvStructurePtr;
959 epics::pvData::PVEnumerated pvEnumerated;
960 std::string s;
961 pvStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtrArray[j]);
962 pvEnumerated.attach(pvStructurePtr);
963 if (monitorMode) {
964 if (pva->pvaData[index].numMonitorReadings == 0) {
965 pva->pvaData[index].fieldType = pvStructurePtr->getField()->getType(); //should always be epics::pvData::structure
966 pva->pvaData[index].pvEnumeratedStructure = true;
967 pva->pvaData[index].numMonitorElements = 1;
968 pva->pvaData[index].numeric = true;
969 pva->pvaData[index].nonnumeric = true;
970 pva->pvaData[index].scalarType = epics::pvData::pvString;
971 pva->pvaData[index].monitorData[0].values = (double *)malloc(sizeof(double));
972 pva->pvaData[index].monitorData[0].stringValues = (char **)malloc(sizeof(char *) * 1);
973 } else {
974 if (pva->pvaData[index].monitorData[0].stringValues[0])
975 free(pva->pvaData[index].monitorData[0].stringValues[0]);
976 }
977 pva->pvaData[index].monitorData[0].values[0] = pvEnumerated.getIndex();
978 s = pvEnumerated.getChoice();
979 pva->pvaData[index].monitorData[0].stringValues[0] = (char *)malloc(sizeof(char) * (s.length() + 1));
980 strcpy(pva->pvaData[index].monitorData[0].stringValues[0], s.c_str());
981 pva->pvaData[index].numMonitorReadings = 1;
982 } else {
983 i = pva->pvaData[index].numGetReadings;
984 if (pva->pvaData[index].numGetReadings == 0) {
985 pva->pvaData[index].fieldType = pvStructurePtr->getField()->getType(); //should always be epics::pvData::structure
986 pva->pvaData[index].pvEnumeratedStructure = true;
987 pva->pvaData[index].numGetElements = 1;
988 pva->pvaData[index].numeric = true;
989 pva->pvaData[index].nonnumeric = true;
990 pva->pvaData[index].scalarType = epics::pvData::pvString;
991 } else if (pva->limitGetReadings) {
992 i = 0;
993 }
994 if (pva->pvaData[index].getData[i].values == NULL) {
995 pva->pvaData[index].getData[i].values = (double *)malloc(sizeof(double));
996 }
997 if (pva->pvaData[index].getData[i].stringValues == NULL) {
998 pva->pvaData[index].getData[i].stringValues = (char **)malloc(sizeof(char *) * 1);
999 }
1000 pva->pvaData[index].getData[i].values[0] = pvEnumerated.getIndex();
1001 s = pvEnumerated.getChoice();
1002 pva->pvaData[index].getData[i].stringValues[0] = (char *)malloc(sizeof(char) * (s.length() + 1));
1003 strcpy(pva->pvaData[index].getData[i].stringValues[0], s.c_str());
1004 if (pva->limitGetReadings) {
1005 pva->pvaData[index].numGetReadings = 1;
1006 } else {
1007 pva->pvaData[index].numGetReadings++;
1008 }
1009 }
1010 pvEnumerated.detach();
1011 return (0);
1012 }
1013 }
1014 std::cerr << "ERROR: Value field is missing." << std::endl;
1015 return (1);
1016}
1017
1018long ExtractStructureValue(PVA_OVERALL *pva, long index, epics::pvData::PVFieldPtr PVFieldPtr, bool monitorMode) {
1019 long fieldCount;
1020 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1021 std::string fieldName;
1022 epics::pvData::PVStructurePtr pvStructurePtr;
1023 epics::pvData::PVFieldPtr pvFieldPtr;
1024 std::string afterDot;
1025 pvStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtr);
1026
1027 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
1028 PVFieldPtrArray = pvStructurePtr->getPVFields();
1029 if (fieldCount > 1) {
1030 size_t pos = pva->pvaChannelNames[index].find('.');
1031 if (pos != std::string::npos) {
1032 afterDot = pva->pvaChannelNames[index].substr(pos + 1);
1033 pos = afterDot.find('.');
1034 if (pos != std::string::npos) {
1035 afterDot = afterDot.substr(pos + 1);
1036 } else {
1037 pva->pvaClientGetPtr[index]->getData()->getPVStructure()->dumpValue(std::cerr);
1038 fprintf(stderr, "Error: sub-field is not specific enough\n");
1039 return (1);
1040 }
1041 } else {
1042 pva->pvaClientGetPtr[index]->getData()->getPVStructure()->dumpValue(std::cerr);
1043 fprintf(stderr, "Error: sub-field is not specific enough\n");
1044 return (1);
1045 }
1046 pvFieldPtr = pvStructurePtr->getSubField(afterDot);
1047 if (pvFieldPtr == NULL) {
1048 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[index].c_str());
1049 return (1);
1050 }
1051 switch (pvStructurePtr->getSubField(afterDot)->getField()->getType()) {
1052 case epics::pvData::scalar: {
1053 if (ExtractScalarValue(pva, index, pvStructurePtr->getSubField(afterDot), monitorMode)) {
1054 return (1);
1055 }
1056 break;
1057 }
1058 case epics::pvData::scalarArray: {
1059 if (ExtractScalarArrayValue(pva, index, pvStructurePtr->getSubField(afterDot), monitorMode)) {
1060 return (1);
1061 }
1062 break;
1063 }
1064 case epics::pvData::structure: {
1065 if (ExtractStructureValue(pva, index, pvStructurePtr->getSubField(afterDot), monitorMode)) {
1066 return (1);
1067 }
1068 break;
1069 }
1070 default: {
1071 std::cerr << "ERROR: Need code to handle " << pvStructurePtr->getSubField(afterDot)->getField()->getType() << std::endl;
1072 return (1);
1073 }
1074 }
1075 return (0);
1076 }
1077 fieldName = PVFieldPtrArray[0]->getFieldName();
1078 switch (PVFieldPtrArray[0]->getField()->getType()) {
1079 case epics::pvData::scalar: {
1080 if (ExtractScalarValue(pva, index, PVFieldPtrArray[0], monitorMode)) {
1081 return (1);
1082 }
1083 return (0);
1084 break;
1085 }
1086 case epics::pvData::scalarArray: {
1087 if (ExtractScalarArrayValue(pva, index, PVFieldPtrArray[0], monitorMode)) {
1088 return (1);
1089 }
1090 return (0);
1091 break;
1092 }
1093 case epics::pvData::structure: {
1094 if (ExtractStructureValue(pva, index, PVFieldPtrArray[0], monitorMode)) {
1095 return (1);
1096 }
1097 return (0);
1098 break;
1099 }
1100 default: {
1101 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
1102 return (1);
1103 }
1104 }
1105 std::cerr << "ERROR: Value field is missing." << std::endl;
1106 return (1);
1107}
1108
1109long ExtractPVAValuesOld(PVA_OVERALL *pva) {
1110 long i, j;
1111 std::string id;
1112 bool monitorMode = false;
1113 epics::pvData::PVStructurePtr pvStructurePtr;
1114 for (i = 0; i < pva->numPVs; i++) {
1115 if (pva->pvaData[i].skip == true) {
1116 continue;
1117 }
1118 if (pva->isConnected[i]) {
1119 pvStructurePtr = pva->pvaClientGetPtr[i]->getData()->getPVStructure();
1120 id = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getStructure()->getID();
1121 if (id == "epics:nt/NTScalar:1.0") {
1122 if (ExtractNTScalarValue(pva, i, pvStructurePtr, monitorMode)) {
1123 return (1);
1124 }
1125 } else if (id == "epics:nt/NTScalarArray:1.0") {
1126 if (ExtractNTScalarArrayValue(pva, i, pvStructurePtr, monitorMode)) {
1127 return (1);
1128 }
1129 } else if (id == "epics:nt/NTEnum:1.0") {
1130 if (ExtractNTEnumValue(pva, i, pvStructurePtr, monitorMode)) {
1131 return (1);
1132 }
1133 } else if (id == "structure") {
1134 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1135 long fieldCount;
1136 PVFieldPtrArray = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getPVFields();
1137 fieldCount = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getStructure()->getNumberFields();
1138 if (fieldCount > 1) {
1139 if (PVFieldPtrArray[0]->getFieldName() != "value") {
1140 pva->pvaClientGetPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1141 fprintf(stderr, "Error: sub-field is not specific enough\n");
1142 return (1);
1143 }
1144 }
1145 if (fieldCount == 0) {
1146 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[i].c_str());
1147 return (1);
1148 }
1149 switch (PVFieldPtrArray[0]->getField()->getType()) {
1150 case epics::pvData::scalar: {
1151 if (ExtractScalarValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
1152 return (1);
1153 }
1154 break;
1155 }
1156 case epics::pvData::scalarArray: {
1157 if (ExtractScalarArrayValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
1158 return (1);
1159 }
1160 break;
1161 }
1162 case epics::pvData::structure: {
1163 if (ExtractStructureValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
1164 return (1);
1165 }
1166 break;
1167 }
1168 default: {
1169 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
1170 return (1);
1171 }
1172 }
1173 if (pva->includeAlarmSeverity && (fieldCount > 1)) {
1174 for (j = 0; j < fieldCount; j++) {
1175 if (PVFieldPtrArray[j]->getFieldName() == "alarm") {
1176 if (PVFieldPtrArray[j]->getField()->getType() == epics::pvData::structure) {
1177 epics::pvData::PVStructurePtr alarmStructurePtr;
1178 epics::pvData::PVFieldPtrArray AlarmFieldPtrArray;
1179 long alarmFieldCount;
1180
1181 alarmStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtrArray[j]);
1182 alarmFieldCount = alarmStructurePtr->getStructure()->getNumberFields();
1183 AlarmFieldPtrArray = alarmStructurePtr->getPVFields();
1184 if (alarmFieldCount > 0) {
1185 if (AlarmFieldPtrArray[0]->getFieldName() == "severity") {
1186 epics::pvData::PVScalarPtr pvScalarPtr;
1187 pvScalarPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalar>(AlarmFieldPtrArray[0]);
1188 pva->pvaData[i].alarmSeverity = pvScalarPtr->getAs<int>();
1189 } else {
1190 pva->pvaClientGetPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1191 fprintf(stderr, "Error: alarm->severity field is not where it was expected to be\n");
1192 return (1);
1193 }
1194 }
1195 }
1196 break;
1197 }
1198 }
1199 }
1200 } else {
1201#ifdef DEBUG
1202 pva->pvaClientGetPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1203#endif
1204 std::cerr << "Error: unrecognized structure ID (" << id << ")" << std::endl;
1205 return (1);
1206 }
1207 }
1208 }
1209 return (0);
1210}
1211
1212long ExtractPVAValues(PVA_OVERALL *pva) {
1213 long i, j;
1214 std::string id;
1215 bool monitorMode = false;
1216 epics::pvData::PVStructurePtr pvStructurePtr;
1217 epics::pvData::PVFieldPtr pvFieldPtr;
1218 std::string afterDot;
1219
1220 for (i = 0; i < pva->numPVs; i++) {
1221 if (pva->pvaData[i].skip == true) {
1222 continue;
1223 }
1224 if (pva->isConnected[i]) {
1225 pvStructurePtr = pva->pvaClientGetPtr[i]->getData()->getPVStructure();
1226 id = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getStructure()->getID();
1227 if (id == "epics:nt/NTScalar:1.0") {
1228 if (ExtractNTScalarValue(pva, i, pvStructurePtr, monitorMode)) {
1229 return (1);
1230 }
1231 } else if (id == "epics:nt/NTScalarArray:1.0") {
1232 if (ExtractNTScalarArrayValue(pva, i, pvStructurePtr, monitorMode)) {
1233 return (1);
1234 }
1235 } else if (id == "epics:nt/NTEnum:1.0") {
1236 if (ExtractNTEnumValue(pva, i, pvStructurePtr, monitorMode)) {
1237 return (1);
1238 }
1239 } else if (id == "structure") {
1240 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1241 long fieldCount;
1242 PVFieldPtrArray = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getPVFields();
1243 fieldCount = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getStructure()->getNumberFields();
1244 if (fieldCount == 0) {
1245 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[i].c_str());
1246 return (1);
1247 }
1248 if (fieldCount > 1) {
1249 if (PVFieldPtrArray[0]->getFieldName() != "value") {
1250 size_t pos = pva->pvaChannelNames[i].find('.');
1251 if (pos != std::string::npos) {
1252 afterDot = pva->pvaChannelNames[i].substr(pos + 1);
1253 } else {
1254 pva->pvaClientGetPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1255 fprintf(stderr, "Error: sub-field is not specific enough\n");
1256 return (1);
1257 }
1258 pvFieldPtr = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getSubField(afterDot);
1259 if (pvFieldPtr == NULL) {
1260 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[i].c_str());
1261 return (1);
1262 }
1263 switch (pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getSubField(afterDot)->getField()->getType()) {
1264 case epics::pvData::scalar: {
1265 if (ExtractScalarValue(pva, i, pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getSubField(afterDot), monitorMode)) {
1266 return (1);
1267 }
1268 break;
1269 }
1270 case epics::pvData::scalarArray: {
1271 if (ExtractScalarArrayValue(pva, i, pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getSubField(afterDot), monitorMode)) {
1272 return (1);
1273 }
1274 break;
1275 }
1276 case epics::pvData::structure: {
1277 if (ExtractStructureValue(pva, i, pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getSubField(afterDot), monitorMode)) {
1278 return (1);
1279 }
1280 break;
1281 }
1282 default: {
1283 std::cerr << "ERROR: Need code to handle " << pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getSubField(afterDot)->getField()->getType() << std::endl;
1284 return (1);
1285 }
1286 }
1287 continue;
1288 }
1289 }
1290 switch (PVFieldPtrArray[0]->getField()->getType()) {
1291 case epics::pvData::scalar: {
1292 if (ExtractScalarValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
1293 return (1);
1294 }
1295 break;
1296 }
1297 case epics::pvData::scalarArray: {
1298 if (ExtractScalarArrayValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
1299 return (1);
1300 }
1301 break;
1302 }
1303 case epics::pvData::structure: {
1304 if (ExtractStructureValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
1305 return (1);
1306 }
1307 break;
1308 }
1309 default: {
1310 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
1311 return (1);
1312 }
1313 }
1314 if (pva->includeAlarmSeverity && (fieldCount > 1)) {
1315 for (j = 0; j < fieldCount; j++) {
1316 if (PVFieldPtrArray[j]->getFieldName() == "alarm") {
1317 if (PVFieldPtrArray[j]->getField()->getType() == epics::pvData::structure) {
1318 epics::pvData::PVStructurePtr alarmStructurePtr;
1319 epics::pvData::PVFieldPtrArray AlarmFieldPtrArray;
1320 long alarmFieldCount;
1321
1322 alarmStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtrArray[j]);
1323 alarmFieldCount = alarmStructurePtr->getStructure()->getNumberFields();
1324 AlarmFieldPtrArray = alarmStructurePtr->getPVFields();
1325 if (alarmFieldCount > 0) {
1326 if (AlarmFieldPtrArray[0]->getFieldName() == "severity") {
1327 epics::pvData::PVScalarPtr pvScalarPtr;
1328 pvScalarPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalar>(AlarmFieldPtrArray[0]);
1329 pva->pvaData[i].alarmSeverity = pvScalarPtr->getAs<int>();
1330 } else {
1331 pva->pvaClientGetPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1332 fprintf(stderr, "Error: alarm->severity field is not where it was expected to be\n");
1333 return (1);
1334 }
1335 }
1336 }
1337 break;
1338 }
1339 }
1340 }
1341 } else {
1342#ifdef DEBUG
1343 pva->pvaClientGetPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1344#endif
1345 std::cerr << "Error: unrecognized structure ID (" << id << ")" << std::endl;
1346 return (1);
1347 }
1348 }
1349 }
1350 return (0);
1351}
1352
1353long count_chars(char *string, char c) {
1354 long i = 0;
1355 while (*string) {
1356 if (*string++ == c)
1357 i++;
1358 }
1359 return i;
1360}
1361
1362long PutScalarValue(PVA_OVERALL *pva, long index, epics::pvData::PVFieldPtr PVFieldPtr) {
1363 epics::pvData::PVScalarPtr pvScalarPtr;
1364 pvScalarPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalar>(PVFieldPtr);
1365 try {
1366 if (pva->pvaData[index].numeric) {
1367 pvScalarPtr->putFrom<double>(pva->pvaData[index].putData[0].values[0]);
1368 } else {
1369 pvScalarPtr->putFrom<std::string>(pva->pvaData[index].putData[0].stringValues[0]);
1370 }
1371 } catch (std::exception &e) {
1372 std::cerr << "Error: " << e.what() << "\n";
1373 return 1;
1374 }
1375 return (0);
1376}
1377
1378long PutNTScalarValue(PVA_OVERALL *pva, long index) {
1379 long j, fieldCount;
1380 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1381 std::string fieldName;
1382 PVFieldPtrArray = pva->pvaClientPutPtr[index]->getData()->getPVStructure()->getPVFields();
1383 fieldCount = pva->pvaClientPutPtr[index]->getData()->getPVStructure()->getStructure()->getNumberFields();
1384 for (j = 0; j < fieldCount; j++) {
1385 fieldName = PVFieldPtrArray[j]->getFieldName();
1386 if (fieldName == "value") {
1387 if (PutScalarValue(pva, index, PVFieldPtrArray[j])) {
1388 return (1);
1389 }
1390 return (0);
1391 }
1392 }
1393 std::cerr << "ERROR: Value field is missing." << std::endl;
1394 return (1);
1395}
1396
1397long PutScalarArrayValue(PVA_OVERALL *pva, long index, epics::pvData::PVFieldPtr PVFieldPtr) {
1398 long n;
1399 epics::pvData::PVScalarArrayPtr pvScalarArrayPtr;
1400 pvScalarArrayPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalarArray>(PVFieldPtr);
1401 try {
1402 if (pva->pvaData[index].numeric) {
1403 epics::pvData::shared_vector<double> values(pva->pvaData[index].numPutElements);
1404 for (n = 0; n < pva->pvaData[index].numPutElements; n++) {
1405 values[n] = pva->pvaData[index].putData[0].values[n];
1406 }
1407 pvScalarArrayPtr->setLength(pva->pvaData[index].numPutElements);
1408 pvScalarArrayPtr->putFrom(freeze(values));
1409 } else {
1410 epics::pvData::shared_vector<std::string> values(pva->pvaData[index].numPutElements);
1411 for (n = 0; n < pva->pvaData[index].numPutElements; n++) {
1412 values[n] = pva->pvaData[index].putData[0].stringValues[n];
1413 }
1414 pvScalarArrayPtr->setLength(pva->pvaData[index].numPutElements);
1415 pvScalarArrayPtr->putFrom(freeze(values));
1416 }
1417 } catch (std::exception &e) {
1418 std::cerr << "Error: " << e.what() << "\n";
1419 return 1;
1420 }
1421 return (0);
1422}
1423
1424long PutNTScalarArrayValue(PVA_OVERALL *pva, long index) {
1425 long j, fieldCount;
1426 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1427 std::string fieldName;
1428 PVFieldPtrArray = pva->pvaClientPutPtr[index]->getData()->getPVStructure()->getPVFields();
1429 fieldCount = pva->pvaClientPutPtr[index]->getData()->getPVStructure()->getStructure()->getNumberFields();
1430 for (j = 0; j < fieldCount; j++) {
1431 fieldName = PVFieldPtrArray[j]->getFieldName();
1432 if (fieldName == "value") {
1433 if (PutScalarArrayValue(pva, index, PVFieldPtrArray[j])) {
1434 return (1);
1435 }
1436 return (0);
1437 }
1438 }
1439 std::cerr << "ERROR: Value field is missing." << std::endl;
1440 return (1);
1441}
1442
1443long PutNTEnumValue(PVA_OVERALL *pva, long index) {
1444 long j, fieldCount;
1445 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1446 std::string fieldName;
1447 PVFieldPtrArray = pva->pvaClientPutPtr[index]->getData()->getPVStructure()->getPVFields();
1448 fieldCount = pva->pvaClientPutPtr[index]->getData()->getPVStructure()->getStructure()->getNumberFields();
1449 for (j = 0; j < fieldCount; j++) {
1450 fieldName = PVFieldPtrArray[j]->getFieldName();
1451 if (fieldName == "value") {
1452 epics::pvData::PVStructurePtr pvStructurePtr;
1453 epics::pvData::PVEnumerated pvEnumerated;
1454 bool result;
1455 pvStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtrArray[j]);
1456 result = pvEnumerated.attach(pvStructurePtr);
1457 if (result) {
1458 try {
1459 int enumindex, numChoices;
1460 epics::pvData::PVStringArray::const_svector choices;
1461 numChoices = pvEnumerated.getNumberChoices();
1462
1463 if (pva->pvaData[index].putData[0].stringValues != NULL) {
1464 enumindex = -1;
1465 choices = pvEnumerated.getChoices();
1466 for (size_t i = 0; i < choices.size(); i++) {
1467 if (pva->pvaData[index].putData[0].stringValues[0] == choices[i]) {
1468 enumindex = i;
1469 }
1470 }
1471 if (enumindex == -1) {
1472 if (sscanf(pva->pvaData[index].putData[0].stringValues[0], "%d", &enumindex) != 1) {
1473 fprintf(stderr, "error: value (%s) for %s is not a valid option.\n", pva->pvaData[index].putData[0].stringValues[0], pva->pvaChannelNames[index].c_str());
1474 return (1);
1475 }
1476 if ((enumindex < 0) || (enumindex >= numChoices)) {
1477 fprintf(stderr, "error: value (%s) for %s is out of range.\n", pva->pvaData[index].putData[0].stringValues[0], pva->pvaChannelNames[index].c_str());
1478 return (1);
1479 }
1480 }
1481 } else {
1482 enumindex = pva->pvaData[index].putData[0].values[0];
1483 if ((enumindex < 0) || (enumindex >= numChoices)) {
1484 fprintf(stderr, "error: value (%s) for %s is out of range.\n", pva->pvaData[index].putData[0].stringValues[0], pva->pvaChannelNames[index].c_str());
1485 return (1);
1486 }
1487 }
1488 pvEnumerated.setIndex(enumindex);
1489 pvEnumerated.setIndex(enumindex);
1490 pvEnumerated.detach();
1491 } catch (std::exception &e) {
1492 std::cerr << "Error: " << e.what() << "\n";
1493 return 1;
1494 }
1495 return (0);
1496 } else {
1497 std::cerr << "Error: Need code to handle a non-enumerated structure" << std::endl;
1498 return (1);
1499 }
1500 }
1501 }
1502 std::cerr << "ERROR: Value field is missing." << std::endl;
1503 return (1);
1504}
1505
1506long PutStructureValue(PVA_OVERALL *pva, long index, epics::pvData::PVFieldPtr PVFieldPtr) {
1507 long fieldCount;
1508 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1509 std::string fieldName;
1510 epics::pvData::PVStructurePtr pvStructurePtr;
1511 pvStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtr);
1512
1513 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
1514 PVFieldPtrArray = pvStructurePtr->getPVFields();
1515 if (fieldCount > 1) {
1516 pvStructurePtr->dumpValue(std::cerr);
1517 fprintf(stderr, "Error: sub-field is not specific enough\n");
1518 return (1);
1519 }
1520 fieldName = PVFieldPtrArray[0]->getFieldName();
1521 switch (PVFieldPtrArray[0]->getField()->getType()) {
1522 case epics::pvData::scalar: {
1523 if (PutScalarValue(pva, index, PVFieldPtrArray[0])) {
1524 return (1);
1525 }
1526 return (0);
1527 break;
1528 }
1529 case epics::pvData::scalarArray: {
1530 if (PutScalarArrayValue(pva, index, PVFieldPtrArray[0])) {
1531 return (1);
1532 }
1533 return (0);
1534 break;
1535 }
1536 case epics::pvData::structure: {
1537 if (PutStructureValue(pva, index, PVFieldPtrArray[0])) {
1538 return (1);
1539 }
1540 return (0);
1541 break;
1542 }
1543 default: {
1544 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
1545 return (1);
1546 }
1547 }
1548 std::cerr << "ERROR: Value field is missing." << std::endl;
1549 return (1);
1550}
1551
1552long PrepPut(PVA_OVERALL *pva, long index, double value) {
1553 pva->pvaData[index].numPutElements = 1;
1554 if (pva->pvaData[index].numeric) {
1555 if (pva->pvaData[index].putData[0].values == NULL) {
1556 pva->pvaData[index].putData[0].values = (double *)malloc(sizeof(double));
1557 }
1558 pva->pvaData[index].putData[0].values[0] = value;
1559 } else {
1560 char buffer[100];
1561 if (pva->pvaData[index].putData[0].stringValues == NULL) {
1562 pva->pvaData[index].putData[0].stringValues = (char **)malloc(sizeof(char *));
1563 } else {
1564 //if (pva->pvaData[index].putData[0].stringValues[0])
1565 //free(pva->pvaData[index].putData[0].stringValues[0]);
1566 }
1567 sprintf(buffer, "%lf", value);
1568 pva->pvaData[index].putData[0].stringValues[0] = (char *)malloc(sizeof(char) * (strlen(buffer) + 1));
1569 strcpy(pva->pvaData[index].putData[0].stringValues[0], buffer);
1570 }
1571 return (0);
1572}
1573
1574long PrepPut(PVA_OVERALL *pva, long index, double *value, long length) {
1575 int i;
1576
1577 if (pva->pvaData[index].numPutElements > 0) {
1578 if (pva->pvaData[index].numeric && (pva->pvaData[index].pvEnumeratedStructure == false)) {
1579 if (pva->pvaData[index].numPutElements != length) {
1580 if (pva->pvaData[index].putData[0].values) {
1581 free(pva->pvaData[index].putData[0].values);
1582 pva->pvaData[index].putData[0].values = NULL;
1583 }
1584 }
1585 } else {
1586 if (pva->pvaData[index].putData[0].stringValues) {
1587 for (i = 0; i < pva->pvaData[index].numPutElements; i++) {
1588 if (pva->pvaData[index].putData[0].stringValues[i]) {
1589 free(pva->pvaData[index].putData[0].stringValues[i]);
1590 }
1591 }
1592 if (pva->pvaData[index].numPutElements != length) {
1593 free(pva->pvaData[index].putData[0].stringValues);
1594 pva->pvaData[index].putData[0].stringValues = NULL;
1595 }
1596 }
1597 }
1598 }
1599
1600 pva->pvaData[index].numPutElements = length;
1601 if (pva->pvaData[index].numeric) {
1602 if (pva->pvaData[index].putData[0].values == NULL) {
1603 pva->pvaData[index].putData[0].values = (double *)malloc(sizeof(double) * length);
1604 }
1605 for (i = 0; i < length; i++) {
1606 pva->pvaData[index].putData[0].values[i] = value[i];
1607 }
1608 } else {
1609 char buffer[100];
1610 if (pva->pvaData[index].putData[0].stringValues == NULL) {
1611 pva->pvaData[index].putData[0].stringValues = (char **)malloc(sizeof(char *) * length);
1612 }
1613 for (i = 0; i < length; i++) {
1614 sprintf(buffer, "%lf", value[i]);
1615 pva->pvaData[index].putData[0].stringValues[i] = (char *)malloc(sizeof(char) * (strlen(buffer) + 1));
1616 strcpy(pva->pvaData[index].putData[0].stringValues[i], buffer);
1617 }
1618 }
1619 return (0);
1620}
1621
1622long PrepPut(PVA_OVERALL *pva, long index, int64_t value) {
1623 pva->pvaData[index].numPutElements = 1;
1624 if (pva->pvaData[index].numeric) {
1625 if (pva->pvaData[index].putData[0].values == NULL) {
1626 pva->pvaData[index].putData[0].values = (double *)malloc(sizeof(double));
1627 }
1628 pva->pvaData[index].putData[0].values[0] = (double)value;
1629 } else {
1630 char buffer[100];
1631 if (pva->pvaData[index].putData[0].stringValues == NULL) {
1632 pva->pvaData[index].putData[0].stringValues = (char **)malloc(sizeof(char *));
1633 } else {
1634 //if (pva->pvaData[index].putData[0].stringValues[0])
1635 //free(pva->pvaData[index].putData[0].stringValues[0]);
1636 }
1637 sprintf(buffer, "%ld", value);
1638 pva->pvaData[index].putData[0].stringValues[0] = (char *)malloc(sizeof(char) * (strlen(buffer) + 1));
1639 strcpy(pva->pvaData[index].putData[0].stringValues[0], buffer);
1640 }
1641 return (0);
1642}
1643
1644long PrepPut(PVA_OVERALL *pva, long index, int64_t *value, long length) {
1645 int i;
1646
1647 if (pva->pvaData[index].numPutElements > 0) {
1648 if (pva->pvaData[index].numeric && (pva->pvaData[index].pvEnumeratedStructure == false)) {
1649 if (pva->pvaData[index].numPutElements != length) {
1650 if (pva->pvaData[index].putData[0].values) {
1651 free(pva->pvaData[index].putData[0].values);
1652 pva->pvaData[index].putData[0].values = NULL;
1653 }
1654 }
1655 } else {
1656 if (pva->pvaData[index].putData[0].stringValues) {
1657 for (i = 0; i < pva->pvaData[index].numPutElements; i++) {
1658 if (pva->pvaData[index].putData[0].stringValues[i]) {
1659 free(pva->pvaData[index].putData[0].stringValues[i]);
1660 }
1661 }
1662 if (pva->pvaData[index].numPutElements != length) {
1663 free(pva->pvaData[index].putData[0].stringValues);
1664 pva->pvaData[index].putData[0].stringValues = NULL;
1665 }
1666 }
1667 }
1668 }
1669
1670 pva->pvaData[index].numPutElements = length;
1671 if (pva->pvaData[index].numeric) {
1672 if (pva->pvaData[index].putData[0].values == NULL) {
1673 pva->pvaData[index].putData[0].values = (double *)malloc(sizeof(double) * length);
1674 }
1675 for (i = 0; i < length; i++) {
1676 pva->pvaData[index].putData[0].values[i] = (double)value[i];
1677 }
1678 } else {
1679 char buffer[100];
1680 if (pva->pvaData[index].putData[0].stringValues == NULL) {
1681 pva->pvaData[index].putData[0].stringValues = (char **)malloc(sizeof(char *) * length);
1682 }
1683 for (i = 0; i < length; i++) {
1684 sprintf(buffer, "%ld", value[i]);
1685 pva->pvaData[index].putData[0].stringValues[i] = (char *)malloc(sizeof(char) * (strlen(buffer) + 1));
1686 strcpy(pva->pvaData[index].putData[0].stringValues[i], buffer);
1687 }
1688 }
1689 return (0);
1690}
1691
1692long PrepPut(PVA_OVERALL *pva, long index, char *value) {
1693 pva->pvaData[index].numPutElements = 1;
1694 if (pva->pvaData[index].numeric && (pva->pvaData[index].pvEnumeratedStructure == false)) {
1695 if (pva->pvaData[index].putData[0].values == NULL) {
1696 pva->pvaData[index].putData[0].values = (double *)malloc(sizeof(double));
1697 }
1698 if (sscanf(value, "%le", &(pva->pvaData[index].putData[0].values[0])) != 1) {
1699 fprintf(stderr, "error: value (%s) for %s is not numerical\n", value, pva->pvaChannelNames[index].c_str());
1700 return (1);
1701 }
1702 } else {
1703 if (pva->pvaData[index].putData[0].stringValues == NULL) {
1704 pva->pvaData[index].putData[0].stringValues = (char **)malloc(sizeof(char *));
1705 } else {
1706 //if (pva->pvaData[index].putData[0].stringValues[0])
1707 //free(pva->pvaData[index].putData[0].stringValues[0]);
1708 }
1709 pva->pvaData[index].putData[0].stringValues[0] = (char *)malloc(sizeof(char) * (strlen(value) + 1));
1710 strcpy(pva->pvaData[index].putData[0].stringValues[0], value);
1711 }
1712 return (0);
1713}
1714
1715long PrepPut(PVA_OVERALL *pva, long index, char **value, long length) {
1716 int i;
1717
1718 if (pva->pvaData[index].numPutElements > 0) {
1719 if (pva->pvaData[index].numeric && (pva->pvaData[index].pvEnumeratedStructure == false)) {
1720 if (pva->pvaData[index].numPutElements != length) {
1721 if (pva->pvaData[index].putData[0].values) {
1722 free(pva->pvaData[index].putData[0].values);
1723 pva->pvaData[index].putData[0].values = NULL;
1724 }
1725 }
1726 } else {
1727 if (pva->pvaData[index].putData[0].stringValues) {
1728 for (i = 0; i < pva->pvaData[index].numPutElements; i++) {
1729 if (pva->pvaData[index].putData[0].stringValues[i]) {
1730 free(pva->pvaData[index].putData[0].stringValues[i]);
1731 }
1732 }
1733 if (pva->pvaData[index].numPutElements != length) {
1734 free(pva->pvaData[index].putData[0].stringValues);
1735 pva->pvaData[index].putData[0].stringValues = NULL;
1736 }
1737 }
1738 }
1739 }
1740
1741 pva->pvaData[index].numPutElements = length;
1742 if (pva->pvaData[index].numeric && (pva->pvaData[index].pvEnumeratedStructure == false)) {
1743 if (pva->pvaData[index].putData[0].values == NULL) {
1744 pva->pvaData[index].putData[0].values = (double *)malloc(sizeof(double) * length);
1745 }
1746 for (i = 0; i < length; i++) {
1747 if (sscanf(value[i], "%le", &(pva->pvaData[index].putData[0].values[i])) != 1) {
1748 fprintf(stderr, "error: value (%s) for %s is not numerical\n", value[i], pva->pvaChannelNames[index].c_str());
1749 return (1);
1750 }
1751 }
1752 } else {
1753 if (pva->pvaData[index].putData[0].stringValues == NULL) {
1754 pva->pvaData[index].putData[0].stringValues = (char **)malloc(sizeof(char *) * length);
1755 }
1756 for (i = 0; i < length; i++) {
1757 pva->pvaData[index].putData[0].stringValues[i] = (char *)malloc(sizeof(char) * (strlen(value[i]) + 1));
1758 strcpy(pva->pvaData[index].putData[0].stringValues[i], value[i]);
1759 }
1760 }
1761 return (0);
1762}
1763
1764/*
1765 Put the values from the pva structure and send them to the PVs. See cavput.cc for an example on how to populate this pva structure.
1766*/
1767long PutPVAValues(PVA_OVERALL *pva) {
1768 long i, j, num = 0;
1769 std::string id;
1770 epics::pvData::Status status;
1771 epics::pvaClient::PvaClientChannelArray pvaClientChannelArray;
1772
1773 pva->isInternalConnected = pva->pvaClientMultiChannelPtr[0]->getIsConnected();
1774 pvaClientChannelArray = pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray();
1775 for (i = 1; i < pva->numMultiChannels; i++) {
1776 epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
1777 epics::pvaClient::PvaClientChannelArray pvaClientChannelArrayAdd;
1778 isConnected = pva->pvaClientMultiChannelPtr[i]->getIsConnected();
1779 std::copy(isConnected.begin(), isConnected.end(), std::back_inserter(pva->isInternalConnected));
1780 pvaClientChannelArrayAdd = pva->pvaClientMultiChannelPtr[i]->getPvaClientChannelArray();
1781 std::copy(pvaClientChannelArrayAdd.begin(), pvaClientChannelArrayAdd.end(), std::back_inserter(pvaClientChannelArray));
1782 }
1783 for (i = 0; i < pva->numPVs; i++) {
1784 if (pva->pvaData[i].skip == true) {
1785 continue;
1786 }
1787 pva->isConnected[i] = pva->isInternalConnected[pva->pvaData[i].L2Ptr];
1788 if (pva->isConnected[i] == false) {
1789 if (pva->pvaData[i].numPutElements > 0) {
1790 fprintf(stderr, "Error: Can't put value to %s. Not connected.\n", pva->pvaChannelNames[i].c_str());
1791 return (1);
1792 }
1793 num++;
1794 } else if ((pva->pvaData[i].numPutElements > 0) && (pva->pvaData[i].havePutPtr == false)) {
1795 pva->pvaClientPutPtr[i] = pvaClientChannelArray[pva->pvaData[i].L2Ptr]->createPut(pva->pvaChannelNamesSub[i]);
1796 pva->pvaData[i].havePutPtr = true;
1797 if (pva->useGetCallbacks) {
1798 pva->pvaClientPutPtr[i]->setRequester((epics::pvaClient::PvaClientPutRequesterPtr)pva->putReqPtr);
1799 }
1800 }
1801 }
1802 pva->numNotConnected = num;
1803
1804 for (i = 0; i < pva->numPVs; i++) {
1805 if (pva->pvaData[i].skip == true) {
1806 continue;
1807 }
1808 if (pva->pvaData[i].numPutElements > 0) {
1809#ifdef DEBUG
1810 pva->pvaClientPutPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1811#endif
1812 //get the id string from the GetPtr instead of the PutPtr
1813 id = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getStructure()->getID();
1814 if (id == "epics:nt/NTScalar:1.0") {
1815 if (PutNTScalarValue(pva, i)) {
1816 return (1);
1817 }
1818 } else if (id == "epics:nt/NTScalarArray:1.0") {
1819 if (PutNTScalarArrayValue(pva, i)) {
1820 return (1);
1821 }
1822 } else if (id == "epics:nt/NTEnum:1.0") {
1823 if (PutNTEnumValue(pva, i)) {
1824 return (1);
1825 }
1826 } else if (id == "structure") {
1827 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
1828 long fieldCount;
1829 PVFieldPtrArray = pva->pvaClientPutPtr[i]->getData()->getPVStructure()->getPVFields();
1830 fieldCount = pva->pvaClientPutPtr[i]->getData()->getPVStructure()->getStructure()->getNumberFields();
1831 if (fieldCount > 1) {
1832 if (PVFieldPtrArray[0]->getFieldName() != "value") {
1833 pva->pvaClientPutPtr[i]->getData()->getPVStructure()->dumpValue(std::cerr);
1834 fprintf(stderr, "Error: sub-field is not specific enough\n");
1835 return (1);
1836 }
1837 }
1838 if (fieldCount == 0) {
1839 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[i].c_str());
1840 return (1);
1841 }
1842 switch (PVFieldPtrArray[0]->getField()->getType()) {
1843 case epics::pvData::scalar: {
1844 if (PutScalarValue(pva, i, PVFieldPtrArray[0])) {
1845 return (1);
1846 }
1847 break;
1848 }
1849 case epics::pvData::scalarArray: {
1850 if (PutScalarArrayValue(pva, i, PVFieldPtrArray[0])) {
1851 return (1);
1852 }
1853 break;
1854 }
1855 case epics::pvData::structure: {
1856 if (PutStructureValue(pva, i, PVFieldPtrArray[0])) {
1857 return (1);
1858 }
1859 break;
1860 }
1861 default: {
1862 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
1863 return (1);
1864 }
1865 }
1866 } else {
1867 std::cerr << "Error: unrecognized structure ID (" << id << ")" << std::endl;
1868 return (1);
1869 }
1870 }
1871 }
1872
1873 for (i = 0; i < pva->numPVs; i++) {
1874 if (pva->pvaData[i].skip == true) {
1875 continue;
1876 }
1877 if (pva->pvaData[i].numPutElements > 0) {
1878 pva->pvaClientPutPtr[i]->issuePut();
1879 }
1880 }
1881
1882 if (pva->useGetCallbacks == false) {
1883 for (i = 0; i < pva->numPVs; i++) {
1884 if (pva->pvaData[i].skip == true) {
1885 continue;
1886 }
1887 if (pva->pvaData[i].numPutElements > 0) {
1888 status = pva->pvaClientPutPtr[i]->waitPut();
1889 if (!status.isSuccess()) {
1890 fprintf(stderr, "error: %s did not respond to the \"put\" request\n", pva->pvaChannelNames[i].c_str());
1891 return (1);
1892 }
1893 }
1894 }
1895 }
1896 for (i = 0; i < pva->numPVs; i++) {
1897 if (pva->pvaData[i].skip == true) {
1898 continue;
1899 }
1900 if (pva->pvaData[i].numPutElements > 0) {
1901 if (pva->pvaData[i].putData[0].stringValues != NULL) {
1902 for (j = 0; j < pva->pvaData[i].numPutElements; j++) {
1903 free(pva->pvaData[i].putData[0].stringValues[j]);
1904 }
1905 }
1906 pva->pvaData[i].numPutElements = 0;
1907 }
1908 }
1909 return (0);
1910}
1911
1912/*
1913 Start monitoring the PVs. Use the PollMonitoredPVA values to identify if an event has occured.
1914 FIX THIS There is a unique problem of what to do with PVs that are not connected when the program starts but become connected later
1915*/
1916long MonitorPVAValues(PVA_OVERALL *pva) {
1917 long i, num;
1918 epics::pvData::Status status;
1919 epics::pvaClient::PvaClientChannelArray pvaClientChannelArray;
1920
1921 if (pva == NULL) {
1922 return (0);
1923 }
1924 num = 0;
1925 pva->isInternalConnected = pva->pvaClientMultiChannelPtr[0]->getIsConnected();
1926 pvaClientChannelArray = pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray();
1927 for (i = 1; i < pva->numMultiChannels; i++) {
1928 epics::pvData::shared_vector<epics::pvData::boolean> isConnected;
1929 epics::pvaClient::PvaClientChannelArray pvaClientChannelArrayAdd;
1930 isConnected = pva->pvaClientMultiChannelPtr[i]->getIsConnected();
1931 std::copy(isConnected.begin(), isConnected.end(), std::back_inserter(pva->isInternalConnected));
1932 pvaClientChannelArrayAdd = pva->pvaClientMultiChannelPtr[i]->getPvaClientChannelArray();
1933 std::copy(pvaClientChannelArrayAdd.begin(), pvaClientChannelArrayAdd.end(), std::back_inserter(pvaClientChannelArray));
1934 }
1935 for (i = 0; i < pva->numPVs; i++) {
1936 if (pva->pvaData[i].skip == true) {
1937 continue;
1938 }
1939 pva->isConnected[i] = pva->isInternalConnected[pva->pvaData[i].L2Ptr];
1940 if (pva->isConnected[i]) {
1941 if (pva->pvaData[i].haveMonitorPtr == false) {
1942 pva->pvaClientMonitorPtr[i] = pvaClientChannelArray[pva->pvaData[i].L2Ptr]->createMonitor(pva->pvaChannelNamesSub[i]);
1943 pva->pvaData[i].haveMonitorPtr = true;
1944 if (pva->useMonitorCallbacks) {
1945 pva->pvaClientMonitorPtr[i]->setRequester((epics::pvaClient::PvaClientMonitorRequesterPtr)pva->monitorReqPtr);
1946 }
1947 pva->pvaClientMonitorPtr[i]->issueConnect();
1948 status = pva->pvaClientMonitorPtr[i]->waitConnect();
1949 if (!status.isSuccess()) {
1950 fprintf(stderr, "error: %s did not respond to the \"waitConnect\" request\n", pva->pvaChannelNames[i].c_str());
1951 return (1);
1952 }
1953 pva->pvaClientMonitorPtr[i]->start();
1954 }
1955 } else {
1956 num++;
1957 }
1958 }
1959 pva->numNotConnected = num;
1960 return (0);
1961}
1962
1963void PausePVAMonitoring(PVA_OVERALL **pva, long count) {
1964 long i;
1965 for (i = 0; i < count; i++) {
1966 PausePVAMonitoring(pva[i]);
1967 }
1968}
1969
1970void PausePVAMonitoring(PVA_OVERALL *pva) {
1971 long i;
1972 if (pva == NULL) {
1973 return;
1974 }
1975 for (i = 0; i < pva->numPVs; i++) {
1976 if (pva->pvaData[i].skip == true) {
1977 continue;
1978 }
1979 if (pva->isConnected[i]) {
1980 pva->pvaClientMonitorPtr[i]->stop();
1981 }
1982 }
1983}
1984
1985void ResumePVAMonitoring(PVA_OVERALL **pva, long count) {
1986 long i;
1987 for (i = 0; i < count; i++) {
1988 ResumePVAMonitoring(pva[i]);
1989 }
1990}
1991
1992void ResumePVAMonitoring(PVA_OVERALL *pva) {
1993 long i;
1994 if (pva == NULL) {
1995 return;
1996 }
1997 for (i = 0; i < pva->numPVs; i++) {
1998 if (pva->pvaData[i].skip == true) {
1999 continue;
2000 }
2001 if (pva->isConnected[i]) {
2002 pva->pvaClientMonitorPtr[i]->start();
2003 }
2004 }
2005}
2006
2007/*
2008 Check to see if an event has occured on a monitored PV and if so, place the data into the pva structure.
2009 Returns number of events found or -1 for error
2010*/
2011long PollMonitoredPVA(PVA_OVERALL *pva) {
2012 long result;
2013 PVA_OVERALL **pvaArray;
2014 pvaArray = (PVA_OVERALL **)malloc(sizeof(PVA_OVERALL *));
2015 pvaArray[0] = pva;
2016 result = PollMonitoredPVA(pvaArray, 1);
2017 free(pvaArray);
2018 return (result);
2019}
2020
2021/* Returns number of events found or -1 for error
2022 */
2023long PollMonitoredPVA(PVA_OVERALL **pva, long count) {
2024 long result = 0, i, n;
2025 std::string id;
2026 bool monitorMode = true, connectionChange = false;
2027 epics::pvData::PVStructurePtr pvStructurePtr;
2028
2029 for (n = 0; n < count; n++) {
2030 if (pva[n] != NULL) {
2031 //A PV which was initially unconnected may have connected and we need to start monitoring it
2032 for (i = 0; i < pva[n]->numMultiChannels; i++) {
2033 if (pva[n]->pvaClientMultiChannelPtr[i]->connectionChange()) {
2034 connectionChange = true;
2035 }
2036 }
2037 if (connectionChange) {
2038 if (MonitorPVAValues(pva[n]) != 0) {
2039 return (1);
2040 }
2041 connectionChange = false;
2042 }
2043
2044 for (long i = 0; i < pva[n]->numPVs; i++) {
2045 if (pva[n]->pvaData[i].skip == true) {
2046 continue;
2047 }
2048 if (pva[n]->isConnected[i]) {
2049 if (pva[n]->pvaClientMonitorPtr[i]->poll()) {
2050 result++;
2051 pvStructurePtr = pva[n]->pvaClientMonitorPtr[i]->getData()->getPVStructure();
2052 id = pvStructurePtr->getStructure()->getID();
2053 if (id == "epics:nt/NTScalar:1.0") {
2054 if (ExtractNTScalarValue(pva[n], i, pvStructurePtr, monitorMode)) {
2055 return (-1);
2056 }
2057 } else if (id == "epics:nt/NTScalarArray:1.0") {
2058 if (ExtractNTScalarArrayValue(pva[n], i, pvStructurePtr, monitorMode)) {
2059 return (-1);
2060 }
2061 } else if (id == "epics:nt/NTEnum:1.0") {
2062 if (ExtractNTEnumValue(pva[n], i, pvStructurePtr, monitorMode)) {
2063 return (-1);
2064 }
2065 } else if (id == "structure") {
2066 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
2067 long fieldCount;
2068 PVFieldPtrArray = pvStructurePtr->getPVFields();
2069 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2070 if (fieldCount > 1) {
2071 if (PVFieldPtrArray[0]->getFieldName() != "value") {
2072 pvStructurePtr->dumpValue(std::cerr);
2073 fprintf(stderr, "Error: sub-field is not specific enough\n");
2074 return (-1);
2075 }
2076 }
2077 switch (PVFieldPtrArray[0]->getField()->getType()) {
2078 case epics::pvData::scalar: {
2079 if (ExtractScalarValue(pva[n], i, PVFieldPtrArray[0], monitorMode)) {
2080 return (-1);
2081 }
2082 break;
2083 }
2084 case epics::pvData::scalarArray: {
2085 if (ExtractScalarArrayValue(pva[n], i, PVFieldPtrArray[0], monitorMode)) {
2086 return (-1);
2087 }
2088 break;
2089 }
2090 case epics::pvData::structure: {
2091 if (ExtractStructureValue(pva[n], i, PVFieldPtrArray[0], monitorMode)) {
2092 return (-1);
2093 }
2094 break;
2095 }
2096 default: {
2097 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
2098 return (-1);
2099 }
2100 }
2101 }
2102 pva[n]->pvaClientMonitorPtr[i]->releaseEvent();
2103 }
2104 }
2105 }
2106 }
2107 }
2108 return result;
2109}
2110
2111/*
2112 Wait for an event on a monitored PV and place the data into the pva structure.
2113 result: -1 no event, 0 event, 1 error
2114*/
2115long WaitEventMonitoredPVA(PVA_OVERALL *pva, long index, double secondsToWait) {
2116 long result = -1;
2117 std::string id;
2118 bool monitorMode = true;
2119 epics::pvData::PVStructurePtr pvStructurePtr;
2120 for (long i = index; i <= index; i++) {
2121 if (pva->isConnected[i]) {
2122 if (pva->pvaClientMonitorPtr[i]->waitEvent(secondsToWait)) {
2123 pvStructurePtr = pva->pvaClientMonitorPtr[i]->getData()->getPVStructure();
2124 id = pvStructurePtr->getStructure()->getID();
2125 if (id == "epics:nt/NTScalar:1.0") {
2126 if (ExtractNTScalarValue(pva, i, pvStructurePtr, monitorMode)) {
2127 return (1);
2128 }
2129 } else if (id == "epics:nt/NTScalarArray:1.0") {
2130 if (ExtractNTScalarArrayValue(pva, i, pvStructurePtr, monitorMode)) {
2131 return (1);
2132 }
2133 } else if (id == "epics:nt/NTEnum:1.0") {
2134 if (ExtractNTEnumValue(pva, i, pvStructurePtr, monitorMode)) {
2135 return (1);
2136 }
2137 } else if (id == "structure") {
2138 epics::pvData::PVFieldPtrArray PVFieldPtrArray;
2139 long fieldCount;
2140 PVFieldPtrArray = pvStructurePtr->getPVFields();
2141 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2142 if (fieldCount > 1) {
2143 if (PVFieldPtrArray[0]->getFieldName() != "value") {
2144 pvStructurePtr->dumpValue(std::cerr);
2145 fprintf(stderr, "Error: sub-field is not specific enough\n");
2146 return (1);
2147 }
2148 }
2149 switch (PVFieldPtrArray[0]->getField()->getType()) {
2150 case epics::pvData::scalar: {
2151 if (ExtractScalarValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
2152 return (1);
2153 }
2154 break;
2155 }
2156 case epics::pvData::scalarArray: {
2157 if (ExtractScalarArrayValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
2158 return (1);
2159 }
2160 break;
2161 }
2162 case epics::pvData::structure: {
2163 if (ExtractStructureValue(pva, i, PVFieldPtrArray[0], monitorMode)) {
2164 return (1);
2165 }
2166 break;
2167 }
2168 default: {
2169 std::cerr << "ERROR: Need code to handle " << PVFieldPtrArray[0]->getField()->getType() << std::endl;
2170 return (1);
2171 }
2172 }
2173 }
2174 pva->pvaClientMonitorPtr[i]->releaseEvent();
2175 result = 0;
2176 }
2177 }
2178 }
2179 return result;
2180}
2181
2182long ExtractPVAUnits(PVA_OVERALL *pva) {
2183 long i, j, n, fieldCount, fieldCount2;
2184 epics::pvData::PVStructurePtr pvStructurePtr;
2185 epics::pvData::PVFieldPtrArray PVFieldPtrArray, PVFieldPtrArray2;
2186 epics::pvData::PVScalarPtr pvScalarPtr;
2187 std::string s;
2188 for (i = 0; i < pva->numPVs; i++) {
2189 if (pva->pvaData[i].skip == true) {
2190 continue;
2191 }
2192 pva->pvaData[i].units = NULL;
2193 if (pva->isConnected[i]) {
2194 PVFieldPtrArray = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getPVFields();
2195 fieldCount = pva->pvaClientGetPtr[i]->getData()->getPVStructure()->getStructure()->getNumberFields();
2196 for (j = 0; j < fieldCount; j++) {
2197 if (PVFieldPtrArray[j]->getFieldName() == "display") {
2198 pvStructurePtr = std::tr1::static_pointer_cast<epics::pvData::PVStructure>(PVFieldPtrArray[j]);
2199 PVFieldPtrArray2 = pvStructurePtr->getPVFields();
2200 fieldCount2 = pvStructurePtr->getStructure()->getNumberFields();
2201 for (n = 0; n < fieldCount2; n++) {
2202 if (PVFieldPtrArray2[n]->getFieldName() == "units") {
2203 pvScalarPtr = std::tr1::static_pointer_cast<epics::pvData::PVScalar>(PVFieldPtrArray2[n]);
2204 s = pvScalarPtr->getAs<std::string>();
2205 pva->pvaData[i].units = (char *)malloc(sizeof(char) * (s.length() + 1));
2206 strcpy(pva->pvaData[i].units, s.c_str());
2207 break;
2208 }
2209 }
2210 break;
2211 }
2212 }
2213 }
2214 }
2215 return (0);
2216}
2217
2218std::string GetProviderName(PVA_OVERALL *pva, long index) {
2219 if (pva->isConnected[index] == false)
2220 return "unknown";
2221 return pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray()[pva->pvaData[index].L2Ptr]->getChannel()->getProvider()->getProviderName();
2222}
2223std::string GetRemoteAddress(PVA_OVERALL *pva, long index) {
2224 if (pva->isConnected[index] == false)
2225 return "unknown";
2226 return pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray()[pva->pvaData[index].L2Ptr]->getChannel()->getRemoteAddress();
2227}
2228bool HaveReadAccess(PVA_OVERALL *pva, long index) {
2229 epics::pvData::PVStructurePtr pvStructurePtr;
2230 size_t fieldCount;
2231 uint32_t value;
2232
2233 if (pva->isConnected[index]) {
2234 pvStructurePtr = pva->pvaClientGetPtr[index]->getData()->getPVStructure();
2235 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2236 if (fieldCount > 0) {
2237 value = pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray()[pva->pvaData[index].L2Ptr]->getChannel()->getAccessRights(pvStructurePtr->getPVFields()[0]);
2238 if ((value == 1) || (value == 2))
2239 return true;
2240 }
2241 }
2242 return false;
2243 /*
2244 std::string provider;
2245 epics::pvAccess::ca::CAChannel::shared_pointer caChan;
2246 if (pva->isConnected[index] == false)
2247 return false;
2248 provider = GetProviderName(pva, index);
2249 if (provider == "ca") {
2250 caChan = std::dynamic_pointer_cast<epics::pvAccess::ca::CAChannel>(pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray()[pva->pvaData[index].L2Ptr]->getChannel());
2251 if (ca_read_access(caChan->getChannelID()) == 0)
2252 return false;
2253 else
2254 return true;
2255 } else {
2256 return true;
2257 }
2258 */
2259}
2260bool HaveWriteAccess(PVA_OVERALL *pva, long index) {
2261 epics::pvData::PVStructurePtr pvStructurePtr;
2262 size_t fieldCount;
2263 uint32_t value;
2264
2265 if (pva->isConnected[index]) {
2266 pvStructurePtr = pva->pvaClientGetPtr[index]->getData()->getPVStructure();
2267 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2268 if (fieldCount > 0) {
2269 value = pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray()[pva->pvaData[index].L2Ptr]->getChannel()->getAccessRights(pvStructurePtr->getPVFields()[0]);
2270 if (value == 2)
2271 return true;
2272 }
2273 }
2274 return false;
2275
2276 /*
2277 {
2278 std::string provider;
2279 epics::pvAccess::ca::CAChannel::shared_pointer caChan;
2280 provider = GetProviderName(pva, index);
2281 if (provider == "ca") {
2282 caChan = std::dynamic_pointer_cast<epics::pvAccess::ca::CAChannel>(pva->pvaClientMultiChannelPtr[0]->getPvaClientChannelArray()[pva->pvaData[index].L2Ptr]->getChannel());
2283 if (ca_write_access(caChan->getChannelID()) == 0)
2284 return false;
2285 else
2286 return true;
2287 } else {
2288 return true;
2289 }
2290 }
2291 */
2292}
2293std::string GetAlarmSeverity(PVA_OVERALL *pva, long index) {
2294 if (pva->isConnected[index] == false)
2295 return "unknown";
2296 if (pva->pvaData[index].alarmSeverity == 1) {
2297 return "MINOR";
2298 } else if (pva->pvaData[index].alarmSeverity > 1) {
2299 return "MAJOR";
2300 } else {
2301 return "NONE";
2302 }
2303}
2304std::string GetStructureID(PVA_OVERALL *pva, long index) {
2305 if (pva->isConnected[index] == false)
2306 return "unknown";
2307 return pva->pvaClientGetPtr[index]->getData()->getPVStructure()->getStructure()->getID();
2308}
2309std::string GetFieldType(PVA_OVERALL *pva, long index) {
2310 std::string id;
2311 epics::pvData::PVStructurePtr pvStructurePtr;
2312 size_t fieldCount;
2313 if (pva->isConnected[index] == false)
2314 return "unknown";
2315 pvStructurePtr = pva->pvaClientGetPtr[index]->getData()->getPVStructure();
2316 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2317 id = pvStructurePtr->getStructure()->getID();
2318 if (id == "epics:nt/NTEnum:1.0") {
2319 return "ENUM structure";
2320 } else if (id == "structure") {
2321 if (fieldCount > 1) {
2322 if (pvStructurePtr->getPVFields()[0]->getFieldName() != "value") {
2323 pvStructurePtr->dumpValue(std::cerr);
2324 fprintf(stderr, "Error: sub-field is not specific enough\n");
2325 return "unknown";
2326 }
2327 } else if (fieldCount == 0) {
2328 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[index].c_str());
2329 return "unknown";
2330 }
2331 return epics::pvData::TypeFunc::name(pvStructurePtr->getPVFields()[0]->getField()->getType());
2332 } else {
2333 std::cerr << "ERROR: Need code to handle " << id << std::endl;
2334 return "unknown";
2335 }
2336}
2337bool IsEnumFieldType(PVA_OVERALL *pva, long index) {
2338 if (pva->isConnected[index] == false)
2339 return false;
2340 if (pva->pvaClientGetPtr[index]->getData()->getPVStructure()->getStructure()->getID() == "epics:nt/NTEnum:1.0")
2341 return true;
2342 else
2343 return false;
2344}
2345uint32_t GetElementCount(PVA_OVERALL *pva, long index) {
2346 std::string id;
2347 epics::pvData::PVStructurePtr pvStructurePtr;
2348 size_t fieldCount;
2349 if (pva->isConnected[index] == false)
2350 return 0;
2351 pvStructurePtr = pva->pvaClientGetPtr[index]->getData()->getPVStructure();
2352 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2353 id = pvStructurePtr->getStructure()->getID();
2354 if (id == "epics:nt/NTEnum:1.0") {
2355 return 1;
2356 } else if (id == "structure") {
2357 if (fieldCount > 1) {
2358 if (pvStructurePtr->getPVFields()[0]->getFieldName() != "value") {
2359 pvStructurePtr->dumpValue(std::cerr);
2360 fprintf(stderr, "Error: sub-field is not specific enough\n");
2361 return 0;
2362 }
2363 } else if (fieldCount == 0) {
2364 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[index].c_str());
2365 return 0;
2366 }
2367 switch (pvStructurePtr->getPVFields()[0]->getField()->getType()) {
2368 case epics::pvData::scalar: {
2369 return 1;
2370 }
2371 case epics::pvData::scalarArray: {
2372 return std::tr1::static_pointer_cast<const epics::pvData::PVScalarArray>(pvStructurePtr->getPVFields()[0])->getLength();
2373 }
2374 default: {
2375 std::cerr << "ERROR: Need code to handle " << pvStructurePtr->getPVFields()[0]->getField()->getType() << std::endl;
2376 return 0;
2377 }
2378 }
2379 } else {
2380 std::cerr << "ERROR: Need code to handle " << id << std::endl;
2381 return 0;
2382 }
2383}
2384std::string GetNativeDataType(PVA_OVERALL *pva, long index) {
2385 std::string id;
2386 epics::pvData::PVStructurePtr pvStructurePtr;
2387 size_t fieldCount;
2388 if (pva->isConnected[index] == false)
2389 return "unknown";
2390 pvStructurePtr = pva->pvaClientGetPtr[index]->getData()->getPVStructure();
2391 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2392 id = pvStructurePtr->getStructure()->getID();
2393 if (id == "epics:nt/NTEnum:1.0") {
2394 return "string";
2395 } else if (id == "structure") {
2396 if (fieldCount > 1) {
2397 if (pvStructurePtr->getPVFields()[0]->getFieldName() != "value") {
2398 pvStructurePtr->dumpValue(std::cerr);
2399 fprintf(stderr, "Error: sub-field is not specific enough\n");
2400 return "unknown";
2401 }
2402 } else if (fieldCount == 0) {
2403 fprintf(stderr, "Error: sub-field does not exist for %s\n", pva->pvaChannelNames[index].c_str());
2404 return "unknown";
2405 }
2406 switch (pvStructurePtr->getPVFields()[0]->getField()->getType()) {
2407 case epics::pvData::scalar: {
2408 return epics::pvData::ScalarTypeFunc::name(std::tr1::static_pointer_cast<const epics::pvData::Scalar>(pvStructurePtr->getPVFields()[0]->getField())->getScalarType());
2409 }
2410 case epics::pvData::scalarArray: {
2411 return epics::pvData::ScalarTypeFunc::name(std::tr1::static_pointer_cast<const epics::pvData::ScalarArray>(pvStructurePtr->getPVFields()[0]->getField())->getElementType());
2412 }
2413 default: {
2414 std::cerr << "ERROR: Need code to handle " << pvStructurePtr->getPVFields()[0]->getField()->getType() << std::endl;
2415 return "unknown";
2416 }
2417 }
2418 } else {
2419 std::cerr << "ERROR: Need code to handle " << id << std::endl;
2420 return "unknown";
2421 }
2422}
2423std::string GetUnits(PVA_OVERALL *pva, long index) {
2424 if (pva->pvaData[index].units)
2425 return pva->pvaData[index].units;
2426 else
2427 return "";
2428}
2429uint32_t GetEnumChoices(PVA_OVERALL *pva, long index, char ***enumChoices) {
2430 uint32_t count = 0;
2431 std::string id;
2432 epics::pvData::PVStructurePtr pvStructurePtr;
2433 size_t fieldCount, n, m;
2434 if (pva->isConnected[index] == false)
2435 return 0;
2436 pvStructurePtr = pva->pvaClientGetPtr[index]->getData()->getPVStructure();
2437 fieldCount = pvStructurePtr->getStructure()->getNumberFields();
2438 id = pvStructurePtr->getStructure()->getID();
2439 if (id == "epics:nt/NTEnum:1.0") {
2440 epics::pvData::PVStringArray::const_svector choices;
2441 for (n = 0; n < fieldCount; n++) {
2442 if (pvStructurePtr->getPVFields()[n]->getFieldName() == "value") {
2443 epics::pvData::PVEnumerated pvEnumerated;
2444 pvEnumerated.attach(std::tr1::static_pointer_cast<epics::pvData::PVStructure>(pvStructurePtr->getPVFields()[n]));
2445 choices = pvEnumerated.getChoices();
2446 count = choices.size();
2447 *enumChoices = (char**)malloc(sizeof(char*) * count);
2448 for (m = 0; m < choices.size(); m++) {
2449 std::string val;
2450 val = "{" + choices[m] + "}";
2451 (*enumChoices)[m] = (char *)malloc(sizeof(char) * strlen(val.c_str()) + 1);
2452 strcpy((*enumChoices)[m], val.c_str());
2453 }
2454 break;
2455 }
2456 }
2457 return count;
2458 } else {
2459 return 0;
2460 }
2461}
Functions for managing and interacting with Process Variable Array (PVA) structures.