sick_scan_common_nw.cpp
Go to the documentation of this file.
00001 
00022 #include "sick_scan/sick_scan_common_nw.h"
00023 #include "sick_scan/tcp/colaa.hpp"
00024 #include "sick_scan/tcp/colab.hpp"
00025 #include "sick_scan/tcp/BasicDatatypes.hpp"
00026 #include "sick_scan/tcp/tcp.hpp"
00027 #include <map>  // for std::map
00028 
00029 #include "sick_scan/tcp/tcp.hpp"
00030 #include "sick_scan/tcp/errorhandler.hpp"
00031 #include "sick_scan/tcp/toolbox.hpp"
00032 #include "sick_scan/tcp/Mutex.hpp"
00033 #include <assert.h>
00034 
00035 SickScanCommonNw::SickScanCommonNw()
00036     {
00037       m_state = CONSTRUCTED;
00038       m_beVerbose = false;
00039 
00040     }
00041 
00042 SickScanCommonNw::~SickScanCommonNw()
00043     {
00044       // Disconnect and shut down receive thread.
00045       if (isConnected() == true)
00046       {
00047         // Change from CONNECTED to CONSTRUCTED
00048         disconnect();
00049       }
00050     }
00051 
00052 
00053 //
00054 // Disconnect from the scanner, and close the interface.
00055 //
00056 bool SickScanCommonNw::disconnect()
00057 {
00058   closeTcpConnection();
00059 
00060   // Change back to CONSTRUCTED
00061   m_state = CONSTRUCTED;
00062   return true;
00063 }
00064 
00065 
00066 //
00067 // Initialisation from Scanner class:
00068 // Parameter setup only. Afterwards, call connect() to connect to the scanner.
00069 //
00070     bool SickScanCommonNw::init(std::string ipAddress,
00071                          unsigned short portNumber,
00072                          Tcp::DisconnectFunction disconnectFunction,
00073                          void* obj)
00074     {
00075       m_ipAddress = ipAddress;
00076       m_portNumber = portNumber;
00077       m_tcp.setDisconnectCallbackFunction(disconnectFunction, obj);
00078       return true;
00079     }
00080 
00081 
00082     bool SickScanCommonNw::setReadCallbackFunction(Tcp::ReadFunction readFunction,
00083                                                    void* obj)
00084     {
00085           m_tcp.setReadCallbackFunction(readFunction, obj);
00086           return(true);
00087     }
00088 //
00089 // Verbinde mit dem unter init() eingestellten Geraet, und pruefe die Verbindung
00090 // durch einen DeviceIdent-Aufruf.
00091 //
00092 // true = Erfolgreich.
00093 //
00094 
00095 
00096     bool SickScanCommonNw::connect()
00097     {
00098 
00099       assert (m_state == CONSTRUCTED); // must not be opened or running already
00100 
00101       // Initialise buffer variables
00102       m_numberOfBytesInReceiveBuffer = 0; // Buffer is empty
00103       m_numberOfBytesInResponseBuffer = 0; // Buffer is empty
00104 
00105       // Establish connection here
00106       // Set the data input callback for our TCP connection
00107       // m_tcp.setReadCallbackFunction(&SickScanCommonNw::readCallbackFunctionS, this); // , this, _1, _2));
00108 
00109       bool success = openTcpConnection();
00110       if (success == true)
00111       {
00112         // Check if scanner type matches
00113         m_state = CONNECTED;
00114 
00115       }
00116       return success;
00117     }
00118 
00119 
00120 
00121 //
00122 // True, if state is CONNECTED, that is:
00123 // - A TCP-connection exists
00124 // - Read thread is running
00125 //
00126     bool SickScanCommonNw::isConnected()
00127     {
00128       return (m_state == CONNECTED);
00129     }
00130 
00131 
00132 
00133 
00134 
00140     bool SickScanCommonNw::openTcpConnection()
00141     {
00142      //  printInfoMessage("SickScanCommonNw::openTcpConnection: Connecting TCP/IP connection to " + m_ipAddress + ":" + toString(m_portNumber) + " ...", m_beVerbose);
00143 
00144       bool success = m_tcp.open(m_ipAddress, m_portNumber, m_beVerbose);
00145       if (success == false)
00146       {
00147         // printError("SickScanCommonNw::openTcpConnection: ERROR: Failed to establish TCP connection, aborting!");
00148         return false;
00149       }
00150 
00151       return true;
00152     }
00153 
00154 
00155 
00156 //
00157 // Close TCP-connection and shut down read thread
00158 //
00159     void SickScanCommonNw::closeTcpConnection()
00160     {
00161       if (m_tcp.isOpen())
00162       {
00163         m_tcp.close();
00164       }
00165     }
00166 
00167 //
00168 // Static entry point.
00169 //
00170     void SickScanCommonNw::readCallbackFunctionS(void* obj, UINT8* buffer, UINT32& numOfBytes)
00171     {
00172       ((SickScanCommonNw*)obj)->readCallbackFunction(buffer, numOfBytes);
00173     }
00174 
00175 
00180     void SickScanCommonNw::readCallbackFunction(UINT8* buffer, UINT32& numOfBytes)
00181     {
00182       bool beVerboseHere = false;
00183       printInfoMessage("SickScanCommonNw::readCallbackFunction(): Called with " + toString(numOfBytes) + " available bytes.", beVerboseHere);
00184 
00185       ScopedLock lock(&m_receiveDataMutex); // Mutex for access to the input buffer
00186       UINT32 remainingSpace = sizeof(m_receiveBuffer) - m_numberOfBytesInReceiveBuffer;
00187       UINT32 bytesToBeTransferred = numOfBytes;
00188       if (remainingSpace < numOfBytes)
00189       {
00190         bytesToBeTransferred = remainingSpace;
00191         // printWarning("SickScanCommonNw::readCallbackFunction(): Input buffer space is to small, transferring only " +
00192         //              ::toString(bytesToBeTransferred) + " of " + ::toString(numOfBytes) + " bytes.");
00193       }
00194       else
00195       {
00196         // printInfoMessage("SickScanCommonNw::readCallbackFunction(): Transferring " + ::toString(bytesToBeTransferred) +
00197         //                   " bytes from TCP to input buffer.", beVerboseHere);
00198       }
00199 
00200       if (bytesToBeTransferred > 0)
00201       {
00202         // Data can be transferred into our input buffer
00203         memcpy(&(m_receiveBuffer[m_numberOfBytesInReceiveBuffer]), buffer, bytesToBeTransferred);
00204         m_numberOfBytesInReceiveBuffer += bytesToBeTransferred;
00205 
00206         UINT32 size = 0;
00207 
00208         while (1)
00209         {
00210           // Now work on the input buffer until all received datasets are processed
00211            SopasEventMessage frame = findFrameInReceiveBuffer();
00212 
00213           size = frame.size();
00214           if (size == 0)
00215           {
00216             // Framesize = 0: There is no valid frame in the buffer. The buffer is either empty or the frame
00217             // is incomplete, so leave the loop
00218             printInfoMessage("SickScanCommonNw::readCallbackFunction(): No complete frame in input buffer, we are done.", beVerboseHere);
00219 
00220             // Leave the loop
00221             break;
00222           }
00223           else
00224           {
00225             // A frame was found in the buffer, so process it now.
00226             printInfoMessage("SickScanCommonNw::readCallbackFunction(): Processing a frame of length " + ::toString(frame.size()) + " bytes.", beVerboseHere);
00227              processFrame(frame);
00228           }
00229         }
00230       }
00231       else
00232       {
00233         // There was input data from the TCP interface, but our input buffer was unable to hold a single byte.
00234         // Either we have not read data from our buffer for a long time, or something has gone wrong. To re-sync,
00235         // we clear the input buffer here.
00236         m_numberOfBytesInReceiveBuffer = 0;
00237       }
00238 
00239     }
00240 
00241 
00242 
00243 //
00244 // Look for 23-frame (STX/ETX) in receive buffer.
00245 // Move frame to start of buffer
00246 //
00247 // Return: 0 : No (complete) frame found
00248 //        >0 : Frame length
00249 //
00250     SopasEventMessage SickScanCommonNw::findFrameInReceiveBuffer()
00251     {
00252       UINT32 frameLen = 0;
00253       UINT32 i;
00254 
00255       // Depends on protocol...
00256       if (m_protocol == CoLa_A)
00257       {
00258         //
00259         // COLA-A
00260         //
00261         // Must start with STX (0x02)
00262         if (m_receiveBuffer[0] != 0x02)
00263         {
00264           // Look for starting STX (0x02)
00265           for (i = 1; i < m_numberOfBytesInReceiveBuffer; i++)
00266           {
00267             if (m_receiveBuffer[i] == 0x02)
00268             {
00269               break;
00270             }
00271           }
00272 
00273           // Found beginning of frame?
00274           if (i >= m_numberOfBytesInReceiveBuffer)
00275           {
00276             // No start found, everything can be discarded
00277             m_numberOfBytesInReceiveBuffer = 0; // Invalidate buffer
00278             return SopasEventMessage(); // No frame found
00279           }
00280 
00281           // Move frame start to index 0
00282           UINT32 newLen = m_numberOfBytesInReceiveBuffer - i;
00283           memmove(&(m_receiveBuffer[0]), &(m_receiveBuffer[i]), newLen);
00284           m_numberOfBytesInReceiveBuffer = newLen;
00285         }
00286 
00287         // Look for ending ETX (0x03)
00288         for (i = 1; i < m_numberOfBytesInReceiveBuffer; i++)
00289         {
00290           if (m_receiveBuffer[i] == 0x03)
00291           {
00292             break;
00293           }
00294         }
00295 
00296         // Found end?
00297         if (i >= m_numberOfBytesInReceiveBuffer)
00298         {
00299           // No end marker found, so it's not a complete frame (yet)
00300           return SopasEventMessage(); // No frame found
00301         }
00302 
00303         // Calculate frame length in byte
00304         frameLen = i + 1;
00305 
00306         return SopasEventMessage(m_receiveBuffer, CoLa_A, frameLen);
00307       }
00308       else if (m_protocol == CoLa_B)
00309       {
00310         UINT32 magicWord;
00311         UINT32 payloadlength;
00312 
00313         if (m_numberOfBytesInReceiveBuffer < 4)
00314         {
00315           return SopasEventMessage();
00316         }
00317         UINT16 pos = 0;
00318         magicWord = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
00319         if (magicWord != 0x02020202)
00320         {
00321           // Look for starting STX (0x02020202)
00322           for (i = 1; i <= m_numberOfBytesInReceiveBuffer - 4; i++)
00323           {
00324             pos = i; // this is needed, as the position value is updated by getIntegerFromBuffer
00325             magicWord = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
00326             if (magicWord == 0x02020202)
00327             {
00328               // found magic word
00329               break;
00330             }
00331           }
00332 
00333           // Found beginning of frame?
00334           if (i > m_numberOfBytesInReceiveBuffer - 4)
00335           {
00336             // No start found, everything can be discarded
00337             m_numberOfBytesInReceiveBuffer = 0; // Invalidate buffer
00338             return SopasEventMessage(); // No frame found
00339           }
00340           else
00341           {
00342             // Move frame start to index
00343             UINT32 bytesToMove = m_numberOfBytesInReceiveBuffer - i;
00344             memmove(&(m_receiveBuffer[0]), &(m_receiveBuffer[i]), bytesToMove); // payload+magic+length+s+checksum
00345             m_numberOfBytesInReceiveBuffer = bytesToMove;
00346           }
00347         }
00348 
00349         // Pruefe Laenge des Pufferinhalts
00350         if (m_numberOfBytesInReceiveBuffer < 9)
00351         {
00352           // Es sind nicht genug Daten fuer einen Frame
00353           printInfoMessage("SickScanCommonNw::findFrameInReceiveBuffer: Frame cannot be decoded yet, only " +
00354                            ::toString(m_numberOfBytesInReceiveBuffer) + " bytes in the buffer.", m_beVerbose);
00355           return SopasEventMessage();
00356         }
00357 
00358         // Read length of payload
00359         pos = 4;
00360         payloadlength = colab::getIntegerFromBuffer<UINT32>(m_receiveBuffer, pos);
00361         printInfoMessage("SickScanCommonNw::findFrameInReceiveBuffer: Decoded payload length is " + ::toString(payloadlength) + " bytes.", m_beVerbose);
00362 
00363         // Ist die Datenlaenge plausibel und wuede in den Puffer passen?
00364         if (payloadlength > (sizeof(m_receiveBuffer) - 9))
00365         {
00366           // magic word + length + checksum = 9
00367           printWarning("SickScanCommonNw::findFrameInReceiveBuffer: Frame too big for receive buffer. Frame discarded with length:"
00368                        + ::toString(payloadlength) + ".");
00369           m_numberOfBytesInReceiveBuffer = 0;
00370           return SopasEventMessage();
00371         }
00372         if ((payloadlength + 9) > m_numberOfBytesInReceiveBuffer)
00373         {
00374           // magic word + length + s + checksum = 10
00375           printInfoMessage("SickScanCommonNw::findFrameInReceiveBuffer: Frame not complete yet. Waiting for the rest of it (" +
00376                            ::toString(payloadlength + 9 - m_numberOfBytesInReceiveBuffer) + " bytes missing).", m_beVerbose);
00377           return SopasEventMessage(); // frame not complete
00378         }
00379 
00380         // Calculate the total frame length in bytes: Len = Frame (9 bytes) + Payload
00381         frameLen = payloadlength + 9;
00382 
00383         //
00384         // test checksum of payload
00385         //
00386         UINT8 temp = 0;
00387         UINT8 temp_xor = 0;
00388         UINT8 checkSum;
00389 
00390         // Read original checksum
00391         pos = frameLen - 1;
00392         checkSum = colab::getIntegerFromBuffer<UINT8>(m_receiveBuffer, pos);
00393 
00394         // Erzeuge die Pruefsumme zum Vergleich
00395         for (UINT16 i = 8; i < (frameLen - 1); i++)
00396         {
00397           pos = i;
00398           temp = colab::getIntegerFromBuffer<UINT8>(m_receiveBuffer, pos);
00399           temp_xor = temp_xor ^ temp;
00400         }
00401 
00402         // Vergleiche die Pruefsummen
00403         if (temp_xor != checkSum)
00404         {
00405           printWarning("SickScanCommonNw::findFrameInReceiveBuffer: Wrong checksum, Frame discarded.");
00406           m_numberOfBytesInReceiveBuffer = 0;
00407           return SopasEventMessage();
00408         }
00409 
00410         return SopasEventMessage(m_receiveBuffer, CoLa_B, frameLen);
00411       }
00412 
00413       // Return empty frame
00414       return SopasEventMessage();
00415     }
00416 
00417 
00418 
00424     void SickScanCommonNw::sendCommandBuffer(UINT8* buffer, UINT16 len)
00425     {
00426       m_tcp.write(buffer, len);
00427     }
00428 
00429 
00430 
00431 
00437     void SickScanCommonNw::processFrame(SopasEventMessage& frame)
00438     {
00439 
00440       if (m_protocol == CoLa_A)
00441       {
00442         printInfoMessage("SickScanCommonNw::processFrame: Calling processFrame_CoLa_A() with " + ::toString(frame.size()) + " bytes.", m_beVerbose);
00443        // processFrame_CoLa_A(frame);
00444       }
00445       else if (m_protocol == CoLa_B)
00446       {
00447         printInfoMessage("SickScanCommonNw::processFrame: Calling processFrame_CoLa_B() with " + ::toString(frame.size()) + " bytes.", m_beVerbose);
00448        // processFrame_CoLa_B(frame);
00449       }
00450     }
00451 
00452 
00453 //
00454 // Copies a complete frame - in any protocol - from the main input buffer to
00455 // the response buffer.
00456 // The frame is *not* removed from the main input buffer.
00457 //
00458     void SickScanCommonNw::copyFrameToResposeBuffer(UINT32 frameLength)
00459     {
00460       printInfoMessage("SickScanCommonNw::copyFrameToResposeBuffer: Copying a frame of " + ::toString(frameLength) +
00461                        " bytes to response buffer.", m_beVerbose);
00462 
00463       if (frameLength <= sizeof(m_responseBuffer))
00464       {
00465         // Wir duerfen kopieren
00466         memcpy(m_responseBuffer, m_receiveBuffer, frameLength);
00467         m_numberOfBytesInResponseBuffer = frameLength;
00468       }
00469       else
00470       {
00471         // Der respose-Buffer ist zu klein
00472         printError("SickScanCommonNw::copyFrameToResposeBuffer: Failed to copy frame (Length=" + ::toString(frameLength) +
00473                    " bytes) to response buffer because the response buffer is too small (buffer size=" +
00474                    ::toString(sizeof(m_responseBuffer)) + " bytes).");
00475         m_numberOfBytesInResponseBuffer = 0;
00476       }
00477     }
00478 
00479 
00480 
00481 //
00482 // Removes a complete frame - in any protocol - from the main input buffer.
00483 //
00484     void SickScanCommonNw::removeFrameFromReceiveBuffer(UINT32 frameLength)
00485     {
00486       // Remove frame from receive buffer
00487       if (frameLength < m_numberOfBytesInReceiveBuffer)
00488       {
00489         // More data in buffer, move them to the buffer start
00490         UINT32 newLen = m_numberOfBytesInReceiveBuffer - frameLength;
00491         printInfoMessage("SickScanCommonNw::removeFrameFromReceiveBuffer: Removing " + ::toString(frameLength) +
00492                          " bytes from the input buffer. New length is " + ::toString(newLen) + " bytes.", m_beVerbose);
00493         memmove(m_receiveBuffer, &(m_receiveBuffer[frameLength]), newLen);
00494         m_numberOfBytesInReceiveBuffer = newLen;
00495       }
00496       else
00497       {
00498         // No other data in buffer, just mark as empty
00499         printInfoMessage("SickScanCommonNw::removeFrameFromReceiveBuffer: Done, no more data in input buffer.", m_beVerbose);
00500         m_numberOfBytesInReceiveBuffer = 0;
00501       }
00502     }
00503 
00504 
00505 
00506 //
00507 // ************************* SOPAS FRAME ************************************************** //
00508 //
00509     SopasEventMessage::SopasEventMessage() :
00510             m_buffer(NULL), m_protocol(CoLa_A), m_frameLength(0)
00511     {
00512     }
00513 
00514 
00515 
00516     SopasEventMessage::SopasEventMessage(BYTE* buffer, SopasProtocol protocol, UINT32 frameLength) :
00517             m_buffer(buffer), m_protocol(protocol), m_frameLength(frameLength)
00518     {
00519 //      Constructor
00520     }
00521 
00522 
00523 
00524     UINT32 SopasEventMessage::getPayLoadLength() const
00525     {
00526       UINT32 payLoadLength = 0;
00527 
00528       switch (m_protocol)
00529       {
00530         case CoLa_A:
00531           payLoadLength = m_frameLength - 2; // everything except the 0x02 0x03 frame
00532           break;
00533         case CoLa_B:
00534           payLoadLength = m_frameLength - 9; // everything except start 0x02020202(4byte), payloadLength(4byte) and checksum(1 byte)
00535       }
00536 
00537       return payLoadLength;
00538     }
00539 
00540 
00547     std::string SopasEventMessage::getCommandString() const
00548     {
00549       std::string commandString;
00550 
00551       switch (m_protocol)
00552       {
00553         case CoLa_A:
00554           commandString = std::string((char*) &m_buffer[2], 2);
00555           break;
00556         case CoLa_B:
00557           commandString = std::string((char*) &m_buffer[9], 2);
00558       }
00559 
00560       return commandString;
00561     }
00562 
00563 
00564 
00572     BYTE* SopasEventMessage::getPayLoad()
00573     {
00574       BYTE* bufferPos = NULL;
00575 
00576       switch (m_protocol)
00577       {
00578         case CoLa_A:
00579           bufferPos = &m_buffer[1];
00580           break;
00581         case CoLa_B:
00582           bufferPos = &m_buffer[8];
00583           break;
00584       }
00585 
00586       return bufferPos;
00587     }
00588 
00589 
00596         BYTE* SopasEventMessage::getRawData()
00597         {
00598                 BYTE* bufferPos = NULL;
00599                 bufferPos = &m_buffer[0];
00600                 return bufferPos;
00601         }
00602 
00603 
00604 
00605     INT32 SopasEventMessage::getVariableIndex()
00606     {
00607       INT32 index = -1;
00608 
00609 
00610       BYTE* bufferPos = &getPayLoad()[3];
00611       switch (m_protocol)
00612       {
00613         case CoLa_A:
00614           index = (INT32)(colaa::decodeUINT16(bufferPos));
00615           break;
00616         case CoLa_B:
00617           index = (INT32)(colab::decodeUINT16(bufferPos));
00618           break;
00619         default:
00620           printError("SopasEventMessage::getVariableIndex: Unknown protocol!");
00621       }
00622 
00623       return index;
00624     }


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