Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Приём/передача незапакованной структуры для C2000
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
sigmaN
Код
typedef uint32_t ba05_blockKey[BA05_BLOCKKEYSIZE];

//заголовок у обоих типов пакетов общий, поэтому опишем его один раз
struct ba05_net_pktHeader
{
    uint16_t    packetType    : 3;    //ID-пакет, BlockPacket или HeaderPacket
    uint16_t    connStageID    : 3;    //public_keys_interchange, random_sample_interchange, hash_interchange
    uint16_t    needACK        : 1;    //сообщает приёмнику, что в ответ на этот пакет нужно обязательно отправить ACK пакет
    uint16_t    ACK            : 1;    //Признак пакета подтверждения. Если ACK==1 - все остальные поля не используются(кроме crc8,естественно)    
    uint16_t    crc8         : 8;
};
//описание поля data для пакета IDPacket
struct ba05_net_IDPacket_data
{
    ba05_ID                public_ID;    
    ba05_ID                corp_ID;    
};
//поле data для Block-пакета описано в объявлении ba05_net_packet ниже
typedef struct
{
    struct ba05_net_pktHeader             header;
    union
    {
        struct ba05_net_IDPacket_data     asIDPacket;
        ba05_blockKey                asBlockPacket;
    }data;
}ba05_net_packet;

Прагмы, заставляющей компилятор запаковать структуру - нет.
Тип ba05_blockKey может изменяться в зависимости от настроек алгоритма. Т.е. вместо uint32_t там может появиться uint16_t или uint64_t, соответственно, выравнивание будет разным.
На данный момент, не сложно догадаться, после header идёт пустышка(1слово), длее идёт data.
Если бы структура передавалась всегда полностью - проблем бы не было. Но в зависимости от ситуации, передаётся либо только header, либо header + asIDPacket, либо целиком(header + asBlockPacket).
Функции отправки/приёма анализируют header.packetType и по нему определяют сколько байт нужно отправить/принять(а также обработать при пересчёте CRC).
И всё было-бы хорошо, если бы не тот факт, что из-за пустышек, применяемых для выравнивания, сумма sizeof всех полей получается меньше sizeof всей структуры.
Как я уже говорил, настройки могут меняться и нужно это дело как-то обработать универсальным способом.
На данный момент я сделал так:
Код
*/
*    Ниже, я постарался обработать эту ситуацию с помощью препроцессора и арифметики с указателями.
*    Суть в том, что вместо sizeof я применял разность адресов .data и .header
*    оператор взятия адреса(&) позволит нам уловить момент вставки компилятором пустышки
*    пример: <header size=1byte,address=0><пустышка size=1byte,address=1><data size=2,address=2>
*    если просто взять sizeof(header) + sizeof(data) байт и отправить - то мы отправим header полностью
*    пустышку полностью, а поле data будет передано не полностью(на sizeof(пустышка) байт меньше)
*    Но если я вместо sizeof(header) использую (&data -  &header) то пустышка будет учтена.
*/
enum {  HeaderPacketSize = sizeof(((ba05_net_packet *)0)->header) }; //header сам по себе никуда не выравнивается
//а дальше пришлось мудрить
#define BlockPacketSize ( ((int)&((ba05_net_packet *)0)->data.asBlockPacket - (int)&((ba05_net_packet *)0)->header) + sizeof(((ba05_net_packet *)0)->data.asBlockPacket) )
#define IDPacketSize ( ((int)&((ba05_net_packet *)0)->data.asIDPacket - (int)&((ba05_net_packet *)0)->header) + sizeof(((ba05_net_packet *)0)->data.asIDPacket) )

//теперь нам нужно правильно определить размер в байтах
#ifdef SIZEOF_IS_IN_WORDS
    enum {  HeaderPacketSize_bytes = HeaderPacketSize * 2    };
    #define BlockPacketSize_bytes ( BlockPacketSize * 2 )
    #define    IDPacketSize_bytes ( IDPacketSize * 2 )
#elif defined(SIZEOF_IS_IN_BYTES)
    enum {  HeaderPacketSize_bytes = HeaderPacketSize        };
    #define BlockPacketSize_bytes ( BlockPacketSize )
    #define    IDPacketSize_bytes ( IDPacketSize )
#endif

Работает. Но как-то мудрёно получается....
Прокомментируйте решение, пожалуйста. Что можно поменять? Как сделать проще/лучше?

