简体   繁体   中英

Non Contiguous Data Structure

I'm working on a bit of code that pulls data from various sensors and stores that data on an SD card. All sensor values belong to at least one group (or "table"). For example, there is a "voltages" table with all of the voltages. Only entire tables can be received from the sensors and only entire tables can be saved to the SD card.

All sensor values are stored in one giant struct. The struct is contiguous but the members of a specific table are not necessarily contiguous. For example,

Value Name  |   Table Number
-----------------------------
Value 1     |   1
Value 2     |   1
Value 3     |     2
Value 4     |     2
Value 5     |   1
Value 6     |     2
Value 7     |   1

I'm using a real time kernal. I want to have one task that maintains the various tables and one task that saves things to the SD card. When a given table is requested, I want the "table task" to pass some kind of handle to the "SD card task".

So my question is: Is there a reasonably simple way to create a handle for a data structure that is non-contiguous?

Here is an example of the entire struct of sensor values (in reality there are about 600 values and 200 tables. Tables can overlap):

typedef struct __attribute__ ((__packed__)) {
    uint8_t  vsys[3];    // Member of Voltage table
    uint16_t cursys[3];  // Member of Current table
    uint32_t cur1;   // Member of Current table
    uint16_t v1;         // Member of Voltage table
    uint16_t cur2;   // Member of Current table
} housekeeping_t;

Functions would be (for example) hk_handle_t get_voltages(); or hk_handle_t get_currents();

I can not change how the data is collected from the sensors. Only how it gets to the SD card.

Reliability is valued above all else

I take it you want to pass an (array-of-)structures to a function such that it serializes a parametrized sub-set of the fields?

One way of doing this would be to pass an array of field descriptors, containing the relative member offsets and sizes, to the generic functions. In C(++) you may take advantage of the offsetof macro to help you with this.

Eg something along these lines:

struct record {
    int apple1, orange1;
    int apple2, orange2;
};

struct field { size_t offset, size; };
#define FIELD(id) { offsetof(struct record, id), sizeof(struct record, id) }
#define SENTINEL() { 0, 0 }

const struct field apples[] = { FIELD(apple1), FIELD(apple2), SENTINEL() };
const struct field oranges[] = { FIELD(orange1), FIELD(orange2), SENTINEL() };

void write_subset(FILE *file, const struct record *record, const struct field *fields) {
    for(; fields->size; ++fields)
        fwrite((const char *) record + fields->offset, fields->size, 1, file);
}

Naturally there are many alternative options. You might include type specifiers to do portable I/O, or create raw byte masks, or define a function per field set with callbacks for the I/O task, etc. As you might imagine it is difficult to good advice without more specifics.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM