vssp.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, ATR, Atsushi Watanabe
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef VSSP_H
31 #define VSSP_H
32 
33 #include <boost/asio.hpp>
34 #include <boost/array.hpp>
35 #include <boost/format.hpp>
36 #include <boost/bind.hpp>
37 #include <boost/serialization/access.hpp>
38 #include <boost/archive/binary_iarchive.hpp>
39 #include <boost/shared_array.hpp>
40 #include <boost/algorithm/string.hpp>
41 #include <boost/chrono.hpp>
42 
43 #include <vector>
44 #include <string>
45 
46 #include <vsspdefs.h>
47 
48 namespace vssp
49 {
50 
52 {
53 private:
54  boost::asio::io_service io_service_;
55  boost::asio::ip::tcp::socket socket_;
56  boost::asio::deadline_timer timer_;
57  bool closed_;
59 
60  boost::function<void(
61  const vssp::Header &,
62  const vssp::RangeHeader &,
63  const vssp::RangeIndex &,
66  const boost::posix_time::ptime &)> cb_point_;
67  boost::function<void(
68  const vssp::Header &,
69  const vssp::AuxHeader &,
71  const boost::posix_time::ptime &)> cb_aux_;
72  boost::function<void(
73  const vssp::Header &,
74  const boost::posix_time::ptime &)> cb_ping_;
75  boost::function<void(
76  const vssp::Header &,
77  const std::string &,
78  const boost::posix_time::ptime &)> cb_error_;
79  boost::function<void(bool)> cb_connect_;
81  std::vector<boost::shared_array<const TableSincos>> tbl_v_;
84  std::vector<bool> tbl_vn_loaded_;
85  double timeout_;
86 
87  boost::asio::streambuf buf_;
88 
89 public:
91  : socket_(io_service_)
92  , timer_(io_service_)
93  , closed_(false)
94  , aux_factor_(AUX_FACTOR_DEFAULT)
95  , cb_point_(0)
96  , cb_aux_(0)
97  , cb_ping_(0)
98  , tbl_h_loaded_(false)
99  , tbl_v_loaded_(false)
100  , timeout_(1.0)
101  {
102  }
103  void setTimeout(const double to)
104  {
105  timeout_ = to;
106  }
107  void connect(const char *ip, const unsigned int port, decltype(cb_connect_) cb)
108  {
109  cb_connect_ = cb;
110  boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(ip), port);
111  timer_.expires_from_now(boost::posix_time::seconds(timeout_));
112  timer_.async_wait(boost::bind(&VsspDriver::onTimeoutConnect, this, boost::asio::placeholders::error));
113  socket_.async_connect(endpoint, boost::bind(&vssp::VsspDriver::onConnect, this, boost::asio::placeholders::error));
114  }
115  void registerErrorCallback(decltype(cb_error_) cb)
116  {
117  cb_error_ = cb;
118  }
119  void registerCallback(decltype(cb_point_) cb)
120  {
121  cb_point_ = cb;
122  }
123  void registerAuxCallback(decltype(cb_aux_) cb)
124  {
125  cb_aux_ = cb;
126  }
127  void registerPingCallback(decltype(cb_ping_) cb)
128  {
129  cb_ping_ = cb;
130  }
131  void setAutoReset(const bool enable)
132  {
133  if (enable)
134  send(std::string("SET:_ars=1\n"));
135  else
136  send(std::string("SET:_ars=0\n"));
137  }
138  [[deprecated("use setHorizontalInterlace() instead of setInterlace()")]]
139  void setInterlace(const int itl)
140  {
142  }
143  void setHorizontalInterlace(const int itl)
144  {
145  send((boost::format("SET:_itl=0,%02d\n") % itl).str());
146  }
147  void setVerticalInterlace(const int itl)
148  {
149  send((boost::format("SET:_itv=0,%02d\n") % itl).str());
150  }
151  void requestVerticalTable(const int itl = 1)
152  {
153  tbl_v_.resize(itl);
154  tbl_vn_loaded_.resize(itl);
155  if (itl == 1)
156  {
157  send(std::string("GET:tblv\n"));
158  }
159  else
160  {
161  for (int i = 0; i < itl; ++i)
162  {
163  send((boost::format("GET:tv%02d\n") % i).str());
164  tbl_vn_loaded_[i] = false;
165  }
166  }
167  }
169  {
170  send(std::string("GET:tblh\n"));
171  }
172  void requestPing()
173  {
174  send(std::string("PNG\n"));
175  }
176  void requestAuxData(const bool start = 1)
177  {
178  send((boost::format("DAT:ax=%d\n") % static_cast<int>(start)).str());
179  }
180  void requestData(const bool intensity = 1, const bool start = 1)
181  {
182  if (intensity)
183  {
184  send((boost::format("DAT:ri=%d\n") % static_cast<int>(start)).str());
185  }
186  else
187  {
188  send((boost::format("DAT:ro=%d\n") % static_cast<int>(start)).str());
189  }
190  }
192  {
193  timer_.cancel();
194  timer_.expires_from_now(boost::posix_time::seconds(timeout_));
195  timer_.async_wait(boost::bind(&VsspDriver::onTimeout, this, boost::asio::placeholders::error));
196  // Read at least 4 bytes.
197  // In most case, callback function will be called for each VSSP line.
198  boost::asio::async_read(socket_, buf_, boost::asio::transfer_at_least(4),
199  boost::bind(&VsspDriver::onRead, this, boost::asio::placeholders::error));
200  }
201  bool poll()
202  {
203  boost::system::error_code ec;
204  io_service_.poll(ec);
205  if (!ec)
206  return true;
207  return false;
208  }
209  void spin()
210  {
211  io_service_.run();
212  }
213  void stop()
214  {
215  io_service_.stop();
216  }
217  boost::asio::io_service &getIoService()
218  {
219  return io_service_;
220  }
221 
222 private:
223  void send(const std::string cmd)
224  {
225  boost::shared_ptr<std::string> data(new std::string(cmd));
226  boost::asio::async_write(socket_, boost::asio::buffer(*data),
227  boost::bind(&VsspDriver::onSend, this, boost::asio::placeholders::error, data));
228  }
229  void onTimeoutConnect(const boost::system::error_code &error)
230  {
231  if (!error)
232  {
233  closed_ = true;
234  io_service_.stop();
235  }
236  }
237  void onTimeout(const boost::system::error_code &error)
238  {
239  if (!error)
240  {
241  closed_ = true;
242  io_service_.stop();
243  }
244  }
245  void onConnect(const boost::system::error_code &error)
246  {
247  timer_.cancel();
248  if (error)
249  {
250  closed_ = true;
251  cb_connect_(false);
252  return;
253  }
254  cb_connect_(true);
255  }
256  void onSend(const boost::system::error_code &error, boost::shared_ptr<std::string> data)
257  {
258  if (error)
259  {
260  closed_ = true;
261  return;
262  }
263  }
264  template <class DATA_TYPE>
266  const vssp::RangeHeader &range_header,
267  const vssp::RangeHeaderV2R1 &range_header_v2r1,
268  const vssp::RangeIndex &range_index,
270  const boost::shared_array<vssp::XYZI> &points)
271  {
272  if (tbl_vn_loaded_.size() != range_header_v2r1.vertical_interlace)
273  return false;
274 
275  int i = 0;
276  const double h_head = range_header.line_head_h_angle_ratio * 2.0 * M_PI / 65535.0;
277  const double h_tail = range_header.line_tail_h_angle_ratio * 2.0 * M_PI / 65535.0;
278  const DATA_TYPE *data = boost::asio::buffer_cast<const DATA_TYPE *>(buf_.data());
279  const int tv = range_header_v2r1.vertical_field;
280  for (int s = 0; s < range_index.nspots; s++)
281  {
282  const double spot = s + range_header.spot;
283  const double h_rad = h_head + (h_tail - h_head) * tbl_h_[spot];
284  const double h_cos = cos(h_rad);
285  const double h_sin = sin(h_rad);
286  const vssp::XYZI dir(tbl_v_[tv][spot].s, tbl_v_[tv][spot].c, h_sin, h_cos);
287  for (int e = index[s]; e < index[s + 1]; e++)
288  points[i++] = dir * data[e];
289  }
290  return true;
291  }
292  void onRead(const boost::system::error_code &error)
293  {
294  const auto time_read = boost::posix_time::microsec_clock::universal_time();
295  const auto length_total = buf_.size();
296  if (error == boost::asio::error::eof)
297  {
298  // Connection closed_
299  closed_ = true;
300  io_service_.stop();
301  return;
302  }
303  else if (error)
304  {
305  // Connection error
306  closed_ = true;
307  io_service_.stop();
308  }
309  while (true)
310  {
311  if (buf_.size() < sizeof(vssp::Header))
312  {
313  break;
314  }
315  // Read packet Header
316  const vssp::Header header = *boost::asio::buffer_cast<const vssp::Header *>(buf_.data());
317  if (header.mark != vssp::VSSP_MARK)
318  {
319  // Invalid packet
320  // find VSSP mark
321  const uint8_t *data = boost::asio::buffer_cast<const uint8_t *>(buf_.data());
322  for (size_t i = 1; i < buf_.size() - sizeof(uint32_t); i++)
323  {
324  const uint32_t *mark = reinterpret_cast<const uint32_t *>(data + i);
325  if (*mark == vssp::VSSP_MARK)
326  {
327  buf_.consume(i);
328  break;
329  }
330  }
331  break;
332  }
333  if (buf_.size() < header.length)
334  break;
335 
336  size_t length = header.length - header.header_length;
337  buf_.consume(header.header_length);
338 
339  do
340  {
341  switch (header.type)
342  {
343  case TYPE_ERR:
344  case TYPE_ER:
345  // Error message
346  {
347  const std::string data(boost::asio::buffer_cast<const char *>(buf_.data()));
348  std::string message(data, 0, header.length - header.header_length - 1);
349  if (cb_error_)
350  cb_error_(header, message, time_read);
351  }
352  break;
353  default:
354  break;
355  }
356  if (header.status != vssp::STATUS_OK)
357  break;
358 
359  switch (header.type)
360  {
361  case TYPE_GET:
362  // Response to get command
363  {
364  const std::string data(boost::asio::buffer_cast<const char *>(buf_.data()));
365  std::vector<std::string> lines;
366  boost::algorithm::split(lines, data, boost::algorithm::is_any_of("\n\r"));
367  if (lines.size() == 0)
368  break;
369 
370  if (lines[0].compare(0, 7, "GET:tbl") == 0 ||
371  lines[0].compare(0, 6, "GET:tv") == 0)
372  {
373  if (lines.size() < 2)
374  break;
375  std::vector<std::string> cells;
376  boost::algorithm::split(cells, lines[1], boost::algorithm::is_any_of(","));
377 
378  if (lines[0].compare("GET:tblv") == 0 ||
379  lines[0].compare(0, 6, "GET:tv") == 0)
380  {
381  int tv = 0;
382  if (lines[0].compare(0, 6, "GET:tv") == 0)
383  tv = std::stoi(lines[0].substr(6));
384 
385  if (tv >= static_cast<int>(tbl_v_.size()))
386  break;
387 
388  boost::shared_array<TableSincos> tbl_v(new TableSincos[cells.size()]);
389  int i = 0;
390  for (auto &cell : cells)
391  {
392  const double rad(std::strtol(cell.c_str(), nullptr, 16) * 2.0 * M_PI / 65535.0);
393  sincos(rad, &tbl_v[i].s, &tbl_v[i].c);
394  i++;
395  }
396  tbl_v_[tv] = tbl_v;
397  tbl_vn_loaded_[tv] = true;
398 
399  bool load_finished = true;
400  for (auto loaded : tbl_vn_loaded_)
401  {
402  if (!loaded)
403  load_finished = false;
404  }
405  tbl_v_loaded_ = load_finished;
406  }
407  else if (lines[0].compare("GET:tblh") == 0)
408  {
409  boost::shared_array<double> tbl_h(new double[cells.size()]);
410  int i = 0;
411  for (auto &cell : cells)
412  {
413  tbl_h[i] = std::strtol(cell.c_str(), nullptr, 16) / 65535.0;
414  i++;
415  }
416  tbl_h_ = tbl_h;
417  tbl_h_loaded_ = true;
418  }
419  }
420  }
421  break;
422  case TYPE_SET:
423  // Response to set command
424  break;
425  case TYPE_DAT:
426  // Response to data request command
427  break;
428  case TYPE_VER:
429  // Response to version request command
430  break;
431  case TYPE_PNG:
432  // Response to ping command
433  if (cb_ping_)
434  cb_ping_(header, time_read);
435  break;
436  case TYPE_RI:
437  case TYPE_RO:
438  // Range data
439  if (!tbl_h_loaded_ || !tbl_v_loaded_ || !cb_point_)
440  {
441  // Something wrong
442  break;
443  }
444  {
445  // Decode range data Header
446  const vssp::RangeHeader range_header = *boost::asio::buffer_cast<const vssp::RangeHeader *>(buf_.data());
448  if (range_header.header_length >= 24)
449  {
450  range_header_v2r1 = *boost::asio::buffer_cast<const vssp::RangeHeaderV2R1 *>(
451  buf_.data() + sizeof(vssp::RangeHeader));
452  }
453  buf_.consume(range_header.header_length);
454  length -= range_header.header_length;
455 
456  // Decode range index Header
457  const vssp::RangeIndex range_index = *boost::asio::buffer_cast<const vssp::RangeIndex *>(buf_.data());
458  size_t index_length = range_index.index_length;
459  buf_.consume(sizeof(vssp::RangeIndex));
460  index_length -= sizeof(vssp::RangeIndex);
461  length -= sizeof(vssp::RangeIndex);
462 
463  // Decode range index
464  boost::shared_array<uint16_t> index(new uint16_t[range_index.nspots + 1]);
465  std::memcpy(index.get(), boost::asio::buffer_cast<const vssp::RangeIndex *>(buf_.data()),
466  sizeof(uint16_t) * (range_index.nspots + 1));
467  buf_.consume(index_length);
468  length -= index_length;
469 
470  // Decode range data
471  boost::shared_array<vssp::XYZI> points(new vssp::XYZI[index[range_index.nspots]]);
472  bool success;
473  switch (header.type)
474  {
475  case TYPE_RI:
476  // Range and Intensity
477  success = rangeToXYZ<vssp::DataRangeIntensity>(
478  range_header, range_header_v2r1, range_index, index, points);
479  break;
480  case TYPE_RO:
481  // Range
482  success = rangeToXYZ<vssp::DataRangeOnly>(
483  range_header, range_header_v2r1, range_index, index, points);
484  break;
485  default:
486  success = false;
487  break;
488  }
489  if (!success)
490  break;
491  cb_point_(header, range_header, range_index, index, points, time_read);
492  }
493  break;
494  case TYPE_AX:
495  // Aux data
496  {
497  // Decode range data Header
498  const vssp::AuxHeader aux_header = *boost::asio::buffer_cast<const vssp::AuxHeader *>(buf_.data());
499  buf_.consume(aux_header.header_length);
500  length -= aux_header.header_length;
501 
502  // Decode Aux data
504  for (int i = 0; i < aux_header.data_count; i++)
505  {
506  const vssp::AuxData *data = boost::asio::buffer_cast<const vssp::AuxData *>(buf_.data());
507  int offset = 0;
508  for (AuxId b = vssp::AX_MASK_LAST; b >= vssp::AX_MASK_FIRST; b = static_cast<AuxId>(b - 1))
509  {
510  if (aux_header.data_bitfield & (1 << static_cast<int>(b)))
511  auxs[i][b] = aux_factor_[b] * data[offset++].val;
512  }
513  buf_.consume(sizeof(int32_t) * offset);
514  length -= sizeof(int32_t) * offset;
515  }
516  if (cb_aux_)
517  cb_aux_(header, aux_header, auxs, time_read);
518  }
519  break;
520  default:
521  break;
522  }
523  }
524  while (false);
525  buf_.consume(length);
526  }
527  receivePackets();
528  return;
529  }
530 };
531 
532 } // namespace vssp
533 
534 #endif // VSSP_H
static const uint32_t TYPE_PNG
Definition: vsspdefs.h:52
void setAutoReset(const bool enable)
Definition: vssp.h:131
static const uint32_t TYPE_SET
Definition: vsspdefs.h:49
Definition: vssp.h:48
bool poll()
Definition: vssp.h:201
uint16_t header_length
Definition: vsspdefs.h:91
uint8_t data_count
Definition: vsspdefs.h:129
double timeout_
Definition: vssp.h:85
void onTimeout(const boost::system::error_code &error)
Definition: vssp.h:237
boost::asio::io_service & getIoService()
Definition: vssp.h:217
void onRead(const boost::system::error_code &error)
Definition: vssp.h:292
ROSCPP_DECL void start()
bool rangeToXYZ(const vssp::RangeHeader &range_header, const vssp::RangeHeaderV2R1 &range_header_v2r1, const vssp::RangeIndex &range_index, const boost::shared_array< const uint16_t > &index, const boost::shared_array< vssp::XYZI > &points)
Definition: vssp.h:265
void requestData(const bool intensity=1, const bool start=1)
Definition: vssp.h:180
void registerAuxCallback(decltype(cb_aux_) cb)
Definition: vssp.h:123
uint16_t header_length
Definition: vsspdefs.h:84
boost::asio::io_service io_service_
Definition: vssp.h:54
void requestVerticalTable(const int itl=1)
Definition: vssp.h:151
void setHorizontalInterlace(const int itl)
Definition: vssp.h:143
XmlRpcServer s
void setTimeout(const double to)
Definition: vssp.h:103
void setVerticalInterlace(const int itl)
Definition: vssp.h:147
boost::function< void(bool)> cb_connect_
Definition: vssp.h:79
static const uint32_t TYPE_AX
Definition: vsspdefs.h:56
void stop()
Definition: vssp.h:213
void registerCallback(decltype(cb_point_) cb)
Definition: vssp.h:119
uint32_t mark
Definition: vsspdefs.h:81
bool tbl_h_loaded_
Definition: vssp.h:82
void registerErrorCallback(decltype(cb_error_) cb)
Definition: vssp.h:115
boost::asio::ip::tcp::socket socket_
Definition: vssp.h:55
static const AuxFactorArray AUX_FACTOR_DEFAULT
Definition: vsspdefs.h:255
void requestAuxData(const bool start=1)
Definition: vssp.h:176
boost::asio::deadline_timer timer_
Definition: vssp.h:56
int16_t line_tail_h_angle_ratio
Definition: vsspdefs.h:95
bool tbl_v_loaded_
Definition: vssp.h:83
AuxFactorArray aux_factor_
Definition: vssp.h:58
uint16_t spot
Definition: vsspdefs.h:99
uint32_t data_bitfield
Definition: vsspdefs.h:128
static const uint32_t TYPE_RI
Definition: vsspdefs.h:54
void registerPingCallback(decltype(cb_ping_) cb)
Definition: vssp.h:127
void receivePackets()
Definition: vssp.h:191
uint16_t nspots
Definition: vsspdefs.h:113
void requestHorizontalTable()
Definition: vssp.h:168
uint8_t vertical_field
Definition: vsspdefs.h:103
boost::asio::streambuf buf_
Definition: vssp.h:87
void onTimeoutConnect(const boost::system::error_code &error)
Definition: vssp.h:229
static const uint32_t TYPE_ERR
Definition: vsspdefs.h:53
uint16_t length
Definition: vsspdefs.h:85
static const uint32_t TYPE_DAT
Definition: vsspdefs.h:50
bool closed_
Definition: vssp.h:57
void setInterlace(const int itl)
Definition: vssp.h:139
std::vector< bool > tbl_vn_loaded_
Definition: vssp.h:84
int16_t line_head_h_angle_ratio
Definition: vsspdefs.h:94
void onConnect(const boost::system::error_code &error)
Definition: vssp.h:245
static const uint32_t TYPE_RO
Definition: vsspdefs.h:55
void onSend(const boost::system::error_code &error, boost::shared_ptr< std::string > data)
Definition: vssp.h:256
static const uint32_t TYPE_ER
Definition: vsspdefs.h:57
const RangeHeaderV2R1 RANGE_HEADER_V2R1_DEFAULT
Definition: vsspdefs.h:106
void spin()
Definition: vssp.h:209
void connect(const char *ip, const unsigned int port, decltype(cb_connect_) cb)
Definition: vssp.h:107
AuxId
Definition: vsspdefs.h:59
boost::function< void(const vssp::Header &, const vssp::RangeHeader &, const vssp::RangeIndex &, const boost::shared_array< uint16_t > &, const boost::shared_array< vssp::XYZI > &, const boost::posix_time::ptime &)> cb_point_
Definition: vssp.h:66
int32_t val
Definition: vsspdefs.h:134
boost::function< void(const vssp::Header &, const boost::posix_time::ptime &)> cb_ping_
Definition: vssp.h:74
const std::string header
static const uint32_t STATUS_OK
Definition: vsspdefs.h:40
boost::function< void(const vssp::Header &, const std::string &, const boost::posix_time::ptime &)> cb_error_
Definition: vssp.h:78
static const uint32_t VSSP_MARK
Definition: vsspdefs.h:39
uint8_t vertical_interlace
Definition: vsspdefs.h:104
void requestPing()
Definition: vssp.h:172
static const uint32_t TYPE_VER
Definition: vsspdefs.h:51
uint32_t status
Definition: vsspdefs.h:83
uint32_t type
Definition: vsspdefs.h:82
std::vector< boost::shared_array< const TableSincos > > tbl_v_
Definition: vssp.h:81
uint16_t header_length
Definition: vsspdefs.h:126
boost::shared_array< const double > tbl_h_
Definition: vssp.h:80
uint16_t index_length
Definition: vsspdefs.h:112
static const uint32_t TYPE_GET
Definition: vsspdefs.h:48
boost::function< void(const vssp::Header &, const vssp::AuxHeader &, const boost::shared_array< vssp::Aux > &, const boost::posix_time::ptime &)> cb_aux_
Definition: vssp.h:71
void send(const std::string cmd)
Definition: vssp.h:223


hokuyo3d
Author(s): Atsushi Watanabe
autogenerated on Sat Jun 8 2019 04:42:00