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


sick_scan
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Wed May 5 2021 03:05:48