P.S. SIZEOF_IS_IN_WORDS/SIZEOF_IS_IN_BYTES тут присутствуют для обеспечения портируемости. Дело в том, что мой компилятор возвращает sizeof в словах(по 2 байта). Побайтового доступа к памяти нет.
Однако, при работе с сетью нам нужны байты. На других архитектурах, где sizeof() ведет себя прилично - этой проблемы не будет. Поэтому я обрабатываю эту ситуацию отдельно.
А функции отправки/приёма просто могут использовать *_bytes и не беспокоиться не о чём smile.gif
zltigo
Цитата(sigmaN @ Oct 26 2009, 15:59) *
Прагмы, заставляющей компилятор запаковать структуру - нет.

Поскольку данное утверждение практически не вероятно, то дальше читать не стал sad.gif
sigmaN
аа. Т.е. как это? Это стандартная фича?
а у меня в описании компилятора виднеется
Цитата
6.9 Pragma Directives
Pragma directives tell the compiler how to treat a certain function, object, or section of code.
The C28x C/C++ compiler supports the following pragmas:
· CODE_ALIGN
· CODE_SECTION
· DATA_ALIGN
· DATA_SECTION
· FAST_FUNC_CALL
· FUNC_EXT_CALLED
· INTERRUPT
· MUST_INTERATE
· UNROLL
Поэтому я как-бы и растерялся маленько smile.gif
zltigo
Цитата(sigmaN @ Oct 26 2009, 16:49) *
аа. Т.е. как это? Это стандартная фича?

Это фича без которой на не восьмибитовых контроллерах не жизнь. Что за компилятор для C28x ? Этот TMS320 вообще теоретически способен работать с невыровненными данными?
sigmaN
Цитата
Что за компилятор для C28x ?
CCS code gen tools 5.2.2 проц TMS320F28335
Цитата
Этот TMS320 вообще теоретически способен работать с невыровненными данными?
похоже, что нет. Где-то помню чётко было прописано, что LSW должен располагаться по чётному адресу, а MSW по нечётному(или наоборот...нет, кажется правильно) Тогда понятно, почему паковать структуру не дают.

sad.gif sad.gif sad.gif

added:
Цитата
All 32-bit reads and writes to memory are aligned at the memory interface to
an even address boundary with the least significant word of the 32-bit data
aligned to the even address.


Для пробы добавил #pragma pack(1) - даёт warning неизвестная прагма sad.gif
zltigo
Цитата(sigmaN @ Oct 26 2009, 17:04) *
Тогда понятно, почему паковать структуру не дают.

Ну тогда я в заголовок добавлю TMS320
sigmaN
Цитата
Ну тогда я в заголовок добавлю TMS320

Тогда, наверное, правильнее будет C2000. Потому как на TMS320 начинается достаточно много процессоров. В том числе и таких, на которых этой проблемы нет.
rezident
Я извиняюсь, а · DATA_ALIGN это случайно не аналог pragma pack?
sigmaN
думаю, что не совсем
Цитата
The DATA_ALIGN pragma aligns the symbol to an alignment boundary.
The alignment boundary is the maximum of the symbol's default alignment value or the value of the constant in bytes.
The constant must be a power of 2.
The syntax of the pragma in C is:
#pragma DATA_ALIGN ( symbol , constant );
rezident
Цитата(sigmaN @ Oct 26 2009, 23:06) *
думаю, что не совсем
Ну дык все верно. В CCS для TMS320C2000 char же 16-и битный. laughing.gif
sigmaN
Но есть интринсик __byte() который позволяет быстро "пройтись" по байтам структуры без всяких сдвигов и масок. Если бы она была char к char'у(хоть и по 16бит) без пропусков.

А DATA_ALIGN разместит только начало структуры с выравниванием, указанным в DATA_ALIGN. На члены структуры это повлияет, но не всегда гарантировано, то не будет пропусков. Т.е. не на 100% так, как это сделала бы #pragma pack()
По-моему придётся сделать что-то вроде struct_to_packet(), которая по одному будет считывать поля структуры и ложить их в пакет(буфер) байт за байтом без пробелов.
sigmaN
А может кто-то подскажет оригинальную идею?
Ведь не один же этот проц такой. Люди же как-то эту проблему решают....

Я конечно выкрутился, но что-то берут меня сомнения насчёт красоты решения smile.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.