Skip to content

Commit dd2aca9

Browse files
committed
table code types containing unions
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.
1 parent e8d1797 commit dd2aca9

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

canard.c

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,6 +1993,46 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
19931993
break;
19941994
}
19951995

1996+
case CANARD_TABLE_CODING_UNION: {
1997+
uint8_t num_tags = bitlen;
1998+
const CanardCodingTableEntry* aux = ++entry;
1999+
const CanardCodingTableEntry* union_header = ++entry;
2000+
const CanardCodingTableEntry* union_entry = union_header + num_tags;
2001+
2002+
uint8_t union_tag;
2003+
uint8_t tag_bitlen = aux->bitlen;
2004+
canardDecodeScalar(transfer, *bit_ofs, tag_bitlen, false, &union_tag);
2005+
*bit_ofs += tag_bitlen;
2006+
if (union_tag >= num_tags) {
2007+
return true; // invalid value
2008+
}
2009+
2010+
void* tag_p = (char*)msg + aux->offset;
2011+
// we know 254 is the max tag value, but the chars taken is compiler dependent
2012+
if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint8_t)) {
2013+
*(uint8_t*)tag_p = union_tag;
2014+
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint16_t)) {
2015+
*(uint16_t*)tag_p = union_tag;
2016+
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint32_t)) {
2017+
*(uint32_t*)tag_p = union_tag;
2018+
} else {
2019+
*(uint64_t*)tag_p = union_tag;
2020+
}
2021+
2022+
// check each tag so we can keep track of the entry pointers
2023+
for (uint8_t tag=0; tag<num_tags; tag++) {
2024+
uint8_t num_entries = (union_header++)->bitlen;
2025+
if (num_entries && tag == union_tag) { // can't decode 0 entries, so check that in addition to match
2026+
tableDecodeCore(union_entry, union_entry+num_entries-1, transfer, bit_ofs, p, tao);
2027+
}
2028+
union_entry += num_entries;
2029+
}
2030+
2031+
entry = union_entry - 1; // point entry to last for ++entry at end of loop
2032+
2033+
break;
2034+
}
2035+
19962036
default:
19972037
return true; // invalid type
19982038
}
@@ -2094,6 +2134,44 @@ CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
20942134
break;
20952135
}
20962136

2137+
case CANARD_TABLE_CODING_UNION: {
2138+
uint8_t num_fields = bitlen;
2139+
const CanardCodingTableEntry* aux = ++entry;
2140+
const CanardCodingTableEntry* union_header = ++entry;
2141+
const CanardCodingTableEntry* union_entry = union_header + num_fields;
2142+
2143+
const void* tag_p = (const char*)msg + aux->offset;
2144+
uint8_t union_tag;
2145+
// we know 254 is the max tag value, but the chars taken is compiler dependent
2146+
if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint8_t)) {
2147+
union_tag = (uint8_t)*(const uint8_t*)tag_p;
2148+
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint16_t)) {
2149+
union_tag = (uint16_t)*(const uint16_t*)tag_p;
2150+
} else if (sizeof(CanardCodingTableUnionEnum) == sizeof(uint32_t)) {
2151+
union_tag = (uint32_t)*(const uint32_t*)tag_p;
2152+
} else {
2153+
union_tag = (uint64_t)*(const uint64_t*)tag_p;
2154+
}
2155+
// the native type is an enum so assume it can't be out of range
2156+
2157+
uint8_t tag_bitlen = aux->bitlen;
2158+
canardEncodeScalar(buffer, *bit_ofs, tag_bitlen, &union_tag);
2159+
*bit_ofs += tag_bitlen;
2160+
2161+
// check each tag so we can keep track of the entry pointers
2162+
for (uint8_t tag=0; tag<num_fields; tag++) {
2163+
uint8_t num_entries = (union_header++)->bitlen;
2164+
if (num_entries && tag == union_tag) { // can't encode 0 entries, so check that in addition to match
2165+
tableEncodeCore(union_entry, union_entry+num_entries-1, buffer, bit_ofs, p, tao);
2166+
}
2167+
union_entry += num_entries;
2168+
}
2169+
2170+
entry = union_entry - 1; // point entry to last for ++entry at end of loop
2171+
2172+
break;
2173+
}
2174+
20972175
default:
20982176
return; // invalid type
20992177
}

canard.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,17 @@ struct CanardRxTransfer
472472
#define CANARD_TABLE_CODING_ARRAY_STATIC (4)
473473
#define CANARD_TABLE_CODING_ARRAY_DYNAMIC (5)
474474
#define CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO (6)
475+
#define CANARD_TABLE_CODING_UNION (7)
476+
477+
/**
478+
* Structure representing the enum for the union tag field for the maximum
479+
* supported structure size in the table. We assume it is the same size as any
480+
* union tag enum with the same span of tag values or less.
481+
*/
482+
typedef enum {
483+
CanardCodingTableUnionEnumMin = 0,
484+
CanardCodingTableUnionEnumMax = 254,
485+
} CanardCodingTableUnionEnum;
475486

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

558+
/**
559+
* Coding table entries (2 total) for union type header.
560+
*
561+
* first entry:
562+
* offset: offset, in chars, to the storage of an arbitrary union member
563+
* type: 7 for union
564+
* bitlen: number of fields in the union
565+
* second entry:
566+
* offset: offset, in chars, to the storage of the tag
567+
* type: always 0
568+
* bitlen: number of bits the tag is encoded into
569+
*
570+
* note: entries which describe the union contents have offsets relative to the start of the array storage
571+
*/
572+
#define CANARD_TABLE_CODING_ENTRIES_UNION(offset, num_fields, tag_bitlen, tag_offset) \
573+
{offset, CANARD_TABLE_CODING_UNION, num_fields}, \
574+
{tag_offset, 0, tag_bitlen}
575+
576+
/**
577+
* Coding table entry for union type field.
578+
*
579+
* offset: always 0
580+
* type: always 0
581+
* bitlen: total number of entries after these which describe the field contents (may encompass e.g. arrays)
582+
*/
583+
#define CANARD_TABLE_CODING_ENTRY_UNION_FIELD(num_entries) \
584+
{0, 0, num_entries}
585+
547586
/**
548587
* This structure describes the encoded form of a particular message. It can be
549588
* contained in ROM. It should be generated using dronecan_dsdlc.
589+
*
590+
* The table can describe any structure of message supported by DSDL, however
591+
* the quantities and sizes of specific aspects are limited by the datatypes
592+
* chosen. For example, the total number of entries is limited to 65536 due to
593+
* the maximum entry index being stored in a uint16_t. The description for each
594+
* type of table entry explains the field types and meanings, from which the
595+
* maximum supported values can be derived.
550596
*/
551597
typedef struct {
552598
uint16_t max_size; // must be > 0

0 commit comments

Comments
 (0)