sick_scan_common_nw.cpp
Go to the documentation of this file.
1 
23 #include "sick_scan/tcp/colaa.hpp"
24 #include "sick_scan/tcp/colab.hpp"
26 #include "sick_scan/tcp/tcp.hpp"
27 #include <map> // for std::map
28 
29 #include "sick_scan/tcp/tcp.hpp"
32 #include "sick_scan/tcp/Mutex.hpp"
33 #include <assert.h>
34 
36  {
38  m_beVerbose = false;
39 
40  }
41 
43  {
44  // Disconnect and shut down receive thread.
45  if (isConnected() == true)
46  {
47  // Change from CONNECTED to CONSTRUCTED
48  disconnect();
49  }
50  }
51 
52 
53 //
54 // Disconnect from the scanner, and close the interface.
55 //
57 {
59 
60  // Change back to CONSTRUCTED
62  return true;
63 }
64 
65 
66 //
67 // Initialisation from Scanner class:
68 // Parameter setup only. Afterwards, call connect() to connect to the scanner.
69 //
70  bool SickScanCommonNw::init(std::string ipAddress,
71  unsigned short portNumber,
72  Tcp::DisconnectFunction disconnectFunction,
73  void* obj)
74  {
75  m_ipAddress = ipAddress;
76  m_portNumber = portNumber;
77  m_tcp.setDisconnectCallbackFunction(disconnectFunction, obj);
78  return true;
79  }
80 
81 
83  void* obj)
84  {
85  m_tcp.setReadCallbackFunction(readFunction, obj);
86  return(true);
87  }
88 //
89 // Verbinde mit dem unter init() eingestellten Geraet, und pruefe die Verbindung
90 // durch einen DeviceIdent-Aufruf.
91 //
92 // true = Erfolgreich.
93 //
94 
95 
97  {
98 
99  assert (m_state == CONSTRUCTED); // must not be opened or running already
100 
101  // Initialise buffer variables
102  m_numberOfBytesInReceiveBuffer = 0; // Buffer is empty
103  m_numberOfBytesInResponseBuffer = 0; // Buffer is empty
104 
105  // Establish connection here
106  // Set the data input callback for our TCP connection
107  // m_tcp.setReadCallbackFunction(&SickScanCommonNw::readCallbackFunctionS, this); // , this, _1, _2));
108 
109  bool success = openTcpConnection();
110  if (success == true)
111  {
112  // Check if scanner type matches
113  m_state = CONNECTED;
114 
115  }
116  return success;
117  }
118 
119 
120 
121 //
122 // True, if state is CONNECTED, that is:
123 // - A TCP-connection exists
124 // - Read thread is running
125 //
127  {
128  return (m_state == CONNECTED);
129  }
130 
131 
132 
133 
134 
141  {
142  // printInfoMessage("SickScanCommonNw::openTcpConnection: Connecting TCP/IP connection to " + m_ipAddress + ":" + toString(m_portNumber) + " ...", m_beVerbose);
143 
144  bool success = m_tcp.open(m_ipAddress, m_portNumber, m_beVerbose);
145  if (success == false)
146  {
147  // printError("SickScanCommonNw::openTcpConnection: ERROR: Failed to establish TCP connection, aborting!");
148  return false;
149  }
150 
151  return true;
152  }
153 
154 
155 
156 //
157 // Close TCP-connection and shut down read thread
158 //
160  {
161  if (m_tcp.isOpen())
162  {
163  m_tcp.close();
164  }
165  }
166 
167 //
168 // Static entry point.
169 //
170  void SickScanCommonNw::readCallbackFunctionS(void* obj, UINT8* buffer, UINT32& numOfBytes)
171  {
172  ((SickScanCommonNw*)obj)->readCallbackFunction(buffer, numOfBytes);
173  }
174 
175 
181  {
182  bool beVerboseHere = false;
183  printInfoMessage("SickScanCommonNw::readCallbackFunction(): Called with " + toString(numOfBytes) + " available bytes.", beVerboseHere);
184 
185  ScopedLock lock(&m_receiveDataMutex); // Mutex for access to the input buffer
186  UINT32 remainingSpace = sizeof(m_receiveBuffer) - m_numberOfBytesInReceiveBuffer;
187  UINT32 bytesToBeTransferred = numOfBytes;
188  if (remainingSpace < numOfBytes)
189  {
190  bytesToBeTransferred = remainingSpace;
191  // printWarning("SickScanCommonNw::readCallbackFunction(): Input buffer space is to small, transferring only " +
192  // ::toString(bytesToBeTransferred) + " of " + ::toString(numOfBytes) + " bytes.");
193  }
194  else
195  {
196  // printInfoMessage("SickScanCommonNw::readCallbackFunction(): Transferring " + ::toString(bytesToBeTransferred) +
197  // " bytes from TCP to input buffer.", beVerboseHere);
198  }
199 
200  if (bytesToBeTransferred > 0)
201  {
202  // Data can be transferred into our input buffer
203  memcpy(&(m_receiveBuffer[m_numberOfBytesInReceiveBuffer]), buffer, bytesToBeTransferred);
204  m_numberOfBytesInReceiveBuffer += bytesToBeTransferred;
205 
206  UINT32 size = 0;
207 
208  while (1)
209  {
210  // Now work on the input buffer until all received datasets are processed
212 
213  size = frame.size();
214  if (size == 0)
215  {
216  // Framesize = 0: There is no valid frame in the buffer. The buffer is either empty or the frame
217  // is incomplete, so leave the loop
218  printInfoMessage("SickScanCommonNw::readCallbackFunction(): No complete frame in input buffer, we are done.", beVerboseHere);
219 
220  // Leave the loop
221  break;
222  }
223  else
224  {
225  // A frame was found in the buffer, so process it now.
226  printInfoMessage("SickScanCommonNw::readCallbackFunction(): Processing a frame of length " + ::toString(frame.size()) + " bytes.", beVerboseHere);
227  processFrame(frame);
228  }
229  }
230  }
231  else
232  {
233  // There was input data from the TCP interface, but our input buffer was unable to hold a single byte.
234  // Either we have not read data from our buffer for a long time, or something has gone wrong. To re-sync,
235  // we clear the input buffer here.
237  }
238 
239  }
240 
241 
242 
243 //
244 // Look for 23-frame (STX/ETX) in receive buffer.
245 // Move frame to start of buffer
246 //
247 // Return: 0 : No (complete) frame found
248 // >0 : Frame length
249 //
251  {
252  UINT32 frameLen = 0;
253  UINT32 i;
254 
255  // Depends on protocol...
256  if (m_protocol == CoLa_A)
257  {
258  //
259  // COLA-A
260  //
261  // Must start with STX (0x02)
262  if (m_receiveBuffer[0] != 0x02)
263  {
264  // Look for starting STX (0x02)
265  for (i = 1; i < m_numberOfBytesInReceiveBuffer; i++)
266  {
267  if (m_receiveBuffer[i] == 0x02)
268  {
269  break;
270  }
271  }
272 
273  // Found beginning of frame?
274  if (i >= m_numberOfBytesInReceiveBuffer)
275  {
276  // No start found, everything can be discarded
277  m_numberOfBytesInReceiveBuffer = 0; // Invalidate buffer
278  return SopasEventMessage(); // No frame found
279  }
280 
281  // Move frame start to index 0
282  UINT32 newLen = m_numberOfBytesInReceiveBuffer - i;
283  memmove(&(m_receiveBuffer[0]), &(m_receiveBuffer[i]), newLen);
284  m_numberOfBytesInReceiveBuffer = newLen;
285  }
286 
287  // Look for ending ETX (0x03)
288  for (i = 1; i < m_numberOfBytesInReceiveBuffer; i++)
289  {
290  if (m_receiveBuffer[i] == 0x03)
291  {
292  break;
293  }
294  }
295 
296  // Found end?
297  if (i >= m_numberOfBytesInReceiveBuffer)
298  {
299  // No end marker found, so it's not a complete frame (yet)
300  return SopasEventMessage(); // No frame found
301  }
302 
303  // Calculate frame length in byte
304  frameLen = i + 1;
305 
306  return SopasEventMessage(m_receiveBuffer, CoLa_A, frameLen);
307  }
308  else if (m_protocol == CoLa_B)
309  {
310  UINT32 magicWord;
311  UINT32 payloadlength;
312 
314  {
315  return SopasEventMessage();
316  }
317  UINT16 pos = 0;
318  magicWord = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
319  if (magicWord != 0x02020202)
320  {
321  // Look for starting STX (0x02020202)
322  for (i = 1; i <= m_numberOfBytesInReceiveBuffer - 4; i++)
323  {
324  pos = i; // this is needed, as the position value is updated by getIntegerFromBuffer
325  magicWord = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
326  if (magicWord == 0x02020202)
327  {
328  // found magic word
329  break;
330  }
331  }
332 
333  // Found beginning of frame?
334  if (i > m_numberOfBytesInReceiveBuffer - 4)
335  {
336  // No start found, everything can be discarded
337  m_numberOfBytesInReceiveBuffer = 0; // Invalidate buffer
338  return SopasEventMessage(); // No frame found
339  }
340  else
341  {
342  // Move frame start to index
343  UINT32 bytesToMove = m_numberOfBytesInReceiveBuffer - i;
344  memmove(&(m_receiveBuffer[0]), &(m_receiveBuffer[i]), bytesToMove); // payload+magic+length+s+checksum
345  m_numberOfBytesInReceiveBuffer = bytesToMove;
346  }
347  }
348 
349  // Pruefe Laenge des Pufferinhalts
351  {
352  // Es sind nicht genug Daten fuer einen Frame
353  printInfoMessage("SickScanCommonNw::findFrameInReceiveBuffer: Frame cannot be decoded yet, only " +
354  ::toString(m_numberOfBytesInReceiveBuffer) + " bytes in the buffer.", m_beVerbose);
355  return SopasEventMessage();
356  }
357 
358  // Read length of payload
359  pos = 4;
360  payloadlength = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
361  printInfoMessage("SickScanCommonNw::findFrameInReceiveBuffer: Decoded payload length is " + ::toString(payloadlength) + " bytes.", m_beVerbose);
362 
363  // Ist die Datenlaenge plausibel und wuede in den Puffer passen?
364  if (payloadlength > (sizeof(m_receiveBuffer) - 9))
365  {
366  // magic word + length + checksum = 9
367  printWarning("SickScanCommonNw::findFrameInReceiveBuffer: Frame too big for receive buffer. Frame discarded with length:"
368  + ::toString(payloadlength) + ".");
370  return SopasEventMessage();
371  }
372  if ((payloadlength + 9) > m_numberOfBytesInReceiveBuffer)
373  {
374  // magic word + length + s + checksum = 10
375  printInfoMessage("SickScanCommonNw::findFrameInReceiveBuffer: Frame not complete yet. Waiting for the rest of it (" +
376  ::toString(payloadlength + 9 - m_numberOfBytesInReceiveBuffer) + " bytes missing).", m_beVerbose);
377  return SopasEventMessage(); // frame not complete
378  }
379 
380  // Calculate the total frame length in bytes: Len = Frame (9 bytes) + Payload
381  frameLen = payloadlength + 9;
382 
383  //
384  // test checksum of payload
385  //
386  UINT8 temp = 0;
387  UINT8 temp_xor = 0;
388  UINT8 checkSum;
389 
390  // Read original checksum
391  pos = frameLen - 1;
392  checkSum = colab::getIntegerFromBuffer<UINT8>(m_receiveBuffer, pos);
393 
394  // Erzeuge die Pruefsumme zum Vergleich
395  for (UINT16 i = 8; i < (frameLen - 1); i++)
396  {
397  pos = i;
398  temp = colab::getIntegerFromBuffer<UINT8>(m_receiveBuffer, pos);
399  temp_xor = temp_xor ^ temp;
400  }
401 
402  // Vergleiche die Pruefsummen
403  if (temp_xor != checkSum)
404  {
405  printWarning("SickScanCommonNw::findFrameInReceiveBuffer: Wrong checksum, Frame discarded.");
407  return SopasEventMessage();
408  }
409 
410  return SopasEventMessage(m_receiveBuffer, CoLa_B, frameLen);
411  }
412 
413  // Return empty frame
414  return SopasEventMessage();
415  }
416 
417 
418 
425  {
426  m_tcp.write(buffer, len);
427  }
428 
429 
430 
431 
438  {
439 
440  if (m_protocol == CoLa_A)
441  {
442  printInfoMessage("SickScanCommonNw::processFrame: Calling processFrame_CoLa_A() with " + ::toString(frame.size()) + " bytes.", m_beVerbose);
443  // processFrame_CoLa_A(frame);
444  }
445  else if (m_protocol == CoLa_B)
446  {
447  printInfoMessage("SickScanCommonNw::processFrame: Calling processFrame_CoLa_B() with " + ::toString(frame.size()) + " bytes.", m_beVerbose);
448  // processFrame_CoLa_B(frame);
449  }
450  }
451 
452 
453 //
454 // Copies a complete frame - in any protocol - from the main input buffer to
455 // the response buffer.
456 // The frame is *not* removed from the main input buffer.
457 //
459  {
460  printInfoMessage("SickScanCommonNw::copyFrameToResposeBuffer: Copying a frame of " + ::toString(frameLength) +
461  " bytes to response buffer.", m_beVerbose);
462 
463  if (frameLength <= sizeof(m_responseBuffer))
464  {
465  // Wir duerfen kopieren
466  memcpy(m_responseBuffer, m_receiveBuffer, frameLength);
467  m_numberOfBytesInResponseBuffer = frameLength;
468  }
469  else
470  {
471  // Der respose-Buffer ist zu klein
472  printError("SickScanCommonNw::copyFrameToResposeBuffer: Failed to copy frame (Length=" + ::toString(frameLength) +
473  " bytes) to response buffer because the response buffer is too small (buffer size=" +
474  ::toString(sizeof(m_responseBuffer)) + " bytes).");
476  }
477  }
478 
479 
480 
481 //
482 // Removes a complete frame - in any protocol - from the main input buffer.
483 //
485  {
486  // Remove frame from receive buffer
487  if (frameLength < m_numberOfBytesInReceiveBuffer)
488  {
489  // More data in buffer, move them to the buffer start
490  UINT32 newLen = m_numberOfBytesInReceiveBuffer - frameLength;
491  printInfoMessage("SickScanCommonNw::removeFrameFromReceiveBuffer: Removing " + ::toString(frameLength) +
492  " bytes from the input buffer. New length is " + ::toString(newLen) + " bytes.", m_beVerbose);
493  memmove(m_receiveBuffer, &(m_receiveBuffer[frameLength]), newLen);
495  }
496  else
497  {
498  // No other data in buffer, just mark as empty
499  printInfoMessage("SickScanCommonNw::removeFrameFromReceiveBuffer: Done, no more data in input buffer.", m_beVerbose);
501  }
502  }
503 
504 
505 
506 //
507 // ************************* SOPAS FRAME ************************************************** //
508 //
510  m_buffer(NULL), m_protocol(CoLa_A), m_frameLength(0)
511  {
512  }
513 
514 
515 
517  m_buffer(buffer), m_protocol(protocol), m_frameLength(frameLength)
518  {
519 // Constructor
520  }
521 
522 
523 
525  {
526  UINT32 payLoadLength = 0;
527 
528  switch (m_protocol)
529  {
530  case CoLa_A:
531  payLoadLength = m_frameLength - 2; // everything except the 0x02 0x03 frame
532  break;
533  case CoLa_B:
534  payLoadLength = m_frameLength - 9; // everything except start 0x02020202(4byte), payloadLength(4byte) and checksum(1 byte)
535  }
536 
537  return payLoadLength;
538  }
539 
540 
548  {
549  std::string commandString;
550 
551  switch (m_protocol)
552  {
553  case CoLa_A:
554  commandString = std::string((char*) &m_buffer[2], 2);
555  break;
556  case CoLa_B:
557  commandString = std::string((char*) &m_buffer[9], 2);
558  }
559 
560  return commandString;
561  }
562 
563 
564 
573  {
574  BYTE* bufferPos = NULL;
575 
576  switch (m_protocol)
577  {
578  case CoLa_A:
579  bufferPos = &m_buffer[1];
580  break;
581  case CoLa_B:
582  bufferPos = &m_buffer[8];
583  break;
584  }
585 
586  return bufferPos;
587  }
588 
589 
597  {
598  BYTE* bufferPos = NULL;
599  bufferPos = &m_buffer[0];
600  return bufferPos;
601  }
602 
603 
604 
606  {
607  INT32 index = -1;
608 
609 
610  BYTE* bufferPos = &getPayLoad()[3];
611  switch (m_protocol)
612  {
613  case CoLa_A:
614  index = (INT32)(colaa::decodeUINT16(bufferPos));
615  break;
616  case CoLa_B:
617  index = (INT32)(colab::decodeUINT16(bufferPos));
618  break;
619  default:
620  printError("SopasEventMessage::getVariableIndex: Unknown protocol!");
621  }
622 
623  return index;
624  }
void printError(std::string message)
std::string getCommandString() const
Returns two character long command.
BYTE * getPayLoad()
contains &#39;s&#39; + command string(2 byte) + content(payload length - 3)
unsigned char BYTE
SopasEventMessage findFrameInReceiveBuffer()
uint16_t UINT16
bool init(std::string ipAddress, unsigned short portNumber, Tcp::DisconnectFunction disconnectFunction, void *obj)
void processFrame(SopasEventMessage &frame)
UINT8 m_responseBuffer[1024]
Receive buffer for everything except scan data and eval case data.
void sendCommandBuffer(UINT8 *buffer, UINT16 len)
UINT8 m_receiveBuffer[25000]
Low-Level receive buffer for all data (25000 should be enough for NAV300 Events)
UINT16 decodeUINT16(BYTE *buffer)
Definition: colab.cpp:142
UINT32 getPayLoadLength() const
contains &#39;s&#39; + command string(2 byte) + content(payload length - 3)
void(* DisconnectFunction)(void *obj)
Definition: tcp.hpp:53
#define printInfoMessage(a, b)
uint32_t UINT32
SopasProtocol m_protocol
bool setReadCallbackFunction(Tcp::ReadFunction readFunction, void *obj)
bool write(UINT8 *buffer, UINT32 numberOfBytes)
Definition: tcp.cpp:51
Interface for TCP/IP.
void copyFrameToResposeBuffer(UINT32 frameLength)
Command Language ASCI.
bool open(std::string ipAddress, UINT16 port, bool enableVerboseDebugOutput=false)
Definition: tcp.cpp:136
UINT32 size() const
BYTE * getRawData()
get SOPAS raw data include header and CRC
SopasProtocol m_protocol
bool isConnected()
Returns true if the tcp connection is established.
void(* ReadFunction)(void *obj, UINT8 *inputBuffer, UINT32 &numBytes)
Definition: tcp.hpp:49
UINT32 m_numberOfBytesInResponseBuffer
Number of bytes in buffer.
Command Language binary.
Object has been constructed. Use init() to go into CONNECTED state.
int32_t INT32
SopasEventMessage()
Default constructor.
Mutex m_receiveDataMutex
Access mutex for buffer.
Class that represents a message that was sent by a sensor. (Event message)
std::string toString(INT32 value)
Definition: toolbox.cpp:275
UINT32 m_numberOfBytesInReceiveBuffer
Number of bytes in buffer.
void removeFrameFromReceiveBuffer(UINT32 frameLength)
void readCallbackFunction(UINT8 *buffer, UINT32 &numOfBytes)
bool connect()
Connects to a sensor via tcp and reads the device name.
bool disconnect()
Closes the connection to the LMS. This is the opposite of init().
bool isOpen()
Definition: tcp.cpp:95
void setReadCallbackFunction(ReadFunction readFunction, void *obj)
Definition: tcp.cpp:110
void setDisconnectCallbackFunction(DisconnectFunction discFunction, void *obj)
Definition: tcp.cpp:82
void close()
Definition: tcp.cpp:326
SopasProtocol
static void readCallbackFunctionS(void *obj, UINT8 *buffer, UINT32 &numOfBytes)
Function that will be called on incomming data via tcp.
void printWarning(std::string message)
UINT16 decodeUINT16(BYTE *buffer)
Definition: colaa.cpp:627
uint8_t UINT8
INT32 getVariableIndex()
Returns the index of a variable (answer to read variable by index). In case of error a negative value...


sick_scan
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Tue Jul 9 2019 04:55:32