Skip to content

Commit

Permalink
table code types containing unions
Browse files Browse the repository at this point in the history
Unions have a 2-entry header (8 bytes), plus 1 entry for each field,
plus the entries describing each field.

The maximum number of fields is 255. Each field cannot consist of more
than 255 entries (including header entries and entries describing nested
types).

This completes the list of DSDL types.
  • Loading branch information
tpwrules committed Jul 27, 2024
1 parent e8d1797 commit dd2aca9
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 0 deletions.
78 changes: 78 additions & 0 deletions canard.c
Original file line number Diff line number Diff line change
Expand Up @@ -1993,6 +1993,46 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
break;
}

case CANARD_TABLE_CODING_UNION: {
uint8_t num_tags = bitlen;
const CanardCodingTableEntry* aux = ++entry;
const CanardCodingTableEntry* union_header = ++entry;
const CanardCodingTableEntry* union_entry = union_header + num_tags;

uint8_t union_tag;
uint8_t tag_bitlen = aux->bitlen;
canardDecodeScalar(transfer, *bit_ofs, tag_bitlen, false, &union_tag);
*bit_ofs += tag_bitlen;
if (union_tag >= num_tags) {
return true; // invalid value
}

void* tag_p = (char*)msg + aux->offset;
// we know 254 is the max tag value, but the chars taken is compiler dependent
if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint8_t)) {
*(uint8_t*)tag_p = union_tag;
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint16_t)) {
*(uint16_t*)tag_p = union_tag;
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint32_t)) {
*(uint32_t*)tag_p = union_tag;
} else {
*(uint64_t*)tag_p = union_tag;
}

// check each tag so we can keep track of the entry pointers
for (uint8_t tag=0; tag<num_tags; tag++) {
uint8_t num_entries = (union_header++)->bitlen;
if (num_entries && tag == union_tag) { // can't decode 0 entries, so check that in addition to match
tableDecodeCore(union_entry, union_entry+num_entries-1, transfer, bit_ofs, p, tao);
}
union_entry += num_entries;
}

entry = union_entry - 1; // point entry to last for ++entry at end of loop

break;
}

default:
return true; // invalid type
}
Expand Down Expand Up @@ -2094,6 +2134,44 @@ CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
break;
}

case CANARD_TABLE_CODING_UNION: {
uint8_t num_fields = bitlen;
const CanardCodingTableEntry* aux = ++entry;
const CanardCodingTableEntry* union_header = ++entry;
const CanardCodingTableEntry* union_entry = union_header + num_fields;

const void* tag_p = (const char*)msg + aux->offset;
uint8_t union_tag;
// we know 254 is the max tag value, but the chars taken is compiler dependent
if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint8_t)) {
union_tag = (uint8_t)*(const uint8_t*)tag_p;
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint16_t)) {
union_tag = (uint16_t)*(const uint16_t*)tag_p;
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint32_t)) {
union_tag = (uint32_t)*(const uint32_t*)tag_p;
} else {
union_tag = (uint64_t)*(const uint64_t*)tag_p;
}
// the native type is an enum so assume it can't be out of range

uint8_t tag_bitlen = aux->bitlen;
canardEncodeScalar(buffer, *bit_ofs, tag_bitlen, &union_tag);
*bit_ofs += tag_bitlen;

// check each tag so we can keep track of the entry pointers
for (uint8_t tag=0; tag<num_fields; tag++) {
uint8_t num_entries = (union_header++)->bitlen;
if (num_entries && tag == union_tag) { // can't encode 0 entries, so check that in addition to match
tableEncodeCore(union_entry, union_entry+num_entries-1, buffer, bit_ofs, p, tao);
}
union_entry += num_entries;
}

entry = union_entry - 1; // point entry to last for ++entry at end of loop

break;
}

default:
return; // invalid type
}
Expand Down
46 changes: 46 additions & 0 deletions canard.h
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,17 @@ struct CanardRxTransfer
#define CANARD_TABLE_CODING_ARRAY_STATIC (4)
#define CANARD_TABLE_CODING_ARRAY_DYNAMIC (5)
#define CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO (6)
#define CANARD_TABLE_CODING_UNION (7)

/**
* Structure representing the enum for the union tag field for the maximum
* supported structure size in the table. We assume it is the same size as any
* union tag enum with the same span of tag values or less.
*/
typedef enum {
CanardCodingTableUnionEnumMin = 0,
CanardCodingTableUnionEnumMax = 254,
} CanardCodingTableUnionEnum;

/**
* This structure describes the encoded form of part of a particular message. It
Expand Down Expand Up @@ -544,9 +555,44 @@ typedef struct {
{elem_size, (array_len)&0xFF, (array_len)>>8}, \
{len_offset, 0, len_bitlen}

/**
* Coding table entries (2 total) for union type header.
*
* first entry:
* offset: offset, in chars, to the storage of an arbitrary union member
* type: 7 for union
* bitlen: number of fields in the union
* second entry:
* offset: offset, in chars, to the storage of the tag
* type: always 0
* bitlen: number of bits the tag is encoded into
*
* note: entries which describe the union contents have offsets relative to the start of the array storage
*/
#define CANARD_TABLE_CODING_ENTRIES_UNION(offset, num_fields, tag_bitlen, tag_offset) \
{offset, CANARD_TABLE_CODING_UNION, num_fields}, \
{tag_offset, 0, tag_bitlen}

/**
* Coding table entry for union type field.
*
* offset: always 0
* type: always 0
* bitlen: total number of entries after these which describe the field contents (may encompass e.g. arrays)
*/
#define CANARD_TABLE_CODING_ENTRY_UNION_FIELD(num_entries) \
{0, 0, num_entries}

/**
* This structure describes the encoded form of a particular message. It can be
* contained in ROM. It should be generated using dronecan_dsdlc.
*
* The table can describe any structure of message supported by DSDL, however
* the quantities and sizes of specific aspects are limited by the datatypes
* chosen. For example, the total number of entries is limited to 65536 due to
* the maximum entry index being stored in a uint16_t. The description for each
* type of table entry explains the field types and meanings, from which the
* maximum supported values can be derived.
*/
typedef struct {
uint16_t max_size; // must be > 0
Expand Down

0 comments on commit dd2aca9

Please sign in to comment.