Basic unit test structure for the logic layer

It compiles the Cut Filament unit test with all the necessary components.
Still, the unit test does nothing.
pull/23/head
D.R.racer 2021-06-16 08:13:09 +02:00
parent 19bc26219b
commit e7ef601ccd
15 changed files with 214 additions and 48 deletions

View File

@ -3,11 +3,13 @@
namespace hal {
namespace eeprom {
uint8_t ReadByte(const uint8_t *addr) {
EEPROM eeprom;
uint8_t EEPROM::ReadByte(EEPROM::addr_t /*addr*/) {
return 0;
}
void UpdateByte(const uint8_t *addr, uint8_t value) {
void EEPROM::UpdateByte(EEPROM::addr_t /*addr*/, uint8_t /*value*/) {
}
} // namespace eeprom

View File

@ -5,16 +5,24 @@ namespace hal {
namespace eeprom {
/// EEPROM interface
extern void WriteByte(const uint8_t *addr, uint8_t value);
extern void UpdateByte(const uint8_t *addr, uint8_t value);
extern uint8_t ReadByte(const uint8_t *addr);
class EEPROM {
public:
using addr_t = uint16_t;
extern void WriteWord(const uint8_t *addr, uint16_t value);
extern void UpdateWord(const uint8_t *addr, uint16_t value);
extern uint16_t ReadWord(const uint8_t *addr);
static void WriteByte(addr_t addr, uint8_t value);
static void UpdateByte(addr_t addr, uint8_t value);
static uint8_t ReadByte(addr_t addr);
/// @returns physical end address of EEPROM memory end
extern constexpr const uint16_t End();
static void WriteWord(addr_t addr, uint16_t value);
static void UpdateWord(addr_t addr, uint16_t value);
static uint16_t ReadWord(addr_t addr);
/// @returns physical end address of EEPROM memory end
/// @@TODO this is sad - the constexpr must be inline... find a way around in the future
constexpr static addr_t End() { return 2048; }
};
extern EEPROM eeprom;
} // namespace EEPROM
} // namespace hal

View File

@ -1,6 +1,9 @@
/// @author Marek Bel
#include "permanent_storage.h"
#include "../hal/eeprom.h"
#include "globals.h"
#include <stddef.h>
namespace modules {
namespace permanent_storage {
@ -23,7 +26,7 @@ struct eeprom_t {
uint8_t eepromDriveErrorCountL[2];
} __attribute__((packed));
// @@TODO static_assert(sizeof(eeprom_t) - 2 <= hal::EEPROM::End(), "eeprom_t doesn't fit into EEPROM available.");
static_assert(sizeof(eeprom_t) - 2 <= hal::eeprom::EEPROM::End(), "eeprom_t doesn't fit into EEPROM available.");
/// @brief EEPROM layout version
static const uint8_t layoutVersion = 0xff;
@ -36,25 +39,30 @@ static const uint8_t layoutVersion = 0xff;
//mres = 16 idler microstep resolution (uint8_t __res(AX_IDL))
//1 pulley ustep = (d*pi)/(mres*FSPR) = 49.48 um
// ideally, this would have been a nice constexpr (since it is a compile time constant), but the C++ standard prohibits reinterpret_casts in constexpr
static eeprom_t *const eepromBase = reinterpret_cast<eeprom_t *>(0); ///< First EEPROM address
static const uint16_t eepromEmpty = 0xffff; ///< EEPROM content when erased
static const uint16_t eepromLengthCorrectionBase = 7900u; ///< legacy bowden length correction base (~391mm)
static const uint16_t eepromBowdenLenDefault = 8900u; ///< Default bowden length (~427 mm)
static const uint16_t eepromBowdenLenMinimum = 6900u; ///< Minimum bowden length (~341 mm)
static const uint16_t eepromBowdenLenMaximum = 16000u; ///< Maximum bowden length (~792 mm)
constexpr const uint16_t eepromEmpty = 0xffffU; ///< EEPROM content when erased
constexpr const uint16_t eepromLengthCorrectionBase = 7900U; ///< legacy bowden length correction base (~391mm)
constexpr const uint16_t eepromBowdenLenDefault = 8900U; ///< Default bowden length (~427 mm)
constexpr const uint16_t eepromBowdenLenMinimum = 6900U; ///< Minimum bowden length (~341 mm)
constexpr const uint16_t eepromBowdenLenMaximum = 16000U; ///< Maximum bowden length (~792 mm)
namespace ee = hal::eeprom;
#define EEOFFSET(x) reinterpret_cast<size_t>(&(x))
void Init() {
if (hal::eeprom::ReadByte((const uint8_t *)hal::eeprom::End()) != layoutVersion) {
if (ee::EEPROM::ReadByte(ee::EEPROM::End()) != layoutVersion) {
EraseAll();
}
}
/// @brief Erase the whole EEPROM
void EraseAll() {
for (uint16_t i = 0; i < hal::eeprom::End(); i++) {
hal::eeprom::UpdateByte((uint8_t *)i, static_cast<uint8_t>(eepromEmpty));
for (uint16_t i = 0; i < ee::EEPROM::End(); i++) {
ee::EEPROM::UpdateByte(i, static_cast<uint8_t>(eepromEmpty));
}
hal::eeprom::UpdateByte((const uint8_t *)hal::eeprom::End(), layoutVersion);
ee::EEPROM::UpdateByte(ee::EEPROM::End(), layoutVersion);
}
/// @brief Is filament number valid?
@ -81,12 +89,13 @@ static bool validBowdenLen(const uint16_t BowdenLength) {
/// Returns stored value, doesn't return actual value when it is edited by increase() / decrease() unless it is stored.
/// @return stored bowden length
uint16_t BowdenLength::get() {
uint8_t filament = 0 /*active_extruder*/; //@@TODO
uint8_t filament = modules::globals::globals.ActiveSlot();
if (validFilament(filament)) {
uint16_t bowdenLength = hal::eeprom::ReadByte((const uint8_t *)&(eepromBase->eepromBowdenLen[filament]));
// @@TODO these reinterpret_cast expressions look horrible but I'm keeping them almost intact to respect the original code from MM_control_01
uint16_t bowdenLength = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromBowdenLen[filament])));
if (eepromEmpty == bowdenLength) {
const uint8_t LengthCorrectionLegacy = hal::eeprom::ReadByte(&(eepromBase->eepromLengthCorrection));
const uint8_t LengthCorrectionLegacy = ee::EEPROM::ReadByte(reinterpret_cast<size_t>(&(eepromBase->eepromLengthCorrection)));
if (LengthCorrectionLegacy <= 200) {
bowdenLength = eepromLengthCorrectionBase + LengthCorrectionLegacy * 10;
}
@ -103,7 +112,7 @@ uint16_t BowdenLength::get() {
/// To be created on stack, new value is permanently stored when object goes out of scope.
/// Active filament and associated bowden length is stored in member variables.
BowdenLength::BowdenLength()
: filament(/*active_extruder*/ 0)
: filament(modules::globals::globals.ActiveSlot()) // @@TODO - verify correct initialization order
, length(BowdenLength::get()) // @@TODO
{
}
@ -137,7 +146,7 @@ bool BowdenLength::decrease() {
/// @brief Store bowden length permanently.
BowdenLength::~BowdenLength() {
if (validFilament(filament))
hal::eeprom::UpdateWord((const uint8_t *)&(eepromBase->eepromBowdenLen[filament]), length);
ee::EEPROM::UpdateWord(EEOFFSET(eepromBase->eepromBowdenLen[filament]), length);
}
/// @brief Get filament storage status
@ -148,12 +157,12 @@ BowdenLength::~BowdenLength() {
/// @retval 0xff Uninitialized EEPROM or no 2 values agrees
uint8_t FilamentLoaded::getStatus() {
if (hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[0])) == hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[1])))
return hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[0]));
if (hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[0])) == hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[2])))
return hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[0]));
if (hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[1])) == hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[2])))
return hal::eeprom::ReadByte(&(eepromBase->eepromFilamentStatus[1]));
if (ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[0])) == ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[1])))
return ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[0]));
if (ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[0])) == ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[2])))
return ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[0]));
if (ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[1])) == ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[2])))
return ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilamentStatus[1]));
return 0xff;
}
@ -163,7 +172,7 @@ uint8_t FilamentLoaded::getStatus() {
/// @retval false Failed
bool FilamentLoaded::setStatus(uint8_t status) {
for (uint8_t i = 0; i < ARR_SIZE(eeprom_t::eepromFilamentStatus); ++i) {
hal::eeprom::UpdateByte(&(eepromBase->eepromFilamentStatus[i]), status);
ee::EEPROM::UpdateByte(EEOFFSET(eepromBase->eepromFilamentStatus[i]), status);
}
if (getStatus() == status)
return true;
@ -187,7 +196,7 @@ int16_t FilamentLoaded::getIndex() {
case KeyFront2:
index = ARR_SIZE(eeprom_t::eepromFilament) - 1; // It is the last one, if no dirty index found
for (uint16_t i = 0; i < ARR_SIZE(eeprom_t::eepromFilament); ++i) {
if (status != (hal::eeprom::ReadByte(&(eepromBase->eepromFilament[i])) >> 4)) {
if (status != (ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilament[i])) >> 4)) {
index = i - 1;
break;
}
@ -197,7 +206,7 @@ int16_t FilamentLoaded::getIndex() {
case KeyReverse2:
index = 0; // It is the last one, if no dirty index found
for (int16_t i = (ARR_SIZE(eeprom_t::eepromFilament) - 1); i >= 0; --i) {
if (status != (hal::eeprom::ReadByte(&(eepromBase->eepromFilament[i])) >> 4)) {
if (status != (ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilament[i])) >> 4)) {
index = i + 1;
break;
}
@ -217,7 +226,7 @@ bool FilamentLoaded::get(uint8_t &filament) {
int16_t index = getIndex();
if ((index < 0) || (static_cast<uint16_t>(index) >= ARR_SIZE(eeprom_t::eepromFilament)))
return false;
const uint8_t rawFilament = hal::eeprom::ReadByte(&(eepromBase->eepromFilament[index]));
const uint8_t rawFilament = ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilament[index]));
filament = 0x0f & rawFilament;
if (filament > 4)
return false;
@ -250,8 +259,8 @@ bool FilamentLoaded::set(uint8_t filament) {
if (!setStatus(status))
return false;
uint8_t filamentRaw = ((status << 4) & 0xf0) + (filament & 0x0f);
hal::eeprom::UpdateByte(&(eepromBase->eepromFilament[index]), filamentRaw);
if (filamentRaw == hal::eeprom::ReadByte(&(eepromBase->eepromFilament[index])))
ee::EEPROM::UpdateByte(EEOFFSET(eepromBase->eepromFilament[index]), filamentRaw);
if (filamentRaw == ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromFilament[index])))
return true;
getNext(status);
if (!setStatus(status))
@ -330,8 +339,8 @@ void DriveError::increment() {
}
uint8_t DriveError::getL() {
uint8_t first = hal::eeprom::ReadByte(&(eepromBase->eepromDriveErrorCountL[0]));
uint8_t second = hal::eeprom::ReadByte(&(eepromBase->eepromDriveErrorCountL[1]));
uint8_t first = ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromDriveErrorCountL[0]));
uint8_t second = ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromDriveErrorCountL[1]));
if (0xff == first && 0 == second)
return 1;
@ -339,15 +348,15 @@ uint8_t DriveError::getL() {
}
void DriveError::setL(uint8_t lowByte) {
hal::eeprom::UpdateByte(&(eepromBase->eepromDriveErrorCountL[lowByte % 2]), lowByte - 1);
ee::EEPROM::UpdateByte(EEOFFSET(eepromBase->eepromDriveErrorCountL[lowByte % 2]), lowByte - 1);
}
uint8_t DriveError::getH() {
return (hal::eeprom::ReadByte(&(eepromBase->eepromDriveErrorCountH)) + 1);
return (ee::EEPROM::ReadByte(EEOFFSET(eepromBase->eepromDriveErrorCountH)) + 1);
}
void DriveError::setH(uint8_t highByte) {
hal::eeprom::UpdateByte(&(eepromBase->eepromDriveErrorCountH), highByte - 1);
ee::EEPROM::UpdateByte(EEOFFSET(eepromBase->eepromDriveErrorCountH), highByte - 1);
}
} // namespace permanent_storage

