CAN总线 (Controller Area Network, CAN)
目录
CAN总线 (Controller Area Network, CAN)整理CAN相关知识和使用技巧。
Agreement
相关术语
1. 帧传输

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;
}
}