00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "CanExtractor.h"
00036
00037 namespace dataspeed_can_tools {
00038
00039 CanExtractor::CanExtractor(const std::string &dbc_file, bool offline, bool expand, bool unknown) :
00040 dbc_(dbc_file), offline_(offline)
00041 {
00042 bag_open_ = false;
00043 expand_ = expand;
00044 unknown_ = unknown;
00045 }
00046
00047 CanExtractor::CanExtractor(const std::vector<std::string> &dbc_file, bool offline, bool expand, bool unknown) :
00048 dbc_(dbc_file), offline_(offline)
00049 {
00050 bag_open_ = false;
00051 expand_ = expand;
00052 unknown_ = unknown;
00053 }
00054
00055 uint64_t CanExtractor::unsignedSignalData(uint64_t raw_data, const RosCanSigStruct& sig_props)
00056 {
00057
00058
00059
00060 uint64_t mask;
00061 if (sig_props.length >= 64) {
00062 mask = ((uint64_t) -1);
00063 } else {
00064
00065 mask = (((uint64_t)1) << sig_props.length) - 1;
00066 }
00067
00068 if (sig_props.order == INTEL) {
00069
00070 return (raw_data >> sig_props.start_bit) & mask;
00071 } else {
00072
00073 int intel_start_bit = 56 - 8 * (sig_props.start_bit / 8) + (sig_props.start_bit % 8) - (sig_props.length - 1);
00074 return (__builtin_bswap64(raw_data) >> intel_start_bit) & mask;
00075 }
00076 }
00077
00078 int64_t CanExtractor::signedSignalData(uint64_t raw_data, const RosCanSigStruct& sig_props)
00079 {
00080 uint64_t mask;
00081 if (sig_props.length >= 64) {
00082 mask = ((uint64_t) -1);
00083 } else {
00084
00085 mask = (((uint64_t)1) << sig_props.length) - 1;
00086 }
00087
00088 int64_t val = unsignedSignalData(raw_data, sig_props);
00089
00090 if (val & (1 << (sig_props.length - 1))) {
00091 val |= ~mask;
00092 }
00093
00094 return val;
00095 }
00096
00097 template<class T>
00098 T CanExtractor::buildMsg(const RosCanSigStruct& info, const uint64_t& data, bool sign)
00099 {
00100 T msg;
00101 if (sign) {
00102 msg.data = (info.factor * signedSignalData(data, info)) + info.offset;
00103 } else {
00104 msg.data = (info.factor * unsignedSignalData(data, info)) + info.offset;
00105 }
00106 return msg;
00107 }
00108
00109 int CanExtractor::getAppropriateSize(const RosCanSigStruct& sig_props, bool output_signed)
00110 {
00111 if (sig_props.length >= 64) {
00112 return 64;
00113 }
00114
00115 int64_t max_val;
00116 int64_t min_val;
00117 if ((sig_props.sign == SIGNED)) {
00118 max_val = (((int64_t)1 << (sig_props.length - 1)) - 1);
00119 min_val = -((int64_t)1 << (sig_props.length - 1));
00120 } else {
00121 max_val = (((int64_t)1 << sig_props.length) - 1);
00122 min_val = 0;
00123 }
00124 max_val = max_val * (int64_t)sig_props.factor + (int64_t)sig_props.offset;
00125 min_val = min_val * (int64_t)sig_props.factor + (int64_t)sig_props.offset;
00126 if (max_val < min_val) {
00127 std::swap(min_val, max_val);
00128 }
00129
00130 if (output_signed) {
00131 if ((INT8_MIN <= min_val) && (max_val <= INT8_MAX)) {
00132 return 8;
00133 } else if ((INT16_MIN <= min_val) && (max_val <= INT16_MAX)) {
00134 return 16;
00135 } else if ((INT32_MIN <= min_val) && (max_val <= INT32_MAX)) {
00136 return 32;
00137 } else {
00138 return 64;
00139 }
00140 } else {
00141 if (max_val <= UINT8_MAX) {
00142 return 8;
00143 } else if (max_val <= UINT16_MAX) {
00144 return 16;
00145 } else if (max_val <= UINT32_MAX) {
00146 return 32;
00147 } else {
00148 return 64;
00149 }
00150 }
00151 }
00152
00153 bool CanExtractor::getMessage(RosCanMsgStruct& can_msg)
00154 {
00155 if (msgs_.find(can_msg.id) == msgs_.end()) {
00156 for (DBCIterator::const_iterator it = dbc_.begin(); it < dbc_.end(); it++) {
00157 if (it->getId() == can_msg.id) {
00158 can_msg.msg_name = it->getName();
00159
00160 for (Message::const_iterator m_it = it->begin(); m_it < it->end(); m_it++) {
00161 RosCanSigStruct new_sig;
00162 new_sig.factor = m_it->getFactor();
00163 new_sig.length = m_it->getLength();
00164 new_sig.maximum = m_it->getMaximum();
00165 new_sig.minimum = m_it->getMinimum();
00166 new_sig.offset = m_it->getOffset();
00167 new_sig.order = m_it->getByteOrder();
00168 new_sig.sig_name = m_it->getName();
00169 new_sig.sign = m_it->getSign();
00170 new_sig.start_bit = m_it->getStartbit();
00171 new_sig.multiplexor = m_it->getMultiplexor();
00172 new_sig.multiplexNum = m_it->getMultiplexedNumber();
00173 can_msg.sigs.push_back(new_sig);
00174 }
00175
00176 msgs_[can_msg.id] = can_msg;
00177 return true;
00178 }
00179 }
00180
00181 if (unknown_msgs_.find(can_msg.id) == unknown_msgs_.end()) {
00182 unknown_msgs_[can_msg.id] = 0;
00183 if (unknown_) {
00184 std::stringstream ss;
00185 ss << "x" << std::hex << std::setfill('0') << std::setw(3) << can_msg.id;
00186 can_msg.msg_name = ss.str();
00187 msgs_[can_msg.id] = can_msg;
00188 return true;
00189 }
00190 ROS_WARN("Received unknown CAN message with ID = 0x%X", can_msg.id);
00191 }
00192 } else {
00193 can_msg = msgs_[can_msg.id];
00194 }
00195
00196 return false;
00197 }
00198
00199 void CanExtractor::initPublishers(RosCanMsgStruct& info, ros::NodeHandle& nh)
00200 {
00201 ros::NodeHandle nh_msg(nh, info.msg_name);
00202
00203 info.message_pub = nh.advertise<can_msgs::Frame>(info.msg_name, 1);
00204
00205 if (expand_) {
00206 ROS_DEBUG("Initializing publishers for %lu signals...",info.sigs.size());
00207 for (size_t i=0; i<info.sigs.size(); i++){
00208 registerCanSignalPublisher(info.sigs[i], nh_msg);
00209 }
00210 }
00211
00212 msgs_[info.id] = info;
00213 }
00214
00215 bool CanExtractor::openBag(const std::string &fname, rosbag::compression::CompressionType compression)
00216 {
00217 if (!bag_open_) {
00218
00219 bag_.setCompression(compression);
00220 bag_fname_ = fname;
00221 return true;
00222 }
00223 return false;
00224 }
00225
00226 bool CanExtractor::closeBag()
00227 {
00228 if (bag_open_) {
00229 bag_.close();
00230 bag_open_ = false;
00231 return true;
00232 }
00233 return false;
00234 }
00235
00236 void CanExtractor::registerCanSignalPublisher(RosCanSigStruct& info, ros::NodeHandle& nh)
00237 {
00238 const uint32_t QUEUE_SIZE = 10;
00239 if (info.length == 1) {
00240 info.sig_pub = nh.advertise<std_msgs::Bool>(info.sig_name, QUEUE_SIZE);
00241 } else if ((fmod(info.factor, 1.0) != 0) || (fmod(info.offset, 1.0) != 0)) {
00242 info.sig_pub = nh.advertise<std_msgs::Float64>(info.sig_name, QUEUE_SIZE);
00243 } else {
00244 if ((info.sign == SIGNED) || (info.offset < 0) || (info.factor < 0)) {
00245 switch (getAppropriateSize(info, true)) {
00246 case 8: info.sig_pub = nh.advertise<std_msgs::Int8 >(info.sig_name, QUEUE_SIZE); break;
00247 case 16: info.sig_pub = nh.advertise<std_msgs::Int16>(info.sig_name, QUEUE_SIZE); break;
00248 case 32: info.sig_pub = nh.advertise<std_msgs::Int32>(info.sig_name, QUEUE_SIZE); break;
00249 case 64: info.sig_pub = nh.advertise<std_msgs::Int64>(info.sig_name, QUEUE_SIZE); break;
00250 }
00251 } else {
00252 switch (getAppropriateSize(info, false)) {
00253 case 8: info.sig_pub = nh.advertise<std_msgs::UInt8 >(info.sig_name, QUEUE_SIZE); break;
00254 case 16: info.sig_pub = nh.advertise<std_msgs::UInt16>(info.sig_name, QUEUE_SIZE); break;
00255 case 32: info.sig_pub = nh.advertise<std_msgs::UInt32>(info.sig_name, QUEUE_SIZE); break;
00256 case 64: info.sig_pub = nh.advertise<std_msgs::UInt64>(info.sig_name, QUEUE_SIZE); break;
00257 }
00258 }
00259 }
00260 }
00261
00262 template<class T>
00263 void CanExtractor::writeToBag(const std::string& frame, const ros::Time& stamp, const T& msg) {
00264
00265 if (!bag_open_) {
00266 ROS_DEBUG("Opening bag file for writing...");
00267 bag_open_ = true;
00268 bag_.open(bag_fname_, rosbag::bagmode::Write);
00269 }
00270 bag_.write(frame, stamp, msg);
00271 }
00272
00273 template<class T>
00274 void CanExtractor::pubCanSig(const RosCanMsgStruct& info, const T& sig_msg, const ros::Time& stamp, size_t i) {
00275 ROS_DEBUG(" Publishing value (%s): %f", info.sigs[i].sig_name.c_str(), (double)sig_msg.data);
00276 if (i < info.sigs.size()) {
00277 if (offline_) {
00278 writeToBag(info.msg_name + "/" + info.sigs[i].sig_name, stamp, sig_msg);
00279 } else {
00280 info.sigs[i].sig_pub.publish(sig_msg);
00281 }
00282 }
00283 }
00284
00285 void CanExtractor::pubCanMsg(const RosCanMsgStruct& info, const can_msgs::Frame& msg, const ros::Time& stamp) {
00286 if (offline_) {
00287 writeToBag(info.msg_name, stamp, msg);
00288 } else {
00289 info.message_pub.publish(msg);
00290 }
00291 }
00292
00293 void CanExtractor::pubMessage(const can_msgs::Frame& msg, const ros::Time &stamp)
00294 {
00295
00296 const uint32_t id = msg.id | (msg.is_extended ? 0x80000000 : 0x00000000);
00297 if (msgs_.find(id) == msgs_.end()) {
00298 ROS_WARN("Bad message ID...");
00299 return;
00300 }
00301 const RosCanMsgStruct &info = msgs_[id];
00302 const uint64_t data = *((uint64_t*)&msg.data[0]);
00303
00304
00305 pubCanMsg(info, msg, stamp);
00306
00307
00308 if (!expand_) return;
00309
00310
00311 unsigned short multiplexorValue = -1;
00312 for (size_t i = 0; i < info.sigs.size(); i++) {
00313 if (info.sigs[i].multiplexor == MULTIPLEXOR) {
00314 multiplexorValue = unsignedSignalData(data, info.sigs[i]);
00315 break;
00316 }
00317 }
00318
00319
00320 for (size_t i = 0; i < info.sigs.size(); i++) {
00321
00322
00323 ROS_DEBUG("MSG Name: %s", info.sigs[i].sig_pub.getTopic().c_str());
00324
00325 if (info.sigs[i].multiplexor == MULTIPLEXED) {
00326 if (info.sigs[i].multiplexNum != multiplexorValue) {
00327 ROS_DEBUG(" Skipping multiplexed value...");
00328 continue;
00329 }
00330 }
00331
00332
00333 if (info.sigs[i].length == 1) {
00334 pubCanSig(info, buildMsg<std_msgs::Bool>(info.sigs[i], data, false), stamp, i);
00335 } else if ((fmod(info.sigs[i].factor, 1.0) != 0) || fmod(info.sigs[i].offset, 1.0) != 0) {
00336 pubCanSig(info, buildMsg<std_msgs::Float64>(info.sigs[i], data, info.sigs[i].sign == SIGNED), stamp, i);
00337 } else {
00338 if ((info.sigs[i].sign == SIGNED) || (info.sigs[i].offset < 0) || (info.sigs[i].factor < 0)) {
00339 if (info.sigs[i].sign == SIGNED) {
00340 switch (getAppropriateSize(info.sigs[i], true)) {
00341 case 8: pubCanSig(info, buildMsg<std_msgs::Int8 >(info.sigs[i], data, true), stamp, i); break;
00342 case 16: pubCanSig(info, buildMsg<std_msgs::Int16>(info.sigs[i], data, true), stamp, i); break;
00343 case 32: pubCanSig(info, buildMsg<std_msgs::Int32>(info.sigs[i], data, true), stamp, i); break;
00344 case 64: pubCanSig(info, buildMsg<std_msgs::Int64>(info.sigs[i], data, true), stamp, i); break;
00345 }
00346 } else {
00347 switch (getAppropriateSize(info.sigs[i], true)) {
00348 case 8: pubCanSig(info, buildMsg<std_msgs::Int8 >(info.sigs[i], data, false), stamp, i); break;
00349 case 16: pubCanSig(info, buildMsg<std_msgs::Int16>(info.sigs[i], data, false), stamp, i); break;
00350 case 32: pubCanSig(info, buildMsg<std_msgs::Int32>(info.sigs[i], data, false), stamp, i); break;
00351 case 64: pubCanSig(info, buildMsg<std_msgs::Int64>(info.sigs[i], data, false), stamp, i); break;
00352 }
00353 }
00354 } else {
00355 switch (getAppropriateSize(info.sigs[i], false)) {
00356 case 8: pubCanSig(info, buildMsg<std_msgs::UInt8 >(info.sigs[i], data, false), stamp, i); break;
00357 case 16: pubCanSig(info, buildMsg<std_msgs::UInt16>(info.sigs[i], data, false), stamp, i); break;
00358 case 32: pubCanSig(info, buildMsg<std_msgs::UInt32>(info.sigs[i], data, false), stamp, i); break;
00359 case 64: pubCanSig(info, buildMsg<std_msgs::UInt64>(info.sigs[i], data, false), stamp, i); break;
00360 }
00361 }
00362 }
00363 }
00364 }
00365
00366 }
00367