/** * @file tests/can_framing.cpp * @brief brief * @date Aug 25, 2015 * @author rheijden * @copyright 2015 Dual Inventive Technology Centre B.V. * * descr */ #include "tests/can.h" #include #include #include static struct di_can_ctx can_ctx; DI_CAN_MSG_DECL_ARRAY(can_msg_list, DI_CAN_CFG_MSG_SIZE, DI_CAN_CFG_MSG_DATA_SIZE); static size_t g_can_send_bytes = 0; static size_t g_can_send_frames = 0; /** * Test send callback */ static di_errno_t test_can_send_cb(const struct di_can_frame_tx *frame) { g_can_send_frames += 1; g_can_send_bytes += frame->size; return DNOK; } /** * Test send helper function * @param m Message to send * @param payload_size Size of the payload in bytes to send * @param exp_frames Expected frame count to be send * @param exp_bytes Bytes expected */ static void test_send(struct di_can_msg *m, size_t payload_size, size_t exp_frames, size_t exp_bytes) { const uint8_t transaction_id = di_can_framing_get_transaction_id(&can_ctx); /* Reset framing bytes and frames counter */ g_can_send_bytes = 0; g_can_send_frames = 0; m->size = payload_size; if (payload_size > DI_CAN_FRAMING_SIZE_MAX) { printf("--- expect: DNE_CAN_INVAL, payload_size(%zu) > DI_CAN_FRAMING_SIZE_MAX(%u)\n", payload_size, DI_CAN_FRAMING_SIZE_MAX); ASSERT_EQ(DNE_CAN_INVAL, di_can_framing_send(&can_ctx, m, transaction_id)); return; } printf("--- expect: bytes: %zu, frames: %zu\n", exp_bytes, exp_frames); ASSERT_EQ(DNOK, di_can_framing_send(&can_ctx, m, transaction_id)); printf("--- got: bytes: %zu, frames %zu\n", g_can_send_bytes, g_can_send_frames); ASSERT_EQ(exp_bytes, g_can_send_bytes); ASSERT_EQ(exp_frames, g_can_send_frames); } /** * Initialize can stack context */ TEST(can_frame, init) { DI_CAN_MSG_INIT_ARRAY(&can_ctx, can_msg_list, DI_CAN_CFG_MSG_SIZE, DI_CAN_CFG_MSG_DATA_SIZE); di_can_init(&can_ctx); di_can_msg_init(&can_ctx, can_msg_list, DI_CAN_CFG_MSG_SIZE); } TEST(can_framing, send) { struct di_can_msg *m; di_can_callback_set_send(&can_ctx, test_can_send_cb); /* Get unused message */ m = di_can_msg_alloc(&can_ctx); ASSERT_NE((void *)NULL, m); printf("DI_CAN_FRAMING_SIZE_MAX: %u\n", DI_CAN_FRAMING_SIZE_MAX); /** Flush buffer, point msg to a valid place @todo do we really need to flush? */ di_buffer_flush(m->buf); m->msg = (uint8_t *)m->buf->data; /** payload_size, frames_expected, bytes_expected */ test_send(m, 0, 1, DI_CAN_FRAME_SIZE); // 1 frame, 0 bytes payload -> SFT, 8 bytes test_send(m, 1, 3, DI_CAN_MSG_SIZE_MFT + 1); // 3 frames, 1 bytes payload -> MFT, 8 + 5 + 1 bytes test_send(m, 8, 3, DI_CAN_MSG_SIZE_MFT + 8); // 3 frames, 8 bytes payload -> MFT, 8 + 5 + 8 bytes test_send(m, 9, 4, DI_CAN_MSG_SIZE_MFT + 9); // 4 frames, 9 bytes payload -> MFT, 8 + 5 + 9 bytes test_send(m, DI_CAN_FRAMING_SIZE_MAX, DI_CAN_FRAME_ID_MAX_COUNT, DI_CAN_MSG_SIZE_MFT + DI_CAN_FRAME_SIZE * 510); test_send(m, DI_CAN_FRAMING_SIZE_MAX + 1, DI_CAN_FRAME_ID_MAX_COUNT, DI_CAN_MSG_SIZE_MFT + DI_CAN_FRAME_SIZE * 510); di_can_msg_free(&m); } /** * Test can framing send fails gracefull */ static size_t g_can_send_frames_fail = 0; /** * Test send callback (returns error) */ static di_errno_t test_can_send_cb_fail(const struct di_can_frame_tx *frame) { (void)frame; if (g_can_send_frames == g_can_send_frames_fail) return DNE_CAN_IO; g_can_send_frames++; return DNOK; } /** * Helper function to test send failed * Messages <= DI_CAN_FRAMING_SIZE_MAX (1024 bytes, 1KByte) are valid * Messages > 1KByte trying to frame will result in DNE_CAN_INVAL * The DNE_CAN_IO error is returned by the callback */ static void test_send_fail(struct di_can_msg *m, size_t payload_size, size_t fail_frame_idx) { g_can_send_frames = 0; g_can_send_frames_fail = fail_frame_idx; m->size = payload_size; m->msg = m->buf->data; /* Message pointer needs to point to the payload to calculate the CRC */ EXPECT_EQ(DNE_CAN_IO, di_can_framing_send(&can_ctx, m, 0)); } TEST(can_framing, send_fail) { struct di_can_msg *m; di_can_callback_set_send(&can_ctx, test_can_send_cb_fail); m = di_can_msg_alloc(&can_ctx); ASSERT_NE((void *)NULL, m); test_send_fail(m, 0, DI_CAN_FRAME_ID_SRC_DST_NODEID); test_send_fail(m, DI_CAN_FRAME_SIZE, DI_CAN_FRAME_ID_MFT_METADATA); /* Test di_can_framing_send_payload */ test_send_fail(m, (16 * DI_CAN_FRAME_SIZE), DI_CAN_FRAME_ID_MFT_METADATA + 8); test_send_fail(m, (16 * DI_CAN_FRAME_SIZE), DI_CAN_FRAME_ID_MFT_METADATA + 15); test_send_fail(m, (16 * DI_CAN_FRAME_SIZE), DI_CAN_FRAME_ID_MFT_METADATA + 16); di_can_msg_free(&m); } /** * Check if the transaction_id is correctly updated */ TEST(can_framing, update_transaction_id) { uint8_t transaction_id; /* Send one message and check transaction id */ can_ctx.transaction = 0; transaction_id = di_can_framing_get_transaction_id(&can_ctx); ASSERT_EQ(0U, transaction_id); ASSERT_EQ(1U, can_ctx.transaction); /* Send multiple and see if the counter wraps */ can_ctx.transaction = 0; for (size_t n = 0; n < (DI_CAN_TRANSACTION_LAST + 4); n++) transaction_id = di_can_framing_get_transaction_id(&can_ctx);; ASSERT_EQ(2U, transaction_id); ASSERT_EQ(3U, can_ctx.transaction); } TEST(can_framing, send_mft_meta_crc_error) { struct di_can_msg *msg = di_can_msg_alloc(&can_ctx); di_can_callback_set_send(&can_ctx, test_can_send_cb); ASSERT_NE((void *)NULL, msg); msg->msg = NULL; msg->size = 1; ASSERT_EQ(DNE_CAN_INVAL, di_can_framing_send(&can_ctx, msg, 0)); di_can_msg_free(&msg); }