SopasBase.cpp
Go to the documentation of this file.
1 //
2 // SopasBase.cpp
3 //
4 // Created on: 18.07.2011
5 // Author: sick
6 //
7 
8 #include "SopasBase.hpp"
9 
10 
11 #include "../manager.hpp"
12 #include "../tools/errorhandler.hpp"
13 #include "../tools/toolbox.hpp"
14 #include "../tools/Mutex.hpp"
15 
16 namespace devices
17 {
18 
19 #define SOPASBASE_VERSION "1.0.0"
20 
21 const std::string SopasBase::EVENTNAME_SUBSCRIBE_EVALCASES("LFErec");
22 const std::string SopasBase::EVENTNAME_SUBSCRIBE_SCANS("LMDscandata");
23 const std::string SopasBase::METHODNAME_LOGIN("SetAccessMode");
24 const std::string SopasBase::METHODNAME_LOGOUT("Run");
25 const std::string SopasBase::METHODNAME_SET_SCANCONFIG("mLMPsetscancfg");
26 const std::string SopasBase::METHODNAME_START_MEASURE("LMCstartmeas");
27 const std::string SopasBase::METHODNAME_STOP_MEASURE("LMCstopmeas");
28 const std::string SopasBase::VARIABLENAME_SCANCONFIG("LMPscancfg");
29 const std::string SopasBase::VARIABLENAME_DATAOUTPUTRANGE("LMPoutputRange");
30 const std::string SopasBase::VARIABLENAME_SCANDATACONFIG("LMDscandatacfg");
31 const std::string SopasBase::VARIABLENAME_DEVICEIDENT("DeviceIdent");
32 
33 // sopas commands
34 const std::string SopasBase::COMMAND_Read_Variable_ByIndex("RI");
35 const std::string SopasBase::COMMAND_Write_Variable_ByIndex("WI");
36 const std::string SopasBase::COMMAND_Invoke_Method_ByIndex("MI");
37 const std::string SopasBase::COMMAND_Method_Result_ByIndex("AI");
38 const std::string SopasBase::COMMAND_Register_Event_ByIndex("EI");
39 const std::string SopasBase::COMMAND_Send_Event_ByIndex("SI"); // receive data event
40 
41 const std::string SopasBase::COMMAND_Read_Variable_Answer("RA");
42 const std::string SopasBase::COMMAND_Write_Variable_Answer("WA");
43 const std::string SopasBase::COMMAND_Invoke_Method_Answer("MA");
44 const std::string SopasBase::COMMAND_Method_Result_Answer("AA");
45 const std::string SopasBase::COMMAND_Register_Event_Answer("EA");
46 const std::string SopasBase::COMMAND_Event_Acknowledge("SA");
47 
48 const std::string SopasBase::COMMAND_Read_Variable_ByName("RN");
49 const std::string SopasBase::COMMAND_Write_Variable_ByName("WN");
50 const std::string SopasBase::COMMAND_Invoke_Method_ByName("MN");
51 const std::string SopasBase::COMMAND_Method_Result_ByName("AN");
52 const std::string SopasBase::COMMAND_Register_Event_ByName("EN");
53 const std::string SopasBase::COMMAND_Send_Event_ByName("SN"); // receive data event
54 
56 
57 
58 
60  m_state(CONSTRUCTED)
61 {
62  m_beVerbose = false;
63 
64  m_protocol = CoLa_A; // Default protocol is CoLa-A
65 }
66 
67 
68 
70 {
71  printInfoMessage("Sopas device destructor: Running.", m_beVerbose);
72 
73  // Derived device must be stopped in it's constructor. No virtual functions may be called here!
74 // assert(isRunning() == false);
75 
76  printInfoMessage("Sopas device destructor: Stopped, now disconnecting.", m_beVerbose);
77 
78  // Disconnect and shut down receive thread.
79  if (isConnected() == true)
80  {
81  // Change from CONNECTED to CONSTRUCTED
82  disconnect();
83  }
84 
85 // printInfoMessage("Sopas device destructor: Disconnected, now deleting socket.", m_beVerbose);
86 
87  printInfoMessage("Sopas device destructor: Done, device is deleted.", m_beVerbose);
88 }
89 
90 
91 
92 //
93 // Initialisation from Scanner class:
94 // Parameter setup only. Afterwards, call connect() to connect to the scanner.
95 //
97  std::string ipAddress,
98  UINT16 portNumber,
99  bool weWantScanData,
100  bool weWantFieldData,
101  bool readOnlyMode,
102  Tcp::DisconnectFunction disconnectFunction,
103  void* obj)
104 {
105  m_protocol = protocol;
106  m_ipAddress = ipAddress;
107  m_portNumber = portNumber;
108  m_weWantScanData = weWantScanData;
109  m_weWantFieldData = weWantFieldData;
110  setReadOnlyMode(readOnlyMode);
111 
112  m_tcp.setDisconnectCallbackFunction(disconnectFunction, obj);
113 
114  return true;
115 }
116 
117 
118 //
119 // Verbinde mit dem unter init() eingestellten Geraet, und pruefe die Verbindung
120 // durch einen DeviceIdent-Aufruf.
121 //
122 // true = Erfolgreich.
123 //
125 {
126  printInfoMessage("SopasBase::connect: Called.", m_beVerbose);
127 
128  assert (m_state == CONSTRUCTED); // must not be opened or running already
129 
130  // Initialise buffer variables
131  m_numberOfBytesInReceiveBuffer = 0; // Buffer is empty
132  m_numberOfBytesInResponseBuffer = 0; // Buffer is empty
133  // m_isLoggedIn = false;
134  m_scannerName = "";
135  m_scannerVersion = "";
136 
137  // Establish connection here
138  // Set the data input callback for our TCP connection
140 
141  bool success = openTcpConnection();
142  if (success == true)
143  {
144  // Check if scanner type matches
145  m_state = CONNECTED;
146  printInfoMessage("SopasBase::connect: Reading scanner infos", m_beVerbose);
148 
149  if (success == true)
150  {
151  printInfoMessage("SopasBase::connect: Initialisation was successful.", m_beVerbose);
152  }
153  else
154  {
155  printError("SopasBase::connect: Failed to read scanner type and version.");
156  }
157  }
158 
159  if (success == false)
160  {
161  printWarning("SopasBase::connect: Initialisation failed!");
162  }
163  else
164  {
165  // Here, we could unsubscribe all events to have a defined default state.
166  }
167 
168  printInfoMessage("SopasBase::connect: Done.", m_beVerbose);
169  return success;
170 }
171 
172 
173 
174 //
175 // True, if state is CONNECTED, that is:
176 // - A TCP-connection exists
177 // - Read thread is running
178 //
180 {
181  return (m_state == CONNECTED);
182 }
183 
184 //
185 // Disconnect from the scanner, and close the interface.
186 //
188 {
190 
191  // Change back to CONSTRUCTED
193  return true;
194 }
195 
196 
197 
198 //
199 // (Un)set read only mode. Setting this mode, the sensor will ignore commands which will change any
200 // parameters on the device. The sensor itself will execute such commands.
201 //
203 {
204  m_readOnlyMode = mode;
205 }
206 
207 
208 
210 {
211  return m_readOnlyMode;
212 }
213 
214 
215 
222 {
223  printInfoMessage("SopasBase::openTcpConnection: Connecting TCP/IP connection to " + m_ipAddress + ":" + toString(m_portNumber) + " ...", m_beVerbose);
224 
225  bool success = m_tcp.open(m_ipAddress, m_portNumber, m_beVerbose);
226  if (success == false)
227  {
228  printError("SopasBase::openTcpConnection: ERROR: Failed to establish TCP connection, aborting!");
229  return false;
230  }
231 
232  return true;
233 }
234 
235 
236 
237 //
238 // Close TCP-connection and shut down read thread
239 //
241 {
242  if (m_tcp.isOpen())
243  {
244  m_tcp.close();
245  }
246 }
247 
248 //
249 // Static entry point.
250 //
251 void SopasBase::readCallbackFunctionS(void* obj, UINT8* buffer, UINT32& numOfBytes)
252 {
253  ((SopasBase*)obj)->readCallbackFunction(buffer, numOfBytes);
254 }
255 
256 
261 void SopasBase::readCallbackFunction(UINT8* buffer, UINT32& numOfBytes)
262 {
263  bool beVerboseHere = false;
264  printInfoMessage("SopasBase::readCallbackFunction(): Called with " + toString(numOfBytes) + " available bytes.", beVerboseHere);
265 
266  ScopedLock lock(&m_receiveDataMutex); // Mutex for access to the input buffer
267  UINT32 remainingSpace = sizeof(m_receiveBuffer) - m_numberOfBytesInReceiveBuffer;
268  UINT32 bytesToBeTransferred = numOfBytes;
269  if (remainingSpace < numOfBytes)
270  {
271  bytesToBeTransferred = remainingSpace;
272  printWarning("SopasBase::readCallbackFunction(): Input buffer space is to small, transferring only " +
273  ::toString(bytesToBeTransferred) + " of " + ::toString(numOfBytes) + " bytes.");
274  }
275  else
276  {
277  printInfoMessage("SopasBase::readCallbackFunction(): Transferring " + ::toString(bytesToBeTransferred) +
278  " bytes from TCP to input buffer.", beVerboseHere);
279  }
280 
281  if (bytesToBeTransferred > 0)
282  {
283  // Data can be transferred into our input buffer
284  memcpy(&(m_receiveBuffer[m_numberOfBytesInReceiveBuffer]), buffer, bytesToBeTransferred);
285  m_numberOfBytesInReceiveBuffer += bytesToBeTransferred;
286 
287  UINT32 size = 0;
288 
289  while (1)
290  {
291  // Now work on the input buffer until all received datasets are processed
293 
294  size = frame.size();
295  if (size == 0)
296  {
297  // Framesize = 0: There is no valid frame in the buffer. The buffer is either empty or the frame
298  // is incomplete, so leave the loop
299  printInfoMessage("SopasBase::readCallbackFunction(): No complete frame in input buffer, we are done.", beVerboseHere);
300 
301  // Leave the loop
302  break;
303  }
304  else
305  {
306  // A frame was found in the buffer, so process it now.
307  printInfoMessage("SopasBase::readCallbackFunction(): Processing a frame of length " + ::toString(frame.size()) + " bytes.", beVerboseHere);
308  processFrame(frame);
309  }
310  }
311  }
312  else
313  {
314  // There was input data from the TCP interface, but our input buffer was unable to hold a single byte.
315  // Either we have not read data from our buffer for a long time, or something has gone wrong. To re-sync,
316  // we clear the input buffer here.
318  }
319 
320  printInfoMessage("SopasBase::readCallbackFunction(): Leaving. Current input buffer fill level is " +
321  ::toString(m_numberOfBytesInReceiveBuffer) + " bytes.", beVerboseHere);
322 }
323 
324 
325 
326 //
327 // Look for 23-frame (STX/ETX) in receive buffer.
328 // Move frame to start of buffer
329 //
330 // Return: 0 : No (complete) frame found
331 // >0 : Frame length
332 //
334 {
335  UINT32 frameLen = 0;
336  UINT32 i;
337 
338  // Depends on protocol...
339  if (m_protocol == CoLa_A)
340  {
341  //
342  // COLA-A
343  //
344  // Must start with STX (0x02)
345  if (m_receiveBuffer[0] != 0x02)
346  {
347  // Look for starting STX (0x02)
348  for (i = 1; i < m_numberOfBytesInReceiveBuffer; i++)
349  {
350  if (m_receiveBuffer[i] == 0x02)
351  {
352  break;
353  }
354  }
355 
356  // Found beginning of frame?
357  if (i >= m_numberOfBytesInReceiveBuffer)
358  {
359  // No start found, everything can be discarded
360  m_numberOfBytesInReceiveBuffer = 0; // Invalidate buffer
361  return SopasEventMessage(); // No frame found
362  }
363 
364  // Move frame start to index 0
365  UINT32 newLen = m_numberOfBytesInReceiveBuffer - i;
366  memmove(&(m_receiveBuffer[0]), &(m_receiveBuffer[i]), newLen);
367  m_numberOfBytesInReceiveBuffer = newLen;
368  }
369 
370  // Look for ending ETX (0x03)
371  for (i = 1; i < m_numberOfBytesInReceiveBuffer; i++)
372  {
373  if (m_receiveBuffer[i] == 0x03)
374  {
375  break;
376  }
377  }
378 
379  // Found end?
380  if (i >= m_numberOfBytesInReceiveBuffer)
381  {
382  // No end marker found, so it's not a complete frame (yet)
383  return SopasEventMessage(); // No frame found
384  }
385 
386  // Calculate frame length in byte
387  frameLen = i + 1;
388 
389  return SopasEventMessage(m_receiveBuffer, CoLa_A, frameLen);
390  }
391  else if (m_protocol == CoLa_B)
392  {
393  UINT32 magicWord;
394  UINT32 payloadlength;
395 
397  {
398  return SopasEventMessage();
399  }
400  UINT16 pos = 0;
401  magicWord = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
402  if (magicWord != 0x02020202)
403  {
404  // Look for starting STX (0x02020202)
405  for (i = 1; i <= m_numberOfBytesInReceiveBuffer - 4; i++)
406  {
407  pos = i; // this is needed, as the position value is updated by getIntegerFromBuffer
408  magicWord = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
409  if (magicWord == 0x02020202)
410  {
411  // found magic word
412  break;
413  }
414  }
415 
416  // Found beginning of frame?
417  if (i > m_numberOfBytesInReceiveBuffer - 4)
418  {
419  // No start found, everything can be discarded
420  m_numberOfBytesInReceiveBuffer = 0; // Invalidate buffer
421  return SopasEventMessage(); // No frame found
422  }
423  else
424  {
425  // Move frame start to index
426  UINT32 bytesToMove = m_numberOfBytesInReceiveBuffer - i;
427  memmove(&(m_receiveBuffer[0]), &(m_receiveBuffer[i]), bytesToMove); // payload+magic+length+s+checksum
428  m_numberOfBytesInReceiveBuffer = bytesToMove;
429  }
430  }
431 
432  // Pruefe Laenge des Pufferinhalts
434  {
435  // Es sind nicht genug Daten fuer einen Frame
436  printInfoMessage("SopasBase::findFrameInReceiveBuffer: Frame cannot be decoded yet, only " +
437  ::toString(m_numberOfBytesInReceiveBuffer) + " bytes in the buffer.", m_beVerbose);
438  return SopasEventMessage();
439  }
440 
441  // Read length of payload
442  pos = 4;
443  payloadlength = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
444  printInfoMessage("SopasBase::findFrameInReceiveBuffer: Decoded payload length is " + ::toString(payloadlength) + " bytes.", m_beVerbose);
445 
446  // Ist die Datenlaenge plausibel und wuede in den Puffer passen?
447  if (payloadlength > (sizeof(m_receiveBuffer) - 9))
448  {
449  // magic word + length + checksum = 9
450  printWarning("SopasBase::findFrameInReceiveBuffer: Frame too big for receive buffer. Frame discarded with length:"
451  + ::toString(payloadlength) + ".");
453  return SopasEventMessage();
454  }
455  if ((payloadlength + 9) > m_numberOfBytesInReceiveBuffer)
456  {
457  // magic word + length + s + checksum = 10
458  printInfoMessage("SopasBase::findFrameInReceiveBuffer: Frame not complete yet. Waiting for the rest of it (" +
459  ::toString(payloadlength + 9 - m_numberOfBytesInReceiveBuffer) + " bytes missing).", m_beVerbose);
460  return SopasEventMessage(); // frame not complete
461  }
462 
463  // Calculate the total frame length in bytes: Len = Frame (9 bytes) + Payload
464  frameLen = payloadlength + 9;
465 
466  //
467  // test checksum of payload
468  //
469  UINT8 temp = 0;
470  UINT8 temp_xor = 0;
471  UINT8 checkSum;
472 
473  // Read original checksum
474  pos = frameLen - 1;
475  checkSum = colab::getIntegerFromBuffer<UINT8>(m_receiveBuffer, pos);
476 
477  // Erzeuge die Pruefsumme zum Vergleich
478  for (UINT16 i = 8; i < (frameLen - 1); i++)
479  {
480  pos = i;
481  temp = colab::getIntegerFromBuffer<UINT8>(m_receiveBuffer, pos);
482  temp_xor = temp_xor ^ temp;
483  }
484 
485  // Vergleiche die Pruefsummen
486  if (temp_xor != checkSum)
487  {
488  printWarning("SopasBase::findFrameInReceiveBuffer: Wrong checksum, Frame discarded.");
490  return SopasEventMessage();
491  }
492 
493  return SopasEventMessage(m_receiveBuffer, CoLa_B, frameLen);
494  }
495 
496  // Return empty frame
497  return SopasEventMessage();
498 }
499 
500 
501 
508 {
509  UINT8 sendBuffer[1024];
510 
511  assert (len < 1000);
512  assert (m_tcp.isOpen() == true);
513 
514  // Frame the string
515  if (m_protocol == CoLa_A)
516  {
517  colaa::addFrameToBuffer(sendBuffer, buffer, &len);
518  }
519  else if (m_protocol == CoLa_B)
520  {
521  colab::addFrameToBuffer(sendBuffer, buffer, &len);
522  }
523 
524  // Debug: Print buffer
525 // traceBuffer("Cmd buffer contents:", sendBuffer, len);
526 
527  // Send command (blocking)
528  m_tcp.write(sendBuffer, len);
529 }
530 
531 
532 
541 bool SopasBase::receiveAnswer(SopasCommand cmd, std::string name, UINT32 timeout, SopasAnswer*& answer)
542 {
543  switch (m_protocol)
544  {
545  case CoLa_A:
546  printInfoMessage("SopasBase::receiveAnswer: calling receiveAnswer_CoLa_A.", m_beVerbose);
547  return receiveAnswer_CoLa_A(cmd, name, timeout, answer);
548  case CoLa_B:
549  printInfoMessage("SopasBase::receiveAnswer: calling receiveAnswer_CoLa_B.", m_beVerbose);
550  return receiveAnswer_CoLa_B(cmd, name, timeout, answer);
551  default:
552  printWarning("SopasBase::receiveAnswer: Wrong protocol (is either not CoLa-A or CoLa-B).");
553  }
554 
555  return false;
556 }
557 
558 
559 
568 bool SopasBase::receiveAnswer(SopasCommand cmd, UINT16 index, UINT32 timeout, SopasAnswer*& answer)
569 {
570  switch (m_protocol)
571  {
572  case CoLa_A:
573  printInfoMessage("SopasBase::receiveAnswer: Calling receiveAnswer_CoLa_A.", m_beVerbose);
574  return receiveAnswer_CoLa_A(cmd, index, timeout, answer);
575  case CoLa_B:
576  printInfoMessage("SopasBase::receiveAnswer: Calling receiveAnswer_CoLa_B.", m_beVerbose);
577  return receiveAnswer_CoLa_B(cmd, index, timeout, answer);
578  default:
579  printWarning("SopasBase::receiveAnswer: Wrong protocol (is either not CoLa-A or CoLa-B).");
580  }
581 
582  return false;
583 }
584 
585 
586 //
587 //
588 //
590 {
591  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: entering function.", m_beVerbose);
592 
593  SopasCommand receivedCommand;
594  std::string rxData;
595  if (timeout == 0)
596  {
597  timeout = 1; // Check at least once
598  }
599 
600  // Check until number of cycles reaches timeout
601  for (UINT32 i = 0; i < timeout; i++)
602  {
603  // Secure against read thread
604  {
607  {
608  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: Response received (len= " +
610  " bytes).", m_beVerbose);
612  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
613  }
614  }
615 
616  if (rxData.length() > 0)
617  {
618  // Decode data
619  receivedCommand = colaA_decodeCommand(&rxData);
620 
621  if (cmd == receivedCommand)
622  {
623 
624  // Set variable answer
625  if (receivedCommand == WA)
626  {
627  // Answer contains variable index only and informs about success.
628  return true;
629  }
630 
631  UINT16 receivedIndex = colaa::decodeUINT16(&rxData); // by name
632 
633  if (receivedIndex == index)
634  {
635  // Answer to Read Variable or invoke method?
636  if (cmd == RA || cmd == AN)
637  {
638  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: *** receive answer with data in return *** ", m_beVerbose);
639 
640  answer = new SopasAnswer((BYTE*)rxData.c_str(), rxData.length());
641  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
642  return true;
643  }
644  else if (receivedCommand == EA)
645  {
646  // Antwort auf Event-Abonnement setzen/loeschen.
647  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: Event (by index) successfully (un)registered: " +
648  ::toString(receivedIndex) + ".", m_beVerbose);
649 
651  return true;
652  }
653  }
654  else
655  {
656  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: This is not the answer we are waiting for. ", m_beVerbose);
657  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
658  }
659  }
660  // Error answer
661  else if (receivedCommand == FA)
662  {
663  printInfoMessage("SopasBase::Error answer received: FA " + rxData + ".", m_beVerbose);
664  answer = new SopasAnswer((BYTE*)rxData.c_str(), rxData.length());
665  return false;
666  }
667  else
668  {
669  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: This is not the answer we are waiting for. ", m_beVerbose);
670  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
671  rxData.clear();
672  }
673  }
674  else
675  {
676  // No data in response buffer. Sleep some time and check again
677  usleep(1000);
678  }
679  }
680 
681  // Not successful, timeout.
682  return false;
683 }
684 
685 
686 
687 bool SopasBase::receiveAnswer_CoLa_A(SopasCommand cmd, std::string name, UINT32 timeout, SopasAnswer*& answer)
688 {
689  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: entering function.", m_beVerbose);
690 
691  SopasCommand receivedCommand;
692  std::string rxData;
693  if (timeout == 0)
694  {
695  timeout = 1; // Check at least once
696  }
697 
698  // Check until number of cycles reaches timeout
699  for (UINT32 i = 0; i < timeout; i++)
700  {
701  // Secure against read thread
702  {
705  {
706  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: Response received (len= " +
709  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
710  }
711  }
712 
713  if (rxData.length() > 0)
714  {
715  // Decode data
716  receivedCommand = colaA_decodeCommand(&rxData);
717 
718  if (cmd == receivedCommand)
719  {
720 
721  // Set variable answer
722  if (receivedCommand == WA)
723  {
724  // Answer contains variable index only and informs about success.
725  return true;
726  }
727 
728  std::string receivedName = colaa::decodeString(&rxData); // by name
729 
730  if (receivedName == name)
731  {
732  // Answer to Read Variable or invoke method?
733  if (cmd == RA || cmd == AN)
734  {
735  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: *** receive answer with data in return *** ", m_beVerbose);
736 
737  answer = new SopasAnswer((BYTE*)rxData.c_str(), rxData.length());
738  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
739  return true;
740  }
741  else if (receivedCommand == EA)
742  {
743  // Antwort auf Event-Abonnement setzen/loeschen.
744 
745  printInfoMessage("SopasBase:: Event successfully (un)registered: " + receivedName + ".", m_beVerbose);
747  return true;
748  }
749  }
750  else
751  {
752  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: This is not the answer we are waiting for.", m_beVerbose);
753  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
754  }
755  }
756  // Error answer
757  else if (receivedCommand == FA)
758  {
759  printInfoMessage("SopasBase:: Error answer received: FA " + rxData + ".", true);
760  answer = new SopasAnswer((BYTE*)rxData.c_str(), rxData.length());
761  return false;
762  }
763  else
764  {
765  printInfoMessage("SopasBase::receiveAnswer_CoLa_A: This is not the answer we are waiting for.", m_beVerbose);
766  m_numberOfBytesInResponseBuffer = 0; // Clear buffer
767  rxData.clear();
768  }
769  }
770  else
771  {
772  // No data in response buffer. Sleep some time and check again
773  usleep(1000);
774  }
775  }
776 
777  // Not successful, timeout.
778  return false;
779 }
780 
781 
782 
783 bool SopasBase::receiveAnswer_CoLa_B(SopasCommand cmd, std::string name, UINT32 timeout, SopasAnswer*& answer)
784 {
785  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Entering function.", m_beVerbose);
786 
787  SopasCommand receivedCommand;
788  UINT16 nextData;
789  std::string receivedName;
790 
791  if (timeout == 0)
792  {
793  timeout = 1; // Check at least once
794  }
795 
796  // Check until number of cycles reaches timeout
797  for (UINT32 i = 0; i < timeout; i++)
798  {
800  {
801 // if (m_beVerbose)
802 // {
803 // printInfoMessage("SopasBase::receiveAnswer_CoLa_B: There is something in receive buffer." << std::endl;
804 // }
805 
806  // protect response buffer
808 
809  // there are only complete frames in response buffer
811 
812  // Parse Sopas Kommando
813  // receivedCommand = stringToSopasCommand(colab::getCommandStringFromBuffer(m_responseBuffer));
814  receivedCommand = stringToSopasCommand(frame.getCommandString());
815 
816  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: receivedCommand= " + frame.getCommandString() + ".", m_beVerbose);
817 
818  if (receivedCommand == FA)
819  {
820  // Fehlermeldung vom Sensor
821  nextData = 0;
822  UINT16 errorCode = colab::getIntegerFromBuffer<UINT16>(&(m_responseBuffer[11]), nextData);
823  printWarning("SopasBase::receiveAnswer_CoLa_B: Error from sensor! Code=" + toString(errorCode) +
824  ", meaning: " + convertSopasErrorCodeToText(errorCode) + ".");
826  return false;
827  }
828 
829  if (cmd != receivedCommand)
830  {
831  // Nicht die gesuchte Antwort
832  // da der sensor über sopas immer nur eine anfrage zur zeit bedienen kann, koennen wir die
833  // Nachricht wegwerfen
834  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: This is not the answer (" + sopasCommandToString(receivedCommand) + ") are waiting for ("
835  + sopasCommandToString(cmd) + ").", m_beVerbose);
837  return false;
838  }
839 
840  // UINT16 nameLength = colab::getIntegerFromBuffer<UINT16>(m_responseBuffer, nextData);
841  // receivedName = colab::getStringFromBuffer(m_responseBuffer, nextData);
842 
843  receivedName = colab::getIdentifierFromBuffer(m_responseBuffer, nextData, sizeof(m_responseBuffer));
844 
845  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: receicedName= " + receivedName + ".", m_beVerbose);
846 
847  if (name != receivedName)
848  {
849  // Nicht die gesuchte Antwort
850  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: This is not the answer we are waiting for. (" + frame.getCommandString() +
851  ", " + name + ").", m_beVerbose);
852 
854  return false;
855  }
856 
857  if (receivedCommand == WA)
858  {
859  // Variable schreiben erfolgreich
860  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Variable successfully set.", m_beVerbose);
862  return true;
863  }
864 
865  else if (receivedCommand == EA)
866  {
867  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Answer to (un)subscribe event " + receivedName + ".", m_beVerbose);
869  return true;
870  }
871  // Antwort auf Methode ByName
872  else if (receivedCommand == AN )
873  {
874  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Answer to method call " + receivedName + ".", m_beVerbose);
875  answer = new SopasAnswer(&m_responseBuffer[nextData], m_numberOfBytesInResponseBuffer - nextData);
877  return true;
878  }
879  else if (receivedCommand == RA)
880  {
881  // Antwort auf das Lesen einer Variablen
882  answer = new SopasAnswer(&m_responseBuffer[nextData], m_numberOfBytesInResponseBuffer - nextData);
884  return true;
885  }
886 
887  else if (receivedCommand == CMD_UNKNOWN)
888  {
889  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Unkown Sopas command.", true);
891  return false;
892  }
893  else
894  {
895  // unbekannter oder unbehandelter Befehl
896  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Untreated Sopas command.", m_beVerbose);
898  return false;
899  }
900 
901  }
902  else
903  {
904  // No data in response buffer. Sleep some time and check again
905  usleep(1000);
906  }
907  }
908 
909  // Not successful, timeout.
910  printInfoMessage("SopasBase::receiveAnswer_CoLa_B: Leaving with timeout.", m_beVerbose);
911 
912  return false;
913 }
914 
915 //
916 // Convert a Sopas error code to readable text.
917 //
919 {
920  switch (errorCode)
921  {
922  case 0:
923  return "Sopas_Ok";
924  case 1:
925  return "Sopas_Error_METHODIN_ACCESSDENIED";
926  case 2:
927  return "Sopas_Error_METHODIN_UNKNOWNINDEX";
928  case 3:
929  return "Sopas_Error_VARIABLE_UNKNOWNINDEX";
930  case 4:
931  return "Sopas_Error_LOCALCONDITIONFAILED";
932  case 5:
933  return "Sopas_Error_INVALID_DATA";
934  case 6:
935  return "Sopas_Error_UNKNOWN_ERROR";
936  case 7:
937  return "Sopas_Error_BUFFER_OVERFLOW";
938  case 8:
939  return "Sopas_Error_BUFFER_UNDERFLOW";
940  case 9:
941  return "Sopas_Error_ERROR_UNKNOWN_TYPE";
942  case 10:
943  return "Sopas_Error_VARIABLE_WRITE_ACCESSDENIED";
944  case 11:
945  return "Sopas_Error_UNKNOWN_CMD_FOR_NAMESERVER";
946  case 12:
947  return "Sopas_Error_UNKNOWN_COLA_COMMAND";
948  case 13:
949  return "Sopas_Error_METHODIN_SERVER_BUSY";
950  case 14:
951  return "Sopas_Error_FLEX_OUT_OF_BOUNDS";
952  case 15:
953  return "Sopas_Error_EVENTREG_UNKNOWNINDEX";
954  case 16:
955  return "Sopas_Error_COLA_A_VALUE_OVERFLOW";
956  case 17:
957  return "Sopas_Error_COLA_A_INVALID_CHARACTER";
958  case 18:
959  return "Sopas_Error_OSAI_NO_MESSAGE";
960  case 19:
961  return "Sopas_Error_OSAI_NO_ANSWER_MESSAGE";
962  case 20:
963  return "Sopas_Error_INTERNAL";
964  case 21:
965  return "Sopas_Error_HubAddressCorrupted";
966  case 22:
967  return "Sopas_Error_HubAddressDecoding";
968  case 23:
969  return "Sopas_Error_HubAddressAddressExceeded";
970  case 24:
971  return "Sopas_Error_HubAddressBlankExpected";
972  case 0x19:
973  return "Sopas_Error_AsyncMethodsAreSuppressed";
974  case 0x20:
975  return "Sopas_Error_ComplexArraysNotSupported";
976  default:
977  return "(unknown_Sopas_error_code)";
978  }
979 
980  return "(unknown_Sopas_error_code)";
981 }
982 
983 //
984 // Decode an incoming CoLa-B answer that was addressed by index.
985 //
987 {
988  bool beVerboseHere = m_beVerbose;
989 // beVerboseHere = true;
990 
991  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Entering function.", beVerboseHere);
992 
993  SopasCommand receivedCommand;
994  UINT16 nextData;
995 
996  if (timeout == 0)
997  {
998  timeout = 1; // Check at least once
999  }
1000 
1001  // Check until number of cycles reaches timeout
1002  for (UINT32 i = 0; i < timeout; i++)
1003  {
1005  {
1006  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: There is something in receive buffer.", beVerboseHere);
1007 
1008  // Protect response buffer
1010 
1011  // There are only complete frames in response buffer, so we can just use it here.
1012  // Debug: Print buffer
1013 // traceBuffer("Response in response buffer:", m_responseBuffer, m_numberOfBytesInResponseBuffer);
1015 
1016  // Parse Sopas Kommando
1017  receivedCommand = stringToSopasCommand(frame.getCommandString());
1018 
1019  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: ReceivedCommand= " + frame.getCommandString() + ".", beVerboseHere);
1020 
1021  nextData = 11; // without 0x02020202 + length(4 byte) + "sXX"
1022  UINT16 receivedIndex = colab::getIntegerFromBuffer<UINT16>(m_responseBuffer, nextData);
1023 // printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: read command " + frame.getCommandString() + ".", beVerboseHere);
1024  if (receivedCommand == FA)
1025  {
1026  // Error message from the sensor. The next 2 bytes (in the receiveIndex) are not
1027  // the index but the error code.
1028  printWarning("SopasBase::receiveAnswer_CoLa_B_idx: Error from sensor! Code=" + toString(receivedIndex) +
1029  ", meaning: " + convertSopasErrorCodeToText(receivedIndex) + ".");
1031  return false;
1032  }
1033 
1034  else if (index != receivedIndex)
1035  {
1036  // Nicht die gesuchte Antwort
1037  // da der sensor über sopas immer nur eine anfrage zur zeit bedienen kann, koennen wir die
1038  // Nachricht wegwerfen
1039  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: This is not the index we are waiting for (expected="
1040  + toString(index) + ", received=" + toString(receivedIndex) + ")." , beVerboseHere);
1042  return false;
1043  }
1044 
1045  else if (cmd != receivedCommand)
1046  {
1047  // Not the desired answer.
1048  // As the sensor can only handle one command at a time on the SOPAS interface, we can discard the message.
1049  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: This is not the answer (" + sopasCommandToString(receivedCommand) +
1050  ") we are waiting for (" + sopasCommandToString(cmd) + "). ", beVerboseHere);
1052  return false;
1053  }
1054 
1055  else if (receivedCommand == WA)
1056  {
1057  // Variable schreiben erfolgreich
1058  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Variable successfully set.", beVerboseHere);
1060  return true;
1061  }
1062 
1063  else if (receivedCommand == EA)
1064  {
1065  // Antwort auf Event-Abonnement setzen/loeschen.
1066  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Event successfully (un)registered: " + ::toString(receivedIndex) + ".", beVerboseHere);
1068  return true;
1069  }
1070 
1071  else if (receivedCommand == AI )
1072  {
1073  // Antwort auf entfernten Methodenaufruf (by name oder by index).
1074  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Answer to method call with index " + ::toString(receivedIndex) + ".", beVerboseHere);
1075  answer = new SopasAnswer(&m_responseBuffer[nextData], m_numberOfBytesInResponseBuffer - nextData);
1077  return true;
1078  }
1079 
1080  else if (receivedCommand == RA)
1081  {
1082  // Antwort auf das Lesen einer Variablen
1083  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Answer to read variable with index " + ::toString(receivedIndex) + ".", beVerboseHere);
1084 
1085  answer = new SopasAnswer(&m_responseBuffer[nextData], m_numberOfBytesInResponseBuffer - nextData);
1087  return true;
1088  }
1089 
1090  else if (receivedCommand == CMD_UNKNOWN)
1091  {
1092  printWarning("SopasBase::receiveAnswer_CoLa_B_idx: Unknown Sopas command.");
1094  return false;
1095  }
1096  else
1097  {
1098  // unbekannter oder unbehandelter Befehl
1099  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Untreated Sopas command.", beVerboseHere);
1101  return false;
1102  }
1103  }
1104  else
1105  {
1106  // No data in response buffer. Sleep some time and check again
1107  usleep(1000);
1108  }
1109  }
1110 
1111  // Not successful, timeout.
1112  printInfoMessage("SopasBase::receiveAnswer_CoLa_B_idx: Leaving with timeout.", beVerboseHere);
1113 
1114  // Not successful, timeout.
1115  return false;
1116 }
1117 
1118 
1119 
1126 {
1127 
1128  if (m_protocol == CoLa_A)
1129  {
1130  printInfoMessage("SopasBase::processFrame: Calling processFrame_CoLa_A() with " + ::toString(frame.size()) + " bytes.", m_beVerbose);
1131  processFrame_CoLa_A(frame);
1132  }
1133  else if (m_protocol == CoLa_B)
1134  {
1135  printInfoMessage("SopasBase::processFrame: Calling processFrame_CoLa_B() with " + ::toString(frame.size()) + " bytes.", m_beVerbose);
1136  processFrame_CoLa_B(frame);
1137  }
1138 }
1139 
1140 
1141 
1142 //
1143 // Reads one frame from receive buffer and decodes it.
1144 //
1145 // CoLa-A protocol only.
1146 //
1148 {
1149  std::string command;
1150  command = m_receiveBuffer[2];
1151  command += m_receiveBuffer[3];
1152  assert (command.length() == 2);
1153 
1154  //
1155  // Process asynchronous event data directly.
1156  // Other commands are copied to separate buffer
1157  //
1158  if (frame.getMessageType() == MSG_SEND_EVENT)
1159  {
1160  if (frame.size() > 8)
1161  {
1162  // "SN" ist ein abonniertes Event, z.B. Scans oder Schutzfelder
1163  std::string eventName;
1164  UINT32 i = 5;// Pointer to the fist Letter of the event Name (without the first 5 bytes: "STX's''S''N'' '")
1165  while (m_receiveBuffer[i] != ' ' && i < frame.size() )
1166  {
1167  // go to the ' ' after the event Name
1168  i++;
1169  }
1170  eventName = std::string((char*) m_receiveBuffer, 5, i - 5); // get the event Name
1171 
1172  if (m_decoderFunctionMapByName[eventName] != NULL)
1173  {
1174  // Not empty
1175  m_decoderFunctionMapByName[eventName](frame);// call the callback of the Event
1176  }
1177  else
1178  {
1179  // Das Event ist unbekannt
1180  printWarning("SopasBase::Received an unknown event! Event name is: " + eventName + ".");
1181  }
1182 //
1183 // if (eventName == scanString) // Scan data (hopefully, event name not parsed yet...)
1184 // {
1185 // if (!m_decoderFunctionMapByName[eventName].empty())
1186 // {
1187 // m_scanDecoderFunction(frame);
1188 // }
1189 // else
1190 // {
1191 // printInfoMessage("SopasBase::no scan decoder registered - discarding data." << std::endl;
1192 // }
1193 // }
1194 // else if (eventName == fieldString) // eval case result data
1195 // {
1196 //
1197 // if (!m_evalCaseDecoderFunction.empty())
1198 // {
1199 // m_evalCaseDecoderFunction(frame);
1200 // }
1201 // else
1202 // {
1203 // printInfoMessage("SopasBase::no eval case decoder registered - discarding data." << std::endl;
1204 // }
1205 // }
1206 // else
1207 // { // Das Event ist unbekannt
1208 // printWarning("SopasBase::Received an unknown event! Short name is: " << eventName << "." << std::endl;
1209 // }
1210  }
1211  else
1212  {
1213  // Das Kommando ist insgesamt zu kurz zum dekodieren
1214  printWarning("SopasBase::Received a very short (and unknown) event! Frame length is " + ::toString(frame.size()) +
1215  " bytes.");
1216  }
1217  }
1218  else
1219  {
1220  // Copy frame to response buffer. Old contents are destroyed
1221  // boost::mutex::scoped_lock lock(m_receiveDataMutex);
1222  copyFrameToResposeBuffer(frame.size());
1223  }
1224 
1225  // Remove frame from receive buffer
1227 }
1228 
1229 
1230 
1231 //
1232 // Reads and decodes a frame from the receiveBuffer. Frame format is CoLa-B.
1233 //
1234 // Note that this function typically runs in TCP callback context, not the device thread.
1235 //
1237 {
1238  // Lese das "Kommando" aus
1239  std::string command = colab::getCommandStringFromBuffer(m_receiveBuffer);
1240 
1241  printInfoMessage("SopasBase::processFrame_CoLa_B: Command is " + command + ".", m_beVerbose);
1242 
1243  //
1244  // Process asynchronous event data directly.
1245  // Other commands are copied to separate buffer
1246  //
1247  bool frameWasProcessed = false;
1248  if (frame.getMessageType() == MSG_SEND_EVENT) // LDMRS: SI, LMS100: SN
1249  {
1250  if (frame.size() > 12)
1251  {
1252  // "SN" or "SI" is a registered event, e.g. Scans or Eval case results.
1253  // printInfoMessage("SopasBase::SN empfangen, Laenge = " << frameLength << "Bytes ." << std::endl;
1254  std::string eventName;
1255  UINT32 eventIndex = 0;
1256  UINT16 pos = 0;
1257 
1258  switch (frame.getEncodingType())
1259  {
1260  case ByIndex: // by index
1261  pos = 11;
1262  eventIndex = colab::getIntegerFromBuffer<UINT16>(m_receiveBuffer, pos);
1263  eventName = m_indexToNameMap[eventIndex];
1264 
1265  switch (eventIndex)
1266  {
1267  case 0x11: // SopasEventByIndex_LDMRS::index_event_ScanData:
1268  eventName = EVENTNAME_SUBSCRIBE_SCANS;
1269  scanDataDecoder(frame);
1270  frameWasProcessed = true;
1271  break;
1272  case 0x29: // SopasEventByIndex_LDMRS::index_event_aEvalCaseResult:
1273  eventName = EVENTNAME_SUBSCRIBE_EVALCASES;
1274  evalCaseResultDecoder(frame);
1275  frameWasProcessed = true;
1276  break;
1277  default:
1278  ;
1279  }
1280  break;
1281 
1282  default: // by name
1283  printWarning("SopasBase::processFrame_CoLa_B: Decoding of events by name is not implemented yet.");
1284  eventName = frame.getVariableName();
1285  break;
1286  }
1287 
1288  if (frameWasProcessed == false)
1289  {
1290  // The incoming event was not handeled
1291  printWarning("SopasBase::processFrame_CoLa_B: Don't know how to process the incoming event with the short name <" +
1292  eventName + "> and the index " + ::toString(eventIndex) + ", ignoring it!");
1293  }
1294  }
1295  else
1296  {
1297  // The frame was too short to be decoded
1298  printWarning("SopasBase::processFrame_CoLa_B: Received a very short (and unknown) event! Frame length is " + ::toString(frame.size()) + " bytes.");
1299  }
1300  }
1301  else
1302  {
1303  // Copy frame to response buffer. Old contents are destroyed.
1304  copyFrameToResposeBuffer(frame.size());
1305  }
1306 
1308 }
1309 
1310 
1311 
1312 //
1313 // Copies a complete frame - in any protocol - from the main input buffer to
1314 // the response buffer.
1315 // The frame is *not* removed from the main input buffer.
1316 //
1318 {
1319  printInfoMessage("SopasBase::copyFrameToResposeBuffer: Copying a frame of " + ::toString(frameLength) +
1320  " bytes to response buffer.", m_beVerbose);
1321 
1322  if (frameLength <= sizeof(m_responseBuffer))
1323  {
1324  // Wir duerfen kopieren
1325  memcpy(m_responseBuffer, m_receiveBuffer, frameLength);
1326  m_numberOfBytesInResponseBuffer = frameLength;
1327  }
1328  else
1329  {
1330  // Der respose-Buffer ist zu klein
1331  printError("SopasBase::copyFrameToResposeBuffer: Failed to copy frame (Length=" + ::toString(frameLength) +
1332  " bytes) to response buffer because the response buffer is too small (buffer size=" +
1333  ::toString(sizeof(m_responseBuffer)) + " bytes).");
1335  }
1336 }
1337 
1338 
1339 
1340 //
1341 // Removes a complete frame - in any protocol - from the main input buffer.
1342 //
1344 {
1345  // Remove frame from receive buffer
1346  if (frameLength < m_numberOfBytesInReceiveBuffer)
1347  {
1348  // More data in buffer, move them to the buffer start
1349  UINT32 newLen = m_numberOfBytesInReceiveBuffer - frameLength;
1350  printInfoMessage("SopasBase::removeFrameFromReceiveBuffer: Removing " + ::toString(frameLength) +
1351  " bytes from the input buffer. New length is " + ::toString(newLen) + " bytes.", m_beVerbose);
1352  memmove(m_receiveBuffer, &(m_receiveBuffer[frameLength]), newLen);
1354  }
1355  else
1356  {
1357  // No other data in buffer, just mark as empty
1358  printInfoMessage("SopasBase::removeFrameFromReceiveBuffer: Done, no more data in input buffer.", m_beVerbose);
1360  }
1361 }
1362 
1363 
1364 
1371 {
1373 }
1374 
1375 
1376 
1378 {
1379  // Request by Name
1380  if (cmdString == "RN")
1381  {
1382  return RN;
1383  } // Read Variable
1384  // else if (cmdString == "WN") { return WN; } // Write Variable
1385  // else if (cmdString == "MN") { return MN; } // Invoke Method
1386  else if (cmdString == "AN")
1387  {
1388  return AN;
1389  } // Method Result (Answer)
1390  // else if (cmdString == "EN") { return EN; } // Register Event
1391  else if (cmdString == "SN")
1392  {
1393  return SN;
1394  } // Send Event
1395 
1396  // Request by Index
1397  if (cmdString == "RI")
1398  {
1399  return RI;
1400  } // Read Variable
1401  else if (cmdString == "WI")
1402  {
1403  return WI;
1404  } // Write Variable
1405  else if (cmdString == "MI")
1406  {
1407  return MI;
1408  } // Invoke Method
1409  else if (cmdString == "AI")
1410  {
1411  return AI;
1412  } // Method Result (Answer)
1413  else if (cmdString == "EI")
1414  {
1415  return EI;
1416  } // Register Event
1417  else if (cmdString == "SI")
1418  {
1419  return SI;
1420  } // Send Event
1421 
1422  // Response
1423  else if (cmdString == "RA")
1424  {
1425  return RA;
1426  } // Read Variable
1427  else if (cmdString == "WA")
1428  {
1429  return WA;
1430  } // Write Variable
1431  else if (cmdString == "MA")
1432  {
1433  return MA;
1434  } // Invoke Method
1435  else if (cmdString == "AA")
1436  {
1437  return AA;
1438  } // Method Result (Answer)
1439  else if (cmdString == "EA")
1440  {
1441  return EA;
1442  } // Register Event
1443  else if (cmdString == "SA")
1444  {
1445  return SA;
1446  } // Event Acknowledge (Only used for reliable events
1447  else if (cmdString == "FA")
1448  {
1449  return FA;
1450  } // Error
1451 
1452  else
1453  {
1454  printError("SopasBase::stringToSopasCommand: Trying to resolve an unknown command: " + cmdString + ".");
1455  }
1456  return CMD_UNKNOWN;
1457 }
1458 
1459 //
1460 // For debugging: Convert the command into a readable string.
1461 //
1463 {
1464 
1465  if (cmd == RN)
1466  {
1467  return ("RN"); // Request by Name
1468  }
1469  // else if (cmdString == "WN") { return WN; } // Write Variable
1470  // else if (cmdString == "MN") { return MN; } // Invoke Method
1471  else if (cmd == AN)
1472  {
1473  return ("AN"); // Method Result, by name
1474  }
1475  // else if (cmdString == "EN") { return EN; } // Register Event
1476  else if (cmd == SN)
1477  {
1478  return ("SN"); // Send Event
1479  }
1480  if (cmd == RI)
1481  {
1482  return ("RI"); // Request by Index
1483  } // Read Variable
1484  else if (cmd == WI)
1485  {
1486  return ("WI"); // Write Variable
1487  }
1488  else if (cmd == MI)
1489  {
1490  return ("MI"); // Invoke Method
1491  }
1492  else if (cmd == AI)
1493  {
1494  return ("AI"); // Method Result (Answer)
1495  }
1496  else if (cmd == EI)
1497  {
1498  return ("EI"); // Register Event
1499  }
1500  else if (cmd == SI)
1501  {
1502  return ("SI");
1503  } // Send Event
1504 
1505  // Response
1506  else if (cmd == RA)
1507  {
1508  return ("RA");
1509  } // Read Variable
1510  else if (cmd == WA)
1511  {
1512  return ("WA"); // Write Variable
1513  }
1514  else if (cmd == MA)
1515  {
1516  return ("MA");
1517  } // Invoke Method
1518  else if (cmd == AA)
1519  {
1520  return ("AA");
1521  } // Method Result (Answer)
1522  else if (cmd == EA)
1523  {
1524  return ("EA");
1525  } // Register Event
1526  else if (cmd == SA)
1527  {
1528  return ("SA");
1529  } // Event Acknowledge (Only used for reliable events)
1530  else if (cmd == FA)
1531  {
1532  return ("FA"); // Error
1533  }
1534  else
1535  {
1536  printError("SopasBase::sopasCommandToString: Trying to resolve an unknown command!");
1537  }
1538 
1539  return "(unknown)";
1540 }
1541 
1542 
1543 
1551 {
1552  // every scanner must support ByName !!!
1553 
1554  bool result = false;
1555 
1556  // Clear old data.
1557  m_scannerName.empty();
1558  m_scannerVersion.empty();
1559 
1560  SopasAnswer* answer = NULL;
1561  result = readVariable(INDEX_DEVICE_IDENT, answer);
1562 
1563  if (result && answer != NULL && answer->isValid())
1564  {
1565 
1566  // decode answer
1567  std::string colaaAnswer;
1568  switch (m_protocol)
1569  {
1570  case CoLa_A:
1571  colaaAnswer = std::string((char*)answer->getBuffer(), answer->size());
1572  colaA_decodeScannerTypeAndVersion(&colaaAnswer);
1573  break;
1574  case CoLa_B:
1576  break;
1577  }
1578 
1579  if (!m_scannerName.empty() && !m_scannerVersion.empty())
1580  {
1581  result = true;
1582  }
1583  }
1584 
1585  if (answer != NULL)
1586  {
1587  delete answer;
1588  }
1589 
1590  return result;
1591 }
1592 
1593 
1594 
1599 {
1600  //
1601  // 1. part: Type
1602  //
1603  // String length
1604  UINT16 len = colaa::decodeUINT16(rxData);
1605 
1606  // Read string
1607  m_scannerName.clear();
1608  m_scannerName = rxData->substr(0, len);
1609 
1610  // Move input data
1611  *rxData = rxData->substr(len + 1);
1612 
1613  //
1614  // 2. part: Version
1615  //
1616  // String length
1617  len = colaa::decodeUINT16(rxData);
1618 
1619  // Read string
1620  m_scannerVersion.clear();
1621  m_scannerVersion = rxData->substr(0, len);
1622 }
1623 
1624 
1625 //
1626 //
1627 //
1629 {
1630  printInfoMessage("SopasBase::colaB_decodeScannerTypeAndVersion: Entering function.", m_beVerbose);
1631 
1632  UINT16 fieldLength;
1633 
1634  // read device type
1635  fieldLength = colab::getIntegerFromBuffer<UINT16>(buffer, pos);
1636  m_scannerName = colab::getStringFromBuffer(buffer, pos, fieldLength);
1637 
1638  // read device version
1639  fieldLength = colab::getIntegerFromBuffer<UINT16>(buffer, pos);
1640  m_scannerVersion = colab::getStringFromBuffer(buffer, pos, fieldLength);
1641 
1642  printInfoMessage("SopasBase::colaB_decodeScannerTypeAndVersion: scanner '" + m_scannerName + "', version '"
1643  + m_scannerVersion + "'.", m_beVerbose);
1644 }
1645 
1646 
1647 //
1648 //
1649 //
1650 bool SopasBase::invokeMethod(const std::string& methodeName, BYTE* parameters, UINT16 parametersLength, SopasAnswer*& answer)
1651 {
1652  // Build command
1653  BYTE cmdBuffer[128];
1654  UINT16 cmdBufferLen = 0;
1655 
1656  switch (m_protocol)
1657  {
1658  case CoLa_A:
1659  cmdBufferLen += colaa::addStringToBuffer(cmdBuffer, COMMAND_Invoke_Method_ByName);
1660  cmdBuffer[cmdBufferLen++] = ' ';
1661  //Name
1662  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[cmdBufferLen]), methodeName);
1663 
1664  if (parametersLength > 0)
1665  {
1666  cmdBuffer[cmdBufferLen++] = ' ';
1667  }
1668  break;
1669  case CoLa_B:
1670  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Invoke_Method_ByName);
1671  // add length of string as UINT16
1672  colab::addIntegerToBuffer<UINT16>(cmdBuffer, cmdBufferLen, methodeName.size());
1673  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, methodeName); // remote method name
1674  break;
1675  }
1676 
1677  if (parametersLength > 0)
1678  {
1679  // add parameters (which must be already in the right encoding (colaa or colab))
1680  memcpy(&cmdBuffer[cmdBufferLen], parameters, parametersLength);
1681  cmdBufferLen += parametersLength;
1682  }
1683 
1684  // Send command
1685  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
1686 
1687  // Wait for answer (the answer of a method is "AN" - not "EA")
1688  bool result = receiveAnswer(AN, methodeName, 2000, answer);
1689 
1690  // Evaluate answer
1691  if (result == true)
1692  {
1693  printInfoMessage("SopasBase::invokeMethod: Calling of " + methodeName + " was successful.", m_beVerbose);
1694  }
1695  else
1696  {
1697  printWarning("SopasBase::invokeMethod: Calling of " + methodeName + " was NOT successful.");
1698  }
1699 
1700  return result;
1701 }
1702 
1703 
1704 //
1705 //
1706 //
1707 bool SopasBase::invokeMethod(UINT16 index, BYTE* parameters, UINT16 parametersLength, SopasAnswer*& answer)
1708 {
1709  // Build command
1710  BYTE cmdBuffer[128];
1711  UINT16 cmdBufferLen = 0;
1712 
1713  switch (m_protocol)
1714  {
1715  case CoLa_A:
1716  printError("SopasBase::invokeMethod: Invoke method cola-a by index not supported.");
1717  return false;
1718  break;
1719  case CoLa_B:
1720  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Invoke_Method_ByIndex);
1721  // add length of string as UINT16
1722  colab::addIntegerToBuffer<UINT16>(cmdBuffer, cmdBufferLen, index);
1723  break;
1724  }
1725 
1726  if (parametersLength > 0)
1727  {
1728  // add parameters (which must be already in the right encoding (colaa or colab))
1729  memcpy(&cmdBuffer[cmdBufferLen], parameters, parametersLength);
1730  cmdBufferLen += parametersLength;
1731  }
1732 
1733  // Send command
1734  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
1735 
1736  // Wait for answer
1737  bool result = receiveAnswer(AI, index, 2000, answer);
1738 
1739  // Evaluate answer
1740  if (result == true)
1741  {
1742  printInfoMessage("SopasBase::invokeMethod: Calling of method with index=" + ::toString(index) + " was successful.", m_beVerbose);
1743  }
1744  else
1745  {
1746  printWarning("SopasBase::invokeMethod: Calling of method with index=" + ::toString(index) + " was NOT successful.");
1747  }
1748 
1749  return result;
1750 }
1751 
1752 
1753 //
1754 //
1755 //
1756 bool SopasBase::readVariable(const std::string& variableName, SopasAnswer*& answer)
1757 {
1758  // Build command
1759  BYTE cmdBuffer[128];
1760  UINT16 cmdBufferLen = 0;
1761 
1762  if (m_protocol == CoLa_A)
1763  {
1764  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[0]), COMMAND_Read_Variable_ByName);
1765  cmdBuffer[cmdBufferLen++] = ' ';
1766  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[cmdBufferLen]), variableName);
1767  }
1768  else
1769  {
1770  // up to now only tested with LD-MRS
1771  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Read_Variable_ByName);
1772  cmdBuffer[cmdBufferLen++] = ' ';
1773  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, variableName);
1774  }
1775 
1776  // Send
1777  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
1778 
1779  // Wait for answer
1780  bool result = receiveAnswer(RA, variableName, 2000, answer);
1781 
1782  if (result)
1783  {
1784  printInfoMessage("SopasBase::readVariable: Answer to " + variableName + " received.", m_beVerbose);
1785  }
1786  else
1787  {
1788  printWarning("SopasBase::readVariable: Answer to " + variableName + " not successful.");
1789  }
1790 
1791  return result;
1792 }
1793 
1794 
1795 //
1796 //
1797 //
1799 {
1800  // Build command
1801  BYTE cmdBuffer[128];
1802  UINT16 cmdBufferLen = 0;
1803 
1804  if (m_protocol == CoLa_A)
1805  {
1806  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[0]), COMMAND_Read_Variable_ByIndex);
1807  cmdBuffer[cmdBufferLen++] = ' ';
1808  cmdBufferLen += colaa::addUINT32ToBuffer(&(cmdBuffer[cmdBufferLen]), (UINT32)index);
1809  }
1810  else
1811  {
1812  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Read_Variable_ByIndex);
1813  colab::addIntegerToBuffer<UINT16>(cmdBuffer, cmdBufferLen, index);
1814  }
1815 
1816  // Send
1817  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
1818 
1819  // Wait for answer
1820  bool result = receiveAnswer(RA, index, 2000, answer);
1821 
1822  if (result)
1823  {
1824  printInfoMessage("SopasBase::readVariable: Answer to " + ::toString(index) + " received.", m_beVerbose);
1825  }
1826  else
1827  {
1828  printWarning("SopasBase::readVariable: Answer to " + ::toString(index) + " not successful.");
1829  }
1830 
1831  return result;
1832 }
1833 
1834 
1835 
1836 bool SopasBase::writeVariable(const std::string& variableName, BYTE* parameters, UINT16 parametersLength)
1837 {
1838  if (m_readOnlyMode)
1839  {
1840  printInfoMessage("SopasBase::writeVariable: ReadOnly Modus - ignore writing to variable '" +
1841  variableName + "'", m_beVerbose);
1842  return true;
1843  }
1844 
1845  // Build command
1846  BYTE cmdBuffer[128];
1847  UINT16 cmdBufferLen = 0;
1848 
1849  if (m_protocol == CoLa_A)
1850  {
1851  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[0]), COMMAND_Write_Variable_ByName);
1852  cmdBuffer[cmdBufferLen++] = ' ';
1853  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[cmdBufferLen]), variableName);
1854  if (parametersLength > 0)
1855  {
1856  cmdBuffer[cmdBufferLen++] = ' ';
1857  }
1858  }
1859  else
1860  {
1861  printError("SopasBase::writeVariable: Write variable cola-b by Name: NOT IMPLEMENTED");
1862  return false;
1863 // colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Write_Variable_ByName);
1864 // colab::addIntegerToBuffer<UINT16>(cmdBuffer, cmdBufferLen, variableName.size()); // add length of string as UINT16
1865 // colab::addStringToBuffer(cmdBuffer, cmdBufferLen, variableName);
1866 // or ?
1867 // colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Write_Variable_ByName);
1868 // colab::addStringToBuffer(cmdBuffer, cmdBufferLen, variableName);
1869  }
1870 
1871 
1872  if (parametersLength > 0)
1873  {
1874  // add parameters (which must be already in the right encoding (colaa or colab))
1875  memcpy(&cmdBuffer[cmdBufferLen], parameters, parametersLength);
1876  cmdBufferLen += parametersLength;
1877  }
1878 
1879 
1880  // Send
1881  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
1882  SopasAnswer* answer = NULL;
1883  // Wait for answer
1884  bool result = receiveAnswer(WA, variableName, 2000, answer);
1885  // free memory for answer
1886  if (answer != NULL)
1887  {
1888  delete answer;
1889  }
1890 
1891  if (result)
1892  {
1893  printInfoMessage("SopasBase::writeVariable: Answer to " + variableName + " received.", m_beVerbose);
1894  }
1895  else
1896  {
1897  printInfoMessage("SopasBase::writeVariable: Answer to " + variableName + " not successful.", m_beVerbose);
1898  }
1899 
1900  return result;
1901 }
1902 
1903 
1904 //
1905 // Write a variable, addressed by index.
1906 //
1907 bool SopasBase::writeVariable(UINT16 variableIndex, BYTE* parameters, UINT16 parametersLength)
1908 {
1909  bool beVerboseHere = m_beVerbose;
1910 // beVerboseHere = true;
1911 
1912  if (m_readOnlyMode == true)
1913  {
1914  printInfoMessage("SopasBase::writeVariable: ReadOnly Modus - ignore writing to variable index '" + ::toString(variableIndex) +
1915  "'", m_beVerbose);
1916  return true;
1917  }
1918 
1919  // Create the command buffer
1920  UINT32 cmdBufferLen = parametersLength + 4;
1921  BYTE* cmdBuffer = new BYTE[cmdBufferLen];
1922 
1923  // Add the command
1925 
1926  // Add the index
1927  BYTE* buffer = &(cmdBuffer[2]);
1928  memwrite_UINT16(buffer, variableIndex);
1929 // UINT16 pos = 0;
1930 // colab::addIntegerToBuffer<UINT16>(&(cmdBuffer[2]), pos, variableIndex);
1931 
1932  // Copy the data
1933  memcpy(&(cmdBuffer[4]), parameters, parametersLength);
1934 
1935  // Send. The frame is added automatically.
1936  printInfoMessage("SopasBase::writeVariable: Sending command buffer now (payload len=" + toString(parametersLength+4) + " bytes).", beVerboseHere);
1937  sendCommandBuffer(cmdBuffer, cmdBufferLen);
1938 
1939  printInfoMessage("SopasBase::writeVariable: Command sent, waiting for reply...", beVerboseHere);
1940  SopasAnswer* answer = NULL;
1941  // Wait for answer
1942  bool result = receiveAnswer(WA, variableIndex, 2000, answer);
1943  // free memory for answer
1944  if (answer != NULL)
1945  {
1946  delete answer;
1947  }
1948  if (result)
1949  {
1950  printInfoMessage("SopasBase::writeVariable: Answer to " + toString(variableIndex) + " received.", beVerboseHere);
1951  }
1952  else
1953  {
1954  printWarning("SopasBase::writeVariable: Answer to " + toString(variableIndex) + " not successful!");
1955  }
1956 
1957  printInfoMessage("SopasBase::writeVariable: All done, leaving.", beVerboseHere);
1958  return result;
1959 }
1960 
1961 
1962 
1963 bool SopasBase::registerEvent(const std::string& eventName)
1964 {
1965  BYTE cmdBuffer[128];
1966  UINT16 cmdBufferLen = 0;
1967 
1968  if (m_protocol == CoLa_A)
1969  {
1970  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[0]), COMMAND_Register_Event_ByName);
1971  cmdBuffer[cmdBufferLen++] = ' ';
1972  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[cmdBufferLen]), eventName);
1973  cmdBuffer[cmdBufferLen++] = ' ';
1974  cmdBuffer[cmdBufferLen++] = '1';
1975  }
1976  else
1977  {
1978  //traceError(SOPASBASE_VERSION) << "register event cola-B by name not supported." << std::endl;
1979  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Register_Event_ByName);
1980  cmdBuffer[cmdBufferLen++] = ' ';
1981  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, eventName);
1982  cmdBuffer[cmdBufferLen++] = ' ';
1983  colab::addIntegerToBuffer<UINT8>(cmdBuffer, cmdBufferLen, 1);
1984 
1985  // return false;
1986  }
1987 
1988  // Send
1989  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
1990  SopasAnswer* answer = NULL;
1991  // Wait for answer
1992  bool result = receiveAnswer(EA, eventName, 2000, answer);
1993 
1994 
1995  // free memory for answer
1996  if (answer != NULL)
1997  {
1998  delete answer;
1999  }
2000  return result;
2001 }
2002 
2003 
2004 //
2005 //
2006 //
2008 {
2009  // Build command
2010  BYTE cmdBuffer[128];
2011  UINT16 cmdBufferLen = 0;
2012 
2013  switch (m_protocol)
2014  {
2015  case CoLa_A:
2016  printError("SopasBase::register event cola-a by index not supported, aborting.");
2017 
2018  return false;
2019 
2020  break;
2021  case CoLa_B:
2022  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Register_Event_ByIndex);
2023  colab::addIntegerToBuffer<UINT16>(cmdBuffer, cmdBufferLen, index);
2024  colab::addIntegerToBuffer<UINT8>(cmdBuffer, cmdBufferLen, 1); // 1 to subscribe
2025  break;
2026  }
2027 
2028  // Send command
2029  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
2030 
2031  // Wait for answer
2032  SopasAnswer* answer = NULL;
2033  bool result = receiveAnswer(EA, index, 2000, answer);
2034 
2035  // there will be no answer (but to be sure to prevent memory leaks)
2036  if (answer != NULL)
2037  {
2038  delete answer;
2039  }
2040 
2041  // Evaluate answer
2042  if (result == true)
2043  {
2044  printInfoMessage("SopasBase::registerEvent: Calling of register with index=" + ::toString(index) + " was successful.", m_beVerbose);
2045  }
2046  else
2047  {
2048  printError("SopasBase::registerEvent: Calling of method with index=" + ::toString(index) + " was NOT successful.");
2049  }
2050  return result;
2051 }
2052 
2053 
2054 
2056 {
2057  // Build command
2058  BYTE cmdBuffer[128];
2059  UINT16 cmdBufferLen = 0;
2060 
2061  switch (m_protocol)
2062  {
2063  case CoLa_A:
2064  printError("SopasBase::unregisterEvent: Unregister event cola-a by index not supported.");
2065 
2066  return false;
2067 
2068  break;
2069  case CoLa_B:
2070  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Register_Event_ByIndex);
2071  colab::addIntegerToBuffer<UINT16>(cmdBuffer, cmdBufferLen, index);
2072  colab::addIntegerToBuffer<UINT8>(cmdBuffer, cmdBufferLen, 0); // 1 to subscribe
2073  break;
2074  }
2075 
2076  // Send command
2077  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
2078 
2079  // Wait for answer
2080  SopasAnswer* answer = NULL;
2081  bool result = receiveAnswer(EA, index, 2000, answer);
2082 
2083  // there will be no answer (but to be sure to prevent memory leaks)
2084  if (answer != NULL)
2085  {
2086  delete answer;
2087  }
2088 
2089  // Evaluate answer
2090  if (result == true)
2091  {
2092  printInfoMessage("SopasBase::calling of register with index=" + ::toString(index) + " was successful.", m_beVerbose);
2093  }
2094  else
2095  {
2096  printInfoMessage("SopasBase::calling of register with index=" + ::toString(index) + " was NOT successful.", m_beVerbose);
2097  }
2098 
2099  return result;
2100 }
2101 
2102 
2103 
2104 bool SopasBase::unregisterEvent(const std::string& eventName)
2105 {
2106  BYTE cmdBuffer[128];
2107  UINT16 cmdBufferLen = 0;
2108 
2109  if (m_protocol == CoLa_A)
2110  {
2111  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[0]), COMMAND_Register_Event_ByName);
2112  cmdBuffer[cmdBufferLen++] = ' ';
2113  cmdBufferLen += colaa::addStringToBuffer(&(cmdBuffer[cmdBufferLen]), eventName);
2114  cmdBuffer[cmdBufferLen++] = ' ';
2115  cmdBuffer[cmdBufferLen++] = '0';
2116  }
2117  else
2118  {
2119 // traceError(SOPASBASE_VERSION) << "unregister event cola-B by name not supported." << std::endl;
2120  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, COMMAND_Register_Event_ByName);
2121  cmdBuffer[cmdBufferLen++] = ' ';
2122  colab::addStringToBuffer(cmdBuffer, cmdBufferLen, eventName);
2123  cmdBuffer[cmdBufferLen++] = ' ';
2124  colab::addIntegerToBuffer<UINT8>(cmdBuffer, cmdBufferLen, 0);
2125 // return false;
2126  }
2127 
2128  // Send
2129  sendCommandBuffer(&(cmdBuffer[0]), cmdBufferLen);
2130  SopasAnswer* answer = NULL;
2131  // Wait for answer
2132  bool result = receiveAnswer(EA, eventName, 2000, answer);
2133 
2134 
2135  // free memory for answer
2136  if (answer != NULL)
2137  {
2138  delete answer;
2139  }
2140  return result;
2141 }
2142 
2143 
2144 
2148 double SopasBase::makeAngleValid(double angle)
2149 {
2151 }
2152 
2153 
2154 
2155 //
2156 // ************************* SOPAS FRAME ************************************************** //
2157 //
2159  m_buffer(NULL), m_protocol(SopasBase::CoLa_A), m_frameLength(0), m_encoding(SopasBase::ByName)
2160 {
2161 }
2162 
2163 
2164 
2166  m_buffer(buffer), m_protocol(protocol), m_frameLength(frameLength), m_encoding(SopasBase::ByName)
2167 {
2168  detectEncoding();
2170 }
2171 
2172 
2173 
2175 {
2176  UINT32 payLoadLength = 0;
2177 
2178  switch (m_protocol)
2179  {
2180  case SopasBase::CoLa_A:
2181  payLoadLength = m_frameLength - 2; // everything except the 0x02 0x03 frame
2182  break;
2183  case SopasBase::CoLa_B:
2184  payLoadLength = m_frameLength - 9; // everything except start 0x02020202(4byte), payloadLength(4byte) and checksum(1 byte)
2185  }
2186 
2187  return payLoadLength;
2188 }
2189 
2190 
2191 
2193 {
2194  std::string commandString;
2195 
2196  switch (m_protocol)
2197  {
2198  case SopasBase::CoLa_A:
2199  commandString = std::string((char*) &m_buffer[2], 2);
2200  break;
2201  case SopasBase::CoLa_B:
2202  commandString = std::string((char*) &m_buffer[9], 2);
2203  }
2204 
2205  return commandString;
2206 }
2207 
2208 
2209 //
2210 // Returns a pointer to the first payload byte.
2211 // CoLa-A: Points beyond the leading "0x02" to the "s..." data.
2212 // CoLa-B: Points beyond the magic word and length bytes, to the "s..." data.
2213 //
2215 {
2216  BYTE* bufferPos = NULL;
2217 
2218  switch (m_protocol)
2219  {
2220  case SopasBase::CoLa_A:
2221  bufferPos = &m_buffer[1];
2222  break;
2223  case SopasBase::CoLa_B:
2224  bufferPos = &m_buffer[8];
2225  break;
2226  }
2227 
2228  return bufferPos;
2229 }
2230 
2231 
2232 
2234 {
2235  INT32 index = -1;
2236 
2238  {
2239  // Encoding is not byIndex, so abort here
2240  printWarning("SopasEventMessage::getVariableIndex: Encoding is not ByIndex, aborting!");
2241  return index;
2242  }
2243 
2244  BYTE* bufferPos = &getPayLoad()[3];
2245  switch (m_protocol)
2246  {
2247  case SopasBase::CoLa_A:
2248  index = (INT32)(colaa::decodeUINT16(bufferPos));
2249  break;
2250  case SopasBase::CoLa_B:
2251  index = (INT32)(colab::decodeUINT16(bufferPos));
2252  break;
2253  default:
2254  printError("SopasEventMessage::getVariableIndex: Unknown protocol!");
2255  }
2256 
2257  return index;
2258 }
2259 
2260 //
2261 // Read the variable name from a sensor message. This works only if the encoding "ByName" is used!
2262 //
2264 {
2265  std::string name;
2266  UINT32 i;
2267  BYTE* bufferPos;
2268 
2270  {
2271  switch (m_protocol)
2272  {
2273  case SopasBase::CoLa_A:
2274  printError("SopasEventMessage::getVariableName: Protocol CoLa-A is not supported, aborting!");
2275  return "";
2276  break;
2277  case SopasBase::CoLa_B:
2278  bufferPos = &getPayLoad()[4];
2279  i = 4;
2280 
2281  // example for message "sSI <variablename> 0x000binarydata"
2282 
2283  // search for the next white space
2284  while ((*bufferPos != ' ') && (i < getPayLoadLength()))
2285  {
2286  name += *bufferPos;
2287  bufferPos++;
2288  i++;
2289  }
2290  break;
2291  }
2292  }
2293 
2294  return name;
2295 }
2296 
2297 
2298 //
2299 // Detects the encoding method (ByName or ByIndex) from the sensor message.
2300 //
2302 {
2303  // if the third byte of the payload is an 'I', the encoding is ByIndex
2304  // sXI: sAI, sRI, sWI, sMI, sEI, sSI
2305  if (getPayLoad()[2] == 'I')
2306  {
2308  }
2309 }
2310 
2311 
2312 
2314 {
2315  std::string command = getCommandString();
2316 
2317  if (command == SopasBase::COMMAND_Event_Acknowledge)
2318  {
2320  }
2321  else if (command == SopasBase::COMMAND_Invoke_Method_Answer)
2322  {
2324  }
2325  else if (command == SopasBase::COMMAND_Method_Result_Answer)
2326  {
2328  }
2330  {
2332  }
2333  else if (command == SopasBase::COMMAND_Read_Variable_Answer)
2334  {
2336  }
2337  else if (command == SopasBase::COMMAND_Write_Variable_Answer)
2338  {
2340  }
2341  else
2342  {
2344  }
2345 }
2346 
2347 SopasAnswer::SopasAnswer(const BYTE* answer, UINT32 answerLength) : m_answerLength(answerLength)
2348 {
2349  if (answerLength > 0)
2350  {
2352  memcpy(m_answerBuffer, answer, answerLength);
2353  }
2354  else
2355  {
2356  m_answerBuffer = NULL;
2357  }
2358 }
2359 
2361 {
2362  if (m_answerBuffer != NULL)
2363  {
2364  delete[] m_answerBuffer;
2365  m_answerLength = 0;
2366  }
2367 }
2368 
2369 } // namespace devices
SopasBase::SopasMessageType getMessageType() const
Definition: SopasBase.hpp:444
std::string getVariableName()
Returns the name of a variable (answer to read variable by name). In case of error an empty value wil...
Definition: SopasBase.cpp:2263
UINT32 getPayLoadLength() const
contains &#39;s&#39; + command string(2 byte) + content(payload length - 3)
Definition: SopasBase.cpp:2174
void printError(std::string message)
void processFrame_CoLa_A(SopasEventMessage &frame)
Definition: SopasBase.cpp:1147
std::string toString(const PositionWGS84::PositionWGS84SourceType &type)
BYTE * getPayLoad()
contains &#39;s&#39; + command string(2 byte) + content(payload length - 3)
Definition: SopasBase.cpp:2214
void closeTcpConnection()
Definition: SopasBase.cpp:240
static const std::string COMMAND_Read_Variable_ByName
Definition: SopasBase.hpp:65
Command Language binary.
Definition: SopasBase.hpp:77
SopasBase::SopasMessageType m_messageType
Definition: SopasBase.hpp:480
State m_state
Device info.
Definition: SopasBase.hpp:352
Write Variable Answer.
Definition: SopasBase.hpp:286
bool registerEvent(const std::string &eventName)
Registers an event by name.
Definition: SopasBase.cpp:1963
unsigned char BYTE
std::string decodeString(std::string *rxData, UINT16 len)
Definition: colaa.cpp:598
bool receiveAnswer_CoLa_A(SopasCommand cmd, std::string name, UINT32 timeout, SopasAnswer *&answer)
Definition: SopasBase.cpp:687
SopasAnswer(const BYTE *answer, UINT32 answerLength)
Constructor. Copies the content of the answer into the buffer of this object.
Definition: SopasBase.cpp:2347
static const std::string VARIABLENAME_DEVICEIDENT
Definition: SopasBase.hpp:45
bool m_weWantScanData
Flag to enable/disable scan data reception.
Definition: SopasBase.hpp:348
static const std::string VARIABLENAME_SCANCONFIG
Definition: SopasBase.hpp:46
void colaB_decodeScannerTypeAndVersion(UINT8 *buffer, UINT16 pos)
Definition: SopasBase.cpp:1628
SopasEventMessage()
Default constructor.
Definition: SopasBase.cpp:2158
Class that encapsulates a buffer that was sent as return to a sync call. (variable / method) ...
Definition: SopasBase.hpp:484
Read Variable (by name)
Definition: SopasBase.hpp:291
uint16_t UINT16
static std::string convertSopasErrorCodeToText(UINT16 errorCode)
Definition: SopasBase.cpp:918
static const std::string COMMAND_Register_Event_Answer
Definition: SopasBase.hpp:62
static const std::string EVENTNAME_SUBSCRIBE_EVALCASES
Definition: SopasBase.hpp:38
static const std::string VARIABLENAME_SCANDATACONFIG
Definition: SopasBase.hpp:48
static const std::string COMMAND_Register_Event_ByName
Definition: SopasBase.hpp:69
std::string getNextStringToken(std::string *rxData)
Definition: colaa.cpp:241
Mutex m_receiveDataMutex
Access mutex for buffer.
Definition: SopasBase.hpp:400
static const std::string COMMAND_Method_Result_Answer
Definition: SopasBase.hpp:61
Class that represents a message that was sent by a sensor. (Event message)
Definition: SopasBase.hpp:416
virtual ~SopasBase()
Destructor.
Definition: SopasBase.cpp:69
SopasCommand colaA_decodeCommand(std::string *rxData)
Definition: SopasBase.cpp:1370
UINT16 decodeUINT16(BYTE *buffer)
Definition: colab.cpp:144
std::string convertRxBufferToString(UINT8 *buffer, UINT16 bufferLen)
Definition: colaa.cpp:788
INT32 getVariableIndex()
Returns the index of a variable (answer to read variable by index). In case of error a negative value...
Definition: SopasBase.cpp:2233
std::string getStringFromBuffer(UINT8 *buffer, UINT16 &pos, UINT16 length)
Definition: colab.cpp:34
SopasBase::SopasEncoding getEncodingType() const
Definition: SopasBase.hpp:439
void(* DisconnectFunction)(void *obj)
Definition: tcp.hpp:53
#define printInfoMessage(a, b)
static const std::string METHODNAME_LOGOUT
Definition: SopasBase.hpp:41
uint32_t UINT32
static const std::string COMMAND_Invoke_Method_ByIndex
Definition: SopasBase.hpp:53
SopasEncoding m_encoding
ByName or ByIndex.
Definition: SopasBase.hpp:381
std::string getCommandString() const
Definition: SopasBase.cpp:2192
read/write variable, invoke methods by index (indexes will be generated !!!)
Definition: SopasBase.hpp:83
static const std::string METHODNAME_LOGIN
Definition: SopasBase.hpp:40
Object has been constructed. Use init() to go into CONNECTED state.
Definition: SopasBase.hpp:301
SopasBase::SopasProtocol m_protocol
Definition: SopasBase.hpp:477
bool isConnected()
Returns true if the tcp connection is established.
Definition: SopasBase.cpp:179
Read Variable Answer.
Definition: SopasBase.hpp:285
static const std::string METHODNAME_STOP_MEASURE
Definition: SopasBase.hpp:44
SopasBase()
Default constructor.
Definition: SopasBase.cpp:59
void addStringToBuffer(UINT8 *buffer, UINT16 &pos, const std::string &stringValue)
Definition: colab.cpp:16
bool write(UINT8 *buffer, UINT32 numberOfBytes)
Definition: tcp.cpp:47
DecoderFunctionMapByName m_decoderFunctionMapByName
Definition: SopasBase.hpp:388
UINT32 m_numberOfBytesInResponseBuffer
Number of bytes in buffer.
Definition: SopasBase.hpp:398
void readCallbackFunction(UINT8 *buffer, UINT32 &numOfBytes)
Definition: SopasBase.cpp:261
static const std::string COMMAND_Write_Variable_ByName
Definition: SopasBase.hpp:66
Invoke Method.
Definition: SopasBase.hpp:281
bool open(std::string ipAddress, UINT16 port, bool enableVerboseDebugOutput=false)
Definition: tcp.cpp:129
Event Acknowledge -Answer to register event.
Definition: SopasBase.hpp:101
void processFrame_CoLa_B(SopasEventMessage &frame)
Definition: SopasBase.cpp:1236
UINT32 m_numberOfBytesInReceiveBuffer
Number of bytes in buffer.
Definition: SopasBase.hpp:403
static const std::string COMMAND_Invoke_Method_Answer
Definition: SopasBase.hpp:60
void copyFrameToResposeBuffer(UINT32 frameLength)
Definition: SopasBase.cpp:1317
static const std::string COMMAND_Send_Event_ByIndex
Definition: SopasBase.hpp:56
bool receiveAnswer(SopasCommand cmd, std::string name, UINT32 timeout, SopasAnswer *&answer)
Take answer from read thread and decode it. Waits for a certain answer by name. Event data (scans) ar...
Definition: SopasBase.cpp:541
static const std::string COMMAND_Register_Event_ByIndex
Definition: SopasBase.hpp:55
read/write variable, invoke methods by name
Definition: SopasBase.hpp:82
bool openTcpConnection()
Definition: SopasBase.cpp:221
static const std::string COMMAND_Read_Variable_Answer
Definition: SopasBase.hpp:58
Invoke Method Answer.
Definition: SopasBase.hpp:287
static const std::string COMMAND_Write_Variable_ByIndex
Definition: SopasBase.hpp:52
std::string sopasCommandToString(SopasCommand cmd)
Definition: SopasBase.cpp:1462
static const std::string COMMAND_Write_Variable_Answer
Definition: SopasBase.hpp:59
void removeFrameFromReceiveBuffer(UINT32 frameLength)
Definition: SopasBase.cpp:1343
bool writeVariable(const std::string &variableName, BYTE *parameters, UINT16 parametersLength)
Write a variable to the sensor by name.
Definition: SopasBase.cpp:1836
void addFrameToBuffer(UINT8 *sendBuffer, UINT8 *cmdBuffer, UINT16 *len)
Definition: colab.cpp:99
void addFrameToBuffer(UINT8 *sendBuffer, UINT8 *cmdBuffer, UINT16 *len)
Definition: colaa.cpp:77
std::string m_ipAddress
Definition: SopasBase.hpp:408
Method Result (ny name)
Definition: SopasBase.hpp:292
SopasEventMessage findFrameInReceiveBuffer()
Depending on the protocol the start and end of a frame will be found.
Definition: SopasBase.cpp:333
Method Result Answer.
Definition: SopasBase.hpp:288
Method Result.
Definition: SopasBase.hpp:282
void setReadOnlyMode(bool mode)
Definition: SopasBase.cpp:202
IndexToNameMap m_indexToNameMap
Definition: SopasBase.hpp:395
std::string getCommandStringFromBuffer(UINT8 *buffer)
Definition: colab.cpp:52
int32_t INT32
void processFrame(SopasEventMessage &frame)
Reads one frame from receive buffer and decodes it.
Definition: SopasBase.cpp:1125
SopasCommand stringToSopasCommand(const std::string &cmdString)
Converts strings in sopas answer buffer to SopasCommand enum.
Definition: SopasBase.cpp:1377
static const std::string EVENTNAME_SUBSCRIBE_SCANS
Definition: SopasBase.hpp:39
bool m_weWantFieldData
Flag to enable/disable protection field data reception.
Definition: SopasBase.hpp:349
static const UINT16 INDEX_DEVICE_IDENT
Definition: SopasBase.hpp:72
void memwrite_UINT16(BYTE *&buffer, UINT16 value)
Definition: toolbox.cpp:576
static const std::string COMMAND_Event_Acknowledge
Definition: SopasBase.hpp:63
UINT8 m_receiveBuffer[25000]
Low-Level receive buffer for all data (25000 should be enough for NAV300 Events)
Definition: SopasBase.hpp:404
UINT16 addStringToBuffer(UINT8 *buffer, const std::string &text)
Definition: colaa.cpp:219
std::string m_scannerName
Read from scanner.
Definition: SopasBase.hpp:353
virtual void evalCaseResultDecoder(SopasEventMessage &msg)=0
SopasProtocol m_protocol
Used protocol (ColaA oder ColaB)
Definition: SopasBase.hpp:380
virtual void scanDataDecoder(SopasEventMessage &msg)=0
void colaA_decodeScannerTypeAndVersion(std::string *rxData)
Definition: SopasBase.cpp:1598
double normalizeRadians(double radians)
Definition: MathToolbox.cpp:31
Event Acknowledge.
Definition: SopasBase.hpp:290
bool action_getScannerTypeAndVersion()
Reads the scanner type and version variable from the sensor and stores it in the member variables...
Definition: SopasBase.cpp:1550
bool disconnect()
Closes the connection to the LMS. This is the opposite of init().
Definition: SopasBase.cpp:187
Read Variable.
Definition: SopasBase.hpp:279
static const std::string METHODNAME_START_MEASURE
Definition: SopasBase.hpp:43
~SopasAnswer()
Destructor. Frees the memory for the copied buffer.
Definition: SopasBase.cpp:2360
static const std::string COMMAND_Method_Result_ByIndex
Definition: SopasBase.hpp:54
SopasBase::SopasEncoding m_encoding
Definition: SopasBase.hpp:479
bool isOpen()
Definition: tcp.cpp:88
Register Event Answer.
Definition: SopasBase.hpp:289
Register Event.
Definition: SopasBase.hpp:283
bool receiveAnswer_CoLa_B(SopasCommand cmd, std::string name, UINT32 timeout, SopasAnswer *&answer)
Definition: SopasBase.cpp:783
static const std::string VARIABLENAME_DATAOUTPUTRANGE
Definition: SopasBase.hpp:47
bool readVariable(const std::string &variableName, SopasAnswer *&answer)
Reads a variable from the sensor by name.
Definition: SopasBase.cpp:1756
void sendCommandBuffer(UINT8 *buffer, UINT16 len)
Sends the content of the buffer via TCP to the sensor.
Definition: SopasBase.cpp:507
static const std::string COMMAND_Invoke_Method_ByName
Definition: SopasBase.hpp:67
UINT16 addUINT32ToBuffer(UINT8 *buffer, UINT32 value)
Definition: colaa.cpp:195
Command Language ASCI.
Definition: SopasBase.hpp:76
void setReadCallbackFunction(ReadFunction readFunction, void *obj)
Definition: tcp.cpp:103
static const std::string COMMAND_Read_Variable_ByIndex
Definition: SopasBase.hpp:51
std::string m_scannerVersion
Read from scanner.
Definition: SopasBase.hpp:354
void setDisconnectCallbackFunction(DisconnectFunction discFunction, void *obj)
Definition: tcp.cpp:75
void close()
Definition: tcp.cpp:285
UINT8 m_responseBuffer[1024]
Receive buffer for everything except scan data and eval case data.
Definition: SopasBase.hpp:399
double makeAngleValid(double angle)
Definition: SopasBase.cpp:2148
Send Event (by name, receive)
Definition: SopasBase.hpp:293
void printWarning(std::string message)
UINT16 decodeUINT16(BYTE *buffer)
Definition: colaa.cpp:622
std::string getIdentifierFromBuffer(UINT8 *buffer, UINT16 &nextData, UINT16 bufferLength)
Definition: colab.cpp:59
bool connect()
Connects to a sensor via tcp and reads the device name.
Definition: SopasBase.cpp:124
bool unregisterEvent(const std::string &eventName)
Unregisters an event by name.
Definition: SopasBase.cpp:2104
static const std::string COMMAND_Send_Event_ByName
Definition: SopasBase.hpp:70
bool invokeMethod(const std::string &methodeName, BYTE *parameters, UINT16 parametersLength, SopasAnswer *&answer)
Invoke a method on the sensor.
Definition: SopasBase.cpp:1650
static void readCallbackFunctionS(void *obj, UINT8 *buffer, UINT32 &numOfBytes)
Function that will be called on incomming data via tcp.
Definition: SopasBase.cpp:251
uint8_t UINT8
static const std::string COMMAND_Method_Result_ByName
Definition: SopasBase.hpp:68
virtual bool init(SopasProtocol protocol, std::string ipAddress, UINT16 portNumber, bool weWantScanData, bool weWantFieldData, bool readOnlyMode, Tcp::DisconnectFunction disconnectFunction, void *obj)
Initialization.
Definition: SopasBase.cpp:96
Write Variable.
Definition: SopasBase.hpp:280
static const std::string METHODNAME_SET_SCANCONFIG
Definition: SopasBase.hpp:42


libsick_ldmrs
Author(s): SICK AG , Martin Günther , Jochen Sprickerhof
autogenerated on Sat Jun 8 2019 17:57:33