Accelerator Independent Data Access / PVAccess 2.0
AIDA-PVA is the latest version of the AIDA framework. Built on top of EPICS 7 it enables client applications to programmatically access and manage any device or database on the SLAC Network using simple channel names.
Loading...
Searching...
No Matches
aida_pva_server_helper.c
Go to the documentation of this file.
1/** @file
2 * @brief This file contain functions and MACROS that should be
3 * used directly Native Channel Providers.
4 * These functions provide all of the features that allow the Channel Provider to implement its service.
5 *
6 * **MEMBER**=SLCLIBS:AIDA_PVALIB
7 * **ATTRIBUTES**=JNI
8 *
9 * - MACROS to allocate, track and release memory
10 * - Throwing exceptions and determining if one has been thrown
11 * - Argument processing, except ascanf() and avscanf()
12 * - MACROS and functions to construct and decode URIs into their constituent parts
13 */
14#include "apdesc.h"
16
17static json_value* navigateToArrayElement(json_value* jsonValue, int index);
18static json_value* navigateToObjectElement(json_value* jsonValue, const char* name);
19static json_value* processArrayReference(json_value* jsonValue, const char* arrayRef);
20static Value getNamedValueImpl(JNIEnv* env, Arguments arguments, char* name, bool forArray);
21static bool isOnlyNumbers(char* string);
22
23/* Override prototypes of externals to uppercase names, since compile.com
24 adds cc/names=UPPERCASE on compiles by default, but if the ATTRIBUTE=JNI
25 is in effect (as is for this module), then it's /names=AS_IS.
26*/
27/**
28 * standalone init is used to initialise standalone processes
29 * @param name process name
30 * @param dbinit dbinit
31 * @param msginit msginit
32 * @param query query
33 * @param set set
34 * @return status
35 */
36unsigned long int STANDALONE_INIT(
37 const struct dsc$descriptor_s* name,
38 const long int* dbinit,
39 const struct msginit* msginit,
40 const long int* query,
41 const long int* set
42);
43
44/**
45 * Call standalone_init()
46 * @param processName the name of the process being initialised
47 * @param initMessageServices boolean to determine if the message service needs to be initialised
48 * @return vms status code
49 */
50vmsstat_t init(const char* processName, bool initMessageServices)
51{
52 const struct msginit msg_init_s = { 1, /* init msg service */
53 1 }; /* init slcnet */
54
55 vmsstat_t status;
56 $DESCRIPTOR (PROCESS_NAME, processName); // Ignored in standalone_init() call
57
58 status = STANDALONE_INIT(&PROCESS_NAME, &((long)(TRUE)),
59 initMessageServices ? &msg_init_s : NULL,
60 &((long)(FALSE)), &((long)(FALSE)));
61
62 return status;
63}
64
65/**
66 * To log any non-OS exceptions and throw back to java.
67 *
68 * The #exception is formatted in a standard way with the optionally supplied #message.
69 * The #exception is always assumed to be from the edu.stanford.slac.except package
70 *
71 * @param env the JNI environment. Used in all functions involving JNI
72 * @param exception the string representation of the exception class to throw.
73 * @param message the optional message to attach to the exception. If NULL it is ignored.
74 */
75void aidaThrowNonOsException(JNIEnv* env, char* exception, const char* message)
76{
77 aidaThrow(env, 1, exception, message);
78}
79
80/**
81 * To log any exceptions and throw back to java.
82 *
83 * The #exception is formatted in a standard way using the VMS status code and its associated message
84 * and the optionally supplied #message.
85 * The #exception is always assumed to be from the edu.stanford.slac.except package
86 *
87 * @param env the JNI environment. Used in all functions involving JNI
88 * @param status the VMS status code to luck up and display text for.
89 * @param exception the string representation of the exception class to throw.
90 * @param message the optional message to attach to the exception. If NULL it is ignored.
91 */
92void aidaThrow(JNIEnv* env, vmsstat_t status, char* exception, const char* message)
93{
94 // Clear any exception that may be in the process of being thrown (unlikely)
95 if ((*env)->ExceptionCheck(env)) {
96 (*env)->ExceptionClear(env);
97 }
98
99 char vmsErrorMessage[BUFSIZ] = { '\0' };
100 $DESCRIPTOR(MESSAGE, vmsErrorMessage);
101 struct dsc$descriptor errorMessageDescriptor = { BUFSIZ, DSC$K_DTYPE_T, DSC$K_CLASS_S, (char*)&vmsErrorMessage };
102
103 // Get the message text associated with the VMS message code. if the cause is an OS error
104 if (!SUCCESS(status)) {
105 ERRTRANSLATE(&status, &errorMessageDescriptor);
106 strncat(errorMessageDescriptor.dsc$a_pointer, "; ",
107 MIN(strlen("; "), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
108 }
109
110 // Add exception
111 strncat(errorMessageDescriptor.dsc$a_pointer, exception,
112 MIN(strlen(exception), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
113
114 // If a message is specified then append it to the vms message string
115 if (message) {
116 strncat(errorMessageDescriptor.dsc$a_pointer, "; ",
117 MIN(strlen("; "), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
118 strncat(errorMessageDescriptor.dsc$a_pointer, message,
119 MIN(strlen(message), BUFSIZ - strlen(errorMessageDescriptor.dsc$a_pointer)));
120 }
121
122 fprintf(stderr, "AIDA Exception: %s: %s\n", exception, errorMessageDescriptor.dsc$a_pointer);
123
124 // Create the fully qualified java class name of the exception to throw
125 char classToCreate[BUFSIZ] = "edu/stanford/slac/except/";
126 strcat (classToCreate, exception);
127
128 // Create the java exception class
129 jclass exceptionClass;
130 exceptionClass = (*env)->FindClass(env, classToCreate);
131 if (!exceptionClass) {
132 fprintf(stderr, "FATAL: Failed to create object of class: %s\n", classToCreate);
133 exit((int)status);
134 }
135
136 // Throw the given exception to Java server code, giving the
137 // VMS error text and supplied message as the exception text.
138 (*env)->ThrowNew(env, exceptionClass, errorMessageDescriptor.dsc$a_pointer);
139}
140
141/**
142 * Check if a string @p str, ends with another string @p suffix.
143 *
144 * @param str the string to check.
145 * @param suffix the @p suffix to look for at the end of @p str
146 * @return `true` if @p str ends with @p suffix. `false`
147 */
148int endsWith(const char* str, char* suffix)
149{
150 if (!str || !suffix) {
151 return false;
152 }
153 size_t lenstr = strlen(str);
154 size_t lenSuffix = strlen(suffix);
155 if (lenSuffix > lenstr)
156 return false;
157 return !strncasecmp(str + lenstr - lenSuffix, suffix, lenSuffix);
158}
159
160/**
161 * Check if a string starts with another string
162 * @param str
163 * @param prefix
164 * @returns true if string starts with prefix
165 */
166int startsWith(const char* str, char* prefix)
167{
168 if (!str || !prefix) {
169 return false;
170 }
171 size_t lenstr = strlen(str);
172 size_t lenPrefix = strlen(prefix);
173 if (lenPrefix > lenstr)
174 return false;
175 return !strncasecmp(str, prefix, lenPrefix);
176}
177
178/**
179 * Get a named argument
180 * @param arguments arguments
181 * @param name name
182 * @return Argument
183 */
184Argument getArgument(Arguments arguments, char* name)
185{
186 Argument noArgument;
187 memset(&noArgument, 0, sizeof(Argument));
188
189 for (int i = 0; i < arguments.argumentCount; i++) {
190 Argument argument = arguments.arguments[i];
191 if (!strcasecmp(argument.name, name)) {
192 if (strlen(argument.value) > 0) {
193 return argument;
194 }
195 }
196 }
197 return noArgument;
198}
199
200/**
201 * Implementation of getNamedValue. This will search the given arguments for an argument
202 * with the given name and will create a Value to store it in. If the forArray
203 * flag is set then the argument's value will be coerced into an array.
204 * Note that if json is detected in the value it will be parsed into the Value's
205 * json value element.
206 *
207 * @param env the JNI environment. Used in all functions involving JNI
208 * @param arguments
209 * @param name
210 * @param forArray
211 * @return
212 */
213static Value getNamedValueImpl(JNIEnv* env, Arguments arguments, char* name, bool forArray)
214{
215 Value value;
216 value.type = AIDA_NO_TYPE;
217
218 Argument valueArgument = getArgument(arguments, name);
219 if (valueArgument.name && valueArgument.value) {
220 // Get value to parse and trim leading space
221 char* valueToParse = valueArgument.value;
222 while (isspace(*valueToParse)) {
223 valueToParse++;
224 }
225
226 // Json arrays can only be parsed by this parser by wrapping them in a json object, so we always
227 // create {"_array": [ ... ]} and when pulling out values we always replace
228 // the element "_array" by its value
229 char arrayValueToParse[strlen(valueToParse) + 30];
230
231 if (*valueToParse == '[') {
232 sprintf(arrayValueToParse, "{\"_array\": %s}", valueToParse);
233 valueToParse = arrayValueToParse;
234 } else if (forArray) {
235 if (strstr(valueToParse, "\"") != NULL) {
237 "Unable to parse supplied JSON value string");
238 return value;
239 } else if (isOnlyNumbers(valueToParse)) {
240 sprintf(arrayValueToParse, "{\"_array\": [%s]}", valueToParse);
241 } else {
242 sprintf(arrayValueToParse, "{\"_array\": [\"%s\"]}", valueToParse);
243 }
244 valueToParse = arrayValueToParse;
245 }
246
247 // If this is a json string then parse it otherwise just extract the string
248 if (*valueToParse == '{') {
249 value.value.jsonValue = json_parse(valueToParse, strlen(valueToParse));
250 if (value.value.jsonValue) {
251 value.type = AIDA_JSON_TYPE;
252 } else {
254 "Unable to parse supplied JSON value string");
255 }
256 } else {
257 value.type = AIDA_STRING_TYPE;
258 value.value.stringValue = valueToParse;
259 }
260 }
261
262 return value;
263}
264
265/**
266 * Check if the string contains only numbers, white space or commas
267 * @param string
268 * @return
269 */
270static bool isOnlyNumbers(char* string)
271{
272 if (string == NULL) {
273 return false;
274 }
275 bool isInNumber = true;
276 bool afterComma = false;
277 bool hasDecimalPoint = false;
278 int len = (int)strlen(string);
279 for (int i = 0; i < len; i++) {
280 // Digits (always ok)
281 if (isdigit(string[i])) {
282 // First digit clear comma and point flags
283 if (!isInNumber) {
284 afterComma = false;
285 hasDecimalPoint = false;
286 isInNumber = true;
287 }
288 continue;
289 } else if (string[i] == '.') {
290 // point is ok if this is in a number, and we've not had any other points in this number
291 if (!hasDecimalPoint && isInNumber) {
292 hasDecimalPoint = true;
293 continue;
294 }
295 } else if (string[i] == ',') {
296 // comma is ok except after comma
297 if (!afterComma) {
298 isInNumber = false;
299 afterComma = true;
300 continue;
301 }
302 } else if (isspace(string[i])) {
303 // Space is ok after a comma or digit
304 if (afterComma || isInNumber) {
305 isInNumber = false;
306 continue;
307 }
308 }
309 return false;
310 }
311 return true;
312}
313
314/**
315 * Get value from a named argument in the provided arguments structure.
316 *
317 * @param env the JNI environment. Used in all functions involving JNI
318 * @param arguments provided arguments structure
319 * @param name provided name
320 * @return the extracted Value
321 */
322Value getNamedValue(JNIEnv* env, Arguments arguments, char* name)
323{
324 return getNamedValueImpl(env, arguments, name, false);
325}
326
327/**
328 * Get value from a named argument in the provided arguments structure.
329 *
330 * @param env the JNI environment. Used in all functions involving JNI
331 * @param arguments provided arguments structure
332 * @param name provided name
333 * @return the extracted Value
334 */
335Value getNamedArrayValue(JNIEnv* env, Arguments arguments, char* name)
336{
337 return getNamedValueImpl(env, arguments, name, true);
338}
339
340/**
341 * Get the json value from the given value identified by the path
342 *
343 * @param value the given value
344 * @param passedInPath is an absolute reference to the element within the json of the given value. e.g. root.collection.[0].name
345 * @return pointer to the json_value
346 */
347json_value* getJsonValue(Value* value, char* passedInPath)
348{
349 if (value->type != AIDA_JSON_TYPE || !value->value.jsonValue) {
350 return NULL;
351 }
352
353 json_value* jsonValue = getJsonRoot(value->value.jsonValue);
354
355 // If there is no path then we already have the json value
356 if (!passedInPath || strlen(passedInPath) == 0) {
357 return jsonValue;
358 }
359
360 // can't use const for strtok
361 char path[strlen(passedInPath) + 1];
362 strcpy(path, passedInPath);
363
364 int len;
365 char name[256];
366 char* arrayRef;
367
368 // Extract the first token
369 char* token = strtok(path, ".");
370
371 while (token) {
372 if (*token == '[') {
373 // if array is at top level
374 jsonValue = processArrayReference(jsonValue, token);
375 } else if ((arrayRef = strstr(token, "["))) {
376 // element followed by array ref
377 len = (int)(arrayRef - token);
378 strncpy(name, token, len);
379 name[len] = 0x0;
380 jsonValue = navigateToObjectElement(jsonValue, name);
381
382 jsonValue = processArrayReference(jsonValue, arrayRef);
383 } else {
384 // element only
385 jsonValue = navigateToObjectElement(jsonValue, token);
386 }
387
388 // Next token
389 token = strtok(NULL, ".");
390 }
391
392 return jsonValue;
393}
394
395/**
396 * Skip root element if it is _array otherwise return unchanged
397 *
398 * This is because our json parser can't process arrays at the top level and so we insert
399 * an object at the top level with an "_array" element if we find an array at the top level
400 *
401 * @param jsonValue the json value traverse
402 * @return json value
403 */
404json_value* getJsonRoot(json_value* jsonValue)
405{
406 if (jsonValue->type == json_object && jsonValue->u.object.length == 1
407 && strcmp(jsonValue->u.object.values[0].name, "_array") == 0) {
408 jsonValue = jsonValue->u.object.values[0].value;
409 }
410 return jsonValue;
411}
412
413/**
414 * Process any array references. Because arrays can be directly nested within other array we
415 * allow up to 4 levels of nesting without any intervening object
416 * @param jsonValue
417 * @param arrayRef
418 * @return the new position or unchanged if any index is out of bounds or no indexes are found
419 */
420static json_value* processArrayReference(json_value* jsonValue, const char* arrayRef)
421{
422 int index[4]; // Up to 4 levels of array with no object
423 int count = sscanf(arrayRef, "[%d][%d][%d][%d]", &index[0], &index[1], &index[2], &index[3]);
424
425 while (count > 0) {
426 jsonValue = navigateToArrayElement(jsonValue, index[--count]);
427 }
428 return jsonValue;
429}
430
431/**
432 * Using the given name navigate to the named element from the current position in the json_value
433 * @param jsonValue
434 * @param name
435 * @return the new position or unchanged if the name is not found
436 */
437static json_value* navigateToObjectElement(json_value* jsonValue, const char* name)
438{
439 if (jsonValue->type == json_object) {
440 for (int i = 0; i < jsonValue->u.object.length; i++) {
441 if (strcasecmp(name, jsonValue->u.object.values[i].name) == 0) {
442 jsonValue = jsonValue->u.object.values[i].value;
443 break;
444 }
445 }
446 }
447 return jsonValue;
448}
449/**
450 * Using the given index navigate to the zero based index'th element of the array at the current position
451 * @param jsonValue
452 * @param index
453 * @return the new position or unchanged if the index is out of bounds
454 */
455static json_value* navigateToArrayElement(json_value* jsonValue, int index)
456{
457 if (jsonValue->type == json_array) {
458 if (jsonValue->u.array.length > index) {
459 jsonValue = jsonValue->u.array.values[index];
460 }
461 }
462 return jsonValue;
463}
464
465/**
466 * Get the Display group name from a URI
467 *
468 * @param groupName pre-allocated space to store the group name
469 * @param uri the new format AIDA PV name
470 * @return EXIT_SUCCESS if all goes well EXIT_FAILURE otherwise
471 */
472int groupNameFromUri(char groupName[], const char* uri)
473{
474 strcpy(groupName, uri);
475 char* groupNameEnd = strrchr(groupName, ':');
476 if (groupNameEnd) {
477 *groupNameEnd = 0x0;
478 }
479 return EXIT_SUCCESS;
480}
481
482/**
483 * Get secondary from pseudo secondary (containing a colon) number from URI
484 * e.g. `BD01:BEND:BDES` => `BEND` as int4u
485 *
486 * @param uri the new format AIDA PV name
487 * @param secn pointer to an int to store the secondary as a number
488 */
489void secnFromUri(const char* uri, int4u* secn)
490{
491 char uriCopy[strlen(uri) + 1];
492 strcpy(uriCopy, uri);
493 char* secondary = strrchr(uriCopy, ':');
494 if (secondary) {
495 memcpy(secn, secondary + 1, sizeof(int4u));
496 return;
497 }
498 fprintf(stderr, "Warning: Found corrupt URI when trying to extract secn: %s\n", uri);
499 *secn = 0;
500}
501
502/**
503 * Get secondary from URI. Just points into the URI so don't go messing with it
504 *
505 * @param uri the new format AIDA PV name
506 */
507const char* secondaryFromUri(const char* uri)
508{
509 char* secondary = strrchr(uri, ':');
510 if (!secondary) {
511 fprintf(stderr, "Warning: Secondary not found in uri: %s\n", uri);
512 return uri;
513 }
514 return secondary + 1;
515}
516
517/**
518 * Get the pmu part of a URI
519 *
520 * @param pmuString the pre-allocated space to store the pmu string
521 * @param uri the new format AIDA PV name
522 */
523void pmuStringFromUri(char* pmuString, const char* uri)
524{
525 unsigned long pmuEnd = strrchr(uri, ':') - uri;
526 if (pmuEnd >= MAX_URI_LEN) {
527 pmuEnd = MAX_URI_LEN - 1;
528 }
529 strncpy(pmuString, uri, pmuEnd);
530 pmuString[pmuEnd] = 0x0;
531}
532
533/**
534 * Get primary, micro and unit from a device name
535 *
536 * @param env the JNI environment. Used in all functions involving JNI
537 * @param device pre-allocated space to store the device
538 * @param primary pre-allocated space to store the primary
539 * @param micro pre-allocated space to store the micro
540 * @param unit pre-allocated space to store the unit
541 */
542int pmuFromDeviceName(JNIEnv* env, char* device, char* primary, char* micro, int4u* unit)
543{
544 // Copy each part to the provided variables
545 char* nextPart = strtok(device, ":");
546 unsigned long len;
547 if (nextPart) {
548 len = strlen(nextPart);
549 if (len != 4) {
550 aidaThrowNonOsException(env, UNABLE_TO_GET_DATA_EXCEPTION, "Device name is not valid");
551 return EXIT_FAILURE;
552 }
553 memcpy(primary, nextPart, PRIM_LEN);
554 nextPart = strtok(NULL, ":");
555 if (nextPart) {
556 len = strlen(nextPart);
557 if (len != 4 || !isdigit(nextPart[2]) || !isdigit(nextPart[3])) {
558 aidaThrowNonOsException(env, UNABLE_TO_GET_DATA_EXCEPTION, "Device name is not valid");
559 return EXIT_FAILURE;
560 }
561 memcpy(micro, nextPart, MICRO_LEN);
562 nextPart = strtok(NULL, ":");
563 if (nextPart) {
564 len = strlen(nextPart);
565 if (len < 1 || len > 4 || !isdigit(nextPart[0]) || (len > 1 && !isdigit(nextPart[1]))
566 || (len > 2 && !isdigit(nextPart[2])) || (len > 3 && !isdigit(nextPart[3]))) {
567 aidaThrowNonOsException(env, UNABLE_TO_GET_DATA_EXCEPTION, "Device name is not valid");
568 return EXIT_FAILURE;
569 }
570 *unit = (int4u)atol(nextPart);
571 }
572 }
573 }
574 return EXIT_SUCCESS;
575}
576
577/**
578 * Convert all URIs to slac names before making queries
579 *
580 * @param slcName pointer to space to store the SLC name
581 * @param uri the new format AIDA PV name
582 */
583void uriToSlcName(char slcName[MAX_URI_LEN], const char* uri)
584{
585 char* separator = strrchr(uri, ':');
586 if (separator) {
587 memcpy(slcName, uri, separator - uri);
588 memcpy(slcName + (separator - uri), ".", 1);
589 strcpy(slcName + (separator - uri) + 1, separator + 1);
590 }
591}
592
593/**
594 * Convert the given URI to the legacy AIDA name for low level functions that still require it that way
595 *
596 * @param legacyName pointer to space to store the legacy AIDA name
597 * @param uri the new format AIDA PV name
598 */
599void uriLegacyName(char legacyName[MAX_URI_LEN], const char* uri)
600{
601 char* firstSeparator = strchr(uri, ':');
602 char* secondSeparator = strchr(firstSeparator + 1, ':');
603 char* lastSeparator = strrchr(uri, ':');
604 // See how many colons. If only three then this is a pseudo and we need to separate after first
605 if (lastSeparator == secondSeparator) {
606 // This has only three parts so separate at first colon
607 memcpy(legacyName, uri, firstSeparator - uri);
608 memcpy(legacyName + (firstSeparator - uri), "//", 2);
609 strcpy(legacyName + (firstSeparator - uri) + 2, firstSeparator + 1);
610 } else {
611 // Normal URI separate at last colon
612 memcpy(legacyName, uri, lastSeparator - uri);
613 memcpy(legacyName + (lastSeparator - uri), "//", 2);
614 strcpy(legacyName + (lastSeparator - uri) + 2, lastSeparator + 1);
615 }
616}
617
618/**
619 * Allocate memory and copy the source to it if specified. If the null terminate flag is set
620 * null terminate the allocate space, at the last position
621 *
622 * @param env to be used to throw exceptions using aidaThrow() and aidaThrowNonOsException()
623 * @param source source of data to copy to newly allocated space, NULL to not copy
624 * @param size the amount of space to allocate
625 * @param nullTerminate true to null terminate
626 * @param message the message to display if anything goes wrong
627 * @return the allocated memory
628 */
629void* allocateMemory(JNIEnv* env, void* source, size_t size, bool nullTerminate, char* message)
630{
631 void* data = malloc(size);
632 if (!data) {
634 return NULL;
635 }
636 if (source) {
637 memcpy(data, source, size - (nullTerminate ? 1 : 0));
638 if (nullTerminate) {
639 *(char*)((char*)data + size - 1) = 0x0;
640 }
641 }
642 return data;
643}
644
645
#define AIDA_INTERNAL_EXCEPTION
Use this string to signal Internal Exceptions in aidaThrow()
#define UNABLE_TO_GET_DATA_EXCEPTION
Use this string to signal Exceptions when trying to Get Data in aidaThrow()
Value getNamedArrayValue(JNIEnv *env, Arguments arguments, char *name)
Get value from a named argument in the provided arguments structure.
int startsWith(const char *str, char *prefix)
Check if a string starts with another string.
void pmuStringFromUri(char *pmuString, const char *uri)
Get the pmu part of a URI.
const char * secondaryFromUri(const char *uri)
Get secondary from URI.
int groupNameFromUri(char groupName[], const char *uri)
Get the Display group name from a URI.
void secnFromUri(const char *uri, int4u *secn)
Get secondary from pseudo secondary (containing a colon) number from URI e.g.
int endsWith(const char *str, char *suffix)
Check if a string str, ends with another string suffix.
void aidaThrow(JNIEnv *env, vmsstat_t status, char *exception, const char *message)
To log any exceptions and throw back to java.
unsigned long int STANDALONE_INIT(const struct dsc$descriptor_s *name, const long int *dbinit, const struct msginit *msginit, const long int *query, const long int *set)
standalone init is used to initialise standalone processes
vmsstat_t init(const char *processName, bool initMessageServices)
Call standalone_init()
void * allocateMemory(JNIEnv *env, void *source, size_t size, bool nullTerminate, char *message)
Allocate memory and copy the source to it if specified.
json_value * getJsonValue(Value *value, char *passedInPath)
Get the json value from the given value identified by the path.
Argument getArgument(Arguments arguments, char *name)
Get a named argument.
Value getNamedValue(JNIEnv *env, Arguments arguments, char *name)
Get value from a named argument in the provided arguments structure.
json_value * getJsonRoot(json_value *jsonValue)
void uriLegacyName(char legacyName[MAX_URI_LEN], const char *uri)
Convert the given URI to the legacy AIDA name for low level functions that still require it that way.
void aidaThrowNonOsException(JNIEnv *env, char *exception, const char *message)
To log any non-OS exceptions and throw back to java.
void uriToSlcName(char slcName[MAX_URI_LEN], const char *uri)
Convert all URIs to slac names before making queries.
int pmuFromDeviceName(JNIEnv *env, char *device, char *primary, char *micro, int4u *unit)
Get primary, micro and unit from a device name.
The Header File for the Native Channel Provider Server Helper functions.
@ AIDA_JSON_TYPE
Argument was provided as JSON text.
@ AIDA_STRING_TYPE
Represents a string.
@ AIDA_NO_TYPE
Used to indicate that no type was provided as an argument.
#define PRIM_LEN
The length of the primary part of a PMU string.
Definition: aida_pva_uri.h:24
#define MAX_URI_LEN
The maximum length of a URI.
Definition: aida_pva_uri.h:20
#define MICRO_LEN
The length of the micro part of a PMU string.
Definition: aida_pva_uri.h:28
A single request argument.
char * value
The string value of the argument.
char * name
The name of the argument.
An Arguments structure stores all of the arguments passed from the request to the Native Channel Prov...
int argumentCount
The number of arguments sent with this request.
Argument * arguments
The array of Arguments.
This special type represents a Value.
ValueContents value
The value's contents, either a string or parsed json.
Type type
AIDA_STRING_TYPE or AIDA_JSON_TYPE.
json_value * jsonValue
The parsed json_value of this Value if the type is AIDA_JSON_TYPE.
char * stringValue
The string value of this Value if the type is AIDA_STRING_TYPE.