snark
packets.h
Go to the documentation of this file.
1 // This file is part of snark, a generic and flexible library
2 // for robotics research.
3 //
4 // Copyright (C) 2011 The University of Sydney
5 //
6 // snark is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 3 of the License, or (at your option) any later version.
10 //
11 // snark is distributed in the hope that it will be useful, but WITHOUT ANY
12 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 // FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
14 // for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with snark. If not, see <http://www.gnu.org/licenses/>.
18 
19 #ifndef SNARK_SENSORS_SICK_PACKET_H_
20 #define SNARK_SENSORS_SICK_PACKET_H_
21 
25 
26 #include <boost/array.hpp>
27 #include <boost/date_time/posix_time/posix_time.hpp>
28 #include <comma/packed/byte.h>
29 #include <comma/packed/little_endian.h>
30 #include <comma/packed/big_endian.h>
31 #include <comma/packed/struct.h>
32 
33 namespace snark { namespace sick { namespace ldmrs {
34 
36 struct timestamp : public comma::packed::packed_struct< timestamp, 8 >
37 {
38  comma::packed::net_uint32 seconds;
39  comma::packed::net_uint32 fractions;
40 };
41 
43 struct little_endian_timestamp : public comma::packed::packed_struct< little_endian_timestamp, 8 >
44 {
45  comma::packed::uint32 fractions;
46  comma::packed::uint32 seconds;
47 };
48 
50 struct header : public comma::packed::packed_struct< header, 24 >
51 {
54  enum types { scan_type = 0x2202, command_type = 0x2010, response_type = 0x2020, fault_type = 0x2030 };
55 
57  static boost::array< unsigned char, 4 > sentinel_value;
58 
60  comma::packed::net_uint32 sentinel;
61 
63  comma::packed::net_uint32 previous_size;
64 
66  comma::packed::net_uint32 payload_size;
67 
69  comma::packed::byte padding;
70 
72  comma::packed::byte device_id;
73 
75  comma::packed::net_uint16 type;
76 
79 
81  header();
82 
84  bool valid() const;
85 };
86 
89 struct fault : public comma::packed::packed_struct< fault, 16 >
90 {
91  comma::packed::uint16 faultRegister1;
92  comma::packed::uint16 faultRegister2;
93  comma::packed::uint16 warningRegister1;
94  comma::packed::uint16 warningRegister2;
95  boost::array< comma::packed::uint16, 4 > reserved;
96  bool fatal() const;
97 };
98 
99 std::ostream& operator<<( std::ostream&, const fault& rhs );
100 
102 struct scan : public comma::packed::packed_struct< scan, 44 >
103 {
105  struct header : public comma::packed::packed_struct< header, 44 >
106  {
109  enum Statuses { measurementFrequencyReached = 0x0008, externalSyncDetected = 0x0010, synced = 0x0020, syncMaster = 0x0040 };
110 
112  comma::packed::uint16 measurement_number;
113 
115  comma::packed::uint16 status;
116 
118  comma::packed::uint16 sync_phase_offset;
119 
121  little_endian_timestamp start; //timestamp start;
122 
124  little_endian_timestamp finish; //timestamp finish;
125 
127  comma::packed::uint16 steps;
128 
131  comma::packed::uint16 start_angle;
132 
135  comma::packed::uint16 finish_angle;
136 
138  comma::packed::uint16 points_count;
139 
141  boost::array< comma::packed::uint16, 7 > padding;
142  };
143 
145  struct point : public comma::packed::packed_struct< point, 10 >
146  {
148  struct id : public comma::packed::packed_struct< id, 1 >
149  {
151  comma::packed::byte value;
152 
154  unsigned int layer() const;
155 
157  unsigned int echo() const;
158  };
159 
161  id id;
162 
164  enum { transparent = 0x01, dust = 0x02, rain = dust, noise = dust, dirt = 0x08 };
165 
167  comma::packed::byte flags;
168 
171  comma::packed::uint16 angle;
172 
174  comma::packed::uint16 range;
175 
177  comma::packed::uint16 echo_pulse_width;
178 
180  comma::packed::uint16 padding;
181 
183  double elevation() const;
184  };
185 
188 
190  point* points();
191 
193  const point* points() const;
194 
196  double angle_as_radians( short angle ) const;
197 
199  double angle_as_radians( const point& point ) const;
200 
203  {
204  public:
205  timestamps( const scan& scan );
206  boost::posix_time::ptime operator[]( std::size_t index ) const;
207  private:
208  const scan& m_scan;
209  boost::posix_time::ptime m_start;
210  boost::posix_time::ptime m_finish;
211  boost::posix_time::time_duration m_elapsed;
212  short m_start_angle;
213  short m_finish_angle;
214  short m_diff;
215  unsigned short m_steps;
216  };
217 };
218 
219 struct scan_packet : public comma::packed::packed_struct< scan_packet, header::size + scan::size >
220 {
221  header packet_header;
222  scan packet_scan;
223 };
224 
225 struct commands
226 {
228  struct header : public comma::packed::packed_struct< header, 4 >
229  {
230  comma::packed::uint16 id;
231  comma::packed::net_uint16 padding;
232  };
233 
235  struct response_header : public comma::packed::packed_struct< response_header, 2 >
236  {
237  comma::packed::uint16 id;
238  std::size_t payload_size() const;
239  };
240 
242  template < typename C, std::size_t Size >
243  struct command : public comma::packed::packed_struct< C, header::size + Size >
244  {
245  header command_header;
246  command() { command_header.id = C::id; }
247  };
248 
250  template < typename C, std::size_t Size >
251  struct response : public comma::packed::packed_struct< typename C::response, response_header::size + Size >
252  {
254  response() { header.id = C::id; }
255  void fail() { header.id = header.id() | 0x8000; }
256  bool ok() const { return ( header.id() & 0x8000 ) == 0; }
257  bool matches( comma::uint16 id ) { return id == ( header.id() & 0x3fff ); }
258  };
259 
260  enum types
261  {
262  reset_dsp_type = 0x0000
263  , get_status_type = 0x0001
264  , save_configuration_type = 0x0004
265  , set_type = 0x0010
266  , get_type = 0x0011
267  , reset_type = 0x001a
268  , start_type = 0x0020
269  , stop_type = 0x0021
270  , set_ntp_seconds_type = 0x0030
271  , set_ntp_fractions_type = 0x0031
272  };
273 
275  struct reset_dsp : public command< reset_dsp, 0 >
276  {
277  enum { id = reset_dsp_type };
278 
279  // no response
280  };
281 
283  struct get_status : public command< get_status, 0 >
284  {
285  enum { id = get_status_type };
286 
287  struct response : public commands::response< get_status, 30 >
288  {
289  comma::packed::uint16 firmwareVersion; // e.g. 0x1230 = version 1.2.3, 0x123B = version 1.2.3b
290  comma::packed::uint16 fpgaVersion; // e.g. 0x1230 = version 1.2.3, 0x123B = version 1.2.3b
291  comma::packed::uint16 status; // todo: define status enum
292  comma::packed::uint32 reserved0;
293  comma::packed::uint16 temperature; // -( Temperature - 579.2364 ) / 3.63
294  comma::packed::uint16 serialNumber0; // YY CW (e. g. YY CW = 0x0740 = year '07, calendar week 40)
295  comma::packed::uint16 serialNumber1; // serial number counter
296  comma::packed::uint16 reserved1;
297  boost::array< comma::packed::uint16, 3 > fpgaVersionDate; // cryptic: YYYY MM DD HH MM FPGA S
298  boost::array< comma::packed::uint16, 3 > dspVersionDate; // cryptic: YYYY MM DD HH MM
299  };
300  };
301 
303  struct save_configuration : public command< save_configuration, 0 >
304  {
305  enum { id = save_configuration_type };
306 
307  struct response : public commands::response< save_configuration, 0 > {};
308  };
309 
311  struct set : public command< set, 6 >
312  {
313  enum { id = set_type };
314  enum IndexValues { ip_address = 0x1000, tcp_port = 0x1001, subnet_mask = 0x1002, gateway = 0x1003, data_output_flag = 0x1012 }; // data output flag: 16 bit, see documentation for meaning, if we need it at all
315  comma::packed::uint16 index;
316  comma::packed::uint32 value; // todo: since it is little endian, it's really unclear what on the earth their documentation means
317 
318  struct response : public commands::response< set, 0 > {};
319  };
320 
322  struct get : public command< get, 2 >
323  {
324  enum { id = get_type };
325  comma::packed::uint16 index;
326 
327  struct response : public commands::response< get, 6 >
328  {
329  comma::packed::uint16 index;
330  comma::packed::uint32 value; // todo: since it is little endian, it's really unclear what on the earth their documentation means
331  };
332  };
333 
335  struct reset : public command< reset, 0 >
336  {
337  enum { id = reset_type };
338 
339  struct response : public commands::response< reset, 0 > {};
340  };
341 
343  struct start : public command< start, 0 >
344  {
345  enum { id = start_type };
346 
347  struct response : public commands::response< start, 0 > {};
348  };
349 
351  struct stop : public command< stop, 0 >
352  {
353  enum { id = stop_type };
354 
355  struct response : public commands::response< stop, 0 > {};
356  };
357 
359  struct set_ntp_seconds : public command< set_ntp_seconds, 6 >
360  {
361  enum { id = set_ntp_seconds_type };
362  comma::packed::uint16 reserved; // field missed in the sick documentation
363  comma::packed::uint32 seconds;
364 
365  set_ntp_seconds();
366  set_ntp_seconds( comma::uint32 seconds );
367 
368  struct response : public commands::response< set_ntp_seconds, 0 > {};
369  };
370 
372  struct set_ntp_fractions : public command< set_ntp_fractions, 6 >
373  {
374  enum { id = set_ntp_fractions_type };
375  comma::packed::uint16 reserved; // field missed in the sick documentation
376  comma::packed::uint32 fractions;
377 
379  set_ntp_fractions( comma::uint32 fractions );
380 
381  struct response : public commands::response< set_ntp_fractions, 0 > {};
382  };
383 
385  template < typename C >
386  struct packet : public comma::packed::packed_struct< packet< C >, ldmrs::header::size + C::size >
387  {
389  C command;
390  packet() { header.type = ldmrs::header::command_type; header.payload_size = C::size; }
391  packet( const C& command ) : command( command ) { header.type = ldmrs::header::command_type; header.payload_size = C::size; }
392 
393  struct response : public comma::packed::packed_struct< response, ldmrs::header::size + C::response::size >
394  {
396  typename C::response response;
397  response() { header.type = ldmrs::header::response_type; header.payload_size = C::response::size; }
398  response( const typename C::response& response ) : response( response ) { header.type = ldmrs::header::response_type; header.payload_size = C::response::size; }
399  };
400  };
401 };
402 
403 std::ostream& operator<<( std::ostream& os, const commands::get_status::response& rhs );
404 std::ostream& operator<<( std::ostream& os, const commands::get::response& rhs );
405 
406 } } } // namespace snark { namespace sick { namespace ldmrs {
407 
408 #endif // #ifndef SNARK_SENSORS_SICK_PACKET_H_