packer.cc 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. #include <algorithm>
  2. #include <cassert>
  3. #include <cmath>
  4. #include <map>
  5. #include <stdexcept>
  6. #include <utility>
  7. #include "candbc.h"
  8. void set_value(std::vector<uint8_t> &msg, const Signal &sig, int64_t ival) {
  9. int i = sig.lsb / 8;
  10. int bits = sig.size;
  11. if (sig.size < 64) {
  12. ival &= ((1ULL << sig.size) - 1);
  13. }
  14. while (i >= 0 && i < msg.size() && bits > 0) {
  15. int shift = (int)(sig.lsb / 8) == i ? sig.lsb % 8 : 0;
  16. int size = std::min(bits, 8 - shift);
  17. msg[i] &= ~(((1ULL << size) - 1) << shift);
  18. msg[i] |= (ival & ((1ULL << size) - 1)) << shift;
  19. bits -= size;
  20. ival >>= size;
  21. i = sig.is_little_endian ? i+1 : i-1;
  22. }
  23. }
  24. CANPacker::CANPacker(const std::string& dbc_name) {
  25. dbc = dbc_lookup(dbc_name);
  26. assert(dbc);
  27. for (const auto& msg : dbc->msgs) {
  28. for (const auto& sig : msg.sigs) {
  29. signal_lookup[std::make_pair(msg.address, sig.name)] = sig;
  30. }
  31. }
  32. }
  33. std::vector<uint8_t> CANPacker::pack(uint32_t address, const std::vector<SignalPackValue> &signals) {
  34. auto msg_it = dbc->addr_to_msg.find(address);
  35. if (msg_it == dbc->addr_to_msg.end()) {
  36. LOGE("undefined address %d", address);
  37. return {};
  38. }
  39. std::vector<uint8_t> ret(msg_it->second->size, 0);
  40. // set all values for all given signal/value pairs
  41. bool counter_set = false;
  42. for (const auto& sigval : signals) {
  43. auto sig_it = signal_lookup.find(std::make_pair(address, sigval.name));
  44. if (sig_it == signal_lookup.end()) {
  45. // TODO: do something more here. invalid flag like CANParser?
  46. LOGE("undefined signal %s - %d\n", sigval.name.c_str(), address);
  47. continue;
  48. }
  49. const auto &sig = sig_it->second;
  50. int64_t ival = (int64_t)(round((sigval.value - sig.offset) / sig.factor));
  51. if (ival < 0) {
  52. ival = (1ULL << sig.size) + ival;
  53. }
  54. set_value(ret, sig, ival);
  55. if (sigval.name == "COUNTER") {
  56. counters[address] = sigval.value;
  57. counter_set = true;
  58. }
  59. }
  60. // set message counter
  61. auto sig_it_counter = signal_lookup.find(std::make_pair(address, "COUNTER"));
  62. if (!counter_set && sig_it_counter != signal_lookup.end()) {
  63. const auto& sig = sig_it_counter->second;
  64. if (counters.find(address) == counters.end()) {
  65. counters[address] = 0;
  66. }
  67. set_value(ret, sig, counters[address]);
  68. counters[address] = (counters[address] + 1) % (1 << sig.size);
  69. }
  70. // set message checksum
  71. auto sig_it_checksum = signal_lookup.find(std::make_pair(address, "CHECKSUM"));
  72. if (sig_it_checksum != signal_lookup.end()) {
  73. const auto &sig = sig_it_checksum->second;
  74. if (sig.calc_checksum != nullptr) {
  75. unsigned int checksum = sig.calc_checksum(address, sig, ret);
  76. set_value(ret, sig, checksum);
  77. }
  78. }
  79. return ret;
  80. }
  81. // This function has a definition in common.h and is used in PlotJuggler
  82. const Msg* CANPacker::lookup_message(uint32_t address) {
  83. return dbc->addr_to_msg.at(address);
  84. }