// Test-fixture application for the pureboot protocol tests: prints "APP" on // the chip's serial link (the same link the loader uses) — the proof that // the loader's hand-over, and on the tinies the host's reset-vector // surgery, actually launched it. Linked normally (crt, vectors at 0); on // the tinies its reset vector is the rjmp the host re-homes. // // On the mega it then listens, and an 'L' makes it jump into the resident // loader — the application-owned loader entry a BOOTRST-unprogrammed mega // relies on (reset always boots the application there), exercised by the // self-update tests. The tinies idle: reset reaches their loader through // the patched vector, so the application owes it nothing. #include using namespace avr::literals; namespace { consteval avr::hertz_t clock() { if (avr::hw::db.name == "ATtiny13A") return 9.6_MHz; if (avr::hw::db.name == "ATtiny85") return 8_MHz; return 16_MHz; } using dev = avr::device<{.clock = clock()}>; template struct link { using tx_t = avr::uart::usart0; static void tx(char c) { tx_t::write(static_cast(c)); } [[noreturn]] static void idle() { // 'L' hands back to the loader at the top slot — 512 bytes, or the // 1 KiB the >64 KiB chips use. constexpr std::uint32_t slot = avr::hw::db.mem.flash_size > 65536 ? 1024 : 512; for (;;) if (tx_t::read_blocking() == 'L') reinterpret_cast(static_cast((avr::hw::db.mem.flash_size - slot) / 2))(); } }; template struct link { using tx_t = avr::uart::software_tx; static void tx(char c) { tx_t::write(static_cast(c)); } [[noreturn]] static void idle() { while (true) { } } }; } // namespace int main() { avr::init::tx_t>(); link::tx('A'); link::tx('P'); link::tx('P'); link::idle(); }