LINUX.ORG.RU

Получить значение поля структуры

 ,


2

3

Задача такая - есть описание поля структуры в формате - стартовый бит (может быть не кратным 8), длинна в битах (1..64), знаковость, LSB или MSB. Надо получить значение. Предполагается, что структура упакованная и может содержать битовые поля. Ну и чтобы было интереснее все это должно работать очень быстро и на процессорах как LSB так и MSB. Arm. Может есть какой-то правильный способ?

как LSB так и MSB

Может ты имеешь в виду little-endian / big-endian ?
А для работы, возьми какую-нибудь либу для работы с bitstream.

anonymous ()
Ответ на: комментарий от anonymous

А для работы, возьми какую-нибудь либу для работы с bitstream.

Ну да, я КО. :)

anonymous ()

ну т.е. образно говоря

#define BIGENDIAN 1
#define LITTLEENDIAN 0

#define SIGNED 1
#define UNSIGNED 0
struct
{
  uint8_t startbit : 1; // тут всегда идет 1 - стартовый бит
  uint8_t lenght : 6;   // от 0 до 63 - это длина от 1 до 64
  uint8_t sign   : 1;   // знаковость
  uint8_t endian : 1;   // тупо-остроконечность
  uint8_t data[8];      // данные. Могут быть короче 64 бит (8 байт)
} test;

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

SZT ★★★★★ ()
Последнее исправление: SZT (всего исправлений: 2)

Если есть возможность что-то менять, то лучше таки впилить выравнивание, ибо его не зря придумали. Прирост скорости от выравненных обращений к памяти значительно превосходит её перерасход.

KivApple ★★★★★ ()
Ответ на: комментарий от SZT

Описания отдельно, данные отдельно. Более подробно - есть описания структур - больше 500 штук. В каждой структуре по несколько (до 64) полей. Поля могут быть с разным ендианлесом в пределах одной структуры. Надо сгенерить код для разбора. Сейчас у меня генеряться по два набора полей (для каждой архитектуры) и код который собирает поля из кусочков если нужно. Но тут привалило еще что некоторые структуры могут еще содержать union. И стало грустнее, т.к. Структуры становятся сложнее.

vromanov ★★ ()

Если все было понято мной правильно, тогда вопросы:
Процессоры ARM с каким набором команд? ARM64? Стоит ли ожидать, что структуры будут преимущественно с длинами в битах равной 8 16 32 64(т.е. чтобы обрабатывать отличные от этого структурки лишь в порядке исключения)?

SZT ★★★★★ ()
Ответ на: комментарий от vromanov

Сами структуры и сами данные выровнены по байтовой границе? Например, если хранить восемь семибитных чисел, это будет вот так выглядеть?

01010010001011011000101000010001010000100110110101001010
{-8bit-}{-8bit-}{-8bit-}{-8bit-}{-8bit-}{-8bit-}{-8bit-}
{7bit-}{7bit-}{7bit-}{7bit-}{7bit-}{7bit-}{7bit-}{7bit-}

SZT ★★★★★ ()
Ответ на: комментарий от vromanov

О, мне тоже скоро с этим работать. Можешь подсказать какую-нибудь литературу о том, как можно считать через OBD2 различные показания вроде уровня топлива, скорости движения и т. п.? Без использования готовых девайсов типа ELM327.

KivApple ★★★★★ ()

Картинки полей внутри структур:

Описание в формате dbc:

Сгенерированный код для структур и их разбора:

vromanov ★★ ()
Ответ на: комментарий от KivApple

Если для грузовиков, то SAE J1939. Если для легковых то OBD2 в самый раз. ELM327 вполне неплохой девайс, но там не хватает производительности если захочется все сообщения снять. Если хочется снять все сообщения, то надо использовтаь либо что-то свое, например на основе STM32 или лучше TMS570, либо устройства типа VECTOR. А что подробнее нужно?

vromanov ★★ ()
Ответ на: комментарий от vromanov

Насколько я понимаю, мне пока с легковушками надо работать. Нужно снять побольше всякой информации (подробности будут немного позднее). Да, планирую применить STM32. Пока нагуглил схему ELM327, собираюсь повторить ту часть, которая отвечает за согласование уровней и т. д.

KivApple ★★★★★ ()

Ну ок, получается так.

Для разворота из LSB в MSB в ARM есть инструкция RBIT http://infocenter.arm.com/help/topic/com.arm.doc.dui0489h/Cihjgdid.html . Не знаю, есть ли это в интринсиках и может ли компилятор додуматься это сгенерировать. Еще ты не сообщил, какие именно ARM-ы там стоят. На случай, если инструкции нет, смотрим https://graphics.stanford.edu/~seander/bithacks.html#BitReverseObvious

Для знаковости (если ее делать ПОСЛЕ разворота) берем знаковый бит, и дозаполняем им всю переменную. Например если у нас 5-битное число 10111 и мы его хотим в 8-битное, то тогда битовой маской выцепляем и делаем sign extend

   10111
   ^
   |
