iop_xdevice.cpp
Go to the documentation of this file.
1 /** @file iop_xdevice.cpp Device container with vDevice interface */
2 
3 /*
4  FAU Discrete Event Systems Library (libfaudes)
5 
6  Copyright (C) 2008, Thomas Moor
7  Exclusive copyright is granted to Klaus Schmidt
8 
9 */
10 
11 
12 
13 #include "iop_xdevice.h"
14 #include "sys/time.h"
15 
16 #include "iop_simplenet.h"
17 #include "iop_comedi.h"
18 #include "iop_wago.h"
19 #include "iop_serial.h"
20 #include "iop_modbus.h"
21 #include "iop_d3ripURT.h"
22 #include "iop_d3ripDART.h"
23 
24 namespace faudes {
25 
26 /*
27  **********************************************
28  **********************************************
29  **********************************************
30 
31  implementation: xDevice
32 
33  **********************************************
34  **********************************************
35  **********************************************
36  */
37 
38 // std faudes
39 FAUDES_TYPE_IMPLEMENTATION(DeviceContainer,xDevice,vDevice)
40 
41 // autoregister
42 volatile static AutoRegisterType<xDevice> gRtiRegisterDeviceContainer("DeviceContainer");
43 
44 //constructor
45 xDevice::xDevice(void) : vDevice() {
46  FD_DHV("xDevice(" << mName << ")::xDevice()");
47  mName="IoDevices";
48  // have appropriate default label
49  mDefaultLabel="DeviceContainer";
50 
51  // auto register fix:
52  // for some reasons the global register objects do not work properly.
53  // since the xdevice is autoregeistered by the rti, we ask the constructor
54  // to register the other devices
55 
56 #ifdef FAUDES_IODEVICE_SIMPLENET
57  volatile static AutoRegisterType<nDevice> gRtiIORegisterSimplenetDevice("SimplenetDevice");
58 #endif
59 #ifdef FAUDES_IODEVICE_COMEDI
60  volatile static AutoRegisterType<cDevice> gRtiIORegisterComediDevice("ComediDevice");
61 #endif
62 #ifdef FAUDES_IODEVICE_WAGO
63  volatile static AutoRegisterType<wDevice> gRtiIORegisterWagoDevice("WagoDevice");
64 #endif
65 #ifdef FAUDES_IODEVICE_SERIAL
66  volatile static AutoRegisterType<spiDevice> gRtiIORegisterSerialPiDevice("SpiDevice");
67 #endif
68 #ifdef FAUDES_IODEVICE_MODBUS
69  volatile static AutoRegisterType<mbDevice> gRtiIORegisterSerialPiDevice("ModbusDevice");
70 #endif
71 #ifdef FAUDES_IODEVICE_D3RIP_URT
72  volatile static AutoRegisterType<d3ripURTDevice> gRtiIORegisterD3ripUrtDevice("D3RipUrtDevice");
73 #endif
74 #ifdef FAUDES_IODEVICE_D3RIP_DART
75  volatile static AutoRegisterType<d3ripDARTDevice> gRtiIORegisterD3ripDartDevice("D3RipDartDevice");
76 #endif
77 
78 }
79 
80 // destructor
82  FD_DHV("xDevice(" << mName << ")::~xDevice()");
83  // loop to free devices.
84  Iterator dit;
85  for(dit=Begin();dit!=End();dit++){
86  delete (*dit);
87  }
88 }
89 
90 //FromTokenReader(rTr)
92  // construct from token reader
93  FD_DHV("xDevice::FromTokenReader()");
94  // allocate
95  xDevice* dev=new xDevice();
96  // read
97  dev->DoRead(rTr);
98  return dev;
99 }
100 
101 //FromFile(rFilename)
102 xDevice* xDevice::FromFile(const std::string& rFileName) {
103  // construct from file
104  FD_DHV("xDevice()::FromFile(" << rFileName <<")");
105  // peek first token
106  TokenReader tr(rFileName);
107  return FromTokenReader(tr);
108 }
109 
110 
111 //Status(void)
113 
114  FD_DHV("xDevice(" << mName << ")::Status() ");
115  //prepare result
117  //vector to store states of all devices integrated in xdevice
118  std::vector<xDevice::DeviceState> states;
119  //vector iterator
120  std::vector<DeviceState>::iterator vit;
121  vit = states.begin();
122  //device iterator
123  iterator dit;
124  //identify device state
125  for(dit=Begin();dit!=End();dit++){
126  //get state of current device and insert it in vector
127  states.push_back((DeviceState)(*dit)->Status());
128  //make sure it isnt the first entry
129  if(vit != states.begin()){
130  //if current entry doesnt equal previous
131  //decide depending on last command
132  if (*vit!=*vit--){
133  //if last command was start: "StartUp"
135  res = StartUp;
136  break;
137  }
138  //if last command was stop: "ShutDown"
139  if(!lastCommandWasStart){
140  res = ShutDown;
141  break;
142  }
143  }
144  }
145  //move on to next device
146  vit++;
147  }
148  //if for-loop finished all entries of vector "states" are equal
149  res = *states.begin();
150  return res;
151 }
152 
153 // Start(void)
154 void xDevice::Start(void) {
155 
156  FD_DHV("xDevice(" << mName <<")::Start()");
157  // start implies reset
158  Reset();
159  //start all existing devices
160  Iterator dit;
161  for(dit = Begin();dit!=End();dit++){
162  (*dit)->Start();
163  }
164  //remember this command
165  lastCommandWasStart = true;
166 }
167 
168 // Stop(void)
169 void xDevice::Stop(void) {
170 
171  FD_DHV("xDevice(" << mName <<")::Stop()");
172  // xDevice Reset
173  Reset();
174  // stop all existing devices
175  Iterator dit;
176  for(dit=Begin();dit!=End();dit++){
177  (*dit)->Stop();
178  }
179  //remember this command
180  lastCommandWasStart = false;
181 }
182 
183 // Reset(void)
184 void xDevice::Reset(void){
185  //clear dynamic data
186 
187  FD_DHV("xDevice(" << mName <<")::Reset()");
188  // device-iterator
189  Iterator dit;
190  for(dit=Begin();dit!=End();dit++){
191  (*dit)->Reset();
192  }
193  // call base to reset time and fifo
194  vDevice::Reset();
195 }
196 
197 // Clear(void)
198 void xDevice::Clear(void){
199  //clear static data
200 
201  FD_DHV("xDevice(" << mName << ")::Clear()");
202  // Stop running devices
203  Stop();
204  // device-iterator
205  Iterator dit;
206  // and clear all devices
207  for(dit=Begin();dit!=End();dit++){
208  (*dit)->Clear();
209  }
210  // destroy existing data
211  for(dit=Begin();dit!=End();dit++){
212  delete (*dit);
213  }
214  // compile with empty containers
215  Compile();
216 }
217 
218 // Insert(vDevice*)
219 void xDevice::Insert(vDevice* device){
220 
221  FD_DHV("xDevice("<<mName<<")::Insert(" << device << "):" << device->Name());
222  // insert any vdevice, but no xdevice
223  if(dynamic_cast<xDevice*>(device)) {
224  std::stringstream errstr;
225  errstr << "Attempt to insert xDevice into xDevice";
226  throw Exception("xDevice::Compile", errstr.str(), 550);
227  }
228  // add to mDevices
229  mDevices.push_back(device);
230  // and update compiled data
231  Compile();
232 }
233 
234 //Insert(rFilename)
235 void xDevice::Insert(const std::string& rFileName){
236  //inserts a device by filename
237  FD_DHV("xDevice("<<mName<<")::Insert(rFileName)");
238  //read device
239  vDevice* pdev = vDevice::FromFile(rFileName);
240  //insert device
241  Insert(pdev);
242  //and remember its name
243  mDeviceNames.push_back(rFileName);
244 }
245 
246 
247 // Compile(void)
248 void xDevice::Compile(void) {
249  //build up internal data-structures
250 
251  FD_DHV("xDevice("<<mName<<")::Compile()");
252  Stop();
253  // build up (event-idx,int)-map and memorize all existing events
254  // prepare containers
255  mInputs.Clear();
256  mOutputs.Clear();
257  mInputToDevice.clear();
258  mOutputToDevice.clear();
259  // temporary container
260  EventSet tmpSenEvents;
261  EventSet tmpActEvents;
262  // event-iterator
263  EventSet::Iterator eit;
264  // device-iterator
265  Iterator dit;
266  // helper
267  int j;
268  // iterate over existing devices
269  for(dit=Begin(), j=0; dit!=End(); dit++,j++){
270  // get events by Index
271  tmpSenEvents = (*dit)->Inputs();
272  tmpActEvents = (*dit)->Outputs();
273  //insert output-events in map
274  for(eit=tmpActEvents.Begin();eit!=tmpActEvents.End();eit++){
275  // test if actual event already exists in map
276  if(mOutputs.Exists(*eit)){
277  //throw exeption
278  std::stringstream errstr;
279  errstr << "Event already exists!";
280  throw Exception("xDevice()::Compile", errstr.str(), 550);
281  }
282  mOutputToDevice[*eit] = j;
283  }
284  // memorize events
285  mInputs.InsertSet(tmpSenEvents);
286  mOutputs.InsertSet(tmpActEvents);
287  // tell the device which mutex/condition-pair to use
288  (*dit)->UseCondition(pWaitMutex,pWaitCondition);
289  (*dit)->UseBuffer(pBufferMutex,pInputBuffer);
290  }//end iteration over existing devices
291  // set time scale from first device
292  if(Size()!=0) (*Begin())->TimeScale(mTimeScale);
293 }
294 
295 
296 //Configure(event,attr)
297 void xDevice::Configure(Idx event, const AttributeDeviceEvent& attr){
298  (void) event; (void) attr;
299  // cannot do vDevice style configuration of events
300 
301  FD_DHV("xDevice("<<mName<<")::Configure(Idx,attr): ");
302  std::stringstream errstr;
303  errstr << "Attempt to configure xDevice by event";
304  throw Exception("xDevice::Configure(Idx,attr)", errstr.str(), 550);
305 }
306 
307 //Configure(rEvents)
308 void xDevice::Configure(const EventSet& rEvents){
309  (void) rEvents;
310  // cannot do vDevice style configuration of events
311 
312  FD_DHV("xDevice("<<mName<<")::Configure(rEvents)");
313  std::stringstream errstr;
314  errstr << "Attempt to configure xDevice by events";
315  throw Exception("xDevice::Configure", errstr.str(), 550);
316 }
317 
318 
319 //CurrentTime(void)
321 
322  FD_DHV("xDevice("<<mName<<"): CurrentTime() ");
323  // throw exception if there is no device
324  if(Size()==0) {
325  std::stringstream errstr;
326  errstr << "xDevice owns no device!";
327  throw Exception("xDevice::CurrentTime", errstr.str(),550);
328  }
329  // ask first device
330  return (*Begin())->CurrentTime();
331 }
332 
333 
334 //CurrentTime(void)
335 long int xDevice::CurrentTimeMs(void) {
336  //debug flag: say hello
337  FD_DHV("xDevice("<<mName<<")::CurrentTimeMs() ");
338  // throw exception if there is no device
339  if(Size()==0) {
340  std::stringstream errstr;
341  errstr << "xDevice owns no device!";
342  throw Exception("xDevice::CurrentTimeMs", errstr.str(),550);
343  }
344  // ask first device
345  return (*Begin())->CurrentTimeMs();
346 }
347 
348 //CurrentTime(now)
350  //debug flag: say hello
351  FD_DHV("xDevice("<<mName<<")::CurrentTime("<<now<<") ");
352  // tell first device if such
353  if(Size()!=0) (*Begin())->CurrentTime(now);
354 }
355 
356 //CurrentTimeMs(now)
357 void xDevice::CurrentTimeMs(long int nowms) {
358  //debug flag: say hello
359 
360  FD_DHV("xDevice("<<mName<<")::CurrentTimeMs("<<nowms<<") ");
361  // tell first device if such
362  if(Size()!=0) (*Begin())->CurrentTimeMs(nowms);
363 }
364 
365 //DoWrite(rTr,rLabel)
366 void xDevice::DoWriteConfiguration(TokenWriter& rTw, const std::string& rLabel, const Type* pContext) const {
367  (void) rTw;
368 
369  FD_DHV("xDevice("<<mName<<")::DoWriteConfiguration()");
370  // hard coded begin
371  rTw.WriteBegin("Devices");
372  // define device-iterator
373  Iterator dit;
374  //iterate over all devices
375  for(Idx i=0; i<Size(); i++) {
376  //if device was read from an extra file
377  if(mDeviceNames.at(i) != ""){
378  //write path to TokenWriter
379  FD_DHV("xDevice("<<mName<<")::DoWrite(): "<<mDeviceNames.at(i));
380  rTw.WriteString(mDeviceNames.at(i)); //TODO: relativ path-names
381  }
382  //else device was directly read from base-config-file
383  else if(mDeviceNames.at(i) == ""){
384  //write configuration
385  FD_DHV("xDevice("<<mName<<")::DoWrite(): "<<mDeviceNames.at(i));
386  (mDevices.at(i))->Write(rTw);
387  }
388  }
389  rTw.WriteEnd("Devices");
390 }
391 
392 
393 // ResetRequest()
395  bool res=false;
396  Iterator dit;
397  for(dit=Begin();dit!=End();dit++){
398  res = res | (*dit)->ResetRequest();
399  }
400  return res;
401 }
402 
403 //DoRead(rTr,rLabel)
404 void xDevice::DoReadConfiguration(TokenReader& rTr, const std::string& rLabel, const Type* pContext) {
405  (void) rLabel; (void) pContext;
406 
407  FD_DHV("xDevice("<<mName<<")::DoReadConfiguration()");
408  //prepare token
409  Token token;
410  //prepare string
411  std::string filename = ""; //to store filename
412  std::string dirname = ""; //to store directory
413  std::string path; //to store absolut path
414  // have default section
415  std::string label = rLabel;
416  if(label=="") label = "Devices";
417  // read begin
418  rTr.ReadBegin(label);
419  // fill mDevices with devices specified in given file
420  while(!rTr.Eos("Devices")){
421  //peek token
422  rTr.Peek(token);
423  // if Token is a String we assume its the name of a file containing a device
424  if(token.Type()==Token::String) {
425  //read Token
426  rTr.Get(token);
427  //import filename
428  filename = token.StringValue();
429  //build up path to base-file
430  if(rTr.SourceMode()==TokenReader::File) dirname = ExtractDirectory(rTr.FileName());
431  //build up path to specified file
432  path = dirname.append(filename);
433  //insert device
434  Insert(path);
435  continue;
436  }
437  // if its not a file it has to be a device
438  else if(token.Type()==Token::Begin) {
439  // read device
440  vDevice* devp = vDevice::FromTokenReader(rTr);
441  // insert device mDevices
442  Insert(devp);
443  //record that this device was read inline
444  mDeviceNames.push_back("");
445  }
446  }
447  rTr.ReadEnd(label);
448 }
449 
450 
451 // WriteOutput(Idx)
453  FD_DHV("xDevice("<<mName<<")::WriteOutput()");
454  // identify corresponding device(if idx is unique)
455  int didx = mOutputToDevice[output];
456  FD_DH("xDevice("<<mName<<")::WriteOutput(): " << output << " to " << didx);
457  mDevices.at(didx)->WriteOutput(output);
458 }
459 
460 
461 // FlusgBufferes()
463  // iterate over all participating devices
464  for(Iterator dit=Begin(); dit!=End(); dit++)
465  (*dit)->FlushOutputs();
466 }
467 
468 
469 
470 } // name space
471 
472 

libFAUDES 2.24g --- 2014.09.15 --- c++ api documentaion by doxygen