diff --git a/.gitmodules b/.gitmodules index eac70c4759..5288bc5ec5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -52,3 +52,6 @@ [submodule "ext/segger/rtt"] path = ext/segger/rtt url = https://github.com/modm-ext/segger-rtt.git +[submodule "ext/libeigen/eigen"] + path = ext/libeigen/eigen + url = https://github.com/modm-ext/eigen-partial.git diff --git a/examples/nucleo_g474re/eigen/main.cpp b/examples/nucleo_g474re/eigen/main.cpp new file mode 100644 index 0000000000..af25e5a73c --- /dev/null +++ b/examples/nucleo_g474re/eigen/main.cpp @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2025, Henrik Hose + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include + +using namespace Board; + +Eigen::IOFormat squarebrackets(5, 0, ", ", "\n", "[", "]"); + +int +main() +{ + Board::initialize(); + LedD13::setOutput(); + + while (1) + { + Eigen::Matrix2f mat{{1, 2}, {3, 4}}; + Eigen::Vector2f u{-1, 1}, v{2, 0}; + MODM_LOG_INFO << "Here is mat*mat:\n" << mat * mat << modm::endl; + MODM_LOG_INFO << "Here is mat*u:\n" << mat * u << modm::endl; + MODM_LOG_INFO << "Here is u^T*mat:\n" << u.transpose() * mat << modm::endl; + MODM_LOG_INFO << "Here is u^T*v:\n" << u.transpose() * v << modm::endl; + MODM_LOG_INFO << "Here is u*v^T:\n" << u * v.transpose() << modm::endl; + MODM_LOG_INFO << "Let's multiply mat by itself" << modm::endl; + mat = mat * mat; + MODM_LOG_INFO << "Now mat is mat:\n" << mat.format(squarebrackets)<< modm::endl; + + modm::delay(1s); + } + + return 0; +} diff --git a/examples/nucleo_g474re/eigen/project.xml b/examples/nucleo_g474re/eigen/project.xml new file mode 100644 index 0000000000..732a474539 --- /dev/null +++ b/examples/nucleo_g474re/eigen/project.xml @@ -0,0 +1,11 @@ + + modm:nucleo-g474re + + + + + modm:build:scons + modm:platform:heap + modm:eigen + + diff --git a/ext/gcc/assert.cpp.in b/ext/gcc/assert.cpp.in index 7e52baed0b..6da210635b 100644 --- a/ext/gcc/assert.cpp.in +++ b/ext/gcc/assert.cpp.in @@ -11,7 +11,6 @@ #include #include -#include %% if options["assert_on_exception"] #include diff --git a/ext/libeigen/Version.in b/ext/libeigen/Version.in new file mode 100644 index 0000000000..f4c4c22b1c --- /dev/null +++ b/ext/libeigen/Version.in @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2025, Henrik Hose + * Copyright (c) 2025, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once + +#if __has_include() +# include +#endif + +%% if eigen_no_io +#define EIGEN_NO_IO +%% endif +#define EIGEN_DONT_VECTORIZE +#define EIGEN_DISABLE_UNALIGNED_ARRAY_ASSERT +#define EIGEN_DONT_PARALLELIZE + +#define EIGEN_MALLOC_ALREADY_ALIGNED 1 +#ifndef EIGEN_MAX_ALIGN_BYTES +#define EIGEN_MAX_ALIGN_BYTES 0 +#endif +#ifndef EIGEN_MAX_STATIC_ALIGN_BYTES +#define EIGEN_MAX_STATIC_ALIGN_BYTES 4 +#endif +%# +%% if eigen_no_malloc +#define EIGEN_NO_MALLOC +%% endif +#ifndef EIGEN_STACK_ALLOCATION_LIMIT +#define EIGEN_STACK_ALLOCATION_LIMIT 1024 +#endif + +#ifndef MODM_DEBUG_BUILD +#define EIGEN_NO_DEBUG +#endif + +#include + +#define eigen_assert(cond) \ + modm_assert(cond, "eigen", __FILE__ ":" MODM_STRINGIFY(__LINE__) " -> \"" #cond "\"") + +#include "Version_orig" diff --git a/ext/libeigen/eigen b/ext/libeigen/eigen new file mode 160000 index 0000000000..4d259caf13 --- /dev/null +++ b/ext/libeigen/eigen @@ -0,0 +1 @@ +Subproject commit 4d259caf13a6d62d0d6f20fbede5f3995015b54b diff --git a/ext/libeigen/eigen.lb b/ext/libeigen/eigen.lb new file mode 100644 index 0000000000..1a5464a6fc --- /dev/null +++ b/ext/libeigen/eigen.lb @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# +# Copyright (c) 2025, Henrik Hose +# Copyright (c) 2025, Niklas Hauser +# +# This file is part of the modm project. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# ----------------------------------------------------------------------------- + +def init(module): + module.name = ":eigen" + module.description = """ +# Eigen Linear Algebra Library + + +""" + + +def prepare(module, options): + module.depends(":architecture:assert") + return True + + +def build(env): + env.outbasepath = "modm/ext/eigen" + env.collect(":build:path.include", "modm/ext/eigen") + + env.substitutions = { + "eigen_no_malloc": not env.has_module(":platform:heap"), + "eigen_no_io": not (env.has_module(":io") and env.has_module(":platform:heap")) + } + env.copy("eigen/Eigen", "Eigen", ignore=env.ignore_files("Version")) + env.copy("eigen/Eigen/Version", "Eigen/Version_orig") + env.template("Version.in", "Eigen/Version") diff --git a/ext/libeigen/iostream_eigen.hpp b/ext/libeigen/iostream_eigen.hpp new file mode 100644 index 0000000000..95986c727b --- /dev/null +++ b/ext/libeigen/iostream_eigen.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2025, Henrik Hose + * Copyright (c) 2025, Niklas Hauser + * + * This file is part of the modm project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ +// ---------------------------------------------------------------------------- + +#pragma once +#include + +namespace modm +{ + +template +modm::IOStream& operator<<(modm::IOStream& s, const Eigen::MatrixBase& m) +{ + for (Eigen::Index r = 0; r < m.rows(); ++r) { + for (Eigen::Index c = 0; c < m.cols(); ++c) { + s << m(r, c); + if (c + 1 < m.cols()) s << ", "; + } + if (r + 1 < m.rows()) s << "\n"; + } + return s; +} + +} // namespace modm diff --git a/src/modm/architecture/interface/assert.hpp.in b/src/modm/architecture/interface/assert.hpp.in index e9fa1325c7..6893c910de 100644 --- a/src/modm/architecture/interface/assert.hpp.in +++ b/src/modm/architecture/interface/assert.hpp.in @@ -12,7 +12,6 @@ #pragma once #include "assert.h" -#include %% if core.startswith("avr") #include %% endif @@ -27,13 +26,13 @@ namespace modm enum class Abandonment : uint8_t { - DontCare = Bit0, ///< Do not care about failure. - Ignore = Bit1, ///< Ignore this failure. - Fail = Bit2, ///< This failure is reason for abandonment. - Debug = Bit7 ///< Only set for a debug-only failure. + DontCare = 0b001, ///< Do not care about failure. + Ignore = 0b010, ///< Ignore this failure. + Fail = 0b100, ///< This failure is reason for abandonment. + Debug = 0x80, ///< Only set for a debug-only failure. }; -using AbandonmentBehavior = Flags8; -MODM_TYPE_FLAGS(AbandonmentBehavior); +/// Contains the superset of Abandonment behavior +using AbandonmentBehavior = Abandonment; /// Contains information about the failed assertion. struct modm_packed diff --git a/src/modm/architecture/module.lb b/src/modm/architecture/module.lb index c9ef5c1579..0ff8e46708 100644 --- a/src/modm/architecture/module.lb +++ b/src/modm/architecture/module.lb @@ -53,7 +53,6 @@ class Assert(Module): default="release" if platform == "hosted" else "debug", enumeration=["off", "debug", "release"])) - module.depends(":architecture:register") if platform == "avr": module.depends(":architecture:accessor") return True diff --git a/src/modm/driver/color/tcs3472.hpp b/src/modm/driver/color/tcs3472.hpp index 5795797cea..8500669974 100644 --- a/src/modm/driver/color/tcs3472.hpp +++ b/src/modm/driver/color/tcs3472.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include diff --git a/src/modm/driver/color/tcs3472.lb b/src/modm/driver/color/tcs3472.lb index c2c8732b0f..5608af2d0f 100644 --- a/src/modm/driver/color/tcs3472.lb +++ b/src/modm/driver/color/tcs3472.lb @@ -19,6 +19,7 @@ def init(module): def prepare(module, options): module.depends( ":architecture:i2c.device", + ":architecture:register", ":ui:color", ":math:utils") return True diff --git a/src/modm/driver/display/st7586s.lb b/src/modm/driver/display/st7586s.lb index 59db05f789..268fa15787 100644 --- a/src/modm/driver/display/st7586s.lb +++ b/src/modm/driver/display/st7586s.lb @@ -18,6 +18,7 @@ def init(module): def prepare(module, options): module.depends( ":architecture:fiber", + ":architecture:register", ":ui:display") return True diff --git a/src/modm/driver/display/st7586s_protocol.hpp b/src/modm/driver/display/st7586s_protocol.hpp index 0ee5319344..5ac49faf2c 100644 --- a/src/modm/driver/display/st7586s_protocol.hpp +++ b/src/modm/driver/display/st7586s_protocol.hpp @@ -11,6 +11,7 @@ #pragma once +#include #include /// @cond diff --git a/src/modm/io/iostream.hpp.in b/src/modm/io/iostream.hpp.in index 2591a81677..96fabc45e2 100644 --- a/src/modm/io/iostream.hpp.in +++ b/src/modm/io/iostream.hpp.in @@ -247,6 +247,20 @@ public: %% endif + inline size_t width() const { return 0; } + inline void width(size_t) {} + inline size_t precision() const { return fmt_precision; } + inline size_t precision(size_t p) { + size_t old = fmt_precision; + fmt_precision = p; + return old; + } + inline char fill() const { return ' '; } + inline char fill(char) { + return ' '; + } + + protected: template< typename T > void @@ -273,7 +287,7 @@ protected: void writeInteger(uint64_t value); %% endif -%% if options.with_float +%% if options.with_float and options.with_printf inline void writeFloat(float value) { writeDouble(static_cast(value)); } void writeDouble(const double& value); @@ -303,6 +317,9 @@ private: { if (c) reinterpret_cast(arg)->write(c); } printf_output_gadget_t output_gadget{out_char, this, NULL, 0, INT_MAX}; %% endif +%% if options.with_float and options.with_printf + size_t fmt_precision = 0; +%% endif }; /// @ingroup modm_io diff --git a/src/modm/io/iostream_printf.cpp.in b/src/modm/io/iostream_printf.cpp.in index 57408972a1..15ee8fc61a 100644 --- a/src/modm/io/iostream_printf.cpp.in +++ b/src/modm/io/iostream_printf.cpp.in @@ -147,7 +147,7 @@ void IOStream::writeDouble(const double& value) { %% if options.with_printf - print_floating_point(&output_gadget, value, 0, 0, 0, true); + print_floating_point(&output_gadget, value, fmt_precision, 0, 0, true); %% else if(!std::isfinite(value)) { if(std::isinf(value)) { diff --git a/src/modm/io/module.lb b/src/modm/io/module.lb index 5d7e51eeb3..08e26d925f 100644 --- a/src/modm/io/module.lb +++ b/src/modm/io/module.lb @@ -48,7 +48,7 @@ def build(env): "is_avr": target.platform == "avr", "with_fiber": env.has_module(":processing:fiber"), "family": target.family, - "core": core, + "core": core } env.outbasepath = "modm/src/modm/io" env.copy("iodevice.hpp") diff --git a/src/modm/platform/adc/at90_tiny_mega/module.lb b/src/modm/platform/adc/at90_tiny_mega/module.lb index bbfd0a2b23..6ac09d3b12 100644 --- a/src/modm/platform/adc/at90_tiny_mega/module.lb +++ b/src/modm/platform/adc/at90_tiny_mega/module.lb @@ -27,6 +27,7 @@ def prepare(module, options): module.depends( ":architecture:adc", + ":architecture:register", ":architecture:interrupt", ":platform:gpio", ":math:algorithm") diff --git a/src/modm/platform/can/common/fdcan/module.lb b/src/modm/platform/can/common/fdcan/module.lb index ef90cfaeda..f8330d3629 100644 --- a/src/modm/platform/can/common/fdcan/module.lb +++ b/src/modm/platform/can/common/fdcan/module.lb @@ -21,6 +21,7 @@ def prepare(module, options): module.depends( ":architecture:assert", + ":architecture:register", ":architecture:can", ":architecture:clock") return True diff --git a/src/modm/platform/core/cortex/assert.cpp.in b/src/modm/platform/core/cortex/assert.cpp.in index b33391fd28..912c3ff683 100644 --- a/src/modm/platform/core/cortex/assert.cpp.in +++ b/src/modm/platform/core/cortex/assert.cpp.in @@ -57,22 +57,22 @@ void modm_assert_report(_modm_assertion_info *cinfo) { auto info = reinterpret_cast(cinfo); - AbandonmentBehavior behavior(info->behavior); + uint8_t behavior(uint8_t(info->behavior)); for (const AssertionHandler *handler = &__assertion_table_start; handler < &__assertion_table_end; handler++) { %% if core.startswith("avr") - behavior |= ((AssertionHandler)pgm_read_ptr(handler))(*info); + behavior |= (uint8_t)((AssertionHandler)pgm_read_ptr(handler))(*info); %% else - behavior |= (*handler)(*info); + behavior |= (uint8_t)(*handler)(*info); %% endif } - info->behavior = behavior; - behavior.reset(Abandonment::Debug); - if ((behavior == Abandonment::DontCare) or - (behavior & Abandonment::Fail)) + info->behavior = AbandonmentBehavior(behavior); + behavior &= ~uint8_t(Abandonment::Debug); + if ((behavior == uint8_t(Abandonment::DontCare)) or + (behavior & uint8_t(Abandonment::Fail))) { modm_abandon(*info); %% if core.startswith("cortex-m") diff --git a/src/modm/platform/pwm/sam_x7x/module.lb b/src/modm/platform/pwm/sam_x7x/module.lb index a6b61f2888..717f3b3d0f 100644 --- a/src/modm/platform/pwm/sam_x7x/module.lb +++ b/src/modm/platform/pwm/sam_x7x/module.lb @@ -44,6 +44,7 @@ def prepare(module, options): return False module.depends( + ":architecture:register", ":cmsis:device", ":platform:clock", ":platform:gpio") diff --git a/src/modm/platform/timer/samg/module.lb b/src/modm/platform/timer/samg/module.lb index 127e75abdf..a6332abdc0 100644 --- a/src/modm/platform/timer/samg/module.lb +++ b/src/modm/platform/timer/samg/module.lb @@ -47,6 +47,7 @@ def prepare(module, options): return False module.depends( + ":architecture:register", ":cmsis:device", ":platform:gpio") diff --git a/src/modm/platform/timer/samg/timer_channel_base.hpp.in b/src/modm/platform/timer/samg/timer_channel_base.hpp.in index 26d6c1cb8c..a96a45f2ef 100644 --- a/src/modm/platform/timer/samg/timer_channel_base.hpp.in +++ b/src/modm/platform/timer/samg/timer_channel_base.hpp.in @@ -12,6 +12,7 @@ #pragma once #include "../device.hpp" +#include namespace modm::platform { diff --git a/src/modm/platform/uart/sam-sercom/module.lb b/src/modm/platform/uart/sam-sercom/module.lb index d54bc0436e..7a814c04ff 100644 --- a/src/modm/platform/uart/sam-sercom/module.lb +++ b/src/modm/platform/uart/sam-sercom/module.lb @@ -51,6 +51,7 @@ def prepare(module, options): module.depends( ":architecture:uart", ":architecture:fiber", + ":architecture:register", ":math:algorithm", ":cmsis:device", ":platform:gpio",