35 #include <epicsGuard.h>
36 #include <epicsString.h>
39 #include "asynPortDriver.h"
44 #define MAX_PATH_LEN 256
55 static std::string
ni_message(
const std::string&
function,
int code)
57 return function +
": " + CNVGetErrorDescription(code);
61 #define ERROR_CHECK(__func, __code) \
64 throw NINetVarException(__func, __code); \
73 return "Connecting...";
79 return "Disconnected";
105 status = CNVDisposeData(m_value);
127 NvItem(
const char* nv_name_,
const char* type_,
unsigned access_,
int field_) : nv_name(nv_name_), type(type_), access(access_),
128 field(field_), id(-1), subscriber(0), b_subscriber(0), writer(0), b_writer(0)
130 std::replace(nv_name.begin(), nv_name.end(),
'/',
'\\');
133 void report(
const std::string& name, FILE* fp)
135 fprintf(fp,
"Report for asyn parameter \"%s\" type \"%s\" network variable \"%s\"\n", name.c_str(), type.c_str(), nv_name.c_str());
136 if (array_data.size() > 0)
138 fprintf(fp,
" Current array size: %d\n", array_data.size());
142 fprintf(fp,
" Network variable structure index: %d\n", field);
144 report(fp,
"subscriber", subscriber,
false);
145 report(fp,
"buffered subscriber", b_subscriber,
true);
146 report(fp,
"writer", writer,
false);
147 report(fp,
"buffered writer", b_writer,
true);
149 void report(FILE* fp,
const char* conn_type,
void* handle,
bool buffered)
151 int error, conn_error;
152 CNVConnectionStatus status;
153 fprintf(fp,
" Connection type: %s", conn_type);
156 fprintf(fp,
" Status: <not being used>\n");
159 error = CNVGetConnectionAttribute(handle, CNVConnectionStatusAttribute, &status);
162 error = CNVGetConnectionAttribute(handle, CNVConnectionErrorAttribute, &conn_error);
166 fprintf(fp,
" error present: %s", CNVGetErrorDescription(conn_error));
170 int nitems, maxitems;
171 error = CNVGetConnectionAttribute(handle, CNVClientBufferNumberOfItemsAttribute, &nitems);
173 error = CNVGetConnectionAttribute(handle, CNVClientBufferMaximumItemsAttribute, &maxitems);
175 fprintf(fp,
" Client buffer: %d items (buffer size = %d)", nitems, maxitems);
190 static void CVICALLBACK
DataCallback (
void * handle, CNVData data,
void * callbackData);
191 static void CVICALLBACK
StatusCallback (
void * handle, CNVConnectionStatus status,
int error,
void * callbackData);
199 int clientBufferMaxItems = 200;
200 error = CNVVariableEngineIsRunning(&running);
204 std::cerr <<
"connectVars: Variable engine is not running" << std::endl;
206 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
208 NvItem* item = it->second;
214 std::cerr <<
"connectVars: connecting to \"" << item->
nv_name <<
"\"" << std::endl;
243 char* description = NULL;
244 int error = CNVGetDataQualityDescription(quality,
";", &description);
248 CNVFreeMemory(description);
252 res = std::string(
"CNVGetDataQualityDescription: ") + CNVGetErrorDescription(error);
269 std::cerr <<
"dataTransferredCallback: \"" << cb_data->
nv_name <<
"\": " << CNVGetErrorDescription(error) << std::endl;
278 static void CVICALLBACK
DataCallback (
void * handle, CNVData data,
void * callbackData)
282 CNVDisposeData (data);
293 catch(
const std::exception& ex)
295 std::cerr <<
"dataCallback: ERROR updating param index " << cb_data->
param_index <<
": " << ex.what() << std::endl;
299 std::cerr <<
"dataCallback: ERROR updating param index " << cb_data->
param_index << std::endl;
306 const char *paramName = NULL;
307 m_driver->getParamName(param_index, ¶mName);
309 if (
m_params[paramName]->type ==
"float64")
311 m_driver->setDoubleParam(param_index, convertToScalar<double>(val));
313 else if (
m_params[paramName]->type ==
"int32" ||
m_params[paramName]->type ==
"boolean")
315 m_driver->setIntegerParam(param_index, convertToScalar<int>(val));
317 else if (
m_params[paramName]->type ==
"string")
319 m_driver->setStringParam(param_index, convertToPtr<char>(val));
323 std::cerr <<
"updateParamValue: unknown type \"" <<
m_params[paramName]->type <<
"\" for param \"" << paramName <<
"\"" << std::endl;
325 if (do_asyn_param_callbacks)
332 template<
typename T,
typename U>
335 const char *paramName = NULL;
336 m_driver->getParamName(param_index, ¶mName);
337 std::vector<char>& array_data =
m_params[paramName]->array_data;
338 U* eval = convertToPtr<U>(val);
341 array_data.resize(nElements *
sizeof(T));
342 memcpy(&(array_data[0]), eval, nElements *
sizeof(T));
347 std::cerr <<
"updateParamArrayValue: cannot update param \"" << paramName <<
"\": shared variable data type incompatible \"" <<
C2CNV<T>::desc <<
"\"" << std::endl;
354 const char *paramName = NULL;
355 m_driver->getParamName(param_index, ¶mName);
357 if (
m_params[paramName]->type ==
"float64array")
359 updateParamArrayValueImpl<T,epicsFloat64>(param_index, val, nElements);
361 if (
m_params[paramName]->type ==
"float32array")
363 updateParamArrayValueImpl<T,epicsFloat32>(param_index, val, nElements);
365 else if (
m_params[paramName]->type ==
"int32array")
367 updateParamArrayValueImpl<T,epicsInt32>(param_index, val, nElements);
369 else if (
m_params[paramName]->type ==
"int16array")
371 updateParamArrayValueImpl<T,epicsInt16>(param_index, val, nElements);
373 else if (
m_params[paramName]->type ==
"int8array")
375 updateParamArrayValueImpl<T,epicsInt8>(param_index, val, nElements);
379 std::cerr <<
"updateParamArrayValue: unknown type \"" <<
m_params[paramName]->type <<
"\" for param \"" << paramName <<
"\"" << std::endl;
384 template <
typename T>
387 std::vector<char>& array_data =
m_params[paramName]->array_data;
388 size_t n = array_data.size() /
sizeof(T);
394 memcpy(value, &(array_data[0]), n *
sizeof(T));
397 template<CNVDataType cnvType>
403 int status = CNVGetScalarDataValue (data, type, &val);
411 size_t dimensions[10];
412 int status = CNVGetArrayDataDimensions(data, nDims, dimensions);
414 size_t nElements = 1;
415 for(
unsigned i=0; i<nDims; ++i)
417 nElements *= dimensions[i];
420 status = CNVGetArrayDataValue(data, type, val, nElements);
430 unsigned int serverError;
432 CNVDataQuality quality;
433 unsigned __int64 timestamp;
434 int year, month, day, hour, minute, good;
437 unsigned short numberOfFields = 0;
438 const char *paramName = NULL;
439 m_driver->getParamName(param_index, ¶mName);
445 status = CNVGetDataType (data, &type, &nDims);
447 if (type == CNVStruct)
449 int field =
m_params[paramName]->field;
450 status = CNVGetNumberOfStructFields(data, &numberOfFields);
452 if (numberOfFields == 0)
454 throw std::runtime_error(
"number of fields");
456 if (field < 0 || field >= numberOfFields)
458 throw std::runtime_error(
"field index");
460 CNVData* fields =
new CNVData[numberOfFields];
461 status = CNVGetStructFields(data, fields, numberOfFields);
463 updateParamCNV(param_index, fields[field], do_asyn_param_callbacks);
467 status = CNVGetDataQuality(data, &quality);
469 status = CNVCheckDataQuality(quality, &good);
471 status = CNVGetDataUTCTimestamp(data, ×tamp);
473 status = CNVGetTimestampInfo(timestamp, &year, &month, &day, &hour, &minute, &second);
477 std::cerr <<
"updateParamCNV: data for param " << paramName <<
" is not good quality: " <<
dataQuality(quality) << std::endl;
485 updateParamCNVImpl<CNVBool>(param_index, data, type, nDims, do_asyn_param_callbacks);
489 updateParamCNVImpl<CNVString>(param_index, data, type, nDims, do_asyn_param_callbacks);
493 updateParamCNVImpl<CNVSingle>(param_index, data, type, nDims, do_asyn_param_callbacks);
497 updateParamCNVImpl<CNVDouble>(param_index, data, type, nDims, do_asyn_param_callbacks);
501 updateParamCNVImpl<CNVInt8>(param_index, data, type, nDims, do_asyn_param_callbacks);
505 updateParamCNVImpl<CNVUInt8>(param_index, data, type, nDims, do_asyn_param_callbacks);
509 updateParamCNVImpl<CNVInt16>(param_index, data, type, nDims, do_asyn_param_callbacks);
513 updateParamCNVImpl<CNVUInt16>(param_index, data, type, nDims, do_asyn_param_callbacks);
517 updateParamCNVImpl<CNVInt32>(param_index, data, type, nDims, do_asyn_param_callbacks);
521 updateParamCNVImpl<CNVUInt32>(param_index, data, type, nDims, do_asyn_param_callbacks);
525 updateParamCNVImpl<CNVInt64>(param_index, data, type, nDims, do_asyn_param_callbacks);
529 updateParamCNVImpl<CNVUInt64>(param_index, data, type, nDims, do_asyn_param_callbacks);
533 std::cerr <<
"updateParamCNV: unknown type " << type <<
" for param " << paramName << std::endl;
536 status = CNVGetDataServerError(data, &serverError);
537 if (status == 0 && serverError != 0)
539 std::cerr <<
"updateParamCNV: Server error: " << serverError << std::endl;
543 std::cerr <<
"updateParamCNV: CNVGetDataServerError: " << CNVGetErrorDescription(status) << std::endl;
549 static void CVICALLBACK
StatusCallback (
void * handle, CNVConnectionStatus status,
int error,
void * callbackData)
560 std::cerr <<
"StatusCallback: " << cb_data->
nv_name <<
": " << CNVGetErrorDescription(error) << std::endl;
568 static epicsThreadOnceId
onceId = EPICS_THREAD_ONCE_INIT;
572 char* dummy_argv[2] = {
"NINetVarInterface", NULL };
573 if (InitCVIRTE (0, dummy_argv, 0) == 0)
574 throw std::runtime_error(
"InitCVIRTE");
580 CoInitializeEx(NULL, COINIT_MULTITHREADED);
581 HRESULT hr=CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_SERVER, IID_IXMLDOMDocument2, (
void**)&
m_pxmldom);
584 throw std::runtime_error(
"Cannot load DomFromCom");
589 m_pxmldom->put_validateOnParse(VARIANT_FALSE);
590 m_pxmldom->put_resolveExternals(VARIANT_FALSE);
594 throw std::runtime_error(
"Cannot load DomFromCom");
602 m_configSection(configSection), m_options(options)
606 short sResult = FALSE;
607 char* configFile_expanded = macEnvExpand(configFile);
609 HRESULT hr =
m_pxmldom->load(_variant_t(configFile_expanded), &sResult);
610 free(configFile_expanded);
613 throw std::runtime_error(
"Cannot load XML \"" +
m_configFile +
"\" (expanded from \"" + std::string(configFile) +
"\"): load failure");
615 if (sResult != VARIANT_TRUE)
617 throw std::runtime_error(
"Cannot load XML \"" +
m_configFile +
"\" (expanded from \"" + std::string(configFile) +
"\"): load failure");
619 std::cerr <<
"Loaded XML config file \"" <<
m_configFile <<
"\" (expanded from \"" << configFile <<
"\")" << std::endl;
642 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/ninetvar/section[@name='%s']/param",
m_configSection.c_str());
643 IXMLDOMNodeList* pXMLDomNodeList = NULL;
644 HRESULT hr =
m_pxmldom->selectNodes(_bstr_t(control_name_xpath), &pXMLDomNodeList);
645 if (SUCCEEDED(hr) && pXMLDomNodeList != NULL)
647 pXMLDomNodeList->get_length(&n);
648 pXMLDomNodeList->Release();
655 static const char* functionName =
"createParams";
660 NvItem* item = it->second;
661 if (item->
type ==
"float64")
663 m_driver->createParam(it->first.c_str(), asynParamFloat64, &(item->
id));
665 else if (item->
type ==
"int32" || item->
type ==
"boolean")
667 m_driver->createParam(it->first.c_str(), asynParamInt32, &(item->
id));
669 else if (item->
type ==
"string")
671 m_driver->createParam(it->first.c_str(), asynParamOctet, &(item->
id));
673 else if (item->
type ==
"float64array")
675 m_driver->createParam(it->first.c_str(), asynParamFloat64Array, &(item->
id));
677 else if (item->
type ==
"float32array")
679 m_driver->createParam(it->first.c_str(), asynParamFloat32Array, &(item->
id));
681 else if (item->
type ==
"int32array")
683 m_driver->createParam(it->first.c_str(), asynParamInt32Array, &(item->
id));
685 else if (item->
type ==
"int16array")
687 m_driver->createParam(it->first.c_str(), asynParamInt16Array, &(item->
id));
689 else if (item->
type ==
"int8array")
691 m_driver->createParam(it->first.c_str(), asynParamInt8Array, &(item->
id));
695 errlogSevPrintf(errlogMajor,
"%s:%s: unknown type %s for parameter %s\n",
driverName,
696 functionName, item->
type.c_str(), it->first.c_str());
706 _snprintf(control_name_xpath,
sizeof(control_name_xpath),
"/ninetvar/section[@name='%s']/param",
m_configSection.c_str());
707 IXMLDOMNodeList* pXMLDomNodeList = NULL;
708 HRESULT hr =
m_pxmldom->selectNodes(_bstr_t(control_name_xpath), &pXMLDomNodeList);
709 if (FAILED(hr) || pXMLDomNodeList == NULL)
711 std::cerr <<
"getParams failed" << std::endl;
714 IXMLDOMNode *pNode, *pAttrNode1, *pAttrNode2, *pAttrNode3, *pAttrNode4, *pAttrNode5;
717 unsigned access_mode;
718 char *last_str = NULL;
719 char *access_str, *str;
720 pXMLDomNodeList->get_length(&n);
721 for(
long i=0; i<n; ++i)
724 hr = pXMLDomNodeList->get_item(i, &pNode);
725 if (SUCCEEDED(hr) && pNode != NULL)
727 IXMLDOMNamedNodeMap *attributeMap = NULL;
728 pAttrNode1 = pAttrNode2 = pAttrNode3 = pAttrNode4 = pAttrNode5 = NULL;
729 pNode->get_attributes(&attributeMap);
730 hr = attributeMap->getNamedItem(_bstr_t(
"name"), &pAttrNode1);
731 hr = attributeMap->getNamedItem(_bstr_t(
"type"), &pAttrNode2);
732 hr = attributeMap->getNamedItem(_bstr_t(
"access"), &pAttrNode3);
733 hr = attributeMap->getNamedItem(_bstr_t(
"netvar"), &pAttrNode4);
734 hr = attributeMap->getNamedItem(_bstr_t(
"field"), &pAttrNode5);
735 BSTR bstrValue1 = NULL, bstrValue2 = NULL, bstrValue3 = NULL, bstrValue4 = NULL, bstrValue5 = NULL;
736 hr=pAttrNode1->get_text(&bstrValue1);
737 hr=pAttrNode2->get_text(&bstrValue2);
738 hr=pAttrNode3->get_text(&bstrValue3);
739 hr=pAttrNode4->get_text(&bstrValue4);
740 if (pAttrNode5 != NULL)
742 hr=pAttrNode5->get_text(&bstrValue5);
743 field = atoi(COLE2CT(bstrValue5));
749 access_str = strdup(COLE2CT(bstrValue3));
750 str = epicsStrtok_r(access_str,
",", &last_str);
753 if (!strcmp(str,
"R"))
757 else if (!strcmp(str,
"BR"))
761 else if (!strcmp(str,
"W"))
765 else if (!strcmp(str,
"BW"))
771 std::cerr <<
"getParams: Unknown access mode \"" << str <<
"\" for param " << COLE2CT(bstrValue1) << std::endl;
773 str = epicsStrtok_r(NULL,
",", &last_str);
776 m_params[std::string(COLE2CT(bstrValue1))] =
new NvItem(COLE2CT(bstrValue4),COLE2CT(bstrValue2),access_mode,field);
777 SysFreeString(bstrValue1);
778 SysFreeString(bstrValue2);
779 SysFreeString(bstrValue3);
780 SysFreeString(bstrValue4);
781 if (bstrValue5 != NULL)
783 SysFreeString(bstrValue5);
785 pAttrNode1->Release();
786 pAttrNode2->Release();
787 pAttrNode3->Release();
788 pAttrNode4->Release();
789 if (pAttrNode5 != NULL)
791 pAttrNode5->Release();
793 attributeMap->Release();
797 pXMLDomNodeList->Release();
804 int status = CNVCreateScalarDataValue(&cvalue, CNVString, value.c_str());
809 template <
typename T>
813 int status = CNVCreateScalarDataValue(&cvalue, static_cast<CNVDataType>(
C2CNV<T>::nvtype), value);
818 template <
typename T>
822 size_t dimensions[1] = { nElements };
823 int status = CNVCreateArrayDataValue(&cvalue, static_cast<CNVDataType>(
C2CNV<T>::nvtype), value, 1, dimensions);
830 int wait_ms = CNVWaitForever, b_wait_ms = CNVDoNotWait;
833 if (item->
field != -1)
835 throw std::runtime_error(
"setValueCNV: unable to update struct variable via param \"" + name +
"\"");
839 error = CNVWrite(item->
writer, value, wait_ms);
843 error = CNVPutDataInBuffer(item->
b_writer, value, b_wait_ms);
847 throw std::runtime_error(
"setValueCNV: param \"" + name +
"\" does not define a writer for \"" + item->
nv_name +
"\"");
855 CNVBufferDataStatus dataStatus;
858 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
860 const NvItem* item = it->second;
868 status = CNVGetDataFromBuffer(item->
b_subscriber, &value, &dataStatus);
870 if (dataStatus == CNVNewData || dataStatus == CNVDataWasLost)
874 if (dataStatus == CNVDataWasLost)
876 std::cerr <<
"updateValues: data was lost for param \"" << it->first <<
"\" (" << item->
nv_name <<
")" << std::endl;
891 fprintf(fp,
"XML ConfigFile: \"%s\"\n",
m_configFile.c_str());
892 fprintf(fp,
"XML ConfigFile section: \"%s\"\n",
m_configSection.c_str());
893 fprintf(fp,
"NINetVarConfigure() Options: %d\n",
m_options);
896 NvItem* item = it->second;
897 item->
report(it->first, fp);
901 #ifndef DOXYGEN_SHOULD_SKIP_THIS
static epicsThreadOnceId onceId
NINetVarInterface(const char *configSection, const char *configFile, int options)
section name of configFile to use to configure this asyn port
CNVBufferedWriter b_writer
static void free(ctype)
function to free any memory associated with type
NINetVarException(const std::string &function, int code)
details about a network shared variable we have connected to an asyn parameter
header for NINetVarInterface class.
int m_options
the various NINetVarOptions currently in use
void dataTransferredCallback(void *handle, int error, CallbackData *cb_data)
called when data has been transferred to the variable
static void CVICALLBACK StatusCallback(void *handle, CNVConnectionStatus status, int error, void *callbackData)
called when status of a network shared variable changes
int ctype
an instance of the underlying type
void updateParamValue(int param_index, T val, bool do_asyn_param_callbacks)
void setValue(const char *param, const T &value)
enum NvItem::@13 NvAccessMode
possible access modes to network shared variable
void updateParamArrayValue(int param_index, T *val, size_t nElements)
void updateParamCNVImpl(int param_index, CNVData data, CNVDataType type, unsigned int nDims, bool do_asyn_param_callbacks)
void setArrayValue(const char *param, const T *value, size_t nElements)
NINetVarException(const std::string &message)
void setValueCNV(const std::string &name, CNVData value)
NvItem(const char *nv_name_, const char *type_, unsigned access_, int field_)
static void CVICALLBACK DataCallback(void *handle, CNVData data, void *callbackData)
called when new data is available on a subscriber connection
void statusCallback(void *handle, CNVConnectionStatus status, int error, CallbackData *cb_data)
called when status of a network shared variable changes
unsigned access
combination of NvAccessMode
ScopedCNVData(const CNVData &d)
static const char * driverName
Name of driver for use in message printing.
IXMLDOMDocument2 * m_pxmldom
void report(const std::string &name, FILE *fp)
helper for asyn driver report function
std::string nv_name
full path to network shared variable
Stores information to be passed back via a shared variable callback on a subscriber connection...
ScopedCNVData & operator=(const CNVData &d)
void dataCallback(void *handle, CNVData data, CallbackData *cb_data)
called when new data is available on a subscriber connection
static void initCV(void *)
CNVBufferedSubscriber b_subscriber
void createParams(asynPortDriver *driver)
Header file for network shared variable convertion routines.
std::vector< char > array_data
only used for array parameters, contains cached copy of data as this is not stored in usual asyn para...
void report(FILE *fp, const char *conn_type, void *handle, bool buffered)
static const char * connectionStatus(CNVConnectionStatus status)
connection status of a network shared variable
void report(FILE *fp, int details)
Helper for EPICS driver report function.
asynPortDriver * m_driver
int id
asyn parameter id, -1 if not assigned
#define ERROR_CHECK(__func, __code)
A CNVData item that automatically "disposes" itself.
CallbackData(NINetVarInterface *intf_, const std::string &nv_name_, int param_index_)
std::string type
type as specified in the XML file e.g. float64array
static void CVICALLBACK DataTransferredCallback(void *handle, int error, void *callbackData)
called when data has been transferred to the variable
static std::string ni_message(const std::string &function, int code)
Manager class for the NetVar Interaction. Parses an netvarconfig.xml file and provides access to the ...
std::string m_configSection
section of configFile to load information from
void updateParamCNV(int param_index, CNVData data, bool do_asyn_param_callbacks)
void updateParamArrayValueImpl(int param_index, T *val, size_t nElements)
ScopedCNVData & operator=(const ScopedCNVData &d)
static void epicsExitFunc(void *arg)
int field
if we refer to a struct, this is the index of the field (starting at 0), otherwise it is -1 ...
static std::string dataQuality(CNVDataQuality quality)
the quality of the data in a network shared variable
void readArrayValue(const char *paramName, T *value, size_t nElements, size_t *nIn)
An STL exception object encapsulating a shared variable error message.
For a given C data type, provide the appropriate network shared variable type.
ScopedCNVData(const ScopedCNVData &d)