sick_scan_common.cpp
Go to the documentation of this file.
00001 
00052 #ifdef _MSC_VER // compiling simulation for MS-Visual C++ - not defined for linux system
00053 #pragma warning(disable: 4996)
00054 #pragma warning(disable: 4267) // due to conversion warning size_t in the ros header file
00055 #define _WIN32_WINNT 0x0501
00056 
00057 #endif
00058 
00059 #include <sick_scan/sick_scan_common_nw.h>
00060 #include <sick_scan/sick_scan_common.h>
00061 #include <sick_scan/sick_generic_radar.h>
00062 
00063 #include <sick_scan/sick_scan_config_internal.h>
00064 
00065 #ifdef _MSC_VER
00066 #include "sick_scan/rosconsole_simu.hpp"
00067 #endif
00068 
00069 #include "sick_scan/binScanf.hpp"
00070 // if there is a missing RadarScan.h, try to run catkin_make in der workspace-root
00071 #include <sick_scan/RadarScan.h>
00072 
00073 
00074 #include <cstdio>
00075 #include <cstring>
00076 
00077 #define _USE_MATH_DEFINES
00078 
00079 #include <math.h>
00080 
00081 #ifndef rad2deg
00082 #define rad2deg(x) ((x) / M_PI * 180.0)
00083 #endif
00084 
00085 #define deg2rad_const (0.017453292519943295769236907684886f)
00086 
00087 #include "sick_scan/tcp/colaa.hpp"
00088 #include "sick_scan/tcp/colab.hpp"
00089 
00090 #include <map>
00091 #include <climits>
00092 #include <sick_scan/sick_generic_imu.h>
00093 
00099 void swap_endian(unsigned char *ptr, int numBytes)
00100 {
00101   unsigned char *buf = (ptr);
00102   unsigned char tmpChar;
00103   for (int i = 0; i < numBytes / 2; i++)
00104   {
00105     tmpChar = buf[numBytes - 1 - i];
00106     buf[numBytes - 1 - i] = buf[i];
00107     buf[i] = tmpChar;
00108   }
00109 }
00110 
00111 
00119 std::vector<unsigned char> stringToVector(std::string s)
00120 {
00121   std::vector<unsigned char> result;
00122   for (int j = 0; j < s.length(); j++)
00123   {
00124     result.push_back(s[j]);
00125   }
00126   return result;
00127 
00128 }
00129 
00130 
00136 static int getDiagnosticErrorCode() // workaround due to compiling error under Visual C++
00137 {
00138 #ifdef _MSC_VER
00139 #undef ERROR
00140   return(2);
00141 #else
00142   return (diagnostic_msgs::DiagnosticStatus::ERROR);
00143 #endif
00144 }
00145 
00153 const std::string binScanfGetStringFromVec(std::vector<unsigned char> *replyDummy, int off, long len)
00154 {
00155   std::string s;
00156   s = "";
00157   for (int i = 0; i < len; i++)
00158   {
00159     char ch = (char) ((*replyDummy)[i + off]);
00160     s += ch;
00161   }
00162   return (s);
00163 }
00164 
00165 namespace sick_scan
00166 {
00174   unsigned char sick_crc8(unsigned char *msgBlock, int len)
00175   {
00176     unsigned char xorVal = 0x00;
00177     int off = 0;
00178     for (int i = off; i < len; i++)
00179     {
00180 
00181       unsigned char val = msgBlock[i];
00182       xorVal ^= val;
00183     }
00184     return (xorVal);
00185   }
00186 
00192   std::string stripControl(std::vector<unsigned char> s)
00193   {
00194     bool isParamBinary = false;
00195     int spaceCnt = 0x00;
00196     int  cnt0x02 = 0;
00197 
00198     for (int i = 0; i < s.size(); i++)
00199     {
00200       if (s[i] != 0x02)
00201       {
00202         isParamBinary = false;
00203 
00204       }
00205       else
00206       {
00207         cnt0x02++;
00208       }
00209       if (i > 4)
00210       {
00211         break;
00212       }
00213     }
00214     if (4 == cnt0x02)
00215     {
00216       isParamBinary = true;
00217     }
00218     std::string dest;
00219     if (isParamBinary == true)
00220     {
00221        int parseState = 0;
00222 
00223        unsigned long lenId = 0x00;
00224        char szDummy[255] = {0};
00225        for (int i = 0; i < s.size(); i++)
00226        {
00227           switch(parseState)
00228           {
00229             case 0:
00230               if (s[i] == 0x02)
00231               {
00232                 dest += "<STX>";
00233               }
00234               else
00235               {
00236                 dest += "?????";
00237               }
00238               if (i == 3)
00239               {
00240                 parseState = 1;
00241               }
00242               break;
00243             case 1:
00244               lenId |= s[i] << (8 * (7 - i));
00245               if (i == 7)
00246               {
00247                 sprintf(szDummy, "<Len=%04lu>", lenId);
00248                 dest += szDummy;
00249                 parseState = 2;
00250               }
00251               break;
00252             case 2:
00253             {
00254               unsigned long dataProcessed = i - 8;
00255               if (s[i] == ' ')
00256               {
00257                 spaceCnt++;
00258               }
00259               if (spaceCnt == 2)
00260               {
00261                 parseState = 3;
00262               }
00263               dest += s[i];
00264               if (dataProcessed >= (lenId - 1))
00265               {
00266                 parseState = 4;
00267               }
00268 
00269               break;
00270             }
00271 
00272             case 3:
00273             {
00274               char ch = dest[dest.length()-1];
00275               if (ch != ' ')
00276               {
00277                 dest += ' ';
00278               }
00279               sprintf(szDummy, "0x%02x", s[i]);
00280               dest += szDummy;
00281 
00282               unsigned long dataProcessed = i - 8;
00283               if (dataProcessed >= (lenId -1))
00284               {
00285                 parseState = 4;
00286               }
00287               break;
00288             }
00289             case 4:
00290             {
00291               sprintf(szDummy, " CRC:<0x%02x>", s[i]);
00292               dest += szDummy;
00293               break;
00294             }
00295             default:
00296               break;
00297           }
00298        }
00299     }
00300     else
00301     {
00302       for (int i = 0; i < s.size(); i++)
00303       {
00304 
00305         if (s[i] >= ' ')
00306         {
00307           // <todo> >= 0x80
00308           dest += s[i];
00309         }
00310         else
00311         {
00312           switch (s[i])
00313           {
00314             case 0x02:
00315               dest += "<STX>";
00316               break;
00317             case 0x03:
00318               dest += "<ETX>";
00319               break;
00320           }
00321         }
00322       }
00323     }
00324 
00325     return(dest);
00326   }
00327 
00332   SickScanCommon::SickScanCommon(SickGenericParser *parser) :
00333       diagnosticPub_(NULL), parser_(parser)
00334   // FIXME All Tims have 15Hz
00335   {
00336     expectedFrequency_ = this->parser_->getCurrentParamPtr()->getExpectedFrequency();
00337 
00338     setSensorIsRadar(false);
00339     init_cmdTables();
00340 #ifndef _MSC_VER
00341     dynamic_reconfigure::Server<sick_scan::SickScanConfig>::CallbackType f;
00342     f = boost::bind(&sick_scan::SickScanCommon::update_config, this, _1, _2);
00343     dynamic_reconfigure_server_.setCallback(f);
00344 #else
00345     // For simulation under MS Visual c++ the update config is switched off
00346     {
00347       SickScanConfig cfg;
00348       ros::NodeHandle tmp("~");
00349       double min_angle, max_angle, res_angle;
00350       tmp.getParam(PARAM_MIN_ANG, min_angle);
00351       tmp.getParam(PARAM_MAX_ANG, max_angle);
00352       tmp.getParam(PARAM_RES_ANG, res_angle);
00353       cfg.min_ang = min_angle;
00354       cfg.max_ang = max_angle;
00355       cfg.skip = 0;
00356       update_config(cfg);
00357     }
00358 #endif
00359     // datagram publisher (only for debug)
00360     ros::NodeHandle pn("~");
00361     pn.param<bool>("publish_datagram", publish_datagram_, false);
00362     if (publish_datagram_)
00363     {
00364       datagram_pub_ = nh_.advertise<std_msgs::String>("datagram", 1000);
00365     }
00366 
00367 
00368     // Pointcloud2 publisher
00369     //
00370 
00371 
00372     std::string cloud_topic_val = "cloud";
00373     pn.getParam("cloud_topic", cloud_topic_val);
00374 
00375     ROS_INFO("Publishing laserscan-pointcloud2 to %s", cloud_topic_val.c_str());
00376     cloud_pub_ = nh_.advertise<sensor_msgs::PointCloud2>(cloud_topic_val, 100);
00377 
00378     // just for debugging, but very helpful for the start
00379     cloud_radar_rawtarget_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud_radar_rawtarget", 100);
00380     cloud_radar_track_pub_ = nh_.advertise<sensor_msgs::PointCloud2>("cloud_radar_track", 100);
00381 
00382     radarScan_pub_ = nh_.advertise<sick_scan::RadarScan>("radar", 100);
00383     imuScan_pub_ = nh_.advertise<sensor_msgs::Imu>("imu", 100);
00384     // scan publisher
00385     pub_ = nh_.advertise<sensor_msgs::LaserScan>("scan", 1000);
00386 
00387 #ifndef _MSC_VER
00388     diagnostics_.setHardwareID("none");   // set from device after connection
00389     diagnosticPub_ = new diagnostic_updater::DiagnosedPublisher<sensor_msgs::LaserScan>(pub_, diagnostics_,
00390         // frequency should be target +- 10%.
00391                                                                                         diagnostic_updater::FrequencyStatusParam(
00392                                                                                             &expectedFrequency_,
00393                                                                                             &expectedFrequency_, 0.1,
00394                                                                                             10),
00395         // timestamp delta can be from 0.0 to 1.3x what it ideally is.
00396                                                                                         diagnostic_updater::TimeStampStatusParam(
00397                                                                                             -1, 1.3 * 1.0 /
00398                                                                                                 expectedFrequency_ -
00399                                                                                                 config_.time_offset));
00400     ROS_ASSERT(diagnosticPub_ != NULL);
00401 #endif
00402   }
00403 
00408   int SickScanCommon::stop_scanner()
00409   {
00410     /*
00411      * Stop streaming measurements
00412      */
00413     const char requestScanData0[] = {"\x02sEN LMDscandata 0\x03\0"};
00414     int result = sendSOPASCommand(requestScanData0, NULL);
00415     if (result != 0)
00416     {
00417       // use printf because we cannot use ROS_ERROR from the destructor
00418       printf("\nSOPAS - Error stopping streaming scan data!\n");
00419     }
00420     else
00421     {
00422       printf("\nSOPAS - Stopped streaming scan data.\n");
00423     }
00424 
00425     return result;
00426   }
00427 
00433   unsigned long SickScanCommon::convertBigEndianCharArrayToUnsignedLong(const unsigned char *vecArr)
00434   {
00435     unsigned long val = 0;
00436     for (int i = 0; i < 4; i++)
00437     {
00438       val = val << 8;
00439       val |= vecArr[i];
00440     }
00441     return (val);
00442   }
00443 
00444 
00450   int sick_scan::SickScanCommon::checkForBinaryAnswer(const std::vector<unsigned char> *reply)
00451   {
00452     int retVal = -1;
00453 
00454     if (reply == NULL)
00455     {
00456     }
00457     else
00458     {
00459       if (reply->size() < 8)
00460       {
00461         retVal = -1;
00462       }
00463       else
00464       {
00465         const unsigned char *ptr = &((*reply)[0]);
00466         unsigned binId = convertBigEndianCharArrayToUnsignedLong(ptr);
00467         unsigned cmdLen = convertBigEndianCharArrayToUnsignedLong(ptr + 4);
00468         if (binId == 0x02020202)
00469         {
00470           int replyLen = reply->size();
00471           if (replyLen == 8 + cmdLen + 1)
00472           {
00473             retVal = cmdLen;
00474           }
00475         }
00476       }
00477     }
00478     return (retVal);
00479 
00480   }
00481 
00482 
00487   bool SickScanCommon::rebootScanner()
00488   {
00489     /*
00490      * Set Maintenance access mode to allow reboot to be sent
00491      */
00492     std::vector<unsigned char> access_reply;
00493     // changed from "03" to "3"
00494     int result = sendSOPASCommand("\x02sMN SetAccessMode 3 F4724744\x03\0", &access_reply);
00495     if (result != 0)
00496     {
00497       ROS_ERROR("SOPAS - Error setting access mode");
00498       diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error setting access mode.");
00499       return false;
00500     }
00501     std::string access_reply_str = replyToString(access_reply);
00502     if (access_reply_str != "sAN SetAccessMode 1")
00503     {
00504       ROS_ERROR_STREAM("SOPAS - Error setting access mode, unexpected response : " << access_reply_str);
00505       diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error setting access mode.");
00506       return false;
00507     }
00508 
00509     /*
00510      * Send reboot command
00511      */
00512     std::vector<unsigned char> reboot_reply;
00513     result = sendSOPASCommand("\x02sMN mSCreboot\x03\0", &reboot_reply);
00514     if (result != 0)
00515     {
00516       ROS_ERROR("SOPAS - Error rebooting scanner");
00517       diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error rebooting device.");
00518       return false;
00519     }
00520     std::string reboot_reply_str = replyToString(reboot_reply);
00521     if (reboot_reply_str != "sAN mSCreboot")
00522     {
00523       ROS_ERROR_STREAM("SOPAS - Error rebooting scanner, unexpected response : " << reboot_reply_str);
00524       diagnostics_.broadcast(getDiagnosticErrorCode(), "SOPAS - Error setting access mode.");
00525       return false;
00526     }
00527 
00528     ROS_INFO("SOPAS - Rebooted scanner");
00529 
00530     // Wait a few seconds after rebooting
00531     ros::Duration(15.0).sleep();
00532 
00533     return true;
00534   }
00535 
00539   SickScanCommon::~SickScanCommon()
00540   {
00541     delete diagnosticPub_;
00542 
00543     printf("sick_scan driver exiting.\n");
00544   }
00545 
00546 
00552   std::string SickScanCommon::generateExpectedAnswerString(const std::vector<unsigned char> requestStr)
00553   {
00554     std::string expectedAnswer = "";
00555     int i = 0;
00556     char cntWhiteCharacter = 0;
00557     int initalTokenCnt = 2; // number of initial token to identify command
00558     std::map<std::string, int> specialTokenLen;
00559     char firstToken[1024] = {0};
00560     specialTokenLen["sRI"] = 1; // for SRi-Command only the first token identify the command
00561     std::string tmpStr = "";
00562     int cnt0x02 = 0;
00563     bool isBinary = false;
00564     for (int i = 0; i < 4; i++)
00565     {
00566       if (i < requestStr.size())
00567       {
00568         if (requestStr[i] == 0x02)
00569         {
00570           cnt0x02++;
00571         }
00572 
00573       }
00574     }
00575 
00576     int iStop = requestStr.size();  // copy string until end of string
00577     if (cnt0x02 == 4)
00578     {
00579 
00580       int cmdLen = 0;
00581       for (int i = 0; i < 4; i++)
00582       {
00583         cmdLen |= cmdLen << 8;
00584         cmdLen |= requestStr[i + 4];
00585       }
00586       iStop = cmdLen + 8;
00587       isBinary = true;
00588 
00589     }
00590     int iStart = (isBinary == true) ? 8 : 0;
00591     for (int i = iStart; i < iStop; i++)
00592     {
00593       tmpStr += (char) requestStr[i];
00594     }
00595     if (isBinary)
00596     {
00597       tmpStr = "\x2" + tmpStr;
00598     }
00599     if (sscanf(tmpStr.c_str(), "\x2%s", firstToken) == 1)
00600     {
00601       if (specialTokenLen.find(firstToken) != specialTokenLen.end())
00602       {
00603         initalTokenCnt = specialTokenLen[firstToken];
00604 
00605       }
00606     }
00607 
00608     for (int i = iStart; i < iStop; i++)
00609     {
00610       if ((requestStr[i] == ' ') || (requestStr[i] == '\x3'))
00611       {
00612         cntWhiteCharacter++;
00613       }
00614       if (cntWhiteCharacter >= initalTokenCnt)
00615       {
00616         break;
00617       }
00618       if (requestStr[i] == '\x2')
00619       {
00620       }
00621       else
00622       {
00623         expectedAnswer += requestStr[i];
00624       }
00625     }
00626 
00630     std::map<std::string, std::string> keyWordMap;
00631     keyWordMap["sWN"] = "sWA";
00632     keyWordMap["sRN"] = "sRA";
00633     keyWordMap["sRI"] = "sRA";
00634     keyWordMap["sMN"] = "sAN";
00635     keyWordMap["sEN"] = "sEA";
00636 
00637     for (std::map<std::string, std::string>::iterator it = keyWordMap.begin(); it != keyWordMap.end(); it++)
00638     {
00639 
00640       std::string keyWord = it->first;
00641       std::string newKeyWord = it->second;
00642 
00643       size_t pos = expectedAnswer.find(keyWord);
00644       if (pos == std::string::npos)
00645       {
00646 
00647       }
00648       else
00649       {
00650         if (pos == 0)  // must be 0, if keyword has been found
00651         {
00652           expectedAnswer.replace(pos, keyWord.length(), newKeyWord);
00653         }
00654         else
00655         {
00656           ROS_WARN("Unexpected position of key identifier.\n");
00657         }
00658       }
00659 
00660     }
00661     return (expectedAnswer);
00662 
00663   }
00664 
00672   int SickScanCommon::sendSopasAndCheckAnswer(std::string requestStr, std::vector<unsigned char> *reply, int cmdId = -1)
00673   {
00674     std::vector<unsigned char> requestStringVec;
00675     for (int i = 0; i < requestStr.length(); i++)
00676     {
00677       requestStringVec.push_back(requestStr[i]);
00678     }
00679     int retCode = sendSopasAndCheckAnswer(requestStringVec, reply, cmdId);
00680     return (retCode);
00681   }
00682 
00690   int SickScanCommon::sendSopasAndCheckAnswer(std::vector<unsigned char> requestStr, std::vector<unsigned char> *reply,
00691                                               int cmdId = -1)
00692   {
00693 
00694     std::string cmdStr = "";
00695     int cmdLen = 0;
00696     for (int i = 0; i < requestStr.size(); i++)
00697     {
00698       cmdLen++;
00699       cmdStr += (char) requestStr[i];
00700     }
00701     int result = -1;
00702 
00703     std::string errString;
00704     if (cmdId == -1)
00705     {
00706       errString = "Error unexpected Sopas Answer for request " + stripControl(requestStr);
00707     }
00708     else
00709     {
00710       errString = this->sopasCmdErrMsg[cmdId];
00711     }
00712 
00713     std::string expectedAnswer = generateExpectedAnswerString(requestStr);
00714 
00715     // send sopas cmd
00716 
00717     std::string reqStr = replyToString(requestStr);
00718     ROS_INFO("Sending  : %s", stripControl(requestStr).c_str());
00719     result = sendSOPASCommand(cmdStr.c_str(), reply, cmdLen);
00720     std::string replyStr = replyToString(*reply);
00721     std::vector<unsigned char> replyVec;
00722     replyStr = "<STX>" + replyStr + "<ETX>";
00723     replyVec=stringToVector(replyStr);
00724     ROS_INFO("Receiving: %s", stripControl(replyVec).c_str());
00725 
00726     if (result != 0)
00727     {
00728       std::string tmpStr = "SOPAS Communication -" + errString;
00729       ROS_INFO("%s\n", tmpStr.c_str());
00730       diagnostics_.broadcast(getDiagnosticErrorCode(), tmpStr);
00731     }
00732     else
00733     {
00734       std::string answerStr = replyToString(*reply);
00735       std::string searchPattern = generateExpectedAnswerString(requestStr);
00736 
00737       if (answerStr.find(searchPattern) != std::string::npos)
00738       {
00739         result = 0;
00740       }
00741       else
00742       {
00743         if (cmdId == CMD_START_IMU_DATA)
00744         {
00745           ROS_INFO("IMU-Data transfer started. No checking of reply to avoid confusing with LMD Scandata\n");
00746           result = 0;
00747         }
00748         else
00749         {
00750           std::string tmpMsg = "Error Sopas answer mismatch " + errString + "Answer= >>>" + answerStr + "<<<";
00751           ROS_ERROR("%s\n", tmpMsg.c_str());
00752           diagnostics_.broadcast(getDiagnosticErrorCode(), tmpMsg);
00753           result = -1;
00754         }
00755       }
00756     }
00757     return result;
00758 
00759   }
00760 
00766   void SickScanCommon::setReadTimeOutInMs(int timeOutInMs)
00767   {
00768     readTimeOutInMs = timeOutInMs;
00769   }
00770 
00776   int SickScanCommon::getReadTimeOutInMs()
00777   {
00778     return (readTimeOutInMs);
00779   }
00780 
00786   int SickScanCommon::getProtocolType(void)
00787   {
00788     return m_protocolId;
00789   }
00790 
00795   void SickScanCommon::setProtocolType(SopasProtocol cola_dialect_id)
00796   {
00797     m_protocolId = cola_dialect_id;
00798   }
00799 
00804   int SickScanCommon::init()
00805   {
00806     int result = init_device();
00807     if (result != 0)
00808     {
00809       ROS_FATAL("Failed to init device: %d", result);
00810       return result;
00811     }
00812     result = init_scanner();
00813     if (result != 0)
00814     {
00815       ROS_INFO("Failed to init scanner Error Code: %d\nWaiting for timeout...\n"
00816                 "If the communication mode set in the scanner memory is different from that used by the driver, the scanner's communication mode is changed.\n"
00817                 "This requires a restart of the TCP-IP connection, which can extend the start time by up to 30 seconds. There are two ways to prevent this:\n"
00818                 "1. [Recommended] Set the communication mode with the SOPAS ET software to binary and save this setting in the scanner's EEPROM.\n"
00819                 "2. Use the parameter \"use_binary_protocol\" to overwrite the default settings of the driver.",
00820                 result);
00821     }
00822 
00823     return result;
00824   }
00825 
00826 
00831   int SickScanCommon::init_cmdTables()
00832   {
00833     sopasCmdVec.resize(SickScanCommon::CMD_END);
00834     sopasCmdMaskVec.resize(
00835         SickScanCommon::CMD_END);  // you for cmd with variable content. sprintf should print into corresponding sopasCmdVec
00836     sopasCmdErrMsg.resize(
00837         SickScanCommon::CMD_END);  // you for cmd with variable content. sprintf should print into corresponding sopasCmdVec
00838     sopasReplyVec.resize(SickScanCommon::CMD_END);
00839     sopasReplyBinVec.resize(SickScanCommon::CMD_END);
00840     sopasReplyStrVec.resize(SickScanCommon::CMD_END);
00841 
00842     std::string unknownStr = "Command or Error message not defined";
00843     for (int i = 0; i < SickScanCommon::CMD_END; i++)
00844     {
00845       sopasCmdVec[i] = unknownStr;
00846       sopasCmdMaskVec[i] = unknownStr;  // for cmd with variable content. sprintf should print into corresponding sopasCmdVec
00847       sopasCmdErrMsg[i] = unknownStr;
00848       sopasReplyVec[i] = unknownStr;
00849       sopasReplyStrVec[i] = unknownStr;
00850     }
00851 
00852     sopasCmdVec[CMD_DEVICE_IDENT_LEGACY] = "\x02sRI 0\x03\0";
00853     sopasCmdVec[CMD_DEVICE_IDENT] = "\x02sRN DeviceIdent\x03\0";
00854     sopasCmdVec[CMD_REBOOT] = "\x02sMN mSCreboot\x03";
00855     sopasCmdVec[CMD_WRITE_EEPROM] = "\x02sMN mEEwriteall\x03";
00856     sopasCmdVec[CMD_SERIAL_NUMBER] = "\x02sRN SerialNumber\x03\0";
00857     sopasCmdVec[CMD_FIRMWARE_VERSION] = "\x02sRN FirmwareVersion\x03\0";
00858     sopasCmdVec[CMD_DEVICE_STATE] = "\x02sRN SCdevicestate\x03\0";
00859     sopasCmdVec[CMD_OPERATION_HOURS] = "\x02sRN ODoprh\x03\0";
00860     sopasCmdVec[CMD_POWER_ON_COUNT] = "\x02sRN ODpwrc\x03\0";
00861     sopasCmdVec[CMD_LOCATION_NAME] = "\x02sRN LocationName\x03\0";
00862     sopasCmdVec[CMD_ACTIVATE_STANDBY] = "\x02sMN LMCstandby\x03";
00863     sopasCmdVec[CMD_SET_ACCESS_MODE_3] = "\x02sMN SetAccessMode 3 F4724744\x03\0";
00864     sopasCmdVec[CMD_GET_OUTPUT_RANGES] = "\x02sRN LMPoutputRange\x03";
00865     sopasCmdVec[CMD_RUN] = "\x02sMN Run\x03\0";
00866     sopasCmdVec[CMD_STOP_SCANDATA] = "\x02sEN LMDscandata 0\x03";
00867     sopasCmdVec[CMD_START_SCANDATA] = "\x02sEN LMDscandata 1\x03";
00868     sopasCmdVec[CMD_START_RADARDATA] = "\x02sEN LMDradardata 1\x03";
00869     sopasCmdVec[CMD_ACTIVATE_NTP_CLIENT] ="\x02sWN TSCRole 1\x03";
00870     sopasCmdVec[CMD_SET_NTP_INTERFACE_ETH]= "\x02sWN TSCTCInterface 0\x03";
00871 
00872     /*
00873      * Radar specific commands
00874      */
00875     sopasCmdVec[CMD_SET_TRANSMIT_RAWTARGETS_ON] = "\x02sWN TransmitTargets 1\x03";  // transmit raw target for radar
00876     sopasCmdVec[CMD_SET_TRANSMIT_RAWTARGETS_OFF] = "\x02sWN TransmitTargets 0\x03";  // do not transmit raw target for radar
00877     sopasCmdVec[CMD_SET_TRANSMIT_OBJECTS_ON] = "\x02sWN TransmitObjects 1\x03";  // transmit objects from radar tracking
00878     sopasCmdVec[CMD_SET_TRANSMIT_OBJECTS_OFF] = "\x02sWN TransmitObjects 0\x03";  // do not transmit objects from radar tracking
00879     sopasCmdVec[CMD_SET_TRACKING_MODE_0] = "\x02sWN TCTrackingMode 0\x03";  // set object tracking mode to BASIC
00880     sopasCmdVec[CMD_SET_TRACKING_MODE_1] = "\x02sWN TCTrackingMode 1\x03";  // set object tracking mode to TRAFFIC
00881 
00882 
00883     sopasCmdVec[CMD_LOAD_APPLICATION_DEFAULT] = "\x02sMN mSCloadappdef\x03";  // load application default
00884     sopasCmdVec[CMD_DEVICE_TYPE] = "\x02sRN DItype\x03";  // ask for radar device type
00885     sopasCmdVec[CMD_ORDER_NUMBER] = "\x02sRN OrdNum\x03";  // ask for radar order number
00886 
00887 
00888 
00889     sopasCmdVec[CMD_START_MEASUREMENT] = "\x02sMN LMCstartmeas\x03";
00890     sopasCmdVec[CMD_STOP_MEASUREMENT] = "\x02sMN LMCstopmeas\x03";
00891     sopasCmdVec[CMD_APPLICATION_MODE_FIELD_ON] = "\x02sWN SetActiveApplications 1 FEVL 1\x03"; // <STX>sWN{SPC}SetActiveApplications{SPC}1{SPC}FEVL{SPC}1<ETX>
00892     sopasCmdVec[CMD_APPLICATION_MODE_FIELD_OFF] = "\x02sWN SetActiveApplications 1 FEVL 0\x03"; // <STX>sWN{SPC}SetActiveApplications{SPC}1{SPC}FEVL{SPC}1<ETX>
00893     sopasCmdVec[CMD_APPLICATION_MODE_RANGING_ON] = "\x02sWN SetActiveApplications 1 RANG 1\x03";
00894     sopasCmdVec[CMD_SET_TO_COLA_A_PROTOCOL] = "\x02sWN EIHstCola 0\x03";
00895     sopasCmdVec[CMD_GET_PARTIAL_SCANDATA_CFG] = "\x02sRN LMDscandatacfg\x03";//<STX>sMN{SPC}mLMPsetscancfg{SPC } +5000{SPC}+1{SPC}+5000{SPC}-450000{SPC}+2250000<ETX>
00896     sopasCmdVec[CMD_GET_PARTIAL_SCAN_CFG] = "\x02sRN LMPscancfg\x03";
00897     sopasCmdVec[CMD_SET_TO_COLA_B_PROTOCOL] = "\x02sWN EIHstCola 1\x03";
00898 
00899     sopasCmdVec[CMD_STOP_IMU_DATA] = "\x02sEN InertialMeasurementUnit 0\x03";
00900     sopasCmdVec[CMD_START_IMU_DATA] = "\x02sEN InertialMeasurementUnit 1\x03";
00901 
00902     // defining cmd mask for cmds with variable input
00903     sopasCmdMaskVec[CMD_SET_PARTIAL_SCAN_CFG] = "\x02sMN mLMPsetscancfg %d 1 %d 0 0\x03";//scanfreq [1/100 Hz],angres [1/10000°],
00904     sopasCmdMaskVec[CMD_SET_PARTICLE_FILTER] = "\x02sWN LFPparticle %d %d\x03";
00905     sopasCmdMaskVec[CMD_SET_MEAN_FILTER] = "\x02sWN LFPmeanfilter %d +%d 1\x03";
00906     sopasCmdMaskVec[CMD_ALIGNMENT_MODE] = "\x02sWN MMAlignmentMode %d\x03";
00907     sopasCmdMaskVec[CMD_APPLICATION_MODE] = "\x02sWN SetActiveApplications 1 %s %d\x03";
00908     sopasCmdMaskVec[CMD_SET_OUTPUT_RANGES] = "\x02sWN LMPoutputRange 1 %X %X %X\x03";
00909     sopasCmdMaskVec[CMD_SET_PARTIAL_SCANDATA_CFG] = "\x02sWN LMDscandatacfg %02d 00 %d %d 0 00 00 0 0 0 1 1\x03";
00910     sopasCmdMaskVec[CMD_SET_ECHO_FILTER] = "\x02sWN FREchoFilter %d\x03";
00911     sopasCmdMaskVec[CMD_SET_NTP_UPDATETIME] = "\x02sWN TSCTCupdatetime %d\x03";
00912     sopasCmdMaskVec[CMD_SET_NTP_TIMEZONE]= "sWN TSCTCtimezone %d";
00913     sopasCmdMaskVec[CMD_SET_IP_ADDR] = "\x02sWN EIIpAddr %02X %02X %02X %02X\x03";
00914     sopasCmdMaskVec[CMD_SET_NTP_SERVER_IP_ADDR] = "\x02sWN TSCTCSrvAddr %02X %02X %02X %02X\x03";
00915     sopasCmdMaskVec[CMD_SET_GATEWAY] = "\x02sWN EIgate %02X %02X %02X %02X\x03";
00916     //error Messages
00917     sopasCmdErrMsg[CMD_DEVICE_IDENT_LEGACY] = "Error reading device ident";
00918     sopasCmdErrMsg[CMD_DEVICE_IDENT] = "Error reading device ident for MRS-family";
00919     sopasCmdErrMsg[CMD_SERIAL_NUMBER] = "Error reading SerialNumber";
00920     sopasCmdErrMsg[CMD_FIRMWARE_VERSION] = "Error reading FirmwareVersion";
00921     sopasCmdErrMsg[CMD_DEVICE_STATE] = "Error reading SCdevicestate";
00922     sopasCmdErrMsg[CMD_OPERATION_HOURS] = "Error reading operation hours";
00923     sopasCmdErrMsg[CMD_POWER_ON_COUNT] = "Error reading operation power on counter";
00924     sopasCmdErrMsg[CMD_LOCATION_NAME] = "Error reading Locationname";
00925     sopasCmdErrMsg[CMD_ACTIVATE_STANDBY] = "Error acticvating Standby";
00926     sopasCmdErrMsg[CMD_SET_PARTICLE_FILTER] = "Error setting Particelefilter";
00927     sopasCmdErrMsg[CMD_SET_MEAN_FILTER] = "Error setting Meanfilter";
00928     sopasCmdErrMsg[CMD_ALIGNMENT_MODE] = "Error setting Alignmentmode";
00929     sopasCmdErrMsg[CMD_APPLICATION_MODE] = "Error setting Meanfilter";
00930     sopasCmdErrMsg[CMD_SET_ACCESS_MODE_3] = "Error Access Mode";
00931     sopasCmdErrMsg[CMD_SET_OUTPUT_RANGES] = "Error setting angular ranges";
00932     sopasCmdErrMsg[CMD_GET_OUTPUT_RANGES] = "Error reading angle range";
00933     sopasCmdErrMsg[CMD_RUN] = "FATAL ERROR unable to start RUN mode!";
00934     sopasCmdErrMsg[CMD_SET_PARTIAL_SCANDATA_CFG] = "Error setting Scandataconfig";
00935     sopasCmdErrMsg[CMD_STOP_SCANDATA] = "Error stopping scandata output";
00936     sopasCmdErrMsg[CMD_START_SCANDATA] = "Error starting Scandata output";
00937     sopasCmdErrMsg[CMD_SET_IP_ADDR] = "Error setting IP address";
00938     sopasCmdErrMsg[CMD_SET_GATEWAY] = "Error setting gateway";
00939     sopasCmdErrMsg[CMD_REBOOT] = "Error rebooting the device";
00940     sopasCmdErrMsg[CMD_WRITE_EEPROM] = "Error writing data to EEPRom";
00941     sopasCmdErrMsg[CMD_ACTIVATE_NTP_CLIENT] ="Error activating NTP client";
00942     sopasCmdErrMsg[CMD_SET_NTP_INTERFACE_ETH] ="Error setting NTP interface to ETH";
00943     sopasCmdErrMsg[CMD_SET_NTP_SERVER_IP_ADDR] ="Error setting NTP server Adress";
00944     sopasCmdErrMsg[CMD_SET_NTP_UPDATETIME] = "Error setting NTP update time";
00945     sopasCmdErrMsg[CMD_SET_NTP_TIMEZONE] = "Error setting NTP timezone";
00946 
00947     // ML: Add hier more useful cmd and mask entries
00948 
00949     // After definition of command, we specify the command sequence for scanner initalisation
00950 
00951     // try for MRS1104
00952     sopasCmdChain.push_back(CMD_SET_ACCESS_MODE_3);
00953 
00954     if (parser_->getCurrentParamPtr()->getUseBinaryProtocol())
00955     {
00956       sopasCmdChain.push_back(CMD_SET_TO_COLA_B_PROTOCOL);
00957     }
00958     else
00959     {
00960       //for binary Mode Testing
00961       sopasCmdChain.push_back(CMD_SET_TO_COLA_A_PROTOCOL);
00962     }
00963 
00964     bool tryToStopMeasurement = true;
00965     if (parser_->getCurrentParamPtr()->getNumberOfLayers() == 1)
00966     {
00967 
00968         tryToStopMeasurement = false;
00969       //XXX
00970       // do not stop measurement for TiM571 otherwise the scanner would not start after start measurement
00971       // do not change the application - not supported for TiM5xx
00972     }
00973     if (parser_->getCurrentParamPtr()->getDeviceIsRadar() == true)
00974     {
00975       sopasCmdChain.push_back(CMD_LOAD_APPLICATION_DEFAULT); // load application default for radar
00976 
00977       tryToStopMeasurement = false;
00978       // do not stop measurement for RMS320 - the RMS320 does not support the stop command
00979     }
00980 
00981     if (tryToStopMeasurement)
00982     {
00983       sopasCmdChain.push_back(CMD_STOP_MEASUREMENT);
00984       int numberOfLayers = parser_->getCurrentParamPtr()->getNumberOfLayers();
00985 
00986       switch (numberOfLayers)
00987       {
00988         case 4:
00989           sopasCmdChain.push_back(CMD_APPLICATION_MODE_FIELD_OFF);
00990           sopasCmdChain.push_back(CMD_APPLICATION_MODE_RANGING_ON);
00991           sopasCmdChain.push_back(CMD_DEVICE_IDENT);
00992           sopasCmdChain.push_back(CMD_SERIAL_NUMBER);
00993 
00994           break;
00995         case 24:
00996           // just measuring - Application setting not supported
00997           // "Old" device ident command "SRi 0" not supported
00998           sopasCmdChain.push_back(CMD_DEVICE_IDENT);
00999           break;
01000 
01001         default:
01002           sopasCmdChain.push_back(CMD_APPLICATION_MODE_FIELD_OFF);
01003           sopasCmdChain.push_back(CMD_APPLICATION_MODE_RANGING_ON);
01004           sopasCmdChain.push_back(CMD_DEVICE_IDENT_LEGACY);
01005 
01006           sopasCmdChain.push_back(CMD_SERIAL_NUMBER);
01007           break;
01008       }
01009 
01010     }
01011     sopasCmdChain.push_back(CMD_FIRMWARE_VERSION);  // read firmware
01012     sopasCmdChain.push_back(CMD_DEVICE_STATE); // read device state
01013     sopasCmdChain.push_back(CMD_OPERATION_HOURS); // read operation hours
01014     sopasCmdChain.push_back(CMD_POWER_ON_COUNT); // read power on count
01015     sopasCmdChain.push_back(CMD_LOCATION_NAME); // read location name
01016 
01017 
01018     return (0);
01019 
01020   }
01021 
01022 
01027   int SickScanCommon::init_scanner()
01028   {
01029 
01030     const int MAX_STR_LEN = 1024;
01031 
01032     int maxNumberOfEchos = 1;
01033 
01034 
01035     maxNumberOfEchos = this->parser_->getCurrentParamPtr()->getNumberOfMaximumEchos();  // 1 for TIM 571, 3 for MRS1104, 5 for 6000
01036 
01037 
01038     bool rssiFlag = false;
01039     bool rssiResolutionIs16Bit = true; //True=16 bit Flase=8bit
01040     int activeEchos = 0;
01041     ros::NodeHandle pn("~");
01042 
01043     pn.getParam("intensity", rssiFlag);
01044     pn.getParam("intensity_resolution_16bit", rssiResolutionIs16Bit);
01045 
01046     //check new ip adress and add cmds to write ip to comand chain
01047     std::string sNewIPAddr = "";
01048     boost::asio::ip::address_v4 ipNewIPAddr;
01049     bool setNewIPAddr = false;
01050     setNewIPAddr = pn.getParam("new_IP_address", sNewIPAddr);
01051     if (setNewIPAddr)
01052     {
01053       boost::system::error_code ec;
01054       ipNewIPAddr = boost::asio::ip::address_v4::from_string(sNewIPAddr, ec);
01055       if (ec == 0)
01056       {
01057         sopasCmdChain.clear();
01058         sopasCmdChain.push_back(CMD_SET_ACCESS_MODE_3);
01059       }
01060       else
01061       {
01062         setNewIPAddr = false;
01063         ROS_ERROR("ERROR: IP ADDRESS could not be parsed Boost Error %s:%d", ec.category().name(), ec.value());;
01064       }
01065 
01066     }
01067     std::string sNTPIpAdress = "";
01068     boost::asio::ip::address_v4 NTPIpAdress;
01069     bool setUseNTP=false;
01070     setUseNTP = pn.getParam("ntp_server_address", sNTPIpAdress);
01071     if (setUseNTP)
01072     {
01073       boost::system::error_code ec;
01074       NTPIpAdress = boost::asio::ip::address_v4::from_string(sNTPIpAdress, ec);
01075       if (ec != 0)
01076       {
01077         setUseNTP = false;
01078         ROS_ERROR("ERROR: NTP Server IP ADDRESS could not be parsed Boost Error %s:%d", ec.category().name(), ec.value());;
01079       }
01080     }
01081 
01082     this->parser_->getCurrentParamPtr()->setIntensityResolutionIs16Bit(rssiResolutionIs16Bit);
01083 
01084     // parse active_echos entry and set flag array
01085     pn.getParam("active_echos", activeEchos);
01086 
01087     ROS_INFO("Parameter setting for <active_echo: %d>", activeEchos);
01088     std::vector<bool> outputChannelFlag;
01089     outputChannelFlag.resize(maxNumberOfEchos);
01090     int i;
01091     int numOfFlags = 0;
01092     for (i = 0; i < outputChannelFlag.size(); i++)
01093     {
01094       /*
01095       After consultation with the company SICK,
01096       all flags are set to true because the firmware currently does not support single selection of targets.
01097       The selection of the echoes takes place via FREchoFilter.
01098        */
01099       /* former implementation
01100       if (activeEchos & (1 << i))
01101       {
01102         outputChannelFlag[i] = true;
01103         numOfFlags++;
01104       }
01105       else
01106       {
01107         outputChannelFlag[i] = false;
01108       }
01109        */
01110       outputChannelFlag[i] = true; // always true (see comment above)
01111       numOfFlags++;
01112     }
01113 
01114     if (numOfFlags == 0) // Fallback-Solution
01115     {
01116       outputChannelFlag[0] = true;
01117       numOfFlags = 1;
01118       ROS_WARN("Activate at least one echo.");
01119     }
01120 
01121     int result;
01122     //================== DEFINE ANGULAR SETTING ==========================
01123     int angleRes10000th = 0;
01124     int angleStart10000th = 0;
01125     int angleEnd10000th = 0;
01126 
01127 
01128     // Mainloop for initial SOPAS cmd-Handling
01129     //
01130     // To add new commands do the followings:
01131     // 1. Define new enum-entry in the enumumation "enum SOPAS_CMD" in the file sick_scan_common.h
01132     // 2. Define new command sequence in the member function init_cmdTables()
01133     // 3. Add cmd-id in the sopasCmdChain to trigger sending of command.
01134     // 4. Add handling of reply by using for the pattern "REPLY_HANDLING" in this code and adding a new case instruction.
01135     // That's all!
01136 
01137 
01138     volatile bool useBinaryCmd = false;
01139     if (this->parser_->getCurrentParamPtr()->getUseBinaryProtocol()) // hard coded for every scanner type
01140     {
01141       useBinaryCmd = true;  // shall we talk ascii or binary with the scanner type??
01142     }
01143 
01144     bool useBinaryCmdNow = false;
01145     int maxCmdLoop = 2; // try binary and ascii during startup
01146 
01147     const int shortTimeOutInMs = 5000; // during startup phase to check binary or ascii
01148     const int defaultTimeOutInMs = 20000; // standard time out 20 sec.
01149 
01150     setReadTimeOutInMs(shortTimeOutInMs);
01151 
01152     bool restartDueToProcolChange = false;
01153 
01154 
01155     for (int i = 0; i < this->sopasCmdChain.size(); i++)
01156     {
01157       ros::Duration(0.2).sleep();   // could maybe removed
01158 
01159       int cmdId = sopasCmdChain[i]; // get next command
01160       std::string sopasCmd = sopasCmdVec[cmdId];
01161       std::vector<unsigned char> replyDummy;
01162       std::vector<unsigned char> reqBinary;
01163 
01164       std::vector<unsigned char> sopasCmdVec;
01165       for (int j = 0; j < sopasCmd.length(); j++)
01166       {
01167         sopasCmdVec.push_back(sopasCmd[j]);
01168       }
01169       ROS_DEBUG("Command: %s", stripControl(sopasCmdVec).c_str());
01170 
01171       // switch to either binary or ascii after switching the command mode
01172       // via ... command
01173 
01174 
01175       for (int iLoop = 0; iLoop < maxCmdLoop; iLoop++)
01176       {
01177         if (iLoop == 0)
01178         {
01179           useBinaryCmdNow = useBinaryCmd; // start with expected value
01180 
01181         }
01182         else
01183         {
01184           useBinaryCmdNow = !useBinaryCmdNow;// try the other option
01185           useBinaryCmd = useBinaryCmdNow; // and use it from now on as default
01186 
01187         }
01188 
01189         this->setProtocolType(useBinaryCmdNow ? CoLa_B : CoLa_A);
01190 
01191 
01192         if (useBinaryCmdNow)
01193         {
01194           this->convertAscii2BinaryCmd(sopasCmd.c_str(), &reqBinary);
01195           result = sendSopasAndCheckAnswer(reqBinary, &replyDummy);
01196           sopasReplyBinVec[cmdId] = replyDummy;
01197         }
01198         else
01199         {
01200           result = sendSopasAndCheckAnswer(sopasCmd.c_str(), &replyDummy);
01201         }
01202         if (result == 0) // command sent successfully
01203         {
01204           // useBinaryCmd holds information about last successful command mode
01205           break;
01206         }
01207       }
01208       if (result != 0)
01209       {
01210         ROS_ERROR("%s", sopasCmdErrMsg[cmdId].c_str());
01211         diagnostics_.broadcast(getDiagnosticErrorCode(), sopasCmdErrMsg[cmdId]);
01212       }
01213       else
01214       {
01215         sopasReplyStrVec[cmdId] = replyToString(replyDummy);
01216       }
01217 
01218       //============================================
01219       // Handle reply of specific commands here by inserting new case instruction
01220       // REPLY_HANDLING
01221       //============================================
01222       maxCmdLoop = 1;
01223 
01224 
01225       // handle special configuration commands ...
01226 
01227       switch (cmdId)
01228       {
01229 
01230         case CMD_SET_TO_COLA_A_PROTOCOL:
01231         {
01232           bool protocolCheck = checkForProtocolChangeAndMaybeReconnect(useBinaryCmdNow);
01233           if (false == protocolCheck)
01234           {
01235             restartDueToProcolChange = true;
01236           }
01237           useBinaryCmd = useBinaryCmdNow;
01238           setReadTimeOutInMs(defaultTimeOutInMs);
01239         }
01240           break;
01241         case CMD_SET_TO_COLA_B_PROTOCOL:
01242         {
01243           bool protocolCheck = checkForProtocolChangeAndMaybeReconnect(useBinaryCmdNow);
01244           if (false == protocolCheck)
01245           {
01246             restartDueToProcolChange = true;
01247           }
01248           useBinaryCmd = useBinaryCmdNow;
01249           setReadTimeOutInMs(defaultTimeOutInMs);
01250         }
01251           break;
01252 
01253           /*
01254           SERIAL_NUMBER: Device ident must be read before!
01255           */
01256 
01257         case CMD_DEVICE_IDENT: // FOR MRS6xxx the Device Ident holds all specific information (used instead of CMD_SERIAL_NUMBER)
01258         {
01259           std::string deviceIdent = "";
01260           int cmdLen = this->checkForBinaryAnswer(&replyDummy);
01261           if (cmdLen == -1)
01262           {
01263             int idLen = 0;
01264             int versionLen = 0;
01265             // ASCII-Return
01266             std::string deviceIdentKeyWord = "sRA DeviceIdent";
01267             char *ptr = (char *) (&(replyDummy[0]));
01268             ptr++; // skip 0x02
01269             ptr += deviceIdentKeyWord.length();
01270             ptr++; //skip blank
01271             sscanf(ptr, "%d", &idLen);
01272             char *ptr2 = strchr(ptr, ' ');
01273             if (ptr2 != NULL)
01274             {
01275               ptr2++;
01276               for (int i = 0; i < idLen; i++)
01277               {
01278                 deviceIdent += *ptr2;
01279                 ptr2++;
01280               }
01281 
01282             }
01283             ptr = ptr2;
01284             ptr++; //skip blank
01285             sscanf(ptr, "%d", &versionLen);
01286             ptr2 = strchr(ptr, ' ');
01287             if (ptr2 != NULL)
01288             {
01289               ptr2++;
01290               deviceIdent += " V";
01291               for (int i = 0; i < versionLen; i++)
01292               {
01293                 deviceIdent += *ptr2;
01294                 ptr2++;
01295               }
01296             }
01297             diagnostics_.setHardwareID(deviceIdent);
01298             if (!isCompatibleDevice(deviceIdent))
01299             {
01300               return ExitFatal;
01301             }
01302 //                                      ROS_ERROR("BINARY REPLY REQUIRED");
01303           }
01304           else
01305           {
01306             long dummy0, dummy1, identLen, versionLen;
01307             dummy0 = 0;
01308             dummy1 = 0;
01309             identLen = 0;
01310             versionLen = 0;
01311 
01312             const char *scanMask0 = "%04y%04ysRA DeviceIdent %02y";
01313             const char *scanMask1 = "%02y";
01314             unsigned char *replyPtr = &(replyDummy[0]);
01315             int scanDataLen0 = binScanfGuessDataLenFromMask(scanMask0);
01316             int scanDataLen1 = binScanfGuessDataLenFromMask(scanMask1); // should be: 2
01317             binScanfVec(&replyDummy, scanMask0, &dummy0, &dummy1, &identLen);
01318 
01319             std::string identStr = binScanfGetStringFromVec(&replyDummy, scanDataLen0, identLen);
01320             int off = scanDataLen0 + identLen; // consuming header + fixed part + ident
01321 
01322             std::vector<unsigned char> restOfReplyDummy = std::vector<unsigned char>(replyDummy.begin() + off,
01323                                                                                      replyDummy.end());
01324 
01325             versionLen = 0;
01326             binScanfVec(&restOfReplyDummy, "%02y", &versionLen);
01327             std::string versionStr = binScanfGetStringFromVec(&restOfReplyDummy, scanDataLen1, versionLen);
01328             std::string fullIdentVersionInfo = identStr + " V" + versionStr;
01329             diagnostics_.setHardwareID(fullIdentVersionInfo);
01330             if (!isCompatibleDevice(fullIdentVersionInfo))
01331             {
01332               return ExitFatal;
01333             }
01334 
01335           }
01336           break;
01337         }
01338 
01339 
01340         case CMD_SERIAL_NUMBER:
01341           if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 4)
01342           {
01343             // do nothing for MRS1104 here
01344           }
01345           else
01346           {
01347             diagnostics_.setHardwareID(
01348                 sopasReplyStrVec[CMD_DEVICE_IDENT_LEGACY] + " " + sopasReplyStrVec[CMD_SERIAL_NUMBER]);
01349 
01350             if (!isCompatibleDevice(sopasReplyStrVec[CMD_DEVICE_IDENT_LEGACY]))
01351             {
01352               return ExitFatal;
01353             }
01354           }
01355           break;
01356           /*
01357           DEVICE_STATE
01358           */
01359         case CMD_DEVICE_STATE:
01360         {
01361           int deviceState = -1;
01362           /*
01363           * Process device state, 0=Busy, 1=Ready, 2=Error
01364           * If configuration parameter is set, try resetting device in error state
01365           */
01366 
01367           int iRetVal = 0;
01368           if (useBinaryCmd)
01369           {
01370             long dummy0 = 0x00;
01371             long dummy1 = 0x00;
01372             deviceState = 0x00; // must be set to zero (because only one byte will be copied)
01373             iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_DEVICE_STATE]), "%4y%4ysRA SCdevicestate %1y", &dummy0,
01374                                   &dummy1, &deviceState);
01375           }
01376           else
01377           {
01378             iRetVal = sscanf(sopasReplyStrVec[CMD_DEVICE_STATE].c_str(), "sRA SCdevicestate %d", &deviceState);
01379           }
01380           if (iRetVal > 0)  // 1 or 3 (depending of ASCII or Binary)
01381           {
01382             switch (deviceState)
01383             {
01384               case 0:
01385                 ROS_DEBUG("Laser is busy");
01386                 break;
01387               case 1:
01388                 ROS_DEBUG("Laser is ready");
01389                 break;
01390               case 2:
01391                 ROS_ERROR_STREAM("Laser reports error state : " << sopasReplyStrVec[CMD_DEVICE_STATE]);
01392                 if (config_.auto_reboot)
01393                 {
01394                   rebootScanner();
01395                 };
01396                 break;
01397               default:
01398                 ROS_WARN_STREAM("Laser reports unknown devicestate : " << sopasReplyStrVec[CMD_DEVICE_STATE]);
01399                 break;
01400             }
01401           }
01402         }
01403           break;
01404 
01405         case CMD_OPERATION_HOURS:
01406         {
01407           int operationHours = -1;
01408           int iRetVal = 0;
01409           /*
01410           * Process device state, 0=Busy, 1=Ready, 2=Error
01411           * If configuration parameter is set, try resetting device in error state
01412           */
01413           if (useBinaryCmd)
01414           {
01415             long dummy0, dummy1;
01416             dummy0 = 0;
01417             dummy1 = 0;
01418             operationHours = 0;
01419             iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_OPERATION_HOURS]), "%4y%4ysRA ODoprh %4y", &dummy0, &dummy1,
01420                                   &operationHours);
01421           }
01422           else
01423           {
01424             operationHours = 0;
01425             iRetVal = sscanf(sopasReplyStrVec[CMD_OPERATION_HOURS].c_str(), "sRA ODoprh %x", &operationHours);
01426           }
01427           if (iRetVal > 0)
01428           {
01429             double hours = 0.1 * operationHours;
01430             pn.setParam("operationHours", hours);
01431           }
01432         }
01433           break;
01434 
01435         case CMD_POWER_ON_COUNT:
01436         {
01437           int powerOnCount = -1;
01438           int iRetVal = -1;
01439           if (useBinaryCmd)
01440           {
01441             long dummy0, dummy1;
01442             powerOnCount = 0;
01443             iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_POWER_ON_COUNT]), "%4y%4ysRA ODpwrc %4y", &dummy0, &dummy1,
01444                                   &powerOnCount);
01445           }
01446           else
01447           {
01448             iRetVal = sscanf(sopasReplyStrVec[CMD_POWER_ON_COUNT].c_str(), "sRA ODpwrc %x", &powerOnCount);
01449           }
01450           if (iRetVal > 0)
01451           {
01452             pn.setParam("powerOnCount", powerOnCount);
01453           }
01454 
01455         }
01456           break;
01457 
01458         case CMD_LOCATION_NAME:
01459         {
01460           char szLocationName[MAX_STR_LEN] = {0};
01461           const char *strPtr = sopasReplyStrVec[CMD_LOCATION_NAME].c_str();
01462           const char *searchPattern = "sRA LocationName "; // Bug fix (leading space) Jan 2018
01463           strcpy(szLocationName, "unknown location");
01464           if (useBinaryCmd)
01465           {
01466             int iRetVal = 0;
01467             long dummy0, dummy1, locationNameLen;
01468             const char *binLocationNameMask = "%4y%4ysRA LocationName %2y";
01469             int prefixLen = binScanfGuessDataLenFromMask(binLocationNameMask);
01470             dummy0 = 0;
01471             dummy1 = 0;
01472             locationNameLen = 0;
01473 
01474             iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_LOCATION_NAME]), binLocationNameMask, &dummy0, &dummy1,
01475                                   &locationNameLen);
01476             if (iRetVal > 0)
01477             {
01478               std::string s;
01479               std::string locationNameStr = binScanfGetStringFromVec(&(sopasReplyBinVec[CMD_LOCATION_NAME]), prefixLen,
01480                                                                      locationNameLen);
01481               strcpy(szLocationName, locationNameStr.c_str());
01482             }
01483           }
01484           else
01485           {
01486             if (strstr(strPtr, searchPattern) == strPtr)
01487             {
01488               const char *ptr = strPtr + strlen(searchPattern);
01489               strcpy(szLocationName, ptr);
01490             }
01491             else
01492             {
01493               ROS_WARN("Location command not supported.\n");
01494             }
01495           }
01496           pn.setParam("locationName", std::string(szLocationName));
01497         }
01498           break;
01499         case CMD_GET_PARTIAL_SCANDATA_CFG:
01500         {
01501 
01502           const char *strPtr = sopasReplyStrVec[CMD_LOCATION_NAME].c_str();
01503           ROS_INFO("Config: %s\n", strPtr);
01504         }
01505           break;
01506           // ML: add here reply handling
01507       }
01508 
01509       if (restartDueToProcolChange)
01510       {
01511         return ExitError;
01512 
01513       }
01514 
01515     }
01516 
01517     if (setNewIPAddr)
01518     {
01519 
01520       setNewIpAddress(ipNewIPAddr, useBinaryCmd);
01521       ROS_INFO("IP address changed. Node restart required");
01522       ROS_INFO("Exiting node NOW.");
01523       exit(0);//stopping node hard to avoide further IP-Communication
01524     }
01525 
01526     if (setUseNTP)
01527     {
01528 
01529       setNTPServerAndStart(NTPIpAdress, useBinaryCmd);
01530     }
01531 
01532     if (this->parser_->getCurrentParamPtr()->getDeviceIsRadar())
01533     {
01534       //=====================================================
01535       // Radar specific commands
01536       //=====================================================
01537     }
01538     else
01539     {
01540       //-----------------------------------------------------------------
01541       //
01542       // This is recommended to decide between TiM551 and TiM561/TiM571 capabilities
01543       // The TiM551 has an angular resolution of 1.000 [deg]
01544       // The TiM561 and TiM571 have an angular resolution of 0.333 [deg]
01545       //-----------------------------------------------------------------
01546 
01547       angleRes10000th = (int) (boost::math::round(
01548           10000.0 * this->parser_->getCurrentParamPtr()->getAngularDegreeResolution()));
01549       std::vector<unsigned char> askOutputAngularRangeReply;
01550 
01551       if (useBinaryCmd)
01552       {
01553         std::vector<unsigned char> reqBinary;
01554         this->convertAscii2BinaryCmd(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &reqBinary);
01555         result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_GET_OUTPUT_RANGES]);
01556       }
01557       else
01558       {
01559         result = sendSopasAndCheckAnswer(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &askOutputAngularRangeReply);
01560       }
01561 
01562 
01563       if (0 == result)
01564       {
01565         int askTmpAngleRes10000th = 0;
01566         int askTmpAngleStart10000th = 0;
01567         int askTmpAngleEnd10000th = 0;
01568         char dummy0[MAX_STR_LEN] = {0};
01569         char dummy1[MAX_STR_LEN] = {0};
01570         int dummyInt = 0;
01571 
01572         int iDummy0, iDummy1;
01573         std::string askOutputAngularRangeStr = replyToString(askOutputAngularRangeReply);
01574         // Binary-Reply Tab. 63
01575         // 0x20 Space
01576         // 0x00 0x01 -
01577         // 0x00 0x00 0x05 0x14  // Resolution in 1/10000th degree  --> 0.13°
01578         // 0x00 0x04 0x93 0xE0  // Start Angle 300000    -> 30°
01579         // 0x00 0x16 0xE3 0x60  // End Angle   1.500.000 -> 150°    // in ROS +/-60°
01580         // 0x83                 // Checksum
01581 
01582         int numArgs;
01583 
01584         if (useBinaryCmd)
01585         {
01586           iDummy0 = 0;
01587           iDummy1 = 0;
01588           dummyInt = 0;
01589           askTmpAngleRes10000th = 0;
01590           askTmpAngleStart10000th = 0;
01591           askTmpAngleEnd10000th = 0;
01592 
01593           const char *askOutputAngularRangeBinMask = "%4y%4ysRA LMPoutputRange %2y%4y%4y%4y";
01594           numArgs = binScanfVec(&sopasReplyBinVec[CMD_GET_OUTPUT_RANGES], askOutputAngularRangeBinMask, &iDummy0,
01595                                 &iDummy1,
01596                                 &dummyInt,
01597                                 &askTmpAngleRes10000th,
01598                                 &askTmpAngleStart10000th,
01599                                 &askTmpAngleEnd10000th);
01600           //
01601         }
01602         else
01603         {
01604           numArgs = sscanf(askOutputAngularRangeStr.c_str(), "%s %s %d %X %X %X", dummy0, dummy1,
01605                            &dummyInt,
01606                            &askTmpAngleRes10000th,
01607                            &askTmpAngleStart10000th,
01608                            &askTmpAngleEnd10000th);
01609         }
01610         if (numArgs >= 6)
01611         {
01612           double askTmpAngleRes = askTmpAngleRes10000th / 10000.0;
01613           double askTmpAngleStart = askTmpAngleStart10000th / 10000.0;
01614           double askTmpAngleEnd = askTmpAngleEnd10000th / 10000.0;
01615 
01616           angleRes10000th = askTmpAngleRes10000th;
01617           ROS_INFO("Angle resolution of scanner is %0.5lf [deg]  (in 1/10000th deg: 0x%X)", askTmpAngleRes,
01618                    askTmpAngleRes10000th);
01619 
01620         }
01621       }
01622       //-----------------------------------------------------------------
01623       //
01624       // Set Min- und Max scanning angle given by config
01625       //
01626       //-----------------------------------------------------------------
01627 
01628       ROS_INFO("MIN_ANG: %8.3f [rad] %8.3f [deg]", config_.min_ang, rad2deg(this->config_.min_ang));
01629       ROS_INFO("MAX_ANG: %8.3f [rad] %8.3f [deg]", config_.max_ang, rad2deg(this->config_.max_ang));
01630 
01631       // convert to 10000th degree
01632       double minAngSopas = rad2deg(this->config_.min_ang) + 90;
01633       double maxAngSopas = rad2deg(this->config_.max_ang) + 90;
01634       angleStart10000th = (int) (boost::math::round(10000.0 * minAngSopas));
01635       angleEnd10000th = (int) (boost::math::round(10000.0 * maxAngSopas));
01636 
01637       char requestOutputAngularRange[MAX_STR_LEN];
01638 
01639         std::vector<unsigned char> outputAngularRangeReply;
01640         const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_OUTPUT_RANGES].c_str();
01641         sprintf(requestOutputAngularRange, pcCmdMask, angleRes10000th, angleStart10000th, angleEnd10000th);
01642 
01643         if (useBinaryCmd)
01644         {
01645           unsigned char tmpBuffer[255] = {0};
01646           unsigned char sendBuffer[255] = {0};
01647           UINT16 sendLen;
01648           std::vector<unsigned char> reqBinary;
01649           int iStatus = 1;
01650           //                            const char *askOutputAngularRangeBinMask = "%4y%4ysWN LMPoutputRange %2y%4y%4y%4y";
01651           // int askOutputAngularRangeBinLen = binScanfGuessDataLenFromMask(askOutputAngularRangeBinMask);
01652           // askOutputAngularRangeBinLen -= 8;  // due to header and length identifier
01653 
01654           strcpy((char *) tmpBuffer, "WN LMPoutputRange ");
01655           unsigned short orgLen = strlen((char *) tmpBuffer);
01656           colab::addIntegerToBuffer<UINT16>(tmpBuffer, orgLen, iStatus);
01657           colab::addIntegerToBuffer<UINT32>(tmpBuffer, orgLen, angleRes10000th);
01658           colab::addIntegerToBuffer<UINT32>(tmpBuffer, orgLen, angleStart10000th);
01659           colab::addIntegerToBuffer<UINT32>(tmpBuffer, orgLen, angleEnd10000th);
01660           sendLen = orgLen;
01661           colab::addFrameToBuffer(sendBuffer, tmpBuffer, &sendLen);
01662 
01663           // binSprintfVec(&reqBinary, askOutputAngularRangeBinMask, 0x02020202, askOutputAngularRangeBinLen, iStatus, angleRes10000th, angleStart10000th, angleEnd10000th);
01664 
01665           // unsigned char sickCrc = sick_crc8((unsigned char *)(&(reqBinary)[8]), reqBinary.size() - 8);
01666           // reqBinary.push_back(sickCrc);
01667           reqBinary = std::vector<unsigned char>(sendBuffer, sendBuffer + sendLen);
01668           // Here we must build a more complex binaryRequest
01669 
01670           // this->convertAscii2BinaryCmd(requestOutputAngularRange, &reqBinary);
01671           result = sendSopasAndCheckAnswer(reqBinary, &outputAngularRangeReply);
01672         }
01673         else
01674         {
01675           result = sendSopasAndCheckAnswer(requestOutputAngularRange, &outputAngularRangeReply);
01676         }
01677 
01678       //-----------------------------------------------------------------
01679       //
01680       // Get Min- und Max scanning angle from the scanner to verify angle setting and correct the config, if something went wrong.
01681       //
01682       // IMPORTANT:
01683       // Axis Orientation in ROS differs from SICK AXIS ORIENTATION!!!
01684       // In relation to a body the standard is:
01685       // x forward
01686       // y left
01687       // z up
01688       // see http://www.ros.org/reps/rep-0103.html#coordinate-frame-conventions for more details
01689       //-----------------------------------------------------------------
01690 
01691       askOutputAngularRangeReply.clear();
01692 
01693       if (useBinaryCmd)
01694       {
01695         std::vector<unsigned char> reqBinary;
01696         this->convertAscii2BinaryCmd(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &reqBinary);
01697         result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_GET_OUTPUT_RANGES]);
01698       }
01699       else
01700       {
01701         result = sendSopasAndCheckAnswer(sopasCmdVec[CMD_GET_OUTPUT_RANGES].c_str(), &askOutputAngularRangeReply);
01702       }
01703 
01704       if (result == 0)
01705       {
01706         char dummy0[MAX_STR_LEN] = {0};
01707         char dummy1[MAX_STR_LEN] = {0};
01708         int dummyInt = 0;
01709         int askAngleRes10000th = 0;
01710         int askAngleStart10000th = 0;
01711         int askAngleEnd10000th = 0;
01712         int iDummy0, iDummy1;
01713         iDummy0 = 0;
01714         iDummy1 = 0;
01715         std::string askOutputAngularRangeStr = replyToString(askOutputAngularRangeReply);
01716         // Binary-Reply Tab. 63
01717         // 0x20 Space
01718         // 0x00 0x01 -
01719         // 0x00 0x00 0x05 0x14  // Resolution in 1/10000th degree  --> 0.13°
01720         // 0x00 0x04 0x93 0xE0  // Start Angle 300000    -> 30°
01721         // 0x00 0x16 0xE3 0x60  // End Angle   1.500.000 -> 150°    // in ROS +/-60°
01722         // 0x83                 // Checksum
01723 
01724         int numArgs;
01725 
01726         /*
01727          *
01728          *  Initialize variables
01729          */
01730 
01731         iDummy0 = 0;
01732         iDummy1 = 0;
01733         dummyInt = 0;
01734         askAngleRes10000th = 0;
01735         askAngleStart10000th = 0;
01736         askAngleEnd10000th = 0;
01737 
01738         /*
01739          *   scan values
01740          *
01741          */
01742 
01743         if (useBinaryCmd)
01744         {
01745           const char *askOutputAngularRangeBinMask = "%4y%4ysRA LMPoutputRange %2y%4y%4y%4y";
01746           numArgs = binScanfVec(&sopasReplyBinVec[CMD_GET_OUTPUT_RANGES], askOutputAngularRangeBinMask, &iDummy0,
01747                                 &iDummy1,
01748                                 &dummyInt,
01749                                 &askAngleRes10000th,
01750                                 &askAngleStart10000th,
01751                                 &askAngleEnd10000th);
01752           //
01753         }
01754         else
01755         {
01756           numArgs = sscanf(askOutputAngularRangeStr.c_str(), "%s %s %d %X %X %X", dummy0, dummy1,
01757                            &dummyInt,
01758                            &askAngleRes10000th,
01759                            &askAngleStart10000th,
01760                            &askAngleEnd10000th);
01761         }
01762         if (numArgs >= 6)
01763         {
01764           double askTmpAngleRes = askAngleRes10000th / 10000.0;
01765           double askTmpAngleStart = askAngleStart10000th / 10000.0;
01766           double askTmpAngleEnd = askAngleEnd10000th / 10000.0;
01767 
01768           angleRes10000th = askAngleRes10000th;
01769           ROS_INFO("Angle resolution of scanner is %0.5lf [deg]  (in 1/10000th deg: 0x%X)", askTmpAngleRes,
01770                    askAngleRes10000th);
01771 
01772         }
01773         double askAngleRes = askAngleRes10000th / 10000.0;
01774         double askAngleStart = askAngleStart10000th / 10000.0;
01775         double askAngleEnd = askAngleEnd10000th / 10000.0;
01776 
01777         askAngleStart -= 90; // angle in ROS relative to y-axis
01778         askAngleEnd -= 90; // angle in ROS relative to y-axis
01779         this->config_.min_ang = askAngleStart / 180.0 * M_PI;
01780         this->config_.max_ang = askAngleEnd / 180.0 * M_PI;
01781         ros::NodeHandle nhPriv("~");
01782         nhPriv.setParam("min_ang",
01783                         this->config_.min_ang); // update parameter setting with "true" values read from scanner
01784         nhPriv.setParam("max_ang",
01785                         this->config_.max_ang); // update parameter setting with "true" values read from scanner
01786         ROS_INFO("MIN_ANG (after command verification): %8.3f [rad] %8.3f [deg]", config_.min_ang,
01787                  rad2deg(this->config_.min_ang));
01788         ROS_INFO("MAX_ANG (after command verification): %8.3f [rad] %8.3f [deg]", config_.max_ang,
01789                  rad2deg(this->config_.max_ang));
01790       }
01791 
01792 
01793 
01794       //-----------------------------------------------------------------
01795       //
01796       // Configure the data content of scan messing regarding to config.
01797       //
01798       //-----------------------------------------------------------------
01799       /*
01800       see 4.3.1 Configure the data content for the scan in the
01801       */
01802       //                              1    2     3
01803       // Prepare flag array for echos
01804       // Except for the LMS5xx scanner here the mask is hard 00 see SICK Telegram listing "Telegram structure: sWN LMDscandatacfg" for details
01805 
01806       outputChannelFlagId = 0x00;
01807       for (int i = 0; i < outputChannelFlag.size(); i++)
01808       {
01809         outputChannelFlagId |= ((outputChannelFlag[i] == true) << i);
01810       }
01811       if (outputChannelFlagId < 1)
01812       {
01813         outputChannelFlagId = 1;  // at least one channel must be set
01814       }
01815       if (this->parser_->getCurrentParamPtr()->getScannerName().compare(SICK_SCANNER_LMS_5XX_NAME) == 0)
01816       {
01817         outputChannelFlagId = 1;
01818         ROS_INFO("LMS 5xx detected overwriting output channel flag ID");
01819 
01820         ROS_INFO("LMS 5xx detected overwriting resolution flag (only 8 bit supported)");
01821         this->parser_->getCurrentParamPtr()->setIntensityResolutionIs16Bit(false);
01822         rssiResolutionIs16Bit = this->parser_->getCurrentParamPtr()->getIntensityResolutionIs16Bit();
01823       }
01824       if (this->parser_->getCurrentParamPtr()->getScannerName().compare(SICK_SCANNER_MRS_1XXX_NAME) == 0)
01825       {
01826         ROS_INFO("MRS 1xxx detected overwriting resolution flag (only 8 bit supported)");
01827         this->parser_->getCurrentParamPtr()->setIntensityResolutionIs16Bit(false);
01828         rssiResolutionIs16Bit = this->parser_->getCurrentParamPtr()->getIntensityResolutionIs16Bit();
01829 
01830       }
01831 
01832       // set scanning angle for tim5xx and for mrs1104
01833       if ((this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 1)
01834           || (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 4)
01835           || (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 24)
01836           )
01837       {
01838         char requestLMDscandatacfg[MAX_STR_LEN];
01839         // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
01840         // CMD_SET_PARTIAL_SCANDATA_CFG = "\x02sWN LMDscandatacfg %02d 00 %d 0 0 00 00 0 0 0 0 1\x03";
01841         const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_PARTIAL_SCANDATA_CFG].c_str();
01842         sprintf(requestLMDscandatacfg, pcCmdMask, outputChannelFlagId, rssiFlag ? 1 : 0, rssiResolutionIs16Bit ? 1 : 0);
01843         if (useBinaryCmd)
01844         {
01845           std::vector<unsigned char> reqBinary;
01846           this->convertAscii2BinaryCmd(requestLMDscandatacfg, &reqBinary);
01847           // FOR MRS6124 this should be
01848           // like this:
01849           // 0000  02 02 02 02 00 00 00 20 73 57 4e 20 4c 4d 44 73   .......sWN LMDs
01850           // 0010  63 61 6e 64 61 74 61 63 66 67 20 1f 00 01 01 00   candatacfg .....
01851           // 0020  00 00 00 00 00 00 00 01 5c
01852           result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_PARTIAL_SCANDATA_CFG]);
01853         }
01854         else
01855         {
01856           std::vector<unsigned char> lmdScanDataCfgReply;
01857           result = sendSopasAndCheckAnswer(requestLMDscandatacfg, &lmdScanDataCfgReply);
01858         }
01859 
01860 
01861         // check setting
01862         char requestLMDscandatacfgRead[MAX_STR_LEN];
01863         // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
01864 
01865         strcpy(requestLMDscandatacfgRead, sopasCmdVec[CMD_GET_PARTIAL_SCANDATA_CFG].c_str());
01866         if (useBinaryCmd)
01867         {
01868           std::vector<unsigned char> reqBinary;
01869           this->convertAscii2BinaryCmd(requestLMDscandatacfgRead, &reqBinary);
01870           result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_GET_PARTIAL_SCANDATA_CFG]);
01871         }
01872         else
01873         {
01874           std::vector<unsigned char> lmdScanDataCfgReadReply;
01875           result = sendSopasAndCheckAnswer(requestLMDscandatacfgRead, &lmdScanDataCfgReadReply);
01876         }
01877 
01878 
01879       }
01880       //BBB
01881       // set scanning angle for tim5xx and for mrs1104
01882       double scan_freq=0;
01883       double ang_res=0;
01884       pn.getParam("scan_freq", scan_freq); // filter_echos
01885       pn.getParam("ang_res", ang_res); // filter_echos
01886       if (scan_freq!=0 || ang_res!=0)
01887       {
01888         if(scan_freq!=0 && ang_res!=0)
01889         {
01890           char requestLMDscancfg[MAX_STR_LEN];
01891           //    sopasCmdMaskVec[CMD_SET_PARTIAL_SCAN_CFG] = "\x02sMN mLMPsetscancfg %d 1 %d 0 0\x03";//scanfreq [1/100 Hz],angres [1/10000°],
01892           const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_PARTIAL_SCAN_CFG].c_str();
01893           sprintf(requestLMDscancfg, pcCmdMask, (long)(scan_freq*100+1e-9),(long)(ang_res*10000+1e-9));
01894           if (useBinaryCmd)
01895           {
01896             std::vector<unsigned char> reqBinary;
01897             this->convertAscii2BinaryCmd(requestLMDscancfg, &reqBinary);
01898             result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_PARTIAL_SCAN_CFG]);
01899           }
01900           else
01901           {
01902             std::vector<unsigned char> lmdScanCfgReply;
01903             result = sendSopasAndCheckAnswer(requestLMDscancfg, &lmdScanCfgReply);
01904           }
01905 
01906 
01907           // check setting
01908           char requestLMDscancfgRead[MAX_STR_LEN];
01909           // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
01910 
01911           strcpy(requestLMDscancfgRead, sopasCmdVec[CMD_GET_PARTIAL_SCAN_CFG].c_str());
01912           if (useBinaryCmd)
01913           {
01914             std::vector<unsigned char> reqBinary;
01915             this->convertAscii2BinaryCmd(requestLMDscancfgRead, &reqBinary);
01916             result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_GET_PARTIAL_SCAN_CFG]);
01917           }
01918           else
01919           {
01920             std::vector<unsigned char> lmdScanDataCfgReadReply;
01921             result = sendSopasAndCheckAnswer(requestLMDscancfgRead, &lmdScanDataCfgReadReply);
01922           }
01923 
01924         }
01925         else
01926         {
01927           ROS_ERROR("ang_res and scan_freq have to be set, only one param is set skiping scan_fre/ang_res config");
01928         }
01929       }
01930       // CONFIG ECHO-Filter (only for MRS1000 not available for TiM5xx
01931       if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() >= 4)
01932       {
01933         char requestEchoSetting[MAX_STR_LEN];
01934         int filterEchoSetting = 0;
01935         pn.getParam("filter_echos", filterEchoSetting); // filter_echos
01936         if (filterEchoSetting < 0)
01937         { filterEchoSetting = 0; }
01938         if (filterEchoSetting > 2)
01939         { filterEchoSetting = 2; }
01940         // Uses sprintf-Mask to set bitencoded echos and rssi enable flag
01941         const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_ECHO_FILTER].c_str();
01942         /*
01943         First echo : 0
01944         All echos : 1
01945         Last echo : 2
01946         */
01947         sprintf(requestEchoSetting, pcCmdMask, filterEchoSetting);
01948         std::vector<unsigned char> outputFilterEchoRangeReply;
01949 
01950 
01951         if (useBinaryCmd)
01952         {
01953           std::vector<unsigned char> reqBinary;
01954           this->convertAscii2BinaryCmd(requestEchoSetting, &reqBinary);
01955           result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_ECHO_FILTER]);
01956         }
01957         else
01958         {
01959           result = sendSopasAndCheckAnswer(requestEchoSetting, &outputFilterEchoRangeReply);
01960         }
01961 
01962       }
01963 
01964 
01965     }
01967 
01968 
01969     //-----------------------------------------------------------------
01970     //
01971     // Start sending LMD-Scandata messages
01972     //
01973     //-----------------------------------------------------------------
01974     std::vector<int> startProtocolSequence;
01975     bool deviceIsRadar = false;
01976     if (this->parser_->getCurrentParamPtr()->getDeviceIsRadar())
01977     {
01978       ros::NodeHandle tmpParam("~");
01979       bool transmitRawTargets = true;
01980       bool transmitObjects = true;
01981       int trackingMode = 0;
01982       std::string trackingModeDescription[] = {"BASIC", "VEHICLE"};
01983 
01984       int numTrackingModes = sizeof(trackingModeDescription) / sizeof(trackingModeDescription[0]);
01985 
01986       tmpParam.getParam("transmit_raw_targets", transmitRawTargets);
01987       tmpParam.getParam("transmit_objects", transmitObjects);
01988       tmpParam.getParam("tracking_mode", trackingMode);
01989 
01990 
01991       if ((trackingMode < 0) || (trackingMode >= numTrackingModes))
01992       {
01993         ROS_WARN("tracking mode id invalid. Switch to tracking mode 0");
01994         trackingMode = 0;
01995       }
01996       ROS_INFO("Raw target transmission is switched [%s]", transmitRawTargets ? "ON" : "OFF");
01997       ROS_INFO("Object transmission is switched [%s]", transmitObjects ? "ON" : "OFF");
01998       ROS_INFO("Tracking mode is set to id [%d] [%s]", trackingMode, trackingModeDescription[trackingMode].c_str());
01999 
02000       deviceIsRadar = true;
02001 
02002       // Asking some informational from the radar
02003       startProtocolSequence.push_back(CMD_DEVICE_TYPE);
02004       startProtocolSequence.push_back(CMD_SERIAL_NUMBER);
02005       startProtocolSequence.push_back(CMD_ORDER_NUMBER);
02006 
02007       /*
02008        * With "sWN TCTrackingMode 0" BASIC-Tracking activated
02009        * With "sWN TCTrackingMode 1" TRAFFIC-Tracking activated
02010        *
02011        */
02012       if (transmitRawTargets)
02013       {
02014         startProtocolSequence.push_back(CMD_SET_TRANSMIT_RAWTARGETS_ON);  // raw targets will be transmitted
02015       }
02016       else
02017       {
02018         startProtocolSequence.push_back(CMD_SET_TRANSMIT_RAWTARGETS_OFF);  // NO raw targets will be transmitted
02019       }
02020 
02021       if (transmitObjects)
02022       {
02023         startProtocolSequence.push_back(CMD_SET_TRANSMIT_OBJECTS_ON);  // tracking objects will be transmitted
02024       }
02025       else
02026       {
02027         startProtocolSequence.push_back(CMD_SET_TRANSMIT_OBJECTS_OFF);  // NO tracking objects will be transmitted
02028       }
02029 
02030       switch (trackingMode)
02031       {
02032         case 0:
02033           startProtocolSequence.push_back(CMD_SET_TRACKING_MODE_0);
02034           break;
02035         case 1:
02036           startProtocolSequence.push_back(CMD_SET_TRACKING_MODE_1);
02037           break;
02038         default:
02039           ROS_DEBUG("Tracking mode switching sequence unknown\n");
02040           break;
02041 
02042       }
02043       // leave user level
02044 
02045       //      sWN TransmitTargets 1
02046       // initializing sequence for radar based devices
02047       startProtocolSequence.push_back(CMD_RUN);  // leave user level
02048       startProtocolSequence.push_back(CMD_START_RADARDATA);
02049     }
02050     else
02051     {
02052       // initializing sequence for laserscanner
02053       startProtocolSequence.push_back(CMD_START_MEASUREMENT);
02054       startProtocolSequence.push_back(CMD_RUN);  // leave user level
02055       startProtocolSequence.push_back(CMD_START_SCANDATA);
02056       if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 4)  // MRS1104 - start IMU-Transfer
02057       {
02058         ros::NodeHandle tmp("~");
02059         bool imu_enable = false;
02060         tmp.getParam("imu_enable", imu_enable);
02061         if (imu_enable)
02062         {
02063           if(useBinaryCmdNow==true)
02064           {
02065             ROS_INFO("Enable IMU data transfer");
02066             // TODO Flag to decide between IMU on or off
02067             startProtocolSequence.push_back(CMD_START_IMU_DATA);
02068           }
02069           else{
02070             ROS_FATAL("IMU USAGE NOT POSSIBLE IN ASCII COMMUNICATION MODE.\nTo use the IMU the communication with the scanner must be set to binary mode.\n This can be done by inserting the line:\n<param name=\"use_binary_protocol\" type=\"bool\" value=\"True\" />\n into the launchfile.\n See also https://github.com/SICKAG/sick_scan/blob/master/doc/IMU.md");
02071             exit(0);
02072           }
02073 
02074         }
02075       }
02076     }
02077 
02078     std::vector<int>::iterator it;
02079     for (it = startProtocolSequence.begin(); it != startProtocolSequence.end(); it++)
02080     {
02081       int cmdId = *it;
02082       std::vector<unsigned char> tmpReply;
02083       //                        sendSopasAndCheckAnswer(sopasCmdVec[cmdId].c_str(), &tmpReply);
02084 
02085       std::string sopasCmd = sopasCmdVec[cmdId];
02086       std::vector<unsigned char> replyDummy;
02087       std::vector<unsigned char> reqBinary;
02088       std::vector<unsigned char> sopasVec;
02089       sopasVec=stringToVector(sopasCmd);
02090       ROS_DEBUG("Command: %s", stripControl(sopasVec).c_str());
02091       if (useBinaryCmd)
02092       {
02093         this->convertAscii2BinaryCmd(sopasCmd.c_str(), &reqBinary);
02094         result = sendSopasAndCheckAnswer(reqBinary, &replyDummy, cmdId);
02095         sopasReplyBinVec[cmdId] = replyDummy;
02096 
02097         switch (cmdId)
02098         {
02099           case CMD_START_SCANDATA:
02100             // ROS_DEBUG("Sleeping for a couple of seconds of start measurement\n");
02101             // ros::Duration(10.0).sleep();
02102             break;
02103         }
02104       }
02105       else
02106       {
02107         result = sendSopasAndCheckAnswer(sopasCmd.c_str(), &replyDummy, cmdId);
02108       }
02109 
02110       if (result != 0)
02111       {
02112         ROS_ERROR("%s", sopasCmdErrMsg[cmdId].c_str());
02113         diagnostics_.broadcast(getDiagnosticErrorCode(), sopasCmdErrMsg[cmdId]);
02114       }
02115       else
02116       {
02117         sopasReplyStrVec[cmdId] = replyToString(replyDummy);
02118       }
02119 
02120 
02121       if (cmdId == CMD_START_RADARDATA)
02122       {
02123         ROS_DEBUG("Starting radar data ....\n");
02124       }
02125 
02126 
02127       if (cmdId == CMD_START_SCANDATA)
02128       {
02129         ROS_DEBUG("Starting scan data ....\n");
02130       }
02131 
02132       if (cmdId == CMD_RUN)
02133       {
02134         bool waitForDeviceState = true;
02135         if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 1)
02136         {
02137           waitForDeviceState = false; // do nothing for tim5xx
02138         }
02139         if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() == 24)
02140         {
02141           waitForDeviceState = false; // do nothing for MRS6xxx
02142         }
02143 
02144         if (waitForDeviceState)
02145         {
02146           int maxWaitForDeviceStateReady = 45;   // max. 30 sec. (see manual)
02147           bool scannerReady = false;
02148           for (int i = 0; i < maxWaitForDeviceStateReady; i++)
02149           {
02150             double shortSleepTime = 1.0;
02151             std::string sopasCmd = sopasCmdVec[CMD_DEVICE_STATE];
02152             std::vector<unsigned char> replyDummy;
02153 
02154             int iRetVal = 0;
02155             int deviceState = 0;
02156 
02157             std::vector<unsigned char> reqBinary;
02158             std::vector<unsigned char> sopasVec;
02159             sopasVec=stringToVector(sopasCmd);
02160             ROS_DEBUG("Command: %s", stripControl(sopasVec).c_str());
02161             if (useBinaryCmd)
02162             {
02163               this->convertAscii2BinaryCmd(sopasCmd.c_str(), &reqBinary);
02164               result = sendSopasAndCheckAnswer(reqBinary, &replyDummy);
02165               sopasReplyBinVec[CMD_DEVICE_STATE] = replyDummy;
02166             }
02167             else
02168             {
02169               result = sendSopasAndCheckAnswer(sopasCmd.c_str(), &replyDummy);
02170               sopasReplyStrVec[CMD_DEVICE_STATE] = replyToString(replyDummy);
02171             }
02172 
02173 
02174             if (useBinaryCmd)
02175             {
02176               long dummy0, dummy1;
02177               dummy0 = 0;
02178               dummy1 = 0;
02179               deviceState = 0;
02180               iRetVal = binScanfVec(&(sopasReplyBinVec[CMD_DEVICE_STATE]), "%4y%4ysRA SCdevicestate %1y", &dummy0,
02181                                     &dummy1, &deviceState);
02182             }
02183             else
02184             {
02185               iRetVal = sscanf(sopasReplyStrVec[CMD_DEVICE_STATE].c_str(), "sRA SCdevicestate %d", &deviceState);
02186             }
02187             if (iRetVal > 0)  // 1 or 3 (depending of ASCII or Binary)
02188             {
02189               if (deviceState == 1) // scanner is ready
02190               {
02191                 scannerReady = true; // interrupt waiting for scanner ready
02192                 ROS_INFO("Scanner ready for measurement after %d [sec]", i);
02193                 break;
02194               }
02195             }
02196             ROS_INFO("Waiting for scanner ready state since %d secs", i);
02197             ros::Duration(shortSleepTime).sleep();
02198 
02199             if (scannerReady)
02200             {
02201               break;
02202             }
02203           }
02204         }
02205       }
02206       tmpReply.clear();
02207 
02208     }
02209     return ExitSuccess;
02210   }
02211 
02212 
02218   std::string sick_scan::SickScanCommon::replyToString(const std::vector<unsigned char> &reply)
02219   {
02220     std::string reply_str;
02221     std::vector<unsigned char>::const_iterator it_start, it_end;
02222     int binLen = this->checkForBinaryAnswer(&reply);
02223     if (binLen == -1) // ASCII-Cmd
02224     {
02225       it_start = reply.begin();
02226       it_end = reply.end();
02227     }
02228     else
02229     {
02230       it_start = reply.begin() + 8; // skip header and length id
02231       it_end = reply.end() - 1; // skip CRC
02232     }
02233     bool inHexPrintMode = false;
02234     for (std::vector<unsigned char>::const_iterator it = it_start; it != it_end; it++)
02235     {
02236       // inHexPrintMode means that we should continue printing hex value after we started with hex-Printing
02237       // That is easier to debug for a human instead of switching between ascii binary and then back to ascii
02238       if (*it >= 0x20 && (inHexPrintMode == false)) // filter control characters for display
02239       {
02240         reply_str.push_back(*it);
02241       }
02242       else
02243       {
02244         if (binLen != -1) // binary
02245         {
02246           char szTmp[255] = {0};
02247           unsigned char val = *it;
02248           inHexPrintMode = true;
02249           sprintf(szTmp, "\\x%02x", val);
02250           for (int ii = 0; ii < strlen(szTmp); ii++)
02251           {
02252             reply_str.push_back(szTmp[ii]);
02253           }
02254         }
02255       }
02256 
02257     }
02258     return reply_str;
02259   }
02260 
02261   bool sick_scan::SickScanCommon::dumpDatagramForDebugging(unsigned char *buffer, int bufLen)
02262   {
02263     bool ret = true;
02264     static int cnt = 0;
02265     char szDumpFileName[255] = {0};
02266     char szDir[255] = {0};
02267     if (cnt == 0)
02268     {
02269       ROS_INFO("Attention: verboseLevel is set to 1. Datagrams are stored in the /tmp folder.");
02270     }
02271 #ifdef _MSC_VER
02272     strcpy(szDir, "C:\\temp\\");
02273 #else
02274     strcpy(szDir, "/tmp/");
02275 #endif
02276     sprintf(szDumpFileName, "%ssick_datagram_%06d.bin", szDir, cnt);
02277     bool isBinary = this->parser_->getCurrentParamPtr()->getUseBinaryProtocol();
02278     if (isBinary)
02279     {
02280       FILE *ftmp;
02281       ftmp = fopen(szDumpFileName, "wb");
02282       if (ftmp != NULL)
02283       {
02284         fwrite(buffer, bufLen, 1, ftmp);
02285         fclose(ftmp);
02286       }
02287     }
02288     cnt++;
02289 
02290     return (true);
02291 
02292   }
02293 
02294 
02300   bool sick_scan::SickScanCommon::isCompatibleDevice(const std::string identStr) const
02301   {
02302     char device_string[7];
02303     int version_major = -1;
02304     int version_minor = -1;
02305 
02306     strcpy(device_string, "???");
02307     // special for TiM3-Firmware
02308     if (sscanf(identStr.c_str(), "sRA 0 6 %6s E V%d.%d", device_string,
02309                &version_major, &version_minor) == 3
02310         && strncmp("TiM3", device_string, 4) == 0
02311         && version_major >= 2 && version_minor >= 50)
02312     {
02313       ROS_ERROR("This scanner model/firmware combination does not support ranging output!");
02314       ROS_ERROR("Supported scanners: TiM5xx: all firmware versions; TiM3xx: firmware versions < V2.50.");
02315       ROS_ERROR("This is a %s, firmware version %d.%d", device_string, version_major, version_minor);
02316 
02317       return false;
02318     }
02319 
02320     bool supported = false;
02321 
02322     // DeviceIdent 8 MRS1xxxx 8 1.3.0.0R.
02323     if (sscanf(identStr.c_str(), "sRA 0 6 %6s E V%d.%d", device_string, &version_major, &version_minor) == 3)
02324     {
02325       std::string devStr = device_string;
02326 
02327 
02328       if (devStr.compare(0, 4, "TiM5") == 0)
02329       {
02330         supported = true;
02331       }
02332 
02333       if (supported == true)
02334       {
02335         ROS_INFO("Device %s V%d.%d found and supported by this driver.", identStr.c_str(), version_major,
02336                  version_minor);
02337       }
02338 
02339     }
02340 
02341     if ((identStr.find("MRS1xxx") !=
02342          std::string::npos)   // received pattern contains 4 'x' but we check only for 3 'x' (MRS1104 should be MRS1xxx)
02343         || (identStr.find("LMS1xxx") != std::string::npos)
02344         )
02345     {
02346       ROS_INFO("Deviceinfo %s found and supported by this driver.", identStr.c_str());
02347       supported = true;
02348     }
02349 
02350 
02351     if (identStr.find("MRS6") !=
02352         std::string::npos)  // received pattern contains 4 'x' but we check only for 3 'x' (MRS1104 should be MRS1xxx)
02353     {
02354       ROS_INFO("Deviceinfo %s found and supported by this driver.", identStr.c_str());
02355       supported = true;
02356     }
02357 
02358     if (identStr.find("RMS3xx") !=
02359         std::string::npos)   // received pattern contains 4 'x' but we check only for 3 'x' (MRS1104 should be MRS1xxx)
02360     {
02361       ROS_INFO("Deviceinfo %s found and supported by this driver.", identStr.c_str());
02362       supported = true;
02363     }
02364 
02365 
02366     if (supported == false)
02367     {
02368       ROS_WARN("Device %s V%d.%d found and maybe unsupported by this driver.", device_string, version_major,
02369                version_minor);
02370       ROS_WARN("Full SOPAS answer: %s", identStr.c_str());
02371     }
02372     return true;
02373   }
02374 
02375 
02380   int SickScanCommon::loopOnce()
02381   {
02382     static int cnt = 0;
02383     diagnostics_.update();
02384 
02385     unsigned char receiveBuffer[65536];
02386     int actual_length = 0;
02387     static unsigned int iteration_count = 0;
02388     bool useBinaryProtocol = this->parser_->getCurrentParamPtr()->getUseBinaryProtocol();
02389 
02390     ros::Time recvTimeStamp = ros::Time::now();  // timestamp incoming package, will be overwritten by get_datagram
02391     // tcp packet
02392     ros::Time recvTimeStampPush = ros::Time::now();  // timestamp
02393 
02394     /*
02395      * Try to get datagram
02396      *
02397      *
02398      */
02399 
02400 
02401     int packetsInLoop = 0;
02402 
02403     const int maxNumAllowedPacketsToProcess = 25; // maximum number of packets, which will be processed in this loop.
02404 
02405     int numPacketsProcessed = 0; // count number of processed datagrams
02406 
02407     static bool firstTimeCalled = true;
02408     static bool dumpData = false;
02409     static int verboseLevel = 0;
02410     static bool slamBundle = false;
02411     float timeIncrement;
02412     static std::string echoForSlam = "";
02413     if (firstTimeCalled == true)
02414     {
02415 
02416     /* Dump Binary Protocol */
02417     ros::NodeHandle tmpParam("~");
02418     tmpParam.getParam("slam_echo", echoForSlam);
02419     tmpParam.getParam("slam_bundle", slamBundle);
02420     tmpParam.getParam("verboseLevel", verboseLevel);
02421       firstTimeCalled = false;
02422     }
02423     do
02424     {
02425 
02426       int result = get_datagram(recvTimeStamp, receiveBuffer, 65536, &actual_length, useBinaryProtocol, &packetsInLoop);
02427       numPacketsProcessed++;
02428 
02429       ros::Duration dur = recvTimeStampPush - recvTimeStamp;
02430 
02431       if (result != 0)
02432       {
02433         ROS_ERROR("Read Error when getting datagram: %i.", result);
02434         diagnostics_.broadcast(getDiagnosticErrorCode(), "Read Error when getting datagram.");
02435         return ExitError; // return failure to exit node
02436       }
02437       if (actual_length <= 0)
02438       {
02439         return ExitSuccess;
02440       } // return success to continue looping
02441 
02442       // ----- if requested, skip frames
02443       if (iteration_count++ % (config_.skip + 1) != 0)
02444         return ExitSuccess;
02445 
02446       if (publish_datagram_)
02447       {
02448         std_msgs::String datagram_msg;
02449         datagram_msg.data = std::string(reinterpret_cast<char *>(receiveBuffer));
02450         datagram_pub_.publish(datagram_msg);
02451       }
02452 
02453 
02454       if (verboseLevel > 0)
02455       {
02456         dumpDatagramForDebugging(receiveBuffer, actual_length);
02457       }
02458 
02459 
02460       bool deviceIsRadar = false;
02461 
02462       if (this->parser_->getCurrentParamPtr()->getDeviceIsRadar() == true)
02463       {
02464         deviceIsRadar = true;
02465       }
02466 
02467       if (true == deviceIsRadar)
02468       {
02469         SickScanRadar radar(this);
02470         int errorCode = ExitSuccess;
02471         // parse radar telegram and send pointcloud2-debug messages
02472         errorCode = radar.parseDatagram(recvTimeStamp, (unsigned char *) receiveBuffer, actual_length,
02473                                         useBinaryProtocol);
02474         return errorCode; // return success to continue looping
02475       }
02476 
02477       static SickScanImu scanImu(this); // todo remove static
02478       if (scanImu.isImuDatagram((char *) receiveBuffer, actual_length))
02479       {
02480         int errorCode = ExitSuccess;
02481         if (scanImu.isImuAckDatagram((char *) receiveBuffer, actual_length))
02482         {
02483 
02484         }
02485         else
02486         {
02487           // parse radar telegram and send pointcloud2-debug messages
02488           errorCode = scanImu.parseDatagram(recvTimeStamp, (unsigned char *) receiveBuffer, actual_length,
02489                                             useBinaryProtocol);
02490 
02491         }
02492         return errorCode; // return success to continue looping
02493 
02494 
02495       }
02496       else
02497       {
02498 
02499         sensor_msgs::LaserScan msg;
02500 
02501         msg.header.stamp = recvTimeStamp;
02502         double elevationAngleInRad = 0.0;
02503         /*
02504          * datagrams are enclosed in <STX> (0x02), <ETX> (0x03) pairs
02505          */
02506         char *buffer_pos = (char *) receiveBuffer;
02507         char *dstart, *dend;
02508         bool dumpDbg = true; // !!!!!
02509         bool dataToProcess = true;
02510         std::vector<float> vang_vec;
02511         vang_vec.clear();
02512         while (dataToProcess)
02513         {
02514           const int maxAllowedEchos = 5;
02515 
02516           int numValidEchos = 0;
02517           int aiValidEchoIdx[maxAllowedEchos] = {0};
02518           size_t dlength;
02519           int success = -1;
02520           int numEchos = 0;
02521           int echoMask = 0;
02522           bool publishPointCloud = true;
02523 
02524           if (useBinaryProtocol)
02525           {
02526             // if binary protocol used then parse binary message
02527             std::vector<unsigned char> receiveBufferVec = std::vector<unsigned char>(receiveBuffer,
02528                                                                                      receiveBuffer + actual_length);
02529 #ifdef DEBUG_DUMP_TO_CONSOLE_ENABLED
02530             if (actual_length > 1000)
02531             {
02532               DataDumper::instance().dumpUcharBufferToConsole(receiveBuffer, actual_length);
02533 
02534             }
02535 
02536             DataDumper::instance().dumpUcharBufferToConsole(receiveBuffer, actual_length);
02537             #endif
02538             if (receiveBufferVec.size() > 8)
02539             {
02540               long idVal = 0;
02541               long lenVal = 0;
02542               memcpy(&idVal, receiveBuffer + 0, 4);  // read identifier
02543               memcpy(&lenVal, receiveBuffer + 4, 4);  // read length indicator
02544               swap_endian((unsigned char *) &lenVal, 4);
02545 
02546               if (idVal == 0x02020202)  // id for binary message
02547               {
02548 #if  0
02549                 {
02550                   static int cnt = 0;
02551                   char szFileName[255];
02552 
02553 #ifdef _MSC_VER
02554                   sprintf(szFileName, "c:\\temp\\dump%05d.bin", cnt);
02555 #else
02556                   sprintf(szFileName, "/tmp/dump%05d.txt", cnt);
02557 #endif
02558                   FILE *fout;
02559                   fout = fopen(szFileName, "wb");
02560                   fwrite(receiveBuffer, actual_length, 1, fout);
02561                   fclose(fout);
02562                   cnt++;
02563                 }
02564 #endif
02565                 // binary message
02566                 if (lenVal < actual_length)
02567                 {
02568                   short elevAngleX200 = 0;  // signed short (F5 B2  -> Layer 24
02569                   // F5B2h -> -2638/200= -13.19°
02570                   int scanFrequencyX100 = 0;
02571                   double elevAngle = 0.00;
02572                   double scanFrequency = 0.0;
02573                   long measurementFrequencyDiv100 = 0; // multiply with 100
02574                   int numberOf16BitChannels = 0;
02575                   int numberOf8BitChannels = 0;
02576                   uint32_t SystemCountScan=0;
02577                   uint32_t SystemCountTransmit=0;
02578 
02579                   memcpy(&elevAngleX200, receiveBuffer + 50, 2);
02580                   swap_endian((unsigned char *) &elevAngleX200, 2);
02581 
02582                   elevationAngleInRad = -elevAngleX200 / 200.0 * deg2rad_const;
02583 
02584                   msg.header.seq = elevAngleX200; // should be multiple of 0.625° starting with -2638 (corresponding to 13.19°)
02585 
02586                   memcpy(&SystemCountScan, receiveBuffer + 0x26, 4);
02587                   swap_endian((unsigned char *) &SystemCountScan, 4);
02588 
02589                   memcpy(&SystemCountTransmit, receiveBuffer + 0x2A, 4);
02590                   swap_endian((unsigned char *) &SystemCountTransmit, 4);
02591                   bool bRet = SoftwarePLL::instance().updatePLL(recvTimeStamp.sec, recvTimeStamp.nsec,SystemCountTransmit);
02592                   ros::Time tmp_time=recvTimeStamp;
02593                   bRet = SoftwarePLL::instance().getCorrectedTimeStamp(recvTimeStamp.sec, recvTimeStamp.nsec,SystemCountScan);
02594                   //TODO Handle return values
02595                   ros::Duration debug_duration=recvTimeStamp-tmp_time;
02596 #ifdef DEBUG_DUMP_ENABLED
02597                   double elevationAngleInDeg=elevationAngleInRad = -elevAngleX200 / 200.0;
02598                   // DataDumper::instance().pushData((double)SystemCountScan, "LAYER", elevationAngleInDeg);
02599                   //DataDumper::instance().pushData((double)SystemCountScan, "LASESCANTIME", SystemCountScan);
02600                   //DataDumper::instance().pushData((double)SystemCountTransmit, "LASERTRANSMITTIME", SystemCountTransmit);
02601                   //DataDumper::instance().pushData((double)SystemCountScan, "LASERTRANSMITDELAY", debug_duration.toSec());
02602 #endif
02603 
02604                   memcpy(&scanFrequencyX100, receiveBuffer + 52, 4);
02605                   swap_endian((unsigned char *) &scanFrequencyX100, 4);
02606 
02607                   memcpy(&measurementFrequencyDiv100, receiveBuffer + 56, 4);
02608                   swap_endian((unsigned char *) &measurementFrequencyDiv100, 4);
02609 
02610 
02611                   msg.scan_time = 1.0 / (scanFrequencyX100 / 100.0);
02612 
02613                   //due firmware inconsistency
02614                   if(measurementFrequencyDiv100>10000)
02615                   {
02616                     measurementFrequencyDiv100/=100;
02617                   }
02618                   msg.time_increment = 1.0 / (measurementFrequencyDiv100 * 100.0);
02619                   timeIncrement=msg.time_increment;
02620                   msg.range_min = parser_->get_range_min();
02621                   msg.range_max = parser_->get_range_max();
02622 
02623                   memcpy(&numberOf16BitChannels, receiveBuffer + 62, 2);
02624                   swap_endian((unsigned char *) &numberOf16BitChannels, 2);
02625 
02626                   int parseOff = 64;
02627 
02628 
02629                   char szChannel[255] = {0};
02630                   float scaleFactor = 1.0;
02631                   float scaleFactorOffset = 0.0;
02632                   int32_t startAngleDiv10000 = 1;
02633                   int32_t sizeOfSingleAngularStepDiv10000 = 1;
02634                   double startAngle = 0.0;
02635                   double sizeOfSingleAngularStep = 0.0;
02636                   short numberOfItems = 0;
02637 
02638                   static int cnt = 0;
02639                   cnt++;
02640                   // get number of 8 bit channels
02641                   // we must jump of the 16 bit data blocks including header ...
02642                   for (int i = 0; i < numberOf16BitChannels; i++)
02643                   {
02644                     int numberOfItems = 0x00;
02645                     memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
02646                     swap_endian((unsigned char *) &numberOfItems, 2);
02647                     parseOff += 21; // 21 Byte header followed by data entries
02648                     parseOff += numberOfItems * 2;
02649                   }
02650 
02651                   // now we can read the number of 8-Bit-Channels
02652                   memcpy(&numberOf8BitChannels, receiveBuffer + parseOff, 2);
02653                   swap_endian((unsigned char *) &numberOf8BitChannels, 2);
02654 
02655                   parseOff = 64;
02656                   enum datagram_parse_task
02657                   {
02658                     process_dist,
02659                     process_vang,
02660                     process_rssi,
02661                     process_idle
02662                   };
02663                   for (int processLoop = 0; processLoop < 2; processLoop++)
02664                   {
02665                     int totalChannelCnt = 0;
02666                     int distChannelCnt;
02667                     int rssiCnt;
02668                     bool bCont = true;
02669                     int vangleCnt;
02670                     datagram_parse_task task = process_idle;
02671                     bool parsePacket = true;
02672                     parseOff = 64;
02673                     bool processData = false;
02674 
02675                     if (processLoop == 0)
02676                     {
02677                       distChannelCnt = 0;
02678                       rssiCnt = 0;
02679                       vangleCnt = 0;
02680                     }
02681 
02682                     if (processLoop == 1)
02683                     {
02684                       processData = true;
02685                       numEchos = distChannelCnt;
02686                       msg.ranges.resize(numberOfItems * numEchos);
02687                       if (rssiCnt > 0)
02688                       {
02689                         msg.intensities.resize(numberOfItems * rssiCnt);
02690                       }
02691                       else
02692                       {
02693                       }
02694                       if (vangleCnt > 0) // should be 0 or 1
02695                       {
02696                         vang_vec.resize(numberOfItems * vangleCnt);
02697                       }
02698                       else
02699                       {
02700                         vang_vec.clear();
02701                       }
02702                       echoMask = (1 << numEchos) - 1;
02703 
02704                       // reset count. We will use the counter for index calculation now.
02705                       distChannelCnt = 0;
02706                       rssiCnt = 0;
02707                       vangleCnt = 0;
02708 
02709                     }
02710 
02711                     szChannel[6] = '\0';
02712                     scaleFactor = 1.0;
02713                     scaleFactorOffset = 0.0;
02714                     startAngleDiv10000 = 1;
02715                     sizeOfSingleAngularStepDiv10000 = 1;
02716                     startAngle = 0.0;
02717                     sizeOfSingleAngularStep = 0.0;
02718                     numberOfItems = 0;
02719 
02720 
02721 #if 1 // prepared for multiecho parsing
02722 
02723                     bCont = true;
02724                     bool doVangVecProc = false;
02725                     // try to get number of DIST and RSSI from binary data
02726                     task = process_idle;
02727                     do
02728                     {
02729                       task = process_idle;
02730                       doVangVecProc = false;
02731                       int processDataLenValuesInBytes = 2;
02732 
02733                       if (totalChannelCnt == numberOf16BitChannels)
02734                       {
02735                         parseOff += 2; // jump of number of 8 bit channels- already parsed above
02736                       }
02737 
02738                       if (totalChannelCnt >= numberOf16BitChannels)
02739                       {
02740                         processDataLenValuesInBytes = 1; // then process 8 bit values ...
02741                       }
02742                       bCont = false;
02743                       strcpy(szChannel, "");
02744 
02745                       if (totalChannelCnt < (numberOf16BitChannels + numberOf8BitChannels))
02746                       {
02747                         szChannel[5] = '\0';
02748                         strncpy(szChannel, (const char *) receiveBuffer + parseOff, 5);
02749                       }
02750                       else
02751                       {
02752                         // all channels processed (16 bit and 8 bit channels)
02753                       }
02754 
02755                       if (strstr(szChannel, "DIST") == szChannel)
02756                       {
02757                         task = process_dist;
02758                         distChannelCnt++;
02759                         bCont = true;
02760                         numberOfItems = 0;
02761                         memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
02762                         swap_endian((unsigned char *) &numberOfItems, 2);
02763 
02764                       }
02765                       if (strstr(szChannel, "VANG") == szChannel)
02766                       {
02767                         vangleCnt++;
02768                         task = process_vang;
02769                         bCont = true;
02770                         numberOfItems = 0;
02771                         memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
02772                         swap_endian((unsigned char *) &numberOfItems, 2);
02773 
02774                         vang_vec.resize(numberOfItems);
02775 
02776                       }
02777                       if (strstr(szChannel, "RSSI") == szChannel)
02778                       {
02779                         task = process_rssi;
02780                         rssiCnt++;
02781                         bCont = true;
02782                         numberOfItems = 0;
02783                         // copy two byte value (unsigned short to  numberOfItems
02784                         memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
02785                         swap_endian((unsigned char *) &numberOfItems, 2); // swap
02786 
02787                       }
02788                       if (bCont)
02789                       {
02790                         scaleFactor = 0.0;
02791                         scaleFactorOffset = 0.0;
02792                         startAngleDiv10000 = 0;
02793                         sizeOfSingleAngularStepDiv10000 = 0;
02794                         numberOfItems = 0;
02795 
02796                         memcpy(&scaleFactor, receiveBuffer + parseOff + 5, 4);
02797                         memcpy(&scaleFactorOffset, receiveBuffer + parseOff + 9, 4);
02798                         memcpy(&startAngleDiv10000, receiveBuffer + parseOff + 13, 4);
02799                         memcpy(&sizeOfSingleAngularStepDiv10000, receiveBuffer + parseOff + 17, 2);
02800                         memcpy(&numberOfItems, receiveBuffer + parseOff + 19, 2);
02801 
02802 
02803                         swap_endian((unsigned char *) &scaleFactor, 4);
02804                         swap_endian((unsigned char *) &scaleFactorOffset, 4);
02805                         swap_endian((unsigned char *) &startAngleDiv10000, 4);
02806                         swap_endian((unsigned char *) &sizeOfSingleAngularStepDiv10000, 2);
02807                         swap_endian((unsigned char *) &numberOfItems, 2);
02808 
02809                         if (processData)
02810                         {
02811                           unsigned short *data = (unsigned short *) (receiveBuffer + parseOff + 21);
02812 
02813                           unsigned char *swapPtr = (unsigned char *) data;
02814                           // copy RSSI-Values +2 for 16-bit values +1 for 8-bit value
02815                           for (int i = 0;
02816                                i < numberOfItems * processDataLenValuesInBytes; i += processDataLenValuesInBytes)
02817                           {
02818                             if (processDataLenValuesInBytes == 1)
02819                             {
02820                             }
02821                             else
02822                             {
02823                               unsigned char tmp;
02824                               tmp = swapPtr[i + 1];
02825                               swapPtr[i + 1] = swapPtr[i];
02826                               swapPtr[i] = tmp;
02827                             }
02828                           }
02829                           int idx = 0;
02830 
02831                           switch (task)
02832                           {
02833 
02834                             case process_dist:
02835                             {
02836                               startAngle = startAngleDiv10000 / 10000.00;
02837                               sizeOfSingleAngularStep = sizeOfSingleAngularStepDiv10000 / 10000.0;
02838                               sizeOfSingleAngularStep *= (M_PI / 180.0);
02839 
02840                               msg.angle_min = startAngle / 180.0 * M_PI - M_PI / 2;
02841                               msg.angle_increment = sizeOfSingleAngularStep;
02842                               msg.angle_max = msg.angle_min + (numberOfItems - 1) * msg.angle_increment;
02843 
02844                               float *rangePtr = NULL;
02845 
02846                               if (numberOfItems > 0)
02847                               {
02848                                 rangePtr = &msg.ranges[0];
02849                               }
02850                               float scaleFactor_001= 0.001F * scaleFactor;// to avoid repeated multiplication
02851                               for (int i = 0; i < numberOfItems; i++)
02852                               {
02853                                 idx = i + numberOfItems * (distChannelCnt - 1);
02854                                 rangePtr[idx] = (float) data[i] *  scaleFactor_001 + scaleFactorOffset;
02855 #ifdef DEBUG_DUMP_ENABLED
02856                                 if (distChannelCnt == 1)
02857                                 {
02858                                   if (i == floor(numberOfItems / 2))
02859                                   {
02860                                   double curTimeStamp = SystemCountScan + i * msg.time_increment * 1E6;
02861                                   //DataDumper::instance().pushData(curTimeStamp, "DIST", rangePtr[idx]);
02862                                 }
02863                                 }
02864 #endif
02865                                 //XXX
02866                               }
02867 
02868                             }
02869                               break;
02870                             case process_rssi:
02871                             {
02872                               // Das muss vom Protokoll abgeleitet werden. !!!
02873 
02874                               float *intensityPtr = NULL;
02875 
02876                               if (numberOfItems > 0)
02877                               {
02878                                 intensityPtr = &msg.intensities[0];
02879 
02880                               }
02881                               for (int i = 0; i < numberOfItems; i++)
02882                               {
02883                                 idx = i + numberOfItems * (rssiCnt - 1);
02884                                 // we must select between 16 bit and 8 bit values
02885                                 float rssiVal = 0.0;
02886                                 if (processDataLenValuesInBytes == 2)
02887                                 {
02888                                   rssiVal = (float) data[i];
02889                                 }
02890                                 else
02891                                 {
02892                                   unsigned char *data8Ptr = (unsigned char *) data;
02893                                   rssiVal = (float) data8Ptr[i];
02894                                 }
02895                                 intensityPtr[idx] = rssiVal * scaleFactor + scaleFactorOffset;
02896                               }
02897                             }
02898                               break;
02899 
02900                             case process_vang:
02901                               float *vangPtr = NULL;
02902                               if (numberOfItems > 0)
02903                               {
02904                                 vangPtr = &vang_vec[0]; // much faster, with vang_vec[i] each time the size will be checked
02905                               }
02906                               for (int i = 0; i < numberOfItems; i++)
02907                               {
02908                                 vangPtr[i] = (float) data[i] * scaleFactor + scaleFactorOffset;
02909                               }
02910                               break;
02911                           }
02912                         }
02913                         parseOff += 21 + processDataLenValuesInBytes * numberOfItems;
02914 
02915 
02916                       }
02917                       totalChannelCnt++;
02918                     } while (bCont);
02919                   }
02920 #endif
02921 
02922                   elevAngle = elevAngleX200 / 200.0;
02923                   scanFrequency = scanFrequencyX100 / 100.0;
02924 
02925 
02926                 }
02927               }
02928             }
02929 
02930 
02931             parser_->checkScanTiming(msg.time_increment, msg.scan_time, msg.angle_increment, 0.00001f);
02932 
02933             success = ExitSuccess;
02934             // change Parsing Mode
02935             dataToProcess = false; // only one package allowed - no chaining
02936           }
02937           else // Parsing of Ascii-Encoding of datagram, xxx
02938           {
02939             dstart = strchr(buffer_pos, 0x02);
02940             if (dstart != NULL)
02941             {
02942               dend = strchr(dstart + 1, 0x03);
02943             }
02944             if ((dstart != NULL) && (dend != NULL))
02945             {
02946               dataToProcess = true; // continue parasing
02947               dlength = dend - dstart;
02948               *dend = '\0';
02949               dstart++;
02950             }
02951             else
02952             {
02953               dataToProcess = false;
02954               break; //
02955             }
02956 
02957             if (dumpDbg)
02958             {
02959               {
02960                 static int cnt = 0;
02961                 char szFileName[255];
02962 
02963 #ifdef _MSC_VER
02964                 sprintf(szFileName, "c:\\temp\\dump%05d.txt", cnt);
02965 #else
02966                 sprintf(szFileName, "/tmp/dump%05d.txt", cnt);
02967 #endif
02968                 FILE *fout;
02969                 fout = fopen(szFileName, "wb");
02970                 fwrite(dstart, dlength, 1, fout);
02971                 fclose(fout);
02972                 cnt++;
02973               }
02974             }
02975 
02976             // HEADER of data followed by DIST1 ... DIST2 ... DIST3 .... RSSI1 ... RSSI2.... RSSI3...
02977 
02978             // <frameid>_<sign>00500_DIST[1|2|3]
02979             numEchos = 1;
02980             // numEchos contains number of echos (1..5)
02981             // _msg holds ALL data of all echos
02982             success = parser_->parse_datagram(dstart, dlength, config_, msg, numEchos, echoMask);
02983             publishPointCloud = true; // for MRS1000
02984 
02985             numValidEchos = 0;
02986             for (int i = 0; i < maxAllowedEchos; i++)
02987             {
02988               aiValidEchoIdx[i] = 0;
02989             }
02990           }
02991 
02992 
02993           int numOfLayers = parser_->getCurrentParamPtr()->getNumberOfLayers();
02994 
02995           if (success == ExitSuccess)
02996           {
02997             bool elevationPreCalculated = false;
02998             double elevationAngleDegree = 0.0;
02999 
03000 
03001             std::vector<float> rangeTmp = msg.ranges;  // copy all range value
03002             std::vector<float> intensityTmp = msg.intensities; // copy all intensity value
03003 
03004             int intensityTmpNum = intensityTmp.size();
03005             float *intensityTmpPtr = NULL;
03006             if (intensityTmpNum > 0)
03007             {
03008               intensityTmpPtr = &intensityTmp[0];
03009             }
03010 
03011             // Helpful: https://answers.ros.org/question/191265/pointcloud2-access-data/
03012             // https://gist.github.com/yuma-m/b5dcce1b515335c93ce8
03013             // Copy to pointcloud
03014             int layer = 0;
03015             int baseLayer = 0;
03016             bool useGivenElevationAngle = false;
03017             switch (numOfLayers)
03018             {
03019               case 1: // TIM571 etc.
03020                 baseLayer = 0;
03021                 break;
03022               case 4:
03023 
03024                 baseLayer = -1;
03025                 if (msg.header.seq == 250) layer = -1;
03026                 else if (msg.header.seq == 0) layer = 0;
03027                 else if (msg.header.seq == -250) layer = 1;
03028                 else if (msg.header.seq == -500) layer = 2;
03029                 elevationAngleDegree = this->parser_->getCurrentParamPtr()->getElevationDegreeResolution();
03030                 elevationAngleDegree = elevationAngleDegree / 180.0 * M_PI;
03031                 // 0.0436332 /*2.5 degrees*/;
03032                 break;
03033               case 24: // Preparation for MRS6000
03034                 baseLayer = -1;
03035                 layer = (msg.header.seq - (-2638)) / 125;
03036                 layer = (23 - layer) - 1;
03037 #if 0
03038               elevationAngleDegree = this->parser_->getCurrentParamPtr()->getElevationDegreeResolution();
03039               elevationAngleDegree = elevationAngleDegree / 180.0 * M_PI;
03040 #endif
03041 
03042                 elevationPreCalculated = true;
03043                 if (vang_vec.size() > 0)
03044                 {
03045                   useGivenElevationAngle = true;
03046                 }
03047                 break;
03048               default:
03049                 assert(0);
03050                 break; // unsupported
03051 
03052             }
03053 
03054 
03055 
03056 
03057 
03058             // XXX  - HIER MEHRERE SCANS publish, falls Mehrzielszenario läuft
03059             if (numEchos > 5)
03060             {
03061               ROS_WARN("Too much echos");
03062             }
03063             else
03064             {
03065 
03066               int startOffset = 0;
03067               int endOffset = 0;
03068               int echoPartNum = msg.ranges.size() / numEchos;
03069               for (int i = 0; i < numEchos; i++)
03070               {
03071 
03072                 bool sendMsg = false;
03073                 if ((echoMask & (1 << i)) & outputChannelFlagId)
03074                 {
03075                   aiValidEchoIdx[numValidEchos] = i; // save index
03076                   numValidEchos++;
03077                   sendMsg = true;
03078                 }
03079                 startOffset = i * echoPartNum;
03080                 endOffset = (i + 1) * echoPartNum;
03081 
03082                 msg.ranges.clear();
03083                 msg.intensities.clear();
03084                 msg.ranges = std::vector<float>(
03085                     rangeTmp.begin() + startOffset,
03086                     rangeTmp.begin() + endOffset);
03087                 // check also for MRS1104
03088                 if (endOffset <= intensityTmp.size() && (intensityTmp.size() > 0))
03089                 {
03090                   msg.intensities = std::vector<float>(
03091                       intensityTmp.begin() + startOffset,
03092                       intensityTmp.begin() + endOffset);
03093                 }
03094                 else
03095                 {
03096                   msg.intensities.resize(echoPartNum); // fill with zeros
03097                 }
03098                 {
03099                   // numEchos
03100                   char szTmp[255] = {0};
03101                   if (this->parser_->getCurrentParamPtr()->getNumberOfLayers() > 1)
03102                   {
03103                     const char *cpFrameId = config_.frame_id.c_str();
03104 #if 0
03105                     sprintf(szTmp, "%s_%+04d_DIST%d", cpFrameId, msg.header.seq, i + 1);
03106 #else // experimental
03107                     char szSignName[10] = {0};
03108                     if ((int) msg.header.seq < 0)
03109                     {
03110                       strcpy(szSignName, "NEG");
03111                     }
03112                     else
03113                     {
03114                       strcpy(szSignName, "POS");
03115 
03116                     }
03117 
03118                     sprintf(szTmp, "%s_%s_%03d_DIST%d", cpFrameId, szSignName, abs((int) msg.header.seq), i + 1);
03119 #endif
03120                   }
03121                   else
03122                   {
03123                     strcpy(szTmp, config_.frame_id.c_str());
03124                   }
03125 
03126                   msg.header.frame_id = std::string(szTmp);
03127                   // Hector slam can only process ONE valid frame id.
03128                   if (echoForSlam.length() > 0)
03129                   {
03130                     if (slamBundle)
03131                     {
03132                       // try to map first echos to horizontal layers.
03133                       if (i == 0)
03134                       {
03135                         // first echo
03136                         msg.header.frame_id = echoForSlam;
03137                         strcpy(szTmp, echoForSlam.c_str());  //
03138                         if (elevationAngleInRad != 0.0)
03139                         {
03140                           float cosVal = cos(elevationAngleInRad);
03141                           int rangeNum = msg.ranges.size();
03142                           for (int j = 0; j < rangeNum; j++)
03143                           {
03144                             msg.ranges[j] *= cosVal;
03145                           }
03146                         }
03147                       }
03148                     }
03149 
03150                     if (echoForSlam.compare(szTmp) == 0)
03151                     {
03152                       sendMsg = true;
03153                     }
03154                     else
03155                     {
03156                       sendMsg = false;
03157                     }
03158                   }
03159 
03160                 }
03161 #ifndef _MSC_VER
03162                 if (numOfLayers > 4)
03163                 {
03164                   sendMsg = false; // too many layers for publish as scan message. Only pointcloud messages will be pub.
03165                 }
03166                 if (sendMsg &
03167                     outputChannelFlagId)  // publish only configured channels - workaround for cfg-bug MRS1104
03168                 {
03169 
03170                   pub_.publish(msg);
03171                 }
03172 #else
03173                 printf("MSG received...");
03174 #endif
03175               }
03176             }
03177 
03178 
03179 
03180             if (publishPointCloud == true)
03181             {
03182 
03183 
03184 
03185               const int numChannels = 4; // x y z i (for intensity)
03186 
03187               int numTmpLayer = numOfLayers;
03188 
03189 
03190               cloud_.header.stamp = recvTimeStamp;
03191               cloud_.header.frame_id = config_.frame_id;
03192               cloud_.header.seq = 0;
03193               cloud_.height = numTmpLayer * numValidEchos; // due to multi echo multiplied by num. of layers
03194               cloud_.width = msg.ranges.size();
03195               cloud_.is_bigendian = false;
03196               cloud_.is_dense = true;
03197               cloud_.point_step = numChannels * sizeof(float);
03198               cloud_.row_step = cloud_.point_step * cloud_.width;
03199               cloud_.fields.resize(numChannels);
03200               for (int i = 0; i < numChannels; i++)
03201               {
03202                 std::string channelId[] = {"x", "y", "z", "intensity"};
03203                 cloud_.fields[i].name = channelId[i];
03204                 cloud_.fields[i].offset = i * sizeof(float);
03205                 cloud_.fields[i].count = 1;
03206                 cloud_.fields[i].datatype = sensor_msgs::PointField::FLOAT32;
03207               }
03208 
03209               cloud_.data.resize(cloud_.row_step * cloud_.height);
03210 
03211               unsigned char *cloudDataPtr = &(cloud_.data[0]);
03212 
03213 
03214               // prepare lookup for elevation angle table
03215 
03216               std::vector<float> cosAlphaTable;
03217               std::vector<float> sinAlphaTable;
03218               int rangeNum = rangeTmp.size() / numValidEchos;
03219               cosAlphaTable.resize(rangeNum);
03220               sinAlphaTable.resize(rangeNum);
03221 
03222               for (size_t iEcho = 0; iEcho < numValidEchos; iEcho++)
03223               {
03224 
03225                 float angle = config_.min_ang;
03226 
03227 
03228                 float *cosAlphaTablePtr = &cosAlphaTable[0];
03229                 float *sinAlphaTablePtr = &sinAlphaTable[0];
03230 
03231                 float *vangPtr = &vang_vec[0];
03232                 float *rangeTmpPtr = &rangeTmp[0];
03233                 for (size_t i = 0; i < rangeNum; i++)
03234                 {
03235                   enum enum_index_descr
03236                   {
03237                     idx_x,
03238                     idx_y,
03239                     idx_z,
03240                     idx_intensity,
03241                     idx_num
03242                   };
03243                   long adroff = i * (numChannels * (int) sizeof(float));
03244 
03245                     adroff += (layer - baseLayer) * cloud_.row_step;
03246 
03247                   adroff += iEcho * cloud_.row_step * numTmpLayer;
03248 
03249                   unsigned char *ptr = cloudDataPtr + adroff;
03250                   float  *fptr = (float *)(cloudDataPtr + adroff);
03251 
03252                   geometry_msgs::Point32 point;
03253                   float range_meter = rangeTmpPtr[iEcho * rangeNum + i];
03254                   float phi = angle; // azimuth angle
03255                   float alpha = 0.0;  // elevation angle
03256 
03257                   if (useGivenElevationAngle) // FOR MRS6124
03258                   {
03259                     alpha = -vangPtr[i] * deg2rad_const;
03260                   }
03261                   else
03262                   {
03263                     if (elevationPreCalculated) // FOR MRS6124 without VANGL
03264                     {
03265                       alpha = elevationAngleInRad;
03266                     }
03267                     else
03268                     {
03269                       alpha = layer * elevationAngleDegree; // for MRS1104
03270                     }
03271                   }
03272 
03273                   if (iEcho == 0)
03274                   {
03275                     cosAlphaTablePtr[i] = cos(alpha);
03276                     sinAlphaTablePtr[i] = sin(alpha);
03277                   }
03278                   else
03279                   {
03280                     // Just for Debugging: printf("%3d %8.3lf %8.3lf\n", (int)i, cosAlphaTablePtr[i], sinAlphaTablePtr[i]);
03281                   }
03282                   // Thanks to Sebastian Pütz <spuetz@uos.de> for his hint
03283                   float rangeCos=range_meter * cosAlphaTablePtr[i];
03284                   fptr[idx_x] = rangeCos * cos(phi);  // copy x value in pointcloud
03285                   fptr[idx_y] = rangeCos * sin(phi);  // copy y value in pointcloud
03286                   fptr[idx_z] = range_meter * sinAlphaTablePtr[i];// copy z value in pointcloud
03287 
03288                   fptr[idx_intensity] = 0.0;
03289                   if (config_.intensity)
03290                   {
03291                     int intensityIndex = aiValidEchoIdx[iEcho] * rangeNum + i;
03292                     // intensity values available??
03293                     if (intensityIndex < intensityTmpNum)
03294                     {
03295                       fptr[idx_intensity] = intensityTmpPtr[intensityIndex]; // copy intensity value in pointcloud
03296                     }
03297                   }
03298                   angle += msg.angle_increment;
03299                 }
03300                 // Publish
03301                 static int cnt = 0;
03302                 int layerOff = (layer - baseLayer);
03303 
03304               }
03305               // if ( (msg.header.seq == 0) || (layerOff == 0)) // FIXEN!!!!
03306               bool shallIFire = false;
03307               if ((msg.header.seq == 0) || (msg.header.seq == 237))
03308               {
03309                 shallIFire = true;
03310               }
03311 
03312 
03313               static int layerCnt = 0;
03314               static int layerSeq[4];
03315 
03316               if (config_.cloud_output_mode>0)
03317               {
03318 
03319                   layerSeq[layerCnt % 4] = layer;
03320                   if (layerCnt >= 4)  // mind. erst einmal vier Layer zusammensuchen
03321                   {
03322                      shallIFire = true; // here are at least 4 layers available
03323                   }
03324                   else
03325                   {
03326                     shallIFire = false;
03327                   }
03328 
03329                   layerCnt++;
03330               }
03331 
03332               if (shallIFire) // shall i fire the signal???
03333               {
03334                 if (config_.cloud_output_mode==0)
03335                 {
03336                    // standard handling of scans
03337                   cloud_pub_.publish(cloud_);
03338 
03339                 }
03340                 else if(config_.cloud_output_mode==2)
03341                 {
03342                   // Following cases are interesting:
03343                   // LMS5xx: seq is always 0 -> publish every scan
03344                   // MRS1104: Every 4th-Layer is 0 -> publish pointcloud every 4th layer message
03345                   // LMS1104: Publish every layer. The timing for the LMS1104 seems to be:
03346                   //          Every 67 ms receiving of a new scan message
03347                   //          Scan message contains 367 measurements
03348                   //          angle increment is 0.75° (yields 274,5° covery -> OK)
03349                   // MRS6124: Publish very 24th layer at the layer = 237 , MRS6124 contains no sequence with seq 0
03350                   //BBB
03351 #ifndef _MSC_VER
03352                   int numTotalShots = 360; //TODO where is this from ?
03353                   int numPartialShots = 40; //
03354 
03355                   for (int i = 0; i < numTotalShots; i += numPartialShots)
03356                   {
03357                     sensor_msgs::PointCloud2 partialCloud;
03358                     partialCloud = cloud_;
03359                     ros::Time partialTimeStamp = cloud_.header.stamp;
03360 
03361                     partialTimeStamp += ros::Duration((i + 0.5 * (numPartialShots - 1)) * timeIncrement);
03362                     partialTimeStamp += ros::Duration((3 * numTotalShots) * timeIncrement);
03363                     partialCloud.header.stamp = partialTimeStamp;
03364                     partialCloud.width = numPartialShots * 3;  // die sind sicher in diesem Bereich
03365 
03366                     int diffTo1100 = cloud_.width - 3 * (numTotalShots + i);
03367                     if (diffTo1100 > numPartialShots)
03368                     {
03369                       diffTo1100 = numPartialShots;
03370                     }
03371                     if (diffTo1100 < 0)
03372                     {
03373                       diffTo1100 = 0;
03374                     }
03375                     partialCloud.width += diffTo1100;
03376                     // printf("Offset: %4d Breite: %4d\n", i, partialCloud.width);
03377                     partialCloud.height = 1;
03378 
03379 
03380                     partialCloud.is_bigendian = false;
03381                     partialCloud.is_dense = true;
03382                     partialCloud.point_step = numChannels * sizeof(float);
03383                     partialCloud.row_step = partialCloud.point_step * partialCloud.width;
03384                     partialCloud.fields.resize(numChannels);
03385                     for (int ii = 0; ii < numChannels; ii++)
03386                     {
03387                       std::string channelId[] = {"x", "y", "z", "intensity"};
03388                       partialCloud.fields[ii].name = channelId[ii];
03389                       partialCloud.fields[ii].offset = ii * sizeof(float);
03390                       partialCloud.fields[ii].count = 1;
03391                       partialCloud.fields[ii].datatype = sensor_msgs::PointField::FLOAT32;
03392                     }
03393 
03394                     partialCloud.data.resize(partialCloud.row_step);
03395 
03396                     int partOff = 0;
03397                     for (int j = 0; j < 4; j++)
03398                     {
03399                       int layerIdx = (j + (layerCnt)) % 4;  // j = 0 -> oldest
03400                       int rowIdx = 1 + layerSeq[layerIdx % 4]; // +1, da es bei -1 beginnt
03401                       int colIdx = j * numTotalShots + i;
03402                       int maxAvail = cloud_.width - colIdx; //
03403                       if (maxAvail < 0)
03404                       {
03405                         maxAvail = 0;
03406                       }
03407 
03408                       if (maxAvail > numPartialShots)
03409                       {
03410                         maxAvail = numPartialShots;
03411                       }
03412 
03413                       // printf("Most recent LayerIdx: %2d RowIdx: %4d ColIdx: %4d\n", layer, rowIdx, colIdx);
03414                       if (maxAvail > 0)
03415                       {
03416                         memcpy(&(partialCloud.data[partOff]),
03417                                &(cloud_.data[(rowIdx * cloud_.width + colIdx + i) * cloud_.point_step]),
03418                                cloud_.point_step * maxAvail);
03419 
03420                       }
03421 
03422                       partOff += maxAvail * partialCloud.point_step;
03423                     }
03424                     assert(partialCloud.data.size()==partialCloud.width*partialCloud.point_step);
03425 
03426 
03427                     cloud_pub_.publish(partialCloud);
03428 #if 0
03429                     memcpy(&(partialCloud.data[0]), &(cloud_.data[0]) + i * cloud_.point_step, cloud_.point_step * numPartialShots);
03430                     cloud_pub_.publish(partialCloud);
03431 #endif
03432                   }
03433                 }
03434                 //                cloud_pub_.publish(cloud_);
03435 
03436 #else
03437                 printf("PUBLISH:\n");
03438 #endif
03439               }
03440             }
03441           }
03442           // Start Point
03443           buffer_pos = dend + 1;
03444         } // end of while loop
03445       }
03446 
03447        // shall we process more data? I.e. are there more packets to process in the input queue???
03448 
03449     } while ( (packetsInLoop > 0) && (numPacketsProcessed < maxNumAllowedPacketsToProcess) );
03450     return ExitSuccess; // return success to continue looping
03451   }
03452 
03453 
03457   void SickScanCommon::check_angle_range(SickScanConfig &conf)
03458   {
03459     if (conf.min_ang > conf.max_ang)
03460     {
03461       ROS_WARN("Maximum angle must be greater than minimum angle. Adjusting >min_ang<.");
03462       conf.min_ang = conf.max_ang;
03463     }
03464   }
03465 
03471   void SickScanCommon::update_config(sick_scan::SickScanConfig &new_config, uint32_t level)
03472   {
03473     check_angle_range(new_config);
03474     config_ = new_config;
03475   }
03476 
03483   int SickScanCommon::convertAscii2BinaryCmd(const char *requestAscii, std::vector<unsigned char> *requestBinary)
03484   {
03485     requestBinary->clear();
03486     if (requestAscii == NULL)
03487     {
03488       return (-1);
03489     }
03490     int cmdLen = strlen(requestAscii);
03491     if (cmdLen == 0)
03492     {
03493       return (-1);
03494     }
03495     if (requestAscii[0] != 0x02)
03496     {
03497       return (-1);
03498     }
03499     if (requestAscii[cmdLen - 1] != 0x03)
03500     {
03501       return (-1);
03502     }
03503     // Here we know, that the ascii format is correctly framed with <stx> .. <etx>
03504     for (int i = 0; i < 4; i++)
03505     {
03506       requestBinary->push_back(0x02);
03507     }
03508 
03509     for (int i = 0; i < 4; i++) // Puffer for Length identifier
03510     {
03511       requestBinary->push_back(0x00);
03512     }
03513 
03514     unsigned long msgLen = cmdLen - 2; // without stx and etx
03515 
03516     // special handling for the following commands
03517     // due to higher number of command arguments
03518     std::string keyWord0 = "sMN SetAccessMode";
03519     std::string keyWord1 = "sWN FREchoFilter";
03520     std::string keyWord2 = "sEN LMDscandata";
03521     std::string keyWord3 = "sWN LMDscandatacfg";
03522     std::string keyWord4 = "sWN SetActiveApplications";
03523     std::string keyWord5 = "sEN IMUData";
03524     std::string keyWord6 = "sWN EIIpAddr";
03525     std::string keyWord7 = "sMN mLMPsetscancfg";
03526     std::string keyWord8 = "sWN TSCTCupdatetime";
03527     std::string keyWord9 = "sWN TSCTCSrvAddr";
03528     //BBB
03529 
03530     std::string cmdAscii = requestAscii;
03531 
03532 
03533     int copyUntilSpaceCnt = 2;
03534     int spaceCnt = 0;
03535     char hexStr[255] = {0};
03536     int level = 0;
03537     unsigned char buffer[255];
03538     int bufferLen = 0;
03539     if (cmdAscii.find(keyWord0) != std::string::npos) // SetAccessMode
03540     {
03541       copyUntilSpaceCnt = 2;
03542       int keyWord0Len = keyWord0.length();
03543       sscanf(requestAscii + keyWord0Len + 1, " %d %s", &level, hexStr);
03544       buffer[0] = (unsigned char) (0xFF & level);
03545       bufferLen = 1;
03546       char hexTmp[3] = {0};
03547       for (int i = 0; i < 4; i++)
03548       {
03549         int val;
03550         hexTmp[0] = hexStr[i * 2];
03551         hexTmp[1] = hexStr[i * 2 + 1];
03552         hexTmp[2] = 0x00;
03553         sscanf(hexTmp, "%x", &val);
03554         buffer[i + 1] = (unsigned char) (0xFF & val);
03555         bufferLen++;
03556       }
03557     }
03558     if (cmdAscii.find(keyWord1) != std::string::npos)
03559     {
03560       int echoCodeNumber = 0;
03561       int keyWord1Len = keyWord1.length();
03562       sscanf(requestAscii + keyWord1Len + 1, " %d", &echoCodeNumber);
03563       buffer[0] = (unsigned char) (0xFF & echoCodeNumber);
03564       bufferLen = 1;
03565     }
03566     if (cmdAscii.find(keyWord2) != std::string::npos)
03567     {
03568       int scanDataStatus = 0;
03569       int keyWord2Len = keyWord2.length();
03570       sscanf(requestAscii + keyWord2Len + 1, " %d", &scanDataStatus);
03571       buffer[0] = (unsigned char) (0xFF & scanDataStatus);
03572       bufferLen = 1;
03573     }
03574 
03575     if (cmdAscii.find(keyWord3) != std::string::npos)
03576     {
03577       int scanDataStatus = 0;
03578       int keyWord3Len = keyWord3.length();
03579       int dummyArr[12] = {0};
03580       if (12 == sscanf(requestAscii + keyWord3Len + 1, " %d %d %d %d %d %d %d %d %d %d %d %d",
03581                        &dummyArr[0], &dummyArr[1], &dummyArr[2],
03582                        &dummyArr[3], &dummyArr[4], &dummyArr[5],
03583                        &dummyArr[6], &dummyArr[7], &dummyArr[8],
03584                        &dummyArr[9], &dummyArr[10], &dummyArr[11]))
03585       {
03586         for (int i = 0; i < 13; i++)
03587         {
03588           buffer[i] = 0x00;
03589         }
03590         buffer[0] = (unsigned char) (0xFF & (dummyArr[0]));
03591         buffer[1] = 0x00;
03592         buffer[2] = (unsigned char) (0xFF & dummyArr[2]);  // Remission
03593         buffer[3] = (unsigned char) (0xFF & dummyArr[3]);  // Remission data format 0=8 bit 1= 16 bit
03594         buffer[10]= (unsigned char) (0xFF & dummyArr[10]);  // Enable timestamp
03595         buffer[12] = (unsigned char) (0xFF & (dummyArr[11]));  // nth-Scan
03596 
03597         bufferLen = 13;
03598       }
03599 
03600     }
03601 
03602     if (cmdAscii.find(keyWord4) != std::string::npos)
03603     {
03604       char tmpStr[1024] = {0};
03605       char szApplStr[255] = {0};
03606       int keyWord4Len = keyWord4.length();
03607       int scanDataStatus = 0;
03608       int dummy0, dummy1;
03609       strcpy(tmpStr, requestAscii + keyWord4Len + 2);
03610       sscanf(tmpStr, "%d %s %d", &dummy0, szApplStr, &dummy1);
03611       // rebuild string
03612       buffer[0] = 0x00;
03613       buffer[1] = dummy0 ? 0x01 : 0x00;
03614       for (int ii = 0; ii < 4; ii++)
03615       {
03616         buffer[2 + ii] = szApplStr[ii]; // idx: 1,2,3,4
03617       }
03618       buffer[6] = dummy1 ? 0x01 : 0x00;
03619       bufferLen = 7;
03620     }
03621 
03622     if (cmdAscii.find(keyWord5) != std::string::npos)
03623     {
03624       int imuSetStatus = 0;
03625       int keyWord5Len = keyWord5.length();
03626       sscanf(requestAscii + keyWord5Len + 1, " %d", &imuSetStatus);
03627       buffer[0] = (unsigned char) (0xFF & imuSetStatus);
03628       bufferLen = 1;
03629     }
03630 
03631     if (cmdAscii.find(keyWord6) != std::string::npos)
03632     {
03633       int adrPartArr[4];
03634       int imuSetStatus = 0;
03635       int keyWord6Len = keyWord6.length();
03636       sscanf(requestAscii + keyWord6Len + 1, " %x %x %x %x", &(adrPartArr[0]), &(adrPartArr[1]), &(adrPartArr[2]),
03637              &(adrPartArr[3]));
03638       buffer[0] = (unsigned char) (0xFF & adrPartArr[0]);
03639       buffer[1] = (unsigned char) (0xFF & adrPartArr[1]);
03640       buffer[2] = (unsigned char) (0xFF & adrPartArr[2]);
03641       buffer[3] = (unsigned char) (0xFF & adrPartArr[3]);
03642       bufferLen = 4;
03643     }
03644     //\x02sMN mLMPsetscancfg %d 1 %d 0 0\x03";
03645     //02 02 02 02 00 00 00 25 73 4D 4E 20 6D 4C 4D 50 73 65 74 73 63 61 6E 63 66 67 20
03646     // 00 00 13 88 4byte freq
03647     // 00 01 2 byte sectors always 1
03648     // 00 00 13 88  ang_res
03649     // FF F9 22 30 sector start always 0
03650     // 00 22 55 10 sector stop  always 0
03651     // 21
03652     if (cmdAscii.find(keyWord7) != std::string::npos)
03653     {
03654       bufferLen = 18;
03655       for(int i=0;i<bufferLen;i++)
03656       {
03657         unsigned char uch=0x00;
03658         switch (i)
03659         {
03660           case 5:
03661             uch=0x01;break;
03662         }
03663         buffer[i]=uch;
03664       }
03665       char tmpStr[1024] = {0};
03666       char szApplStr[255] = {0};
03667       int keyWord7Len = keyWord7.length();
03668       int scanDataStatus = 0;
03669       int dummy0, dummy1;
03670       strcpy(tmpStr, requestAscii + keyWord7Len + 2);
03671       sscanf(tmpStr, "%d 1 %d", &dummy0, &dummy1);
03672 
03673       buffer[0] = (unsigned char)(0xFF & (dummy0 >> 24));
03674       buffer[1] = (unsigned char)(0xFF & (dummy0 >> 16));
03675       buffer[2] = (unsigned char)(0xFF & (dummy0 >> 8));
03676       buffer[3] = (unsigned char)(0xFF & (dummy0 >> 0));
03677 
03678 
03679       buffer[6] = (unsigned char)(0xFF & (dummy1 >> 24));
03680       buffer[7] = (unsigned char)(0xFF & (dummy1 >> 16));
03681       buffer[8] = (unsigned char)(0xFF & (dummy1 >> 8));
03682       buffer[9] = (unsigned char)(0xFF & (dummy1 >> 0));
03683 
03684 
03685     }
03686     if (cmdAscii.find(keyWord8) != std::string::npos)
03687     {
03688       uint32_t updatetime = 0;
03689       int keyWord8Len = keyWord8.length();
03690       sscanf(requestAscii + keyWord8Len + 1, " %d", &updatetime);
03691       buffer[0] = (unsigned char)(0xFF & (updatetime >> 24));
03692       buffer[1] = (unsigned char)(0xFF & (updatetime >> 16));
03693       buffer[2] = (unsigned char)(0xFF & (updatetime >> 8));
03694       buffer[3] = (unsigned char)(0xFF & (updatetime >> 0));
03695       bufferLen = 4;
03696     }
03697     if (cmdAscii.find(keyWord9) != std::string::npos)
03698     {
03699       int adrPartArr[4];
03700       int imuSetStatus = 0;
03701       int keyWord9Len = keyWord9.length();
03702       sscanf(requestAscii + keyWord9Len + 1, " %x %x %x %x", &(adrPartArr[0]), &(adrPartArr[1]), &(adrPartArr[2]),
03703              &(adrPartArr[3]));
03704       buffer[0] = (unsigned char) (0xFF & adrPartArr[0]);
03705       buffer[1] = (unsigned char) (0xFF & adrPartArr[1]);
03706       buffer[2] = (unsigned char) (0xFF & adrPartArr[2]);
03707       buffer[3] = (unsigned char) (0xFF & adrPartArr[3]);
03708       bufferLen = 4;
03709     }
03710     // copy base command string to buffer
03711     bool switchDoBinaryData = false;
03712     for (int i = 1; i <= (int) (msgLen); i++)  // STX DATA ETX --> 0 1 2
03713     {
03714       char c = requestAscii[i];
03715       if (switchDoBinaryData == true)
03716       {
03717         if (0 == bufferLen)  // no keyword handling before this point
03718         {
03719           if (c >= '0' && c <= '9')  // standard data format expected - only one digit
03720           {
03721             c -= '0';              // convert ASCII-digit to hex-digit
03722           }                          // 48dez to 00dez and so on.
03723         }
03724         else
03725         {
03726           break;
03727         }
03728       }
03729       requestBinary->push_back(c);
03730       if (requestAscii[i] == 0x20) // space
03731       {
03732         spaceCnt++;
03733         if (spaceCnt >= copyUntilSpaceCnt)
03734         {
03735           switchDoBinaryData = true;
03736         }
03737       }
03738 
03739     }
03740     // if there are already process bytes (due to special key word handling)
03741     // copy these data bytes to the buffer
03742     for (int i = 0; i < bufferLen; i++) // append variable data
03743     {
03744       requestBinary->push_back(buffer[i]);
03745     }
03746 
03747     msgLen = requestBinary->size();
03748     msgLen -= 8;
03749     for (int i = 0; i < 4; i++)
03750     {
03751       unsigned char bigEndianLen = msgLen & (0xFF << (3 - i) * 8);
03752       (*requestBinary)[i + 4] = ((unsigned char) (bigEndianLen)); // HIER WEITERMACHEN!!!!
03753     }
03754     unsigned char xorVal = 0x00;
03755     xorVal = sick_crc8((unsigned char *) (&((*requestBinary)[8])), requestBinary->size() - 8);
03756     requestBinary->push_back(xorVal);
03757 #if 0
03758     for (int i = 0; i < requestBinary->size(); i++)
03759     {
03760       unsigned char c = (*requestBinary)[i];
03761       printf("[%c]%02x ", (c < ' ') ? '.' : c, c) ;
03762     }
03763     printf("\n");
03764 #endif
03765     return (0);
03766 
03767   };
03768 
03769 
03776   bool SickScanCommon::checkForProtocolChangeAndMaybeReconnect(bool &useBinaryCmdNow)
03777   {
03778     bool retValue = true;
03779     bool shouldUseBinary = this->parser_->getCurrentParamPtr()->getUseBinaryProtocol();
03780     if (shouldUseBinary == useBinaryCmdNow)
03781     {
03782       retValue = true;  // !!!! CHANGE ONLY FOR TEST!!!!!
03783     }
03784     else
03785     {
03786       /*
03787             // we must reconnect and set the new protocoltype
03788             int iRet = this->close_device();
03789             ROS_INFO("SOPAS - Close and reconnected to scanner due to protocol change and wait 15 sec. ");
03790             ROS_INFO("SOPAS - Changing from %s to %s\n", shouldUseBinary ? "ASCII" : "BINARY", shouldUseBinary ? "BINARY" : "ASCII");
03791             // Wait a few seconds after rebooting
03792             ros::Duration(15.0).sleep();
03793 
03794             iRet = this->init_device();
03795             */
03796       if (shouldUseBinary == true)
03797       {
03798         this->setProtocolType(CoLa_B);
03799       }
03800       else
03801       {
03802         this->setProtocolType(CoLa_A);
03803       }
03804 
03805       useBinaryCmdNow = shouldUseBinary;
03806       retValue = false;
03807     }
03808     return (retValue);
03809   }
03810 
03811 
03812   bool SickScanCommon::setNewIpAddress(boost::asio::ip::address_v4 ipNewIPAddr, bool useBinaryCmd)
03813   {
03814     int eepwritetTimeOut =1;
03815     char szCmd[255];
03816     bool result = false;
03817 
03818 
03819     unsigned long adrBytesLong[4];
03820     std::string s = ipNewIPAddr.to_string();  // convert to string, to_bytes not applicable for older linux version
03821     const char *ptr = s.c_str(); // char * to address
03822     // decompose pattern like aaa.bbb.ccc.ddd
03823     sscanf(ptr,"%lu.%lu.%lu.%lu", &(adrBytesLong[0]), &(adrBytesLong[1]), &(adrBytesLong[2]), &(adrBytesLong[3]));
03824 
03825     // convert into byte array
03826     unsigned char ipbytearray[4];
03827     for (int i = 0; i < 4; i++)
03828     {
03829       ipbytearray[i] = adrBytesLong[i] & 0xFF;
03830     }
03831 
03832 
03833     char ipcommand[255];
03834     const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_IP_ADDR].c_str();
03835     sprintf(ipcommand, pcCmdMask, ipbytearray[0], ipbytearray[1], ipbytearray[2], ipbytearray[3]);
03836     if (useBinaryCmd)
03837     {
03838       std::vector<unsigned char> reqBinary;
03839       this->convertAscii2BinaryCmd(ipcommand, &reqBinary);
03840       result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_IP_ADDR]);
03841       reqBinary.clear();
03842       this->convertAscii2BinaryCmd(sopasCmdVec[CMD_WRITE_EEPROM].c_str(), &reqBinary);
03843       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_WRITE_EEPROM]);
03844       reqBinary.clear();
03845       this->convertAscii2BinaryCmd(sopasCmdVec[CMD_RUN].c_str(), &reqBinary);
03846       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_RUN]);
03847       reqBinary.clear();
03848       this->convertAscii2BinaryCmd(sopasCmdVec[CMD_SET_ACCESS_MODE_3].c_str(), &reqBinary);
03849       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_ACCESS_MODE_3]);
03850       reqBinary.clear();
03851       this->convertAscii2BinaryCmd(sopasCmdVec[CMD_REBOOT].c_str(), &reqBinary);
03852       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_REBOOT]);
03853     }
03854     else
03855     {
03856       std::vector<unsigned char> ipcomandReply;
03857       std::vector<unsigned char> resetReply;
03858       std::string runCmd = sopasCmdVec[CMD_RUN];
03859       std::string restartCmd = sopasCmdVec[CMD_REBOOT];
03860       std::string EEPCmd = sopasCmdVec[CMD_WRITE_EEPROM];
03861       std::string UserLvlCmd = sopasCmdVec[CMD_SET_ACCESS_MODE_3];
03862       result = sendSopasAndCheckAnswer(ipcommand, &ipcomandReply);
03863       result &= sendSopasAndCheckAnswer(EEPCmd, &resetReply);
03864       result &= sendSopasAndCheckAnswer(runCmd, &resetReply);
03865       result &= sendSopasAndCheckAnswer(UserLvlCmd, &resetReply);
03866       result &= sendSopasAndCheckAnswer(restartCmd, &resetReply);
03867     }
03868     return (result);
03869   }
03870 
03871   bool SickScanCommon::setNTPServerAndStart(boost::asio::ip::address_v4 ipNewIPAddr, bool useBinaryCmd)
03872   {
03873     char szCmd[255];
03874     bool result = false;
03875 
03876 
03877     unsigned long adrBytesLong[4];
03878     std::string s = ipNewIPAddr.to_string();  // convert to string, to_bytes not applicable for older linux version
03879     const char *ptr = s.c_str(); // char * to address
03880     // decompose pattern like aaa.bbb.ccc.ddd
03881     sscanf(ptr,"%lu.%lu.%lu.%lu", &(adrBytesLong[0]), &(adrBytesLong[1]), &(adrBytesLong[2]), &(adrBytesLong[3]));
03882 
03883     // convert into byte array
03884     unsigned char ipbytearray[4];
03885     for (int i = 0; i < 4; i++)
03886     {
03887       ipbytearray[i] = adrBytesLong[i] & 0xFF;
03888     }
03889 
03890 
03891     char ntpipcommand[255];
03892     char ntpupdatetimecommand[255];
03893     const char *pcCmdMask = sopasCmdMaskVec[CMD_SET_NTP_SERVER_IP_ADDR].c_str();
03894     sprintf(ntpipcommand, pcCmdMask, ipbytearray[0], ipbytearray[1], ipbytearray[2], ipbytearray[3]);
03895 
03896     const char *pcCmdMaskUpdatetime = sopasCmdMaskVec[CMD_SET_NTP_UPDATETIME].c_str();
03897     sprintf(ntpupdatetimecommand, pcCmdMaskUpdatetime, 5);
03898     std::vector<unsigned char> outputFilterntpupdatetimecommand;
03899     //
03900     if (useBinaryCmd)
03901     {
03902       std::vector<unsigned char> reqBinary;
03903       this->convertAscii2BinaryCmd(sopasCmdVec[CMD_SET_NTP_INTERFACE_ETH].c_str(), &reqBinary);
03904       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_NTP_INTERFACE_ETH]);
03905       reqBinary.clear();
03906       this->convertAscii2BinaryCmd(ntpipcommand, &reqBinary);
03907       result = sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_NTP_SERVER_IP_ADDR]);
03908       reqBinary.clear();
03909       this->convertAscii2BinaryCmd(ntpupdatetimecommand, &reqBinary);
03910       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_SET_NTP_UPDATETIME]);
03911       reqBinary.clear();
03912       this->convertAscii2BinaryCmd(sopasCmdVec[CMD_ACTIVATE_NTP_CLIENT].c_str(), &reqBinary);
03913       result &= sendSopasAndCheckAnswer(reqBinary, &sopasReplyBinVec[CMD_ACTIVATE_NTP_CLIENT]);
03914       reqBinary.clear();
03915 
03916     }
03917     else
03918     {
03919       std::vector<unsigned char> ipcomandReply;
03920       std::vector<unsigned char> resetReply;
03921       std::string ntpInterFaceETHCmd = sopasCmdVec[CMD_SET_NTP_INTERFACE_ETH];
03922       std::string activateNTPCmd = sopasCmdVec[CMD_ACTIVATE_NTP_CLIENT];
03923       result &= sendSopasAndCheckAnswer(ntpInterFaceETHCmd , &resetReply);
03924       result = sendSopasAndCheckAnswer(ntpipcommand, &ipcomandReply);
03925       result &= sendSopasAndCheckAnswer(activateNTPCmd, &resetReply);
03926       result &= sendSopasAndCheckAnswer(ntpupdatetimecommand, &outputFilterntpupdatetimecommand);
03927     }
03928     return (result);
03929   }
03930 
03931   void SickScanCommon::setSensorIsRadar(bool _isRadar)
03932   {
03933     sensorIsRadar = _isRadar;
03934   }
03935 
03936   bool SickScanCommon::getSensorIsRadar(void)
03937   {
03938     return (sensorIsRadar);
03939   }
03940 
03941   // SopasProtocol m_protocolId;
03942 
03943 } /* namespace sick_scan */
03944 
03945 
03946 


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