It comes with the price, but we wanna some new features so...
TODO: Remake this to not use un-defines
Make it use "log level" when making defines instead
- Write-and-set-password screen now shows the target chip "(T5577)" under
the protocol, matching the Write screen for consistency (static literal -
that path always writes a T5577).
- Collapse the per-block pages/blocks/labels parallel arrays into one
steps[] struct-of-rows so page+data+label cannot drift apart; wire output
unchanged.
- Merge lfrfid_worker_write_verify_attempt + _finish into one
verify_and_finish() that returns the loop-stop bool, removing the nested
call duplicated across the three write branches. Behavior is identical
(abort -> stop, match -> fire OK + stop, no-match -> count + keep trying).
- Refresh stale "8265/H5" doc comments left by the rename to "8265".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Use the short "8265" name on both the write-progress and success screens
instead of "8265/H5", so the on-screen label is consistent and the success
popup needs no special-case shortening to fit beside the dolphin icon. The
H5 (RU) alias stays documented in the variant enum comment.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The cold-reset added at the start of hitagmicro_write called
furi_hal_rfid_tim_read_stop() while the read timer was already stopped (the
worker's verify read and any prior session leave the field off). On TIM2
(APB1) furi_hal_bus_disable() furi_check-asserts the bus is running, so this
crashed on every Hitag write attempt.
The field is already off on entry, so just hold it off with the delay; drop
the unbalanced tim_read_stop()/pins_reset() (those belong only after a
matching tim_read_start()).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Fix the 2nd-consecutive-write failure (same tag, not moved): a successful
write leaves the chip warm and emitting (its read-back verify holds the
field on, and the post-write latch cycles drive TTF emission), but the next
write's open-loop select chain assumed a cold power-on reset. Add a leading
cold field-off (HITAGMICRO_COLD_RESET_US) at the start of hitagmicro_write
so every session starts from a known cold state.
Review + simplify cleanup:
- pass the LOGIN password as an explicit hitagmicro_write(data, password)
argument instead of a struct field the worker patched in; normalize the
API version to 87.9 (a single bump over dev)
- collapse the variant password/name parallel arrays into one table
- use bit_lib_set_bit/get_bit instead of hand-rolled bit twiddling
- factor the field power-cycle into hitagmicro_field_on/off helpers
- guard the debug frame dump behind the log level
- name the write_chip_name buffer size; one scene status-text helper
- revert the global MAX_UNSUCCESSFUL_READS 10->5 (the too-long timer already
shows the same "Still Trying" popup); fix a stale docstring + comments
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardware logs showed a tag go from emitting its old ID to emitting nothing
and never recover - a partial write corrupting it. Root cause (vs Proxmark):
PM3 validates the select+login response before every write and aborts if it
fails; our open-loop writer can't, so it fires WRITE blindly even when the
tag wasn't actually selected, and a config write that lands while the data
writes don't leaves the tag reconfigured-but-dataless = a brick.
These magic chips are normally already EM4100/TTF-configured, so the data
blocks alone change the emitted ID. Write config LAST instead of first: a
failed/partial run then keeps the previous working config (no brick), and a
fresh tag still gets configured once its data is in place.
Note: this only mitigates bricking; the intermittent commit (chip flakiness)
remains. PM3-level reliability needs closed-loop select validation (RX),
which the Flipper HAL supports but this writer does not yet implement.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardware logs showed the data we write is correct (it reads back exactly
when it lands), but the 8265 commits a WRITE only intermittently - matching
Proxmark's note that it "often fails during continuous command execution,
need to retry". The worker already retries whole passes; make each attempt
more likely to land so it succeeds in fewer passes:
- Hold the field on 30ms (was 9ms) after each WRITE so the EEPROM finishes
programming before the field drops.
- Re-send each WRITE twice per session (HITAGMICRO_WRITE_REPEATS),
idempotent, to catch a flaky commit.
Note: closed-loop RX would not help here - the 8265 returns no WRITE ack
(see PM3 hitagu.c), so only the read-back can confirm a commit, which we
already do. The intermittency is the chip; retrying is the mitigation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Two issues from hardware testing:
- The "Still Trying to Write..." popup showed the write-progress text
pasted over its dolphin instead of its own message: progress events kept
firing after the warning and overwrote the popup. Guard the write scene
with a flag so progress no longer touches the popup once a warning is up.
- The 8265's first write often failed because TTF emission starts only
after real post-write power cycles; the latch pulses were ~3ms on, too
brief to count. Hold the field 50ms per latch cycle and do 6 of them so
emission starts before the read-back verify (correct variant + no stall).
Also raise LFRFID_WORKER_WRITE_MAX_UNSUCCESSFUL_READS 5 -> 10: it is counted
per verify attempt and one Hitag sweep makes up to 5, so 5 fired the
warning after a single pass.
Note: the 8265 is intermittently write-flaky (Proxmark notes the same and
retries); the worker's retry loop covers occasional first-pass misses.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardware test (per-block select) cloned the tag, but the 8265 only began
TTF emission a power cycle later, so its own read-back verify missed it and
the match landed on the NEXT variant tried (wrote 8265 -> showed 8210; wrote
8210 -> showed H5.5), and it wasted a ~2.5s verify timeout each time.
- Latch: after writing all blocks, cycle the field a few times
(HITAGMICRO_LATCH_CYCLES) so the chip starts emitting before the verify.
This makes the correct variant's own verify match -> right label + much
faster for the 8265 family (no more wasted timeout + extra variant pass).
- Labels: success screen shows the model code only - 8265/H5, 8210, H5.5.
- Write progress: the worker now reports each target as it is attempted
(LFRFIDWorkerWriteStartTarget); the write screen shows it under the source
protocol, e.g. [EM4100] / (T5577) / (EM4305) / (8265/H5), so the multi-
attempt sweep is visible instead of looking frozen.
Confirmed earlier (not bugs): block1 last byte 00 is correct for an all-low
id like DEADBEEF00 (column parity is 0); config 05 00 00 00 matches
`lf em 410x clone --htu`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardware tracing showed the open-loop select chain IS accepted by the
8265 (the tag changed state after our write), but a single select
followed by three writes left the tag emulating nothing - the chip drops
the session after a write, so only the first lands.
Mirror Proxmark3's `lf em 410x clone --htu` exactly: select the tag fresh
with a power cycle before EVERY block, writing config, block0, block1 in
that order. Each iteration powers up, runs the full open-loop select +
login, writes one block, then powers down (HITAGMICRO_POWERDOWN_US) so the
next block re-selects cleanly.
Also confirmed (not a bug): for an all-low id like DEADBEEF00 the EM4100
column parity is genuinely 0, so block1 = FB DF 00 00 is correct; and the
config we send (05 00 00 00) matches `lf em 410x clone --htu`, not the
doc's manual `lf cmdread` recipe (05 80 00 00).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
A Proxmark3 `lf hitag htu` clone trace shows the 8265 only honors a WRITE
after a closed-loop select: READ UID -> GET SYSTEM INFO -> READ config ->
LOGIN, with the tag responding to each. Our previous blind LOGIN+WRITE
skipped all of that, so the chip was never selected and ignored us
(writes did nothing on 8265/8210/H5.5).
Send the whole chain open-loop: transmit READ UID, SYSINFO, READ config,
LOGIN, then the three WRITEs, waiting out each (unread) tag response
window between commands (waits derived from the PM3 trace). The tag still
selects/authenticates on receipt; we just can't observe it (no RX).
Frame builders for READ UID / SYSINFO / READ MULTIPLE BLOCK were added and
verified byte-identical to the PM3 trace (e.g. READ UID 22 04 ..,
READ 22 5F ..). Restructured so each frame's bit-banging is its own short
FURI_CRITICAL section and the long inter-frame waits run with interrupts
enabled.
Still open-loop, so unconfirmed on hardware; if this does not take, the
fallbacks are a per-write select (mirroring PM3 exactly) or a true
closed-loop implementation with RX.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Tracing (debug log level) to diagnose Hitag micro writes, which are
open-loop and have no RX to confirm the tag accepted anything:
- hitagmicro_write logs each built frame (LOGIN / WRITE x3) as hex, so the
transmitted bytes can be compared against a Proxmark3 lf hitag htu trace.
- the verify helper logs whether the read-back saw nothing, saw the wrong
data, or matched - distinguishing a write that did not take from a wrong
block/config mapping.
- the worker logs which Hitag variant it is currently writing.
UI: the detected-chip label overlapped the dolphin artwork. Move it into
the icon-free strip to the right of the 91px icon (right-aligned at the
screen edge). Note: popup text uses the thin secondary font; a Widget
would be needed for a bold label.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review fixes:
- Count WriteFobCannotBeWritten per failed verify (new verify_attempt
helper) instead of per pass, so the cannot-write hint stays timely now
that one write pass issues several writes + verifies.
- furi_check the variant password before memcpy (NULL contract).
- Generalize hitagmicro_crc16 offset for byte-aligned input (latent UB).
- Comments: T0-unit clarity, drop non-standard CCITT name, fix 8265/H5
example, inline the perf trade-off note.
Simplify:
- Build all frames before FURI_CRITICAL; only timed modulation stays in
the critical section.
- send_sof reuses hitagmicro_gap(); CRC ref-out reuses
bit_lib_reverse_16_fast (drops the now-unused string.h include).
- write_finish helper dedups the identical T5577/EM4305 verify branches.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add an open-loop writer (lib/lfrfid/tools/hitagmicro.c) that clones an
EM4100 ID onto ID82xx / Hitag micro 8265 magic chips, mirroring
Proxmark3 `lf em 410x clone --htu`. Folded into the existing sequential
Write flow (no UI picker): each target (T5577, EM4305, Hitag micro x3
passwords) is written then verified by read-back, and the chip/variant
that actually took is reported on the success screen.
- New firmware API 87.10: hitagmicro_write, hitagmicro_variant_password,
hitagmicro_variant_name, lfrfid_worker_get_write_chip_name.
- Detection verifies after each write (perf trade-off, see PR notes).
- Open-loop port of a closed-loop PM3 path; a few frame constants
(flags 0x04/0x05, config byte1) still need on-tag validation.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Static (fixed-code) 433.92 MHz OOK/AM Manchester remote from the Telcoma /
Cardin EDGE family (EDGE2 / EDGE4 / EDGE20; sold compatible with TANGO /
QUASAR / SLIM / SE). Frame = 0xFF preamble + per-remote serial + a one-hot
channel marker; decoded to a canonical 32-bit key where key[31:24]=0xFF,
key[23:3]=serial, key[2:0]=one-hot channel (gate=0, others 1/2/4). The
channel-aware encoder reproduces each channel's exact waveform (gate channel
verified against the original remote's RF; gate frame is 32 data bits + a
required HIGH stop half-bit, other channels are 33 bits with no stop).
This is the EDGE 433.92 fixed-code protocol; it is NOT the existing Cardin
S449 (FSK KeeLoq rolling) or S466 (27 MHz PWM), which are different products.
- decoder + encoder: lib/subghz/protocols/telcoma_edge.{c,h}
- registered in protocol_items.{c,h}
- unit tests + sample captures covering the 32-bit (gate) and 33-bit
(channel) decode paths
- listed in documentation/SubGHzSupportedSystems.md
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add Write Single Block poller functions for ISO 15693-3 and SLIX/SLIX2,
enable the Write scene for both protocols, and skip blocks that already
contain the correct data to minimise RF session time and avoid timeouts
on large tags (e.g. 80-block ICODE SLIX2).
Tested on NXP ICODE SLIX2 (UID E0 04 01 09 05 05 09 37, 80 x 4 byte blocks).