Skip to content

Commit 971cadc

Browse files
tpwrulestridge
authored andcommitted
table code dynamic arrays, including tail array optimization
Dynamic arrays have a 3-entry header (12 bytes), plus the entries describing the contents of the array. Array contents cannot consist of more than 256 entries (including header entries and entries describing nested types). The maximum array length cannot exceed 65535.
1 parent 507b9dc commit 971cadc

File tree

3 files changed

+147
-8
lines changed

3 files changed

+147
-8
lines changed

canard.c

Lines changed: 118 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,13 @@ bool canardTableDecodeMessage(const CanardCodingTable* table,
10081008
uint32_t bit_ofs = 0;
10091009
const CanardCodingTableEntry* entry = &table->entries[0];
10101010
const CanardCodingTableEntry* entry_last = &table->entries[table->entries_max];
1011-
if (tableDecodeCore(entry, entry_last, transfer, &bit_ofs, msg)) {
1011+
if (tableDecodeCore(entry, entry_last, transfer, &bit_ofs, msg,
1012+
#if CANARD_ENABLE_TAO_OPTION
1013+
transfer->tao
1014+
#else
1015+
true
1016+
#endif
1017+
)) {
10121018
return true; // decode failure
10131019
}
10141020

@@ -1038,7 +1044,13 @@ uint32_t canardTableEncodeMessage(const CanardCodingTable* table,
10381044
uint32_t bit_ofs = 0;
10391045
const CanardCodingTableEntry* entry = &table->entries[0];
10401046
const CanardCodingTableEntry* entry_last = &table->entries[table->entries_max];
1041-
tableEncodeCore(entry, entry_last, buffer, &bit_ofs, msg);
1047+
tableEncodeCore(entry, entry_last, buffer, &bit_ofs, msg,
1048+
#if CANARD_ENABLE_TAO_OPTION
1049+
tao
1050+
#else
1051+
true
1052+
#endif
1053+
);
10421054

10431055
return ((bit_ofs+7)/8);
10441056
}
@@ -1897,7 +1909,8 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
18971909
const CanardCodingTableEntry* entry_last,
18981910
const CanardRxTransfer* transfer,
18991911
uint32_t* bit_ofs,
1900-
void* msg)
1912+
void* msg,
1913+
bool tao)
19011914
{
19021915
do {
19031916
void* p = (char*)msg + entry->offset;
@@ -1931,7 +1944,7 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
19311944

19321945
uint16_t elems = aux->type | ((uint16_t)aux->bitlen << 8);
19331946
while (elems--) {
1934-
if (tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p)) {
1947+
if (tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p, !elems && tao)) {
19351948
return true;
19361949
}
19371950
p = (char*)p + aux->offset;
@@ -1940,6 +1953,60 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
19401953
break;
19411954
}
19421955

1956+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC:
1957+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO: {
1958+
const CanardCodingTableEntry* aux = ++entry;
1959+
const CanardCodingTableEntry* aux2 = ++entry;
1960+
const CanardCodingTableEntry* array_entry = ++entry;
1961+
const CanardCodingTableEntry* array_entry_last = array_entry + bitlen;
1962+
entry = array_entry_last; // point entry to last for ++entry at end of loop
1963+
1964+
uint16_t max_len = aux->type | ((uint16_t)aux->bitlen << 8);
1965+
void* len_p = ((char*)msg + aux2->offset);
1966+
uint8_t len_bitlen = aux2->bitlen;
1967+
if (type != CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO || !tao) {
1968+
// not using TAO
1969+
canardDecodeScalar(transfer, *bit_ofs, len_bitlen, false, len_p);
1970+
*bit_ofs += len_bitlen;
1971+
1972+
uint16_t elems;
1973+
if (len_bitlen <= 8) {
1974+
elems = *(uint8_t*)len_p;
1975+
} else { // 16 bits is max supported len
1976+
elems = *(uint16_t*)len_p;
1977+
}
1978+
if (elems > max_len) {
1979+
return true; // invalid value
1980+
}
1981+
1982+
while (elems--) {
1983+
if (tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p, !elems && tao)) {
1984+
return true;
1985+
}
1986+
p = (char*)p + aux->offset;
1987+
}
1988+
} else {
1989+
// TAO optimization in play
1990+
uint16_t elems = 0;
1991+
// TAO requires the element size to be at least 8 bits so if we have less we know we are done
1992+
uint32_t max_bits = (transfer->payload_len*8)-7;
1993+
while (max_bits > *bit_ofs) {
1994+
if (!max_len-- || tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p, false)) {
1995+
return true;
1996+
}
1997+
p = (char*)p + aux->offset;
1998+
elems++;
1999+
}
2000+
if (len_bitlen <= 8) {
2001+
*(uint8_t*)len_p = (uint8_t)elems;
2002+
} else { // 16 bits is max supported len
2003+
*(uint16_t*)len_p = elems;
2004+
}
2005+
}
2006+
2007+
break;
2008+
}
2009+
19432010
default:
19442011
return true; // invalid type
19452012
}
@@ -1954,7 +2021,8 @@ CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
19542021
const CanardCodingTableEntry* entry_last,
19552022
uint8_t* buffer,
19562023
uint32_t* bit_ofs,
1957-
const void* msg)
2024+
const void* msg,
2025+
bool tao)
19582026
{
19592027
do {
19602028
const void* p = (const char*)msg + entry->offset;
@@ -1989,7 +2057,51 @@ CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
19892057

19902058
uint16_t elems = aux->type | ((uint16_t)aux->bitlen << 8);
19912059
while (elems--) {
1992-
tableEncodeCore(array_entry, array_entry_last, buffer, bit_ofs, p);
2060+
tableEncodeCore(array_entry, array_entry_last, buffer, bit_ofs, p, !elems && tao);
2061+
p = (const char*)p + aux->offset;
2062+
}
2063+
2064+
break;
2065+
}
2066+
2067+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC:
2068+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO: {
2069+
const CanardCodingTableEntry* aux = ++entry;
2070+
const CanardCodingTableEntry* aux2 = ++entry;
2071+
const CanardCodingTableEntry* array_entry = ++entry;
2072+
const CanardCodingTableEntry* array_entry_last = array_entry + bitlen;
2073+
entry = array_entry_last; // point entry to last for ++entry at end of loop
2074+
2075+
uint16_t max_len = aux->type | ((uint16_t)aux->bitlen << 8);
2076+
const void* len_p = (const char*)msg + aux2->offset;
2077+
uint8_t len_bitlen = aux2->bitlen;
2078+
2079+
uint16_t elems;
2080+
if (len_bitlen <= 8) {
2081+
elems = *(const uint8_t*)len_p;
2082+
} else { // 16 bits is max supported len
2083+
elems = *(const uint16_t*)len_p;
2084+
}
2085+
if (elems > max_len) {
2086+
elems = max_len;
2087+
}
2088+
2089+
if (type != CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO || !tao) {
2090+
// encode the length value we have clamped to the maximum
2091+
uint8_t elems_8;
2092+
if (len_bitlen <= 8) {
2093+
elems_8 = (uint8_t)elems;
2094+
len_p = &elems_8;
2095+
} else { // 16 bits is max supported len
2096+
len_p = &elems;
2097+
}
2098+
canardEncodeScalar(buffer, *bit_ofs, len_bitlen, len_p);
2099+
*bit_ofs += len_bitlen;
2100+
}
2101+
2102+
int element_tao = type != CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO && tao;
2103+
while (elems--) {
2104+
tableEncodeCore(array_entry, array_entry_last, buffer, bit_ofs, p, !elems && element_tao);
19932105
p = (const char*)p + aux->offset;
19942106
}
19952107

canard.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,8 @@ struct CanardRxTransfer
470470
#define CANARD_TABLE_CODING_FLOAT (2)
471471
#define CANARD_TABLE_CODING_VOID (3)
472472
#define CANARD_TABLE_CODING_ARRAY_STATIC (4)
473+
#define CANARD_TABLE_CODING_ARRAY_DYNAMIC (5)
474+
#define CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO (6)
473475

474476
/**
475477
* This structure describes the encoded form of part of a particular message. It
@@ -519,6 +521,29 @@ typedef struct {
519521
{offset, CANARD_TABLE_CODING_ARRAY_STATIC, (num_entries)-1}, \
520522
{elem_size, (array_len)&0xFF, (array_len)>>8}
521523

524+
/**
525+
* Coding table entries (3 total) for array type with a dynamic length.
526+
*
527+
* first entry:
528+
* offset: offset, in chars, to the storage of the first element in the message struct
529+
* type: 5 for dynamic array, 6 for dynamic array eligible for TAO
530+
* bitlen: total number of entries after these which describe the array contents (may encompass e.g. other arrays), minus one
531+
* second entry:
532+
* offset: size, in chars, of one array element, i.e. sizeof(arr[0])
533+
* type: low 8 bits of array length
534+
* bitlen: high 8 bits of array length
535+
* third entry:
536+
* offset: offset, in chars, to the storage in the message struct containing the array length
537+
* type: always 0
538+
* bitlen: number of bits the array length is encoded into
539+
*
540+
* note: entries which describe the array contents have offsets relative to the start of the array storage
541+
*/
542+
#define CANARD_TABLE_CODING_ENTRIES_ARRAY_DYNAMIC(offset, tao, num_entries, elem_size, array_len, len_bitlen, len_offset) \
543+
{offset, (tao) ? CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO : CANARD_TABLE_CODING_ARRAY_DYNAMIC, (num_entries)-1}, \
544+
{elem_size, (array_len)&0xFF, (array_len)>>8}, \
545+
{len_offset, 0, len_bitlen}
546+
522547
/**
523548
* This structure describes the encoded form of a particular message. It can be
524549
* contained in ROM. It should be generated using dronecan_dsdlc.

canard_internals.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,15 +158,17 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
158158
const CanardCodingTableEntry* entry_end,
159159
const CanardRxTransfer* transfer,
160160
uint32_t* bit_ofs,
161-
void* msg);
161+
void* msg,
162+
bool tao);
162163
#endif
163164

164165
#if CANARD_ENABLE_TABLE_ENCODING
165166
CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
166167
const CanardCodingTableEntry* entry_end,
167168
uint8_t* buffer,
168169
uint32_t* bit_ofs,
169-
const void* msg);
170+
const void* msg,
171+
bool tao);
170172
#endif
171173

172174
/*

0 commit comments

Comments
 (0)