41 #include <epicsGuard.h>
42 #include <epicsString.h>
44 #include <cantProceed.h>
45 #include <epicsTime.h>
48 #include "pugixml.hpp"
50 #include "asynPortDriver.h"
52 #include <epicsExport.h>
57 #define MAX_PATH_LEN 256
73 static std::string
ni_message(
const std::string&
function,
int code)
75 return function +
": " + CNVGetErrorDescription(code);
79 #define ERROR_CHECK(__func, __code) \
82 throw NetShrVarException(__func, __code); \
85 #define ERROR_PRINT_CONTINUE(__func, __code) \
88 std::cerr << NetShrVarException::ni_message(__func, __code); \
98 return "Connecting...";
103 case CNVDisconnected:
104 return "Disconnected";
132 status = CNVDisposeData(
m_value);
159 NvItem(
const std::string& nv_name_,
const char* type_,
unsigned access_,
int field_,
const std::string& ts_param_,
bool with_ts_) :
nv_name(nv_name_),
type(type_),
access(access_),
166 void report(
const std::string& name, FILE* fp)
168 fprintf(fp,
"Report for asyn parameter \"%s\" type \"%s\" network variable \"%s\"\n", name.c_str(),
type.c_str(),
nv_name.c_str());
171 fprintf(fp,
" Current array size (bytes): %d\n", (
int)
array_data.size());
175 fprintf(fp,
" Network variable structure index: %d\n",
field);
178 if (epicsTimeToStrftime(tbuffer,
sizeof(tbuffer),
"%Y-%m-%d %H:%M:%S.%06f", &
epicsTS) <= 0)
180 strcpy(tbuffer,
"<unknown>");
182 fprintf(fp,
" Update time: %s\n", tbuffer);
189 void report(FILE* fp,
const char* conn_type,
void* handle,
bool buffered)
191 int error, conn_error;
192 CNVConnectionStatus status;
197 fprintf(fp,
" Connection type: %s", conn_type);
200 error = CNVGetConnectionAttribute(handle, CNVConnectionStatusAttribute, &status);
203 error = CNVGetConnectionAttribute(handle, CNVConnectionErrorAttribute, &conn_error);
207 fprintf(fp,
" error present: %s", CNVGetErrorDescription(conn_error));
211 int nitems, maxitems;
212 error = CNVGetConnectionAttribute(handle, CNVClientBufferNumberOfItemsAttribute, &nitems);
214 error = CNVGetConnectionAttribute(handle, CNVClientBufferMaximumItemsAttribute, &maxitems);
216 fprintf(fp,
" Client buffer: %d items (buffer size = %d)", nitems, maxitems);
220 catch (
const std::exception& ex)
222 fprintf(fp,
" Unable to get connection status: %s\n", ex.what());
236 static void CVICALLBACK
DataCallback (
void * handle, CNVData data,
void * callbackData);
237 static void CVICALLBACK
StatusCallback (
void * handle, CNVConnectionStatus status,
int error,
void * callbackData);
246 int error = CNVCreateReader(item->
nv_name.c_str(), NULL, NULL, waitTime, 0, &reader);
249 int status = CNVRead(reader, 10, &cvalue);
257 catch(
const std::exception& ex)
259 std::cerr <<
"Unable to read initial value from \"" << item->
nv_name <<
"\": " << ex.what() << std::endl;
268 case CNVBrowseTypeUndefined:
269 return "The item's browse type is not defined.";
272 case CNVBrowseTypeMachine:
273 return "The item is a computer.";
276 case CNVBrowseTypeProcess:
277 return "This item is a process.";
280 case CNVBrowseTypeFolder:
281 return "The item is a folder.";
284 case CNVBrowseTypeItem:
285 return "The item is a variable.";
288 case CNVBrowseTypeItemRange:
289 return "The item is a range of variables. ";
292 case CNVBrowseTypeImplicitItem:
293 return "The item is an implict item.";
306 CNVBrowser browser = NULL;
309 CNVBrowseType browseType = CNVBrowseTypeUndefined;
310 error = CNVCreateBrowser(&browser);
312 error = CNVBrowse(browser, path.c_str());
315 CNVDisposeBrowser(browser);
320 error = CNVBrowseNextItem(browser, &item, &leaf, &browseType, NULL);
321 std::cerr <<
"error " << error <<
" leaf " << leaf <<
" type " <<
getBrowseType(browseType) << std::endl;
325 std::cerr << item << std::endl;
329 CNVDisposeBrowser(browser);
340 int error, exists = 0;
341 size_t proc_pos = path.find(
'\\', 2);
342 size_t var_pos = path.rfind(
'\\');
344 if (proc_pos != std::string::npos && var_pos != std::string::npos)
346 std::string host_name = path.substr(2, proc_pos - 2);
347 std::string proc_name = path.substr(proc_pos + 1, var_pos - proc_pos - 1);
348 std::string var_name = path.substr(var_pos + 1);
349 if (host_name ==
"localhost")
351 error = CNVVariableExists(proc_name.c_str(), var_name.c_str(), &exists);
369 std::cerr <<
"varExists: cannot parse \"" << path <<
"\"" << std::endl;
382 int clientBufferMaxItems = 200;
385 error = CNVVariableEngineIsRunning(&running);
389 std::cerr <<
"connectVars: NI Variable engine is not running" << std::endl;
391 char** processes = NULL;
392 int numberOfProcesses = 0;
394 error = CNVGetProcesses(&processes, &numberOfProcesses);
396 std::cerr <<
"connectVars: NSV processes on machine:";
397 for(
int i=0; i<numberOfProcesses; ++i)
399 error = CNVProcessIsRunning(processes[i], &isRunning);
401 std::cerr <<
" \"" << processes[i] <<
"\" (" << (isRunning != 0 ?
"RUNNING" :
"NOT RUNNING") <<
")";
403 std::cerr << std::endl;
404 CNVFreeMemory(processes);
408 static const char* alarm_fields[] = {
"Hi",
"HiHi",
"Lo",
"LoLo" };
410 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
412 NvItem* item = it->second;
413 std::string param_name = it->first;
416 for(
int i=0; i<
sizeof(alarm_fields) /
sizeof(
const char*); ++i)
418 std::string prefix = item->
nv_name +
"\\Alarms\\" + alarm_fields[i] +
"\\";
421 std::cerr <<
"Adding " << alarm_fields[i] <<
" alarm field for " << item->
nv_name <<
" (asyn parameter: " << param_name <<
")" << std::endl;
424 new_params[param_name +
"_" + alarm_fields[i] +
"_Set"] =
new NvItem(prefix +
"Set",
"boolean",
NvItem::Read, -1,
"",
false);
425 new_params[param_name +
"_" + alarm_fields[i] +
"_Ack"] =
new NvItem(prefix +
"Ack",
"boolean",
NvItem::Read, -1,
"",
false);
433 m_params.insert(new_params.begin(), new_params.end());
438 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
440 NvItem* item = it->second;
443 std::cerr <<
"connectVars: connecting to \"" << item->
nv_name <<
"\"" << std::endl;
481 char* description = NULL;
482 int error = CNVGetDataQualityDescription(quality,
";", &description);
486 CNVFreeMemory(description);
490 res = std::string(
"CNVGetDataQualityDescription: ") + CNVGetErrorDescription(error);
507 std::cerr <<
"dataTransferredCallback: \"" << cb_data->
nv_name <<
"\": " << CNVGetErrorDescription(error) << std::endl;
517 static void CVICALLBACK
DataCallback (
void * handle, CNVData data,
void * callbackData)
523 CNVDisposeData (data);
525 catch(
const std::exception& ex)
527 std::cerr <<
"DataCallback: ERROR : " << ex.what() << std::endl;
531 std::cerr <<
"DataCallback: ERROR" << std::endl;
543 catch(
const std::exception& ex)
545 std::cerr <<
"dataCallback: ERROR updating param index " << cb_data->
param_index <<
": " << ex.what() << std::endl;
549 std::cerr <<
"dataCallback: ERROR updating param index " << cb_data->
param_index << std::endl;
556 int connected_param_index = -1;
557 const char *conectedParamName = NULL;
558 std::string suffix =
"_" + alarmStr +
"_Set";
559 if ( (paramName.size() > suffix.size()) && (paramName.substr(paramName.size() - suffix.size()) == suffix) )
561 std::string connectedParamName = paramName.substr(0, paramName.size() - suffix.size());
562 if (
m_driver->findParam(connectedParamName.c_str(), &connected_param_index) == asynSuccess)
565 if ( (
m_driver->getParamStatus(connected_param_index, &status) == asynSuccess) && (status == asynSuccess) )
567 std::cerr <<
"Alarm type " << alarmStr << (value != 0 ?
" raised" :
" cleared") <<
" for asyn parameter " << connectedParamName << std::endl;
584 const char *paramName = NULL;
586 m_driver->getParamName(param_index, ¶mName);
588 m_params[paramName]->epicsTS = *epicsTS;
589 if (
m_params[paramName]->type ==
"float64" ||
m_params[paramName]->type ==
"ftimestamp")
591 m_driver->setDoubleParam(param_index, convertToScalar<double>(val));
593 else if (
m_params[paramName]->type ==
"int32" ||
m_params[paramName]->type ==
"boolean")
595 int intVal = convertToScalar<int>(val);
596 m_driver->setIntegerParam(param_index, intVal);
602 else if (
m_params[paramName]->type ==
"string" ||
m_params[paramName]->type ==
"timestamp")
604 m_driver->setStringParam(param_index, convertToPtr<char>(val));
608 std::cerr <<
"updateParamValue: unknown type \"" <<
m_params[paramName]->type <<
"\" for param \"" << paramName <<
"\"" << std::endl;
610 if (do_asyn_param_callbacks)
617 template<
typename T,
typename U>
620 const char *paramName = NULL;
621 m_driver->getParamName(param_index, ¶mName);
622 std::vector<char>& array_data =
m_params[paramName]->array_data;
623 U* eval = convertToPtr<U>(val);
626 array_data.resize(nElements *
sizeof(T));
627 memcpy(&(array_data[0]), eval, nElements *
sizeof(T));
632 std::cerr <<
"updateParamArrayValue: cannot update param \"" << paramName <<
"\": shared variable data type incompatible \"" <<
C2CNV<T>::desc <<
"\"" << std::endl;
640 static const uint64_t epoch_diff = 2713996800u;
641 static const uint64_t to_nsec = std::numeric_limits<uint64_t>::max() / 1000000000u;
642 epicsTS->secPastEpoch = lv_time[0] - epoch_diff;
643 epicsTS->nsec = lv_time[1] / to_nsec;
649 const char *paramName = NULL;
650 epicsTimeStamp epicsTSv;
651 m_driver->getParamName(param_index, ¶mName);
652 bool with_ts =
m_params[paramName]->with_ts;
655 size_t n_ts_elem = 16 /
sizeof(T);
656 const uint64_t* time_data =
reinterpret_cast<const uint64_t*
>(val);
657 if (nElements > n_ts_elem)
661 nElements -= n_ts_elem;
666 std::cerr <<
"updateParamArrayValue: param \"" << paramName <<
"\" not enough elements for timestamp" << std::endl;
672 m_params[paramName]->epicsTS = *epicsTS;
673 if (
m_params[paramName]->type ==
"float64array")
675 updateParamArrayValueImpl<T,epicsFloat64>(param_index, val, nElements);
677 else if (
m_params[paramName]->type ==
"float32array")
679 updateParamArrayValueImpl<T,epicsFloat32>(param_index, val, nElements);
681 else if (
m_params[paramName]->type ==
"int32array")
683 updateParamArrayValueImpl<T,epicsInt32>(param_index, val, nElements);
685 else if (
m_params[paramName]->type ==
"int16array")
687 updateParamArrayValueImpl<T,epicsInt16>(param_index, val, nElements);
689 else if (
m_params[paramName]->type ==
"int8array")
691 updateParamArrayValueImpl<T,epicsInt8>(param_index, val, nElements);
693 else if (
m_params[paramName]->type ==
"timestamp" ||
m_params[paramName]->type ==
"ftimestamp")
695 if ( nElements == 2 &&
sizeof(T) ==
sizeof(uint64_t) )
697 uint64_t* time_data =
reinterpret_cast<uint64_t*
>(val);
700 if (
m_params[paramName]->type ==
"timestamp")
702 char time_buffer[40];
703 epicsTimeToStrftime(time_buffer,
sizeof(time_buffer),
"%Y-%m-%dT%H:%M:%S.%06f", epicsTS);
704 updateParamValue(param_index, time_buffer, epicsTS, do_asyn_param_callbacks);
708 double dval = epicsTS->secPastEpoch + epicsTS->nsec / 1e9;
714 std::cerr <<
"updateParamArrayValue: timestamp param \"" << paramName <<
"\" not given UInt64[2] array" << std::endl;
719 std::cerr <<
"updateParamArrayValue: unknown type \"" <<
m_params[paramName]->type <<
"\" for param \"" << paramName <<
"\"" << std::endl;
725 template <
typename T>
735 int status = CNVRead(item->
reader, 10, &cvalue);
745 std::cerr <<
"NetShrVarInterface::readArrayValue: Param \"" << paramName <<
"\" (" << item->
nv_name <<
") is not valid" << std::endl;
748 std::vector<char>& array_data = item->
array_data;
749 size_t n = array_data.size() /
sizeof(T);
755 memcpy(value, &(array_data[0]), n *
sizeof(T));
769 int status = CNVRead(item->
reader, 10, &cvalue);
779 std::cerr <<
"NetShrVarInterface::readValue: Param \"" << param <<
"\" (" << item->
nv_name <<
") is not valid" << std::endl;
785 template<CNVDataType cnvType>
787 epicsTimeStamp* epicsTS,
bool do_asyn_param_callbacks)
789 static const int maxDims = 10;
793 int status = CNVGetScalarDataValue (data, type, &val);
799 else if (nDims <= maxDims)
802 size_t dimensions[maxDims];
803 int status = CNVGetArrayDataDimensions(data, nDims, dimensions);
805 size_t nElements = 1;
806 for(
unsigned i=0; i<nDims; ++i)
808 nElements *= dimensions[i];
815 status = CNVGetArrayDataValue(data, type, val, nElements);
829 int year, month, day, hour, minute;
831 int status = CNVGetTimestampInfo(timestamp, &year, &month, &day, &hour, &minute, &second);
838 memset(&tms, 0,
sizeof(tms));
839 tms.tm_year = year - 1900;
840 tms.tm_mon = month - 1;
844 tms.tm_sec =
static_cast<int>(floor(second));
845 unsigned long nanosec =
static_cast<unsigned long>(floor((second - floor(second)) * 1.e9 + 0.5));
846 epicsTimeFromGMTM(epicsTS, &tms, nanosec);
855 unsigned int nDims = 0;
856 unsigned int serverError;
858 CNVDataQuality quality;
860 unsigned short numberOfFields = 0;
861 const char *paramName = NULL;
862 unsigned __int64 timestamp;
863 epicsTimeStamp epicsTSLocal;
864 m_driver->getParamName(param_index, ¶mName);
865 if (paramName == NULL)
869 std::string paramNameStr = paramName;
875 status = CNVGetDataType (data, &type, &nDims);
879 const std::string& ts_param =
m_params[paramName]->ts_param;
880 if (ts_param.size() > 0)
882 epicsTS = &(
m_params[ts_param]->epicsTS);
886 status = CNVGetDataUTCTimestamp(data, ×tamp);
890 epicsTimeGetCurrent(&epicsTSLocal);
892 epicsTS = &epicsTSLocal;
894 if (type == CNVStruct)
896 int field =
m_params[paramName]->field;
897 status = CNVGetNumberOfStructFields(data, &numberOfFields);
899 if (numberOfFields == 0)
901 throw std::runtime_error(
"number of fields");
903 if (field < 0 || field >= numberOfFields)
905 throw std::runtime_error(
"field index");
907 CNVData* fields =
new CNVData[numberOfFields];
908 status = CNVGetStructFields(data, fields, numberOfFields);
912 const std::string& this_nv =
m_params[paramName]->nv_name;
915 std::vector<const NvItem*> items_left;
916 items_left.reserve(numberOfFields);
919 NvItem* item = it->second;
922 if (item->
type ==
"timestamp" || item->
type ==
"ftimestamp")
928 items_left.push_back(item);
932 for (std::vector<const NvItem*>::const_iterator it = items_left.begin(); it != items_left.end(); ++it)
937 for(
int i=0; i<numberOfFields; ++i)
939 status = CNVDisposeData(fields[i]);
945 status = CNVGetDataQuality(data, &quality);
947 status = CNVCheckDataQuality(quality, &good);
950 int p_alarmStat, p_alarmSevr;
952 if (good == 1 && p_stat != asynSuccess)
954 std::cerr <<
"updateParamCNV: data for param " << paramName <<
" is good quality again" << std::endl;
960 std::cerr <<
"updateParamCNV: data for param " << paramName <<
" is not good quality: " <<
dataQuality(quality) << std::endl;
963 else if ( quality & (CNVDataQualityLowLimited | CNVDataQualityHighLimited) )
965 std::cerr <<
"NV has signaled CNVDataQualityLowLimited / CNVDataQualityHighLimited for " << paramName << std::endl;
966 if (p_stat == asynSuccess && p_alarmStat == epicsAlarmNone && p_alarmSevr == epicsSevNone)
968 setParamStatus(param_index, asynSuccess, epicsAlarmHwLimit, epicsSevMinor);
971 else if ( quality & CNVDataQualityInAlarm )
977 if (!(
m_params[paramName]->connected_alarm))
979 if (p_stat == asynSuccess && p_alarmStat == epicsAlarmNone && p_alarmSevr == epicsSevNone)
981 std::cerr <<
"Unexpected Alarm for " <<
m_params[paramName]->nv_name <<
" - Alarming enabled after IOC started?" << std::endl;
982 std::cerr <<
"Raising generic HWLIMIT/MINOR Alarm for \"" << paramName <<
"\"" << std::endl;
983 std::cerr <<
"(For more specific HI/LOW etc alarms start this IOC after enabling Alarming)" << std::endl;
984 setParamStatus(param_index, asynSuccess, epicsAlarmHwLimit, epicsSevMinor);
991 if (p_stat == asynSuccess && p_alarmStat == epicsAlarmHwLimit)
993 std::cerr <<
"Clearing HWLIMIT Alarm for \"" << paramName <<
"\"" << std::endl;
1003 updateParamCNVImpl<CNVBool>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1007 updateParamCNVImpl<CNVString>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1011 updateParamCNVImpl<CNVSingle>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1015 updateParamCNVImpl<CNVDouble>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1019 updateParamCNVImpl<CNVInt8>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1023 updateParamCNVImpl<CNVUInt8>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1027 updateParamCNVImpl<CNVInt16>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1031 updateParamCNVImpl<CNVUInt16>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1035 updateParamCNVImpl<CNVInt32>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1039 updateParamCNVImpl<CNVUInt32>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1043 updateParamCNVImpl<CNVInt64>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1047 updateParamCNVImpl<CNVUInt64>(param_index, data, type, nDims, epicsTS, do_asyn_param_callbacks);
1051 std::cerr <<
"updateParamCNV: unknown type " << type <<
" for param " << paramName << std::endl;
1054 status = CNVGetDataServerError(data, &serverError);
1055 if (status == 0 && serverError != 0)
1057 std::cerr <<
"updateParamCNV: Server error: " << serverError << std::endl;
1059 else if (status < 0)
1061 std::cerr <<
"updateParamCNV: CNVGetDataServerError: " << CNVGetErrorDescription(status) << std::endl;
1067 static void CVICALLBACK
StatusCallback (
void * handle, CNVConnectionStatus status,
int error,
void * callbackData)
1078 std::cerr <<
"StatusCallback: " << cb_data->
nv_name <<
": " << CNVGetErrorDescription(error) << std::endl;
1084 if (status != CNVConnected)
1091 static epicsThreadOnceId
onceId = EPICS_THREAD_ONCE_INIT;
1096 char* dummy_argv[2] = { strdup(
"NetShrVarInterface"), NULL };
1097 if (InitCVIRTE (0, dummy_argv, 0) == 0)
1098 throw std::runtime_error(
"InitCVIRTE");
1106 long destCapacity = 128;
1116 dest =
static_cast<char*
>(mallocMustSucceed(destCapacity,
"NetShrVarInterface::envExpand"));
1117 n = macExpandString(
m_mac_env, str, dest, destCapacity);
1118 }
while (n >= (destCapacity - 1));
1123 size_t unused = destCapacity - ++n;
1126 dest =
static_cast<char*
>(realloc(dest, n));
1135 m_configSection(configSection), m_options(options), m_mac_env(NULL),
1136 m_writer_wait_ms(5000),
1137 m_b_writer_wait_ms(CNVDoNotWait),
1138 m_items_read(0), m_bytes_read(0)
1145 if (macCreateHandle(&
m_mac_env, NULL) != 0)
1147 throw std::runtime_error(
"Cannot create mac handle");
1149 for(
char** cp = environ; *cp != NULL; ++cp)
1151 char* str_tmp = strdup(*cp);
1152 char* equals_loc = strchr(str_tmp,
'=');
1153 if (equals_loc != NULL)
1156 macPutValue(
m_mac_env, str_tmp, equals_loc + 1);
1160 char* configFile_expanded =
envExpand(configFile);
1164 pugi::xml_parse_result result =
m_xmlconfig.load_file(configFile_expanded);
1165 free(configFile_expanded);
1168 std::cerr <<
"Loaded XML config file \"" <<
m_configFile <<
"\" (expanded from \"" << configFile <<
"\")" << std::endl;
1172 throw std::runtime_error(
"Cannot load XML \"" +
m_configFile +
"\" (expanded from \"" + std::string(configFile) +
"\"): load failure: "
1173 + result.description());
1194 epicsSnprintf(control_name_xpath,
sizeof(control_name_xpath),
"/netvar/section[@name='%s']/param",
m_configSection.c_str());
1197 pugi::xpath_node_set params =
m_xmlconfig.select_nodes(control_name_xpath);
1198 return params.size();
1200 catch(
const std::exception& ex)
1202 std::cerr <<
"nparams failed " << ex.what() << std::endl;
1209 static const char* functionName =
"initAsynParamIds";
1212 NvItem* item = it->second;
1217 if (item->
type ==
"float64" || item->
type ==
"ftimestamp")
1219 m_driver->createParam(it->first.c_str(), asynParamFloat64, &(item->
id));
1221 else if (item->
type ==
"int32" || item->
type ==
"boolean")
1223 m_driver->createParam(it->first.c_str(), asynParamInt32, &(item->
id));
1225 else if (item->
type ==
"string" || item->
type ==
"timestamp")
1227 m_driver->createParam(it->first.c_str(), asynParamOctet, &(item->
id));
1229 else if (item->
type ==
"float64array")
1231 m_driver->createParam(it->first.c_str(), asynParamFloat64Array, &(item->
id));
1233 else if (item->
type ==
"float32array")
1235 m_driver->createParam(it->first.c_str(), asynParamFloat32Array, &(item->
id));
1237 else if (item->
type ==
"int32array")
1239 m_driver->createParam(it->first.c_str(), asynParamInt32Array, &(item->
id));
1241 else if (item->
type ==
"int16array")
1243 m_driver->createParam(it->first.c_str(), asynParamInt16Array, &(item->
id));
1245 else if (item->
type ==
"int8array")
1247 m_driver->createParam(it->first.c_str(), asynParamInt8Array, &(item->
id));
1251 errlogSevPrintf(errlogMajor,
"%s:%s: unknown type %s for parameter %s\n",
driverName,
1252 functionName, item->
type.c_str(), it->first.c_str());
1259 static const char* functionName =
"createParams";
1269 epicsSnprintf(control_name_xpath,
sizeof(control_name_xpath),
"/netvar/section[@name='%s']/param",
m_configSection.c_str());
1270 pugi::xpath_node_set params;
1273 params =
m_xmlconfig.select_nodes(control_name_xpath);
1274 if (params.size() == 0)
1276 std::cerr <<
"getParams failed" << std::endl;
1280 catch(
const std::exception& ex)
1282 std::cerr <<
"getParams failed " << ex.what() << std::endl;
1286 unsigned access_mode;
1287 char *last_str = NULL;
1288 char *access_str, *str;
1289 for (pugi::xpath_node_set::const_iterator it = params.begin(); it != params.end(); ++it)
1291 pugi::xpath_node node = *it;
1292 std::string attr1 = node.node().attribute(
"name").value();
1293 std::string attr2 = node.node().attribute(
"type").value();
1294 std::string attr3 = node.node().attribute(
"access").value();
1295 std::string attr4 =
envExpand(node.node().attribute(
"netvar").value());
1296 std::string attr5 = node.node().attribute(
"field").value();
1297 std::string attr6 = node.node().attribute(
"ts_param").value();
1298 std::string with_ts_s = node.node().attribute(
"with_ts").value();
1299 bool with_ts =
false;
1300 if (with_ts_s ==
"true")
1304 if (attr5.size() == 0)
1310 field = atoi(attr5.c_str());
1312 access_str = strdup(attr3.c_str());
1314 str = epicsStrtok_r(access_str,
",", &last_str);
1315 while( str != NULL )
1317 if (!strcmp(str,
"R"))
1321 else if (!strcmp(str,
"BR"))
1325 else if (!strcmp(str,
"SR"))
1329 else if (!strcmp(str,
"W"))
1333 else if (!strcmp(str,
"BW"))
1339 std::cerr <<
"getParams: Unknown access mode \"" << str <<
"\" for param " << attr1 << std::endl;
1341 str = epicsStrtok_r(NULL,
",", &last_str);
1346 std::cerr <<
"getParams: Unable to link unknown \"" << attr6 <<
"\" as ts_param for " << attr1 << std::endl;
1349 m_params[attr1] =
new NvItem(attr4.c_str(),attr2.c_str(),access_mode,field,attr6,with_ts);
1357 int status = CNVCreateScalarDataValue(&cvalue, CNVString, value.c_str());
1362 template <
typename T>
1366 int status = CNVCreateScalarDataValue(&cvalue, static_cast<CNVDataType>(
C2CNV<T>::nvtype), value);
1371 template <
typename T>
1375 size_t dimensions[1] = { nElements };
1376 int status = CNVCreateArrayDataValue(&cvalue, static_cast<CNVDataType>(
C2CNV<T>::nvtype), value, 1, dimensions);
1386 if (item->
field != -1)
1388 if (item->
reader == NULL) {
1389 int waitTime = 3000;
1390 error = CNVCreateReader(item->
nv_name.c_str(), NULL, NULL, waitTime, 0, &(item->
reader));
1394 error = CNVRead(item->
reader, 10, &cvalue);
1399 int field = item->
field;
1400 unsigned short numberOfFields = 0;
1401 error = CNVGetNumberOfStructFields(cvalue, &numberOfFields);
1403 if (numberOfFields == 0)
1405 throw std::runtime_error(
"number of fields");
1407 if (field < 0 || field >= numberOfFields)
1409 throw std::runtime_error(
"field index");
1411 CNVData* fields =
new CNVData[numberOfFields];
1412 error = CNVGetStructFields(cvalue, fields, numberOfFields);
1414 error = CNVDisposeData(fields[field]);
1416 fields[field] = value;
1417 error = CNVSetStructDataValue(cvalue, fields, numberOfFields);
1419 for(
int i=0; i<numberOfFields; ++i) {
1421 error = CNVDisposeData(fields[i]);
1430 throw std::runtime_error(
"setValueCNV: param \"" + name +
"\" cannot read cluster for \"" + item->
nv_name +
"\"");
1448 throw std::runtime_error(
"setValueCNV: param \"" + name +
"\" does not define a writer for \"" + item->
nv_name +
"\"");
1456 m_driver->setParamStatus(param_id, status);
1457 m_driver->setParamAlarmStatus(param_id, alarmStat);
1458 m_driver->setParamAlarmSeverity(param_id, alarmSevr);
1465 m_driver->getParamStatus(param_id, &status);
1466 m_driver->getParamAlarmStatus(param_id, &alarmStat);
1467 m_driver->getParamAlarmSeverity(param_id, &alarmSevr);
1475 CNVBufferDataStatus dataStatus;
1477 for(params_t::const_iterator it=
m_params.begin(); it !=
m_params.end(); ++it)
1479 const NvItem* item = it->second;
1489 status = CNVGetDataFromBuffer(item->
b_subscriber, &value, &dataStatus);
1495 if (dataStatus == CNVDataWasLost)
1497 std::cerr <<
"NetShrVarInterface::updateValues: BufferedReader: data was lost for param \"" << it->first <<
"\" (" << item->
nv_name <<
") - is poll frequency too low?" << std::endl;
1500 if (dataStatus == CNVNewData || dataStatus == CNVDataWasLost)
1507 std::cerr <<
"NetShrVarInterface::updateValues: BufferedReader: param \"" << it->first <<
"\" (" << item->
nv_name <<
") is not valid" << std::endl;
1524 static uint32_t last_items_read = 0;
1525 static uint64_t last_bytes_read = 0;
1527 fprintf(fp,
"XML ConfigFile: \"%s\"\n",
m_configFile.c_str());
1528 fprintf(fp,
"XML ConfigFile section: \"%s\"\n",
m_configSection.c_str());
1529 fprintf(fp,
"NetShrVarConfigure() Options: %d\n",
m_options);
1530 fprintf(fp,
"Total items read: %llu\n", static_cast<unsigned long long>(
m_items_read));
1531 fprintf(fp,
"Total bytes read: %llu\n", static_cast<unsigned long long>(
m_bytes_read));
1534 fprintf(fp,
"* Data rates are average since last call to this command *\n");
1535 fprintf(fp,
"Items read /s: %f\n", (
m_items_read - last_items_read) / tdiff );
1536 fprintf(fp,
"Bytes read /s: %f\n", (
m_bytes_read - last_bytes_read) / tdiff );
1542 NvItem* item = it->second;
1543 item->
report(it->first, fp);
1547 #ifndef DOXYGEN_SHOULD_SKIP_THIS
CNVBufferedSubscriber b_subscriber
void readVarInit(NvItem *item)
used to perform an initial read of a subscribed variable
void report(FILE *fp, const char *conn_type, void *handle, bool buffered)
int m_b_writer_wait_ms
how long to wait for a buffered write operation to complete in milliseconds
CallbackData(NetShrVarInterface *intf_, const std::string &nv_name_, int param_index_)
bool convertTimeStamp(unsigned __int64 timestamp, epicsTimeStamp *epicsTS)
convert a timestamp obtained from CNVGetDataUTCTimestamp() into an EPICS timestamp timestamp has 100n...
bool operator!=(CNVData d) const
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
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)
char * envExpand(const char *str)
expand epics environment strings using previously saved environment based on EPICS macEnvExpand() ...
void updateParamValue(int param_index, T val, epicsTimeStamp *epicsTS, bool do_asyn_param_callbacks)
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
void getParamStatus(int param_id, asynStatus &status, int &alarmStat, int &alarmSevr)
static void CVICALLBACK StatusCallback(void *handle, CNVConnectionStatus status, int error, void *callbackData)
called when status of a network shared variable changes
#define ERROR_PRINT_CONTINUE(__func, __code)
NetShrVarInterface * intf
static const char * getBrowseType(CNVBrowseType browseType)
void updateParamArrayValue(int param_index, T *val, size_t nElements, epicsTimeStamp *epicsTS, bool do_asyn_param_callbacks)
static void CVICALLBACK DataTransferredCallback(void *handle, int error, void *callbackData)
called when data has been transferred to the variable
void updateConnectedAlarmStatus(const std::string ¶mName, int value, const std::string &alarmStr, epicsAlarmCondition stat, epicsAlarmSeverity sevr)
std::string ts_param
parameter that is timestamp source
void report(FILE *fp, int details)
Helper for EPICS driver report function.
void updateBytesReadCount(unsigned nbytes)
struct timeb m_last_report
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)
bool with_ts
timestamp is encoded in first few array elements
void readValue(const char *param)
read a value and update corresponding asyn parameter
std::string nv_name
full path to network shared variable
void createParams(asynPortDriver *driver)
static void convertLabviewTimeToEpicsTime(const uint64_t *lv_time, epicsTimeStamp *epicsTS)
bool operator==(CNVData d) const
static bool pathExists(const std::string &path)
std::map< std::string, NvItem * > params_t
NvItem(const std::string &nv_name_, const char *type_, unsigned access_, int field_, const std::string &ts_param_, bool with_ts_)
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)
called externally with m_driver locked
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.
epicsTimeStamp epicsTS
timestamp of shared variable update
static void initCV(void *)
int ctype
an instance of the underlying type
int m_writer_wait_ms
how long to wait for a write operation to complete in milliseconds
static void epicsExitFunc(void *arg)
void setArrayValue(const char *param, const T *value, size_t nElements)
void statusCallback(void *handle, CNVConnectionStatus status, int error, CallbackData *cb_data)
called by StatusCallback() when status of a network shared variable changes
void updateParamCNVImpl(int param_index, CNVData data, CNVDataType type, unsigned int nDims, epicsTimeStamp *epicsTS, bool do_asyn_param_callbacks)
void setParamStatus(int param_id, asynStatus status, epicsAlarmCondition alarmStat=epicsAlarmNone, epicsAlarmSeverity alarmSevr=epicsSevNone)
ScopedCNVData & operator=(const CNVData &d)
void updateValues()
This is called from a polling loop in the driver to update values from buffered subscribers.
static bool varExists(const std::string &path)
void updateParamCNV(int param_index, CNVData data, epicsTimeStamp *epicsTS, bool do_asyn_param_callbacks)
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
NetShrVarException(const std::string &message)
For a given C data type, provide the appropriate network shared variable type.
my_atomic_uint64_t m_bytes_read
my_atomic_uint32_t m_items_read
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)
int64_t sec_from_epoch
from 01/01/1904 00:00:00.00 UTC