This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Structure Pointer is not pointing correctly to raw byte array.


Hi,

Below are the structures in my code.

struct uip_eth_hdr {
struct uip_eth_addr dest;
struct uip_eth_addr src;
Uint16 type;
};

struct ethip_hdr {
struct uip_eth_hdr ethhdr;
unsigned char vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
Uint16 ipchksum;
Uint16 srcipaddr[2],
destipaddr[2];
};

unsigned char uip_buf[1500];
#define IPBUF ((struct ethip_hdr *)&uip_buf[0])

Raw data packet of uip_buf :
FF FF FF FF FF FF B0 83 FE 6B BA E3 08 06 00 01
08 00 06 04 00 01 B0 83 FE 6B BA E3 C0 A8 00 28
00 00 00 00 00 00 C0 A8 00 14 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 AF D4 22 91

Mapped values of IPBUF :
ETH Dst add : FF FF FF FF FF FF
ETH Src add : B0 83 FE 6B BA E3
Eth type : 8 Problem
vh1 : 06
tos : 00
len : 01 08
ipid : 00 06
ipoffset : 04 00
ttl : 01
proto : B0
checksum : 131 Problem
srcip : 254 107 Problem
dstip : 186 227 Problem

From above code you can see value mapped is wrong from "Eth type".

PUBF->type should reserve 2 byte from raw array but it reserve only 1 byte, hence next all values parse wrongly.

Can anyone suggest me what is going on with code? Actually i had read a lot forum about size of data types(E.g. :- sizeof(Uint16) return value 1) But didn't find any perfect solution.

