Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CAN: Rework multi-frame reports to include MF type #27

Merged
merged 1 commit into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 15 additions & 15 deletions include/thingset/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down Expand Up @@ -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) \
Expand Down
34 changes: 30 additions & 4 deletions src/can.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -193,12 +195,31 @@ 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;
context->started = true;
}
else if (context->msg != msg_no) {
LOG_WRN("Out-of-message frame received");
thingset_can_free_rx_buf(buffer);
return;
}
else if (!context->started) {
LOG_WRN("Missing first frame");
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) {
Expand All @@ -209,7 +230,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);
Expand All @@ -218,8 +241,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);
}
}
Expand Down Expand Up @@ -257,16 +280,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)) {
Expand Down
2 changes: 1 addition & 1 deletion tests/can/prj.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
16 changes: 11 additions & 5 deletions tests/can/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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));
}
}

Expand Down
Loading