Алгоритм битовой маски по сообщениям CAN

Используя CAN-связь с DBC в качестве базы данных, существует два разных способа кодирования целочисленных сигналов в 64-битные (8-байтовые) данные сообщения: Intel и Motorola.
Чтобы преобразовать 8-байтовые данные сообщения в отдельные сигналы, я сначала хочу использовать битовую маску, чтобы «охватить» только интересные биты, а затем выполнить некоторые операции сдвига, чтобы получить число, которое представляет сигнал.
Здесь меня интересует только поколение битовых масок:
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;
}

С числами на основе Motorola (big-endian) это немного сложнее:
поскольку метеоритер (НЕ БИТДЕР) поменялся местами, младший байт (в соответствии с индексом) может содержать «пробелы» в старших битах, а старший (индексированный) байт может иметь «пробелы» в нижнем конце байта ( см. сигнал MOTO_20 на изображении; биты 22/23 и 32/33 не являются частью сигнала, хотя они окружены битами, которые являются).

Я ищу способ рассчитать эту битовую маску на основе начального бита и длины соответствующего сигнала. Вы можете найти два примера сигналов на основе моторолы, размещенных в кадре CAN на изображении ниже. Начальные биты и длины указаны под изображением.

Предполагается, что битовая маска соответствует структуре сообщения шины CAN с использованием dbc (изображение в качестве примера): каждый бит сигнала, отмеченный на изображении, должен быть равен 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

Макет сообщения

-2

Решение

Я понял это, сосредоточившись на «пробелах», которые образуются в пределах битового поля, и помещая в результат только 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;
}
-1

Другие решения

Других решений пока нет …