Thanks in advance.

  • On the C2000 char and Uint16 are both 16-bit types, so char vh1 is going to be 16 bits (sizeof 1) and len[2] is going to give you 32 bits (sizeof 2).

    Have you read what the compiler user guide has to say on the subject? It might help clear up some confusion. Chapter 6.4 covers data types and has a note that explains why sizeof behaves the way it does.

    Compiler Users's Guide: http://www.ti.com/general/docs/lit/getliterature.tsp?baseLiteratureNumber=spru514&fileType=pdf

    You can use bit fields to get the items in the struct to be truly 8-bits. Maybe something like this:

    struct ethip_hdr {
        struct uip_eth_hdr ethhdr;
        Uint16 vhl:8,
        tos:8,
        len,
        ipid,
        ipoffset,
        ttl:8,
        proto:8;
        Uint16 ipchksum;
        Uint16 srcipaddr[2],
        destipaddr;
    };

    Whitney

  • Thanks for pointing me at specific chapter but it didn't match to my exact requirement.

    In 1st request, Look at "Eth type : 8 Problem".
    How can i store two byte value in this variable from raw data? It should be "Eth type : 0x0806".

    Right now i am using this workaround.

    struct uip_eth_hdr {
    struct uip_eth_addr dest;
    struct uip_eth_addr src;
    Uint16 typeH:8, typeL:8, typeH1:8, typeL1:8;
    };

    type = BUF->typeH << 8 | BUF->typeH1; // type = 0x0806

    But this problem is occurring in full stack and for this workaround i need to change my whole code according to this and that is not the best the idea. So if you have any idea about this then let me know.

    Thanks,
    Kalpesh.
  • Kalpesh,

    Can you show me what the buffer looks like in the memory browser? It sounds like it contains 0x0008 0x0006 instead of 0x0806. I would think that that is a problem with how the buffer is being filled, and not a problem with the uip_eth_hdr struct itself.

    Hopefully once I understand the issue a bit better we can come up with a solution that won't require major changes across the whole stack.

    Thanks,
    Whitney
  • Hi Whitney,

    See attachment for memory information of "uip_buf" in detail.

    From memory looks like, Address 0x0000C08C and 0x0000C08D are in sequence without any extra field with data 0x00.

    Thanks,

    Kalpesh.

  • Kalpesh,

    That's what I was expecting it to look like. You have to remember that chars are 16 bits on the C2000, so what you have here is:

    00FF 00FF 00FF 00FF 00FF 00FF 00B0 0083 00FE 006B 00BA 00E3 0008 0006

    But the structure we've created is expecting:

    FFFF FFFF FFFF B083 FE6B BAE3 0806

    When you're filling the uip_buf, you could pack it as shown above by shifting every other byte received into the upper 8 bits of the char. Or you could take advantage of the __byte() intrinsic that's described in the compiler user guide. The consequence of this is that you'll have to make modifications to the stack almost anywhere pointer arithmetic or indexing into this buffer is being performed since in this scenario, two bytes have the same address.

    Unfortunately, given that the architecture can't do 8-bit byte addressability, I don't think there's going to be a good way to get around having to make these changes to the stack.

    Whitney

  • Whitney,

    Great explanation, Thanks.

    Let me clarify bit more,

    Whitney Dewey said:
    shifting every other byte received into the upper 8 bits of the char

    That is good idea but for stack it is bad idea. Because when i try to access any field of "unsigned char" then it will not return what i expect.

    E.g. :- If i fill major byte by every 2nd element of uip_buf, it will looks like : FFFF FFFF FFFF B083 FE6B BAE3 0806

    When i try to access 1st six byte mac address then it will consume 12 byte of my payload.

    CONCLUSION : By this method i can access 2 byte value perfectly but it will create problem with 1 byte value.

     

     

    Whitney Dewey said:
    Or you could take advantage of the __byte() intrinsic that's described in the compiler user guide.

    Since two byte has the same address. That is the real problem.

    So my concern is,

    Can't we do something special which can resolve problem of "two byte has same address" at top level and it will behave as normal standard controller for whole other code?

    And one more doubt, Is there any special reason behind this logic(two byte has same address)?

    Thanks,

    Kalpesh.

  • Kalpesh,

    I'm imagining there are two possible routes here:
    1. You leave your array of characters the way you had it originally where each byte gets put into its own 16-bit word with its own.
    2. You pack the data by shifting every other word into the upper 8 bits of each the 16-bit character.

    With #1, you'll be able to use character array indexing and pointer arithmetic as expected since each byte will have its own address. However since the bytes are placed in 16-bit memory spaces there are 8 bits of zeroes between every byte which will cause you to pad your structures and shift and OR bytes around when you want to access two consecutive bytes as a single 16-bit value (i.e. what you showed above when you broke type into typeH:8, typeL:8, typeH1:8, typeL1:8).

    With #2, it's easier to use bit-fields to create structs that more accurately describe the format of the data and it is easier to access consecutive bytes as a single 16-bit or 32-bit value since you don't have to shift and OR bytes to get rid of the extra zeroes. However, since there are two bytes per address, you can't use pointer arithmetic or array indexing to move through the data byte-by-byte. You can use __byte()--for example, __byte(array_addr, i) would where you're incrementing i would take you through an array with address array_addr byte-by-byte without any shifting.

    I still think #2 is the easier solution, but you'll need to examine your stack code and decide.

    Unfortunately, there isn't a nice top-level solution at this time that will help you work around this shortcoming in the architecture. We do have an F28M35x/F28M36x dual core device that has an M3 with an EMAC peripheral that could handle a stack that required byte addressability, but running it on a C28 core of the F28335x is going to require code changes.

    Whitney
  • Hi Whitney,

    Whitney Dewey said:
    With #1,

    Yes exactly, Right now i had change code almost at every place where data type is Uint16 in structure.

    And after broke type it look like,

            typeH = 0x08, typeL = 0x00, typeH1 = 0x06; typeL1 = 0x00

    And then i am integrate them with,

    type = BUF->typeH << 8 | BUF->typeH1; // type = 0x0806

    Whitney Dewey said:
    With #2

    You are telling to fill array's every most byte with next consecutive byte.

    No doubt i don't need to use extra Shift and OR of bytes. But the problem is We can't use address of bit field(Compiler is not allowed and that is obvious) so we need to use __byte and again for this i need to change code where i had user pointer to point data(Almost everywhere!).

    And again thanks for this everything.

    Thanks,

    Kalpesh