TelegramS300.h
Go to the documentation of this file.
1 /*
2  * Copyright 2017 Fraunhofer Institute for Manufacturing Engineering and Automation (IPA)
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9 
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 #pragma once
19 
20 #include <arpa/inet.h>
21 
22 /*
23 * S300 header format in continuous mode:
24 *
25 * | 00 00 00 00 | 4 byte reply header
26 * | 00 00 | data block number (fixed for continuous output)
27 * | xx xx | size of data telegram in 16-bit data words
28 * | FF xx | coordination flag and device address (07 in most cases, but 08 for slave configured scanners)
29 * | xx xx | protocol version (02 01 for old protocol,.otherwise 03 01)
30 * | 0x 00 | status: 00 00 = normal, 01 00 = lockout
31 * | xx xx xx xx | scan number (time stamp)
32 * | xx xx | telegram number
33 * | BB BB | ID of output (AAAA=I/O, BBBB=range measruements, CCCC=reflector measurements)
34 * | 11 11 | number of configures measurement field (1111, 2222, 3333, 4444 or 5555)
35 * ... data
36 * | xx xx | CRC
37 *
38 * in this parser, user_data_ denotes all but the first 20 bytes (up to and including telegram number above)
39 * and the last two bytes (CRC)
40 *
41 */
42 
43 
45 
46  #pragma pack(push,1)
48  struct {
49  uint32_t reply_telegram;
50  uint16_t trigger_result;
51  uint16_t size; // in 16bit=2byte words
53  uint8_t device_addresss;
54  };
55  uint8_t bytes[10];
56  };
58  struct {
59  uint16_t protocol_version;
60  uint16_t status;
61  uint32_t scan_number;
62  uint16_t telegram_number;
63  };
64  uint8_t bytes[10];
65  };
67  struct {
68  uint16_t type;
69  };
70  uint8_t bytes[2];
71  };
72 
74  struct {
75  uint16_t type;
76  };
77  uint8_t bytes[2];
78  };
79 
80  union TELEGRAM_TAIL {
81  struct {
82  uint16_t crc;
83  };
84  uint8_t bytes[2];
85  };
86 
88  struct {
89  unsigned distance : 13; //cm
90  unsigned bit13 : 1; //reflector or scanner distorted
91  unsigned protective : 1;
92  unsigned warn_field : 1;
93  };
94  uint16_t val16;
95  uint8_t bytes[2];
96  };
97 
98  #pragma pack(pop)
99 
101  enum TELEGRAM_COMMON_TYPES {IO=0xAAAA, DISTANCE=0xBBBB, REFLEXION=0xCCCC};
102  enum TELEGRAM_DIST_SECTOR {_1=0x1111, _2=0x2222, _3=0x3333, _4=0x4444, _5=0x5555};
103 
104 
105  static void ntoh(TELEGRAM_COMMON1 &tc) {
106  tc.reply_telegram = ntohl(tc.reply_telegram);
107  tc.trigger_result = ntohs(tc.trigger_result);
108  tc.size = ntohs(tc.size);
109  }
110 
111  static void ntoh(TELEGRAM_COMMON2 &tc) {
112  tc.protocol_version = ntohs(tc.protocol_version);
113  tc.status = ntohs(tc.status);
114  tc.scan_number = ntohl(tc.scan_number);
115  tc.telegram_number = ntohs(tc.telegram_number);
116  }
117 
118  static void ntoh(TELEGRAM_COMMON3 &tc) {
119  tc.type = ntohs(tc.type);
120  }
121 
122  static void ntoh(TELEGRAM_DISTANCE &tc) {
123  tc.type = ntohs(tc.type);
124  }
125 
126  static void ntoh(TELEGRAM_TAIL &tc) {
127  //crc calc. is also in network order
128  //tc.crc = ntohs(tc.crc);
129  }
130 
131  static void print(const TELEGRAM_COMMON1 &tc) {
132  std::cout<<"HEADER"<<std::dec<<std::endl;
133  std::cout<<"reply_telegram"<<":"<<tc.reply_telegram<<std::endl;
134  std::cout<<"trigger_result"<<":"<<tc.trigger_result<<std::endl;
135  std::cout<<"size"<<":"<<2*tc.size<<std::endl;
136  std::cout<<"coordination_flag"<<":"<< std::hex<<tc.coordination_flag<<std::endl;
137  std::cout<<"device_addresss"<<":"<< std::hex<<(int)tc.device_addresss<<std::endl;
138  }
139 
140  static void print(const TELEGRAM_COMMON2 &tc) {
141  std::cout<<"protocol_version"<<":"<< std::hex<<tc.protocol_version<<std::endl;
142  std::cout<<"status"<<":"<<tc.status<<std::endl;
143  std::cout<<"scan_number"<<":"<< std::hex<<tc.scan_number<<std::endl;
144  std::cout<<"telegram_number"<<":"<< std::hex<<tc.telegram_number<<std::endl;
145  }
146 
147  static void print(const TELEGRAM_COMMON3 &tc) {
148  std::cout<<"type"<<":"<< std::hex<<tc.type<<std::endl;
149  switch(tc.type) {
150  case IO: std::cout<<"type"<<": "<<"IO"<<std::endl; break;
151  case DISTANCE: std::cout<<"type"<<": "<<"DISTANCE"<<std::endl; break;
152  case REFLEXION: std::cout<<"type"<<": "<<"REFLEXION"<<std::endl; break;
153  default: std::cout<<"type"<<": "<<"unknown "<<tc.type<<std::endl; break;
154  }
155  std::cout<<std::dec<<std::endl;
156  }
157 
158  static void print(const TELEGRAM_DISTANCE &tc) {
159  std::cout<<"DISTANCE"<<std::endl;
160  std::cout<<"type"<<":"<< std::hex<<tc.type<<std::endl;
161  switch(tc.type) {
162  case _1: std::cout<<"field 1"<<std::endl; break;
163  case _2: std::cout<<"field 2"<<std::endl; break;
164  case _3: std::cout<<"field 3"<<std::endl; break;
165  case _4: std::cout<<"field 4"<<std::endl; break;
166  case _5: std::cout<<"field 5"<<std::endl; break;
167  default: std::cout<<"unknown "<<tc.type<<std::endl; break;
168  }
169  std::cout<<std::dec<<std::endl;
170  }
171 
172  static void print(const TELEGRAM_TAIL &tc) {
173  std::cout<<"TAIL"<<std::endl;
174  std::cout<<"crc"<<":"<< std::hex<<tc.crc<<std::endl;
175  std::cout<<std::dec<<std::endl;
176  }
177 
178  //-------------------------------------------
179  static unsigned int createCRC(uint8_t *ptrData, int Size);
180 
181  //supports versions: 0301, 0201
182  static bool check(const TELEGRAM_COMMON1 &tc, const uint8_t DEVICE_ADDR) {
183  uint8_t TELEGRAM_COMMON_PATTERN_EQ[] = {0,0,0,0, 0,0, 0,0, 0xFF, 0&DEVICE_ADDR/*version, 2, 1*/};
184  uint8_t TELEGRAM_COMMON_PATTERN_OR[] = {0,0,0,0, 0,0, 0xff,0xff, 0,0xff/*version, 1, 0*/};
185 
186  for(size_t i=0; i<sizeof(TELEGRAM_COMMON_PATTERN_EQ); i++) {
187  if(TELEGRAM_COMMON_PATTERN_EQ[i] != (tc.bytes[i]&(~TELEGRAM_COMMON_PATTERN_OR[i])) ) {
188  //std::cout<<"invalid at byte "<<i<<std::endl;
189  return false;
190  }
191  }
192 
193  return true;
194  }
195 
201 public:
202 
204  size_field_start_byte_(0),
205  crc_bytes_in_size_(0),
206  user_data_size_(0)
207  {}
208 
209  bool parseHeader(const unsigned char *buffer, const size_t max_size, const uint8_t DEVICE_ADDR, const bool debug)
210  {
211  if(sizeof(tc1_)>max_size) return false;
212  tc1_ = *((TELEGRAM_COMMON1*)buffer);
213 
214  if(!check(tc1_, DEVICE_ADDR)) {
215  //if(debug) std::cout<<"basic check failed"<<std::endl;
216  return false;
217  }
218 
219  ntoh(tc1_);
220  if(debug) print(tc1_);
221 
222  tc2_ = *((TELEGRAM_COMMON2*)(buffer+sizeof(TELEGRAM_COMMON1)));
223  tc3_ = *((TELEGRAM_COMMON3*)(buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2))));
224 
225  TELEGRAM_TAIL tt;
226  uint16_t crc;
227  int full_data_size = 0;
228 
229  // The size reported by the protocol varies depending on the calculation which is different depending
230  // on several factors.
231  // The calculation is described on pp. 70-73 in:
232  // https://www.sick.com/media/dox/1/91/891/Telegram_listing_S3000_Expert_Anti_Collision_S300_Expert_de_en_IM0022891.PDF
233  //
234  // Also, the size is reported as 16bit-words = 2 bytes...
235  //
236  // For the old protocol/compatability mode:
237  // "The telegram size is calculated ... starting with the ... 5. byte ... up to and including the ... CRC."
238  if(tc2_.protocol_version==0x102)
239  {
240  size_field_start_byte_ = 4; // start at 5th byte (started numbering at 0)
241  crc_bytes_in_size_ = 2; // include 2 bytes CRC
242 
243  // the user_data_size is the size of the actual payload data in bytes,
244  //i.e. all data except of the CRC and the first two common telegrams
245  user_data_size_ =
246  2*tc1_.size -
247  (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) - size_field_start_byte_ + crc_bytes_in_size_);
248  full_data_size = sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
249 
250  tt = *((TELEGRAM_TAIL*) (buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)) );
251  ntoh(tt);
252  crc = createCRC((uint8_t*)buffer+JUNK_SIZE, full_data_size-JUNK_SIZE-sizeof(TELEGRAM_TAIL));
253  }
254  // Special handling for the new protocol, as the settings cannot be fully deduced from the protocol itself
255  // Thus, we have to try both possibilities and check against the CRC...
256  else
257  {
258  // If NO I/O or measuring fields are configured:
259  // "The telegram size is calculated ... starting with the ... 9. byte ... up to and including the ... CRC."
260  size_field_start_byte_ = 8; // start at 9th byte (started numbering at 0)
261  crc_bytes_in_size_ = 2; // include 2 bytes CRC
262  user_data_size_ =
263  2*tc1_.size -
264  (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) - size_field_start_byte_ + crc_bytes_in_size_);
265  full_data_size = sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
266 
267  tt = *((TELEGRAM_TAIL*) (buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)) );
268  ntoh(tt);
269  crc = createCRC((uint8_t*)buffer+JUNK_SIZE, full_data_size-JUNK_SIZE-sizeof(TELEGRAM_TAIL));
270 
271  if(tt.crc!=crc)
272  {
273  // If any I/O or measuring field is configured:
274  // "The telegram size is calculated ... starting with the ... 13. byte ... up to and including the
275  // last byte ... bevore (sic!) the CRC."
276  size_field_start_byte_ = 12; // start at 13th byte (started numbering at 0)
277  crc_bytes_in_size_ = 0; // do NOT include 2 bytes CRC
278  user_data_size_ =
279  2*tc1_.size -
280  (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) - size_field_start_byte_ + crc_bytes_in_size_);
281  full_data_size =
282  sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
283 
284  tt = *((TELEGRAM_TAIL*) (buffer+(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)) );
285  ntoh(tt);
286  crc = createCRC((uint8_t*)buffer+JUNK_SIZE, full_data_size-JUNK_SIZE-sizeof(TELEGRAM_TAIL));
287  }
288  }
289 
290  if( (sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL)) > (int)max_size)
291  {
292  if(debug) std::cout<<"invalid header size"<<std::endl;
293  return false;
294  }
295 
296 
297  if(tt.crc!=crc) {
298  if(debug) {
299  print(tc2_);
300  print(tc3_);
301  print(tt);
302  std::cout<<"at "<<std::dec<<(sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_)<<std::hex<<std::endl;
303  std::cout<<"invalid CRC: "<<crc<<" ("<<tt.crc<<")"<<std::endl;
304  }
305  return false;
306  }
307 
308  memset(&td_, 0, sizeof(td_));
309  switch(tc3_.type) {
310  case IO: break;
311 
312  case DISTANCE:
313  if(debug) std::cout<<"got distance"<<std::endl;
314 
315  td_ = *((TELEGRAM_DISTANCE*)(buffer+sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+sizeof(TELEGRAM_COMMON3)));
316  ntoh(td_);
317  //print(td_);
318  break;
319 
320  case REFLEXION: break;
321  default: return false;
322  }
323 
324  return true;
325  }
326 
327  bool isDist() const {return tc3_.type==DISTANCE;}
328  int getField() const {
329  switch(td_.type) {
330  case _1: return 1;
331  case _2: return 2;
332  case _3: return 3;
333  case _4: return 4;
334  case _5: return 5;
335  default: return -1;
336  }
337  }
338 
339  int getCompletePacketSize() const {
340  return sizeof(TELEGRAM_COMMON1)+sizeof(TELEGRAM_COMMON2)+user_data_size_+sizeof(TELEGRAM_TAIL);
341  }
342 
343  void readDistRaw(const unsigned char *buffer, std::vector<int> &res, bool debug) const
344  {
345  res.clear();
346  if(!isDist()) return;
347 
348  size_t num_points =
349  (user_data_size_ - sizeof(TELEGRAM_COMMON3) - sizeof(TELEGRAM_DISTANCE)) / sizeof(TELEGRAM_S300_DIST_2B);
350  if (debug) std::cout << "Number of points: " << std::dec << num_points << std::endl;
351  for(size_t i=0; i<num_points; ++i) {
352  TELEGRAM_S300_DIST_2B dist =
353  *((TELEGRAM_S300_DIST_2B*) (buffer + (sizeof(TELEGRAM_COMMON1) + sizeof(TELEGRAM_COMMON2) +
354  sizeof(TELEGRAM_COMMON3) + sizeof(TELEGRAM_DISTANCE) +
355  i * sizeof(TELEGRAM_S300_DIST_2B))) );
356  //for distance only: res.push_back((int)dist.distance);
357  res.push_back((int)dist.val16);
358  }
359  }
360 
361 };
TELEGRAM_DISTANCE td_
Definition: TelegramS300.h:199
static bool check(const TELEGRAM_COMMON1 &tc, const uint8_t DEVICE_ADDR)
Definition: TelegramS300.h:182
bool isDist() const
Definition: TelegramS300.h:327
TELEGRAM_COMMON1 tc1_
Definition: TelegramS300.h:196
TELEGRAM_COMMON2 tc2_
Definition: TelegramS300.h:197
static void ntoh(TELEGRAM_COMMON2 &tc)
Definition: TelegramS300.h:111
static void ntoh(TELEGRAM_COMMON1 &tc)
Definition: TelegramS300.h:105
static void print(const TELEGRAM_COMMON3 &tc)
Definition: TelegramS300.h:147
static void print(const TELEGRAM_DISTANCE &tc)
Definition: TelegramS300.h:158
static void print(const TELEGRAM_TAIL &tc)
Definition: TelegramS300.h:172
static unsigned int createCRC(uint8_t *ptrData, int Size)
TELEGRAM_COMMON3 tc3_
Definition: TelegramS300.h:198
static void ntoh(TELEGRAM_DISTANCE &tc)
Definition: TelegramS300.h:122
static void ntoh(TELEGRAM_COMMON3 &tc)
Definition: TelegramS300.h:118
static void ntoh(TELEGRAM_TAIL &tc)
Definition: TelegramS300.h:126
int getField() const
Definition: TelegramS300.h:328
void readDistRaw(const unsigned char *buffer, std::vector< int > &res, bool debug) const
Definition: TelegramS300.h:343
static void print(const TELEGRAM_COMMON1 &tc)
Definition: TelegramS300.h:131
bool parseHeader(const unsigned char *buffer, const size_t max_size, const uint8_t DEVICE_ADDR, const bool debug)
Definition: TelegramS300.h:209
int size_field_start_byte_
Definition: TelegramS300.h:200
static void print(const TELEGRAM_COMMON2 &tc)
Definition: TelegramS300.h:140
int getCompletePacketSize() const
Definition: TelegramS300.h:339


cob_sick_s300
Author(s): Florian Weisshardt
autogenerated on Wed Apr 7 2021 02:11:50