From 5847e01156cb22e8b0dc0c82f04eb3cc6fc0d85c Mon Sep 17 00:00:00 2001 From: "David J. Fiddes" <35607151+davefiddes@users.noreply.github.com> Date: Mon, 24 Jun 2024 19:28:15 +0100 Subject: [PATCH] Unit test fixes to support CAN mapping fixes (#44) * Fix unit tests Update the test_vcu unit test to follow recent evolution of CAN and libopencm3 interface changes. Update the Makefile to reflect the current names of the CTRL_xxx defines and add the new GITHUB_RUN_NUMBER define. Ensure that the GitHub Action builds and runs the unit tests again. Tests: - Build and run the updated unit tests demuddle CI changes * Move the unit test stub CanHardware into its own module To allow more than one unit test that accesses the CAN hardware move the stub implementation into its own module. Tests: - Run the updated unit tests * Basic canmap test outline * Unit test CanMap transmit mapping For a wide variety of little/big-endian, offsets and lengths verify that mapping these into a CAN frame results in the expected contents. Tests: - Verify many failures are reported, clearly when running the current libopeninv - Verify no failures with the fixes in libopeninv PR#18 * Unit test CanMap receive mapping For a wide variety of little/big-endian, offsets and lengths verify that mapping a parameter from a CAN frame results in the expected contents. Tests: - Verify many failures are reported, clearly when running the current libopeninv - Verify no failures with the fixes in libopeninv PR#18 * Ensure unit test failure line numbers are shown in decimal When unit tests use std::hex to print failure information the line numbers printed by the ASSERT() macro are printed in hex as well. This is less than helpful so ensure they are always printed in decimal. * Unit test CAN map add validation Validate all of the different ways it is possible to incorrectly specify a can mapping through the "can tx" or "can rx" command with a unit test. Tests: - Verify many failures are reported, clearly when running the current libopeninv - Verify no failures with the fixes in libopeninv PR#18 --- .github/workflows/CI-build.yml | 16 +- test/Makefile | 11 +- test/stub_canhardware.cpp | 45 ++ test/stub_canhardware.h | 48 ++ test/stub_libopencm3.c | 49 ++ test/test.h | 2 +- test/test_canmap.cpp | 862 +++++++++++++++++++++++++++++++++ test/test_vcu.cpp | 36 +- 8 files changed, 1028 insertions(+), 41 deletions(-) create mode 100644 test/stub_canhardware.cpp create mode 100644 test/stub_canhardware.h create mode 100644 test/stub_libopencm3.c create mode 100644 test/test_canmap.cpp diff --git a/.github/workflows/CI-build.yml b/.github/workflows/CI-build.yml index fc005fe..36850ce 100644 --- a/.github/workflows/CI-build.yml +++ b/.github/workflows/CI-build.yml @@ -51,13 +51,11 @@ jobs: with: name: FOC firmware hex path: stm32_foc.hex - -# Unit tests are currently broken so don't build and run them for now -#- name: Build unit tests on host -# run: | -# make -C test -# -# - name: Run unit tests on host -# run: | -# test/test_sine + - name: Build unit tests on host + run: | + make -C test + + - name: Run unit tests on host + run: | + test/test_sine diff --git a/test/Makefile b/test/Makefile index 4dcfb44..e030ea4 100644 --- a/test/Makefile +++ b/test/Makefile @@ -3,13 +3,20 @@ CPP = g++ LD = g++ CP = cp CFLAGS = -std=c99 -ggdb -DSTM32F1 -I../include -I../libopeninv/include -I../libopencm3/include -CPPFLAGS = -ggdb -DSTM32F1 -DCONTROL_FOC=1 -DCONTROL_SINE=0 -DCONTROL=DCONTROL_FOC -I../include -I../libopeninv/include -I../libopencm3/include +CPPFLAGS = -ggdb -DSTM32F1 -DCTRL_FOC=1 -DCTRL_SINE=0 -DCTRL=CTRL_FOC -I../include -I../libopeninv/include -I../libopencm3/include LDFLAGS = -g BINARY = test_sine OBJS = test_main.o fu.o test_fu.o test_fp.o test_vcu.o my_fp.o my_string.o params.o vehiclecontrol.o \ - test_throttle.o throttle.o sine_core.o temp_meas.o + test_throttle.o throttle.o sine_core.o temp_meas.o stub_canhardware.o test_canmap.o canmap.o \ + stub_libopencm3.o VPATH = ../src ../libopeninv/src +# Check if the variable GITHUB_RUN_NUMBER exists. When running on the github actions running, this +# variable is automatically available. +# Create a compiler define with the content of the variable. Or, if it does not exist, use replacement value 99999. +CPPFLAGS += $(shell \ + if [ -z "$$GITHUB_RUN_NUMBER" ]; then echo "-DGITHUB_RUN_NUMBER=0"; else echo "-DGITHUB_RUN_NUMBER=$$GITHUB_RUN_NUMBER"; fi ) + all: $(BINARY) $(BINARY): $(OBJS) diff --git a/test/stub_canhardware.cpp b/test/stub_canhardware.cpp new file mode 100644 index 0000000..c82b5a8 --- /dev/null +++ b/test/stub_canhardware.cpp @@ -0,0 +1,45 @@ +/* + * This file is part of the stm32-sine project. + * + * Copyright (C) 2021 Johannes Huebner + * Copyright (C) 2024 David J. Fiddes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "stub_canhardware.h" + +CanCallback* vcuCan = nullptr; +uint32_t vcuCanId; + +CanHardware::CanHardware() +{} + +bool CanHardware::AddCallback(CanCallback* cb) +{ + vcuCan = cb; + return true; +} + +bool CanHardware::RegisterUserMessage(uint32_t canId, uint32_t mask) +{ + vcuCanId = canId; + return true; +} + +void CanHardware::ClearUserMessages() {} + +void CanHardware::HandleRx(uint32_t canId, uint32_t data[2], uint8_t dlc) +{ + vcuCan->HandleRx(canId, data, dlc); +} diff --git a/test/stub_canhardware.h b/test/stub_canhardware.h new file mode 100644 index 0000000..13331cb --- /dev/null +++ b/test/stub_canhardware.h @@ -0,0 +1,48 @@ +/* + * This file is part of the stm32-sine project. + * + * Copyright (C) 2021 Johannes Huebner + * Copyright (C) 2024 David J. Fiddes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef TEST_CANHARDWARE_H +#define TEST_CANHARDWARE_H + +#include "canhardware.h" +#include +#include +#include + +class CanStub: public CanHardware +{ + void SetBaudrate(enum baudrates baudrate) {} + void Send(uint32_t canId, uint32_t data[2], uint8_t len) + { + m_canId = canId; + memcpy(&m_data[0], &data[0], sizeof(m_data)); + m_len = len; + } + virtual void ConfigureFilters() {} + +public: + std::array m_data; + uint8_t m_len; + uint32_t m_canId; +}; + +extern CanCallback* vcuCan; +extern uint32_t vcuCanId; + +#endif // TEST_CANHARDWARE_H \ No newline at end of file diff --git a/test/stub_libopencm3.c b/test/stub_libopencm3.c new file mode 100644 index 0000000..3197cd4 --- /dev/null +++ b/test/stub_libopencm3.c @@ -0,0 +1,49 @@ +/* + * This file is part of the stm32-sine project. + * + * Copyright (C) 2024 David J. Fiddes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "stdint.h" + +void flash_unlock(void) +{ +} + +void flash_lock(void) +{ +} + +void flash_set_ws(uint32_t ws) +{ +} + +void flash_program_word(uint32_t address, uint32_t data) +{ +} + +void flash_erase_page(uint32_t page_address) +{ +} + +uint16_t desig_get_flash_size(void) +{ + return 8; +} + +uint32_t crc_calculate(uint32_t data) +{ + return 0xaa55; +} diff --git a/test/test.h b/test/test.h index 5794842..0c88731 100644 --- a/test/test.h +++ b/test/test.h @@ -29,7 +29,7 @@ extern int _failedAssertions; std::cout << "Test " << __FILE__ << "::" << __func__ << " passed." << std::endl; \ else \ { \ - std::cout << "Assertion failed: " << STRING(c) << " in " __FILE__ " : " << __LINE__ << std::endl; \ + std::cout << "Assertion failed: " << STRING(c) << " in " __FILE__ " : " << std::dec << __LINE__ << std::endl; \ _failedAssertions++; \ } diff --git a/test/test_canmap.cpp b/test/test_canmap.cpp new file mode 100644 index 0000000..9899092 --- /dev/null +++ b/test/test_canmap.cpp @@ -0,0 +1,862 @@ +/* + * This file is part of the stm32-sine project. + * + * Copyright (C) 2024 David J. Fiddes + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "canhardware.h" +#include "canmap.h" +#include "params.h" +#include "stub_canhardware.h" +#include "test.h" + +#include +#include +#include +#include +#include +#include +#include + +class CanMapTest : public UnitTest +{ +public: + explicit CanMapTest(const std::list* cases) : UnitTest(cases) + { + } + virtual void TestCaseSetup(); +}; + +std::unique_ptr canStub; +std::unique_ptr canMap; + +void CanMapTest::TestCaseSetup() +{ + canStub = std::make_unique(); + canMap = std::make_unique(canStub.get(), false); + Param::LoadDefaults(); +} + +const uint32_t CanId = 0x123; + +std::ostream& operator<<(std::ostream& o, const std::array& data) +{ + for (const auto& element : data) + { + o << "0x" << std::setfill('0') << std::setw(2) << std::hex + << (int)element << " "; + } + return o; +} + +bool FrameMatches(const std::array& expected) +{ + if (canStub->m_canId != CanId) + { + std::cout << "CAN ID doesn't match. Expected: " << CanId + << " Actual: " << canStub->m_canId << "\n"; + return false; + } + + if (canStub->m_len != 8) + { + std::cout << "CAN frame length doesn't match. Expected: 8 " + << "Actual: " << canStub->m_len << "\n"; + return false; + } + + if (canStub->m_data != expected) + { + std::cout << "CAN frame data doesn't match.\n" + << "Actual : " << canStub->m_data << "\n" + << "Expected: " << expected << "\n"; + + return false; + } + + return true; +} + +static void SendFrame(const std::array& frame) +{ + canStub->HandleRx(CanId, (uint32_t*)&frame[0], 8); +} + +static void send_map_little_endian_byte_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 0, 8, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0x42, 0, 0, 0, 0, 0, 0, 0 })); +} + +static void send_map_little_endian_16_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 0, 16, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0x42, 0, 0, 0, 0, 0, 0, 0 })); +} + +static void send_map_little_endian_32_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 0, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0x42, 0, 0, 0, 0, 0, 0, 0 })); +} + +static void send_map_little_endian_32_bit_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 32, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0x42, 0, 0, 0 })); +} + +static void send_map_little_endian_negative_number_16_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 0, 16, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0xfe, 0xff, 0, 0, 0, 0, 0, 0 })); +} + +static void send_map_little_endian_negative_number_24_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 0, 24, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0xfe, 0xff, 0xff, 0, 0, 0, 0, 0 })); +} + +static void send_map_little_endian_negative_number_32_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 0, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0xfe, 0xff, 0xff, 0xff, 0, 0, 0, 0 })); +} + +static void send_map_little_endian_negative_number_32_bit_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 32, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0xfe, 0xff, 0xff, 0xff })); +} + +static void send_map_little_endian_negative_number_32_bit_spanning_both_words() +{ + canMap->AddSend(Param::ocurlim, CanId, 16, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0xfe, 0xff, 0xff, 0xff, 0, 0 })); +} + +static void send_map_little_endian_negative_number_32_bit_mostly_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 8, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0xfe, 0xff, 0xff, 0xff, 0, 0, 0 })); +} + +static void +send_map_little_endian_negative_number_32_bit_mostly_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 24, 32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0xfe, 0xff, 0xff, 0xff, 0 })); +} + +static void send_map_little_endian_negative_number_16_bit_at_end_of_frame() +{ + canMap->AddSend(Param::ocurlim, CanId, 48, 16, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0, 0, 0xfe, 0xff })); +} + +static void send_map_big_endian_byte_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 7, -8, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0x42, 0, 0, 0, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_16_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 23, -16, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0x42, 0, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_32_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 31, -32, 1.0, 0); + Param::SetFloat(Param::ocurlim, 0x42); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0x42, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_byte_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 7, -8, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0xfe, 0, 0, 0, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_16_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 23, -16, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0xff, 0xfe, 0, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_24_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 23, -24, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0xff, 0xff, 0xfe, 0, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_32_bit_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 31, -32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0xff, 0xff, 0xff, 0xfe, 0, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_byte_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 39, -8, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0xfe, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_16_bit_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 47, -16, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0xff, 0xfe, 0, 0 })); +} + +static void send_map_big_endian_negative_24_bit_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 55, -24, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0xff, 0xff, 0xfe, 0 })); +} + +static void send_map_big_endian_negative_32_bit_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 63, -32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xfe })); +} + +static void send_map_big_endian_negative_number_24_bit_at_end_of_frame() +{ + canMap->AddSend(Param::ocurlim, CanId, 63, -24, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0, 0, 0xff, 0xff, 0xfe })); +} + +static void send_map_big_endian_negative_16_bit_spanning_both_words() +{ + canMap->AddSend(Param::ocurlim, CanId, 39, -16, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0xff, 0xfe, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_32_bit_spanning_both_words() +{ + canMap->AddSend(Param::ocurlim, CanId, 47, -32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0xff, 0xff, 0xff, 0xfe, 0, 0 })); +} + +static void send_map_big_endian_negative_32_bit_mostly_in_first_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 39, -32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0xff, 0xff, 0xff, 0xfe, 0, 0, 0 })); +} + +static void send_map_big_endian_negative_32_bit_mostly_in_second_word() +{ + canMap->AddSend(Param::ocurlim, CanId, 55, -32, 1.0, 0); + Param::SetFloat(Param::ocurlim, -2); + + canMap->SendAll(); + + ASSERT(FrameMatches({ 0, 0, 0, 0xff, 0xff, 0xff, 0xfe, 0 })); +} + +static void receive_map_little_endian_byte_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 8, 1.0, 0); + + SendFrame({ 42, 0, 0, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_little_endian_16_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 16, 1.0, 0); + + SendFrame({ 42, 0, 0, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_little_endian_32_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 32, 1.0, 0); + + SendFrame({ 42, 0, 0, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_little_endian_32_bit_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 32, 32, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 42, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_little_endian_negative_number_16_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 16, 1.0, 0); + + SendFrame({ 0xfe, 0xff, 0, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_little_endian_negative_number_24_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 24, 1.0, 0); + + SendFrame({ 0xfe, 0xff, 0xff, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_little_endian_negative_number_31_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 1, 31, 1.0, 0); + + SendFrame({ 0xfc, 0xff, 0xff, 0xff, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_little_endian_negative_number_32_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 32, 1.0, 0); + + SendFrame({ 0xfe, 0xff, 0xff, 0xff, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_little_endian_negative_number_32_bit_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 32, 32, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0xfe, 0xff, 0xff, 0xff }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void +receive_map_little_endian_negative_number_32_bit_spanning_both_words() +{ + canMap->AddRecv(Param::ocurlim, CanId, 16, 32, 1.0, 0); + + SendFrame({ 0, 0, 0xfe, 0xff, 0xff, 0xff, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void +receive_map_little_endian_negative_number_32_bit_mostly_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 8, 32, 1.0, 0); + + SendFrame({ 0, 0xfe, 0xff, 0xff, 0xff, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void +receive_map_little_endian_negative_number_32_bit_mostly_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 24, 32, 1.0, 0); + + SendFrame({ 0, 0, 0, 0xfe, 0xff, 0xff, 0xff, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_little_endian_negative_number_16_bit_at_end_of_frame() +{ + canMap->AddRecv(Param::ocurlim, CanId, 48, 16, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0, 0, 0xfe, 0xff }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_byte_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 7, -8, 1.0, 0); + + SendFrame({ 42, 0, 0, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_big_endian_16_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 23, -16, 1.0, 0); + + SendFrame({ 0, 0, 42, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_big_endian_31_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 31, -31, 1.0, 0); + + SendFrame({ 0x80, 0, 0, 42, 0x80, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_big_endian_32_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 31, -32, 1.0, 0); + + SendFrame({ 0, 0, 0, 42, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == 42); +} + +static void receive_map_big_endian_negative_byte_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 7, -8, 1.0, 0); + + SendFrame({ 0xfe, 0, 0, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_16_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 23, -16, 1.0, 0); + + SendFrame({ 0, 0xff, 0xfe, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_24_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 23, -24, 1.0, 0); + + SendFrame({ 0xff, 0xff, 0xfe, 0, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_31_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 31, -31, 1.0, 0); + + SendFrame({ 0x7f, 0xff, 0xff, 0xfe, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_32_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 31, -32, 1.0, 0); + + SendFrame({ 0xff, 0xff, 0xff, 0xfe, 0, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_byte_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 39, -8, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0xfe, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_16_bit_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 47, -16, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0xff, 0xfe, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_24_bit_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 55, -24, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0xff, 0xff, 0xfe, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_32_bit_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 63, -32, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xfe }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_number_24_bit_at_end_of_frame() +{ + canMap->AddRecv(Param::ocurlim, CanId, 63, -24, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0, 0xff, 0xff, 0xfe }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_16_bit_spanning_both_words() +{ + canMap->AddRecv(Param::ocurlim, CanId, 39, -16, 1.0, 0); + + SendFrame({ 0, 0, 0, 0xff, 0xfe, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_32_bit_spanning_both_words() +{ + canMap->AddRecv(Param::ocurlim, CanId, 47, -32, 1.0, 0); + + SendFrame({ 0, 0, 0xff, 0xff, 0xff, 0xfe, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_32_bit_mostly_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 39, -32, 1.0, 0); + + SendFrame({ 0, 0xff, 0xff, 0xff, 0xfe, 0, 0, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_big_endian_negative_32_bit_mostly_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 55, -32, 1.0, 0); + + SendFrame({ 0, 0, 0, 0xff, 0xff, 0xff, 0xfe, 0 }); + + ASSERT(Param::GetInt(Param::ocurlim) == -2); +} + +static void receive_map_little_endian_single_bit_first_bit() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, 1, 1.0, 0); + + SendFrame({ 0x1, 0, 0, 0, 0, 0, 0, 0 }); + ASSERT(Param::GetBool(Param::ocurlim)); + + SendFrame({ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); + ASSERT(!Param::GetBool(Param::ocurlim)); +} + +static void receive_map_big_endian_single_bit_first_bit() +{ + canMap->AddRecv(Param::ocurlim, CanId, 0, -1, 1.0, 0); + + SendFrame({ 0x80, 0, 0, 0, 0, 0, 0, 0 }); + ASSERT(Param::GetBool(Param::ocurlim)); + + SendFrame({ 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }); + ASSERT(!Param::GetBool(Param::ocurlim)); +} + +static void receive_map_little_endian_single_bit_last_bit() +{ + canMap->AddRecv(Param::ocurlim, CanId, 63, 1, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0, 0, 0, 0x80 }); + ASSERT(Param::GetBool(Param::ocurlim)); + + SendFrame({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }); + ASSERT(!Param::GetBool(Param::ocurlim)); +} + +static void receive_map_big_endian_single_bit_last_bit() +{ + canMap->AddRecv(Param::ocurlim, CanId, 63, -1, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0, 0, 0, 1 }); + ASSERT(Param::GetBool(Param::ocurlim)); + + SendFrame({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe }); + ASSERT(!Param::GetBool(Param::ocurlim)); +} + +static void receive_map_little_endian_single_bit_in_first_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 21, 1, 1.0, 0); + + SendFrame({ 0, 0, 0x20, 0, 0, 0, 0, 0 }); + ASSERT(Param::GetBool(Param::ocurlim)); + + SendFrame({ 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff }); + ASSERT(!Param::GetBool(Param::ocurlim)); +} + +static void receive_map_little_endian_single_bit_in_second_word() +{ + canMap->AddRecv(Param::ocurlim, CanId, 53, 1, 1.0, 0); + + SendFrame({ 0, 0, 0, 0, 0, 0, 0x20, 0 }); + ASSERT(Param::GetBool(Param::ocurlim)); + + SendFrame({ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff }); + ASSERT(!Param::GetBool(Param::ocurlim)); +} + +static void fail_to_map_with_invalid_can_id() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x800, 0, 16, 1.0) == CAN_ERR_INVALID_ID); + + ASSERT( + canMap->AddSend(Param::amp, 0x40000000, 0, 16, 1.0) == + CAN_ERR_INVALID_ID); +} + +static void fail_to_map_with_invalid_little_endian_offset() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x123, -1, 1, 1.0) == CAN_ERR_INVALID_OFS); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 64, 1, 1.0) == CAN_ERR_INVALID_OFS); +} + +static void fail_to_map_with_invalid_little_endian_length() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x123, 0, 0, 1.0) == CAN_ERR_INVALID_LEN); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 0, 33, 1.0) == CAN_ERR_INVALID_LEN); +} + +static void fail_to_map_with_invalid_little_endian_total_struct_offset() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x123, 63, 2, 1.0) == CAN_ERR_INVALID_OFS); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 49, 16, 1.0) == CAN_ERR_INVALID_OFS); +} + +static void fail_to_map_with_invalid_big_endian_offset() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x123, -1, -1, 1.0) == CAN_ERR_INVALID_OFS); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 64, -1, 1.0) == CAN_ERR_INVALID_OFS); +} + +static void fail_to_map_with_invalid_big_endian_length() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x123, 0, -33, 1.0) == CAN_ERR_INVALID_LEN); +} + +static void fail_to_map_with_invalid_big_endian_total_struct_offset() +{ + ASSERT( + canMap->AddSend(Param::amp, 0x123, 0, -2, 1.0) == CAN_ERR_INVALID_OFS); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 14, -16, 1.0) == + CAN_ERR_INVALID_OFS); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 7, -32, 1.0) == + CAN_ERR_INVALID_OFS); + ASSERT( + canMap->AddSend(Param::amp, 0x123, 30, -32, 1.0) == + CAN_ERR_INVALID_OFS); +} + +REGISTER_TEST( + CanMapTest, + send_map_little_endian_byte_in_first_word, + send_map_little_endian_16_bit_in_first_word, + send_map_little_endian_32_bit_in_first_word, + send_map_little_endian_32_bit_in_second_word, + send_map_little_endian_negative_number_16_bit_in_first_word, + send_map_little_endian_negative_number_24_bit_in_first_word, + send_map_little_endian_negative_number_32_bit_in_first_word, + send_map_little_endian_negative_number_32_bit_in_second_word, + send_map_little_endian_negative_number_32_bit_spanning_both_words, + send_map_little_endian_negative_number_32_bit_mostly_in_first_word, + send_map_little_endian_negative_number_32_bit_mostly_in_second_word, + send_map_little_endian_negative_number_16_bit_at_end_of_frame, + send_map_big_endian_byte_in_first_word, + send_map_big_endian_16_bit_in_first_word, + send_map_big_endian_32_bit_in_first_word, + send_map_big_endian_negative_byte_in_first_word, + send_map_big_endian_negative_16_bit_in_first_word, + send_map_big_endian_negative_24_bit_in_first_word, + send_map_big_endian_negative_32_bit_in_first_word, + send_map_big_endian_negative_byte_in_second_word, + send_map_big_endian_negative_16_bit_in_second_word, + send_map_big_endian_negative_24_bit_in_second_word, + send_map_big_endian_negative_32_bit_in_second_word, + send_map_big_endian_negative_number_24_bit_at_end_of_frame, + send_map_big_endian_negative_16_bit_spanning_both_words, + send_map_big_endian_negative_32_bit_spanning_both_words, + send_map_big_endian_negative_32_bit_mostly_in_first_word, + send_map_big_endian_negative_32_bit_mostly_in_second_word, + receive_map_little_endian_byte_in_first_word, + receive_map_little_endian_16_bit_in_first_word, + receive_map_little_endian_32_bit_in_first_word, + receive_map_little_endian_32_bit_in_second_word, + receive_map_little_endian_negative_number_16_bit_in_first_word, + receive_map_little_endian_negative_number_24_bit_in_first_word, + receive_map_little_endian_negative_number_31_bit_in_first_word, + receive_map_little_endian_negative_number_32_bit_in_first_word, + receive_map_little_endian_negative_number_32_bit_in_second_word, + receive_map_little_endian_negative_number_32_bit_spanning_both_words, + receive_map_little_endian_negative_number_32_bit_mostly_in_first_word, + receive_map_little_endian_negative_number_32_bit_mostly_in_second_word, + receive_map_little_endian_negative_number_16_bit_at_end_of_frame, + receive_map_big_endian_byte_in_first_word, + receive_map_big_endian_16_bit_in_first_word, + receive_map_big_endian_31_bit_in_first_word, + receive_map_big_endian_32_bit_in_first_word, + receive_map_big_endian_negative_byte_in_first_word, + receive_map_big_endian_negative_16_bit_in_first_word, + receive_map_big_endian_negative_24_bit_in_first_word, + receive_map_big_endian_negative_31_bit_in_first_word, + receive_map_big_endian_negative_32_bit_in_first_word, + receive_map_big_endian_negative_byte_in_second_word, + receive_map_big_endian_negative_16_bit_in_second_word, + receive_map_big_endian_negative_24_bit_in_second_word, + receive_map_big_endian_negative_32_bit_in_second_word, + receive_map_big_endian_negative_number_24_bit_at_end_of_frame, + receive_map_big_endian_negative_16_bit_spanning_both_words, + receive_map_big_endian_negative_32_bit_spanning_both_words, + receive_map_big_endian_negative_32_bit_mostly_in_first_word, + receive_map_big_endian_negative_32_bit_mostly_in_second_word, + receive_map_little_endian_single_bit_first_bit, + receive_map_big_endian_single_bit_first_bit, + receive_map_little_endian_single_bit_last_bit, + receive_map_big_endian_single_bit_last_bit, + receive_map_little_endian_single_bit_in_first_word, + receive_map_little_endian_single_bit_in_second_word, + fail_to_map_with_invalid_can_id, + fail_to_map_with_invalid_little_endian_offset, + fail_to_map_with_invalid_little_endian_length, + fail_to_map_with_invalid_little_endian_total_struct_offset, + fail_to_map_with_invalid_big_endian_offset, + fail_to_map_with_invalid_big_endian_length, + fail_to_map_with_invalid_big_endian_total_struct_offset); diff --git a/test/test_vcu.cpp b/test/test_vcu.cpp index 9c854ac..0657c22 100644 --- a/test/test_vcu.cpp +++ b/test/test_vcu.cpp @@ -24,6 +24,7 @@ #include "hwdefs.h" #include "pwmgeneration.h" #include "vehiclecontrol.h" +#include "stub_canhardware.h" #include "test.h" static uint32_t crc32_word(uint32_t Crc, uint32_t Data); @@ -32,8 +33,6 @@ static uint32_t crc = 0; static uint32_t rtc = 0; static uint32_t speed = 0; static ERROR_MESSAGE_NUM errorMessage; -static CanCallback* vcuCan = 0; -static uint32_t vcuCanId; class VCUTest: public UnitTest { @@ -42,13 +41,6 @@ class VCUTest: public UnitTest virtual void TestCaseSetup(); }; -class CanStub: public CanHardware -{ - void SetBaudrate(enum baudrates baudrate) {} - void Send(uint32_t canId, uint32_t data[2], uint8_t len) {} - virtual void ConfigureFilters() {} -}; - static void FillInCanData(uint32_t* data, uint32_t pot, uint32_t pot2, uint32_t canio, uint32_t cruisespeed, uint32_t regenPreset, uint32_t seq) { uint32_t crc = 0xFFFFFFFF; @@ -71,7 +63,7 @@ static void CanTest2() FillInCanData(data, 100, 200, CAN_IO_FWD, 1000, 50, 1); - vcuCan->HandleRx(vcuCanId, data); + vcuCan->HandleRx(vcuCanId, data, 8); VehicleControl::GetDigInputs(); VehicleControl::ProcessThrottle(); @@ -89,7 +81,7 @@ static void CanTest3() FillInCanData(data, 100, 200, CAN_IO_START, 1000, 50, 1); Param::SetInt(Param::potmode, POTMODE_DUALCHANNEL | POTMODE_CAN); - vcuCan->HandleRx(vcuCanId, data); + vcuCan->HandleRx(vcuCanId, data, 8); VehicleControl::GetDigInputs(); VehicleControl::ProcessThrottle(); @@ -106,10 +98,10 @@ static void TestCanSeqError1() Param::SetInt(Param::potmode, POTMODE_DUALCHANNEL | POTMODE_CAN); FillInCanData(data, 100, 200, CAN_IO_START, 1000, 60, 1); - vcuCan->HandleRx(vcuCanId, data); + vcuCan->HandleRx(vcuCanId, data, 8); //call again with same sequence counter -> triggers an error message FillInCanData(data, 100, 200, CAN_IO_START, 1000, 60, 1); - vcuCan->HandleRx(vcuCanId, data); + vcuCan->HandleRx(vcuCanId, data, 8); ASSERT(errorMessage == ERR_CANCOUNTER); ASSERT(Param::GetInt(Param::regenpreset) == 60); //Only after 5 errors will this be reset to 0 @@ -125,7 +117,7 @@ static void TestCanSeqError2() { //Call 6 times with same sequence counter -> will trigger unrecoverable error FillInCanData(data, 100, 200, CAN_IO_START, 1000, 60, 1); - vcuCan->HandleRx(vcuCanId, data); + vcuCan->HandleRx(vcuCanId, data, 8); } //Now simulate 500ms or 50 rtc ticks passed @@ -165,7 +157,7 @@ extern "C" uint32_t rtc_get_counter_val() return rtc; } -extern "C" void timer_set_oc_value(uint32_t, uint16_t, uint16_t) +extern "C" void timer_set_oc_value(uint32_t, enum tim_oc_id, uint32_t) { } @@ -266,20 +258,6 @@ void Param::Change(Param::PARAM_NUM p) } -CanHardware::CanHardware() {} - -bool CanHardware::AddReceiveCallback(CanCallback* cb) -{ - vcuCan = cb; - return true; -} - -bool CanHardware::RegisterUserMessage(uint32_t canId) -{ - vcuCanId = canId; - return true; -} - const char* errorListString = ""; HWREV hwRev = HW_REV3; uint16_t AnaIn::values[NUM_SAMPLES*ANA_IN_COUNT];