proj: switching to Linux

This commit is contained in:
2025-07-06 11:00:29 +02:00
parent 9ebbedb04a
commit 8f0dbd4cbd
23 changed files with 255 additions and 170 deletions
+33
View File
@@ -10,6 +10,39 @@
"type": "espidf",
"name": "Launch",
"request": "launch"
},
{
"name": "C/C++: g++.exe debug selected file",
"type": "cppdbg",
"request": "launch",
// "program": "${fileDirname}\\${fileBasenameNoExtension}.exe",
"program": "${workspaceFolder}/test/unitOnHost/build/watchFace/watchFaceTest.exe",
// "program": "${workspaceFolder}/core/test/unitOnHost/build/devHal/devHalTest.exe",
"args": [],
"stopAtEntry": false,
"cwd": "${fileDirname}",
"environment": [],
"externalConsole": false,
"MIMode": "gdb",
"miDebuggerPath": "C:\\msys64\\ucrt64\\bin\\gdb.exe",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"description": "Set Disassembly Flavor to Intel",
"text": "-gdb-set disassembly-flavor intel",
"ignoreFailures": true
}
],
"existing": false,
// "preLaunchTask": "C/C++: g++.exe build active file",
"detail": "preLaunchTask: C/C++: g++.exe build active file",
"taskDetail": "compiler: C:\\msys64\\ucrt64\\bin\\g++.exe",
"taskStatus": "Detected Task"
}
]
}
+1 -1
View File
@@ -1,4 +1,4 @@
idf_component_register(
INCLUDE_DIRS "."
INCLUDE_DIRS "include"
REQUIRES devHal
)
@@ -0,0 +1,62 @@
#pragma once
#include "stepperDrv.hpp"
#include "stepperMotor.hpp"
#include <cmath>
class WatchMotor {
static constexpr uint8_t Positions = 6;
public:
using AllmostFinishedCb = void (*)(uint8_t newIdx);
WatchMotor(IStepperMotor &stepper, AllmostFinishedCb onDone)
: _stepper(stepper),
_onFinCb(onDone) {
}
void moveTo(uint8_t position, uint8_t profile, int minJumps, float accel, float speed) {
auto sign = position % 6;
int minTurns = minJumps / 6;
float corr = 0.0F;
float currentPos = _stepper.getScaledPos() * 6;
if ((_currentIndex > 4) && (currentPos < 2)) {
corr = 6 - _currentIndex - currentPos;
} else if ((_currentIndex < 2) && (currentPos > 2)) {
corr = _currentIndex + 6 - currentPos;
} else {
corr = _currentIndex - currentPos;
}
int steps = 0;
if (_currentIndex < sign) {
steps = (sign - _currentIndex);
} else if (_currentIndex >= sign) {
steps = (sign + 6 - _currentIndex);
}
steps += minTurns * 6;
if (steps < minJumps) {
steps += 6;
}
float delta = 2.0F * std::numbers::pi / 6 * steps;
ESP_LOGD("MV", "Moving to %d by %.2f + %.2f", sign, delta, corr);
_stepper.moveBy(delta + corr, profile, accel, speed, [&]() {
if (_onFinCb) {
_onFinCb(position);
}
});
_currentIndex = sign;
}
float getScaled() { return _stepper.getScaledPos() * 6; }
uint8_t getIndex() { return _currentIndex; }
private:
IStepperMotor &_stepper;
uint8_t _currentIndex{};
AllmostFinishedCb _onFinCb{};
};
+1
View File
@@ -0,0 +1 @@
// Dummy file
@@ -0,0 +1,4 @@
UnitTestsFrame()
target_link_libraries(${moduleName} PUBLIC
devHal
)
@@ -0,0 +1,105 @@
/**
* @file TestableUTest.cpp
* @author Gustice
* @brief
*
* @copyright Copyright (c) 2024
*/
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
#include "doctest/doctest.h"
#include <iostream>
#include <numbers>
#include "watchFace.hpp"
class StepperMotorMock : public IStepperMotor {
public:
void moveBy(float angle, uint8_t profile = 0) override {
lastAngle = angle;
lastProfile = profile;
}
void moveBy(float angle, uint8_t profile, float accel, float speed, std::function<void()> profileDone = nullptr) override {
lastAngle = angle;
lastProfile = profile;
}
float getScaledPos() const override {
return nextPos;
}
uint16_t getQuanted() const override {
return 0;
}
float lastAngle{};
uint8_t lastProfile{};
float lastAccel{};
float lastSpeed{};
float nextPos{};
};
void onFin(uint8_t idx) {
}
class WatchFaceFixture {
using PositionStore = StepperMotor::Position<50, 5>;
public:
protected:
static constexpr int MicroSteps = 32;
StepperMotorMock motor;
WatchMotor sut{motor, onFin};
private:
};
TEST_CASE_FIXTURE(WatchFaceFixture, "Moving simple steps") {
auto next = 0*std::numbers::pi/3;
motor.nextPos = next;
sut.moveTo(1, 0, 0, 1, 1);
auto delta = 1*std::numbers::pi/3;
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(2, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 2.0F/6;
sut.moveTo(3, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 3.0F/6;
sut.moveTo(4, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 4.0F/6;
sut.moveTo(5, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 5.0F/6;
sut.moveTo(6, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 6.0F/6;
sut.moveTo(1, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(2, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
}
TEST_CASE_FIXTURE(WatchFaceFixture, "Moving multiple turns") {
auto next = 0*std::numbers::pi/3;
motor.nextPos = next;
sut.moveTo(1, 0, 0, 1, 1);
auto delta = 1*std::numbers::pi/3;
CHECK(motor.lastAngle == doctest::Approx(delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(1, 0, 0, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(6*delta).epsilon(0.000625)); // MicroStep tolerance
motor.nextPos = 1.0F/6;
sut.moveTo(1, 0, 7, 1, 1);
CHECK(motor.lastAngle == doctest::Approx(12*delta).epsilon(0.000625)); // MicroStep tolerance
}
-50
View File
@@ -1,50 +0,0 @@
#pragma once
#include "StepperDrv8833.hpp"
#include "stepperMotor.hpp"
#include <cmath>
class WatchMotor {
static constexpr uint8_t Positions = 6;
public:
WatchMotor(StepperMotor &stepper, OutputPort &sleep)
: _stepper(stepper),
_motorSleep(sleep) {
_motorSleep.write(false);
}
void moveTo(uint8_t sign, uint8_t profile = 0) {
sign = sign % 6;
float delta = 2.0F * std::numbers::pi;
float corr = 0.0F;
float currentPos = _stepper.getScaledPos() * 6;
if ((_currentIndex > 4) && (currentPos < 2)) {
corr = 6 - _currentIndex - currentPos;
} else if ((_currentIndex < 2) && (currentPos > 2)) {
corr = _currentIndex + 6 - currentPos;
} else {
corr = _currentIndex - currentPos;
}
// stepper.getScaledPos() * 6
if (_currentIndex < sign) {
delta = delta / 6 * (sign - _currentIndex);
} else if (_currentIndex > sign) {
delta = delta / 6 * (sign + 6 - _currentIndex);
}
ESP_LOGD("MV", "Moving to %d by %.2f + %.2f", sign, delta, corr);
_stepper.moveBy(delta + corr, profile);
_currentIndex = sign;
}
float getScaled() { return _stepper.getScaledPos() * 6; }
uint8_t getIndex() { return _currentIndex; }
private:
StepperMotor &_stepper;
OutputPort &_motorSleep;
uint8_t _currentIndex{};
};
+1 -1
Submodule core updated: c85bfa2afc...1ce930dff8
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+15 -20
View File
@@ -591,7 +591,10 @@ void MovementTask() {
StepperMotor stepper(stepperCfg, stepperDriver, initSens);
WatchMotor watch(stepper, motorSleep);
WatchMotor watch(stepper, [](uint8_t newPos) {
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(newPos));
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, newPos));
});
ESP_LOGI("Stepper", "Find Home");
stepper.findRef();
@@ -627,23 +630,15 @@ void MovementTask() {
continue;
}
int jumps = newPos - watch.getIndex();
if (jumps <= 0) {
jumps += 6;
}
jumps = jumps + (activeState.minJumps % 6) * 6;
if (jumps < activeState.minJumps) {
jumps += 6;
}
Syslog::logv(Syslog::Severity::Notice,
"Running Stepper by %i steps with prof=%i a=%.2f w=%.2f",
jumps, activeState.profile, activeState.accel, activeState.speed);
"Running Stepper by min%i steps with prof=%i a=%.2f w=%.2f",
activeState.minJumps, activeState.profile, activeState.accel, activeState.speed);
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(0));
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StartMoving, 0));
watch.moveTo(newPos, activeState.profile);
pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(newPos));
responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, newPos));
auto &as = activeState;
watch.moveTo(newPos, as.profile, as.minJumps, as.accel, as.speed);
// pictoIllumQue.enqueue(std::make_unique<PictoIllumCommand>(newPos));
// responseQueue.enqueue(std::make_unique<WatchIndex>(ResponseType::StepAt, newPos));
}
} else if (cmd->type == MoveType::Demo) {
ESP_LOGI(TAG, "Running Demo");
@@ -652,7 +647,7 @@ void MovementTask() {
fos::Task::delayMs(1000);
int steps[3]{4, 2, 0};
for (size_t j = 0; j < 3; j++) {
watch.moveTo(steps[j], i);
watch.moveTo(steps[j], i, 1, 1, 1);
fos::Task::delayMs(1000);
}
}
@@ -735,7 +730,7 @@ bool onCheckSpitTypeVeto(bool knownType, bool createdByClient) {
}
bool onCheckSpitObjectVeto(bool knownType) {
return true; // Bypass veto
return true; // Bypass veto
if (!knownType) { // Don't allow objects of unregistered SPITTypes
return false;
}
@@ -988,8 +983,8 @@ void app_main(void) {
// ToDo send
Syslog::logv(Syslog::Severity::Notice, "Health state");
// ESP_LOGI(TAG, "Min heap size: %" PRIu32 " / FreeHeap %" PRIu32 "\n",
ESP_LOGI(TAG, "Min heap size: %u / FreeHeap %lu",
heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT),
esp_get_free_heap_size());
// ESP_LOGI(TAG, "Min heap size: %u / FreeHeap %lu",
// heap_caps_get_minimum_free_size(MALLOC_CAP_DEFAULT),
// esp_get_free_heap_size());
}
}
+1 -1
View File
@@ -24,7 +24,7 @@
// Component header
#include "Task.hpp"
#include "PwmExpanderPca9685.hpp"
#include "StepperDrv8833.hpp"
#include "stepperDrv.hpp"
#include "stepperMotor.hpp"
#include "cliWrapper.hpp"
#include "udpSockets.hpp"
+3
View File
@@ -0,0 +1,3 @@
#!/bin/bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
code --profile Embed-Esp ${SCRIPT_DIR}
+24 -6
View File
@@ -11,11 +11,11 @@
#include "Processor.hpp"
#include "PwmExpanderPca9685.hpp"
#include "StepperDrv8833.hpp"
#include "Task.hpp"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "stepperDrv.hpp"
#include "stepperMotor.hpp"
#include "watchFace.hpp"
#include <array>
@@ -181,6 +181,10 @@ constexpr bool DoFullTurns = false;
constexpr bool DoTurnSteps = false;
constexpr bool DoTurnProfiles = true;
void AllmostDone(uint8_t newIdx) {
ESP_LOGW(TAG, "Done callback");
}
void testMovementTask() {
esp_log_level_set(TAG, ESP_LOG_DEBUG);
esp_log_level_set("STP", ESP_LOG_DEBUG);
@@ -207,7 +211,7 @@ void testMovementTask() {
OutputPort motorSleep(GPIO_NUM_15, GpioPort::Logic::Inverted);
StepperMotor stepper(stepperCfg, stepperDriver, initSens);
WatchMotor watch(stepper, motorSleep);
WatchMotor watch(stepper, motorSleep, AllmostDone);
///
/// Full Turns with full steps
@@ -273,14 +277,14 @@ void testMovementTask() {
ESP_LOGI(TAG, "Move to each index multiple times");
illum.flashAll(BLUE);
for (size_t i = 1; i <= 2 * 3; i++) {
watch.moveTo(3 * i);
watch.moveTo(3 * i, 0, 0, 1, 1);
ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
}
ESP_LOGI(TAG, "Move to each index multiple times");
illum.flashAll(BLUE);
for (size_t i = 1; i <= 6 * 3; i++) {
watch.moveTo(i);
watch.moveTo(i, 0, 0, 1, 1);
ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
}
}
@@ -290,14 +294,28 @@ void testMovementTask() {
///
if constexpr (DoTurnProfiles) {
for (size_t i = ProfileGenerator::Smooth; i < ProfileGenerator::NumProfiles; i++) {
// for (size_t i = ProfileGenerator::JumpIn; i < ProfileGenerator::NumProfiles; i++) { // If only part is needed
// for (size_t i = ProfileGenerator::JumpIn; i < ProfileGenerator::NumProfiles; i++) { // If only part is needed
ESP_LOGI(TAG, "Running Profile %d ", i);
ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos());
fos::Task::delayMs(1000);
illum.flashAll(BLUE);
int steps[3]{4, 2, 0};
for (size_t j = 0; j < 3; j++) {
watch.moveTo(steps[j], i);
watch.moveTo(steps[j], i, 0, 1, 1);
ESP_LOGI(TAG, "Last position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
fos::Task::delayMs(1000);
}
}
for (size_t i = ProfileGenerator::Smooth; i < ProfileGenerator::NumProfiles; i++) {
// for (size_t i = ProfileGenerator::JumpIn; i < ProfileGenerator::NumProfiles; i++) { // If only part is needed
ESP_LOGI(TAG, "Running Profile %d ", i);
ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos());
fos::Task::delayMs(1000);
illum.flashAll(BLUE);
int steps[3]{4, 2, 0};
for (size_t j = 0; j < 3; j++) {
watch.moveTo(steps[j], i, 0, 3, 3);
ESP_LOGI(TAG, "Last position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
fos::Task::delayMs(1000);
}
+4 -19
View File
@@ -1,26 +1,11 @@
cmake_minimum_required(VERSION 3.16)
include(../../core/test/unitOnHost/test_core.cmake)
set(DEF_UTESTDIR "uTest")
set(DEF_SRCDIR "src")
set(DEF_INCLUDEDIR "include")
# use just host compilers for this one
set(CMAKE_C_COMPILER "gcc")
set(CMAKE_CXX_COMPILER "g++")
set(CMAKE_GENERATOR "Ninja")
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
set(CMAKE_VERBOSE_MAKEFILE TRUE)
include(test_core.cmake)
UnitTestSetup()
enable_testing()
project(UnitTests)
find_package(doctest REQUIRED PATHS "/mingw64/lib/cmake")
# target_link_libraries(${PROJECT_NAME} PRIVATE doctest::doctest)
addSubDirs_ofRoot("${CMAKE_CURRENT_LIST_DIR}/../../components")
addSubDirs_ofRoot("${CMAKE_CURRENT_LIST_DIR}/../../core/components")
add_subdirectory("${CMAKE_CURRENT_LIST_DIR}/../../core/test/unitOnHost/hwMock" hwMock)
-28
View File
@@ -1,28 +0,0 @@
# Unit Testing - Software
In contrast to *test*-directory this module demonstrates how unit tests can also be run on host.
These unit tests aim to test freestanding software modules with more convenient methods and tools
## Setup
make sure you have following packages installed on your host syste
- gnu compiler
- cmake
- generator
- doctest-dev
## Build and test code
* Start some terminal in *uTest*-directory that has access to all needed tools (i.e. on windows a mingw environment or WSL)
Run following commands
```sh
# run cmake configuration
cmake -S . -B build
# run cmake build
cmake --build build
# run tests
./build/<testprog>
# run all tests with
cd build && ctest
```
-43
View File
@@ -1,43 +0,0 @@
function(addSubDirs_ofRoot anchorPath)
message("scanning: ${anchorPath}")
file(GLOB targetModules RELATIVE "${anchorPath}" "${anchorPath}/*")
foreach(module ${targetModules})
message("checking: ${module}")
get_filename_component(moduleName ${module} NAME)
set(modulePath "${anchorPath}/${moduleName}")
if (NOT IS_DIRECTORY "${modulePath}")
# skip files
continue()
endif()
if (${moduleName} MATCHES "^_.*")
# skip ignored component
continue()
endif()
if(EXISTS "${modulePath}/${DEF_UTESTDIR}")
message("Found unit-test: ${moduleName}")
add_subdirectory("${modulePath}/${DEF_UTESTDIR}" ${moduleName})
endif()
endforeach()
endfunction()
macro(unitTestsFrame)
if (CMAKE_TESTING_ENABLED)
# get_filename_component(moduleName "${CMAKE_CURRENT_LIST_DIR}/.." NAME)
file(GLOB_RECURSE targetSources "../${DEF_SRCDIR}/*.cpp" "../${DEF_SRCDIR}/*.c")
add_library(${moduleName} ${targetSources})
target_include_directories(${moduleName} PUBLIC "../${DEF_INCLUDEDIR}")
set(moduleTestName "${moduleName}Test")
file(GLOB_RECURSE testSource "*.cpp")
add_executable(${moduleTestName} ${testSource})
target_link_libraries(${moduleTestName} PRIVATE ${moduleName} doctest::doctest)
target_include_directories(${moduleTestName} PRIVATE "../${DEF_SRCDIR}")
add_test (TEST-${moduleName} ${moduleTestName})
# gtest_discover_tests(${moduleTestName}
# PROPERTIES TIMEOUT 30 LABELS ${moduleName} LABELS "all"
# )
endif()
endmacro()