Struct problems / mixed up output

Dear all,

I have a problem with struct on my Arduino Zero.
I try to implement a binary based protocol with struct, which works out great:

struct __attribute__ ((packed)) prHdr
{
    unsigned int pkt_ver:3;     /* Bit 0 - 2  */
    unsigned int type:1;        /* Bit 3 */
    unsigned int secHdrFlag:1;  /* Bit 4 */
    unsigned int APID:11;       /* Bit 5 - 15 */
    unsigned int seqFlag:2;     /* Bit 16 - 17  */
    unsigned int seqCount:14;   /* Bit 18 - 31 */
    unsigned int data_len:16;   /* Bit 32 - 47  */
};

struct __attribute__ ((packed)) packet
{
    prHdr pHdr;
    uint8_t data[2];
};
 
void pkt_assembly (packet * spkt)
{
    spkt -> pHdr.pkt_ver = 0;
    spkt -> pHdr.type = 0;
    spkt -> pHdr.secHdrFlag = 1;
    spkt -> pHdr.APID = 0x42;
    spkt -> pHdr.seqFlag = 3;
    spkt -> pHdr.seqCount = 1;
    spkt -> pHdr.data_len = 7;
    spkt -> data[0] = 0xFF;
    spkt -> data[1] = 0xFF;
}

void setup() {
  SerialUSB.begin(9600);
}
void loop() {
  packet tm;
  pkt_assembly(& tm);
  SerialUSB.write((uint8_t*)&tm, sizeof(tm));
  delay(1000);
}

However, as soon as I output it via serial, it gets all mixed up.
I would think to get

0x08 0x42 0xC0 0x01 0x00 0x07 0xFF 0xFF as output,
however I get
0x50 0x08 0x07 0x00 0x07 0x00 0xFF 0xFF

It is somehow mixing stuff up and I don't know why.
Any help?

Thank you :slight_smile:

NMaas:
0x08 0x42 0xC0 0x01 0x00 0x07 0xFF 0xFF as output,
however I get
0x50 0x08 0x07 0x00 0x07 0x00 0xFF 0xFF

It is somehow mixing stuff up and I don't know why.
Any help?

Thank you :slight_smile:

You constructed your expected output with incorrect assumptions. For example, bits 0-2 are actually the least significant bits, not the most significant bits of the integer and you have 3 unsigned integers in this structure. Hence, you are populating the bits of each integer beginning with the least significant bits.

Therefore the expected output would be:

0x08 0x50 0x00 0x07 0x00 0x07 0xFF 0xFF

However, this Arduino is little endian so in memory the bytes of each integer are swapped giving:

0x50 0x08 0x07 0x00 0x07 0x00 0xFF 0xFF

which, indeed, matches what you are seeing

