TelegramS300.h
Go to the documentation of this file.
00001 /*
00002  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *   http://www.apache.org/licenses/LICENSE-2.0
00009 
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016  
00017 
00018 #pragma once
00019 
00020 #include <arpa/inet.h>
00021 
00022 /*
00023 * S300 header format in continuous mode:
00024 *
00025 *      | 00 00 00 00 |   4 byte reply header
00026 *      | 00 00 |         data block number (fixed for continuous output)
00027 *      | xx xx |         size of data telegram in 16-bit data words
00028 *      | FF xx |         coordination flag and device address (07 in most cases, but 08 for slave configured scanners)
00029 *      | xx xx |         protocol version (02 01 for old protocol,.otherwise 03 01)
00030 *      | 0x 00 |         status: 00 00 = normal, 01 00 = lockout
00031 *      | xx xx xx xx |   scan number (time stamp)
00032 *      | xx xx |         telegram number
00033 *      | BB BB |         ID of output (AAAA=I/O, BBBB=range measruements, CCCC=reflector measurements)
00034 *      | 11 11 |         number of configures measurement field (1111, 2222, 3333, 4444 or 5555)
00035 *         ...            data
00036 *      | xx xx |         CRC
00037 *
00038 * in this parser, user_data_ denotes all but the first 20 bytes (up to and including telegram number above)
00039 * and the last two bytes (CRC)
00040 *
00041 */
00042 
00043 
00044 class TelegramParser {
00045 
00046         #pragma pack(push,1)
00047         union TELEGRAM_COMMON1 {
00048                 struct {
00049                         uint32_t reply_telegram;
00050                         uint16_t trigger_result;
00051                         uint16_t size; // in 16bit=2byte words
00052                         uint8_t  coordination_flag;
00053                         uint8_t  device_addresss;
00054                 };
00055                 uint8_t bytes[10];
00056         };
00057         union TELEGRAM_COMMON2 {
00058                 struct {
00059                         uint16_t protocol_version;
00060                         uint16_t status;
00061                         uint32_t scan_number;
00062                         uint16_t telegram_number;
00063                 };
00064                 uint8_t bytes[10];
00065         };
00066         union TELEGRAM_COMMON3 {
00067                 struct {
00068                         uint16_t type;
00069                 };
00070                 uint8_t bytes[2];
00071         };
00072 
00073         union TELEGRAM_DISTANCE {
00074                 struct {
00075                         uint16_t type;
00076                 };
00077                 uint8_t bytes[2];
00078         };
00079 
00080         union TELEGRAM_TAIL {
00081                 struct {
00082                         uint16_t crc;
00083                 };
00084                 uint8_t bytes[2];
00085         };
00086 
00087         union TELEGRAM_S300_DIST_2B {
00088                 struct {
00089                         unsigned distance : 13; //cm
00090                         unsigned bit13 : 1;  //reflector or scanner distorted
00091                         unsigned protective : 1;
00092                         unsigned warn_field : 1;
00093                 };
00094                 uint16_t val16;
00095                 uint8_t bytes[2];
00096         };
00097 
00098         #pragma pack(pop)
00099 
00100         enum TELEGRAM_COMMON_HS {JUNK_SIZE=4};
00101         enum TELEGRAM_COMMON_TYPES {IO=0xAAAA, DISTANCE=0xBBBB, REFLEXION=0xCCCC};
00102         enum TELEGRAM_DIST_SECTOR {_1=0x1111, _2=0x2222, _3=0x3333, _4=0x4444, _5=0x5555};
00103 
00104 
00105         static void ntoh(TELEGRAM_COMMON1 &tc) {
00106                 tc.reply_telegram = ntohl(tc.reply_telegram);
00107                 tc.trigger_result = ntohs(tc.trigger_result);
00108                 tc.size = ntohs(tc.size);
00109         }
00110 
00111         static void ntoh(TELEGRAM_COMMON2 &tc) {
00112                 tc.protocol_version = ntohs(tc.protocol_version);
00113                 tc.status = ntohs(tc.status);
00114                 tc.scan_number = ntohl(tc.scan_number);
00115                 tc.telegram_number = ntohs(tc.telegram_number);
00116         }
00117 
00118         static void ntoh(TELEGRAM_COMMON3 &tc) {
00119                 tc.type = ntohs(tc.type);
00120         }
00121 
00122         static void ntoh(TELEGRAM_DISTANCE &tc) {
00123                 tc.type = ntohs(tc.type);
00124         }
00125 
00126         static void ntoh(TELEGRAM_TAIL &tc) {
00127             //crc calc. is also in network order
00128                 //tc.crc = ntohs(tc.crc);
00129         }
00130 
00131         static void print(const TELEGRAM_COMMON1 &tc) {
00132                 std::cout<<"HEADER"<<std::dec<<std::endl;
00133                 std::cout<<"reply_telegram"<<":"<<tc.reply_telegram<<std::endl;
00134                 std::cout<<"trigger_result"<<":"<<tc.trigger_result<<std::endl;
00135                 std::cout<<"size"<<":"<<2*tc.size<<std::endl;
00136                 std::cout<<"coordination_flag"<<":"<< std::hex<<tc.coordination_flag<<std::endl;
00137                 std::cout<<"device_addresss"<<":"<< std::hex<<(int)tc.device_addresss<<std::endl;
00138         }
00139 
00140         static void print(const TELEGRAM_COMMON2 &tc) {
00141                 std::cout<<"protocol_version"<<":"<< std::hex<<tc.protocol_version<<std::endl;
00142                 std::cout<<"status"<<":"<<tc.status<<std::endl;
00143                 std::cout<<"scan_number"<<":"<< std::hex<<tc.scan_number<<std::endl;
00144                 std::cout<<"telegram_number"<<":"<< std::hex<<tc.telegram_number<<std::endl;
00145         }
00146 
00147         static void print(const TELEGRAM_COMMON3 &tc) {
00148                 std::cout<<"type"<<":"<< std::hex<<tc.type<<std::endl;
00149                 switch(tc.type) {
00150                         case IO: std::cout<<"type"<<": "<<"IO"<<std::endl; break;
00151                         case DISTANCE: std::cout<<"type"<<": "<<"DISTANCE"<<std::endl; break;
00152                         case REFLEXION: std::cout<<"type"<<": "<<"REFLEXION"<<std::endl; break;
00153                         default: std::cout<<"type"<<": "<<"unknown "<<tc.type<<std::endl; break;
00154                 }
00155                 std::cout<<std::dec<<std::endl;
00156         }
00157 
00158         static void print(const TELEGRAM_DISTANCE &tc) {
00159                 std::cout<<"DISTANCE"<<std::endl;
00160                 std::cout<<"type"<<":"<< std::hex<<tc.type<<std::endl;
00161                 switch(tc.type) {
00162                         case _1: std::cout<<"field 1"<<std::endl; break;
00163                         case _2: std::cout<<"field 2"<<std::endl; break;
00164                         case _3: std::cout<<"field 3"<<std::endl; break;
00165                         case _4: std::cout<<"field 4"<<std::endl; break;
00166                         case _5: std::cout<<"field 5"<<std::endl; break;
00167                         default: std::cout<<"unknown "<<tc.type<<std::endl; break;
00168                 }
00169                 std::cout<<std::dec<<std::endl;
00170         }
00171 
00172         static void print(const TELEGRAM_TAIL &tc) {
00173                 std::cout<<"TAIL"<<std::endl;
00174                 std::cout<<"crc"<<":"<< std::hex<<tc.crc<<std::endl;
00175                 std::cout<<std::dec<<std::endl;
00176         }
00177 
00178         //-------------------------------------------
00179         static unsigned int createCRC(uint8_t *ptrData, int Size);
00180 
00181         //supports versions: 0301, 0201
00182         static bool check(const TELEGRAM_COMMON1 &tc, const uint8_t DEVICE_ADDR) {
00183                 uint8_t TELEGRAM_COMMON_PATTERN_EQ[] = {0,0,0,0, 0,0, 0,0, 0xFF, 0&DEVICE_ADDR/*version, 2, 1*/};
00184                 uint8_t TELEGRAM_COMMON_PATTERN_OR[] = {0,0,0,0, 0,0, 0xff,0xff, 0,0xff/*version, 1, 0*/};
00185 
00186                 for(size_t i=0; i<sizeof(TELEGRAM_COMMON_PATTERN_EQ); i++) {
00187                         if(TELEGRAM_COMMON_PATTERN_EQ[i] != (tc.bytes[i]&(~TELEGRAM_COMMON_PATTERN_OR[i])) ) {
00188                                 //std::cout<<"invalid at byte "<<i<<std::endl;
00189                                 return false;
00190                         }
00191                 }
00192 
00193                 return true;
00194         }
00195 
00196         TELEGRAM_COMMON1 tc1_;
00197         TELEGRAM_COMMON2 tc2_;
00198         TELEGRAM_COMMON3 tc3_;
00199         TELEGRAM_DISTANCE td_;
00200         int size_field_start_byte_, crc_bytes_in_size_, user_data_size_;
00201 public:
00202 
00203         TelegramParser() :
00204                 size_field_start_byte_(0),
00205                 crc_bytes_in_size_(0),
00206                 user_data_size_(0)
00207         {}
00208 
00209         bool parseHeader(const unsigned char *buffer, const size_t max_size, const uint8_t DEVICE_ADDR, const bool debug)
00210         {
00211                 if(sizeof(tc1_)>max_size) return false;
00212                 tc1_ = *((TELEGRAM_COMMON1*)buffer);
00213 
00214                 if(!check(tc1_, DEVICE_ADDR)) {
00215                         //if(debug) std::cout<<"basic check failed"<<std::endl;
00216                         return false;
00217                 }
00218 
00219                 ntoh(tc1_);
00220                 if(debug) print(tc1_);
00221 
00222                 tc2_ = *((TELEGRAM_COMMON2*)(buffer+sizeof(TELEGRAM_COMMON1)));
00223                 tc3_ = *((TELEGRAM_COMMON3*)(buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2))));
00224 
00225                 TELEGRAM_TAIL tt;
00226                 uint16_t crc;
00227                 int full_data_size = 0;
00228 
00229                 // The size reported by the protocol varies depending on the calculation which is different depending
00230                 // on several factors.
00231                 // The calculation is described on pp. 70-73 in:
00232                 // https://www.sick.com/media/dox/1/91/891/Telegram_listing_S3000_Expert_Anti_Collision_S300_Expert_de_en_IM0022891.PDF
00233                 //
00234                 // Also, the size is reported as 16bit-words = 2 bytes...
00235                 //
00236                 // For the old protocol/compatability mode:
00237                 // "The telegram size is calculated ... starting with the ... 5. byte ... up to and including the ... CRC."
00238                 if(tc2_.protocol_version==0x102)
00239                 {
00240                         size_field_start_byte_ = 4; // start at 5th byte (started numbering at 0)
00241                         crc_bytes_in_size_ = 2; // include 2 bytes CRC
00242 
00243                         // the user_data_size is the size of the actual payload data in bytes,
00244                         //i.e. all data except of the CRC and the first two common telegrams
00245                         user_data_size_ =
00246                                 2*tc1_.size -
00247                                 (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) - size_field_start_byte_ + crc_bytes_in_size_);
00248                         full_data_size = sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
00249 
00250                         tt = *((TELEGRAM_TAIL*) (buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)) );
00251                         ntoh(tt);
00252                         crc = createCRC((uint8_t*)buffer+JUNK_SIZE, full_data_size-JUNK_SIZE-sizeof(TELEGRAM_TAIL));
00253                 }
00254                 // Special handling for the new protocol, as the settings cannot be fully deduced from the protocol itself
00255                 // Thus, we have to try both possibilities and check against the CRC...
00256                 else
00257                 {
00258                         // If NO I/O or measuring fields are configured:
00259                         // "The telegram size is calculated ... starting with the ... 9. byte ... up to and including the ... CRC."
00260                         size_field_start_byte_ = 8; // start at 9th byte (started numbering at 0)
00261                         crc_bytes_in_size_ = 2; // include 2 bytes CRC
00262                         user_data_size_ =
00263                                 2*tc1_.size -
00264                                 (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) - size_field_start_byte_ + crc_bytes_in_size_);
00265                         full_data_size = sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
00266 
00267                         tt = *((TELEGRAM_TAIL*) (buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)) );
00268                         ntoh(tt);
00269                         crc = createCRC((uint8_t*)buffer+JUNK_SIZE, full_data_size-JUNK_SIZE-sizeof(TELEGRAM_TAIL));
00270                         
00271                         if(tt.crc!=crc)
00272                         {
00273                                 // If any I/O or measuring field is configured:
00274                                 // "The telegram size is calculated ... starting with the ... 13. byte ... up to and including the
00275                                 // last byte ... bevore (sic!) the CRC."
00276                                 size_field_start_byte_ = 12; // start at 13th byte (started numbering at 0)
00277                                 crc_bytes_in_size_ = 0; // do NOT include 2 bytes CRC
00278                                 user_data_size_ =
00279                                         2*tc1_.size -
00280                                         (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) - size_field_start_byte_ + crc_bytes_in_size_);
00281                                 full_data_size =
00282                                         sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
00283 
00284                                 tt = *((TELEGRAM_TAIL*) (buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)) );
00285                                 ntoh(tt);
00286                                 crc = createCRC((uint8_t*)buffer+JUNK_SIZE, full_data_size-JUNK_SIZE-sizeof(TELEGRAM_TAIL));
00287                         }
00288                 }
00289 
00290                 if( (sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL)) > (int)max_size)
00291                 {
00292                         if(debug) std::cout<<"invalid header size"<<std::endl;
00293                         return false;
00294                 }
00295 
00296 
00297                 if(tt.crc!=crc) {
00298                         if(debug) {
00299                                 print(tc2_);
00300                                 print(tc3_);
00301                                 print(tt);
00302                                 std::cout<<"at "<<std::dec<<(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)<<std::hex<<std::endl;
00303                                 std::cout<<"invalid CRC: "<<crc<<" ("<<tt.crc<<")"<<std::endl;
00304                         }
00305                         return false;
00306                 }
00307 
00308                 memset(&td_, 0, sizeof(td_));
00309                 switch(tc3_.type) {
00310                         case IO: break;
00311 
00312                         case DISTANCE:
00313                                 if(debug) std::cout<<"got distance"<<std::endl;
00314 
00315                                 td_ = *((TELEGRAM_DISTANCE*)(buffer+sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+sizeof(TELEGRAM_COMMON3)));
00316                                 ntoh(td_);
00317                                 //print(td_);
00318                                 break;
00319 
00320                         case REFLEXION: break;
00321                         default: return false;
00322                 }
00323 
00324                 return true;
00325         }
00326 
00327         bool isDist() const {return tc3_.type==DISTANCE;}
00328         int getField() const {
00329                 switch(td_.type) {
00330                         case _1: return 1;
00331                         case _2: return 2;
00332                         case _3: return 3;
00333                         case _4: return 4;
00334                         case _5: return 5;
00335                         default: return -1;
00336                 }
00337         }
00338 
00339         int getCompletePacketSize() const {
00340                 return sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
00341         }
00342 
00343         void readDistRaw(const unsigned char *buffer, std::vector<int> &res, bool debug) const
00344         {
00345                 res.clear();
00346                 if(!isDist()) return;
00347 
00348                 size_t num_points =
00349                         (user_data_size_ - sizeof(TELEGRAM_COMMON3) - sizeof(TELEGRAM_DISTANCE)) / sizeof(TELEGRAM_S300_DIST_2B);
00350                 if (debug) std::cout << "Number of points: " << std::dec << num_points << std::endl;
00351                 for(size_t i=0; i<num_points; ++i) {
00352                         TELEGRAM_S300_DIST_2B dist =
00353                                 *((TELEGRAM_S300_DIST_2B*) (buffer + (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) +
00354                                                                       sizeof(TELEGRAM_COMMON3) + sizeof(TELEGRAM_DISTANCE) +
00355                                                                       i * sizeof(TELEGRAM_S300_DIST_2B))) );
00356                         //for distance only: res.push_back((int)dist.distance);
00357                         res.push_back((int)dist.val16);
00358                 }
00359         }
00360 
00361 };


cob_sick_s300
Author(s): Florian Weisshardt
autogenerated on Sat Jun 8 2019 21:02:23