blob: 1085c103993e358d0777b078c2f6a23be06b7f62 [file] [log] [blame]
/*
* Copyright (c) 2019 Alexander Wachter
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <drivers/can.h>
#include <ztest.h>
#include <strings.h>
/*
* @addtogroup t_can_driver
* @{
* @defgroup t_can_timing test_basic_can_timing
* @brief TestPurpose: verify timing algorithm
* @details
* - Test Steps
* -# Calculate timing for a sample
* -# Verify sample point
* -# verify bitrate
* - Expected Results
* -# All tests MUST pass
* @}
*/
#if defined(CONFIG_CAN_LOOPBACK_DEV_NAME)
#define CAN_DEVICE_NAME CONFIG_CAN_LOOPBACK_DEV_NAME
#else
#define CAN_DEVICE_NAME DT_CHOSEN_ZEPHYR_CAN_PRIMARY_LABEL
#endif
const struct device *can_dev;
struct timing_samples {
uint32_t bitrate;
uint16_t sp;
bool inval;
};
const struct timing_samples samples[] = {
{125000, 875, false},
{500000, 875, false},
{1000000, 875, false},
{125000, 900, false},
{125000, 800, false},
#ifdef CONFIG_CAN_FD_MODE
{1000000 + 1, 875, true},
#else
{8000000 + 1, 875, true},
#endif
{125000, 1000, true},
};
/*
* Bitrate must match exactly
*/
static void verify_bitrate(struct can_timing *timing, uint32_t bitrate)
{
const uint32_t ts = 1 + timing->prop_seg + timing->phase_seg1 +
timing->phase_seg2;
uint32_t core_clock;
uint32_t bitrate_calc;
int ret;
zassert_not_equal(timing->prescaler, 0, "Prescaler is zero");
ret = can_get_core_clock(can_dev, &core_clock);
zassert_equal(ret, 0, "Unable to get core clock");
bitrate_calc = core_clock / timing->prescaler / ts;
zassert_equal(bitrate, bitrate_calc, "Bitrate missmatch");
}
/*
* SP must be withing the margin and in bound of the limits
*/
static void verify_sp(struct can_timing *timing, uint16_t sp,
uint16_t sp_margin)
{
const struct can_driver_api *api =
(const struct can_driver_api *)can_dev->api;
const struct can_timing *max = &api->timing_max;
const struct can_timing *min = &api->timing_min;
uint32_t ts = 1 + timing->prop_seg + timing->phase_seg1 +
timing->phase_seg2;
uint16_t sp_calc =
((1 + timing->prop_seg + timing->phase_seg1) * 1000) / ts;
zassert_true(timing->prop_seg <= max->prop_seg, "prop_seg exceeds max");
zassert_true(timing->phase_seg1 <= max->phase_seg1,
"phase_seg1 exceeds max");
zassert_true(timing->phase_seg2 <= max->phase_seg2,
"phase_seg2 exceeds max");
zassert_true(timing->prop_seg >= min->prop_seg,
"prop_seg lower than min");
zassert_true(timing->phase_seg1 >= min->phase_seg1,
"phase_seg1 lower than min");
zassert_true(timing->phase_seg2 >= min->phase_seg2,
"phase_seg2 lower than min");
zassert_within(sp, sp_calc, sp_margin, "SP error %d [%d] not within %d",
sp_calc, sp, sp_margin);
}
/*
* Verify the result of the algorithm
*/
static void test_verify_algo(void)
{
struct can_timing timing = {0};
int ret;
for (int i = 0; i < ARRAY_SIZE(samples); ++i) {
ret = can_calc_timing(can_dev, &timing, samples[i].bitrate,
samples[i].sp);
if (samples[i].inval) {
zassert_equal(ret, -EINVAL,
"ret value %d not -EINVAL", ret);
continue;
}
zassert_true(ret >= 0, "Unknown error %d", ret);
/* For the given values, we expect a sp error < 10% */
zassert_true(ret < 100, "Huge sample point error %d", ret);
verify_sp(&timing, samples[i].sp, ret);
verify_bitrate(&timing, samples[i].bitrate);
}
}
void test_main(void)
{
can_dev = device_get_binding(CAN_DEVICE_NAME);
zassert_not_null(can_dev, "Device not found");
ztest_test_suite(can_timing,
ztest_unit_test(test_verify_algo));
ztest_run_test_suite(can_timing);
}