View File

@ -1 +1,17 @@
#
add_subdirectory(cut_filament)
# add_subdirectory(feed_to_finda)
# add_subdirectory(feed_to_bondtech)
# add_subdirectory(unload_to_finda)
# add_subdirectory(eject_filament)
# add_subdirectory(load_filament)
# add_subdirectory(tool_change)
# add_subdirectory(cut_filament)
# add_subdirectory(unload_filament)

View File

@ -0,0 +1,32 @@
# define the test executable
add_executable(
cut_filament_tests
../../../../src/logic/cut_filament.cpp
../../../../src/logic/feed_to_finda.cpp
../../../../src/logic/unload_filament.cpp
../../../../src/logic/unload_to_finda.cpp
../../../../src/modules/buttons.cpp
../../../../src/modules/debouncer.cpp
../../../../src/modules/finda.cpp
../../../../src/modules/fsensor.cpp
../../../../src/modules/globals.cpp
../../../../src/modules/idler.cpp
../../../../src/modules/leds.cpp
../../../../src/modules/motion.cpp
../../../../src/modules/permanent_storage.cpp
../../../../src/modules/selector.cpp
../../modules/stubs/stub_adc.cpp
../../modules/stubs/stub_eeprom.cpp
../../modules/stubs/stub_shr16.cpp
../stubs/main_loop_stub.cpp
test_cut_filament.cpp
)
# define required search paths
target_include_directories(
cut_filament_tests PUBLIC ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal
${CMAKE_SOURCE_DIR}/src/logic
)
# tell build system about the test case
add_catch_test(cut_filament_tests)

