Files
unleashed-firmware/lib/ibutton/SConscript
T
Mykhailo ShevchukandClaude Opus 5 c74f6b1d57 iButton: choose which blank types a write may try, and show the current one (#1153)
* iButton: choose which blank types a write may try, and show the current one

A Dallas key carries no hint of which blank is in front of the reader, so a
write attempt walks the blank types in turn and keeps the one whose read-back
matches. Until now that chain was hidden inside dallas_ds1990_write_id(): the
app could not say which type it was attempting, and the user could not stop it
attempting one. Mirrors the LFRFID write-target design.

iButtonWriteTarget names the four writers (RW1990.1, RW1990.2, TM2004, TM01x)
and a protocol declares which of them apply to it, so DS1420 no longer has to
repeat DS1990's chain by hand. The group walks that mask, announcing each
target before it is tried - from outside the critical section, because the
announcement reaches the UI thread.

Settings > Write Blanks toggles them, stored via saved_struct and honoured by
the app and the CLI. Honouring it is opt-in: a worker starts at
ibutton_write_targets_default(), which is all four, matching the behaviour
before this existed.

ibutton_protocols_write_id() keeps its signature and delegates with no context,
so the API change is additive (88.12) and existing FAPs still link.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* iButton: address review of the write-target work

Every Dallas protocol now goes through write_targets. ds_generic, ds1971,
ds1992 and ds1996 each had a write_id that called tm2004_write() directly, so
they took a fallback branch that consulted neither mask and wrote a TM2004
with TM2004 switched off - the setting covered two protocols out of six. With
all six converted the fallback branch, the write_id slot in the Dallas
descriptor and the "zero means it writes itself" sentinel all go away, and the
ROM comes from get_editable_data() rather than a cast onto the front of the
protocol's data.

A mask that resolves to nothing no longer looks like an empty reader: the
worker reports iButtonWorkerWriteNoEnabledTarget, and the write screen
distinguishes "no blanks enabled" from "no enabled blank can write this key" -
reachable without disabling everything, since DS1420 cannot use TM01x. The CLI
says so too instead of spinning.

Settings are saved on Back while the plugin is still mapped, and a failure
raises a storage error dialog instead of only a log line, which is what the
plugin ABI comment always claimed happened.

Also: iButtonWriteTargetContext moves beside the types it is built from, so
ibutton_protocols.h stops pulling protocol_group_base.h and protocol_common_i.h
into the SDK tree; write_chip_name is cleared per write session; the settings
loader masks on read and no longer logs "unreadable (OK)" for a corrupt file;
static asserts pin the enum bit positions the saved mask depends on; and the
success screen names the blank that accepted the key.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* iButton: simplify the write-target code

The blank name on the write screen was always one target behind. Worker, app
and GUI threads all run at Normal priority, so posting the progress event does
not yield, and the next line masks the scheduler for most of a second - the
label queued before a target was painted only once that target had finished.
A 1 ms delay after the announcement is what actually lets the screen repaint.

Nothing-enabled is terminal, not something a retry can fix while the screen is
up, so it now reports once and drops the worker to idle instead of rebuilding
the screen and re-blinking every second forever.

The write context is normalised once at the API boundary, so the group stops
testing it for NULL twice; write_chip_name's 16-byte buffer and its snprintf
become the target itself, with the name derived on read; and the four places a
write reports collapse into one helper.

ibutton_protocols_get_write_targets, _write_id_targets, ibutton_write_target_write
and ibutton_write_targets_default have no caller outside lib/ibutton, so they
drop to '-' and stop costing FAP export thunks - the same treatment
lfrfid_write_target_type already gets.

Also: write_id's doc block had been orphaned by an insertion above it; the four
bit-position asserts collapse into one; .write_targets sits with the data fields
in all six descriptors rather than where write_id used to be; read() and
write_copy() stop the bus outside their critical sections, matching write_id;
and a dead scene-state enum, an overstated settings comment and three verbose
blocks go.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* iButton: let the write screen keep up with the blank being tried

The label showed only TM01x - the last blank of the pass. Announcing a target
and then masking the scheduler microseconds later just queues the events up, so
the app got to paint once, at the end, with the final name. 1 ms was nowhere
near a widget rebuild plus a GUI frame; 50 ms lets each one land, costing
200 ms on a pass where all four are tried and fail.

With nothing enabled the scene also flashed up a writing screen that the first
tick immediately replaced with an error. It already knows the mask before the
worker starts, so it now says so directly. The narrower case - something
enabled, but nothing that fits this key - still needs the worker to answer,
since the app cannot ask which blanks a protocol supports.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* iButton: changelog for the write-target selection

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* iButton: address review of the write-target selection

Honour the documented NULL write_ctx instead of dereferencing it, and let
ibutton_protocols_write_id() be the NULL case it describes.

The blank-type setting governs Write ID only, so an empty list no longer
blocks Full Writing, which rewrites the same chip and never consults it.

Do not crash on a write result this build has not heard of: the app is a
separate .fap, so a newer firmware must not take an older one down with it.
The switch keeps no default, so -Wswitch still catches in-tree additions.

Drop an unreadable settings file rather than fail every later read, which
left the settings page presenting defaults as a saved choice and skipping
the save that would have replaced it. Make the setter read-modify-write so
a setting added beside this one is not zeroed.

Clear the blank-type label when a pass gives up, reset the app-wide Popup
before the plugin error uses it, name the remedy instead of printing a
PluginManagerError ordinal, return before touching the bus when no target
is enabled, and check the ROM size the blank writers assume.

Export ibutton_write_targets_default(), which an exported header already
told apps a worker starts from.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* iButton: simplify the write-target selection

Derive the WriteId feature from write_targets instead of storing the same
fact twice in all six Dallas tables, which also deletes the runtime checks
that existed to catch the two disagreeing.

Charge the announce delay to the callback that repaints, not to the 1-Wire
path: the CLI registers a write callback but drops the progress result, so
it paid 50 ms per target for a name it never prints.

Drop the read-modify-write in the settings setter - it read a value it
overwrote on the next line, costing a stat and a full load on every save.
A static assert on the struct size forces the question when a second
setting is actually added.

Stop deleting an unreadable settings file from inside the getter: it is a
filesystem write on a read path, and "unreadable" includes a version a
newer firmware wrote. The page now saves on the way out even when nothing
changed, which replaces a bad file without destroying a good one.

Remove the "none enabled at all" branch and the scene state behind it. The
early return in on_enter means that event can only arrive with targets
enabled, so the distinction was unreachable.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 20:08:28 +03:00

27 lines
537 B
Python

Import("env")
env.Append(
LINT_SOURCES=[
Dir("."),
],
CPPPATH=[
"#/lib/ibutton",
],
SDK_HEADERS=[
File("ibutton_key.h"),
File("ibutton_worker.h"),
File("ibutton_protocols.h"),
File("ibutton_settings.h"),
File("ibutton_write_targets.h"),
],
)
libenv = env.Clone(FW_LIB_NAME="ibutton")
libenv.ApplyLibFlags()
sources = libenv.GlobRecursive("*.c*")
lib = libenv.StaticLibrary("${FW_LIB_NAME}", sources)
libenv.Install("${LIB_DIST_DIR}", lib)
Return("lib")