From 278a1cc815c138fb02d88fef769dc1f991855d00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20J=C3=A4ger?= Date: Wed, 6 Mar 2024 17:49:50 +0100 Subject: [PATCH] CAN: Rework multi-frame reports to include MF type --- include/thingset/can.h | 30 +++++++++++++++--------------- src/can.c | 28 ++++++++++++++++++++++++---- tests/can/prj.conf | 2 +- tests/can/src/main.c | 16 +++++++++++----- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/include/thingset/can.h b/include/thingset/can.h index d7334d0..d37e2fd 100644 --- a/include/thingset/can.h +++ b/include/thingset/can.h @@ -44,14 +44,14 @@ extern "C" { * * Multi-frame reports: * - * 28 26 25 24 23 20 19 16 15 13 12 11 8 7 0 - * +----------+-----+-----+---------+------+-----+------+-------------+ - * | Priority | 0x1 | res | src bus | msg# | end | seq# | source addr | - * +----------+-----+-----+---------+------+-----+------+-------------+ + * 28 26 25 24 23 20 19 16 15 14 13 12 11 8 7 0 + * +----------+-----+-----+---------+------+---------+------+-------------+ + * | Priority | 0x1 | res | src bus | msg# | MF type | seq# | source addr | + * +----------+-----+-----+---------+------+---------+------+-------------+ * * Priority: 5 or 7 - * msg#: Wrapping message counter from 0 to 7 - * end: End of message flag + * msg#: Wrapping message counter from 0 to 3 + * MF type: 0: first frame, 1: consecutive frame, 2: last frame, 3: single frame * seq#: Wrapping sequence counter from 0 to 15 * src bus and res: Either source bus or bridge number * @@ -108,21 +108,21 @@ extern "C" { #define THINGSET_CAN_DATA_ID_GET(id) \ (((uint32_t)id & THINGSET_CAN_DATA_ID_MASK) >> THINGSET_CAN_DATA_ID_POS) -/* message number, end flag and sequence number for multi-frame reports */ +/* message number, type and sequence number for multi-frame reports */ #define THINGSET_CAN_SEQ_NO_POS (8U) #define THINGSET_CAN_SEQ_NO_MASK (0xF << THINGSET_CAN_SEQ_NO_POS) #define THINGSET_CAN_SEQ_NO_SET(no) \ (((uint32_t)no << THINGSET_CAN_SEQ_NO_POS) & THINGSET_CAN_SEQ_NO_MASK) #define THINGSET_CAN_SEQ_NO_GET(id) \ (((uint32_t)id & THINGSET_CAN_SEQ_NO_MASK) >> THINGSET_CAN_SEQ_NO_POS) -#define THINGSET_CAN_END_FLAG_POS (12U) -#define THINGSET_CAN_END_FLAG_MASK (0x1 << THINGSET_CAN_END_FLAG_POS) -#define THINGSET_CAN_END_FLAG_SET(val) \ - (((uint32_t)val << THINGSET_CAN_END_FLAG_POS) & THINGSET_CAN_END_FLAG_MASK) -#define THINGSET_CAN_END_FLAG_GET(id) \ - (((uint32_t)id & THINGSET_CAN_END_FLAG_MASK) >> THINGSET_CAN_END_FLAG_POS) -#define THINGSET_CAN_MSG_NO_POS (13U) -#define THINGSET_CAN_MSG_NO_MASK (0x7 << THINGSET_CAN_MSG_NO_POS) +#define THINGSET_CAN_MF_TYPE_POS (12U) +#define THINGSET_CAN_MF_TYPE_MASK (0x3 << THINGSET_CAN_MF_TYPE_POS) +#define THINGSET_CAN_MF_TYPE_FIRST (0U << THINGSET_CAN_MF_TYPE_POS) +#define THINGSET_CAN_MF_TYPE_CONSEC (1U << THINGSET_CAN_MF_TYPE_POS) +#define THINGSET_CAN_MF_TYPE_LAST (2U << THINGSET_CAN_MF_TYPE_POS) +#define THINGSET_CAN_MF_TYPE_SINGLE (3U << THINGSET_CAN_MF_TYPE_POS) +#define THINGSET_CAN_MSG_NO_POS (14U) +#define THINGSET_CAN_MSG_NO_MASK (0x3 << THINGSET_CAN_MSG_NO_POS) #define THINGSET_CAN_MSG_NO_SET(no) \ (((uint32_t)no << THINGSET_CAN_MSG_NO_POS) & THINGSET_CAN_MSG_NO_MASK) #define THINGSET_CAN_MSG_NO_GET(id) \ diff --git a/src/can.c b/src/can.c index 2422cd7..c950a4a 100644 --- a/src/can.c +++ b/src/can.c @@ -63,7 +63,9 @@ static const struct isotp_fast_opts fc_opts = { struct thingset_can_rx_context { uint8_t src_addr; + uint8_t msg; uint8_t seq; + bool started; }; NET_BUF_POOL_DEFINE(thingset_can_rx_buffer_pool, CONFIG_THINGSET_CAN_REPORT_RX_NUM_BUFFERS, @@ -193,12 +195,25 @@ static void thingset_can_report_rx_cb(const struct device *dev, struct can_frame { struct thingset_can *ts_can = user_data; uint8_t source_addr = THINGSET_CAN_SOURCE_GET(frame->id); + uint8_t msg_no = THINGSET_CAN_MSG_NO_GET(frame->id); uint8_t seq = THINGSET_CAN_SEQ_NO_GET(frame->id); struct net_buf *buffer = thingset_can_get_rx_buf(source_addr); if (buffer != NULL) { struct thingset_can_rx_context *context = (struct thingset_can_rx_context *)buffer->user_data; + + if ((frame->id & THINGSET_CAN_MF_TYPE_MASK) == THINGSET_CAN_MF_TYPE_SINGLE + || (frame->id & THINGSET_CAN_MF_TYPE_MASK) == THINGSET_CAN_MF_TYPE_FIRST) + { + context->msg = msg_no; + } + else if (context->msg != msg_no) { + LOG_WRN("Out-of-message frame received"); + thingset_can_free_rx_buf(buffer); + return; + } + if ((context->seq & 0xF) == seq) { int chunk_len = can_dlc_to_bytes(frame->dlc); if (buffer->len + chunk_len > buffer->size) { @@ -209,7 +224,9 @@ static void thingset_can_report_rx_cb(const struct device *dev, struct can_frame uint8_t *buf = net_buf_add(buffer, chunk_len); LOG_DBG("Reassembling %d bytes from ID 0x%08X", chunk_len, frame->id); memcpy(buf, frame->data, chunk_len); - if (THINGSET_CAN_END_FLAG_GET(frame->id) != 0) { + if ((frame->id & THINGSET_CAN_MF_TYPE_MASK) == THINGSET_CAN_MF_TYPE_SINGLE + || (frame->id & THINGSET_CAN_MF_TYPE_MASK) == THINGSET_CAN_MF_TYPE_LAST) + { LOG_DBG("Finished; dispatching %d bytes from node %x", buffer->len, source_addr); ts_can->report_rx_cb(buffer->data, buffer->len, source_addr); thingset_can_free_rx_buf(buffer); @@ -218,8 +235,8 @@ static void thingset_can_report_rx_cb(const struct device *dev, struct can_frame context->seq++; } else { - /* out-of-sequence message received, so free the buffer */ - LOG_WRN("Out-of-sequence message received"); + /* out-of-sequence frame received, so free the buffer */ + LOG_WRN("Out-of-sequence frame received"); thingset_can_free_rx_buf(buffer); } } @@ -257,16 +274,19 @@ int thingset_can_send_report_inst(struct thingset_can *ts_can, const char *path, }; do { + uint32_t mf_type; if (len - pos > CAN_MAX_DLEN) { chunk_len = CAN_MAX_DLEN; + mf_type = (pos == 0) ? THINGSET_CAN_MF_TYPE_FIRST : THINGSET_CAN_MF_TYPE_CONSEC; } else { chunk_len = len - pos; end = true; + mf_type = (pos == 0) ? THINGSET_CAN_MF_TYPE_SINGLE : THINGSET_CAN_MF_TYPE_LAST; } memcpy(frame.data, tx_buf->data + pos, chunk_len); frame.id = THINGSET_CAN_PRIO_REPORT_LOW | THINGSET_CAN_TYPE_MF_REPORT - | THINGSET_CAN_MSG_NO_SET(ts_can->msg_no) | THINGSET_CAN_END_FLAG_SET(end) + | THINGSET_CAN_MSG_NO_SET(ts_can->msg_no) | mf_type | THINGSET_CAN_SEQ_NO_SET(seq) | THINGSET_CAN_SOURCE_SET(ts_can->node_addr); frame.dlc = can_bytes_to_dlc(chunk_len); if (end && IS_ENABLED(CONFIG_CAN_FD_MODE)) { diff --git a/tests/can/prj.conf b/tests/can/prj.conf index 66c582f..f06901a 100644 --- a/tests/can/prj.conf +++ b/tests/can/prj.conf @@ -24,4 +24,4 @@ CONFIG_ZTEST_NEW_API=y CONFIG_ZTEST_SUMMARY=n # enable click-able absolute paths in assert messages -#CONFIG_BUILD_OUTPUT_STRIP_PATHS=n +CONFIG_BUILD_OUTPUT_STRIP_PATHS=n diff --git a/tests/can/src/main.c b/tests/can/src/main.c index 5c63499..ececd58 100644 --- a/tests/can/src/main.c +++ b/tests/can/src/main.c @@ -116,13 +116,13 @@ ZTEST(thingset_can, test_receive_packetized_report) struct can_frame report_frames[] = { { - .id = 0x1D000002, /* node with address 0x02, seq 0x0, msg 0x0 */ + .id = 0x1D000002, /* msg 0x0, first frame, seq 0x0 */ .flags = CAN_FRAME_IDE, .data = { 0x1F, 0x19, 0x12, 0x34, 0x6B, 0x68, 0x65, 0x6C }, .dlc = 8, }, { - .id = 0x1D001102, /* node with address 0x02, seq 0x1, msg 0x0, end = true */ + .id = 0x1D002102, /* msg 0x0, last frame, seq 0x1 */ .flags = CAN_FRAME_IDE, .data = { 0x6C, 0x6F, 0x20, 0x77, 0x6F, 0x72, 0x6C, 0x64 }, .dlc = 8, @@ -171,13 +171,19 @@ ZTEST(thingset_can, test_send_packetized_report) for (uint32_t seq = 0; seq * CAN_MAX_DLEN < strlen(report_exp); seq++) { int missing_len = strlen(report_exp) - seq * CAN_MAX_DLEN; - uint32_t end = missing_len <= CAN_MAX_DLEN ? 0x00001000 : 0; + uint32_t mf_type; + if (missing_len > CAN_MAX_DLEN) { + mf_type = (seq == 0) ? 0x00000000 : 0x00001000; + } + else { + mf_type = (seq == 0) ? 0x00003000 : 0x00002000; + } err = k_msgq_get(&report_packets_msgq, &rx_frame, K_MSEC(100)); zassert_equal(err, 0, "receiving CAN frame %d timed out", seq); - zassert_equal(rx_frame.id, 0x1d000001 | ((msg_no & 0x7) << 13) | end | (seq << 8), + zassert_equal(rx_frame.id, 0x1d000001 | ((msg_no & 0x3) << 14) | mf_type | (seq << 8), "CAN ID 0x%x for seq %d of msg %d not correct", rx_frame.id, seq, msg_no); zassert_mem_equal(rx_frame.data, report_exp + seq * CAN_MAX_DLEN, - end ? missing_len : CAN_MAX_DLEN); + MIN(missing_len, CAN_MAX_DLEN)); } }