Hi ToddL, thank you very much for your insightful answer!
I try to implement parts of the CCSDS TM/TC protocol for Arduino ( https://public.ccsds.org/Pubs/133x0b1c2.pdf Page 31 / 4-2) - actually the primary header and added some data to it. My expected value is a known good packet, as it would be used by the processing software - hence I try to transform my generated packet (with the same values as the known good packet) in such a way, that it should match the known good.

If I rearrange my packet like this:

struct __attribute__ ((packed)) prHdr
{
    unsigned int data_len:16;   /* Bit 32 - 47  */
     unsigned int seqCount:14;   /* Bit 18 - 31 */   
    unsigned int seqFlag:2;     /* Bit 16 - 17  */
    unsigned int APID:11;       /* Bit 5 - 15 */
    unsigned int secHdrFlag:1;  /* Bit 4 */
    unsigned int type:1;        /* Bit 3 */
    unsigned int pkt_ver:3;     /* Bit 0 - 2  */
};

struct __attribute__ ((packed)) packet
{
    uint8_t data[2];
    prHdr pHdr;
};
 
void pkt_assembly (packet * spkt)
{
    spkt -> pHdr.pkt_ver = 0;
    spkt -> pHdr.type = 0;
    spkt -> pHdr.secHdrFlag = 1;
    spkt -> pHdr.APID = 0x42;
    spkt -> pHdr.seqFlag = 3;
    spkt -> pHdr.seqCount = 1;
    spkt -> pHdr.data_len = 7;
    spkt -> data[0] = 0xFF;
    spkt -> data[1] = 0xFF;
}

void setup() {
  SerialUSB.begin(9600);
}
void loop() {
  packet tm;
  pkt_assembly(& tm);
  SerialUSB.write((uint8_t*)&tm, sizeof(tm));
  delay(1000);
}

I actually get to the point that I get

0xFF 0xFF 0x07 0x00 0x01 0xC0 0x42 0x08

instead of the known good

0x08 0x42 0xC0 0x01 0x00 0x07 0xFF 0xFF

I thought I could just take the start position of the pointer of the tm packet, add the size of it and then start from this point reading backwards to reverse the output

unsigned int writePacket (const packet & value)
  {
    byte * y = (byte*) &value;
    *y = *y + sizeof(value);
    unsigned int i;
    for (i = sizeof value; i > 0; i--)
          SerialUSB.write(*y--);
    return i;
  }

However, this ended in the output of

0x17 0x00 0x00 0x21 0x67 0x20 0x00 0x00

So I am probably still doing something wrong. Any ideas - and thanks a lot!

NMaas:
Hi ToddL, thank you very much for your insightful answer!
I try to implement parts of the CCSDS TM/TC protocol for Arduino ( https://public.ccsds.org/Pubs/133x0b1c2.pdf Page 31 / 4-2) - actually the primary header and added some data to it. My expected value is a known good packet, as it would be used by the processing software - hence I try to transform my generated packet (with the same values as the known good packet) in such a way, that it should match the known good.

So I am probably still doing something wrong. Any ideas - and thanks a lot!

You new prHdr structure looks correct now so all you really need to do is byte swap the header so it is in big endian order. You do not need to mess with the data bytes as long as you are populating the data one byte at a time.

Here is a new pkt_assembly function that does a quick and dirty conversion using the htons (host to network short) function which converts to big endian. You will need to include util.h to use that function.

void pkt_assembly (packet * spkt)
{
    spkt -> pHdr.pkt_ver = 0;
    spkt -> pHdr.type = 0;
    spkt -> pHdr.secHdrFlag = 1;
    spkt -> pHdr.APID = 0x42;
    spkt -> pHdr.seqFlag = 3;
    spkt -> pHdr.seqCount = 1;
    spkt -> pHdr.data_len = 7;
    spkt -> data[0] = 0xFF;
    spkt -> data[1] = 0xFF;

    // Make sure header is big endian
    unsigned int* pHdr_temp = (unsigned int*) &(spkt->pHdr);
    *pHdr_temp = htons(*pHdr_temp++);
    *pHdr_temp = htons(*pHdr_temp++);
    *pHdr_temp = htons(*pHdr_temp);
}

I could not test this code but it compiles. Good luck!

Thanks!
I could not really include the util.h, so I added the relevant contents manually.

#ifndef htons
#define htons(x) ( ((x)<< 8 & 0xFF00) | \
                   ((x)>> 8 & 0x00FF) )
#endif

#ifndef ntohs
#define ntohs(x) htons(x)
#endif

#ifndef htonl
#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
                   ((x)<< 8 & 0x00FF0000UL) | \
                   ((x)>> 8 & 0x0000FF00UL) | \
                   ((x)>>24 & 0x000000FFUL) )
#endif

#ifndef ntohl
#define ntohl(x) htonl(x)
#endif



struct __attribute__ ((packed)) prHdr
{
  unsigned int data_len: 16;  /* Bit 32 - 47  */
  unsigned int seqCount: 14;  /* Bit 18 - 31 */
  unsigned int seqFlag: 2;    /* Bit 16 - 17  */
  unsigned int APID: 11;      /* Bit 5 - 15 */
  unsigned int secHdrFlag: 1; /* Bit 4 */
  unsigned int type: 1;       /* Bit 3 */
  unsigned int pkt_ver: 3;    /* Bit 0 - 2  */
};

struct __attribute__ ((packed)) packet
{
  uint8_t data[2];
  prHdr pHdr;
};

void pkt_assembly (packet * spkt)
{
  spkt -> pHdr.pkt_ver = 0;
  spkt -> pHdr.type = 0;
  spkt -> pHdr.secHdrFlag = 1;
  spkt -> pHdr.APID = 0x42;
  spkt -> pHdr.seqFlag = 3;
  spkt -> pHdr.seqCount = 1;
  spkt -> pHdr.data_len = 7;
  spkt -> data[0] = 0xFF;
  spkt -> data[1] = 0xFF;

  // Make sure header is big endian
  unsigned int* pHdr_temp = (unsigned int*) & (spkt->pHdr);
  *pHdr_temp = htons(*pHdr_temp++);
  *pHdr_temp = htons(*pHdr_temp++);
  *pHdr_temp = htons(*pHdr_temp);
}

void setup() {
  SerialUSB.begin(9600);
  delay(1000);
}
void loop() {
  packet tm;
  pkt_assembly(& tm);
  SerialUSB.write((uint8_t*)&tm, sizeof(tm));
  delay(5000);
}

The code does compile, however, gives out quite a few warnings:
error: operation on 'pHdr_temp' may be undefined [-Werror=sequence-point]

Also, it seems like something is going wrong. I can upload the code to the Arduino Zero, however, it is not recognized as USB device again. Seems like it crashes hard somehow. I need to be quick and double press the reset button to get it back into bootloader mode to upload new code.