Click here to Skip to main content
15,887,175 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello fellow CPians,

as part of an attempt to pass messages back and forth between two µCs, I created Message_t. To send such a message, user has to tell the sending function, how many bytes to transfer.

I'd like to have a notation for Message_t that has a message type declared in one place only and is easily telling user its size in calling code.

What I have tried:

Different declarations of GeneralMessage_t and ThermocontactMessage_t here:
C
typedef struct ThermocontactMessage_t
{
    uint32_t count;
    uint8_t value:1;
}ThermocontactMessage_t;    // Pro: Reachable by sizeof in calling code
                            // Con: Maintain here _and_ within union


typedef struct Message_t
{
    MessageHeader_t hdr;
    union
    {
        struct
        {
            void* data;
        }GeneralMessage_t;  // Pro: One place to maintain.
                            // Con: No size info in calling code.

        struct
        {
            uint64_t value;
        }TestMessage;

        ThermocontactMessage_t ThermocontactMessage;
    }content;
}Message_t;

/* Usage */
void SomeFunction(bool thermocontactState)
{
    Message_t msg = {
        .content.ThermocontactMessage.value = thermocontactState,
        .content.ThermocontactMessage.count = ++messageCount,
        .hdr.id = MessageType_Thermocontact,
        .hdr.length = sizeof(ThermocontactMessage_t)
    };
}
GeneralMessage_t is great because it needs to be declared only in one place. ThermocontactMessage_t, on the other hand, is accessible for the sizeof operator in SomeFunction().
Posted
Updated 8-Apr-16 4:30am

1 solution

I am not sure that I understand your question correctly. The problem you are facing is that all your messages have a common header and then some type-specific part. And to send them you want both of these parts in a contiguous buffer. I guess you have two options here:

(1) Include the header in every message type, i.e.
C++
typedef struct ThermocontactMessage_t
{
    MessageHeader_t hdr;
    uint32_t count;
    uint8_t value:1;
}ThermocontactMessage_t; 


(2) Just leave your type-specific structures as they are and construct a buffer with header + message in your transmit function:
C++
typedef struct Message_t
{
    MessageHeader_t hdr;
    BYTE data[MAX_CARGO_SIZE];
}Message_t;

void SomeFunction(bool thermocontactState)
{
    Message_t msg;
    ThermocontactMessage_t* pData = (ThermocontactMessage_t*) msg.data;

    // fill the header 
    msg.hdr.id = MessageType_Thermocontact,
    msg.hdr.length = sizeof(ThermocontactMessage_t)

    // fill the cargo part
    pData->value = thermocontactState;
    pData->count = ++messageCount;
    ...
}


With many message types you are going to end-up with a lot of repetitive code, which can be mitigated by use of a macro that fills the header and casts a pointer to the data part. Then this function would look like:
C++
void SomeFunction(bool thermocontactState)
{
    Message_t msg;
    ThermocontactMessage_t* pData = FILLHEADER (Thermocontact);
    pData->value = thermocontactState;
    pData->count = ++messageCount;
    ...
}


That looks a lot nicer, avoids copy-paste errors and keeps your code clean. The macro is smart enough to derive from its argument Thermocontact that the message type-id is MessageType_Thermocontact by prepending MessageType_ and that the message structure is ThermocontactMessage_t by appending Message_t. Thus with a bit of macro-magic you can accomplish quite a bit. Of course, all of this would not be necessary if you could use C++ instead of C.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900