Compare commits
14 Commits
6ba4a2ce3d
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 76d6b1583b | |||
| 5ec4a5441a | |||
| 7aa98a8ebd | |||
| 64d6df256d | |||
| 16ebed63c2 | |||
| eee2e6172a | |||
| d6269952a6 | |||
| 6a7213de60 | |||
| ed2fddc427 | |||
| 1694e3bbab | |||
| 02565c9396 | |||
| 00082617d1 | |||
| b8a40aed17 | |||
| cae18b98e7 |
Submodule fantemp/adc updated: 7fe32b9717...5e9dac872a
@@ -9,7 +9,7 @@ namespace {
|
||||
typedef void (*jmp_fn)() __attribute__((noreturn));
|
||||
|
||||
jmp_fn boot = reinterpret_cast<jmp_fn>(0x0000);
|
||||
jmp_fn bootloader = reinterpret_cast<jmp_fn>(0x7E00 / 2);
|
||||
jmp_fn bootloader = reinterpret_cast<jmp_fn>(0x7800 / 2);
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -31,7 +31,7 @@ void Bootloader::reset()
|
||||
|
||||
bool Bootloader::check()
|
||||
{
|
||||
if (pgm_read_byte(reinterpret_cast<uint16_t>(bootloader) * 2) == 0xF8)
|
||||
if (pgm_read_byte(reinterpret_cast<uint16_t>(bootloader) * 2) != 0xFF)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#define F_CPU 16000000
|
||||
#define F_CPU 16'000'000
|
||||
#include <util/delay.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -8,6 +8,7 @@ double Controller::m_resistance;
|
||||
double Controller::m_temperature;
|
||||
uint8_t Controller::m_fanSpeed;
|
||||
bool Controller::m_dataAvailable = false;
|
||||
bool Controller::m_autoMode = true;
|
||||
|
||||
volatile uint32_t Controller::m_adcSampleSum;
|
||||
volatile bool Controller::m_adcSampleReady = false;
|
||||
@@ -28,7 +29,9 @@ void Controller::callback()
|
||||
|
||||
m_resistance = m_thermistor.getResistance(m_adcSample);
|
||||
m_temperature = m_thermistor.getTemperature(m_resistance);
|
||||
m_fanSpeed = mapTemperature(m_temperature);
|
||||
|
||||
if (m_autoMode)
|
||||
m_fanSpeed = mapTemperature(m_temperature);
|
||||
|
||||
pwm::setDuty(m_fanSpeed);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ class Controller {
|
||||
static double m_temperature;
|
||||
static uint8_t m_fanSpeed;
|
||||
static bool m_dataAvailable;
|
||||
static bool m_autoMode;
|
||||
|
||||
static void init();
|
||||
|
||||
|
||||
Submodule fantemp/eeprom updated: 33a4d55f03...3bcba0a191
@@ -81,126 +81,137 @@
|
||||
</ToolNumber>
|
||||
<ToolName>Custom Programming Tool</ToolName>
|
||||
</custom>
|
||||
<AAFDebugger>
|
||||
<AAFDebugFiles>
|
||||
<DebugFile>
|
||||
<path>\Debug\fantemp.lss</path>
|
||||
<AAFSetting>
|
||||
<Label>Lss Files</Label>
|
||||
<Extention>.lss</Extention>
|
||||
<Regex>^\s*(?<address>[a-f0-9]*):\s*.*$</Regex>
|
||||
<DebugEnabled>true</DebugEnabled>
|
||||
<RegexGroups>address</RegexGroups>
|
||||
<DebuggerExpression>$pc</DebuggerExpression>
|
||||
</AAFSetting>
|
||||
</DebugFile>
|
||||
</AAFDebugFiles>
|
||||
</AAFDebugger>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
|
||||
<ToolchainSettings>
|
||||
<AvrGccCpp>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p</avrgcc.common.Device>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>NDEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
|
||||
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
|
||||
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>NDEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<avrgcccpp.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.directories.IncludePaths>
|
||||
<avrgcccpp.compiler.optimization.level>Optimize for size (-Os)</avrgcccpp.compiler.optimization.level>
|
||||
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
|
||||
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
|
||||
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.linker.general.UseVprintfLibrary>True</avrgcccpp.linker.general.UseVprintfLibrary>
|
||||
<avrgcccpp.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
<Value>libprintf_flt</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.linker.libraries.Libraries>
|
||||
<avrgcccpp.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.assembler.general.IncludePaths>
|
||||
</AvrGccCpp>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p</avrgcc.common.Device>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>NDEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize for size (-Os)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
|
||||
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
|
||||
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>NDEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<avrgcccpp.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.directories.IncludePaths>
|
||||
<avrgcccpp.compiler.optimization.level>Optimize for size (-Os)</avrgcccpp.compiler.optimization.level>
|
||||
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
|
||||
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
|
||||
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.linker.libraries.Libraries>
|
||||
<avrgcccpp.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.assembler.general.IncludePaths>
|
||||
</AvrGccCpp>
|
||||
</ToolchainSettings>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
|
||||
<ToolchainSettings>
|
||||
<AvrGccCpp>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p</avrgcc.common.Device>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcc.compiler.optimization.DebugLevel>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
|
||||
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
|
||||
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<avrgcccpp.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.directories.IncludePaths>
|
||||
<avrgcccpp.compiler.optimization.level>Optimize (-O1)</avrgcccpp.compiler.optimization.level>
|
||||
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcccpp.compiler.optimization.DebugLevel>
|
||||
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
|
||||
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
|
||||
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.linker.general.UseVprintfLibrary>True</avrgcccpp.linker.general.UseVprintfLibrary>
|
||||
<avrgcccpp.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
<Value>libprintf_flt</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.linker.libraries.Libraries>
|
||||
<avrgcccpp.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.assembler.general.IncludePaths>
|
||||
<avrgcccpp.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcccpp.assembler.debugging.DebugLevel>
|
||||
</AvrGccCpp>
|
||||
<avrgcc.common.Device>-mmcu=atmega328p</avrgcc.common.Device>
|
||||
<avrgcc.common.outputfiles.hex>True</avrgcc.common.outputfiles.hex>
|
||||
<avrgcc.common.outputfiles.lss>True</avrgcc.common.outputfiles.lss>
|
||||
<avrgcc.common.outputfiles.eep>True</avrgcc.common.outputfiles.eep>
|
||||
<avrgcc.common.outputfiles.srec>True</avrgcc.common.outputfiles.srec>
|
||||
<avrgcc.common.outputfiles.usersignatures>False</avrgcc.common.outputfiles.usersignatures>
|
||||
<avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcc.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcc.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcc.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.symbols.DefSymbols>
|
||||
<avrgcc.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcc.compiler.directories.IncludePaths>
|
||||
<avrgcc.compiler.optimization.level>Optimize (-O1)</avrgcc.compiler.optimization.level>
|
||||
<avrgcc.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcc.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcc.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcc.compiler.optimization.DebugLevel>
|
||||
<avrgcc.compiler.warnings.AllWarnings>True</avrgcc.compiler.warnings.AllWarnings>
|
||||
<avrgcc.compiler.warnings.ExtraWarnings>True</avrgcc.compiler.warnings.ExtraWarnings>
|
||||
<avrgcc.compiler.warnings.Pedantic>True</avrgcc.compiler.warnings.Pedantic>
|
||||
<avrgcc.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -std=c11</avrgcc.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultCharTypeUnsigned>
|
||||
<avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>True</avrgcccpp.compiler.general.ChangeDefaultBitFieldUnsigned>
|
||||
<avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<ListValues>
|
||||
<Value>DEBUG</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.symbols.DefSymbols>
|
||||
<avrgcccpp.compiler.directories.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.compiler.directories.IncludePaths>
|
||||
<avrgcccpp.compiler.optimization.level>Optimize (-O1)</avrgcccpp.compiler.optimization.level>
|
||||
<avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>True</avrgcccpp.compiler.optimization.AllocateBytesNeededForEnum>
|
||||
<avrgcccpp.compiler.optimization.DebugLevel>Maximum (-g3)</avrgcccpp.compiler.optimization.DebugLevel>
|
||||
<avrgcccpp.compiler.warnings.AllWarnings>True</avrgcccpp.compiler.warnings.AllWarnings>
|
||||
<avrgcccpp.compiler.warnings.Pedantic>True</avrgcccpp.compiler.warnings.Pedantic>
|
||||
<avrgcccpp.compiler.miscellaneous.OtherFlags>-fno-threadsafe-statics -Wextra -std=c++17</avrgcccpp.compiler.miscellaneous.OtherFlags>
|
||||
<avrgcccpp.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.linker.libraries.Libraries>
|
||||
<avrgcccpp.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
<Value>%24(PackRepoDir)\Atmel\ATmega_DFP\1.4.346\include</Value>
|
||||
</ListValues>
|
||||
</avrgcccpp.assembler.general.IncludePaths>
|
||||
<avrgcccpp.assembler.debugging.DebugLevel>Default (-Wa,-g)</avrgcccpp.assembler.debugging.DebugLevel>
|
||||
</AvrGccCpp>
|
||||
</ToolchainSettings>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -8,55 +8,115 @@
|
||||
#include "clock.hpp"
|
||||
#include "controller.hpp"
|
||||
|
||||
uint64_t Statistics::m_lastTempSave = 0;
|
||||
double Statistics::m_minTemp;
|
||||
double Statistics::m_maxTemp;
|
||||
uint64_t Statistics::m_lastTemperatureWriteback = 0;
|
||||
uint64_t Statistics::m_lastTemperatureSample = 0;
|
||||
uint32_t Statistics::m_temperatureHistogram[TEMPERATURE_RANGE];
|
||||
|
||||
EEVAR(double, e_minTemp);
|
||||
EEVAR(double, e_maxTemp);
|
||||
namespace {
|
||||
|
||||
// Must be in translation unit and cannot be forward declared
|
||||
EEARRAY(uint32_t, e_temperatureHistogram, Statistics::TEMPERATURE_RANGE);
|
||||
|
||||
// Could be declared in every function that uses it, but that would be code duplication
|
||||
EepromArray<e_temperatureHistogram, EEARRAY_SIZE(e_temperatureHistogram), true> g_eepTemperatureHistogram;
|
||||
|
||||
} // namespace
|
||||
|
||||
void Statistics::init()
|
||||
{
|
||||
m_minTemp = getMinTemp();
|
||||
m_maxTemp = getMaxTemp();
|
||||
|
||||
if (isnan(m_minTemp)) {
|
||||
m_minTemp = type::numeric_limits<double>::max();
|
||||
}
|
||||
if (isnan(m_maxTemp)) {
|
||||
m_maxTemp = type::numeric_limits<double>::lowest();
|
||||
for (uint8_t i = 0; i < g_eepTemperatureHistogram.size(); ++i) {
|
||||
m_temperatureHistogram[i] = g_eepTemperatureHistogram[i];
|
||||
if (m_temperatureHistogram[i] == type::numeric_limits<uint32_t>::max()) {
|
||||
m_temperatureHistogram[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Statistics::callback()
|
||||
{
|
||||
Eeprom<e_minTemp, true> eepromMinTemp;
|
||||
Eeprom<e_maxTemp, true> eepromMaxTemp;
|
||||
|
||||
if (Controller::m_dataAvailable) {
|
||||
if (Controller::m_temperature < m_minTemp) {
|
||||
m_minTemp = Controller::m_temperature;
|
||||
}
|
||||
if (Controller::m_temperature > m_maxTemp) {
|
||||
m_maxTemp = Controller::m_temperature;
|
||||
if (clk::millis() >= m_lastTemperatureSample + TEMPERATURE_SAMPLE_DELAY) {
|
||||
const auto temperature = clampTemperature(static_cast<int8_t>(round(Controller::m_temperature)));
|
||||
++m_temperatureHistogram[temperature];
|
||||
m_lastTemperatureSample = clk::millis();
|
||||
}
|
||||
|
||||
if (clk::millis() >= m_lastTempSave + TEMP_SAVE_DELAY) {
|
||||
eepromMinTemp = m_minTemp;
|
||||
eepromMaxTemp = m_maxTemp;
|
||||
m_lastTempSave = clk::millis();
|
||||
if (clk::millis() >= m_lastTemperatureWriteback + TEMPERATURE_WRITEBACK_DELAY) {
|
||||
saveTemperatureHistogram();
|
||||
m_lastTemperatureWriteback = clk::millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double Statistics::getMinTemp()
|
||||
void Statistics::reset()
|
||||
{
|
||||
Eeprom<e_minTemp, true> eepromMinTemp;
|
||||
return eepromMinTemp;
|
||||
for (uint8_t i = 0; i < TEMPERATURE_RANGE; ++i) {
|
||||
m_temperatureHistogram[i] = 0;
|
||||
g_eepTemperatureHistogram[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
double Statistics::getMaxTemp()
|
||||
uint8_t Statistics::getMinTemperature()
|
||||
{
|
||||
Eeprom<e_maxTemp, true> eepromMaxTemp;
|
||||
return eepromMaxTemp;
|
||||
for (uint8_t i = 0; i < TEMPERATURE_RANGE; ++i) {
|
||||
if (m_temperatureHistogram[i] > 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return TEMPERATURE_RANGE;
|
||||
}
|
||||
|
||||
uint8_t Statistics::getMaxTemperature()
|
||||
{
|
||||
for (int8_t i = TEMPERATURE_RANGE - 1; i >= 0; --i) {
|
||||
if (m_temperatureHistogram[i] > 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return TEMPERATURE_RANGE;
|
||||
}
|
||||
|
||||
uint64_t Statistics::getTotalHistogramSamples()
|
||||
{
|
||||
uint64_t totalSamples = 0;
|
||||
|
||||
for (uint8_t i = 0; i < TEMPERATURE_RANGE; ++i) {
|
||||
totalSamples += m_temperatureHistogram[i];
|
||||
}
|
||||
|
||||
return totalSamples;
|
||||
}
|
||||
|
||||
uint32_t Statistics::getHighestHistogramSamples()
|
||||
{
|
||||
uint32_t max = 0;
|
||||
|
||||
for (uint8_t i = 0; i < TEMPERATURE_RANGE; ++i) {
|
||||
if (m_temperatureHistogram[i] > max) {
|
||||
max = m_temperatureHistogram[i];
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
uint32_t Statistics::getHistogram(const int8_t &temperature)
|
||||
{
|
||||
return m_temperatureHistogram[clampTemperature(temperature)];
|
||||
}
|
||||
|
||||
void Statistics::saveTemperatureHistogram()
|
||||
{
|
||||
for (uint8_t i = 0; i < g_eepTemperatureHistogram.size(); ++i) {
|
||||
g_eepTemperatureHistogram[i] = m_temperatureHistogram[i];
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t Statistics::clampTemperature(const int8_t &temperature)
|
||||
{
|
||||
if (temperature < 0)
|
||||
return 0;
|
||||
if (temperature >= TEMPERATURE_RANGE)
|
||||
return TEMPERATURE_RANGE - 1;
|
||||
return static_cast<uint8_t>(temperature);
|
||||
}
|
||||
|
||||
@@ -4,17 +4,28 @@
|
||||
|
||||
class Statistics {
|
||||
public:
|
||||
static constexpr auto TEMPERATURE_RANGE = 100;
|
||||
|
||||
static void init();
|
||||
static void callback();
|
||||
static void reset();
|
||||
|
||||
static double getMinTemp();
|
||||
static double getMaxTemp();
|
||||
static uint8_t getMinTemperature();
|
||||
static uint8_t getMaxTemperature();
|
||||
|
||||
static uint64_t getTotalHistogramSamples();
|
||||
static uint32_t getHighestHistogramSamples();
|
||||
static uint32_t getHistogram(const int8_t &temperature);
|
||||
|
||||
static void saveTemperatureHistogram();
|
||||
|
||||
private:
|
||||
static constexpr auto TEMP_SAVE_DELAY = 60000;
|
||||
static constexpr auto TEMPERATURE_WRITEBACK_DELAY = 1'800'000;
|
||||
static constexpr auto TEMPERATURE_SAMPLE_DELAY = 1'000;
|
||||
|
||||
static uint64_t m_lastTempSave;
|
||||
static uint64_t m_lastTemperatureWriteback;
|
||||
static uint64_t m_lastTemperatureSample;
|
||||
static uint32_t m_temperatureHistogram[TEMPERATURE_RANGE];
|
||||
|
||||
static double m_minTemp;
|
||||
static double m_maxTemp;
|
||||
static uint8_t clampTemperature(const int8_t &temperature);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
@@ -22,9 +22,13 @@ GF(MONITOR_CMD, "monitor");
|
||||
GF(BOOTLOADER_CMD, "bootloader");
|
||||
GF(UPTIME_CMD, "uptime");
|
||||
GF(STATISTICS_CMD, "statistics");
|
||||
GF(HISTOGRAM_CMD, "histogram");
|
||||
GF(RESET_CMD, "reset");
|
||||
GF(SET_CMD, "set");
|
||||
GF(AUTO_CMD, "auto");
|
||||
|
||||
GF(VERSION_CMD, "version");
|
||||
GF(VERSION, "1.4");
|
||||
GF(VERSION, "1.8");
|
||||
|
||||
static inline bool substringEquals(const char *str, const ::detail::FlashString *flashStr, const size_t &size)
|
||||
{
|
||||
@@ -126,6 +130,26 @@ class Terminal {
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint8_t parseFanSpeed()
|
||||
{
|
||||
const auto setCmdLen = strlen_P(reinterpret_cast<const char *>(detail::SET_CMD));
|
||||
|
||||
if (m_inputSize > setCmdLen && substringEquals(m_inputBuffer, detail::SET_CMD, setCmdLen) &&
|
||||
m_inputSize < INPUT_BUFFER_SIZE) {
|
||||
m_inputBuffer[m_inputSize] = '\0'; // Null terminate to be parsable by stdlib
|
||||
const auto *fanSpeedStr = m_inputBuffer + setCmdLen;
|
||||
auto *fanSpeedStrEnd = m_inputBuffer + setCmdLen;
|
||||
const auto fanSpeed = strtol(fanSpeedStr, &fanSpeedStrEnd, 10);
|
||||
|
||||
if (fanSpeedStrEnd != fanSpeedStr && *fanSpeedStr != '\0' && *fanSpeedStrEnd == '\0') {
|
||||
if (fanSpeed >= 0 && fanSpeed <= 100)
|
||||
return static_cast<uint8_t>(fanSpeed);
|
||||
}
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
static void parseInput()
|
||||
{
|
||||
if (m_inputSize) {
|
||||
@@ -146,6 +170,14 @@ class Terminal {
|
||||
printUptime();
|
||||
} else if (substringEquals(m_inputBuffer, detail::STATISTICS_CMD, m_inputSize)) {
|
||||
printStatistics();
|
||||
} else if (substringEquals(m_inputBuffer, detail::HISTOGRAM_CMD, m_inputSize)) {
|
||||
printHistogram();
|
||||
} else if (stringEquals(m_inputBuffer, detail::RESET_CMD, m_inputSize)) {
|
||||
handleReset();
|
||||
} else if (uint8_t targetFanSpeed = parseFanSpeed(); targetFanSpeed <= 100) {
|
||||
handleSet(targetFanSpeed);
|
||||
} else if (substringEquals(m_inputBuffer, detail::AUTO_CMD, m_inputSize)) {
|
||||
handleAuto();
|
||||
} else if (substringEquals(m_inputBuffer, detail::VERSION_CMD, m_inputSize)) {
|
||||
printVersion();
|
||||
} else {
|
||||
@@ -168,13 +200,17 @@ class Terminal {
|
||||
static void printHelp()
|
||||
{
|
||||
m_serial << F("FanTemp command overview: ") << detail::ENDL;
|
||||
m_serial << detail::HELP_CMD << F(" .......: print this help message") << detail::ENDL;
|
||||
m_serial << detail::HELP_CMD << F(" .......: prints this help message") << detail::ENDL;
|
||||
m_serial << detail::SHOW_CMD << F(" .......: shows current temperature and fan speed") << detail::ENDL;
|
||||
m_serial << detail::CURVE_CMD << F(" ......: shows mapping from temperature to fan speed") << detail::ENDL;
|
||||
m_serial << detail::MONITOR_CMD << F(" ....: loops the show command until Ctrl + C is pressed") << detail::ENDL;
|
||||
m_serial << detail::BOOTLOADER_CMD << F(" .: enters the bootloader after 3 seconds") << detail::ENDL;
|
||||
m_serial << detail::UPTIME_CMD << F(" .....: show system uptime") << detail::ENDL;
|
||||
m_serial << detail::STATISTICS_CMD << F(" .: Print overall statistics like min and max temp") << detail::ENDL;
|
||||
m_serial << detail::UPTIME_CMD << F(" .....: shows system uptime") << detail::ENDL;
|
||||
m_serial << detail::STATISTICS_CMD << F(" .: prints overall statistics like min and max temp") << detail::ENDL;
|
||||
m_serial << detail::HISTOGRAM_CMD << F(" ..: prints a histogram of the temperature") << detail::ENDL;
|
||||
m_serial << detail::RESET_CMD << F(" ......: resets statistics to 0 in EEPROM and RAM") << detail::ENDL;
|
||||
m_serial << detail::SET_CMD << F(" ........: sets the fan speed to the provided value") << detail::ENDL;
|
||||
m_serial << detail::AUTO_CMD << F(" .......: turns on automatic fan control") << detail::ENDL;
|
||||
m_serial << detail::VERSION_CMD << F(" ....: displays firmware version") << detail::ENDL;
|
||||
}
|
||||
|
||||
@@ -183,13 +219,14 @@ class Terminal {
|
||||
if (Controller::m_dataAvailable) {
|
||||
char floatBuffer[16];
|
||||
|
||||
sprintf(floatBuffer, "%.2f", Controller::m_adcSample);
|
||||
dtostrf(Controller::m_adcSample, 0, 2, floatBuffer);
|
||||
m_serial << F("ADC value ...: ") << floatBuffer << F(" / 1023") << detail::ENDL;
|
||||
sprintf(floatBuffer, "%.2f", Controller::m_resistance);
|
||||
dtostrf(Controller::m_resistance, 0, 2, floatBuffer);
|
||||
m_serial << F("Resistance ..: ") << floatBuffer << F(" Ohm") << detail::ENDL;
|
||||
sprintf(floatBuffer, "%.2f", Controller::m_temperature);
|
||||
dtostrf(Controller::m_temperature, 0, 2, floatBuffer);
|
||||
m_serial << F("Temperature .: ") << floatBuffer << F(" C") << detail::ENDL;
|
||||
m_serial << F("Fan speed ...: ") << Controller::m_fanSpeed << F("%") << detail::ENDL;
|
||||
m_serial << F("Fan speed ...: ") << Controller::m_fanSpeed << F("%")
|
||||
<< (Controller::m_autoMode ? F(" auto") : F(" manual")) << detail::ENDL;
|
||||
} else {
|
||||
m_serial << F("No data available yet!") << detail::ENDL;
|
||||
}
|
||||
@@ -202,7 +239,7 @@ class Terminal {
|
||||
m_serial.template txNumber<uint8_t, 10, 3, ' '>(Controller::mapTemperature(i));
|
||||
m_serial << F("%\t");
|
||||
for (uint8_t s = 0; s < Controller::mapTemperature(i); ++s) {
|
||||
m_serial << "#";
|
||||
m_serial << '#';
|
||||
}
|
||||
m_serial << detail::ENDL;
|
||||
}
|
||||
@@ -210,6 +247,9 @@ class Terminal {
|
||||
|
||||
static void handleBootloader()
|
||||
{
|
||||
m_serial << F("Saving statistics to EEPROM") << detail::ENDL;
|
||||
Statistics::saveTemperatureHistogram();
|
||||
|
||||
m_serial << F("Entering bootloader...") << detail::ENDL;
|
||||
m_serial.flushTx();
|
||||
|
||||
@@ -239,12 +279,75 @@ class Terminal {
|
||||
|
||||
static void printStatistics()
|
||||
{
|
||||
char floatBuffer[16];
|
||||
const auto minTemp = Statistics::getMinTemperature();
|
||||
const auto maxTemp = Statistics::getMaxTemperature();
|
||||
|
||||
sprintf(floatBuffer, "%.2f", Statistics::getMinTemp());
|
||||
m_serial << F("Minimum temperature .: ") << floatBuffer << F(" C") << detail::ENDL;
|
||||
sprintf(floatBuffer, "%.2f", Statistics::getMaxTemp());
|
||||
m_serial << F("Maximum temperature .: ") << floatBuffer << F(" C") << detail::ENDL;
|
||||
m_serial << F("Minimum temperature .: ");
|
||||
if (minTemp != Statistics::TEMPERATURE_RANGE) {
|
||||
m_serial << minTemp << F(" C");
|
||||
} else {
|
||||
m_serial << F("Not available");
|
||||
}
|
||||
|
||||
m_serial << detail::ENDL << F("Maximum temperature .: ");
|
||||
if (maxTemp != Statistics::TEMPERATURE_RANGE) {
|
||||
m_serial << maxTemp << F(" C");
|
||||
} else {
|
||||
m_serial << F("Not available");
|
||||
}
|
||||
m_serial << detail::ENDL;
|
||||
}
|
||||
|
||||
static void printHistogram()
|
||||
{
|
||||
const auto totalSamples = Statistics::getTotalHistogramSamples();
|
||||
|
||||
if (totalSamples > 0) {
|
||||
const auto maximumSamples = Statistics::getHighestHistogramSamples();
|
||||
auto normalizationFactor = (maximumSamples / 100 > 1) ? (maximumSamples / 100) : 1;
|
||||
|
||||
while (maximumSamples / normalizationFactor > 100)
|
||||
++normalizationFactor;
|
||||
|
||||
for (uint8_t t = Statistics::getMinTemperature(); t <= Statistics::getMaxTemperature(); ++t) {
|
||||
const auto histogramSamples = Statistics::getHistogram(t);
|
||||
m_serial.template txNumber<uint8_t, 10, 2>(t);
|
||||
m_serial << F(" C = ");
|
||||
const auto percent =
|
||||
static_cast<uint8_t>((2 * 100 * histogramSamples + totalSamples) / (2 * totalSamples));
|
||||
m_serial.template txNumber<uint8_t, 10, 3, ' '>(percent);
|
||||
m_serial << F("%\t");
|
||||
const auto normalizedSamples = static_cast<uint8_t>(histogramSamples / normalizationFactor);
|
||||
for (uint8_t i = 0; i < normalizedSamples; ++i) {
|
||||
m_serial << '#';
|
||||
}
|
||||
m_serial << detail::ENDL;
|
||||
}
|
||||
} else {
|
||||
m_serial << F("There is no data yet!") << detail::ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
static void handleReset()
|
||||
{
|
||||
m_serial << F("Resetting statistics in EEPROM and RAM") << detail::ENDL;
|
||||
Statistics::reset();
|
||||
m_serial << F("Reset statistics") << detail::ENDL;
|
||||
}
|
||||
|
||||
static void handleSet(uint8_t targetFanSpeed)
|
||||
{
|
||||
m_serial << F("Setting fan speed to ");
|
||||
m_serial.txNumber(targetFanSpeed);
|
||||
m_serial << detail::ENDL;
|
||||
Controller::m_autoMode = false;
|
||||
Controller::m_fanSpeed = targetFanSpeed;
|
||||
}
|
||||
|
||||
static void handleAuto()
|
||||
{
|
||||
m_serial << F("Turning on automatic fan control") << detail::ENDL;
|
||||
Controller::m_autoMode = true;
|
||||
}
|
||||
|
||||
static void printVersion()
|
||||
|
||||
Submodule fantemp/uart updated: ae03c8d43e...04b6782ec4
Reference in New Issue
Block a user