Skip to content

Commit 31a0045

Browse files
tpwrulestridge
authored andcommitted
table code types containing primitive and void fields
Each table has a four byte header, plus some number of entries (4 bytes). Each field consumes one entry. The maximum encoded message length in bytes, size of the C message struct in chars, and number of table entries all are limited to 65535 for table coding to be possible. Also supports nested compound types containing these fields.
1 parent 2002413 commit 31a0045

File tree

3 files changed

+161
-12
lines changed

3 files changed

+161
-12
lines changed

canard.c

Lines changed: 110 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -999,11 +999,28 @@ bool canardTableDecodeMessage(const CanardCodingTable* table,
999999
const CanardRxTransfer* transfer,
10001000
void* msg)
10011001
{
1002-
(void)table;
1003-
(void)transfer;
1004-
(void)msg;
1002+
#if CANARD_ENABLE_TAO_OPTION
1003+
if (transfer->tao && (transfer->payload_len > table->max_size)) {
1004+
return true; // invalid length
1005+
}
1006+
#endif
1007+
1008+
uint32_t bit_ofs = 0;
1009+
const CanardCodingTableEntry* entry = &table->entries[0];
1010+
const CanardCodingTableEntry* entry_last = &table->entries[table->entries_max];
1011+
if (tableDecodeCore(entry, entry_last, transfer, &bit_ofs, msg)) {
1012+
return true; // decode failure
1013+
}
10051014

1006-
return true;
1015+
const uint32_t byte_len = (bit_ofs+7U)/8U;
1016+
#if CANARD_ENABLE_TAO_OPTION
1017+
// if this could be CANFD then the dlc could indicating more bytes than
1018+
// we actually have
1019+
if (!transfer->tao) {
1020+
return byte_len > transfer->payload_len;
1021+
}
1022+
#endif
1023+
return byte_len != transfer->payload_len;
10071024
}
10081025
#endif
10091026

@@ -1016,14 +1033,14 @@ uint32_t canardTableEncodeMessage(const CanardCodingTable* table,
10161033
#endif
10171034
)
10181035
{
1019-
(void)table;
1020-
(void)buffer;
1021-
(void)msg;
1022-
#if CANARD_ENABLE_TAO_OPTION
1023-
(void)tao;
1024-
#endif
1036+
memset(buffer, 0, table->max_size);
1037+
1038+
uint32_t bit_ofs = 0;
1039+
const CanardCodingTableEntry* entry = &table->entries[0];
1040+
const CanardCodingTableEntry* entry_last = &table->entries[table->entries_max];
1041+
tableEncodeCore(entry, entry_last, buffer, &bit_ofs, msg);
10251042

1026-
return 0;
1043+
return ((bit_ofs+7)/8);
10271044
}
10281045
#endif
10291046

@@ -1872,6 +1889,88 @@ CANARD_INTERNAL void swapByteOrder(void* data, unsigned size)
18721889
}
18731890
}
18741891

1892+
/**
1893+
* Table coding functions
1894+
*/
1895+
#if CANARD_ENABLE_TABLE_DECODING
1896+
CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
1897+
const CanardCodingTableEntry* entry_last,
1898+
const CanardRxTransfer* transfer,
1899+
uint32_t* bit_ofs,
1900+
void* msg)
1901+
{
1902+
do {
1903+
void* p = (char*)msg + entry->offset;
1904+
uint8_t type = entry->type;
1905+
uint8_t bitlen = entry->bitlen;
1906+
1907+
switch (type) {
1908+
case CANARD_TABLE_CODING_UNSIGNED:
1909+
case CANARD_TABLE_CODING_SIGNED:
1910+
case CANARD_TABLE_CODING_FLOAT: {
1911+
canardDecodeScalar(transfer, *bit_ofs, bitlen, type != CANARD_TABLE_CODING_UNSIGNED, p);
1912+
if (type == CANARD_TABLE_CODING_FLOAT && bitlen == 16) {
1913+
uint16_t float16_val = (uint16_t)*(int16_t*)p;
1914+
*(float*)p = canardConvertFloat16ToNativeFloat(float16_val);
1915+
}
1916+
1917+
*bit_ofs += bitlen;
1918+
break;
1919+
}
1920+
1921+
case CANARD_TABLE_CODING_VOID:
1922+
// nothing to decode for void
1923+
*bit_ofs += bitlen;
1924+
break;
1925+
1926+
default:
1927+
return true; // invalid type
1928+
}
1929+
} while (++entry <= entry_last);
1930+
1931+
return false; // success
1932+
}
1933+
#endif
1934+
1935+
#if CANARD_ENABLE_TABLE_ENCODING
1936+
CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
1937+
const CanardCodingTableEntry* entry_last,
1938+
uint8_t* buffer,
1939+
uint32_t* bit_ofs,
1940+
const void* msg)
1941+
{
1942+
do {
1943+
const void* p = (const char*)msg + entry->offset;
1944+
uint8_t type = entry->type;
1945+
uint8_t bitlen = entry->bitlen;
1946+
1947+
switch (type) {
1948+
case CANARD_TABLE_CODING_UNSIGNED:
1949+
case CANARD_TABLE_CODING_SIGNED:
1950+
case CANARD_TABLE_CODING_FLOAT: {
1951+
uint16_t float16_val;
1952+
if (type == CANARD_TABLE_CODING_FLOAT && bitlen == 16) {
1953+
float16_val = canardConvertNativeFloatToFloat16(*(const float*)p);
1954+
p = &float16_val;
1955+
}
1956+
canardEncodeScalar(buffer, *bit_ofs, bitlen, p);
1957+
1958+
*bit_ofs += bitlen;
1959+
break;
1960+
}
1961+
1962+
case CANARD_TABLE_CODING_VOID:
1963+
// void encoding is taken care of by memset to 0 in the wrapper
1964+
*bit_ofs += bitlen;
1965+
break;
1966+
1967+
default:
1968+
return; // invalid type
1969+
}
1970+
} while (++entry <= entry_last);
1971+
}
1972+
#endif
1973+
18751974
/*
18761975
* CRC functions
18771976
*/

