ISIS Logo
NINetVar
An EPICS support module to export National Instruments Network Shared Variables as process variables
NINetVarDriver.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 
30 #include <windows.h>
31 
32 #include "convertToString.h"
33 #include "NINetVarInterface.h"
34 #include "NINetVarDriver.h"
35 
36 #include <epicsExport.h>
37 
39 std::string Win32StructuredException::win32_message(unsigned int code, EXCEPTION_POINTERS * pExp)
40 {
41  char buffer[256];
42  _snprintf(buffer, sizeof(buffer), "Win32StructuredException code 0x%x pExpCode 0x%x pExpAddress %p", code, pExp->ExceptionRecord->ExceptionCode, pExp->ExceptionRecord->ExceptionAddress);
43  buffer[sizeof(buffer)-1] = '\0';
44  return std::string(buffer);
45 }
46 
47 static const char *driverName="NINetVarDriver";
48 
51 static void seTransFunction(unsigned int u, EXCEPTION_POINTERS* pExp)
52 {
53  throw Win32StructuredException(u, pExp);
54 }
55 
58 {
59  _set_se_translator(seTransFunction);
60 }
61 
67 template<typename T>
68 asynStatus NINetVarDriver::writeValue(asynUser *pasynUser, const char* functionName, T value)
69 {
70  int function = pasynUser->reason;
71  asynStatus status = asynSuccess;
72  const char *paramName = NULL;
74  getParamName(function, &paramName);
75  try
76  {
77  if (m_netvarint == NULL)
78  {
79  throw std::runtime_error("m_netvarint is NULL");
80  }
81  m_netvarint->setValue(paramName, value);
82  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
83  "%s:%s: function=%d, name=%s, value=%s\n",
84  driverName, functionName, function, paramName, convertToString(value).c_str());
85  return asynSuccess;
86  }
87  catch(const std::exception& ex)
88  {
89  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
90  "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
91  driverName, functionName, status, function, paramName, convertToString(value).c_str(), ex.what());
92  return asynError;
93  }
94 }
95 
102 template<typename T>
103 asynStatus NINetVarDriver::writeArrayValue(asynUser *pasynUser, const char* functionName, T* value, size_t nElements)
104 {
105  int function = pasynUser->reason;
106  asynStatus status = asynSuccess;
107  const char *paramName = NULL;
109  getParamName(function, &paramName);
110  try
111  {
112  if (m_netvarint == NULL)
113  {
114  throw std::runtime_error("m_netvarint is NULL");
115  }
116  m_netvarint->setArrayValue(paramName, value, nElements);
117  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
118  "%s:%s: function=%d, name=%s, nElements=%d\n",
119  driverName, functionName, function, paramName, nElements);
120  return asynSuccess;
121  }
122  catch(const std::exception& ex)
123  {
124  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
125  "%s:%s: status=%d, function=%d, name=%s, nElements=%d, error=%s",
126  driverName, functionName, status, function, paramName, nElements, ex.what());
127  return asynError;
128  }
129 }
130 
134 asynStatus NINetVarDriver::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
135 {
136  asynStatus status = writeValue(pasynUser, "writeFloat64", value);
137  return (status == asynSuccess ? asynPortDriver::writeFloat64(pasynUser, value) : status);
138 }
139 
140 asynStatus NINetVarDriver::writeInt32(asynUser *pasynUser, epicsInt32 value)
141 {
142  asynStatus status = writeValue(pasynUser, "writeInt32", value);
143  return (status == asynSuccess ? asynPortDriver::writeInt32(pasynUser, value) : status);
144 }
145 
146 asynStatus NINetVarDriver::writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
147 {
148  int function = pasynUser->reason;
149  asynStatus status = asynSuccess;
150  const char *paramName = NULL;
152  getParamName(function, &paramName);
153  const char* functionName = "writeOctet";
154  std::string value_s(value, maxChars);
155  try
156  {
157  if (m_netvarint == NULL)
158  {
159  throw std::runtime_error("m_netvarint is NULL");
160  }
161  m_netvarint->setValue(paramName, value_s);
162  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
163  "%s:%s: function=%d, name=%s, value=%s\n",
164  driverName, functionName, function, paramName, value_s.c_str());
165  *nActual = value_s.size();
166  return asynPortDriver::writeOctet(pasynUser, value_s.c_str(), maxChars, nActual);
167  }
168  catch(const std::exception& ex)
169  {
170  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
171  "%s:%s: status=%d, function=%d, name=%s, value=%s, error=%s",
172  driverName, functionName, status, function, paramName, value_s.c_str(), ex.what());
173  *nActual = 0;
174  return asynError;
175  }
176 }
177 
178 asynStatus NINetVarDriver::readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn)
179 {
180  return readArrayValue(pasynUser, "readFloat64Array", value, nElements, nIn);
181 }
182 
183 asynStatus NINetVarDriver::readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements, size_t *nIn)
184 {
185  return readArrayValue(pasynUser, "readFloat32Array", value, nElements, nIn);
186 }
187 
188 asynStatus NINetVarDriver::readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn)
189 {
190  return readArrayValue(pasynUser, "readInt32Array", value, nElements, nIn);
191 }
192 
193 asynStatus NINetVarDriver::readInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements, size_t *nIn)
194 {
195  return readArrayValue(pasynUser, "readInt16Array", value, nElements, nIn);
196 }
197 
198 asynStatus NINetVarDriver::readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn)
199 {
200  return readArrayValue(pasynUser, "readInt8Array", value, nElements, nIn);
201 }
202 
203 template<typename T>
204 asynStatus NINetVarDriver::readArrayValue(asynUser *pasynUser, const char* functionName, T *value, size_t nElements, size_t *nIn)
205 {
206  int function = pasynUser->reason;
207  asynStatus status = asynSuccess;
208  const char *paramName = NULL;
210  getParamName(function, &paramName);
211  try
212  {
213  if (m_netvarint == NULL)
214  {
215  throw std::runtime_error("m_netvarint is NULL");
216  }
217  m_netvarint->readArrayValue(paramName, value, nElements, nIn);
218  asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
219  "%s:%s: function=%d, name=%s, size=%d\n",
220  driverName, functionName, function, paramName, nElements);
221  return asynSuccess;
222  }
223  catch(const std::exception& ex)
224  {
225  *nIn = 0;
226  epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
227  "%s:%s: status=%d, function=%d, name=%s, size=%d, error=%s",
228  driverName, functionName, status, function, paramName, nElements, ex.what());
229  return asynError;
230  }
231 }
232 
233 asynStatus NINetVarDriver::writeInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements)
234 {
235  return writeArrayValue(pasynUser, "writeInt32Array", value, nElements);
236 }
237 
238 asynStatus NINetVarDriver::writeInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements)
239 {
240  return writeArrayValue(pasynUser, "writeInt16Array", value, nElements);
241 }
242 
243 asynStatus NINetVarDriver::writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements)
244 {
245  return writeArrayValue(pasynUser, "writeInt8Array", value, nElements);
246 }
247 
248 asynStatus NINetVarDriver::writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements)
249 {
250  return writeArrayValue(pasynUser, "writeFloat64Array", value, nElements);
251 }
252 
253 asynStatus NINetVarDriver::writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements)
254 {
255  return writeArrayValue(pasynUser, "writeFloat32Array", value, nElements);
256 }
257 
259 void NINetVarDriver::report(FILE* fp, int details)
260 {
261  if (m_netvarint != NULL)
262  {
263  m_netvarint->report(fp, details);
264  }
265  else
266  {
267  fprintf(fp, "NetVarInt pointer is NULL\n");
268  }
269  asynPortDriver::report(fp, details);
270 }
271 
272 
279 NINetVarDriver::NINetVarDriver(NINetVarInterface* netvarint, int poll_ms, const char *portName)
280  : asynPortDriver(portName,
281  0, /* maxAddr */
282  netvarint->nParams(),
283  asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynOctetMask | asynDrvUserMask, /* Interface mask */
284  asynInt32Mask | asynInt32ArrayMask | asynFloat64Mask | asynFloat64ArrayMask | asynOctetMask, /* Interrupt mask */
285  ASYN_CANBLOCK, /* asynFlags. This driver can block but it is not multi-device */
286  1, /* Autoconnect */
287  0, /* Default priority */
288  0), /* Default stack size*/
289  m_netvarint(netvarint), m_poll_ms(poll_ms), m_shutting_down(false)
290 {
291  const char *functionName = "NINetVarDriver";
292 
293  m_netvarint->createParams(this);
294  if (poll_ms == 0)
295  {
296  std::cerr << "Warning: driver is not polling for buffered reads, only subscribers will see changes" << std::endl;
297  }
298  epicsAtExit(epicsExitFunc, this);
299 
300  // Create the thread for background tasks (not used at present, could be used for I/O intr scanning)
301  if (epicsThreadCreate("NINetVarDriverTask",
302  epicsThreadPriorityMedium,
303  epicsThreadGetStackSize(epicsThreadStackMedium),
304  (EPICSTHREADFUNC)NINetVarTask, this) == 0)
305  {
306  printf("%s:%s: epicsThreadCreate failure\n", driverName, functionName);
307  return;
308  }
309 }
310 
312 {
313  NINetVarDriver* driver = static_cast<NINetVarDriver*>(arg);
314  if (driver == NULL)
315  {
316  return;
317  }
318  driver->shuttingDown(true);
319 }
320 
321 
323 {
324  NINetVarDriver* driver = (NINetVarDriver*)arg;
326  int poll_ms = driver->pollTime();
327  if (poll_ms > 0)
328  {
329  while(!driver->shuttingDown())
330  {
331  driver->updateValues();
332  epicsThreadSleep(static_cast<double>(poll_ms) / 1000.0);
333  }
334  }
335 }
336 
337 extern "C" {
338 
347  int NINetVarConfigure(const char *portName, const char* configSection, const char *configFile, int pollPeriod, int options)
348  {
350  try
351  {
352  NINetVarInterface* netvarint = new NINetVarInterface(configSection, configFile, options);
353  if (netvarint != NULL)
354  {
355  new NINetVarDriver(netvarint, pollPeriod, portName);
356  return(asynSuccess);
357  }
358  else
359  {
360  errlogSevPrintf(errlogFatal, "NINetVarConfigure failed (NULL)\n");
361  return(asynError);
362  }
363 
364  }
365  catch(const std::exception& ex)
366  {
367  errlogSevPrintf(errlogFatal, "NINetVarConfigure failed: %s\n", ex.what());
368  return(asynError);
369  }
370  }
371 
372  // EPICS iocsh shell commands
373 
374  static const iocshArg initArg0 = { "portName", iocshArgString};
375  static const iocshArg initArg1 = { "configSection", iocshArgString};
376  static const iocshArg initArg2 = { "configFile", iocshArgString};
377  static const iocshArg initArg3 = { "pollPeriod", iocshArgInt};
378  static const iocshArg initArg4 = { "options", iocshArgInt};
379 
380  static const iocshArg * const initArgs[] = { &initArg0,
381  &initArg1,
382  &initArg2,
383  &initArg3,
384  &initArg4 };
385 
386  static const iocshFuncDef initFuncDef = {"NINetVarConfigure", sizeof(initArgs) / sizeof(iocshArg*), initArgs};
387 
388  static void initCallFunc(const iocshArgBuf *args)
389  {
390  NINetVarConfigure(args[0].sval, args[1].sval, args[2].sval, args[3].ival, args[4].ival);
391  }
392 
394  static void NINetVarRegister(void)
395  {
396  iocshRegister(&initFuncDef, initCallFunc);
397  }
398 
400 
401 }
402 
virtual void report(FILE *fp, int details)
EPICS driver report function for iocsh dbior command.
virtual asynStatus readInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements, size_t *nIn)
static const iocshArg initArg4
options as per NINetVarOptions enum
virtual asynStatus writeOctet(asynUser *pasynUser, const char *value, size_t maxChars, size_t *nActual)
header for NINetVarInterface class.
static const iocshFuncDef initFuncDef
std::string convertToString(T t)
Convert a numeric type to a string.
static void initCallFunc(const iocshArgBuf *args)
static const iocshArg initArg3
poll period (ms)
static const iocshArg *const initArgs[]
epicsExportRegistrar(NINetVarRegister)
void setValue(const char *param, const T &value)
An STL exception describing a Win32 Structured Exception.
void setArrayValue(const char *param, const T *value, size_t nElements)
static const char * driverName
Name of driver for use in message printing.
void shuttingDown(bool state)
asynStatus writeValue(asynUser *pasynUser, const char *functionName, T value)
write a value to the driver
virtual asynStatus readFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements, size_t *nIn)
EPICS Asyn port driver class.
static void epicsExitFunc(void *arg)
static const iocshArg initArg0
The name of the asyn driver port we will create.
static void NINetVarRegister(void)
Register new commands with EPICS IOC shell.
static std::string win32_message(unsigned int code, EXCEPTION_POINTERS *pExp)
Helper function to map a win32 structured exception into a C++ standard exception.
virtual asynStatus readInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements, size_t *nIn)
virtual asynStatus writeInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements)
static const iocshArg initArg1
section name of configFile to use to configure this asyn port
int NINetVarConfigure(const char *portName, const char *configSection, const char *configFile, int pollPeriod, int options)
EPICS iocsh callable function to call constructor of NINetVarInterface().
void createParams(asynPortDriver *driver)
virtual asynStatus writeInt32(asynUser *pasynUser, epicsInt32 value)
virtual asynStatus readFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements, size_t *nIn)
virtual asynStatus writeInt16Array(asynUser *pasynUser, epicsInt16 *value, size_t nElements)
NINetVarDriver(NINetVarInterface *netvarint, int poll_ms, const char *portName)
Constructor for the NINetVarDriver class.
static void registerStructuredExceptionHandler()
Register a handler for Win32 strcutured exceptions. This needs to be done on a per thread basis...
static const iocshArg initArg2
Path to the XML input file to load configuration information from.
static void seTransFunction(unsigned int u, EXCEPTION_POINTERS *pExp)
Function to translate a Win32 structured exception into a standard C++ exception. ...
virtual asynStatus writeFloat32Array(asynUser *pasynUser, epicsFloat32 *value, size_t nElements)
NINetVarInterface * m_netvarint
asynStatus readArrayValue(asynUser *pasynUser, const char *functionName, T *value, size_t nElements, size_t *nIn)
void report(FILE *fp, int details)
Helper for EPICS driver report function.
Header for templated number to string conversion functions.
virtual asynStatus writeFloat64Array(asynUser *pasynUser, epicsFloat64 *value, size_t nElements)
Manager class for the NetVar Interaction. Parses an netvarconfig.xml file and provides access to the ...
virtual asynStatus writeFloat64(asynUser *pasynUser, epicsFloat64 value)
write a float to the driver
virtual asynStatus readInt8Array(asynUser *pasynUser, epicsInt8 *value, size_t nElements, size_t *nIn)
Header for NINetVarDriver class.
virtual asynStatus writeInt32Array(asynUser *pasynUser, epicsInt32 *value, size_t nElements)
static void NINetVarTask(void *arg)
void readArrayValue(const char *paramName, T *value, size_t nElements, size_t *nIn)
asynStatus writeArrayValue(asynUser *pasynUser, const char *functionName, T *value, size_t nElements)
write an array to the driver
Copyright © 2013 Science and Technology Facilities Council | Generated by   doxygen 1.8.8