2

I have these structs

typedef struct DeviceState_s {
    uint32_t Function_Type;
    uint8_t Left_Trigger;//byte [1]#9 left analog trigger
    uint8_t Right_Trigger;//byte [2]#10 right analog trigger
    uint8_t Buttons_1;//byte [3]#11 1----XY(1/Z) ..X and Y are the bits representing the buttons state (1 for unpress 0 for press) the last bit is z if the controller supports it.
    uint8_t Buttons_2;//byte [4]#12 PR PL PD PU start A B (1/C)  PR=pad right same for the rest and the bit marked as one is c if the controller supports it.
    uint8_t Analog_a1;//byte [5]#13 useless in original controller
    uint8_t Analog_a2;//byte [6]#14 useless in original controller
    uint8_t Analog_Y;//byte [7]#15 joystick Y axis movement
    uint8_t Analog_X;//byte [8]#16 joystick X axis movement

} DeviceState;

typedef struct DeviceStatus_s {
    uint32_t Function; 
    uint32_t DeviceID[3]; 
    uint8_t AreaCode; //1
    uint8_t ConnectorDirection; //1
    char ProductName[30];
    char ProductLicense[60];
    uint16_t StandbyPower; //2
    uint16_t MaxPower;  //2
} DeviceStatus;


typedef struct Status_FPacket_s {
    PacketHeader Header; //4
    DeviceStatus Status //112
} Status_FPacket;
static Status_FPacket Status_Packet; 

then I pulsate them later on. But There is no need to populate the Status each time, it's always the same. I thought maybe one was like so.

typedef struct Status_FPacket_s {
    PacketHeader Header; //4
    DeviceStatus Status //112
    = {
        .Function = FUNC_CONTROLLER,
        .DeviceID[0] = 0xffff06fe,
        .DeviceID[1] = 0x0000ffff,
        .DeviceID[2] = 0x00000000,
        .AreaCode = 0xff,
        .ConnectorDirection = 0,
        .ProductName =0,
        .ProductLicense  =0,
        .StandbyPower =  (430>>8) | (430<<8),
        .MaxPower =  (500>>8) | (500<<8),
    };

} Status_FPacket;

but that didn't work. Maybe I need to use my own type?

///////////adding AbeMonk's suggestion////////

typedef struct DeviceStatus_s {
    uint32_t Function; 
    uint32_t DeviceID[3]; 
    uint8_t AreaCode; //1
    uint8_t ConnectorDirection; //1
    char ProductName[30];
    char ProductLicense[60];
    uint16_t StandbyPower; //2
    uint16_t MaxPower;  //2
} DeviceStatus;

static DeviceStatus  controllerStatus =
{
    .Function=FUNC_CONTROLLER,
    .DeviceID[0]= 0xffff06fe,
    .DeviceID[1]= 0x0000ffff,
    .DeviceID[2] = 0x00000000,
    .AreaCode = 0xff,
    .ConnectorDirection = 0,
    .ProductName = "....";
    .ProductLicense "....";
    .StandbyPower =  (430>>8) | (430<<8),
    .MaxPower =  (500>>8) | (500<<8),
};

then just do this later

Status_Packet.Status = controllerStatus;

the things I use to set my strings are

strncpy(Status_Packet.Status.ProductName, "text here", sizeof(Status_Packet.Status.ProductName));

not sure how to do this without strncpy.

user2144480
  • 1,083
  • 7
  • 11
  • 2
    `typedefs` cannot contain initializers. You can only initialize variables. So you'd need to declare a variable with that type, at which point you could initialize the desired structure fields. – Tom Karzes Jul 09 '23 at 22:23
  • When you say you want to "make static data in structs", do you mean static as in object-oriented programming, where the value of a variable is the same across instances? If so, then I believe higher-level OOP features like that aren't available in C. Also, as mentioned by **Tom Karzes**, you cannot initialize variables inside of struct definitions. – AbeMonk Jul 09 '23 at 23:07
  • 1
    Depending on what you need, it might be best to declare a `const` "default" or "template" copy of that struct, with the initial values you want, then assign/copy that to any new ones you declare so they have the initial values you want. – John Bayko Jul 09 '23 at 23:42
  • @user2144480, Why the `typedef struct DeviceState_s ... DeviceState;` code? It is not used in the question. – chux - Reinstate Monica Jul 09 '23 at 23:43
  • @user2144480 What do comments `//4` and `//112` imply? – chux - Reinstate Monica Jul 09 '23 at 23:45
  • I suppose "then I pulsate them later on." should be "then I populate them later on." – chux - Reinstate Monica Jul 09 '23 at 23:46
  • Is `DeviceState` supposed to be `DeviceStatus`? – Barmar Jul 10 '23 at 00:18
  • John Bayko That sounds like what I'm looking to do. This data needs to be constant as it will not change. – user2144480 Jul 10 '23 at 01:35
  • looks like this gives many ways to do what I want. https://stackoverflow.com/questions/13716913/default-value-for-struct-member-in-c but it looks like they all initialize the data, I was hoping for a way to stick it in memory and save on space. Maybe more like PROGMEM. This is firmware and space is a commodity. maybe ChrisZZ's post in that solution would work. – user2144480 Jul 10 '23 at 01:55
  • I guess another way to explain this is, I want to do the header data on the fly. Status_Packet.Header.[propery] = x;... but for status I want to have this data in memory and just do Status_Packet.Status = my_data. but I'm not clear on how to store the const data template. – user2144480 Jul 10 '23 at 02:12
  • 1
    If I understand correctly, you want to create a struct implementation that has a default value which is only stored in memory once across all instances? If this is what you mean, you could 1) Store a global variable that has the default value 2) Have the struct implementation store a **pointer** to the data type of the global variable 3) Create a function that you will call every time you initialize the struct; this function will populate the struct's pointer with the **address** of that global variable, such that it will only be stored in memory *once*. – AbeMonk Jul 10 '23 at 02:42
  • () maybe but I like the sound of (2), (3) Would defeat the purpose as that would add to program space. With the second suggestion. What can I " google" for to see how it is done? Storing the data is so complicated with all the endianess. – user2144480 Jul 10 '23 at 20:14
  • ok added a suggestion up above, few areas of confusion but is this the idea? – user2144480 Jul 10 '23 at 20:29
  • nm, I see I can initialize using a string. takes 50 mS to run the copy so it is not a copy from memory but a copy from ram, but I think I can figure this out on my own, thx for the help. – user2144480 Jul 10 '23 at 21:06
  • I'll add an answer so I can give more detail just to clear up any confusion. I'm having a hard time understanding exactly what you want, but I'll do my best according to what I do understand. – AbeMonk Jul 10 '23 at 22:32

