refactor/bringup: Bringup full project
moving SPIT-App parts to main app LiveShowDemoProject added Debugging motor movements
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
"../../core/components"
|
||||
"../../core/managed_components"
|
||||
"../../components"
|
||||
# "../../managed_components"
|
||||
)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(INTEGRATION_TESTS_FW)
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
idf_component_register(SRCS "movementTests.cpp"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* @file watchMain.cpp
|
||||
* @author Gustice
|
||||
* @brief ChaosWatch Application
|
||||
*
|
||||
* @copyright Copyright (c) 2024
|
||||
*/
|
||||
|
||||
/// NOTE: Create IDF shell navigate to directory ("test/integration")
|
||||
// and run "idf.py -p COM9 flash monitor"
|
||||
|
||||
#include "Processor.hpp"
|
||||
#include "PwmExpanderPca9685.hpp"
|
||||
#include "StepperDrv8833.hpp"
|
||||
#include "Task.hpp"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "sdkconfig.h"
|
||||
#include "stepperMotor.hpp"
|
||||
#include "watchFace.hpp"
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
/* Watchface Indicies
|
||||
6/ 5/
|
||||
5 / 1 4 / 0
|
||||
4 2 3 1
|
||||
3 2
|
||||
*/
|
||||
|
||||
extern "C" { // This switch allows the ROS C-implementation to find this main
|
||||
void app_main(void);
|
||||
}
|
||||
|
||||
static const char *TAG = "IT";
|
||||
|
||||
struct DeviceState {
|
||||
uint8_t minJumps{6};
|
||||
uint8_t maxJumps{32};
|
||||
uint8_t profile{};
|
||||
uint8_t restTime{};
|
||||
float speed = 1.0; // Rad/sec
|
||||
float accel = 1.0; // Rad/sec^2
|
||||
Color color{0x80, 0x80, 0x80};
|
||||
uint8_t pictogram{}; // 0..5 active Pictogramm
|
||||
};
|
||||
|
||||
class IndexIllumination {
|
||||
public:
|
||||
IndexIllumination()
|
||||
: master(I2C_NUM_0, /*sda=*/GPIO_NUM_10, /*scl=*/GPIO_NUM_11),
|
||||
ledDriver1(master, /*iverted=*/false),
|
||||
ledDriver2(master, /*iverted=*/false, 0x41),
|
||||
pwmEnable(GPIO_NUM_1, GpioPort::Logic::Inverted),
|
||||
RED{CRed.getColor<Color::Rgbw>()},
|
||||
GREEN{CGreen.getColor<Color::Rgbw>()},
|
||||
BLUE{CBlue.getColor<Color::Rgbw>()} {
|
||||
pwmEnable.write(true);
|
||||
clearColorData();
|
||||
syncToDevice();
|
||||
}
|
||||
|
||||
void clearColorData() {
|
||||
for (size_t i = 0; i < 2; i++) {
|
||||
for (size_t j = 0; j < PmwExpanderPca9685::PwmChannels; j++) {
|
||||
Values[i][j] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setColorOfIndexTo(uint8_t idx, Color::Rgbw color) {
|
||||
if (idx >= 6) {
|
||||
return;
|
||||
}
|
||||
auto sp = LedStartPoints[idx];
|
||||
sp[0] = (uint16_t)(color.white) << 5;
|
||||
sp[1] = (uint16_t)(color.blue) << 5;
|
||||
sp[2] = (uint16_t)(color.green) << 5;
|
||||
sp[3] = (uint16_t)(color.red) << 5;
|
||||
}
|
||||
|
||||
void syncToDevice() {
|
||||
ledDriver1.sendImage(Values[0]);
|
||||
ledDriver2.sendImage(Values[1]);
|
||||
}
|
||||
|
||||
void flashAll(Color::Rgbw color, int duration = 200) {
|
||||
clearColorData();
|
||||
for (size_t i = 0; i < 6; i++) {
|
||||
setColorOfIndexTo(i, color);
|
||||
}
|
||||
syncToDevice();
|
||||
fos::Task::delayMs(duration);
|
||||
clearColorData();
|
||||
syncToDevice();
|
||||
}
|
||||
|
||||
private:
|
||||
PmwExpanderPca9685::GrayValues Values[2]{};
|
||||
std::array<uint16_t *, 6> LedStartPoints{
|
||||
&(Values[0][4]), // 1
|
||||
&(Values[1][12]),
|
||||
&(Values[1][8]),
|
||||
&(Values[1][4]),
|
||||
&(Values[0][12]),
|
||||
&(Values[0][8]), // 6
|
||||
};
|
||||
|
||||
I2cMaster master;
|
||||
PmwExpanderPca9685 ledDriver1;
|
||||
PmwExpanderPca9685 ledDriver2;
|
||||
OutputPort pwmEnable;
|
||||
const Color::Rgbw RED;
|
||||
const Color::Rgbw GREEN;
|
||||
const Color::Rgbw BLUE;
|
||||
};
|
||||
|
||||
DeviceState activeState;
|
||||
|
||||
void IndexColorSweep(IndexIllumination &illum) {
|
||||
const auto RED = CRed.getColor<Color::Rgbw>();
|
||||
const auto GREEN = CGreen.getColor<Color::Rgbw>();
|
||||
const auto BLUE = CBlue.getColor<Color::Rgbw>();
|
||||
|
||||
illum.flashAll(RED);
|
||||
fos::Task::delayMs(200);
|
||||
illum.flashAll(GREEN);
|
||||
fos::Task::delayMs(200);
|
||||
illum.flashAll(BLUE);
|
||||
fos::Task::delayMs(200);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(0, GREEN);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(0, RED);
|
||||
illum.setColorOfIndexTo(1, GREEN);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(1, RED);
|
||||
illum.setColorOfIndexTo(2, GREEN);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(2, RED);
|
||||
illum.setColorOfIndexTo(3, GREEN);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(3, RED);
|
||||
illum.setColorOfIndexTo(4, GREEN);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(4, RED);
|
||||
illum.setColorOfIndexTo(5, GREEN);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(5, RED);
|
||||
illum.syncToDevice();
|
||||
fos::Task::delayMs(500);
|
||||
|
||||
illum.clearColorData();
|
||||
illum.setColorOfIndexTo(0, GREEN);
|
||||
illum.syncToDevice();
|
||||
}
|
||||
|
||||
constexpr bool DoFlushAtBeginning = false;
|
||||
constexpr bool DoFullTurns = false;
|
||||
constexpr bool DoTurnSteps = false;
|
||||
constexpr bool DoTurnProfiles = true;
|
||||
|
||||
void testMovementTask() {
|
||||
esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
||||
esp_log_level_set("STP", ESP_LOG_DEBUG);
|
||||
ESP_LOGD(TAG, "Init Lights for signaling");
|
||||
|
||||
IndexIllumination illum;
|
||||
|
||||
if constexpr (DoFlushAtBeginning) {
|
||||
IndexColorSweep(illum);
|
||||
}
|
||||
const auto BLUE = CBlue.getColor<Color::Rgbw>();
|
||||
|
||||
ESP_LOGD(TAG, "Init Stepper");
|
||||
|
||||
constexpr int MicroSteps = 32;
|
||||
constexpr float Intensity = 0.25;
|
||||
constexpr float StepWidth = 1.8;
|
||||
StepperDriverDrv8833::Pins stepperPins({LEDC_TIMER_0,
|
||||
{LEDC_CHANNEL_0, LEDC_CHANNEL_1, LEDC_CHANNEL_2, LEDC_CHANNEL_3},
|
||||
{GPIO_NUM_21, GPIO_NUM_20, GPIO_NUM_23, GPIO_NUM_22}});
|
||||
StepperDriverDrv8833 stepperDriver(stepperPins, MicroSteps, Intensity);
|
||||
StepperConfig stepperCfg(StepWidth, MicroSteps);
|
||||
InputPort initSens(GPIO_NUM_18);
|
||||
OutputPort motorSleep(GPIO_NUM_15, GpioPort::Logic::Inverted);
|
||||
StepperMotor stepper(stepperCfg, stepperDriver, initSens);
|
||||
|
||||
WatchMotor watch(stepper, motorSleep);
|
||||
|
||||
///
|
||||
/// Full Turns with full steps
|
||||
///
|
||||
if constexpr (DoFullTurns) {
|
||||
ESP_LOGD(TAG, "Find Home");
|
||||
stepper.findRef();
|
||||
ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos());
|
||||
fos::Task::delayMs(2000);
|
||||
|
||||
ESP_LOGD(TAG, "Make one turns with full steps");
|
||||
// stepper.setPos(0);
|
||||
illum.flashAll(BLUE);
|
||||
int i = 0;
|
||||
|
||||
ESP_LOGD(TAG, "Position at begin is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
|
||||
while (i++ < 200) {
|
||||
stepper.fullStep(1);
|
||||
fos::Task::delayMs(100);
|
||||
ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
|
||||
}
|
||||
fos::Task::delayMs(2000);
|
||||
|
||||
int spB = stepper.getSubPos();
|
||||
stepper.demoFullTurn();
|
||||
int spE = stepper.getSubPos();
|
||||
ESP_LOGD(TAG, "Fullsteps SubPos begin %d / end %d", spB, spE);
|
||||
fos::Task::delayMs(2000);
|
||||
|
||||
ESP_LOGD(TAG, "Position at begin is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
|
||||
i = 0;
|
||||
while (i++ < 64) {
|
||||
stepper.step(1);
|
||||
fos::Task::delayMs(100);
|
||||
ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Homing
|
||||
///
|
||||
ESP_LOGD(TAG, "Find Home");
|
||||
stepper.findRef();
|
||||
ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos());
|
||||
for (size_t i = 0; i < 7; i++) {
|
||||
stepper.fullStep(1);
|
||||
fos::Task::delayMs(40);
|
||||
}
|
||||
illum.flashAll(BLUE);
|
||||
fos::Task::delayMs(1000);
|
||||
|
||||
auto ref = stepper.zeroPosition();
|
||||
ESP_LOGD(TAG, "Reference saved at %.2f ", ref);
|
||||
ESP_LOGD(TAG, "Correct Home");
|
||||
|
||||
///
|
||||
/// Multiple Turns continuous
|
||||
///
|
||||
if constexpr (DoTurnSteps) {
|
||||
|
||||
ESP_LOGD(TAG, "Fist Position is %3d / %.2f / Micro %d", stepper.getQuanted(), stepper.getScaledPos() * 6, stepper.getSubPos());
|
||||
fos::Task::delayMs(1000);
|
||||
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);
|
||||
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);
|
||||
ESP_LOGD(TAG, "Position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// All other Profiles
|
||||
///
|
||||
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
|
||||
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);
|
||||
ESP_LOGI(TAG, "Last position is %3d / %.2f", stepper.getQuanted(), stepper.getScaledPos() * 6);
|
||||
fos::Task::delayMs(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (true) {
|
||||
ESP_LOGI(TAG, "Finish");
|
||||
fos::Task::delayMs(60000);
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void) {
|
||||
ESP_LOGI(TAG, "Start Movement Integration Tests");
|
||||
|
||||
static fos::Task movementTest(testMovementTask, "Move", fos::Task::DefaultStackSize * 8);
|
||||
|
||||
while (true) {
|
||||
fos::Task::delayMs(5000);
|
||||
// ESP_LOGI(TAG, "Finish");
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,18 @@
|
||||
#
|
||||
# Compiler options
|
||||
#
|
||||
CONFIG_COMPILER_CXX_EXCEPTIONS=y
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y
|
||||
CONFIG_ESPTOOLPY_FLASHSIZE="8MB"
|
||||
|
||||
#
|
||||
# Log output
|
||||
#
|
||||
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
|
||||
CONFIG_LOG_DEFAULT_LEVEL=3
|
||||
CONFIG_LOG_MAXIMUM_LEVEL_DEBUG=y
|
||||
CONFIG_LOG_MAXIMUM_LEVEL=4
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cmake.cmakePath": "C:/msys64/usr/bin/cmake.exe"
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
|
||||
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)
|
||||
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")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
# 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
|
||||
```
|
||||
@@ -0,0 +1,43 @@
|
||||
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()
|
||||
@@ -3,7 +3,10 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Include the components directory of the main application:
|
||||
#
|
||||
set(EXTRA_COMPONENT_DIRS "../components ../managed_components")
|
||||
set(EXTRA_COMPONENT_DIRS
|
||||
"../../components"
|
||||
# "../../managed_components"
|
||||
)
|
||||
|
||||
# Set the components to include the tests for.
|
||||
# This can be overriden from CMake cache:
|
||||
@@ -0,0 +1,9 @@
|
||||
dependencies:
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.3.0
|
||||
manifest_hash: c4f4ec05313d427eb56c633f78ce213e553379725bf2af3c511665f930571beb
|
||||
target: esp32c6
|
||||
version: 1.0.0
|
||||
Reference in New Issue
Block a user