Skip to content

Releases: jclima/almanac

Almanac v1.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Aug 08:08

A feature release. The device gains a puzzle and an honest answer to "what
version am I running?", and the repository gains a release process and a
host-side tool that builds a daily briefing you can read on the panel.

The minor bump is the scope change, not the line count: SCOPE.md now has a
third mission pillar, and this is the release that opens it.

2048

A new Home tile. Four directions, one screen update per move, best score kept
across games.

It is worth being clear about what this is, because the document that governs
this fork used to forbid it. SCOPE.md listed "Interactive apps — games,
calculators, notepads" as out of scope. Rather than quietly cross that line,
this release moves it: the Mission gains "Pass the time — a small turn-based
diversion for when you are waiting and not reading"
, and a new Diversions
section puts a frame around the door it opens. A diversion is in scope only if
all four hold:

  1. Turn-based. One user action, one screen update. Anything that assumes a
    frame rate is out — the panel refreshes in 770–1720 ms.
  2. Playable on the buttons we have. Seven physical buttons, four
    directional. This is what rules out text adventures, despite their being a
    natural e-reader match.
  3. No network. Ever. Not even optional.
  4. No steady-state RAM. State measured in bytes, no heap allocation,
    nothing retained while you are reading.

2048 was chosen because it passes all four rather than because it was the most
wanted: the board is 16 cells stored as exponents, the four directions map onto
the screen-direction buttons the input layer already rotates per orientation,
and there is no heap allocation anywhere in the feature.

Emulators are permanently out, and SCOPE.md now records why so it does
not have to be re-argued: every working ESP32 port of an NES- or Game Boy-class
emulator needs PSRAM, which the C3 does not have, and a frame rate this panel
cannot produce.

Practical details:

  • The board is drawn with FAST_REFRESH per move and a HALF_REFRESH deghost
    pass on a cycle, following the reader's own refresh discipline. A move that
    changes nothing refreshes nothing, so a blocked swipe costs no ink time.
  • The game is saved to /.crosspoint/2048.json once, on exit, behind a dirty
    flag — never per move. SPIFFS and SD erase cycles are finite and page turns
    already spend them.

The running version is now visible

Settings shows the firmware version the device is actually running. Previously
the only way to know was to remember what you flashed.

A daily briefing, built on your computer

New host-side tool: scripts/generate_dashboard_epub.py. It fetches weather,
news headlines, sun and moon times, and aircraft currently overhead, renders
them to a dated EPUB, and uploads it to the device over the File Transfer
screen you already use.

python3 -m venv .venv && .venv/bin/pip install -r scripts/requirements.txt
.venv/bin/python scripts/generate_dashboard_epub.py

No firmware code changed for this. That is the whole design, and it is why
a feature that fetches RSS can exist in a project whose scope document rules
out RSS: the exclusion protects the device's RAM, flash and battery, and this
spends none of them. The radio comes up only for the File Transfer session you
start by hand. The device's side of it is opening an EPUB, which it already
knew how to do.

Every section fails independently — if a source is unreachable it renders as
"unavailable" with a reason and the page still builds. See
docs/mini-dashboard.md.

Fixes and internals

  • The SDL2 simulator builds and runs again. Three regressions had stacked
    up against an environment CI does not build: [env:simulator] was the last
    place still defining CROSSPOINT_VERSION after the rename, an
    unconditional sdkconfig.h include had started reaching the host build
    through OtaUpdater.h, and the external simulator library's
    SecureHttpClient shim had drifted behind freeink-sdk. It is still not in
    CI, so it will drift again.
  • Release machinery. A manual Release Train workflow now resolves the next
    version, bumps platformio.ini and README.md, drafts notes, and tags —
    behind gates that refuse to release from a non-develop ref, on red CI, or
    on a docs-only diff. Its version and notes logic is host-testable and
    covered by scripts/test_release_train.py.
  • Nearby Flights is documented in the user guide.
  • The contributor guide's font IDs were wrong. It named FONT_UI_MEDIUM
    and FONT_UI, neither of which exists; code written against it would not
    compile.

Upgrading

Settings → Check for Update works from 1.0.1 or later. If you are still on
1.0.0, its update check is the bug 1.0.1 fixed and cannot be relied on — flash
firmware.bin over USB at offset 0x10000 once, and OTA is trustworthy from
there.

Settings, caches and reading progress in /.crosspoint/ are unaffected. This
release adds /.crosspoint/2048.json; nothing existing is rewritten.

Assets

firmware.bin is the gh_release build for the Xteink X4/X3. For a device
coming from stock or CrossPoint, flash all three binaries:

esptool.py --chip esp32c3 write_flash 0x0 bootloader.bin 0x8000 partitions.bin 0x10000 firmware.bin

firmware.elf and firmware.map are for symbolicating crash traces. There is
no Seeed Sticky binary — it is a different MCU family and has to be built from
source (pio run -e sticky).

This build uses 15.6% of RAM (51,156 of 327,680 bytes) and 84.4% of the
application partition (5,531,127 of 6,553,600 bytes).

