CanDriver.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2015-2020, Dataspeed Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Dataspeed Inc. nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
37 #include <std_msgs/String.h>
38 
39 namespace dataspeed_can_usb
40 {
41 
42 static bool getParamHex(const ros::NodeHandle &nh, const std::string& key, int& i) {
43  if (nh.getParam(key, i)) {
44  return true;
45  } else {
46  std::string str;
47  if (nh.getParam(key, str)) {
48  if (str.length() > 2) {
49  if ((str.at(0) == '0') && (str.at(1) == 'x')) {
50  unsigned int u;
51  std::stringstream ss;
52  ss << std::hex << str.substr(2);
53  ss >> u;
54  if (!ss.fail()) {
55  i = u;
56  return true;
57  }
58  }
59  }
60  }
61  }
62  return false;
63 }
64 
65 static uint8_t getModeFromString(const std::string &str) {
66  if (str == "normal") {
67  return 0;
68  } else if (str == "listen-only") {
69  return 1;
70  }
71  return 0; // Default to "normal"
72 }
73 
74 CanDriver::CanDriver(ros::NodeHandle &nh, ros::NodeHandle &nh_priv, lusb::UsbDevice *dev, const std::string &name, const ModuleVersion &firmware) :
75  nh_(nh), nh_priv_(nh_priv), name_(name), total_drops_(0), firmware_(firmware)
76 {
77  dev_ = new CanUsb(dev);
78  dev_->setRecvCallback(boost::bind(&CanDriver::recvDevice, this, _1, _2, _3, _4, _5));
79 
80  // Get Parameters
81  sync_time_ = false;
82  error_topic_ = true;
83  std::string mode;
84  Channel channel;
85 #if 0
86  priv_nh.getParam("sync_time", sync_time_);
87 #endif
88  nh_priv.getParam("bitrate", channel.bitrate);
89  nh_priv.getParam("mode", mode);
90  nh_priv.getParam("error_topic", error_topic_);
91  nh_priv.getParam("mac_addr", mac_addr_);
92 
93  channel.mode = getModeFromString(mode);
94  channels_.resize(CanUsb::MAX_CHANNELS, channel);
95  for (unsigned int i = 0; i < CanUsb::MAX_CHANNELS; i++) {
96  std::string mode;
97  std::stringstream ss1, ss2;
98  ss1 << "bitrate_" << (i + 1);
99  ss2 << "mode_" << (i + 1);
100  nh_priv.getParam(ss1.str(), channels_[i].bitrate);
101  nh_priv.getParam(ss2.str(), mode);
102  channels_[i].mode = getModeFromString(mode);
103  for (unsigned int j = 0; j < CanUsb::MAX_FILTERS; j++) {
104  bool success = true;
105  Filter filter;
106  std::stringstream ss1, ss2;
107  ss1 << "channel_" << (i + 1) << "_mask_" << j;
108  ss2 << "channel_" << (i + 1) << "_match_" << j;
109  success &= getParamHex(nh_priv, ss1.str(), (int&)filter.mask);
110  success &= getParamHex(nh_priv, ss2.str(), (int&)filter.match);
111  if (success) {
112  channels_[i].filters.push_back(filter);
113  }
114  }
115  }
116 
117  serviceDevice();
118 
119  // Setup Timers
122 }
123 
125 {
126  if (dev_) {
127  if (dev_->isOpen()) {
128  dev_->reset();
129  }
130  delete dev_;
131  dev_ = NULL;
132  }
133 }
134 
135 void CanDriver::recvRos(const can_msgs::Frame::ConstPtr& msg, unsigned int channel)
136 {
137  dev_->sendMessage(channel, msg->id, msg->is_extended, msg->dlc, msg->data.elems);
138 }
139 
140 void CanDriver::recvDevice(unsigned int channel, uint32_t id, bool extended, uint8_t dlc, const uint8_t data[8])
141 {
142  boost::lock_guard<boost::mutex> lock(mutex_);
143  if (channel < pubs_.size()) {
144  can_msgs::Frame msg;
145  msg.header.stamp = ros::Time::now();
146  msg.id = id;
147  msg.is_rtr = false;
148  msg.is_extended = extended;
149  msg.is_error = (dlc == 0x0F);
150  msg.dlc = dlc;
151  memcpy(msg.data.elems, data, 8);
152  if (msg.is_error && (channel < pubs_err_.size())) {
153  pubs_err_[channel].publish(msg);
154  } else {
155  pubs_[channel].publish(msg);
156  }
157  }
158 }
159 
161  unsigned int dev_time;
163  if (dev_->getTimeStamp(dev_time)) {
165  ros::WallTime t1 = stampDev2Ros(dev_time);
166  delay = t2 - t0;
167  int64_t nsec = (t2 - t0).toNSec();
168  ros::WallDuration delta;
169  delta.fromNSec(nsec / 2);
170  ros::WallTime asdf = t0 + delta;
171  offset = asdf - t1;
172  return true;
173  }
174  return false;
175 }
176 
178 {
179  if (!dev_->isOpen()) {
180  boost::lock_guard<boost::mutex> lock(mutex_);
181  pubs_err_.clear();
182  pubs_.clear();
183  subs_.clear();
185  if (dev_->open(mac_addr_)) {
186  if (dev_->reset()) {
188  ROS_INFO("%s: version %s", name_.c_str(), dev_->version().c_str());
189  std_msgs::String version_msg;
190  pub_version_ = nh_priv_.advertise<std_msgs::String>("version", 1, true);
191  version_msg.data = dev_->version().c_str();
192  pub_version_.publish(version_msg);
193  ROS_INFO("%s: MAC address %s", name_.c_str(), dev_->macAddr().toString().c_str());
194  if (firmware_.valid() && version < firmware_) {
195  ROS_WARN("Detected old %s firmware version %u.%u.%u, updating to %u.%u.%u is suggested. Execute `%s` to update.", name_.c_str(),
196  version.major(), version.minor(), version.build(),
198  "rosrun dataspeed_can_usb fw_update.bash");
199  }
200  bool synced = false;
201  if (sync_time_) {
202  ROS_INFO("%s: Synchronizing time...", name_.c_str());
203  ros::WallDuration offset, delay;
204  for (unsigned int i = 0; i < 10; i++) {
205  sampleTimeOffset(offset, delay);
206  ROS_INFO("%s: Offset: %f seconds, Delay: %f seconds", name_.c_str(), offset.toSec(), delay.toSec());
207  }
208  synced = true;
209  }
210  if (!sync_time_ || synced) {
211  bool success = true;
212  for (unsigned int i = 0; i < dev_->numChannels(); i++) {
213  for (unsigned int j = 0; j < channels_[i].filters.size(); j++) {
214  const uint32_t mask = channels_[i].filters[j].mask;
215  const uint32_t match = channels_[i].filters[j].match;
216  if (dev_->addFilter(i, mask, match)) {
217  ROS_INFO("%s: Ch%u, Mask: 0x%08X, Match: 0x%08X", name_.c_str(), i + 1, mask, match);
218  } else {
219  ROS_WARN("%s: Ch%u, Mask: 0x%08X, Match: 0x%08X failed", name_.c_str(), i + 1, mask, match);
220  }
221  }
222  }
223  for (unsigned int i = 0; i < dev_->numChannels(); i++) {
224  const int bitrate = i < channels_.size() ? channels_[i].bitrate : 0;
225  const uint8_t mode = i < channels_.size() ? channels_[i].mode : 0;
226  if (dev_->setBitrate(i, bitrate, mode)) {
227  ROS_INFO("%s: Ch%u %ukbps", name_.c_str(), i + 1, bitrate / 1000);
228  } else {
229  ROS_WARN("%s: Ch%u %ukbps failed", name_.c_str(), i + 1, bitrate / 1000);
230  success = false;
231  }
232  }
233  if (success) {
234  // Setup Publishers and Subscribers
235  for (unsigned int i = 0; i < dev_->numChannels(); i++) {
236  if (i < channels_.size() && channels_[i].bitrate) {
237  std::stringstream ns;
238  ns << "can_bus_" << (i + 1);
239  ros::NodeHandle node(nh_, ns.str());
240  if (channels_[i].mode) {
241  subs_.push_back(ros::Subscriber()); // Listen-only mode cannot transmit
242  } else {
243  subs_.push_back(node.subscribe<can_msgs::Frame>("can_tx", 100, boost::bind(&CanDriver::recvRos, this, _1, i), ros::VoidConstPtr(), ros::TransportHints().tcpNoDelay()));
244  }
245  pubs_.push_back(node.advertise<can_msgs::Frame>("can_rx", 100, false));
246  if (error_topic_) {
247  pubs_err_.push_back(node.advertise<can_msgs::Frame>("can_err", 100, false));
248  }
249  } else {
250  subs_.push_back(ros::Subscriber());
251  pubs_.push_back(ros::Publisher());
252  if (error_topic_) {
253  pubs_err_.push_back(ros::Publisher());
254  }
255  }
256  }
257  } else {
258  dev_->reset();
259  dev_->closeDevice();
260  ROS_WARN("%s: Failed to set bitrate", name_.c_str());
261  }
262  } else {
263  dev_->closeDevice();
264  ROS_WARN("%s: Failed to sync time", name_.c_str());
265  }
266  } else {
267  dev_->closeDevice();
268  ROS_WARN("%s: Failed to reset", name_.c_str());
269  }
270  } else {
271  if (mac_addr_.empty()) {
272  ROS_WARN_THROTTLE(10.0, "%s: Not found", name_.c_str());
273  } else {
274  ROS_WARN_THROTTLE(10.0, "%s: MAC address '%s' not found", name_.c_str(), mac_addr_.c_str());
275  }
276  }
277  } else {
278  std::vector<uint32_t> rx_drops, tx_drops;
279  std::vector<uint8_t> rx_errors, tx_errors;
280  if (dev_->getStats(rx_drops, tx_drops, rx_errors, tx_errors, true)) {
281  unsigned int size = std::min(rx_drops.size(), tx_drops.size());
282  uint32_t total = 0;
283  for (unsigned int i = 0; i < size; i++) {
284  total += rx_drops[i];
285  total += tx_drops[i];
286  }
287  if (total != total_drops_) {
288  total_drops_ = total;
289  std::stringstream ss;
290  for (unsigned int i = 0; i < size; i++) {
291  ss << "Rx" << (i + 1) << ": " << rx_drops[i] << ", ";
292  ss << "Tx" << (i + 1) << ": " << tx_drops[i] << ", ";
293  }
294  ROS_WARN("Dropped CAN messages: %s", ss.str().c_str());
295  }
296  }
297  }
298 }
299 
301 {
302  serviceDevice();
303 }
304 
306 {
307  dev_->flushMessages();
308 }
309 
310 } // namespace dataspeed_can_usb
311 
unsigned int numChannels() const
Definition: CanUsb.h:71
std::vector< ros::Subscriber > subs_
Definition: CanDriver.h:107
void recvDevice(unsigned int channel, uint32_t id, bool extended, uint8_t dlc, const uint8_t data[8])
Definition: CanDriver.cpp:140
static bool getParamHex(const ros::NodeHandle &nh, const std::string &key, int &i)
Definition: CanDriver.cpp:42
#define ROS_WARN_THROTTLE(rate,...)
void publish(const boost::shared_ptr< M > &message) const
std::string version() const
Definition: CanUsb.cpp:370
std::vector< ros::Publisher > pubs_err_
Definition: CanDriver.h:112
static uint8_t getModeFromString(const std::string &str)
Definition: CanDriver.cpp:65
ros::NodeHandle nh_priv_
Definition: CanDriver.h:81
void recvRos(const can_msgs::Frame::ConstPtr &msg, unsigned int channel)
Definition: CanDriver.cpp:135
void sendMessage(unsigned int channel, uint32_t id, bool extended, uint8_t dlc, const uint8_t data[8], bool flush=true)
Definition: CanUsb.cpp:303
bool sampleTimeOffset(ros::WallDuration &offset, ros::WallDuration &delay)
Definition: CanDriver.cpp:160
#define ROS_WARN(...)
ros::WallTimer timer_flush_
Definition: CanDriver.h:101
bool getTimeStamp(uint32_t &timestamp)
Definition: CanUsb.cpp:289
std::vector< ros::Publisher > pubs_
Definition: CanDriver.h:111
TransportHints & tcpNoDelay(bool nodelay=true)
#define ROS_INFO(...)
bool getStats(std::vector< uint32_t > &rx_drops, std::vector< uint32_t > &tx_drops, std::vector< uint8_t > &rx_errors, std::vector< uint8_t > &tx_errors, bool clear=false)
Definition: CanUsb.cpp:263
ros::Publisher pub_version_
Definition: CanDriver.h:110
void setRecvCallback(const Callback &callback)
Definition: CanUsb.h:89
WallTimer createWallTimer(WallDuration period, void(T::*callback)(const WallTimerEvent &), T *obj, bool oneshot=false, bool autostart=true) const
ros::WallTime stampDev2Ros(unsigned int dev_stamp)
Definition: CanDriver.h:75
void timerFlushCallback(const ros::WallTimerEvent &event)
Definition: CanDriver.cpp:305
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
uint16_t versionBuild() const
Definition: CanUsb.h:67
bool open(const std::string &mac=std::string())
Definition: CanUsb.cpp:111
uint16_t versionMinor() const
Definition: CanUsb.h:66
uint16_t versionMajor() const
Definition: CanUsb.h:65
static const unsigned int MAX_CHANNELS
Definition: CanUsb.h:58
static WallTime now()
std::vector< Channel > channels_
Definition: CanDriver.h:97
bool getParam(const std::string &key, std::string &s) const
WallDuration & fromNSec(int64_t t)
void timerServiceCallback(const ros::WallTimerEvent &event)
Definition: CanDriver.cpp:300
static Time now()
ros::WallTimer timer_service_
Definition: CanDriver.h:100
std::string toString(bool upper=false) const
Definition: MacAddr.h:64
MacAddr macAddr() const
Definition: CanUsb.h:70
CanDriver(ros::NodeHandle &nh, ros::NodeHandle &nh_priv, lusb::UsbDevice *dev=NULL, const std::string &name=std::string("Dataspeed USB CAN Tool"), const ModuleVersion &firmware=ModuleVersion(10, 4, 0))
Definition: CanDriver.cpp:74
bool addFilter(unsigned int channel, uint32_t mask, uint32_t match)
Definition: CanUsb.cpp:245
bool setBitrate(unsigned int channel, uint32_t bitrate, uint8_t mode=0)
Definition: CanUsb.cpp:229
static const unsigned int MAX_FILTERS
Definition: CanUsb.h:59


dataspeed_can_usb
Author(s): Kevin Hallenbeck
autogenerated on Thu Jul 9 2020 03:42:00