этот бит размножить на старшие
   
   
111
   10111

т.е.

uint8_t val = 0b10111;
uint8_t val_bitlen = 4; // 4 это у нас 5 т.к. 0 это 1

bool signbit = val >> val_bitlen;

if(signbit == 1) val |= ((0b11111111 >> val_bitlen) << val_bitlen)

// сдвиг влево-вправо занулит в конце лишние биты, т.е. получится 0b11110000 и побитовый or наложит 
11110000    
00010111
получим
11110111

SZT ★★★★★ ()
Ответ на: комментарий от KivApple

Если на STM32 то рекомендую купить Что-то вроде такого набора http://www.waveshare.com/product/mcu-tools/stm32/open405r-c-package-a.htm. В него входит все что нужно (кроме пограмматора). В том числе два CAN трансивера. Или только это и два трансивера http://www.waveshare.com/product/mcu-tools/stm32/open405r-c-standard.htm

Но TMS570 лучше. Можно купить ланчпад за $20+$7 доставка FEDEX. http://www.ti.com/tool/launchxl2-tms57012?keyMatch=LAUNCHXL2_TMS57012&tis... И к нему нужен будет такой-же трансивер как и к STM32. У TMS570 куда лучше поддержка CAN, есть бесплатная среда разработки, и он автомотивный.

vromanov ★★ ()
Ответ на: комментарий от SZT

Прежде чем разворачивать, надо еще собрать из кусочков. Разворот хорошо работает если все лежит в одной переменной. Процесор: STM32F4 и TI TMS570.

vromanov ★★ ()
Ответ на: комментарий от vromanov

В собирании из кусочков вообще проблем не вижу. Ну т.е. надо делать битовые маски и ими выцеплять куски. ARM-ам надо чтоб по 32битному выравниванию все было, так что нужны маски вида

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000001
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000111
00000000 00000000 00000000 00001111
...
11111111 11111111 11111111 11111111 <--- ЦЕНТР
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111100
11111111 11111111 11111111 11111000
...
10000000 00000000 00000000 00000000
Хранить их естественно не надо, достаточно взять 0xffffffff (ЦЕНТР) в uint32_t и сдвигать его влево или вправо, и таким образом получаем нужное количество единичек или с левого или с правого края. Потом сшиваем через побитовый or

SZT ★★★★★ ()
Ответ на: комментарий от SZT

хотя не, туплю. Там же не все 32-битные числа. Такая схема нужна на случай попадания числа на границу 32-битных кусков, чтобы их получить. А если число посередине 32битного выровненного куска затесялось, т.е. не пересекает границы... Ну значит дергаем 0xffffffff взад-вперед, получая нужный кусок единичек в нужном месте

SZT ★★★★★ ()
Ответ на: комментарий от SZT

Там может получится так, что одно поле находится внутри другого. По причине разницы архитектур.

vromanov ★★ ()
Ответ на: комментарий от vromanov

У меня как раз такая плата с STM32 есть, только базовая плата, без остальных модулей. CAN-трансивер купил микросхему - собираюсь вытравить плату и припаять её с обвязкой. Для опытного образца сгодится.

Где можно прочитать про форматы автомобильных сообщений на CAN-шине? Насколько важно поддерживать остальные протоколы OBD2 (J1850, K-линия, L-линия)? Где можно почитать про форматы сообщений на этих интерфейсах?

KivApple ★★★★★ ()
Ответ на: комментарий от KivApple

Про OBD2 и другие форматы на этом разъеме подсказать не могу, т.к. этим не занимался. Форматы кроме OBD2 закрытые, для каждого автомобиля свои. Можно поискать в интернете информацию от энтузиастов по конкретной марке.

vromanov ★★ ()
Ответ на: комментарий от KivApple

Если надо быстро, одноразово и по CAN, то под офтопиком есть Openport 2.0, can пакеты получаются буквально за пару вызовов функций, примеры для sdk в комплекте. Если вообще хочется разобраться и отладить свой CAN код - Saleae Logic можно цеплять прямо к canh-canl.

anonymous ()
Ответ на: комментарий от anonymous

Свой код уже есть. И с этим кодом ездят машины. Хочется его улучшить. Конкретно - избавиться от промежуточных структур.

vromanov ★★ ()
Ответ на: комментарий от SZT
 uint8_t startbit : 1; // тут всегда идет 1 - стартовый бит
  uint8_t lenght : 6;   // от 0 до 63 - это длина от 1 до 64
  uint8_t sign   : 1;   // знаковость
  uint8_t endian : 1;   // тупо-остроконечность
  uint8_t data[8]; 

у тебя семь бит для выравнивания после endian торчят

anonymous ()

Отбой. Сделал все-таки на структурах с кусочками полей.

vromanov ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.