The scan only sees NFC data. It cannot sense whether a label's display
listens for infrared or radio, so the messages now say what was found
instead of naming a vendor or a transport as fact.
- "VUSION tag / SES-imagotag uses radio, not IR" becomes "Likely radio
tag / Link: nfc.imagotag.com / TagTinker is IR-only".
- Match an http:// or https:// link whose host is nfc.imagotag.com
(case-insensitive), as prefix code 0x03/0x04 or inline after 0x00,
instead of the substring "imagotag" anywhere in the URL. A "://"
inside a path, query or fragment is not taken as the scheme.
- "Not a Pricer tag" becomes "Unrecognized tag / No ID TagTinker can
decode"; "Unsupported chip" becomes "Unreadable chip / Chip answered
but no data was read".
- Move the decision into tagtinker_nfc_classify() so it can be tested
off-device.
- De-duplicate on UID and result together. The firmware reports a read
that stops partway as a success with fewer pages, so a UID-only check
could keep a tag stuck on "Unrecognized tag" after a partial first
read.
- Announce an unreadable chip once until the field is empty. Those reads
carry no UID, so UID de-duplication never applied and the message
repeated on every poll.
- Bring the prompt back from the scene tick instead of a popup callback.
A popup with a callback consumes every short press, so Back only
dismissed the message and a second Back was needed to leave.
- Stop the scanner on the Back event rather than waiting for on_exit, so
the poll loop is already winding down when the scene is popped and the
join there is as short as possible. On device, leaving from a message
takes exactly one Back.
- Move custom event ids to 200+. NfcScanEventSuccess was 100, the same
id as the target menu's "+ Type Barcode" item.
- Stop the scan LED when "Target list full" ends scanning.
- README: add "Which tags work", with vendor-documented radio examples
and a table of what each scan message means.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A tag whose type code is not in the profile table has no dimensions, so
after the unknown-profile guard its Set Text / Set Image / WiFi Plugins
actions are hidden. This adds a "Set Custom Size" action for those tags:
enter width, height and colour, and the graphics actions become usable.
The IR framing is identical to a table profile; only the screen geometry
differs, so no protocol is guessed. Custom size is applied only when the
barcode's type is not in the table, so a real profile is never overridden.
- New scene (VariableItemList): Width and Height in 8 px steps from 8 to
800, Colour mono/red/yellow, and Save.
- tagtinker_target_refresh_profile() synthesizes a "Custom" profile from
the stored size for unknown-type targets, so Show Tag Info, Set Text
and Set Image all see real dimensions.
- targets.txt gains three optional fields (barcode|name|cw|ch|ccolor);
older two-field lines still load, with no custom size.
- "Set Custom Size" appears in Target Actions only for unknown-type
targets (tagtinker_type_is_known()).
Builds clean on release SDK 1.4.3 (API 87.1) and dev SDK; no new
clang-format drift.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
tx_bmp_open() accepted 24- and 32-bit BMPs of any width, then each source
row was read into uint8_t row_buf[128] on the stack. A 24-bit BMP wider
than 42 px, or a 1-bit BMP wider than 1024 px, overran it. The decoder
also reads one bit per pixel, so 24/32-bit files were misread anyway.
A host build of the previous code under AddressSanitizer reports a
132-byte write into the 128-byte buffer for a 24-bit, 43 px wide file.
- Accept only 1bpp and the stacked-plane "2bpp" layout, reject zero or
over-16-bit sizes, and reject rows wider than TX_BMP_ROW_BUF_SIZE.
- Read header fields as uint32_t. Shifting into bit 31 of an int and
negating INT32_MIN were undefined.
- The result screen showed "Flipped ;)" and played the success sound
even when the send failed or was cancelled. Show "Send failed" with
the error sound, or "Stopped" with no sound when cancelled with Back.
- Check for a stop request after the gap between frames of a sequence.
tagtinker_ir_transmit() clears the stop flag on entry, so a Back
pressed during the gap was lost and the next frame went out in full.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A tag whose type code is not in the profile table gets a zeroed profile:
kind Unknown, 0x0, Mono. NFC scan, targets.txt and web_job.txt (and the
unreachable phone-sync code) all create such targets, and because only
Segment was excluded they were offered Set Text, Set Image and WiFi
Plugins. Set Text on a 0x0 job reaches malloc(0), which the firmware
treats as a fatal error.
- Offer Set Text, Set Image and WiFi Plugins only for dot-matrix
profiles found in the table; the app has no display size for others.
- Show Tag Info says the type is not in the profile table and which
actions are hidden, instead of reporting "Size: 0x0" and "Color: Mono".
- Refuse a 0x0 text job before either sized text path allocates.
- Manual barcode entry with all 16 slots used now shows "Target List
Full". It used to open Target Actions with selected_target -1, where
Show Tag Info and LED Test index targets[-1].
- Widget buttons call back on press, short press and release, so the
Back button went back twice. Act on the short press only.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Default image page is 2 unless the user picked 2-7. Set Text packs planes instead of 45KB buffers. WiFi and odd-size BMPs use glass 296x152 then transpose.
Co-authored-by: Cursor <cursoragent@cursor.com>
These tags look like 296x152 but the firmware only takes 152x296, so landscape BMPs get transposed. Tested on a real 2.6 color tag.
Co-authored-by: Cursor <cursoragent@cursor.com>
Worker (cloud-plugins/):
- New plugin 'GitHub Profile': avatar dithered upper-left, display
name + @handle (with accent star) + word-wrapped bio in the right
column, followers/repos line, and a 53x7 contribution heatmap
with an accent palette (red dots for everyday activity, black for
the rare hottest days). Tuned for 208x112 ESLs and adapts to
296x128 with a bigger avatar and roomier heatmap.
- Identicon plugin gains DiceBear style selector (pixel-art /
bottts / lorelei / adventurer / micah / fun-emoji / shapes) on
top of the original symmetric grid 'local' mode. Both are
rendered through the new shared image_util pipeline.
- Crypto plugin redesigned: editorial layout with corner brackets,
bold price headline, white-knockout delta badge with a real
triangle glyph, currency symbol prefix using the canvas font's
new euro / pound / yen glyphs, and a stippled accent fill under
the sparkline.
Canvas:
- setPixel is now last-write-wins across planes, so drawing black
on top of an accent-filled area produces a clean black pixel
instead of the muddy plane-conflict the e-paper driver was
showing previously. Every pixel is therefore exactly one of
white / black / accent which is what plugin authors intuit.
- New whitePixel + drawTextWhite primitives for knockout text
(e.g. white labels punched through a coloured badge).
- FONT_EXTRA shipped with the canvas for currency / arrow / shape
/ star / bracket glyphs. Plugins can now write '\u20AC1234' and
have the euro symbol Just Work.
Image pipeline (new image_util.ts):
- One fetchImageGray() that sniffs PNG vs JPEG, decodes via
upng-js / jpeg-js, composites alpha over white, and returns a
tightly-packed grayscale buffer.
- One blitGrayDither() that nearest-neighbour scales the gray
buffer to a destination rect and serpentine Floyd-Steinberg
dithers it on the way in. Used by identicon and github.
FAP:
- WiFi BMP writer is now plane-aware: writes the same biPlanes=1,
biBitCount=2, 3-entry palette layout the rest of the IR TX
pipeline already understood for web-image-prep BMPs. Tri-colour
tags now actually receive accent ink from cloud-rendered plugins.
- WiFi run scene un-forces accent: plugins are invoked with the
tag's actual accent capability and the BMP is opened with the
matching plane count.
- Run scene now calls bmp_abort on exit so an aborted transfer
doesn't leak the ~10 KB pixel buffer.
- Plugin manifest cache capped at TT_WIFI_MAX_FAP_PLUGINS=8 (down
from 16) and the UART RX stream buffer shrunk to 8 KB. Together
these cut WiFi-flow heap pressure by ~23 KB and fix the OOM
crashes that occasionally happened when opening WiFi Plugins.
- Broadcast scene auto-transmit fix: enter_callback now filters
by the >> Transmit << row index, and the cursor defaults to
row 0 instead of Transmit. Previously a stale OK key-release
from the prior submenu would land on the Transmit row and
blast the radio without any user action.
- Flipper FAP: WiFi Setup, Plugins picker, plugin-run scene wired into
Targeted Payloads -> <tag> -> WiFi Plugins
- Framed UART link to the dev board with bulk-read RX path and 16 KB
stream buffer to keep up with full plugin bursts
- ESP firmware: 900 KB UART<->HTTPS bridge, USB-Serial-JTAG console,
cert-bundle TLS, 16 KB worker stack to host mbedTLS handshake
- Cloudflare Worker: Crypto, Weather, Identicon plugins out of the
box; new plugins are a single TypeScript file, no Flipper reflash
- Shared protocol header + 1bpp BMP writer that matches web-image-prep
palette/stride conventions
- Add web-image-prep/: self-contained HTML5 image preparer with
perceptual Oklab 3-colour quantisation, Floyd-Steinberg/Atkinson/
Bayer dither, all supported tag profiles, BMPs that match the FAP
reader exactly. Auto-deployed to GitHub Pages.
- Add 'Set Image' under Targeted Payloads. Lists every BMP in
apps_data/tagtinker/dropped/, scrolls long names, marks foreign-
resolution files with a '~' prefix.
- Stream-time nearest-neighbour rescaling so any BMP can target any
tag at any page; image options screen is now Page-only.
- Remove Phone Sync menu and the Android companion app: replaced by
the browser preparer + drop folder.
- Static, IR-friendly transmit screen ('Tinkering Tag', point hint,
3-dot loader, 'Flipped ;)').
Add "+ Scan NFC" option in the Targeted Payloads menu.
Scans Mifare Ultralight NDEF tags, decodes the encoded
ESL ID, and auto-creates the target — no manual barcode
entry needed. Cyan LED blinks during scan. Loops until
a tag is found or the user presses Back.
New files:
- nfc/tagtinker_nfc.c/.h — NDEF URI decoder module
- scenes/tagtinker_scene_nfc_scan.c — NFC scan scene
Version bumped to 2.1, NFC credit added to About screen.