From bf9dfcd0881f58fa8df01b87bdd4e5caee31a1d3 Mon Sep 17 00:00:00 2001 From: "Rule Timothy (VM/EMT3)" Date: Fri, 2 Feb 2024 16:20:28 +0100 Subject: [PATCH] NCodec support for CAN FD. Signed-off-by: Rule Timothy (VM/EMT3) --- doc/content/apis/ncodec/examples/ncodec_api.c | 5 +- doc/content/apis/ncodec/index.md | 32 ++--- doc/content/apis/ncodec/ncodec-component.png | Bin 20557 -> 20559 bytes dse/ncodec/codec.c | 5 +- dse/ncodec/codec.h | 27 ++-- dse/ncodec/example/codec.c | 12 +- dse/ncodec/example/example.c | 5 +- dse/ncodec/libs/automotive-bus/CMakeLists.txt | 2 +- .../libs/automotive-bus/frame_can_fbs.c | 32 +++-- .../libs/automotive-bus/tests/CMakeLists.txt | 2 +- .../libs/automotive-bus/tests/test_can_fbs.c | 122 +++++++++++++----- 11 files changed, 165 insertions(+), 79 deletions(-) diff --git a/doc/content/apis/ncodec/examples/ncodec_api.c b/doc/content/apis/ncodec/examples/ncodec_api.c index 231c45f..8f78cfd 100644 --- a/doc/content/apis/ncodec/examples/ncodec_api.c +++ b/doc/content/apis/ncodec/examples/ncodec_api.c @@ -38,7 +38,8 @@ int main(int argc, char* argv[]) .name = "name", .value = "simple network codec" }); /* Write a message to the Network Codec. */ - ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, + .frame_type = CAN_EXTENDED_FRAME, .buffer = (uint8_t*)greeting, .len = strlen(greeting) }); ncodec_flush(nc); @@ -47,7 +48,7 @@ int main(int argc, char* argv[]) stream_seek(nc, 0, NCODEC_SEEK_SET); /* Read the response from the Network Codec. */ - NCodecMessage msg = {}; + NCodecCanMessage msg = {}; rc = ncodec_read(nc, &msg); if (rc > 0) { printf("Message is: %s\n", (char*)msg.buffer); diff --git a/doc/content/apis/ncodec/index.md b/doc/content/apis/ncodec/index.md index eadad38..3020048 100644 --- a/doc/content/apis/ncodec/index.md +++ b/doc/content/apis/ncodec/index.md @@ -32,9 +32,9 @@ title Network Codec package "Model Environment" { interface "Signal Interface" as Sif component "Model" as foo { - component "Model" as Model - interface "CodecVTable" as Cvt - component "Codec" as Codec + component "Model" as Model + interface "CodecVTable" as Cvt + component "Codec" as Codec interface "StreamVTable" as Svt } component "Stream" as Stream @@ -73,6 +73,17 @@ center footer Dynamic Simulation Environment ## Typedefs +### NCodecCanMessage + +```c +typedef struct NCodecCanMessage { + uint32_t frame_id; + uint8_t* buffer; + size_t len; + NCodecCanFrameType frame_type; +} +``` + ### NCodecConfigItem ```c @@ -92,16 +103,6 @@ typedef struct NCodecInstance { } ``` -### NCodecMessage - -```c -typedef struct NCodecMessage { - uint32_t frame_id; - uint8_t* buffer; - size_t len; -} -``` - ### NCodecStreamVTable ```c @@ -273,7 +274,8 @@ nc (NCODEC*) msg (NCodecMessage*) : (out) The message representation to write to the Network Codec. Caller owns - the message buffer/memory. + the message buffer/memory. Message type is defined by the codec +implementation. #### Returns @@ -351,7 +353,7 @@ nc (NCODEC*) msg (NCodecMessage*) : The message representation to write to the Network Codec. Caller owns the - message buffer/memory. + message buffer/memory. Message type is defined by the codec implementation. #### Returns diff --git a/doc/content/apis/ncodec/ncodec-component.png b/doc/content/apis/ncodec/ncodec-component.png index 7a291a48af8d67a587e01bf69847aad9119a6982..e317e380e514e2355c0e8cb3a849421413bc25bd 100644 GIT binary patch delta 487 zcmVh4}C5kCY7st)(cAJ)W62ez|HiQM#=-id+^n z4|7@7Qc$4*G}D~o9o4T=z2MAl1JopcAtlAZ%6xOY7JH_osLX+X0lop6!Gxx2M{v!B=4$X1zf3)X1Gwyl*}8p49?3I1w@W))5G-dJ4B zZ;uO~oGdo0e}M5>IAz+1D&qz>E11(AX}LBhOtDOqDNgRPo9Ew2bQZ=J<8xRNQMTsa dNRbMYwGmK<6xSL21q?+E@&1AAv9m4$A5Nqo<^TWy delta 485 zcmVNXE#TRD>1UVW`%K`w30pkIB( zN>Wny3T3{~+o@)UbQpU)H9uvX$is>G=~wes3ohB#0xGtJHvruv9EOE><)OFi`W;GE zKC3XW2K9Fgct@^()(6Ol&w3y))NSa>2UZhkUW~dXx;j3z=L@flBuw3SJc)+#Uc.stream->write(nc, msg->buffer, msg->len); - return msg->len; + _nc->c.stream->write(nc, _msg->buffer, _msg->len); + return _msg->len; } int codec_read(NCODEC* nc, NCodecMessage* msg) { if (nc == NULL) return -ENOSTR; if (msg == NULL) return -EINVAL; + NCodecCanMessage* _msg = (NCodecCanMessage*)msg; __codec* _nc = (__codec*)nc; @@ -71,10 +73,10 @@ int codec_read(NCODEC* nc, NCodecMessage* msg) /* Construct the response. */ strncat(data, " says ", buffer_len - strlen(data)); strncat(data, _nc->name, buffer_len); - msg->len = strlen(data); + _msg->len = strlen(data); /* Return the message (buffer owned by stream, caller must duplicate). */ - msg->buffer = (uint8_t*)data; - return msg->len; + _msg->buffer = (uint8_t*)data; + return _msg->len; } int codec_flush(NCODEC* nc) diff --git a/dse/ncodec/example/example.c b/dse/ncodec/example/example.c index 231c45f..8f78cfd 100644 --- a/dse/ncodec/example/example.c +++ b/dse/ncodec/example/example.c @@ -38,7 +38,8 @@ int main(int argc, char* argv[]) .name = "name", .value = "simple network codec" }); /* Write a message to the Network Codec. */ - ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, + .frame_type = CAN_EXTENDED_FRAME, .buffer = (uint8_t*)greeting, .len = strlen(greeting) }); ncodec_flush(nc); @@ -47,7 +48,7 @@ int main(int argc, char* argv[]) stream_seek(nc, 0, NCODEC_SEEK_SET); /* Read the response from the Network Codec. */ - NCodecMessage msg = {}; + NCodecCanMessage msg = {}; rc = ncodec_read(nc, &msg); if (rc > 0) { printf("Message is: %s\n", (char*)msg.buffer); diff --git a/dse/ncodec/libs/automotive-bus/CMakeLists.txt b/dse/ncodec/libs/automotive-bus/CMakeLists.txt index d1c34d1..03ea5db 100644 --- a/dse/ncodec/libs/automotive-bus/CMakeLists.txt +++ b/dse/ncodec/libs/automotive-bus/CMakeLists.txt @@ -27,7 +27,7 @@ add_compile_options(${C_CXX_WARNING_FLAGS}) # External Project - Automotive Bus Schema # ------------------------------------------- FetchContent_Declare(automotive-bus-schema - URL https://github.com/boschglobal/automotive-bus-schema/releases/download/v1.0.2/automotive-bus-schema.tar.gz + URL https://github.com/boschglobal/automotive-bus-schema/releases/download/v1.0.3/automotive-bus-schema.tar.gz ) FetchContent_MakeAvailable(automotive-bus-schema) set(SCHEMAS_SOURCE_DIR ${automotive-bus-schema_SOURCE_DIR}/flatbuffers/c) diff --git a/dse/ncodec/libs/automotive-bus/frame_can_fbs.c b/dse/ncodec/libs/automotive-bus/frame_can_fbs.c index 92a9db0..03b70c4 100644 --- a/dse/ncodec/libs/automotive-bus/frame_can_fbs.c +++ b/dse/ncodec/libs/automotive-bus/frame_can_fbs.c @@ -50,9 +50,10 @@ static void finalize_stream( int can_write(NCODEC* nc, NCodecMessage* msg) { - ABCodecInstance* _nc = (ABCodecInstance*)nc; + ABCodecInstance* _nc = (ABCodecInstance*)nc; + NCodecCanMessage* _msg = (NCodecCanMessage*)msg; if (_nc == NULL) return -ENOSTR; - if (msg == NULL) return -EINVAL; + if (_msg == NULL) return -EINVAL; if (_nc->c.stream == NULL) return -ENOSR; flatcc_builder_t* B = &_nc->fbs_builder; @@ -61,10 +62,10 @@ int can_write(NCODEC* nc, NCodecMessage* msg) ns(Stream_frames_push_start(B)); ns(CanFrame_start(B)); /* Encode the message. */ - ns(CanFrame_frame_id_add(B, msg->frame_id)); + ns(CanFrame_frame_id_add(B, _msg->frame_id)); + ns(CanFrame_frame_type_add(B, _msg->frame_type)); ns(CanFrame_payload_add( - B, flatbuffers_uint8_vec_create(B, msg->buffer, msg->len))); - ns(CanFrame_frame_type_add(B, ns(FrameTypes_CanFrame))); + B, flatbuffers_uint8_vec_create(B, _msg->buffer, _msg->len))); /* Add additional metadata. */ ns(CanFrame_bus_id_add(B, _nc->bus_id)); ns(CanFrame_node_id_add(B, _nc->node_id)); @@ -73,7 +74,7 @@ int can_write(NCODEC* nc, NCodecMessage* msg) ns(Frame_f_CanFrame_add(B, ns(CanFrame_end(B)))); ns(Stream_frames_push_end(B)); - return msg->len; + return _msg->len; } @@ -137,14 +138,16 @@ static void get_vector_from_message(NCODEC* nc) int can_read(NCODEC* nc, NCodecMessage* msg) { - ABCodecInstance* _nc = (ABCodecInstance*)nc; + ABCodecInstance* _nc = (ABCodecInstance*)nc; + NCodecCanMessage* _msg = (NCodecCanMessage*)msg; if (_nc == NULL) return -ENOSTR; - if (msg == NULL) return -EINVAL; + if (_msg == NULL) return -EINVAL; if (_nc->c.stream == NULL) return -ENOSR; /* Reset the message, in case caller ignores the return value. */ - msg->len = 0; - msg->buffer = NULL; + _msg->len = 0; + _msg->frame_type = CAN_BASE_FRAME; + _msg->buffer = NULL; /* Process the stream/frames. */ if (_nc->msg_ptr == NULL) get_msg_from_stream(nc); @@ -164,15 +167,16 @@ int can_read(NCODEC* nc, NCodecMessage* msg) continue; /* Return the message. */ - msg->frame_id = ns(CanFrame_frame_id(can_frame)); + _msg->frame_id = ns(CanFrame_frame_id(can_frame)); + _msg->frame_type = ns(CanFrame_frame_type(can_frame)); flatbuffers_uint8_vec_t payload = ns(CanFrame_payload(can_frame)); - msg->buffer = + _msg->buffer = (uint8_t*)payload; // TODO think about this cast ... caller // should not modify ... restrict? - msg->len = flatbuffers_uint8_vec_len(payload); + _msg->len = flatbuffers_uint8_vec_len(payload); /* ... but don't forget to save the vector index either. */ _nc->vector_idx = _vi + 1; - return msg->len; + return _msg->len; } /* Next msg/vector? */ diff --git a/dse/ncodec/libs/automotive-bus/tests/CMakeLists.txt b/dse/ncodec/libs/automotive-bus/tests/CMakeLists.txt index 6e0172a..3d2687f 100644 --- a/dse/ncodec/libs/automotive-bus/tests/CMakeLists.txt +++ b/dse/ncodec/libs/automotive-bus/tests/CMakeLists.txt @@ -29,7 +29,7 @@ add_compile_options(${C_CXX_WARNING_FLAGS}) # External Project - Automotive Bus Schema # ------------------------------------------- FetchContent_Declare(automotive-bus-schema - URL https://github.com/boschglobal/automotive-bus-schema/releases/download/v1.0.2/automotive-bus-schema.tar.gz + URL https://github.com/boschglobal/automotive-bus-schema/releases/download/v1.0.3/automotive-bus-schema.tar.gz ) FetchContent_MakeAvailable(automotive-bus-schema) set(SCHEMAS_SOURCE_DIR ${automotive-bus-schema_SOURCE_DIR}/flatbuffers/c) diff --git a/dse/ncodec/libs/automotive-bus/tests/test_can_fbs.c b/dse/ncodec/libs/automotive-bus/tests/test_can_fbs.c index 53990a5..a5dbd0e 100644 --- a/dse/ncodec/libs/automotive-bus/tests/test_can_fbs.c +++ b/dse/ncodec/libs/automotive-bus/tests/test_can_fbs.c @@ -25,7 +25,8 @@ extern int can_read(NCODEC* nc, NCodecMessage* msg); extern int can_flush(NCODEC* nc); extern int stream_seek(NCODEC* nc, size_t pos, int op); extern size_t stream_tell(NCODEC* nc); -extern int stream_read(NCODEC* nc, uint8_t** data, size_t* len, int pos_op); +extern int stream_read(NCODEC* nc, uint8_t** data, size_t* len, + int pos_op); typedef struct Mock { @@ -39,6 +40,7 @@ extern NCodecStreamVTable mem_stream; "application/x-automotive-bus; " \ "interface=stream;type=frame;bus=can;schema=fbs;" \ "bus_id=1;node_id=2;interface_id=3" +#define BUF_NODEID_OFFSET 53 NCODEC* ncodec_open(const char* mime_type, NCodecStreamVTable* stream) @@ -87,14 +89,14 @@ void test_can_fbs_no_stream(void** state) NCODEC* nc = (void*)ncodec_create(MIMETYPE); assert_non_null(nc); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting, .len = strlen(greeting) }); assert_int_equal(rc, -ENOSR); rc = ncodec_flush(nc); assert_int_equal(rc, -ENOSR); - NCodecMessage msg = {}; + NCodecCanMessage msg = {}; rc = ncodec_read(nc, &msg); assert_int_equal(rc, -ENOSR); assert_null(msg.buffer); @@ -139,7 +141,7 @@ void test_can_fbs_truncate(void** state) // Write to the stream. stream_seek(nc, 0, NCODEC_SEEK_RESET); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting, .len = strlen(greeting) }); assert_int_equal(rc, strlen(greeting)); @@ -165,8 +167,8 @@ void test_can_fbs_read_nomsg(void** state) int rc; stream_seek(nc, 0, NCODEC_SEEK_RESET); - NCodecMessage msg = {}; - size_t len = ncodec_read(nc, &msg); + NCodecCanMessage msg = {}; + size_t len = ncodec_read(nc, &msg); assert_int_equal(len, -ENOMSG); assert_int_equal(msg.len, 0); assert_null(msg.buffer); @@ -181,7 +183,7 @@ void test_can_fbs_write(void** state) const char* greeting = "Hello World"; - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting, .len = strlen(greeting) }); assert_int_equal(rc, strlen(greeting)); @@ -208,7 +210,10 @@ void test_can_fbs_readwrite(void** state) // Write and flush a message. stream_seek(nc, 0, NCODEC_SEEK_RESET); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, + + .frame_type = 0, + .buffer = (uint8_t*)greeting, .len = strlen(greeting) }); assert_int_equal(rc, strlen(greeting)); @@ -221,14 +226,16 @@ void test_can_fbs_readwrite(void** state) uint8_t* buffer; size_t buffer_len; stream_read(nc, &buffer, &buffer_len, NCODEC_POS_NC); - buffer[54] = 8; - // for (uint32_t i = 0; i< buffer_len;i+=8) printf("%02x %02x %02x %02x %02x - // %02x %02x %02x\n", - // buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3], - // buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7]); + buffer[BUF_NODEID_OFFSET] = 8; + if (0) { + for (uint32_t i = 0; i < buffer_len; i += 8) + printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", buffer[i + 0], + buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], + buffer[i + 5], buffer[i + 6], buffer[i + 7]); + } // Read the message back. - NCodecMessage msg = {}; + NCodecCanMessage msg = {}; len = ncodec_read(nc, &msg); assert_int_equal(len, strlen(greeting)); assert_int_equal(msg.len, strlen(greeting)); @@ -248,11 +255,11 @@ void test_can_fbs_readwrite_frames(void** state) // Write and flush a message. stream_seek(nc, 0, NCODEC_SEEK_RESET); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting1, .len = strlen(greeting1) }); assert_int_equal(rc, strlen(greeting1)); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting2, .len = strlen(greeting2) }); assert_int_equal(rc, strlen(greeting2)); @@ -264,15 +271,17 @@ void test_can_fbs_readwrite_frames(void** state) uint8_t* buffer; size_t buffer_len; stream_read(nc, &buffer, &buffer_len, NCODEC_POS_NC); - buffer[58] = 8; - buffer[58 + 40] = 8; - // for (uint32_t i = 0; i< len;i+=8) printf("%02x %02x %02x %02x %02x %02x - // %02x %02x\n", - // buffer[i+0], buffer[i+1], buffer[i+2], buffer[i+3], - // buffer[i+4], buffer[i+5], buffer[i+6], buffer[i+7]); + buffer[BUF_NODEID_OFFSET + 4] = 8; + buffer[BUF_NODEID_OFFSET + 4 + 40] = 8; + if (0) { + for (uint32_t i = 0; i < buffer_len; i += 8) + printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", buffer[i + 0], + buffer[i + 1], buffer[i + 2], buffer[i + 3], buffer[i + 4], + buffer[i + 5], buffer[i + 6], buffer[i + 7]); + } // Read the messages back. - NCodecMessage msg = {}; + NCodecCanMessage msg = {}; len = ncodec_read(nc, &msg); assert_int_equal(len, strlen(greeting1)); @@ -293,20 +302,21 @@ void test_can_fbs_readwrite_messages(void** state) Mock* mock = *state; NCODEC* nc = mock->nc; int rc; + size_t len; const char* greeting1 = "Hello World"; const char* greeting2 = "Foo Bar"; // Write and flush a message. stream_seek(nc, 0, NCODEC_SEEK_RESET); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting1, .len = strlen(greeting1) }); assert_int_equal(rc, strlen(greeting1)); - size_t len = ncodec_flush(nc); + len = ncodec_flush(nc); assert_int_equal(len, 0x66); - rc = ncodec_write(nc, &(struct NCodecMessage){ .frame_id = 42, + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, .buffer = (uint8_t*)greeting2, .len = strlen(greeting2) }); assert_int_equal(rc, strlen(greeting2)); @@ -319,11 +329,11 @@ void test_can_fbs_readwrite_messages(void** state) size_t buffer_len; stream_read(nc, &buffer, &buffer_len, NCODEC_POS_NC); assert_int_equal(0xc8, buffer_len); - buffer[54] = 9; - buffer[0x66 + 54] = 7; + buffer[BUF_NODEID_OFFSET] = 9; + buffer[0x66 + BUF_NODEID_OFFSET] = 7; // Read the messages back. - NCodecMessage msg = {}; + NCodecCanMessage msg = {}; len = ncodec_read(nc, &msg); assert_int_equal(len, strlen(greeting1)); @@ -339,6 +349,59 @@ void test_can_fbs_readwrite_messages(void** state) } +typedef struct frame_type_testcase { + uint8_t enum_value; + uint8_t encoded_value; +} frame_type_testcase; + +void test_can_fbs_frame_type(void** state) +{ + Mock* mock = *state; + NCODEC* nc = mock->nc; + int rc; + size_t len; + + const char* greeting = "Hello World"; + frame_type_testcase tc[] = { + { .enum_value = CAN_BASE_FRAME, .encoded_value = 0 }, + { .enum_value = CAN_EXTENDED_FRAME, .encoded_value = 1 }, + { .enum_value = CAN_FD_BASE_FRAME, .encoded_value = 2 }, + { .enum_value = CAN_FD_EXTENDED_FRAME, .encoded_value = 3 }, + }; + + for (uint i = 0; i < ARRAY_SIZE(tc); i++) { + // Write message. + ncodec_truncate(nc); + rc = ncodec_write(nc, &(struct NCodecCanMessage){ .frame_id = 42, + .frame_type = tc[i].enum_value, + .buffer = (uint8_t*)greeting, + .len = strlen(greeting) }); + assert_int_equal(rc, strlen(greeting)); + len = ncodec_flush(nc); + assert_int_equal(len, tc[i].enum_value ? 0x6a : 0x66); + // Seek to the start, keeping the content, modify the node_id. + stream_seek(nc, 0, NCODEC_SEEK_SET); + uint8_t* buffer; + size_t buffer_len; + stream_read(nc, &buffer, &buffer_len, NCODEC_POS_NC); + buffer[BUF_NODEID_OFFSET + (tc[i].enum_value ? 4 : 0)] = 8; + if (0) { + for (uint32_t i = 0; i < buffer_len; i += 8) + printf("%02x %02x %02x %02x %02x %02x %02x %02x\n", + buffer[i + 0], buffer[i + 1], buffer[i + 2], buffer[i + 3], + buffer[i + 4], buffer[i + 5], buffer[i + 6], buffer[i + 7]); + } + // Read message. + NCodecCanMessage msg = {}; + len = ncodec_read(nc, &msg); + assert_int_equal(len, strlen(greeting)); + assert_int_equal(msg.len, strlen(greeting)); + assert_int_equal(msg.frame_type, tc[i].enum_value); + assert_int_equal(tc[i].enum_value, tc[i].encoded_value); + } +} + + int run_can_fbs_tests(void) { void* s = test_setup; @@ -354,6 +417,7 @@ int run_can_fbs_tests(void) cmocka_unit_test_setup_teardown(test_can_fbs_readwrite_frames, s, t), cmocka_unit_test_setup_teardown(test_can_fbs_readwrite_messages, s, t), cmocka_unit_test_setup_teardown(test_can_fbs_truncate, s, t), + cmocka_unit_test_setup_teardown(test_can_fbs_frame_type, s, t), }; return cmocka_run_group_tests_name("CAN FBS", can_fbs_tests, NULL, NULL);