Electronic – Problem managing streamed data with struct pointers, some of the streamed data seems to be stored, some not with an STM32F401VE

halstm32

I've recently been teached about how to manage streamed data in this case for managing commands, then my code is like the following explanation: I've programmed the uart2 to receive the streamed data byte to byte and I've been storing it in a buffer, every time arrives a byte then a flag is set and the function that analizes the streamed data takes the address of the reception buffer, inside the function that analizes the streamed data I declared several pointers to a struct to manage differente kind of commands.

All the commands has a code in the first byte and a termination suffix, the suffix is 0xff 0xf 0xff and the command code are the following:

NEX_RET_CMD_FINISHED (0x01)
NEX_RET_SLEEP_CURRENT (0x86) (134)
NEX_RET_AWAKE_CURRENT (0x87) (135)
NEX_RET_EVENT_TOUCH_HEAD (0x65) (101)
NEX_RET_CURRENT_PAGE_ID_HEAD (0x66) 102)
NEX_RET_EVENT_POSITION_HEAD (0x67) (103)
NEX_RET_EVENT_SLEEP_POSITION_HEAD (0x68) (104)

the code in the stream analizer is the following

uint8_t analize_string(uint32_t * incomming)
{
typedef uint8_t cCode;

typedef struct
{
    cCode prefix;
    uint32_t suffix : 24;
} recvMessage;

typedef struct
{
    cCode prefix;
    uint8_t page;
} head;

typedef struct
{
    head header;
    uint32_t suffix;
} pageEvent;

typedef struct
{
    head header;
    uint8_t ident;
    uint8_t event;
    uint32_t suffix : 24;
} eventID;

typedef struct
{
    cCode prefix;
    uint8_t page;
    uint8_t ID;
    uint8_t event;
    uint32_t suffix : 24;
} eventBody;

typedef struct
{
    cCode prefix;
    uint16_t x;
    uint16_t y;
    uint8_t event;
} touchC;

uint8_t analize_string(uint8_t * incomming)
{
    static uint8_t incCounter = 0;
    recvMessage *confirm;
    confirm = (recvMessage *) incomming;
    pageEvent *pEvent;
    pEvent = (pageEvent *) incomming;
    eventID * identif;
    identif = (eventID *) incomming;
    touchEvent *sleepingEvent;
    sleepingEvent = (touchEvent *) incomming;
//  data *message;
    if((confirm->prefix == NEX_RET_CMD_FINISHED)
            && (confirm->suffix == 0xffffff))
    {
        interface.aHMI = true;
    }
    if((confirm->prefix == NEX_RET_SLEEP_CURRENT)
            && (confirm->suffix == 0xffffff))
    {
        interface.aHMI = true;
        interface.pSleep = true;
    }
    if((confirm->prefix == NEX_RET_AWAKE_CURRENT)
            && (confirm->suffix == 0xffffff))
    {
        interface.aHMI = true;
        interface.pSleep = false;
    }
    if((identif->header.prefix == NEX_RET_EVENT_TOUCH_HEAD)
                && (identif->suffix == 0xffffff))
        {
            interface.aHMI = true;
        }
    if((sleepingEvent->prefix == NEX_RET_EVENT_POSITION_HEAD)
            && (sleepingEvent->suffix == 0xffffff))
    {
        interface.aHMI = true;
    }
    if((pEvent->header.prefix == NEX_RET_CURRENT_PAGE_ID_HEAD)
            && (pEvent->suffix == 0xffffff))
    {
        interface.aHMI = true;
        interface.page = pEvent->header.page;
    }
    if( if((sleepingEvent->prefix == NEX_RET_EVENT_POSITION_HEAD)
            && (sleepingEvent->suffix == 0xffffff))
    {
        interface.aHMI = true;
    }
    if((sleepingEvent->prefix == NEX_RET_EVENT_SLEEP_POSITION_HEAD)
            && sleepingEvent->suffix)
    {
        interface.aHMI = true;
    }
    HAL_UART_Transmit_IT(&dbSerial, (uint8_t *) &sleepingEvent[incCounter], 1);
    if(interface.aHMI)
    {
//////      screen_handler();
        interface.aHMI = false;
    }
    incCounter++;
    if(incCounter == Long_Rec)
    {
        incCounter = 0;
    }
    receive_data((char *) &U2rxBuffer[incCounter], (uint16_t) sizeof(uint8_t));
    return incCounter;
}
in main the call to the function is treated like follows



receive_data(U2rxBuffer, sizeof(uint8_t));/* Inicializa la recepción de 1
                                     * caracter.                             */
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
      if(received == true)
      {
          analize_string((uint8_t *) U2rxBuffer);
          received = false;
      }
  }
}