Lineage

Almanac is a hard fork of
CrossPoint Reader by
Dave Allie and contributors (MIT licence). It takes no further merges from
upstream and sends nothing back. If you want the reader without the aviation
and theming additions, use CrossPoint — it is the better-maintained, more
widely tested project.

Almanac v1.0.2

Choose a tag to compare

@github-actions github-actions released this 09 Aug 23:10

A fix release. Both firmware-install paths now refuse an image built for a
different MCU, and the Home screen loses two visible rough edges.

This is also the first release a device can reach over the air: 1.0.1 fixed the
update check that 1.0.0 got wrong, so a 1.0.1 device will see and install this
one normally.

Firmware installs now check the MCU

Almanac builds for two different chips — the Xteink X4/X3 on an ESP32-C3 and
the Seeed Sticky on an ESP32-S3 — and releases publish only the C3 binary. Two
separate paths could accept the wrong one. Neither could damage a device, but
both wasted the user's time and ended in a message that didn't explain itself.

  • Over the air, a Sticky was offered the X4's firmware. The version
    comparison sees only the release's version number, which says nothing about
    the chip, so a release newer than the running build read as an available
    update on any device. A Sticky would download 5.5MB and then fail: the write
    is verified by esp_ota_end(), which checks the image header's chip id
    against the running build and refuses a mismatch before anything reboots, so
    this was a wasted transfer rather than a bad flash. The update check now
    knows no binary is published for its MCU and reports no update without
    bringing the radio up.

  • From the SD card, any wrong image was accepted. This one is broader — it
    affects the X4 too, not just the Sticky, because the file is whatever the
    user copied onto the card. Validation checked the size, the magic byte, the
    segment table, the XOR checksum and the SHA256 trailer; an image for another
    chip passes every one of those, because it is perfectly well formed, just not
    runnable here. Nor did anything downstream catch it: this path writes with
    raw partition writes and switches boot by hand, so it never reaches the
    ESP-IDF verification the OTA path gets. The wrong image was written in full
    and only the bootloader refused it, one reboot later. Validation now reads
    the chip id out of the image header and stops with "Firmware is for another
    device".

The Sticky consequence of the first fix, stated plainly: a Sticky has no
update path.
It will report no update indefinitely, which is correct while no
Sticky binary is published — keep it current by building and flashing from
source.

Home screen

  • The masthead mark read as visibly pixelated on device. The bezel ring's
    stroke scales with the mark, so at 64px it rounded to a single pixel, and a
    1px circle cannot render smoothly on a 1-bit panel — it stair-steps. The four
    inter-cardinal ticks had collapsed to specks for the same reason. The mark is
    now 96px, the largest whole-8 size that still fits the masthead, which lands
    the ring at 2px.

  • A book whose EPUB metadata carries a whitespace-only title drew a Continue
    Reading tile with a selection frame and nothing inside it. Only a strictly
    empty title triggered the generic-label fallback; a blank one passed the
    guard. Blank titles now fall back too.

Upgrading

Settings → Check for Update works from 1.0.1. If you are still on 1.0.0,
its update check is the bug 1.0.1 fixed and cannot be relied on — flash
firmware.bin over USB at offset 0x10000 once, and OTA is trustworthy from
there.

Settings, caches and reading progress in /.crosspoint/ are unaffected.

Assets

firmware.bin is the gh_release build for the Xteink X4/X3. For a device
coming from stock or CrossPoint, flash all three binaries:

esptool.py --chip esp32c3 write_flash 0x0 bootloader.bin 0x8000 partitions.bin 0x10000 firmware.bin

firmware.elf and firmware.map are for symbolicating crash traces. There is
no Seeed Sticky binary — it is a different MCU family and has to be built from
source (pio run -e sticky).

Lineage

Almanac is a hard fork of
CrossPoint Reader by
Dave Allie and contributors (MIT licence). It takes no further merges from
upstream and sends nothing back. If you want the reader without the aviation
and theming additions, use CrossPoint — it is the better-maintained, more
widely tested project.

Almanac v1.0.1

Choose a tag to compare

@github-actions github-actions released this 08 Aug 15:11

A fix release. The headline change is that the OTA update check now reads this
repository's release tags correctly; in 1.0.0 its result was indeterminate.

Fixed

  • OTA update check could not parse Almanac's release tags. OtaUpdater
    compared the release's raw tag_namealmanac-v1.0.0 — against the
    firmware's bare ALMANAC_VERSION using sscanf("%d.%d.%d", ...). sscanf
    fails to match on the leading almanac-v, returns 0 and leaves its outputs
    untouched, so the comparison ran on three uninitialized stack values: the
    result was indeterminate, and could report an update that did not exist.
    Version comparison now lives in lib/Version/SemVer, which skips a
    non-numeric tag prefix, requires a complete major.minor.patch triple, and
    reports "no update" for anything it cannot parse rather than acting on
    half-read numbers. Covered by 13 host tests.

    Bare numeric tags are not an alternative here: 0.4.0 through 1.5.0
    already exist in this repository, inherited from CrossPoint.

  • UITheme::adjustedMetrics is value-initialized. No behaviour change —
    getMetrics() already overwrote it before any read — but it removes the
    uninitialized-member gap cppcheck flagged.

  • The Flight Tracker zip-code digit check uses std::all_of, keeping the
    explicit '0''9' range test rather than the locale-dependent
    std::isdigit, which is undefined for the negative char values a UTF-8
    lead byte produces.

