Skip to content

Commit dcf5531

Browse files
committed
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 0272d96 commit dcf5531

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
}
@@ -1883,7 +1895,8 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
18831895
const CanardCodingTableEntry* entry_last,
18841896
const CanardRxTransfer* transfer,
18851897
uint32_t* bit_ofs,
1886-
void* msg)
1898+
void* msg,
1899+
bool tao)
18871900
{
18881901
do {
18891902
void* p = (char*)msg + entry->offset;
@@ -1914,7 +1927,7 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
19141927

19151928
uint16_t elems = aux->type | ((uint16_t)aux->bitlen << 8);
19161929
while (elems--) {
1917-
if (tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p)) {
1930+
if (tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p, !elems && tao)) {
19181931
return true;
19191932
}
19201933
p = (char*)p + aux->offset;
@@ -1923,6 +1936,60 @@ CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
19231936
break;
19241937
}
19251938

1939+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC:
1940+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO: {
1941+
const CanardCodingTableEntry* aux = ++entry;
1942+
const CanardCodingTableEntry* aux2 = ++entry;
1943+
const CanardCodingTableEntry* array_entry = ++entry;
1944+
const CanardCodingTableEntry* array_entry_last = array_entry + bitlen;
1945+
entry = array_entry_last; // point entry to last for ++entry at end of loop
1946+
1947+
uint16_t max_len = aux->type | ((uint16_t)aux->bitlen << 8);
1948+
void* len_p = ((char*)msg + aux2->offset);
1949+
uint8_t len_bitlen = aux2->bitlen;
1950+
if (type != CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO || !tao) {
1951+
// not using TAO
1952+
canardDecodeScalar(transfer, *bit_ofs, len_bitlen, false, len_p);
1953+
*bit_ofs += len_bitlen;
1954+
1955+
uint16_t elems;
1956+
if (len_bitlen <= 8) {
1957+
elems = *(uint8_t*)len_p;
1958+
} else { // 16 bits is max supported len
1959+
elems = *(uint16_t*)len_p;
1960+
}
1961+
if (elems > max_len) {
1962+
return true; // invalid value
1963+
}
1964+
1965+
while (elems--) {
1966+
if (tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p, !elems && tao)) {
1967+
return true;
1968+
}
1969+
p = (char*)p + aux->offset;
1970+
}
1971+
} else {
1972+
// TAO optimization in play
1973+
uint16_t elems = 0;
1974+
// TAO requires the element size to be at least 8 bits so if we have less we know we are done
1975+
uint32_t max_bits = (transfer->payload_len*8)-7;
1976+
while (max_bits > *bit_ofs) {
1977+
if (!max_len-- || tableDecodeCore(array_entry, array_entry_last, transfer, bit_ofs, p, false)) {
1978+
return true;
1979+
}
1980+
p = (char*)p + aux->offset;
1981+
elems++;
1982+
}
1983+
if (len_bitlen <= 8) {
1984+
*(uint8_t*)len_p = (uint8_t)elems;
1985+
} else { // 16 bits is max supported len
1986+
*(uint16_t*)len_p = elems;
1987+
}
1988+
}
1989+
1990+
break;
1991+
}
1992+
19261993
default:
19271994
return true; // invalid type
19281995
}
@@ -1937,7 +2004,8 @@ CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
19372004
const CanardCodingTableEntry* entry_last,
19382005
uint8_t* buffer,
19392006
uint32_t* bit_ofs,
1940-
const void* msg)
2007+
const void* msg,
2008+
bool tao)
19412009
{
19422010
do {
19432011
const void* p = (const char*)msg + entry->offset;
@@ -1969,7 +2037,51 @@ CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
19692037

19702038
uint16_t elems = aux->type | ((uint16_t)aux->bitlen << 8);
19712039
while (elems--) {
1972-
tableEncodeCore(array_entry, array_entry_last, buffer, bit_ofs, p);
2040+
tableEncodeCore(array_entry, array_entry_last, buffer, bit_ofs, p, !elems && tao);
2041+
p = (const char*)p + aux->offset;
2042+
}
2043+
2044+
break;
2045+
}
2046+
2047+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC:
2048+
case CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO: {
2049+
const CanardCodingTableEntry* aux = ++entry;
2050+
const CanardCodingTableEntry* aux2 = ++entry;
2051+
const CanardCodingTableEntry* array_entry = ++entry;
2052+
const CanardCodingTableEntry* array_entry_last = array_entry + bitlen;
2053+
entry = array_entry_last; // point entry to last for ++entry at end of loop
2054+
2055+
uint16_t max_len = aux->type | ((uint16_t)aux->bitlen << 8);
2056+
const void* len_p = (const char*)msg + aux2->offset;
2057+
uint8_t len_bitlen = aux2->bitlen;
2058+
2059+
uint16_t elems;
2060+
if (len_bitlen <= 8) {
2061+
elems = *(const uint8_t*)len_p;
2062+
} else { // 16 bits is max supported len
2063+
elems = *(const uint16_t*)len_p;
2064+
}
2065+
if (elems > max_len) {
2066+
elems = max_len;
2067+
}
2068+
2069+
if (type != CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO || !tao) {
2070+
// encode the length value we have clamped to the maximum
2071+
uint8_t elems_8;
2072+
if (len_bitlen <= 8) {
2073+
elems_8 = (uint8_t)elems;
2074+
len_p = &elems_8;
2075+
} else { // 16 bits is max supported len
2076+
len_p = &elems;
2077+
}
2078+
canardEncodeScalar(buffer, *bit_ofs, len_bitlen, len_p);
2079+
*bit_ofs += len_bitlen;
2080+
}
2081+
2082+
int element_tao = type != CANARD_TABLE_CODING_ARRAY_DYNAMIC_TAO && tao;
2083+
while (elems--) {
2084+
tableEncodeCore(array_entry, array_entry_last, buffer, bit_ofs, p, !elems && element_tao);
19732085
p = (const char*)p + aux->offset;
19742086
}
19752087

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)