View File

@ -0,0 +1,24 @@
#include "catch2/catch.hpp"
#include "../../../../src/modules/buttons.h"
#include "../../../../src/modules/finda.h"
#include "../../../../src/modules/fsensor.h"
#include "../../../../src/modules/globals.h"
#include "../../../../src/modules/idler.h"
#include "../../../../src/modules/leds.h"
#include "../../../../src/modules/permanent_storage.h"
#include "../../../../src/modules/selector.h"
#include "../../../../src/logic/cut_filament.h"
#include "../../modules/stubs/stub_adc.h"
#include "../stubs/main_loop_stub.h"
using Catch::Matchers::Equals;
TEST_CASE("cut_filament::basic1", "[cut_filament]") {
using namespace logic;
CutFilament cf;
currentCommand = &cf;
main_loop();
}

View File

@ -0,0 +1,22 @@
#include "main_loop_stub.h"
#include "../../../../src/modules/buttons.h"
#include "../../../../src/modules/finda.h"
#include "../../../../src/modules/fsensor.h"
#include "../../../../src/modules/globals.h"
#include "../../../../src/modules/idler.h"
#include "../../../../src/modules/leds.h"
#include "../../../../src/modules/permanent_storage.h"
#include "../../../../src/modules/selector.h"
logic::CommandBase *currentCommand = nullptr;
// just like in the real FW, step all the known automata
void main_loop() {
modules::buttons::buttons.Step(hal::adc::ReadADC(0));
modules::leds::leds.Step(0);
modules::finda::finda.Step(0);
modules::fsensor::fsensor.Step(0);
modules::idler::idler.Step();
modules::selector::selector.Step();
currentCommand->Step();
}

