CAN 消息上的位掩码算法
Algorithm for bitmask on CAN messages
使用 CAN 与 DBC 通信作为数据库,有两种不同的方式将整数信号编码为 64 位(8 字节)消息数据:Intel 和 Motorola。
要将 8 字节的消息数据转换为不同的信号,我首先想使用位掩码 "scope" 仅感兴趣的位,然后进行一些移位操作以获得信号所代表的数字。
这里我只对位掩码生成感兴趣:
Intel(也称为 little-endian)非常简单:你获取起始位并迭代到 startBit + length
将你的 64 位掩码中的每一位设置为你得到的 1:
uint64_t generateBitmask(Signal* signal) {
uint64_t bitmask = 0;
uint64_t one = 1;
int startBit = signal->startbit;
int endBit = startBit + signal->length;
if(signal->byteOrder == INTEL) {
for(int i = startBit; i < endBit; ++i)
{
bitmask |= (one << i);
}
}
return bitmask;
}
对于基于摩托罗拉(big-endian)的数字,它有点复杂:
由于字节顺序(不是位顺序)被交换,(根据索引)最低字节可能在高位包含 "gaps" 而最高(索引)字节可能在低端有 "gaps"字节的(参见图像中的信号 MOTO_20;位 22/23 和 32/33 不是信号的一部分,尽管它们被信号包围)。
我正在寻找一种方法来根据相应信号的起始位和长度来计算此位掩码。请在下图中的 CAN 帧中找到基于摩托罗拉的信号的两个示例。图片下方给出了起始位和长度。
位掩码应该对应于使用 dbc 的 CAN 总线消息布局的样子(以图像为例):图像中标记的信号的每一位都应该是 1:
示例 MOTO_20:00000000 00000000 00000000 11111000 11111111 01111111 00000000 00000000
示例 MOTO_16:00000000 00000000 00000000 00000000 00000000 00000000 11111111 11111111
信号 MOTO_20 的起始位为 34,长度为 20
信号 MOTO_16 的起始位为 8,长度为 16
我通过关注位域中形成的 "gaps" 并在没有间隙时只在结果中放入 1 来解决这个问题:
uint64_t generateBitmask(int startBit, int length) {
uint64_t result = 0;
int startByte = startBit / 8;
int byteLength = length % 8 == 0 ? length / 8 : length / 8 + 1;
int lowerGapStart = startBit % 8;
int upperGapStart = (7 + (length - ((byteLength * 8) - (lowerGapStart)))) % 8;
for (int i = startByte; i > startByte - byteLength; --i) {
for (int j = 0; j < 8; ++j) {
if (i == startByte && j < lowerGapStart ||
i == startByte - byteLength + 1 && j > upperGapStart) {
continue;
} else {
bitmask |= (one << (i * 8) + j);
}
}
}
return result;
}
使用 CAN 与 DBC 通信作为数据库,有两种不同的方式将整数信号编码为 64 位(8 字节)消息数据:Intel 和 Motorola。
要将 8 字节的消息数据转换为不同的信号,我首先想使用位掩码 "scope" 仅感兴趣的位,然后进行一些移位操作以获得信号所代表的数字。
这里我只对位掩码生成感兴趣:
Intel(也称为 little-endian)非常简单:你获取起始位并迭代到 startBit + length
将你的 64 位掩码中的每一位设置为你得到的 1:
uint64_t generateBitmask(Signal* signal) {
uint64_t bitmask = 0;
uint64_t one = 1;
int startBit = signal->startbit;
int endBit = startBit + signal->length;
if(signal->byteOrder == INTEL) {
for(int i = startBit; i < endBit; ++i)
{
bitmask |= (one << i);
}
}
return bitmask;
}
对于基于摩托罗拉(big-endian)的数字,它有点复杂:
由于字节顺序(不是位顺序)被交换,(根据索引)最低字节可能在高位包含 "gaps" 而最高(索引)字节可能在低端有 "gaps"字节的(参见图像中的信号 MOTO_20;位 22/23 和 32/33 不是信号的一部分,尽管它们被信号包围)。
我正在寻找一种方法来根据相应信号的起始位和长度来计算此位掩码。请在下图中的 CAN 帧中找到基于摩托罗拉的信号的两个示例。图片下方给出了起始位和长度。
位掩码应该对应于使用 dbc 的 CAN 总线消息布局的样子(以图像为例):图像中标记的信号的每一位都应该是 1:
示例 MOTO_20:00000000 00000000 00000000 11111000 11111111 01111111 00000000 00000000
示例 MOTO_16:00000000 00000000 00000000 00000000 00000000 00000000 11111111 11111111
信号 MOTO_20 的起始位为 34,长度为 20
信号 MOTO_16 的起始位为 8,长度为 16
我通过关注位域中形成的 "gaps" 并在没有间隙时只在结果中放入 1 来解决这个问题:
uint64_t generateBitmask(int startBit, int length) {
uint64_t result = 0;
int startByte = startBit / 8;
int byteLength = length % 8 == 0 ? length / 8 : length / 8 + 1;
int lowerGapStart = startBit % 8;
int upperGapStart = (7 + (length - ((byteLength * 8) - (lowerGapStart)))) % 8;
for (int i = startByte; i > startByte - byteLength; --i) {
for (int j = 0; j < 8; ++j) {
if (i == startByte && j < lowerGapStart ||
i == startByte - byteLength + 1 && j > upperGapStart) {
continue;
} else {
bitmask |= (one << (i * 8) + j);
}
}
}
return result;
}