canard.h

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,21 +464,52 @@ struct CanardRxTransfer
464464
};
465465

466466
#if CANARD_ENABLE_TABLE_DECODING || CANARD_ENABLE_TABLE_ENCODING
467+
468+
#define CANARD_TABLE_CODING_UNSIGNED (0)
469+
#define CANARD_TABLE_CODING_SIGNED (1)
470+
#define CANARD_TABLE_CODING_FLOAT (2)
471+
#define CANARD_TABLE_CODING_VOID (3)
472+
467473
/**
468474
* This structure describes the encoded form of part of a particular message. It
469475
* can be contained in ROM. It should be generated using dronecan_dsdlc.
470476
*/
471477
typedef struct {
478+
uint16_t offset;
479+
uint8_t type;
480+
uint8_t bitlen;
472481
} CanardCodingTableEntry;
473482

483+
/**
484+
* Coding table entry for primitive types (unsigned, signed, float).
485+
*
486+
* offset: offset, in chars, to the storage in the message struct
487+
* type: 0, 1, or 2 for unsigned, signed, float
488+
* bitlen: number of bits the primitive is encoded into
489+
*/
490+
#define CANARD_TABLE_CODING_ENTRY_PRIMITIVE(offset, type, bitlen) \
491+
{offset, type, bitlen}
492+
493+
/**
494+
* Coding table entry for void type.
495+
*
496+
* offset: always 0
497+
* type: 3 for void
498+
* bitlen: number of bits of padding in the encoded output
499+
*/
500+
#define CANARD_TABLE_CODING_ENTRY_VOID(bitlen) \
501+
{0, CANARD_TABLE_CODING_VOID, bitlen}
502+
474503
/**
475504
* This structure describes the encoded form of a particular message. It can be
476505
* contained in ROM. It should be generated using dronecan_dsdlc.
477506
*/
478507
typedef struct {
479-
size_t entries_max;
508+
uint16_t max_size; // must be > 0
509+
uint16_t entries_max;
480510
CanardCodingTableEntry entries[];
481511
} CanardCodingTable;
512+
482513
#endif
483514

484515
/**

canard_internals.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,25 @@ CANARD_INTERNAL bool isBigEndian(void);
150150

151151
CANARD_INTERNAL void swapByteOrder(void* data, unsigned size);
152152

153+
/**
154+
* Table coding functions
155+
*/
156+
#if CANARD_ENABLE_TABLE_DECODING
157+
CANARD_INTERNAL bool tableDecodeCore(const CanardCodingTableEntry* entry,
158+
const CanardCodingTableEntry* entry_end,
159+
const CanardRxTransfer* transfer,
160+
uint32_t* bit_ofs,
161+
void* msg);
162+
#endif
163+
164+
#if CANARD_ENABLE_TABLE_ENCODING
165+
CANARD_INTERNAL void tableEncodeCore(const CanardCodingTableEntry* entry,
166+
const CanardCodingTableEntry* entry_end,
167+
uint8_t* buffer,
168+
uint32_t* bit_ofs,
169+
const void* msg);
170+
#endif
171+
153172
/*
154173
* Transfer CRC
155174
*/

0 commit comments

Comments
 (0)