and the flag received is set in the RxCpltCallback for the uart2like follows

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    received = true;
}

the code of the main functions is the following

while (1)
{
    if(received == true)
    {
        analize_string((uint32_t *) &U2rxBuffer[0]);
        received = false;
    }
}

and some of the conditions to analize the stream works, some other doesn't works; by example, the conditions that compares with the macros NEX_RET_CMD_FINISHED and

NEX_RET_SLEEP_CURRENT works perfectly and those commands only has four bytes being the prefix and the suffix, the condition that works with the macro NEX_RET_EVENT_SLEEP_POSITION_HEAD also works well but the condition that works with the macro NEX_RET_EVENT_POSITION_HEAD doesn't works well thoug both commands has the same 9 bytes long, when I send to the other uart the content of the pointer sleepingEvent then it prints this

Printed

the text in the upper console s what I sent through the uart2 and the lower console is what I suposse is the content of the pointer to a struct sleepingEvent, now seeing that I can note that the content of the stream beyond the prefix is lost or not properly stored (I don't know which of that causes are) and I don't know how to solve it.

If I print directly the content of the pointer incomming then it prints what is in the lower console of the following image

enter image description here

what I see there is that the uart_transmit function is printing bad what is received.

NOTE: I think is more c related problem in the address assignation of the structres but I don't know.

So, can someone help my to solve the problem?

Thanks so much in advance for the help.

UPDATE: Adittional content to show why I did the definitions of the structures like that:

the code that defines the structures in the book that I mentioned to @brhans is

struct horse
{
    int age;
    int height;
    char name[20];
    char father[20];
    char mother[20];
} Dobbin = {
24, 17, "Dobbin", "Trigger", "Flossie"
};

and the explanatory figure is

structure memory arrangement

Surely I've interpreter something wrong.

Best Answer

You need to 'pack' your structs to ensure that their fields are placed as you expect them to be, particularly since you're working with 32-bit hardware.
How you do that depends on your compiler - it might be something like __packed or __attribute__((packed)).
Without this your compiler is aligning the fields inside your struct on boundaries which probably depend on their size.

Your pageEvent struct is a good example of this.
What you think you have is something like this:

{
  {
    1 byte: cCode prefix
    1 byte: uint8_t page
  } head
  4 bytes: uint32_t suffix
} pageEvent

but what you really have is something like this:

{
  {
    1 byte: cCode prefix
    1 byte: uint8_t page
  } head
>> 2 spare bytes for alignment <<
  4 bytes: uint32_t suffix
} pageEvent

because your compiler wants to align the uint32_t suffix on a 4-byte address, so it inserts 2 'invisible' bytes into your struct.
You'll have similar problems with your touchC struct.

Note that if your underlying hardware were an 8-bit or 16-bit device, the alignment requirement could possibly be less 'strict'. The compiler would probably be ok with placing 32-bit wide fields on 16-bit/2-byte addresses in a 16-bit device since these fields would be accessed as 2 separate memory reads by the hardware. Similarly on an 8-bit device there might be no packing needed, since every read would be an individual byte - even for 16- and 32-bit fields.

These alignment issues bit me when I started porting code from 8-bit PICs over to 16-bit dsPICs, and again (although to a lesser extent) when porting code over to 32-bit devices.
Something I've started doing recently when writing code which is intended to be portable across many different hardware platforms & compilers is to use a static_assert compiler directive to check the size of my structs at compile time.
For example for your pageEvent struct with a 24-bit suffix I would write:

static_assert(sizeof(pageEvent) == 5, "Error: pageEvent is wrong size!");

immediately after the struct typedef.
Depending on your compiler, the directive might be a little different, like Static_Assert or __static_assert or something similar.

Related Topic