`(quarters + 2) / 4` is round-half-up only for positive values: C truncates a negative quotient toward zero, so -3.00 C read as -2, -1.00 C as 0 and -0.75 C as 0 - nine of fifteen negative quarter-values off by a whole degree, always toward zero. `(quarters + 2) >> 2` is an arithmetic shift, which floors, and is right across the whole range. It is also smaller: the shift skips the bias correction signed division needs. The formula was written three times - thermistor::celsius(), which nothing called, and inline at both live call sites - so the defect had three homes and so would its fix. One `thermistor::whole_degrees()` now, called from both, and the dead entry point is gone (rules 6, 27). test/consteval.cpp is new and is what should have caught it: whole_degrees across zero including both ties and both table limits, the curve's start and saturation points and its monotonicity, and the thermistor table anchored where the Beta equation fixes it - the count at which the divider reads the thermistor's nominal resistance must read the nominal temperature - plus both clamps and the fall across every step. Red-green: four assertions fire against the old division. Beside it: the cubic's three coefficients are named rather than inlined and restated in prose (rule 5), the consteval table builders take explicit 32-bit types (rule 25), the curve's clamp reads the table's own size (rule 36), and the serial override says what expects the rate rather than what the board has always done (rules 12, 13). And bootloader::handle_reset()'s watchdog diversion is gone. Its own comment called it a leftover "kept only because it is free and cannot hurt", and it did not: pureboot peeks WDRF without clearing it and hands back on purpose, so a watchdog reset arrives here with the flag still set and the diversion jumped into the loader with MCUSR already cleared - opening the activation window that policy exists to close. Clearing MCUSR is the whole job and stays. 8206 -> 8168 bytes, byte-identical between generated and reflect. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
22 lines
1.0 KiB
CMake
22 lines
1.0 KiB
CMake
# The battery is a compile: a static_assert that fails is the failure. It is a
|
|
# target rather than only a ctest so a plain build catches a regression too.
|
|
add_library(consteval_tests OBJECT consteval.cpp)
|
|
target_include_directories(consteval_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../src)
|
|
target_link_libraries(consteval_tests PRIVATE libavr)
|
|
|
|
add_test(NAME fantemp.consteval
|
|
COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target consteval_tests)
|
|
|
|
# The board has no reset line and no programming header, so the loader-entry
|
|
# route in the emitted image is the only thing standing between a firmware change
|
|
# and an unreflashable board.
|
|
find_package(Python3 COMPONENTS Interpreter)
|
|
if(Python3_FOUND)
|
|
add_test(NAME fantemp.reachability
|
|
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check_reachability.py
|
|
--objdump ${CMAKE_OBJDUMP} --elf $<TARGET_FILE:fantemp>
|
|
--image $<TARGET_FILE_DIR:fantemp>/fantemp.bin)
|
|
else()
|
|
message(STATUS "Python not found - the reachability check is skipped")
|
|
endif()
|