ISIS Logo
INSTETC
INSTETC IOC
instetcDriver.cpp
Go to the documentation of this file.
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stdio.h>
4 #include <errno.h>
5 #include <math.h>
6 #include <exception>
7 #include <iostream>
8 #include <sstream>
9 #include <fstream>
10 #include <sys/stat.h>
11 
12 #include <list>
13 #include <algorithm>
14 #include <iterator>
15 #include <vector>
16 
17 #include <epicsTypes.h>
18 #include <epicsTime.h>
19 #include <epicsThread.h>
20 #include <epicsString.h>
21 #include <epicsTimer.h>
22 #include <epicsMutex.h>
23 #include <epicsEvent.h>
24 #include <iocsh.h>
25 
26 #include "instetcDriver.h"
27 
28 #include <macLib.h>
29 #include <epicsGuard.h>
30 
31 #include <epicsExport.h>
32 
33 static const char *driverName="instetcDriver";
34 
39 instetcDriver::instetcDriver(const char *portName, const char* filePath, const int lineCount, const double pollingPeriod)
40  : file_mod(0), filePath(filePath), lineCount(lineCount), pollingPeriod(pollingPeriod), asynPortDriver(portName,
41  0, /* maxAddr */
43  asynInt32Mask | asynFloat64Mask | asynOctetMask | asynDrvUserMask, /* Interface mask */
44  asynInt32Mask | asynFloat64Mask | asynOctetMask, /* Interrupt mask */
45  ASYN_CANBLOCK, /* asynFlags. This driver can block but it is not multi-device */
46  1, /* Autoconnect */
47  0, /* Default priority */
48  0) /* Default stack size*/
49 {
50  const char *functionName = "instetcDriver";
51  createParam(P_TextString, asynParamOctet, &P_Text);
52 
53  // Create the thread for background tasks (not used at present, could be used for I/O intr scanning)
54  if (epicsThreadCreate("instetcPoller",
55  epicsThreadPriorityMedium,
56  epicsThreadGetStackSize(epicsThreadStackMedium),
57  (EPICSTHREADFUNC)pollerThreadC, this) == 0)
58  {
59  printf("%s:%s: epicsThreadCreate failure\n", driverName, functionName);
60  return;
61  }
62 }
63 
64 // -1 if file does not exist, 0 if no change to file content, 1 if new lines
65 int instetcDriver::getLastLines(std::string& the_lines)
66 {
67  size_t const granularity = 100 * lineCount;
68  char filePathEx[1024];
69  time_t now;
70  struct tm now_tm;
71  struct stat stat_struct;
72  time(&now);
73  memcpy(&now_tm, localtime(&now), sizeof(struct tm));
74  if ( 0 == strftime(filePathEx, sizeof(filePathEx)-1, filePath.c_str(), &now_tm) )
75  {
76  strncpy(filePathEx, filePath.c_str(), sizeof(filePathEx)-1);
77  }
78  filePathEx[sizeof(filePathEx)-1] = '\0';
79  if (stat(filePathEx, &stat_struct) != 0)
80  {
81  if (file_mod == 0)
82  {
83  the_lines = std::string("File \"") + filePathEx + "\" does not exist";
84  file_mod = 1; // just so we do not continue to update with same message
85  return -1;
86  }
87  // file does not exist, but it used to -> assume it was date rotated
88  return 0;
89  }
90  if (stat_struct.st_mtime == file_mod)
91  {
92  return 0;
93  }
94  file_mod = stat_struct.st_mtime;
95  std::ifstream source(filePathEx, std::ios_base::binary);
96  source.seekg(0, std::ios_base::end);
97  size_t size = static_cast<size_t>(source.tellg());
98  std::vector<char> buffer;
99 
100  int newlineCount = 0;
101  while (source
102  && buffer.size() != size
103  && newlineCount < lineCount )
104  {
105  buffer.resize(std::min(buffer.size() + granularity, size));
106  source.seekg(-static_cast<std::streamoff>(buffer.size()), std::ios_base::end);
107  source.read(buffer.data(), buffer.size());
108  newlineCount = static_cast<int>(std::count(buffer.begin(), buffer.end(), '\n'));
109  }
110 
111  std::vector<char>::iterator start = buffer.begin();
112  while (newlineCount > lineCount)
113  {
114  start = std::find(start, buffer.end(), '\n') + 1;
115  --newlineCount;
116  }
117 
118  std::vector<char>::iterator end = std::remove(start, buffer.end(), '\r');
119  the_lines = std::string(start, end);
120  return 1;
121 }
122 
124 {
125  instetcDriver* driver = (instetcDriver*)arg;
126  driver->pollerThread(driver->filePath, driver->lineCount, driver->pollingPeriod);
127 }
128 
129 #define LEN_BUFFER 10024 /* needs to match size if char waveform in DB file */
130 
131 void instetcDriver::pollerThread(const std::string& filePath, int lineCount, double pollingPeriod)
132 {
133  std::string lines;
134  updateText("");
135  while (true)
136  {
137  if (getLastLines(lines) != 0)
138  {
139  updateText(lines.substr(0, LEN_BUFFER));
140  }
141  epicsThreadSleep(3.0);
142  }
143 }
144 
145 void instetcDriver::updateText(const std::string& text)
146 {
147  lock();
148  setStringParam(P_Text, text.c_str());
149  callParamCallbacks();
150  unlock();
151 }
152 
153 
154 extern "C" {
157  static int instetcConfigure(const char *portName, const char* logFilePath, const int lineCount, const double pollingPeriod)
158  {
159  try
160  {
161  new instetcDriver(portName, logFilePath, lineCount, pollingPeriod);
162  return(asynSuccess);
163  }
164  catch(const std::exception& ex)
165  {
166  std::cerr << "instetcDriver failed: " << ex.what() << std::endl;
167  return(asynError);
168  }
169  }
170 
171  // EPICS iocsh shell commands
172 
173  static const iocshArg initArg0 = { "portName", iocshArgString};
174  static const iocshArg initArg1 = { "logFilePath", iocshArgString};
175  static const iocshArg initArg2 = { "lineCount", iocshArgInt};
176  static const iocshArg initArg3 = { "pollingPeriod", iocshArgDouble};
177 
178  static const iocshArg * const initArgs[] = { &initArg0, &initArg1, &initArg2, &initArg3 };
179 
180  static const iocshFuncDef initFuncDef = {"instetcConfigure", sizeof(initArgs) / sizeof(iocshArg*), initArgs};
181 
182  static void initCallFunc(const iocshArgBuf *args)
183  {
184  instetcConfigure(args[0].sval, args[1].sval, args[2].ival, args[3].dval);
185  }
186 
187  static void instetcRegister(void)
188  {
189  iocshRegister(&initFuncDef, initCallFunc);
190  }
191 
193 }
194 
#define NUM_INSTETC_PARAMS
Definition: instetcDriver.h:29
void pollerThread(const std::string &filePath, int lineCount, double pollingPeriod)
double pollingPeriod
Definition: instetcDriver.h:15
epicsExportRegistrar(instetcRegister)
std::string filePath
Definition: instetcDriver.h:13
static const iocshArg initArg1
The path to the file we will monitor.
static void pollerThreadC(void *arg)
static const iocshArg initArg2
The number of log file lines to broadcast.
int getLastLines(std::string &the_lines)
instetcDriver(const char *portName, const char *filePath, const int lineCount, double pollingPeriod)
Constructor for the lvDCOMDriver class.
static const char * driverName
static void instetcRegister(void)
static const iocshFuncDef initFuncDef
static const iocshArg *const initArgs[]
void updateText(const std::string &text)
static void initCallFunc(const iocshArgBuf *args)
static const iocshArg initArg3
The number of seconds between file reads.
#define P_TextString
Definition: instetcDriver.h:30
#define LEN_BUFFER
static int instetcConfigure(const char *portName, const char *logFilePath, const int lineCount, const double pollingPeriod)
EPICS iocsh callable function to call constructor of lvDCOMInterface().
static const iocshArg initArg0
The name of the asyn driver port we will create.
Copyright © 2013 Science and Technology Facilities Council | Generated by   doxygen 1.8.5