1 Answers1

1

C is not an object oriented language. While structs in C can be used to group data, their functionality doesn't extend much beyond that - in other words, they don't provide nearly the level of functionality and abstraction that C++ classes, for instance, provide. However, this doesn't make it impossible to achieve - or at least get close to - a theoretical "static" struct member in C. Using pointers and global variables, it is possible to achieve something of the like:

First, you need to initialize a global variable:

DeviceStatus global_status
= {
    .Function = FUNC_CONTROLLER,
    .DeviceID[0] = 0xffff06fe,
    .DeviceID[1] = 0x0000ffff,
    .DeviceID[2] = 0x00000000,
    .AreaCode = 0xff,
    .ConnectorDirection = 0,
    .ProductName =0,
    .ProductLicense  =0,
    .StandbyPower =  (430>>8) | (430<<8),
    .MaxPower =  (500>>8) | (500<<8),
};

Then, in the struct implementation that will contain this "static" member, you would declare a pointer. This means that the global variable will not need to be copied across instances, and will change for all instances if modified by one:

typedef struct Status_FPacket_s {
   PacketHeader Header;
   DeviceStatus* Status; 
} Status_FPacket;

Of course, storing the address in the pointer will take up space (though significantly less than a copy by value). However, I cannot think of a way to avoid this (at least without the more obvious solution which is just to use the global variable directly in all situations where it is needed; however, I assume you would have already done this if it were adequate).

Now, all you need do is create a "constructor" (seeing as we're trying to emulate classes, in a sense) that will be called every time you initialize a Status_FPacket object:

Status_FPacket create_Status_FPacket() {
    Status_FPacket obj;
    obj.Status = &global_status;
    return obj;
}

Then when you want to initialize a Status_FPacket object:

Status_FPacket status_packet = create_Status_FPacket();

A slight possible modification

I'm aware that global variables are considered bad practice. There is one way around this, though there may be repurcussions I'm not aware of (I have tried it though, and it seems to work). You could create a static variable inside the "constructor" function like so:

Status_FPacket create_Status_FPacket() {
    static DeviceStatus global_status
    = {
       .Function = FUNC_CONTROLLER,
       .DeviceID[0] = 0xffff06fe,
       .DeviceID[1] = 0x0000ffff,
       .DeviceID[2] = 0x00000000,
       .AreaCode = 0xff,
       .ConnectorDirection = 0,
       .ProductName =0,
       .ProductLicense  =0,
       .StandbyPower =  (430>>8) | (430<<8),
       .MaxPower =  (500>>8) | (500<<8),
    };

    Status_FPacket obj;
    obj.Status = &global_status;
    return obj;
}

Static function variables in C are special - they retain their place in memory across all function calls and endure for the entire lifetime of the application. This means the static global_status variable will actually be the same instance every time the "constructor" is called.

Avoiding strcpy

As for your use of strcpy, this unnecessary overhead can be completely avoided. I assume you won't be internally modifying the values of productName and productLiscense once they are assigned one. In this case, you can declare them as constant char pointers instead of arrays, like so:

typedef struct DeviceStatus_s {
   uint32_t Function; 
   uint32_t DeviceID[3]; 
   uint8_t AreaCode; 
   uint8_t ConnectorDirection; 
   const char* ProductName;
   const char* ProductLicense;
   uint16_t StandbyPower; 
   uint16_t MaxPower; 
} DeviceStatus;

You will now be able to directly assign string literals to them using = since they are constant.

AbeMonk
  • 110
  • 7