ISIS Logo
NetShrVar
An EPICS support module to export National Instruments Network Shared Variables as process variables
NetShrVarDriver.cpp
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2013 Science and Technology Facilities Council (STFC), GB.
3 * All rights reverved.
4 * This file is distributed subject to a Software License Agreement found
5 * in the file LICENSE.txt that is included with this distribution.
6 \*************************************************************************/
7 
10 
11 #include <stdlib.h>
12 #include <string.h>
13 #include <stdio.h>
14 #include <errno.h>
15 #include <math.h>
16 #include <exception>
17 #include <iostream>
18 
19 #include <shareLib.h>
20 #include <epicsTypes.h>
21 #include <epicsTime.h>
22 #include <epicsThread.h>
23 #include <epicsString.h>
24 #include <epicsTimer.h>
25 #include <epicsMutex.h>
26 #include <epicsEvent.h>
27 #include <errlog.h>
28 #include <iocsh.h>
29 #include <alarm.h>
30 
31 #ifdef _WIN32
32 #include <windows.h>
33 #endif
34 
35 #include <epicsExport.h>
36 
37 #include "convertToString.h"
38 #include "NetShrVarInterface.h"
39 #include "NetShrVarDriver.h"
40 
41 static const char *driverName="NetShrVarDriver";
42 
48 template<typename T>
49 asynStatus NetShrVarDriver::writeValue(asynUser *pasynUser, const char* functionName, T value)
50 {
51  int function = pasynUser->reason;
52  asynStatus status = asynSuccess;
53  const char *paramName = NULL;
54  getParamName(function, &paramName);
55  try
56  {
57  if (m_netvarint == NULL)
58  {
59  throw std::runtime_error("m_netvarint is NULL");
60  }
61  m_netvarint->setValue(paramName, value);
62  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
63  "%s:%s: function=%d, name=%s, value=%s\n",
64  driverName, functionName, function, paramName, convertToString(value).c_str());
65  return asynSuccess;
66  }
67  catch(const std::exception& ex)
68  {
69  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
70  "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
71  driverName, functionName, status, function, paramName, convertToString(value).c_str(), ex.what());
72  return asynError;
73  }
74 }
75 
76 asynStatus NetShrVarDriver::readValue(asynUser *pasynUser, const char* functionName)
77 {
78  int function = pasynUser->reason;
79  const char *paramName = NULL;
80  getParamName(function, &paramName);
81  try
82  {
83  if (m_netvarint == NULL)
84  {
85  throw std::runtime_error("m_netvarint is NULL");
86  }
87  m_netvarint->readValue(paramName);
88  // ASYN_TRACEIO_DRIVER done by function calling us
89  return asynSuccess;
90  }
91  catch(const std::exception& ex)
92  {
93  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
94  "%s:%s: function=%d, name=%s, error=%s",
95  driverName, functionName, function, paramName, ex.what());
96  return asynError;
97  }
98 }
99 
106 template<typename T>
107 asynStatus NetShrVarDriver::writeArrayValue(asynUser *pasynUser, const char* functionName, T* value, size_t nElements)
108 {
109  int function = pasynUser->reason;
110  asynStatus status = asynSuccess;
111  const char *paramName = NULL;
112  getParamName(function, &paramName);
113  try
114  {
115  if (m_netvarint == NULL)
116  {
117  throw std::runtime_error("m_netvarint is NULL");
118  }
119  m_netvarint->setArrayValue(paramName, value, nElements);
120  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
121  "%s:%s: function=%d, name=%s, nElements=%d\n",
122  driverName, functionName, function, paramName, (int)nElements);
123  return asynSuccess;
124  }
125  catch(const std::exception& ex)
126  {
127  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
128  "%s:%s: status=%d, function=%d, name=%s, nElements=%d, error=%s",
129  driverName, functionName, status, function, paramName, (int)nElements, ex.what());
130  return asynError;
131  }
132 }
133 
137 asynStatus NetShrVarDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
138 {
139  asynStatus status = writeValue(pasynUser, "writeFloat64", value);
140  return (status == asynSuccess ? asynPortDriver::writeFloat64(pasynUser, value) : status);
141 }
142 
143 asynStatus NetShrVarDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
144 {
145  asynStatus status = writeValue(pasynUser, "writeInt32", value);
146  return (status == asynSuccess ? asynPortDriver::writeInt32(pasynUser, value) : status);
147 }
148 
149 asynStatus NetShrVarDriver::readFloat64(asynUser *pasynUser, epicsFloat64 *value)
150 {
151  static const char* functionName = "readFloat64";
152  int function = pasynUser->reason;
153  const char *paramName = NULL;
154  getParamName(function, &paramName);
155  asynStatus status = readValue(pasynUser, functionName);
156  if (status == asynSuccess)
157  {
158  asynPortDriver::readFloat64(pasynUser, value);
159  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
160  "%s:%s: function=%d, name=%s, value=%f\n",
161  driverName, functionName, function, paramName, *value);
162  }
163  return status;
164 }
165 
166 asynStatus NetShrVarDriver::readInt32(asynUser *pasynUser, epicsInt32 *value)
167 {
168  static const char* functionName = "readInt32";
169  int function = pasynUser->reason;
170  const char *paramName = NULL;
171  getParamName(function, &paramName);
172  asynStatus status = readValue(pasynUser, functionName);
173  if (status == asynSuccess)
174  {
175  asynPortDriver::readInt32(pasynUser, value);
176  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
177  "%s:%s: function=%d, name=%s, value=%d\n",
178  driverName, functionName, function, paramName, *value);
179  }
180  return status;
181 }
182 
183 asynStatus NetShrVarDriver::readOctet(asynUser *pasynUser, char *value, size_t maxChars, size_t *nActual, int *eomReason)
184 {
185  static const char *functionName = "readOctet";
186  int function = pasynUser->reason;
187  const char *paramName = NULL;
188  getParamName(function, &paramName);
189  asynStatus status = readValue(pasynUser, functionName);
190  if (status == asynSuccess)
191  {
192  std::string value_s;
193  getStringParam(function, value_s);
194  if ( value_s.size() > maxChars ) // did we read more than we have space for?
195  {
196  *nActual = maxChars;
197  if (eomReason) { *eomReason = ASYN_EOM_CNT | ASYN_EOM_END; }
198  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
199  "%s:%s: function=%d, name=%s, value=\"%s\" (TRUNCATED from %d chars)\n",
200  driverName, functionName, function, paramName, value_s.substr(0,*nActual).c_str(), value_s.size());
201  }
202  else
203  {
204  *nActual = value_s.size();
205  if (eomReason) { *eomReason = ASYN_EOM_END; }
206  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
207  "%s:%s: function=%d, name=%s, value=\"%s\"\n",
208  driverName, functionName, function, paramName, value_s.c_str());
209  }
210  strncpy(value, value_s.c_str(), maxChars); // maxChars will NULL pad if possible, change to *nActual if we do not want this
211  }
212  else
213  {
214  *nActual = 0;
215  if (eomReason) { *eomReason = ASYN_EOM_END; }
216  value[0] = '\0';
217  }
218  return status;
219 }
220 
221 asynStatus NetShrVarDriver::writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
222 {
223  int function = pasynUser->reason;
224  asynStatus status = asynSuccess;
225  const char *paramName = NULL;
226  getParamName(function, &paramName);
227  const char* functionName = "writeOctet";
228  std::string value_s(value, maxChars);
229  try
230  {
231  if (m_netvarint == NULL)
232  {
233  throw std::runtime_error("m_netvarint is NULL");
234  }
235  m_netvarint->setValue(paramName, value_s);
236  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
237  "%s:%s: function=%d, name=%s, value=%s\n",
238  driverName, functionName, function, paramName, value_s.c_str());
239  *nActual = value_s.size();
240  return asynPortDriver::writeOctet(pasynUser, value_s.c_str(), maxChars, nActual);
241  }
242  catch(const std::exception& ex)
243  {
244  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
245  "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
246  driverName, functionName, status, function, paramName, value_s.c_str(), ex.what());
247  *nActual = 0;
248  return asynError;
249  }
250 }
251 
252 asynStatus NetShrVarDriver::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn)
253 {
254  return readArrayValue(pasynUser, "readFloat64Array", value, nElements, nIn);
255 }
256 
257 asynStatus NetShrVarDriver::readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements, size_t *nIn)
258 {
259  return readArrayValue(pasynUser, "readFloat32Array", value, nElements, nIn);
260 }
261 
262 asynStatus NetShrVarDriver::readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn)
263 {
264  return readArrayValue(pasynUser, "readInt32Array", value, nElements, nIn);
265 }
266 
267 asynStatus NetShrVarDriver::readInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements, size_t *nIn)
268 {
269  return readArrayValue(pasynUser, "readInt16Array", value, nElements, nIn);
270 }
271 
272 asynStatus NetShrVarDriver::readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn)
273 {
274  return readArrayValue(pasynUser, "readInt8Array", value, nElements, nIn);
275 }
276 
277 template<typename T>
278 asynStatus NetShrVarDriver::readArrayValue(asynUser *pasynUser, const char* functionName, T *value, size_t nElements, size_t *nIn)
279 {
280  epicsTimeStamp epicsTS;
281  int function = pasynUser->reason;
282  asynStatus status = asynSuccess;
283  const char *paramName = NULL;
284  getParamName(function, &paramName);
285  try
286  {
287  if (m_netvarint == NULL)
288  {
289  throw std::runtime_error("m_netvarint is NULL");
290  }
291  m_netvarint->readArrayValue(paramName, value, nElements, nIn); // this will also update driver timestamp
292  getTimeStamp(&epicsTS);
293  pasynUser->timestamp = epicsTS;
294  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
295  "%s:%s: function=%d, name=%s, size=%d\n",
296  driverName, functionName, function, paramName, (int)nElements);
297  return asynSuccess;
298  }
299  catch(const std::exception& ex)
300  {
301  *nIn = 0;
302  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
303  "%s:%s: status=%d, function=%d, name=%s, size=%d, error=%s",
304  driverName, functionName, status, function, paramName, (int)nElements, ex.what());
305  return asynError;
306  }
307 }
308 
309 asynStatus NetShrVarDriver::writeInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements)
310 {
311  return writeArrayValue(pasynUser, "writeInt32Array", value, nElements);
312 }
313 
314 asynStatus NetShrVarDriver::writeInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements)
315 {
316  return writeArrayValue(pasynUser, "writeInt16Array", value, nElements);
317 }
318 
319 asynStatus NetShrVarDriver::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements)
320 {
321  return writeArrayValue(pasynUser, "writeInt8Array", value, nElements);
322 }
323 
324 asynStatus NetShrVarDriver::writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements)
325 {
326  return writeArrayValue(pasynUser, "writeFloat64Array", value, nElements);
327 }
328 
329 asynStatus NetShrVarDriver::writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements)
330 {
331  return writeArrayValue(pasynUser, "writeFloat32Array", value, nElements);
332 }
333 
335 void NetShrVarDriver::report(FILE* fp, int details)
336 {
337  if (m_netvarint != NULL)
338  {
339  unlock();
340  m_netvarint->report(fp, details);
341  lock();
342  }
343  else
344  {
345  fprintf(fp, "NetVarInt pointer is NULL\n");
346  }
347  asynPortDriver::report(fp, details);
348 }
349 
350 
357 NetShrVarDriver::NetShrVarDriver(NetShrVarInterface* netvarint, int poll_ms, const char *portName)
358  : asynPortDriver(portName,
359  0, /* maxAddr */
360  static_cast<int>(netvarint->nParams()),
361  asynInt32Mask | asynInt8ArrayMask | asynInt16ArrayMask | asynInt32ArrayMask | asynFloat64Mask | asynFloat32ArrayMask | asynFloat64ArrayMask | asynOctetMask | asynDrvUserMask, /* Interface mask */
362  asynInt32Mask | asynInt8ArrayMask | asynInt16ArrayMask | asynInt32ArrayMask | asynFloat64Mask | asynFloat32ArrayMask | asynFloat64ArrayMask | asynOctetMask, /* Interrupt mask */
363  ASYN_CANBLOCK, /* asynFlags. This driver can block but it is not multi-device */
364  1, /* Autoconnect */
365  0, /* Default priority */
366  0), /* Default stack size*/
367  m_netvarint(netvarint), m_poll_ms(poll_ms), m_shutting_down(false)
368 {
369  const char *functionName = "NetShrVarDriver";
370 
371  m_netvarint->createParams(this);
372  if (poll_ms == 0)
373  {
374  std::cerr << "Warning: driver is not polling for buffered reads, only subscribers will see changes" << std::endl;
375  }
376  epicsAtExit(epicsExitFunc, this);
377 
378  // Create the thread for background tasks (not used at present, could be used for I/O intr scanning)
379  if (epicsThreadCreate("NetShrVarDriverTask",
380  epicsThreadPriorityMedium,
381  epicsThreadGetStackSize(epicsThreadStackMedium),
382  (EPICSTHREADFUNC)NetShrVarTask, this) == 0)
383  {
384  printf("%s:%s: epicsThreadCreate failure\n", driverName, functionName);
385  return;
386  }
387 }
388 
390 {
391  NetShrVarDriver* driver = static_cast<NetShrVarDriver*>(arg);
392  if (driver == NULL)
393  {
394  return;
395  }
396  driver->shuttingDown(true);
397 }
398 
399 
401 {
402  NetShrVarDriver* driver = (NetShrVarDriver*)arg;
403  int poll_ms = driver->pollTime();
404  if (poll_ms > 0)
405  {
406  while(!driver->shuttingDown())
407  {
408  try
409  {
410  driver->updateValues();
411  }
412  catch (const std::exception& ex)
413  {
414  std::cerr << "NetShrVarTask: " << ex.what() << std::endl;
415  }
416  catch (...)
417  {
418  std::cerr << "NetShrVarTask: unknown exception" << std::endl;
419  }
420  epicsThreadSleep(static_cast<double>(poll_ms) / 1000.0);
421  }
422  }
423 }
424 
425 extern "C" {
426 
435  int NetShrVarConfigure(const char *portName, const char* configSection, const char *configFile, int pollPeriod, int options)
436  {
437  try
438  {
439  NetShrVarInterface* netvarint = new NetShrVarInterface(configSection, configFile, options);
440  if (netvarint != NULL)
441  {
442  new NetShrVarDriver(netvarint, pollPeriod, portName);
443  return(asynSuccess);
444  }
445  else
446  {
447  errlogSevPrintf(errlogFatal, "NetShrVarConfigure failed (NULL)\n");
448  return(asynError);
449  }
450 
451  }
452  catch(const std::exception& ex)
453  {
454  errlogSevPrintf(errlogFatal, "NetShrVarConfigure failed: %s\n", ex.what());
455  return(asynError);
456  }
457  }
458 
459  // EPICS iocsh shell commands
460 
461  static const iocshArg initArg0 = { "portName", iocshArgString};
462  static const iocshArg initArg1 = { "configSection", iocshArgString};
463  static const iocshArg initArg2 = { "configFile", iocshArgString};
464  static const iocshArg initArg3 = { "pollPeriod", iocshArgInt};
465  static const iocshArg initArg4 = { "options", iocshArgInt};
466 
467  static const iocshArg * const initArgs[] = { &initArg0,
468  &initArg1,
469  &initArg2,
470  &initArg3,
471  &initArg4 };
472 
473  static const iocshFuncDef initFuncDef = {"NetShrVarConfigure", sizeof(initArgs) / sizeof(iocshArg*), initArgs};
474 
475  static void initCallFunc(const iocshArgBuf *args)
476  {
477  NetShrVarConfigure(args[0].sval, args[1].sval, args[2].sval, args[3].ival, args[4].ival);
478  }
479 
481  static void NetShrVarRegister(void)
482  {
483  iocshRegister(&initFuncDef, initCallFunc);
484  }
485 
487 
488 }
489 
virtual asynStatus writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements)
static void epicsExitFunc(void *arg)
std::string convertToString(T t)
Convert a numeric type to a string.
virtual asynStatus writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements)
virtual asynStatus readOctet(asynUser *pasynUser, char *value, size_t maxChars, size_t *nActual, int *eomReason)
void shuttingDown(bool state)
NetShrVarInterface * m_netvarint
void setValue(const char *param, const T &value)
virtual asynStatus writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements)
virtual asynStatus readInt32(asynUser *pasynUser, epicsInt32 *value)
virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn)
static const iocshArg initArg2
Path to the XML input file to load configuration information from.
static void NetShrVarTask(void *arg)
asynStatus readArrayValue(asynUser *pasynUser, const char *functionName, T *value, size_t nElements, size_t *nIn)
static const iocshArg *const initArgs[]
static const iocshArg initArg0
The name of the asyn driver port we will create.
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value)
void report(FILE *fp, int details)
Helper for EPICS driver report function.
Manager class for the NetVar Interaction. Parses an netvarconfig.xml file and provides access to the ...
virtual void report(FILE *fp, int details)
EPICS driver report function for iocsh dbior command.
static void initCallFunc(const iocshArgBuf *args)
Header for NetShrVarDriver class.
void readValue(const char *param)
read a value and update corresponding asyn parameter
void createParams(asynPortDriver *driver)
static const iocshArg initArg4
options as per NetShrVarOptions enum
int NetShrVarConfigure(const char *portName, const char *configSection, const char *configFile, int pollPeriod, int options)
EPICS iocsh callable function to call constructor of NetShrVarInterface().
static const iocshArg initArg1
section name of configFile to use to configure this asyn port
virtual asynStatus readInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements, size_t *nIn)
static const iocshFuncDef initFuncDef
virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn)
asynStatus readValue(asynUser *pasynUser, const char *functionName)
EPICS Asyn port driver class.
asynStatus writeArrayValue(asynUser *pasynUser, const char *functionName, T *value, size_t nElements)
write an array to the driver
void readArrayValue(const char *paramName, T *value, size_t nElements, size_t *nIn)
called externally with m_driver locked
Header for templated number to string conversion functions.
void setArrayValue(const char *param, const T *value, size_t nElements)
asynStatus writeValue(asynUser *pasynUser, const char *functionName, T value)
write a value to the driver
virtual asynStatus readFloat64(asynUser *pasynUser, epicsFloat64 *value)
NetShrVarDriver(NetShrVarInterface *netvarint, int poll_ms, const char *portName)
Constructor for the NetShrVarDriver class.
virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
virtual asynStatus readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements, size_t *nIn)
header for NetShrVarInterface class.
virtual asynStatus writeInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements)
epicsExportRegistrar(NetShrVarRegister)
static void NetShrVarRegister(void)
Register new commands with EPICS IOC shell.
static const iocshArg initArg3
poll period (ms) for BufferedReaders
virtual asynStatus writeInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements)
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value)
write a float to the driver
static const char * driverName
Name of driver for use in message printing.
virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn)
Copyright © 2013 Science and Technology Facilities Council | Generated by   doxygen 1.8.5