#pragma once #include #include #include // The auto-mode fan curve, tabulated at compile time as a flash_table of duty // percent per C: a cubic that is held at zero below the temperature the fan // starts at. namespace app::curve { inline constexpr double cubic_term = 0.002246; inline constexpr double square_term = -0.09; inline constexpr double linear_term = 0.91; inline constexpr std::int8_t start_celsius = 20; namespace detail { consteval std::uint8_t duty_entry(std::int32_t celsius) { double x = celsius; if (x < start_celsius) { return 0; } double duty = cubic_term * x * x * x + square_term * x * x + linear_term * x; if (duty < 0) { duty = 0; } if (duty > 100) { duty = 100; } return static_cast(duty + 0.5); } inline constexpr avr::flash_table<[] { std::array out{}; for (std::int32_t t = 0; t < static_cast(out.size()); ++t) { out[static_cast(t)] = duty_entry(t); } return out; }()> table; } // namespace detail // Duty percent for a temperature, clamped to the table's own window. inline std::uint8_t duty(std::int8_t celsius) { constexpr auto highest = static_cast(detail::table.size() - 1); if (celsius < 0) { celsius = 0; } if (celsius > highest) { celsius = highest; } return detail::table[static_cast(celsius)]; } } // namespace app::curve