View File

@ -0,0 +1,6 @@
#pragma once
#include "../../../../src/logic/command_base.h"
extern void main_loop();
extern logic::CommandBase *currentCommand;

View File

@ -1,7 +1,7 @@
# define the test executable
add_executable(
buttons_tests ../../../../src/modules/buttons.cpp ../../../../src/modules/debouncer.cpp
stub_adc.cpp test_buttons.cpp
../stubs/stub_adc.cpp test_buttons.cpp
)
# define required search paths

View File

@ -1,6 +1,6 @@
#include "catch2/catch.hpp"
#include "buttons.h"
#include "stub_adc.h"
#include "../stubs/stub_adc.h"
using Catch::Matchers::Equals;

View File

@ -1,5 +1,5 @@
# define the test executable
add_executable(leds_tests ../../../../src/modules/leds.cpp stub_shr16.cpp test_leds.cpp)
add_executable(leds_tests ../../../../src/modules/leds.cpp ../stubs/stub_shr16.cpp test_leds.cpp)
# define required search paths
target_include_directories(

View File

@ -0,0 +1,47 @@
#include "catch2/catch.hpp"
#include "../../../../src/hal/eeprom.h"
#include <array>
#include <stddef.h>
#include <stdint.h>
namespace hal {
namespace eeprom {
EEPROM eeprom;
constexpr uint16_t eepromSize = 2048U;
static std::array<uint8_t, eepromSize> EE;
/// EEPROM interface
void EEPROM::WriteByte(EEPROM::addr_t offset, uint8_t value) {
REQUIRE(offset < EE.size());
EE[offset] = value;
}
void EEPROM::UpdateByte(EEPROM::addr_t offset, uint8_t value) {
WriteByte(offset, value);
}
uint8_t EEPROM::ReadByte(EEPROM::addr_t offset) {
REQUIRE(offset < EE.size());
return EE[offset];
}
void EEPROM::WriteWord(EEPROM::addr_t offset, uint16_t value) {
REQUIRE(offset < EE.size() - 1);
*reinterpret_cast<uint16_t *>(&EE[offset]) = value;
}
void EEPROM::UpdateWord(EEPROM::addr_t offset, uint16_t value) {
WriteWord(offset, value);
}
uint16_t EEPROM::ReadWord(EEPROM::addr_t offset) {
REQUIRE(offset < EE.size() - 1);
return *reinterpret_cast<uint16_t *>(&EE[offset]);
}
} // namespace eeprom
} // namespace hal

View File

@ -14,10 +14,10 @@ void SHR16::Init() {
void SHR16::SetLED(uint16_t led) {
shr16_v_copy = ((led & 0x00ff) << 8) | ((led & 0x0300) >> 2);
}
void SHR16::SetTMCEnabled(uint8_t ena) {
void SHR16::SetTMCEnabled(uint8_t index, bool ena) {
// do nothing right now
}
void SHR16::SetTMCDir(uint8_t dir) {
void SHR16::SetTMCDir(uint8_t index, bool dir) {
// do nothing right now
}
void SHR16::Write(uint16_t v) {