Releases and tooling

  • Tagging almanac-v* now builds and publishes the release with its five
    assets attached; previously the workflow stopped at uploading CI artifacts
    and the release page was assembled by hand. The job also fails if the tag
    disagrees with [almanac] version in platformio.ini, since a release whose
    binary reports an older version than its tag would offer every device an
    update it can never satisfy.

  • Release notes are kept in docs/release-notes/<tag>.md so they are reviewed
    alongside the change.

  • scripts/gen_compiledb.py generates a working compile_commands.json for
    clangd. pio run -t compiledb does not produce a usable one in this project.

Documentation

  • The README's install section pointed at "no binaries yet"; it now points at
    the releases page, with flash offsets for both an update and a from-scratch
    flash.
  • The README documents zip-code home-location entry for the Flight Tracker and
    the simulator build environment, both of which existed but were unlisted.

Upgrading

From 1.0.0, flash over USB. Whether 1.0.0 offers this release is exactly
what was indeterminate — it may, it may not, and that is the bug being fixed.
Don't wait to find out: flash firmware.bin at offset 0x10000. The update
check is trustworthy from 1.0.1 onward.

The firmware is otherwise functionally identical to 1.0.0 on device. Settings,
caches and reading progress in /.crosspoint/ are unaffected.

Assets

firmware.bin is the gh_release build for the Xteink X4/X3. For a device
coming from stock or CrossPoint, flash all three binaries:

esptool.py --chip esp32c3 write_flash 0x0 bootloader.bin 0x8000 partitions.bin 0x10000 firmware.bin

firmware.elf and firmware.map are for symbolicating crash traces. There is
no Seeed Sticky binary — it is a different MCU family and has to be built from
source (pio run -e sticky).

Lineage

Almanac is a hard fork of
CrossPoint Reader by
Dave Allie and contributors (MIT licence). It takes no further merges from
upstream and sends nothing back. If you want the reader without the aviation
and theming additions, use CrossPoint — it is the better-maintained, more
widely tested project.

Almanac v1.0.0

Choose a tag to compare

@jclima jclima released this 08 Aug 01:59

Almanac's first tagged release, for the Xteink X4 (ESP32-C3).

What it does

  • Nearby Flights — fetches aircraft near a configured home location from OpenSky Network's free API, shown as a distance-sorted list, a radar view with range rings and heading-oriented markers, and a detail screen with an on-demand aircraft-type/registration lookup via adsbdb.
  • Home location by zip code — set your Flight Tracker home location by typing a 5-digit US zip code instead of raw lat/lon; geocoded via Zippopotam.us. Manual lat/lon entry remains available as a fallback.
  • Reading, inherited from CrossPoint Reader: EPUB 2/3 with embedded styles/images/hyphenation/kerning, chapter navigation, footnotes, bookmarks, StarDict dictionary lookups, go-to-percent, auto page turn, orientation control, focus reading, KOReader progress sync, .epub/.xtc/.xtch/.txt/.bmp, custom SD fonts, WiFi file transfer/OPDS/WebDAV/Calibre wireless, OTA updates, 31 UI languages with RTL support.
  • Tesserae sleep screens — a self-hosted, server-rendered dashboard shown when the reader sleeps, with monochrome and 4-level grayscale support on X3/X4 panels.
  • Almanac theme — an instrument-panel look: solid black header/footer bars, a framed list with hairline separators, two-level row selection, its own boot splash/sleep screen/compass-rose mark. It's the firmware's only theme.

Status

Built and flashed on real X4 hardware. Verified by CI on every change: build (default/sticky environments), the host unit-test suite, clang-format (pinned to v21), and cppcheck (fails on any finding).

Verified on device: boots to Home, reads settings/caches from SD, no off-panel draw errors, no panics. Not yet verified on device: the theme across all screens in every orientation, the flight tracker end to end on this exact release build, and reading progress surviving an upgrade. This is one person's firmware on one device — treat it accordingly.

Install

Flash firmware.bin at offset 0x10000, or use the full set (bootloader.bin, partitions.bin, firmware.bin) with esptool.py / PlatformIO's uploader for a from-scratch flash. firmware.elf and firmware.map are included for crash-trace symbolication.

See README.md and USER_GUIDE.md for the full feature list, build instructions, and settings reference.

Lineage

Almanac is a hard fork of CrossPoint Reader by Dave Allie and contributors (MIT licence). It takes no further merges from upstream and sends nothing back. If you want the reader without the aviation/theming additions, use CrossPoint — it's the better-maintained, more widely tested project.