36 #include <epicsGuard.h>
37 #include <epicsString.h>
40 #include "pugixml.hpp"
42 #include "asynPortDriver.h"
47 #define MAX_PATH_LEN 256
58 static std::string
ni_message(
const std::string&
function,
int code)
60 return function +
": " + CNVGetErrorDescription(code);
64 #define ERROR_CHECK(__func, __code) \
67 throw NetShrVarException(__func, __code); \
76 return "Connecting...";
82 return "Disconnected";
108 status = CNVDisposeData(
m_value);
130 NvItem(
const char* nv_name_,
const char* type_,
unsigned access_,
int field_) :
nv_name(nv_name_),
type(type_),
access(access_),
136 void report(
const std::string& name, FILE* fp)
138 fprintf(fp,
"Report for asyn parameter \"%s\" type \"%s\" network variable \"%s\"\n", name.c_str(),
type.c_str(),
nv_name.c_str());
141 fprintf(fp,
" Current array size: %d\n", (
int)
array_data.size());
145 fprintf(fp,
" Network variable structure index: %d\n",
field);
152 void report(FILE* fp,
const char* conn_type,
void* handle,
bool buffered)
154 int error, conn_error;
155 CNVConnectionStatus status;
156 fprintf(fp,
" Connection type: %s", conn_type);
159 fprintf(fp,
" Status: <not being used>\n");
162 error = CNVGetConnectionAttribute(handle, CNVConnectionStatusAttribute, &status);
165 error = CNVGetConnectionAttribute(handle, CNVConnectionErrorAttribute, &conn_error);
169 fprintf(fp,
" error present: %s", CNVGetErrorDescription(conn_error));
173 int nitems, maxitems;
174 error = CNVGetConnectionAttribute(handle, CNVClientBufferNumberOfItemsAttribute, &nitems);
176 error = CNVGetConnectionAttribute(handle, CNVClientBufferMaximumItemsAttribute, &maxitems);
178 fprintf(fp,
" Client buffer: %d items (buffer size = %d)", nitems, maxitems);
193 static void CVICALLBACK
DataCallback (
void * handle, CNVData data,
void * callbackData);
194 static void CVICALLBACK
StatusCallback (
void * handle, CNVConnectionStatus status,
int error,
void * callbackData);
202 int clientBufferMaxItems = 200;
205 error = CNVVariableEngineIsRunning(&running);
209 std::cerr <<
"connectVars: Variable engine is not running" << std::endl;
212 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
214 NvItem* item = it->second;
220 std::cerr <<
"connectVars: connecting to \"" << item->
nv_name <<
"\"" << std::endl;
249 char* description = NULL;
250 int error = CNVGetDataQualityDescription(quality,
";", &description);
254 CNVFreeMemory(description);
258 res = std::string(
"CNVGetDataQualityDescription: ") + CNVGetErrorDescription(error);
275 std::cerr <<
"dataTransferredCallback: \"" << cb_data->
nv_name <<
"\": " << CNVGetErrorDescription(error) << std::endl;
284 static void CVICALLBACK
DataCallback (
void * handle, CNVData data,
void * callbackData)
288 CNVDisposeData (data);
299 catch(
const std::exception& ex)
301 std::cerr <<
"dataCallback: ERROR updating param index " << cb_data->
param_index <<
": " << ex.what() << std::endl;
305 std::cerr <<
"dataCallback: ERROR updating param index " << cb_data->
param_index << std::endl;
312 const char *paramName = NULL;
313 m_driver->getParamName(param_index, ¶mName);
315 if (
m_params[paramName]->type ==
"float64")
317 m_driver->setDoubleParam(param_index, convertToScalar<double>(val));
319 else if (
m_params[paramName]->type ==
"int32" ||
m_params[paramName]->type ==
"boolean")
321 m_driver->setIntegerParam(param_index, convertToScalar<int>(val));
323 else if (
m_params[paramName]->type ==
"string")
325 m_driver->setStringParam(param_index, convertToPtr<char>(val));
329 std::cerr <<
"updateParamValue: unknown type \"" <<
m_params[paramName]->type <<
"\" for param \"" << paramName <<
"\"" << std::endl;
331 if (do_asyn_param_callbacks)
338 template<
typename T,
typename U>
341 const char *paramName = NULL;
342 m_driver->getParamName(param_index, ¶mName);
343 std::vector<char>& array_data =
m_params[paramName]->array_data;
344 U* eval = convertToPtr<U>(val);
347 array_data.resize(nElements *
sizeof(T));
348 memcpy(&(array_data[0]), eval, nElements *
sizeof(T));
353 std::cerr <<
"updateParamArrayValue: cannot update param \"" << paramName <<
"\": shared variable data type incompatible \"" <<
C2CNV<T>::desc <<
"\"" << std::endl;
360 const char *paramName = NULL;
361 m_driver->getParamName(param_index, ¶mName);
363 if (
m_params[paramName]->type ==
"float64array")
365 updateParamArrayValueImpl<T,epicsFloat64>(param_index, val, nElements);
367 else if (
m_params[paramName]->type ==
"float32array")
369 updateParamArrayValueImpl<T,epicsFloat32>(param_index, val, nElements);
371 else if (
m_params[paramName]->type ==
"int32array")
373 updateParamArrayValueImpl<T,epicsInt32>(param_index, val, nElements);
375 else if (
m_params[paramName]->type ==
"int16array")
377 updateParamArrayValueImpl<T,epicsInt16>(param_index, val, nElements);
379 else if (
m_params[paramName]->type ==
"int8array")
381 updateParamArrayValueImpl<T,epicsInt8>(param_index, val, nElements);
385 std::cerr <<
"updateParamArrayValue: unknown type \"" <<
m_params[paramName]->type <<
"\" for param \"" << paramName <<
"\"" << std::endl;
390 template <
typename T>
393 std::vector<char>& array_data =
m_params[paramName]->array_data;
394 size_t n = array_data.size() /
sizeof(T);
400 memcpy(value, &(array_data[0]), n *
sizeof(T));
403 template<CNVDataType cnvType>
409 int status = CNVGetScalarDataValue (data, type, &val);
417 size_t dimensions[10];
418 int status = CNVGetArrayDataDimensions(data, nDims, dimensions);
420 size_t nElements = 1;
421 for(
unsigned i=0; i<nDims; ++i)
423 nElements *= dimensions[i];
426 status = CNVGetArrayDataValue(data, type, val, nElements);
436 unsigned int serverError;
438 CNVDataQuality quality;
439 unsigned __int64 timestamp;
440 int year, month, day, hour, minute, good;
443 unsigned short numberOfFields = 0;
444 const char *paramName = NULL;
445 m_driver->getParamName(param_index, ¶mName);
451 status = CNVGetDataType (data, &type, &nDims);
453 if (type == CNVStruct)
455 int field =
m_params[paramName]->field;
456 status = CNVGetNumberOfStructFields(data, &numberOfFields);
458 if (numberOfFields == 0)
460 throw std::runtime_error(
"number of fields");
462 if (field < 0 || field >= numberOfFields)
464 throw std::runtime_error(
"field index");
466 CNVData* fields =
new CNVData[numberOfFields];
467 status = CNVGetStructFields(data, fields, numberOfFields);
469 updateParamCNV(param_index, fields[field], do_asyn_param_callbacks);
473 status = CNVGetDataQuality(data, &quality);
475 status = CNVCheckDataQuality(quality, &good);
477 status = CNVGetDataUTCTimestamp(data, ×tamp);
479 status = CNVGetTimestampInfo(timestamp, &year, &month, &day, &hour, &minute, &second);
483 std::cerr <<
"updateParamCNV: data for param " << paramName <<
" is not good quality: " <<
dataQuality(quality) << std::endl;
491 updateParamCNVImpl<CNVBool>(param_index, data, type, nDims, do_asyn_param_callbacks);
495 updateParamCNVImpl<CNVString>(param_index, data, type, nDims, do_asyn_param_callbacks);
499 updateParamCNVImpl<CNVSingle>(param_index, data, type, nDims, do_asyn_param_callbacks);
503 updateParamCNVImpl<CNVDouble>(param_index, data, type, nDims, do_asyn_param_callbacks);
507 updateParamCNVImpl<CNVInt8>(param_index, data, type, nDims, do_asyn_param_callbacks);
511 updateParamCNVImpl<CNVUInt8>(param_index, data, type, nDims, do_asyn_param_callbacks);
515 updateParamCNVImpl<CNVInt16>(param_index, data, type, nDims, do_asyn_param_callbacks);
519 updateParamCNVImpl<CNVUInt16>(param_index, data, type, nDims, do_asyn_param_callbacks);
523 updateParamCNVImpl<CNVInt32>(param_index, data, type, nDims, do_asyn_param_callbacks);
527 updateParamCNVImpl<CNVUInt32>(param_index, data, type, nDims, do_asyn_param_callbacks);
531 updateParamCNVImpl<CNVInt64>(param_index, data, type, nDims, do_asyn_param_callbacks);
535 updateParamCNVImpl<CNVUInt64>(param_index, data, type, nDims, do_asyn_param_callbacks);
539 std::cerr <<
"updateParamCNV: unknown type " << type <<
" for param " << paramName << std::endl;
542 status = CNVGetDataServerError(data, &serverError);
543 if (status == 0 && serverError != 0)
545 std::cerr <<
"updateParamCNV: Server error: " << serverError << std::endl;
549 std::cerr <<
"updateParamCNV: CNVGetDataServerError: " << CNVGetErrorDescription(status) << std::endl;
555 static void CVICALLBACK
StatusCallback (
void * handle, CNVConnectionStatus status,
int error,
void * callbackData)
566 std::cerr <<
"StatusCallback: " << cb_data->
nv_name <<
": " << CNVGetErrorDescription(error) << std::endl;
574 static epicsThreadOnceId
onceId = EPICS_THREAD_ONCE_INIT;
578 char* dummy_argv[2] = { strdup(
"NetShrVarInterface"), NULL };
579 if (InitCVIRTE (0, dummy_argv, 0) == 0)
580 throw std::runtime_error(
"InitCVIRTE");
587 m_configSection(configSection), m_options(options)
590 char* configFile_expanded = macEnvExpand(configFile);
594 pugi::xml_parse_result result =
m_xmlconfig.load_file(configFile_expanded);
595 free(configFile_expanded);
598 std::cerr <<
"Loaded XML config file \"" <<
m_configFile <<
"\" (expanded from \"" << configFile <<
"\")" << std::endl;
602 throw std::runtime_error(
"Cannot load XML \"" +
m_configFile +
"\" (expanded from \"" + std::string(configFile) +
"\"): load failure: "
603 + result.description());
624 epicsSnprintf(control_name_xpath,
sizeof(control_name_xpath),
"/netvar/section[@name='%s']/param",
m_configSection.c_str());
627 pugi::xpath_node_set params =
m_xmlconfig.select_nodes(control_name_xpath);
628 return params.size();
630 catch(
const std::exception& ex)
632 std::cerr <<
"nparams failed " << ex.what() << std::endl;
639 static const char* functionName =
"createParams";
644 NvItem* item = it->second;
645 if (item->
type ==
"float64")
647 m_driver->createParam(it->first.c_str(), asynParamFloat64, &(item->
id));
649 else if (item->
type ==
"int32" || item->
type ==
"boolean")
651 m_driver->createParam(it->first.c_str(), asynParamInt32, &(item->
id));
653 else if (item->
type ==
"string")
655 m_driver->createParam(it->first.c_str(), asynParamOctet, &(item->
id));
657 else if (item->
type ==
"float64array")
659 m_driver->createParam(it->first.c_str(), asynParamFloat64Array, &(item->
id));
661 else if (item->
type ==
"float32array")
663 m_driver->createParam(it->first.c_str(), asynParamFloat32Array, &(item->
id));
665 else if (item->
type ==
"int32array")
667 m_driver->createParam(it->first.c_str(), asynParamInt32Array, &(item->
id));
669 else if (item->
type ==
"int16array")
671 m_driver->createParam(it->first.c_str(), asynParamInt16Array, &(item->
id));
673 else if (item->
type ==
"int8array")
675 m_driver->createParam(it->first.c_str(), asynParamInt8Array, &(item->
id));
679 errlogSevPrintf(errlogMajor,
"%s:%s: unknown type %s for parameter %s\n",
driverName,
680 functionName, item->
type.c_str(), it->first.c_str());
690 epicsSnprintf(control_name_xpath,
sizeof(control_name_xpath),
"/netvar/section[@name='%s']/param",
m_configSection.c_str());
691 pugi::xpath_node_set params;
694 params =
m_xmlconfig.select_nodes(control_name_xpath);
695 if (params.size() == 0)
697 std::cerr <<
"getParams failed" << std::endl;
701 catch(
const std::exception& ex)
703 std::cerr <<
"getParams failed " << ex.what() << std::endl;
707 unsigned access_mode;
708 char *last_str = NULL;
709 char *access_str, *str;
710 for (pugi::xpath_node_set::const_iterator it = params.begin(); it != params.end(); ++it)
712 pugi::xpath_node node = *it;
713 std::string attr1 = node.node().attribute(
"name").value();
714 std::string attr2 = node.node().attribute(
"type").value();
715 std::string attr3 = node.node().attribute(
"access").value();
716 std::string attr4 = node.node().attribute(
"netvar").value();
717 std::string attr5 = node.node().attribute(
"field").value();
718 if (attr5.size() == 0)
724 field = atoi(attr5.c_str());
726 access_str = strdup(attr3.c_str());
728 str = epicsStrtok_r(access_str,
",", &last_str);
731 if (!strcmp(str,
"R"))
735 else if (!strcmp(str,
"BR"))
739 else if (!strcmp(str,
"W"))
743 else if (!strcmp(str,
"BW"))
749 std::cerr <<
"getParams: Unknown access mode \"" << str <<
"\" for param " << attr1 << std::endl;
751 str = epicsStrtok_r(NULL,
",", &last_str);
754 m_params[attr1] =
new NvItem(attr4.c_str(),attr2.c_str(),access_mode,field);
763 int status = CNVCreateScalarDataValue(&cvalue, CNVString, value.c_str());
768 template <
typename T>
772 int status = CNVCreateScalarDataValue(&cvalue, static_cast<CNVDataType>(
C2CNV<T>::nvtype), value);
777 template <
typename T>
781 size_t dimensions[1] = { nElements };
782 int status = CNVCreateArrayDataValue(&cvalue, static_cast<CNVDataType>(
C2CNV<T>::nvtype), value, 1, dimensions);
789 int wait_ms = CNVWaitForever, b_wait_ms = CNVDoNotWait;
792 if (item->
field != -1)
794 throw std::runtime_error(
"setValueCNV: unable to update struct variable via param \"" + name +
"\"");
798 error = CNVWrite(item->
writer, value, wait_ms);
802 error = CNVPutDataInBuffer(item->
b_writer, value, b_wait_ms);
806 throw std::runtime_error(
"setValueCNV: param \"" + name +
"\" does not define a writer for \"" + item->
nv_name +
"\"");
814 CNVBufferDataStatus dataStatus;
817 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
819 const NvItem* item = it->second;
827 status = CNVGetDataFromBuffer(item->
b_subscriber, &value, &dataStatus);
829 if (dataStatus == CNVNewData || dataStatus == CNVDataWasLost)
833 if (dataStatus == CNVDataWasLost)
835 std::cerr <<
"updateValues: data was lost for param \"" << it->first <<
"\" (" << item->
nv_name <<
")" << std::endl;
850 fprintf(fp,
"XML ConfigFile: \"%s\"\n",
m_configFile.c_str());
851 fprintf(fp,
"XML ConfigFile section: \"%s\"\n",
m_configSection.c_str());
852 fprintf(fp,
"NetShrVarConfigure() Options: %d\n",
m_options);
855 NvItem* item = it->second;
856 item->
report(it->first, fp);
860 #ifndef DOXYGEN_SHOULD_SKIP_THIS
CNVBufferedSubscriber b_subscriber
void report(FILE *fp, const char *conn_type, void *handle, bool buffered)
CallbackData(NetShrVarInterface *intf_, const std::string &nv_name_, int param_index_)
Stores information to be passed back via a shared variable callback on a subscriber connection...
static std::string dataQuality(CNVDataQuality quality)
the quality of the data in a network shared variable
int m_options
the various NetShrVarOptions currently in use
void updateParamCNVImpl(int param_index, CNVData data, CNVDataType type, unsigned int nDims, bool do_asyn_param_callbacks)
static void free(ctype)
function to free any memory associated with type
std::string m_configSection
section of configFile to load information from
void setValue(const char *param, const T &value)
std::string type
type as specified in the XML file e.g. float64array
std::vector< char > array_data
only used for array parameters, contains cached copy of data as this is not stored in usual asyn para...
#define ERROR_CHECK(__func, __code)
NetShrVarException(const std::string &function, int code)
NetShrVarInterface(const char *configSection, const char *configFile, int options)
section name of configFile to use to configure this asyn port
NvItem(const char *nv_name_, const char *type_, unsigned access_, int field_)
static void CVICALLBACK StatusCallback(void *handle, CNVConnectionStatus status, int error, void *callbackData)
called when status of a network shared variable changes
NetShrVarInterface * intf
static void CVICALLBACK DataTransferredCallback(void *handle, int error, void *callbackData)
called when data has been transferred to the variable
void report(FILE *fp, int details)
Helper for EPICS driver report function.
static const char * driverName
Name of driver for use in message printing.
pugi::xml_document m_xmlconfig
Manager class for the NetVar Interaction. Parses an netvarconfig.xml file and provides access to the ...
void setValueCNV(const std::string &name, CNVData value)
void updateParamCNV(int param_index, CNVData data, bool do_asyn_param_callbacks)
std::string nv_name
full path to network shared variable
void createParams(asynPortDriver *driver)
enum NvItem::@13 NvAccessMode
possible access modes to network shared variable
void updateParamArrayValueImpl(int param_index, T *val, size_t nElements)
int field
if we refer to a struct, this is the index of the field (starting at 0), otherwise it is -1 ...
void readArrayValue(const char *paramName, T *value, size_t nElements, size_t *nIn)
static std::string ni_message(const std::string &function, int code)
void report(const std::string &name, FILE *fp)
helper for asyn driver report function
ScopedCNVData(const CNVData &d)
static const char * connectionStatus(CNVConnectionStatus status)
connection status of a network shared variable
An STL exception object encapsulating a shared variable error message.
asynPortDriver * m_driver
CNVBufferedWriter b_writer
void dataCallback(void *handle, CNVData data, CallbackData *cb_data)
called by DataCallback() when new data is available on a subscriber connection
Header file for network shared variable to EPICS type convertion routines.
static void initCV(void *)
int ctype
an instance of the underlying type
static void epicsExitFunc(void *arg)
void setArrayValue(const char *param, const T *value, size_t nElements)
void updateParamValue(int param_index, T val, bool do_asyn_param_callbacks)
void statusCallback(void *handle, CNVConnectionStatus status, int error, CallbackData *cb_data)
called by StatusCallback() when status of a network shared variable changes
ScopedCNVData & operator=(const CNVData &d)
void updateValues()
update values from buffered subscribers
void dataTransferredCallback(void *handle, int error, CallbackData *cb_data)
called when data has been transferred to the variable
header for NetShrVarInterface class.
details about a network shared variable we have connected to an asyn parameter
static epicsThreadOnceId onceId
static void CVICALLBACK DataCallback(void *handle, CNVData data, void *callbackData)
called when new data is available on a subscriber connection
void updateParamArrayValue(int param_index, T *val, size_t nElements)
NetShrVarException(const std::string &message)
For a given C data type, provide the appropriate network shared variable type.
A CNVData item that automatically "disposes" itself.
int id
asyn parameter id, -1 if not assigned
unsigned access
combination of NvAccessMode
ScopedCNVData & operator=(const ScopedCNVData &d)
ScopedCNVData(const ScopedCNVData &d)