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];