目录

CAN总线 (Controller Area Network, CAN)

CAN总线 (Controller Area Network, CAN)整理CAN相关知识和使用技巧。

Agreement

相关术语

1. 帧传输

https://store.yirami.xyz/review/can_bus/can_frame_transmit.png

IDENTIFIER The IDENTIFIER’s length is 11 bits. These bits are transmitted in the order from ID-10 to ID-0. The least significant bit is ID-0. DATA FIELD The DATA FIELD consists of the data to be transferred within a DATA FRAME. It can contain from 0 to 8 bytes, which each contain 8 bits which are transferred MSB first.

2. 组包/解包范例
2.1 组包
template <typename T>
void MsgPackage<T>::BuildSignal_(const Signal<T> &layout, const T &value,
                                 unsigned char *raw) {
  // check if long signal
  const int involved_byte = std::abs(layout.start_bit/8-layout.end_bit/8)+1;
  if (sizeof(uint64_t)<static_cast<size_t>(involved_byte)) {
    // TODO(yirami): handle long signal
    std::cout << "[YLog/Error]@canpack: " << "Long signal with "
              << involved_byte << " bytes, unable to handle this!" << std::endl;
    assert(false);
    return;
  }
  // 量化信号物理值并转为内存值。由于计算机中数值同样以补码保存,故无需补码转换
  assert(raw);
  // TODO(yirami): handle the physical value out of valid expression scope
  const uint64_t mask = (static_cast<int64_t>(1) << layout.length) - 1;
  int64_t val = 0;
  if (*(layout.value_type) == typeid(signed int)) {
    const int rval = Int32(std::round(value));  // 物理信号圆整
    val = Int64((rval-Int32(layout.offset))/Int32(layout.factor));  // 量化
    const int remainder = (rval-Int32(layout.offset))%Int32(layout.factor);
    val = (remainder/layout.factor > 0.5)?val+1:val;  // 考虑四舍五入,不直接强转为浮点型是考虑到精度存在丢失可能
  } else if (*(layout.value_type) == typeid(float)) {
    val = Int64(std::round((value-layout.offset)/layout.factor));
  } else if (*(layout.value_type) == typeid(double)) {
    val = Int64(std::round((value-layout.offset)/layout.factor));
  } else {
    // TODO(yirami): support more types
    std::cout << "[YLog/Error]@canpack: " << "Unimplemented value type @ "
              << layout.value_type->name() << "!" << std::endl;
    assert(false);
    return;
  }
  //
  const int step = layout.order == ByteOrder::INTEL?1:-1;
  const int base = layout.start_bit/8;
  uint64_t concate_byte = *(reinterpret_cast<uint64_t*>(&val));  // 有符号类型重新解释为无符号类型,符号位有含义不能丢
  concate_byte &= mask;  // 擦除多余符号位
  concate_byte <<= layout.start_bit%8;  // 按照信号布局要求对齐
  for (int ii = 0; ii < involved_byte; ii++)  // 逐字节写入对应位置
    raw[base+ii*step] |= UInt8((concate_byte >> (ii << 3)) & 0xFF);  // 隐含要求raw中传进来时对应地址内容为空,即0
}
2.2 解包
template <typename T>
T MsgPackage<T>::ParseSignal_(const Signal<T> &layout,
                              const unsigned char *raw) {
  // check if long signal
  const int involved_byte = std::abs(layout.start_bit/8-layout.end_bit/8)+1;
  if (sizeof(uint64_t)<static_cast<size_t>(involved_byte)) {
    // TODO(yirami): handle long signal
    std::cout << "[YLog/Error]@canpack: " << "Long signal with "
              << involved_byte << " bytes, unable to handle this!" << std::endl;
    assert(false);
    return 0;
  }
  //
  assert(raw);
  const uint64_t mask = (static_cast<int64_t>(1) << layout.length) - 1;
  uint64_t concate_byte = 0;
  const int step = layout.order == ByteOrder::INTEL?1:-1;
  const int base = layout.start_bit/8;
  for (int ii = 0; ii < involved_byte; ii++)  // 仅提取信号相关的部分字节
    concate_byte |= static_cast<uint64_t>(raw[base+ii*step]) << (ii*8);
  concate_byte >>= layout.start_bit%8;  // 依据信号布局,对齐lsb到0位
  concate_byte &= mask;  // 擦除信号长度外的信息
  //
  if (layout.is_signed) {  // 如果为有符号信号量
    if (concate_byte >= ((uint64_t)1 << (layout.length -1)))  // 判断是否是负值「最高位为1」,注意边界值
      concate_byte |= ~mask;  // 补齐高位的1「生成信号的补码表示」
  }
  const int64_t val = *(reinterpret_cast<int64_t*>(&concate_byte));  // 由于已经是补码表示了,直接重新解释该量
  //
  if (*(layout.value_type) == typeid(signed int)) {
    const int64_t rval = val*static_cast<int64_t>(layout.factor)+\
                         static_cast<int64_t>(layout.offset);  // 还原信号量的物理值
    return static_cast<T>(rval);
  } else if (*(layout.value_type) == typeid(float)) {
    const T rval = static_cast<float>(val)*layout.factor+layout.offset;
    return static_cast<T>(rval);
  } else if (*(layout.value_type) == typeid(double)) {
    const T rval = static_cast<double>(val)*layout.factor+layout.offset;
    return static_cast<T>(rval);
  } else {
    // TODO(yirami): support more types
    std::cout << "[YLog/Error]@canpack: " << "Unimplemented value type @ "
              << layout.value_type->name() << "!" << std::endl;
    assert(false);
    return 0;
  }
}

XXX

Intro

Infer

Conclusion

Appendix

Reference
Archive