364 Commits

Author SHA1 Message Date
Mykhailo Shevchuk 71280128a3 Apply clang-format to recently merged NFC/RPC/CCID files [ci skip]
Run `fbt format` over the tree; normalizes whitespace, comment
spacing and argument wrapping in the bambu parser, Network/GPS RPC
services and ccid_test USB layer. No functional change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 00:05:57 +03:00
Mykhailo Shevchuk 45c3762c06 [NFC]: Added support for Mifare Plus in SL3 to NFC (#1032)
* [NFC] Add MIFARE Plus SL3 crypto primitives (mf_plus_crypto)

Foundation for native MIFARE Plus SL3 support: AES-128 ECB/CBC (firmware mbedtls), AES-CMAC + the MFP 8-byte truncation, AN10922 session-key derivation, MAC assembly, and the data-encryption IV builders.

IV layout follows Proxmark3 mfp_data_crypt(), verified against source: single low counter byte; read R_lo@[0/4/8]+TI, write W_lo@[7/11/15]+TI. The write-direction IV is not yet hardware-validated -- flagged in-header for confirmation before the write/emulation paths (PR6/7).

No callers yet; poller/listener land in later PRs.

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

* [NFC] Add RFC 4493 self-test for MIFARE Plus SL3 crypto

Known-answer vectors for mf_plus_crypto: the four RFC 4493 AES-CMAC cases (empty / single / partial-final / multi-block) plus the cmac8 odd-index truncation, and a regression test locking the PM3-matched data-IV byte layout (read R_lo@[0/4/8]+TI, write W_lo@[7/11/15]+TI, low-byte-only).

Added to the nfc unit-test suite; the four mf_plus_crypto_* symbols are exported via the test-only API table (unit_test_api_table, api 0.0) so the test plugin resolves them at runtime. Builds clean (firmware + test_nfc plugin); on-device run via the unit_tests CLI.

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

* [NFC] Extend MfPlusData with SL3 block/key model + versioned dump

PR2 of native MIFARE Plus SL3. MfPlusData now holds SL3 content: data blocks + a read bitmap, per-sector AES KeyA/KeyB (+ found masks), admin keys (CMK/CCK/L3-switch/SL1-auth), config blocks (0xB0xx), and the originality signature. Keys are stored separately from block data (SL3 keys are in the 0x40xx keyspace, not data memory, unlike Classic's sector-trailer layout).

Adds a versioned .nfc save/load mirroring mf_classic (dense 'hex or ??' per-block lines, a 'Data format version' key, backward-compatible with legacy metadata-only dumps). is_equal now diffs blocks+keys+config+signature so emulation writeback to .shd can be detected.

Review hardening: mf_plus_str_to_bytes parses into a local and commits on success (out untouched on failure), guards a truncated-line OOB read, and logs corrupt hex vs a legitimate '??'; load refuses an unknown newer data-format version; alloc zeroes via reset; compile-time asserts lock the mask-fits-domain invariants.

Builds clean (fbt firmware_all). Gated: code/silent-failure/type-design/comment review + simplify.

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

* [NFC] Add MIFARE Plus SL3 read poller (auth + read + signature)

PR3 of native MIFARE Plus SL3. Extends the previously detection-only mf_plus poller with the SL3 secure-messaging read flow, composing over the existing iso14443_4a poller.

Primitives (ported byte-faithfully from the flipperzero-mfp-reader fork onto the PR1 crypto): AuthFirst (0x70/0x72) with the rrot(RndA)/rol(RndB) token + session-key derivation, encrypted+MAC'd block read (0x31) with the pre/post-increment r_ctr counter model, and the plaintext originality signature (Read_Sig 0x3C).

State machine (mirroring mf_classic's mode/event API): after detection, RequestMode -> ReadSignature -> per-sector RequestKey -> AuthSector -> ReadSectorBlocks -> ReadSuccess, gated on SL3 + read mode. The app supplies candidate keys via RequestKey and tracks progress via DataUpdate; RequestMode defaults to Info so the existing detect/info scan is unchanged. The app-side dictionary driver lands in PR4.

Also lands the PR2-deferred accessor family + per-sector geometry and routes the serializer through the atomic setters.

Review hardening: a genuine wrong key (Auth) advances to the next candidate while a comms fault fails loudly instead of silently dropping a key; a response-MAC mismatch aborts the sector (counter desync) rather than cascading; the SL3 path is logged throughout.

Builds clean (fbt firmware_all). Gated: code + silent-failure review + simplify. On-device read of a real SL3 card is manual QA.

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

* [NFC] Add MIFARE Plus SL3 dictionary attack

Recover SL3 sector AES keys by dictionary and read all sectors, exposed as
"Unlock with Dictionary" on the read and saved menus (gated on SL3; SL0/1/2
never reach this path).

- New scene nfc_scene_mf_plus_dict_attack: the SL3 poller has no
  resume-from-prior-data path, so the user and built-in system dictionaries are
  consumed in a SINGLE poller pass (user keys first) rather than as separate
  runs, which would discard already-recovered keys. Restarts the combined key
  stream per (sector, key type) since the poller has no NextSector event.
- System dictionary asset (mf_plus_dict.nfc): union of PM3
  g_mifare_plus_default_keys and client/dictionaries/mfp_default_keys.dic,
  deduplicated and upper-cased (33 AES-128 keys).
- Reuses the shared dict_attack view in its sector-oriented layout; sets the
  type explicitly on entry (the shared view keeps whatever type the last scene
  left it in).
- mf_plus_is_card_read(): a block-completeness check used to grade the outcome
  full vs semi success, instead of the poller's sector counter (which also
  counts sectors that aborted mid-read). A terminal ReadFailed (lost card /
  comms fault) is logged and always graded semi-success, never a clean read.
- Expose mf_plus_get_sector_count and mf_plus_is_card_read in the public SDK
  API (the NFC app is an external FAP and calls them), mirroring the mf_classic
  geometry/status helpers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Add MIFARE Plus user key management scenes

Add "MIFARE Plus Keys" to Extra Actions, mirroring the MIFARE Classic and
Ultralight C key managers, so users can grow the SL3 dictionary the "Unlock
with Dictionary" attack consults.

- Scenes: keys (Add/List menu with system+user key counts), keys_add (byte
  input, rejects duplicates), keys_list (pick a user key), keys_delete (confirm
  + delete), keys_warn_duplicate. Keys are 16-byte AES-128, stored in the
  lazily-created user dictionary (NFC_APP_MF_PLUS_DICT_USER_PATH).
- keys_delete hoists the load-key-at-index walk into a helper shared by
  on_enter and on_event and tolerates a stale index (falls back to the list)
  instead of asserting; keys_list uses a distinct inner loop index rather than
  shadowing the outer one.
- Route save/delete success back to the MIFARE Plus keys menu.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Recover MIFARE Plus SL3 admin keys and config blocks

Extend the SL3 read scan with an admin-key phase after the sectors: recover the
0x90xx admin keys by dictionary and, once the Card Master or Config key is
found, read the 0xB0xx configuration blocks with it.

- Generalize the auth primitive to a raw 16-bit key address
  (mf_plus_poller_authenticate_key_id); the sector variant now delegates to it.
  Admin key addresses: CMK 0x9000, CCK 0x9001, L3 switch 0x9003, SL1 auth 0x9004
  (the enum skips 0x9002, so a lookup table maps them). Auth is the same
  0x70/0x72 flow as sector keys, little-endian address.
- Generalize the encrypted read with a block-address high byte: data blocks
  pass 0x00, config blocks pass 0xB0 (both in the frame and the command MAC).
- New states RequestAdminKey -> AuthAdminKey -> ReadConfig. Config is read
  interleaved while the CMK/CCK session is fresh, and tracked by the per-block
  config mask so a CCK pass fills blocks a CMK pass could not read.
- The admin/config phase is best-effort (the sectors are already captured before
  it runs): a wrong candidate asks for the next, an absent admin slot (AUTH_FIRST
  rejection) is skipped, and a lost card finishes with the complete data instead
  of failing an otherwise-complete read.
- The dictionary-attack scene answers admin-key requests from the same
  dictionaries and restarts the key stream when the request target changes
  (sector key <-> admin key, or which admin key).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Render recovered MIFARE Plus SL3 content

The "More info" view showed only GetVersion data; now it also dumps the SL3
content recovered by the dictionary attack: originality signature, sector keys
A/B, admin keys (0x90xx), config blocks (0xB0xx) and the data blocks, each shown
as hex or "??" when not recovered. Section is gated on SL3 (the poller populates
this content only for SL3 read mode).

- Expose the read-only accessors (mf_plus_get_block_count, mf_plus_is_block_read,
  mf_plus_is_key_found, mf_plus_is_admin_key_found, mf_plus_is_config_block_read)
  and a mf_plus_get_admin_key_name getter in the public SDK API so the NFC app
  (an external FAP) can render them; the matching set_* accessors stay internal.
  Mirrors the mf_classic public accessor surface. Folded into the existing 87.12
  API bump for this feature (no further version bump).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Add MIFARE Plus SL3 native listener (auth + read emulation)

Emulate a recovered SL3 card so a reader can authenticate and read it. The
listener is the card-side mirror of the read poller, reusing the same
mf_plus_crypto primitives with reader/card roles reversed.

- mf_plus_listener composes over the ISO14443-4A listener (registered in
  nfc_listener_defs.c). run() dispatches received APDUs on the command byte.
- AUTH_FIRST (0x70): resolve the sector/admin key from the recovered MfPlusData,
  generate RndB, reply E(key, RndB). AUTH_CONTINUE (0x72): verify the RndB echo,
  derive the session keys from rrot(RndA)+RndB (same inputs as the poller), and
  echo rol(RndA) so both this port's poller and a PM3-style reader accept it.
- READ (0x31): verify the command MAC (pre-increment r_ctr), then reply with the
  encrypted block + response MAC using the post-increment counter/IV, byte-for-
  byte matching the poller's read. Serves data blocks and 0xB0xx config blocks.
- READ_SIG (0x3C): returns the stored originality signature. Unknown commands
  (GetVersion, WritePerso probe) are left unanswered so the reader falls back to
  ATS identification.
- Runtime get_features gate: SL3 -> EmulateFull, SL0/1/2 -> EmulateUid only, so
  non-SL3 cards are not offered full emulation. Emulate scene allocates the
  native MfPlus listener for SL3 (required for a future .shd writeback) and
  falls back to a UID-only ISO14443-4A listener otherwise.

Reader-write handling and .shd writeback come next; the write path is not yet
included here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MFP: sector read-progress helper + drop the empty signature dump line

- mf_plus_get_read_sectors_and_keys(): counts fully-read sectors (all blocks
  captured) and recovered sector keys, for the read-progress screens (mirrors
  mf_classic_get_read_sectors_and_keys). Public so the app FAP can use it.
- The originality signature is now written to the .nfc last and only when the
  card actually has one; a card with no signature (MFP X/EV0) no longer gets a
  misleading "Signature: ??" line, and its absence loads as "no signature".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MFP: align read-success and info screens with MIFARE Classic

The read-success and info screens now show name / UID / Keys Found / Sectors
Read (and Tech / ATQA / SAK on the full info), matching the MIFARE Classic
layout via nfc_render_iso14443_3a_info + the new sectors/keys helper. The
ISO14443-4 protocol detail (ATS, bit rates) moved from the info screen into
"More info", where the full SL3 dump lives.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MFP: auto-run the dictionary attack after reading an SL3 card

The read poller callback now reports the SL3 identity scan as "incomplete" and
the read scene auto-continues into the dictionary attack, so recovering keys no
longer requires the manual "Unlock with Dictionary" tap -- mirroring the MIFARE
Classic read flow. SL0/SL1/SL2 finish at the read-success screen as before.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MFP: group Keys under MIFARE Classic; shorten the save-name prefix

- Move "MIFARE Plus Keys" directly under "MIFARE Classic Keys" in Extra Actions.
- Abbreviate " Plus" -> "P" in the auto-generated save name, so MIFARE Plus
  dumps prefill as "MFP..." (and NTAG I2C Plus as "NTAG I2CP...") instead of the
  "MF+" the generic " Plus" -> "+" rule produced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: support plaintext (0x33) block reads

Some SL3 cards require plaintext block reads (command 0x33) instead of the
encrypted default (0x31), governed by the per-block access conditions. A card
like the MIFARE Plus S rejects 0x31 with status 0x0B ("command not available
at current card state") on every data block, so it authenticates all keys yet
reads zero sectors.

Poller: mf_plus_poller_read_block() gains a `plain` flag selecting the opcode;
in plain mode the data travels in the clear (no CBC-decrypt) and the response
MAC is verified over the transmitted plaintext. A new MfPlusError value,
Rejected, distinguishes a card status-byte refusal (a bare status frame that
leaves r_ctr in sync) from a comms/RF fault (Protocol).

The sector-read handler probes the mode in-line: on a Rejected while the mode
is still unlocked, it re-authenticates the sector (resetting the counter) and
retries the SAME block in the other mode, adopting that mode card-wide only on
a successful read. A transient comms fault never flips the mode, and a block
refused in both modes is skipped while the next block re-probes, so neither an
encrypted nor a plain-only card can be mislocked by an unreadable first block.

Listener: mf_plus_listener_read_handler() answers both 0x31 and 0x33 (plaintext
+ response MAC), so an emulated S-style card round-trips.

SL0/SL1/SL2 are unaffected; config (0xB0xx) reads stay encrypted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: answer WritePerso probe in the listener

A reader's info scan (PM3 `hf mfp info`) identifies a MIFARE Plus card by
sending the SL0-only WritePerso command (0xA8) to the invalid block 0x9090 and
reading the rejection status byte: a card in SL3 refuses it with 0x0B ("command
not available at the current card state"), which the reader reads as Plus + SL3.

Our SL3 listener left 0xA8 unanswered, so an emulated card returned "No card
response" to that probe and the reader printed "Identification failed" even
though UID/ATQA/SAK/ATS were all emulated correctly. Add a stateless handler
that answers WritePerso with 0x0B.

WritePerso is rejected by a real card regardless of block address or
authentication state, so the handler ignores the frame and needs no session; it
touches neither the listener state nor the crypto counters. GetVersion (0x60)
and Read_Sig (0x3C) are intentionally still left unanswered for an EV0/X/SE
card, which genuinely has neither -- matching real-card behaviour.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: NAK unsupported commands in the listener

A reader's info scan (PM3 `hf mfp info` / `hf 14a info`) sends GetVersion (0x60)
and Read_Sig (0x3C) while identifying a card. Our SL3 listener left those (and
any other unimplemented command) unanswered, so an emulated card returned an
empty frame and the reader printed "No card response" for each -- an EV0/S/X
part has neither command, but a real one still answers rather than going mute.

A real MIFARE Plus S 2K (EV0) confirms this: to GetVersion it replies with a
bare 0x0B status ("command not available at the current card state"):

    Rdr | 02 90 60 00 00 00 ..  | GET VERSION
    Tag | 02 0B ..              | INF = 0x0B

Mirror that: unimplemented commands, and Read_Sig on a card with no signature,
now NAK with 0x0B via a small mf_plus_listener_send_status() helper (shared with
the WritePerso handler). The reader's scan completes instead of timing out, and
reading the emulation back still falls through to ATS-based typing (GetVersion
0x0B -> version parse fails -> ATS; Read_Sig 0x0B -> signature absent).

GetVersion is intentionally not answered with a fabricated version: 0x0B is what
a real EV0 returns. Replaying a stored version for EV1/EV2 is a later item.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus: drop the manual "Unlock with Dictionary" menu item

The SL3 dictionary attack now runs automatically on read (the read scene enters
the dict-attack scene on PollerIncomplete), so the manual "Unlock with
Dictionary" entry on the read and saved menus was redundant. Remove it: delete
the submenu item, its enum, and its event handler, and point both menus at the
common empty scene handlers. The standard Save/Emulate/Info/etc. items are added
by the framework and are unaffected.

The dict-attack scene stays reachable through the automatic read flow; only the
manual entry point is gone. mf_plus_is_sl3 is kept (the runtime feature gate
still uses it).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: NAK failed authentication in the listener

When a reader (or key check like PM3 `hf mfp chk`) authenticates with a wrong
key, our SL3 listener answered AUTH_FIRST but then went silent on the
AUTH_CONTINUE whose RndB echo didn't match. The reader timed out and desynced
its whole scan -- a sector with a custom key poisoned the checks of later
factory-key sectors.

A real MIFARE Plus S 2K (EV0) confirms the correct behaviour: to a wrong-key
AUTH_CONTINUE it replies with a bare 0x06 status (authentication error):

    Rdr | 0B 00 72 D0 78 ..  | SECOND AUTH STEP (wrong key)
    Tag | 0B 00 06 84 E9     | INF = 0x06

Mirror that. Every auth failure -- malformed AUTH_FIRST/AUTH_CONTINUE, a key
the emulated (partial) dump never recovered, AUTH_CONTINUE without a prior
AUTH_FIRST, and the wrong-key RndB-echo mismatch -- now NAKs with 0x06 via the
shared status helper instead of staying silent. The reader records a miss and
advances to the next key. Our own poller already reads a non-0x90 AUTH_CONTINUE
status as MfPlusErrorAuth ("wrong key, next candidate"), so reading the
emulation back is unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: add a "Show Keys" screen

Mirror the MIFARE Classic "Show Keys" viewer for MIFARE Plus SL3. A new scene
lists the recovered per-sector AES keys (A/B) and the four admin keys (Card
Master, Card Config, L3 Switch, SL1 Card Auth) in a scrollable widget, offered
via a "Show Keys" item on both the read and saved menus for SL3 cards.

Like the MFC viewer it lists only sectors with a recovered key and omits the
unknown ones to stay compact on a partially-read card; keys print as compact
uppercase hex (16-byte AES keys are too long for per-byte spacing). It adds an
explicit "No keys recovered yet." line for the empty case and a footer with the
A / B / admin found counts. The item is always present for SL3 so the view is
reachable even before any key is recovered.

All accessors and key fields are already public, so no API change is needed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: switch data IV to the fork's validated two-counter layout

The data-encryption IV builders followed PM3's single-low-byte layout, which is
only PM3-source-derived and never hardware-validated for the write direction.
Switch both to the reference fork's layout instead: a little-endian
{R_ctr, W_ctr} word {R_lo, R_hi, W_lo, W_hi} repeated across the IV, with TI at
IV[12..15] for reads and IV[0..3] for writes. This is the layout validated
end-to-end by a U-Prox encoder writing keys to the fork's emulation, so it is
the trustworthy basis for the encrypted write path (0xA1) coming next.

For a read-only session (W_ctr == 0, R_ctr < 256) the word collapses to
{R_lo, 0, 0, 0} and the read IV is byte-for-byte identical to the old PM3
layout, so the hardware-validated read path is unaffected -- both read-IV
callers (poller, listener) simply pass their session's W_ctr (0 until a write).

Unit-test IV vectors updated to the new layout, including two full-counter
cases that pin every R/W byte position; the test-only API-table signatures
follow the new 4-arg form.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: emulate writes (0xA1/0xA3) for .shd writeback

Add the card-side write handler to the SL3 listener so a reader writing to the
emulated card mutates MfPlusData, which the generic emulate-exit diff then
auto-saves as a .shd. This completes the emulation-with-change path (e.g. a
U-Prox encoder re-keying the emulated card).

The handler is a native port of the reference fork's validated handle_write:
- Frame [cmd, BNr_lo, BNr_hi, data(16), cmd_mac(8)]. Command MAC over
  {BNr_lo, BNr_hi, data-as-transmitted} with the pre-increment W_ctr; response
  is 0x90 + MAC over the post-increment W_ctr (mirrors the read counter model).
- 0xA1 (keys) CBC-decrypts the block with the write IV; 0xA3 (data) carries
  plaintext. W_ctr advances only on an accepted write, so a NAK (bad MAC, short
  frame, unknown address, not authenticated) never desyncs the reader.
- store_write resolves the 2-byte address to a sector key (0x40xx), admin key
  (0x90xx), data block (high 0x00) or config block (0xB0xx) and calls the
  matching mf_plus_set_* mutator (field + found/read mask), so is_equal detects
  the change and a key write rotates the stored key for the re-auth round-trip.

Not yet hardware-validated: the encrypted-write IV rests on the fork's
U-Prox-validated layout (see the crypto commit), to be confirmed on-device.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: poller write path (write-to-card)

Add the reader-side write to the SL3 poller, the card-side counterpart of the
already-validated listener write handler. This is the protocol core of "Write
to Initial Card"; the UI wiring follows in a separate commit.

- mf_plus_poller_write_block(): 0xA1 encrypted (CBC-encrypt the block with the
  write IV) / 0xA3 plain, mirroring mf_plus_poller_read_block. Command MAC over
  {block_low, block_high, data-as-transmitted} with the pre-increment W_ctr; a
  status rejection (0x0B) returns MfPlusErrorRejected without advancing W_ctr,
  an accepted write advances it once and verifies the response MAC over the
  post-increment value.
- Write state machine: RequestWriteSector (ask the app for the sector's
  recovered key) -> AuthWriteSector -> RequestWriteBlock (ask for the block
  data) -> WriteBlock. Writes only the sectors/blocks present in the dump; a
  sector whose key isn't in the dump is skipped.
- Write-mode probe: like the read probe, the first block is tried encrypted and,
  on a status rejection, the sector is re-authenticated and the block retried
  plain, adopting whichever mode succeeds card-wide. The user's note that write,
  like read, has both plain and encrypted forms is handled here.
- New MfPlusPollerModeWrite + RequestWriteSector/RequestWriteBlock/WriteSuccess/
  WriteFailed events; the ISO14443-4a fault path reports WriteFailed in write
  mode.

Not yet hardware-validated on the poller side (the write crypto itself is
HW-proven via the listener + U-Prox); confirm with a real-card write.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: "Write to Initial Card" UI

Wire the app UI for writing a saved SL3 dump back to its source card, using the
generic write-scene machinery (the same approach as MIFARE Classic).

- Advertise NfcProtocolFeatureWrite for SL3 only (runtime get_features gate), so
  SL0/1/2 -- which have no recovered blocks -- never offer it.
- The generic "Write" item is relabelled "Write to Initial Card" on the saved
  menu and removed from the read menu (writing right after a read makes no
  sense), mirroring MIFARE Classic. Both menus keep "Show Keys".
- The write scene starts the poller in write mode; its callback gates on a UID
  match (write only the card the dump came from), then feeds the recovered
  sector keys (preferring key A) and data blocks from the loaded dump. A
  sector/block the dump lacks is skipped by leaving key/block_provided false.

Completes the "Write to Initial Card" feature (poller path landed in the
previous commit). Not yet hardware-validated end-to-end; confirm on a real card.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: "Update from Initial Card"

Add the re-read-and-refresh flow (card -> saved dump + shadow), mirroring
MIFARE Classic. Offered on the saved menu for SL3; runs no dictionary attack --
it re-reads the source card using the dump's already-recovered keys.

- Three scenes (update_initial + success + wrong_card) mirroring the MIFARE
  Classic ones. The worker runs the read poller in read mode: UID-gate on
  RequestMode, then feed the recovered sector/admin keys from the dump.
- Loop guard: the read poller re-requests a (sector, key) after a failed auth to
  get the next dictionary candidate, but here there is only the one recovered
  key -- so a re-keyed card would loop. feed_once() feeds each key exactly once
  (scene state = last-fed-id + 1) and answers "no key" on an immediate repeat.
- Merge, don't replace: the poller reports ReadSuccess even if its best-effort
  admin/config/signature phase is cut short (early card lift), so a wholesale
  set_data could silently drop keys/config the dump already had. New public
  helper mf_plus_merge_update() overlays every field the re-read recovered onto
  a clone of the old dump without clearing anything, so the refresh only adds/
  updates. Exposed in api_symbols.csv (still 87.12) for the FAP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus: detect S/X/SE by ATS nibbles, not full match

A real MIFARE Plus SE presents ATS historical bytes C1 05 21 30 00 77 C1 --
the trailing bytes (caps + CRC16) differ from the AN10833 values (...F6 D1),
so the exact 7-byte match failed and the SE was mis-detected as a generic Plus.

Match the discriminating nibbles instead, the way PM3 does. The block is
C1 05 <type/size> <gen> <caps> <crc16>; only the type/size nibbles are stable:
- S / X mask their size (byte2/3 = 2F 2F); the caps byte's SVC bit separates
  them (set = X, clear = S).
- SE reveals its size (byte2 = 0x21 = 1K, byte3 = 0x30).
The C1 05 + high-nibble-2 gate keeps a DESFire (also SAK 0x20) from being
mis-claimed. The SAK 0x08/0x18 SL1 cases now use the same matcher, so SE 1K SL1
is recognized too while S/X classify exactly as before.

Removes the now-unused mf_plus_ats_t1_tk_values table (its SE entries held the
unreliable AN10833 tail); the mf_classic SL1 probe keeps its own local S/X pair.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [gui] elements_text_box: word-wrap instead of breaking mid-word

The multiline text box wrapped character by character, so a long line broke in
the middle of a word (e.g. an emulated "MIFARE Plus S 2K SL3" name split as
"...2K S" / "L3"). Track the last space on the current line and, on overflow,
break there so the whole trailing word moves to the next line; fall back to the
original character wrap when a single word is itself wider than the box.

A word containing an inline font marker (\e#, \e*, \e!) still character-wraps:
rewinding across an already-applied marker would re-toggle the emphasis and
corrupt the width measurement, so `marker_since_space` blocks the word-wrap
branch for those words.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: MFC-style block dump + ISO14443-4 "More" page

Rework the SL3 "More info" so the block layout reads like MIFARE Classic and the
protocol/hardware detail moves to a second page.

- The block dump is now per-sector: each block as hex, and the sector trailer
  shows the recovered Key A + the trailer block's access bits (its bytes 6-9) +
  Key B. SL3 keeps the AES keys in a separate keyspace, so the raw trailer's key
  bytes are meaningless -- substituting the recovered keys is what makes it read
  like a Classic dump. The separate "Sector Keys" section is dropped (its keys
  now live in the trailers). Hex is emitted in space-separated 2-byte groups so
  long lines wrap between groups.
- nfc_render_mf_plus_data is split into nfc_render_mf_plus_dump (blocks + admin
  keys + config + signature) and nfc_render_mf_plus_iso4 (GetVersion +
  ISO14443-4). The block-dump page gains a "More" button to a new
  MfPlusIso4Info scene holding the ISO14443-4 details that used to be inline.
- mf_plus_sector_get_first_block / _block_count are promoted to the public
  header (+ api_symbols.csv, still 87.12) so the app-side render can walk the
  per-sector geometry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: answer AUTH_FIRST for unrecovered sectors

When emulating a partially-recovered dump, a reader authenticating a sector
whose key we never recovered was NAK'd at AUTH_FIRST (phase 1) with 0x06. A real
card always answers AUTH_FIRST -- it holds every key and only rejects a wrong
key at AUTH_CONTINUE -- so a phase-1 NAK is unlike any real card, and some
readers (a U-Prox encoder) abort the whole exchange when they see it, leaving
the auth "unfinished".

Verified on hardware: to AUTH_FIRST the real card answers 90 02 BE AA.. (0x90 +
E(RndB)); our emulation answered 06 58 B3.

Now an unrecovered key runs the handshake with a random placeholder: phase 1
completes normally, and since the placeholder can't match the reader's key, the
reader's phase-2 token fails to echo our RndB and we NAK 0x06 at AUTH_CONTINUE
-- exactly as a real card rejects a wrong key. No false-successful auth (the
reader would have to guess our per-session random 16 bytes, and even then the
sector's blocks were never recovered so nothing is exposed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus: restructure More-info into a hub + fix dump OOM

The Info screen's "More" button now opens a small hub (View Dump /
ISO14443-4 Data), DESFire-style, instead of the block dump directly:

- View Dump (SL3 only): the Classic-style block dump, now rendered in a
  memory-light text_box (stores the pointer, lays out visible lines
  lazily) rather than a text-scroll widget. The widget deep-copies the
  whole string AND allocates a FuriString per wrapped line, which for a
  multi-KB 2K/4K dump exploded into hundreds of allocations and OOM'd on
  the ~30 KB-free NFC thread. Also furi_string_reserve the dump up front
  so the many cat calls don't grow by doubling (that transient ~2x
  realloc was the intermittent "opened on the 3rd try" OOM).
- ISO14443-4 Data: the ISO14443-4 protocol details as a widget with a
  "More" button to a new GetVersion page.

Dump layout: block number on its own line with hex below, so a 16-byte
block wraps into two even 2-byte-group lines instead of colliding with
the "N:" prefix; dropped the leading blank line.

Splits nfc_render_mf_plus_iso4 into nfc_render_mf_plus_iso14443_4 +
nfc_render_mf_plus_version_info for the two new pages.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus: add 18 "Add Manually" variants

Add SE / S 2K / S 4K / X 2K / X 4K / EV1 2K+4K / EV2 2K+4K generators,
each in a 4-byte and 7-byte UID flavour, to the core nfc_data_generator
(they auto-appear in the app's "Add Manually" list, which iterates the
generator enum). All are built at SL3 -- the native ISO14443-4
presentation this app fully supports -- with a random NXP UID,
product-correct ATQA/SAK, and a well-formed ATS.

Defaults follow real/known values where available and sensible
placeholders otherwise:
- ATS historical bytes: SE uses a real capture (C1 05 21 30 00 77 C1);
  S/X use AN10833 (2F 2F, SVC bit distinguishes them) -- validated
  byte-identical against real S/X cards' ATS. EV1/EV2 identify via
  GetVersion so they reuse the generic Plus block. S/X share their ATS
  across 2K/4K (the size is masked there; ATQA carries it).
- EV1/EV2 get a plausible GetVersion response (hw_major 0x11/0x22,
  hw_storage 0x16/0x18) and a random 56-byte originality signature; the
  EV0 products (SE/S/X) have neither, matching real silicon.
- SL3 sector/admin keys and blocks are left empty -- a synthetic card
  has no recovered keys.

Generated cards round-trip through save/load and re-detect as the
intended product (type/size/SL are stored explicitly).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Add Manually: keep the list cursor on the picked type

Opening a card type from "Add Manually" and pressing Back re-entered the
type list at the top instead of on the row just opened. The set_type
scene rebuilds its submenu on every entry (including on Back) but never
restored the selection. Save the picked row in the scene state (stored
+1 so the default 0 means "nothing picked yet" -> top) and restore it in
on_enter. Applies to every protocol's Add Manually list, not just
MIFARE Plus.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] iso14443-4: don't crash on an I-block with no INF field

Decoding a received I-block copied its INF field with
bit_buffer_copy_right(input, prologue_len), which furi_check-crashes
(bit_buffer.c: size must be > start_index) when the I-block carries no
INF at all -- total size <= its prologue length. A bare PCB-only
I-block, or a CID-flagged empty I-block on a CID-supporting card, trips
it. Every other malformed case in this decoder already returns Skip;
this one asserted and took the whole device down.

Guard it the same way: skip an I-block whose size is <= its prologue
length instead of asserting. Also catches a truncated frame whose PCB
claims a CID/NAD byte it is too short to contain.

Found on hardware emulating a MIFARE Plus SL3 card to an NXP TagInfo
reader: TagInfo desyncs into an R(NAK) retransmission storm and emits
empty I-blocks, crashing within seconds. Fix is in the shared 14443-4
transport, so it hardens all 14443-4 emulation (DESFire, Type-4, ...),
not just MIFARE Plus. HW-confirmed: no more crash.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus: recognize the second SE ATS fingerprint

NXP TagInfo (v6.2.0, reverse-engineered) matches TWO Plus SE ATS
historical-byte fingerprints -- C1 05 21 30 00 77 C1 and
C1 05 20 30 00 AB 9B -- differing only in the size/gen nibble (byte2
0x21 vs 0x20). We only matched 0x21, so a real SE carrying the 0x20
fingerprint fell through to Unknown. Match SE on byte3 == 0x30 with
byte2 in {0x20, 0x21}; S/X keep byte3 == 0x2F, so no overlap and no
regression. Real S/X ATS are already byte-identical to TagInfo's table.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus: emulate GetVersion for EV1/EV2

An emulated EV1/EV2 now answers GetVersion so a reader (NXP TagInfo,
PM3) classifies it correctly instead of falling back to a generic Plus.
GetVersion is an application-level command (no transport support), so
the listener crafts the chained response itself.

It replays the stored 28-byte MfPlusVersion as three frames, matching a
real EV1 capture byte-for-byte:
  0x60 -> 0xAF + 7 HW bytes
  0xAF -> 0xAF + 7 SW bytes
  0xAF -> 0x90 + 14 UID/batch/date bytes   (final status 0x90, NOT
                                            DESFire's 0x00)
Both the native form and the ISO7816-wrapped 0x90-CLA form (data first,
0x91 <status> trailer) are handled, with a small get_version_stage
chain-state on the listener (reset on field-off/halt and when any other
command interrupts the chain).

Gated on a real version being present (EV1/EV2: hw_vendor 0x04, family
nibble 0x02); EV0 parts (S/X/SE) have none and keep NAKing 0x0B, which
is faithful and is TagInfo's EV gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus Add Manually: blank-format memory + real EV1 version

Manually-added MIFARE Plus cards were identity-only: every block and key
read as "??", which is useless to emulate or inspect. Fill a
blank-formatted factory state, the MIFARE-Plus analogue of the Classic
generator's 0x00 blocks + default keys:
- data blocks zeroed and marked read; block 0 rebuilt as the manufacturer
  block (UID + BCC on 4-byte UIDs + SAK + ATQA + 0xFF), since
  mf_plus_set_uid doesn't populate block 0
- every sector and admin AES key set to the all-FF default and marked
  found; config blocks zeroed

Also align the EV1/EV2 generator version bytes to a real EV1 GetVersion
capture (hw_proto 0x04; the software version reports its own major/minor
0x01/0x01, independent of the hardware major), so an emulated Add-Manually
EV card's GetVersion matches real silicon.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] docs: MIFARE Plus detection reference (NXP TagInfo RE)

Static-analysis notes on how NXP TagInfo classifies a MIFARE Plus card
(variant / security level / size) via SAK routing, ATS fingerprinting,
GetVersion, Read-Signature and the VCA applet -- the reference our
detection and emulation are aligned to.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: changelog entry + API 87.12

Add the "Native MIFARE Plus support in SL3" changelog line and bump the
listed Current API from 87.11 to 87.12 (the single API bump this feature
introduces).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Show full raw ATS on the ISO14443-4 info screen

Add the complete ATS frame (TL T0 [TA1] [TB1] [TC1] + historical bytes) as a
raw line at the top of the shared ISO14443-4a extra renderer, before the
decoded protocol info, so every 14443-4 protocol (MIFARE Plus, DESFire,
NTAG4xx, Type-4, plain 14443-4a) exposes the exact ATS. The dedicated
[Historical bytes] section is kept, mirroring PM3's separate ATS and
Historical bytes blocks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] Cache recovered MIFARE Plus SL3 keys per UID

Mirror the MIFARE Classic key cache for SL3: on save, persist the recovered
sector AES keys (A/B) and 0x90xx admin keys to /ext/nfc/.cache/{UID}.mfpkeys.
On a later read, feed the cached key for each (sector, key type) / admin
target before the dictionaries, so a known card authenticates on the first
try instead of re-running the whole dictionary attack. A wrong cached key
(re-keyed card) falls through to the dictionaries, and a cache miss runs the
attack exactly as before.

A distinct .mfpkeys extension and file header keep it from colliding with the
MIFARE Classic {UID}.keys cache (a Plus card read in SL1 is MIFARE Classic).
The cache helper is bundled into the nfc_mf_plus plugin sources (its own link
unit), mirroring nfc_mf_classic. SL0/SL1/SL2 are unaffected.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [NFC] MIFARE Plus SL3: note per-UID key cache in changelog

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* [GUI] Fix elements_text_box line[] overflow on 8+ line boxes

elements_text_box bounded line_num only by the height break, which on a
near-full-height box (>=63px tall with 9px leading) commits a 7th line and then
writes line[ELEMENTS_MAX_LINES_NUM] -- index 7 of a 7-element array -- a stack
out-of-bounds write. The word-wrap change (less dense than char wrap) lets text
that previously fit in <=7 lines reach 8, exposing the latent gap. Add the
missing line_num >= ELEMENTS_MAX_LINES_NUM bound so line[] is never indexed past
its last slot. Hardens the shared primitive for every firmware text box.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 21:01:10 +03:00
MX 68659ee8cd OFW CCID: move USB layer from firmware HAL into ccid_test app [ci skip]
https://github.com/flipperdevices/flipperzero-firmware/pull/4407/changes
2026-07-07 20:49:34 +03:00
MX ad60eeada0 Merge remote-tracking branch 'OFW/dev' into dev 2026-07-05 03:17:03 +03:00
Filipe Paz Rodrigues d4b023ce53 CCID: add interrupt support (#4198)
* CCID: add interrupt support

Allow smartcard to be inserted or removed by calling the following functions:
 - furi_hal_usb_ccid_insert_smartcard
 - furi_hal_usb_ccid_remove_smartcard

These functions will use the interrrupt endpoint to send a notify change message

* Clang format

* Fixes

* fbt format and logs to debug

---------

Co-authored-by: Štefan Croitoru <66339601+turbospok@users.noreply.github.com>
2026-07-05 01:02:44 +03:00
MX 0d123bdfa5 Merge remote-tracking branch 'OFW/dev' into dev 2026-07-01 01:50:39 +03:00
MMX 97e088ec29 SubGHz: Add Elplast protocol (#4309)
* add protocol

* add unit test
2026-06-30 20:38:54 +03:00
Benjamin Tamasi f222b00ac6 SubGhz: add Telcoma/Cardin EDGE protocol
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>
2026-06-03 14:11:25 +02:00
MX aa75974395 feat: add Indala 224-bit (long format) RFID protocol support
OFW PR 4343 by kuzaxak
2026-03-07 23:53:22 +03:00
MX 50b5ee103c bipki removal procedure
don't worry, they are in other app
2026-01-12 08:13:05 +03:00
MX 22ee3bdae2 Merge remote-tracking branch 'OFW/dev' into dev 2025-11-06 20:29:16 +03:00
MMX 6a5ae6cc0d Infrared Universal remote DBs unit test & move infrared_signal / infrared_brute_force into lib (#4284)
* make infrared db unit tests

* fix the tests, no assets are in asset folder oh no

* fix formate

* ship ir app along with unit_test pkg

* libify ir signal and bruteforce parts

* small cleanup

* api: removed infrared methods (you can link with the lib if needed), unit_tests, infrared: adjusted to link with ir lib; api: added `__aeabi_f2d`

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-11-06 20:23:59 +04:00
MX 40f7c007d9 Merge remote-tracking branch 'OFW/dev' into dev 2025-10-01 19:37:50 +03:00
Zinong Li 85b6b2b896 NFC FeliCa: Service Directory Traverse + Dump All Unencrypted-Readable Services' Blocks (#4254)
* SimpleArray attached to FelicaData

* tx rx done. response parsing done (in log)

* dynamic vector as buffer. rendering begin

* On screen render for directory tree

* flags in render to indicate is_public_readable

* beautify render flags

* format

* offload dynamic vector into individual files

* saving. exposed dir tree writing for double use

* save: additional formatting

* save: clean up and some additional notes

* load done

* delete unnecessary debug log

* Load: safer way to handle backward compatibility

`parsed` being true is only contingent on whether the header (device type, UID, etc) are correctly read. The detailed data can be absent if saved from previous versions.

Side effects:
1. The data format version number must not increment.
2. Newer sections of dumps must be appended in the end of the file.

* format

* handle block reading according to IC type

Old version was aimed for FeliCa Lite dumping, which doesn't apply to FeliCa standard. Thus they need to be diverged in the poller run workflow.

* read block content works. rendering begin

* Render Refactor: dir & dump view from submenu

* Render: show IC type name

* IC parsing function cleanup

* Revert "IC parsing function cleanup"

This reverts commit ee3f7bf125b54b10d238b0aeb657ba15f27f93ba.

* Load: Standard dump. Fully backward compatible

* format

* sync API version

* format saved file

* delete unused variable

* clean ups

* IC type addition

* correction

* beautify attribute parsing

* correction

* Lite save: delete extra line

* correction: FeliCa link in Lite-S mode

* format

* Save: simplify printing

* update IC type parsing

* conform to api standard: const resp ptr to ptr

also slightly faster and more readable block dump loop

* disambiguate workflow type vs ic type

It was too confusing to have the ic name string telling you one thing and ic_type enum saying the other. Might as well use better naming to indicate the use case for the two things

* beautify on device render

* reject dynamic_vector, embrace m-array

* lint

* use full variable name

* partial fix: poller context's data proper init

* edit unit test dump IC code

and a small bug fix for the Lite auth workflow

* unit test felica dump PMm correction

* Fixes for static analysis warnings

---------

Co-authored-by: hedger <hedger@nanode.su>
Co-authored-by: hedger <hedger@users.noreply.github.com>
2025-10-01 18:54:08 +04:00
MX 05c64d2b1f Merge remote-tracking branch 'OFW/dev' into dev 2025-10-01 17:20:46 +03:00
MMX fad487df0e SubGHz: Added 9 new protocols, fixes to existing protocols (#4255)
* Fix Typos

* Tune decoders

* Better parsing, show more data in existing protocols

* Add new protocols

* Update keeloqs

* Add unit tests & raws

* Add honeywell unittest

* Comment until better solution is found

Adding GAPs to be sent first to make signal better suitable for decoder (decoding from only one signal sample) does nothing, needs something else
TODO: Fix encoders?

* suppressed missing issue warning

* subghz: re-enabled failing encoder tests

* Fix two?

3 left

* properly do gangqi and marantec for unit test and real use

* fix unit tests now

* fix possible memory leak

* reset decoder step too

* subghz: extra encoder safety; report random signal test results on failure

* unit_tests: subghz: renamed test file for consistency

* subghz: more explicit buffer position resets

* Fix gangqi samples

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-10-01 18:05:50 +04:00
MX f4529dc8c1 Merge remote-tracking branch 'OFW/dev' into dev 2025-09-29 23:11:36 +03:00
Ivan Barsukov 1e0f3a606f cli: Buzzer command (#4006)
* Add args_read_float_and_trim function

* Add args_read_duration function

* Add notes_frequency_from_name function

* Add cli_sleep function and sleep CLI command

* Update CLI top command to use cli_sleep

* Add buzzer CLI command

* toolbox: make args_read_duration less convoluted

* notification: make notification_messages_notes_frequency_from_name less convoluted

* unit_tests: better float checking

* fix formatting and f18

---------

Co-authored-by: Anna Antonenko <portasynthinca3@gmail.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-09-29 21:53:10 +04:00
Nathan N e7634d7563 NFC: Ultralight C App Key Management, Dictionary Attack (#4271)
* Upstream Ultralight C dictionary attack (squashed)

* linter: formatting

* unit_tests: nfc: split nfc data to named var

* Fix mf_ultralight_poller_sync_read_card

* linter: suppressed warnings on TODOs

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-09-29 21:05:06 +04:00
MX 93b4ad4595 Merge remote-tracking branch 'OFW/dev' into dev 2025-09-24 22:32:16 +03:00
hedger 0d5beedb01 BLE: improved pairing security (#4240)
* ble: use unique root security keys for new pairings after pairing reset; added migrations for existing pairing data; unit_tests: added migration tests

* bt: lower logging level

* hal: bt: updated doxygen strings

* hal: ble: Added checks for root_keys ptr

* service: ble: bt_keys_storage minor cleanup
2025-09-24 22:36:45 +04:00
MMX 30077dd512 Fix PVS warnings (#4277)
* Fixing PVS warns

* pvs: additional fixes

---------

Co-authored-by: hedger <hedger@nanode.su>
2025-09-24 21:00:39 +04:00
MX 905b5726ad Merge remote-tracking branch 'OFW/dev' into dev 2025-09-24 17:58:32 +03:00
MMX 7554b32538 SubGHz: Linear and Dickert MAHS protocols fixes & improvements (#4267)
* Linear and dickert mahs fixes

* fix dip pattern

* proper fix

by WillyJL

* Fix unit tests

Linear Decoder now decodes more linear signals

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
2025-09-24 14:45:03 +04:00
MX bea8d41c8b Merge remote-tracking branch 'OFW/dev' into dev 2025-09-24 01:38:43 +03:00
WillyJL 8bd66c9920 JS: Expose button event type in gui/widget button callback (#4252)
* JS: Expose button event type in gui/widget button callback --nobuild

* js_sdk: bump major version

* unit_tests: fix js test

* js: fix gui widget demo

---------

Co-authored-by: Anna Antonenko <portasynthinca3@gmail.com>
Co-authored-by: hedger <hedger@users.noreply.github.com>
2025-09-24 02:16:47 +04:00
MX 00dde53304 Merge remote-tracking branch 'OFW/dev' into dev 2025-04-07 18:02:16 +03:00
Anna Antonenko 3d02063bce fbt: Deterministic STARTUP order & additional checks (#4179)
* unit_tests: clear startup order

* fam: ensure unique STARTUP order

* fbt: warn on same .order values within a group leading to non-determinitic builds

* fbt: better formatting for app order warning

---------

Co-authored-by: hedger <hedger@nanode.su>
2025-04-07 16:45:09 +04:00
MX c8fc2fa7b3 Merge remote-tracking branch 'OFW/dev' into dev 2025-04-06 01:54:22 +03:00
Anna Antonenko 6b5d006690 [FL-3953] Application chaining (#4105)
* feat: app chaining

* add `launch_current_app_after_deferred`, remove `get_referring_application`

* fix naming

* new api

* fix f18

* fix deferred launches after errors

* fix: memory leak

* Updater: MIN_GAP_PAGES = 0

* loader: loader_get_application_launch_path doc

* loader: fix freeze

* loader: reject mlib, reduce code size

* loader: generic synchronous call, reduce size

* loader: reject furi_string, reduce size

* apps: debug: removed order field from manifests since it is no longer meaningful

---------

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-04-05 20:22:05 +04:00
Anna Antonenko 7192c9e68b [FL-3965] Separate cli_shell into toolbox (#4175)
* cli_shell: separate into toolbox

* fix: cmd flags

* fix formatting

* cli: increase default stack depth

* cli_shell: fix loader lock logic

* cli: fix command flags

* fix f18

* speaker_debug: fix

* cli_registry: fix docs

* ufbt: rename cli target back

* cli: rename app and record

* cli: fix and simplify help command

* cli_master_shell: fix ext commands

* fix formatting

* cli: rename master to main

* fix formatting

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
2025-04-05 02:58:58 +04:00
Anna Antonenko 5dcf6b55ef [FL-3928, FL-3929] CLI commands in fals and threads (#4116)
* feat: FuriThread stdin

* ci: fix f18

* feat: stdio callback context

* feat: FuriPipe

* POTENTIALLY EXPLOSIVE pipe welding

* fix: non-explosive welding

* Revert welding

* docs: furi_pipe

* feat: pipe event loop integration

* update f18 sdk

* f18

* docs: make doxygen happy

* fix: event loop not triggering when pipe attached to stdio

* fix: partial stdout in pipe

* allow simultaneous in and out subscription in event loop

* feat: vcp i/o

* feat: cli ansi stuffs and history

* feat: more line editing

* working but slow cli rewrite

* restore previous speed after 4 days of debugging 🥲

* fix: cli_app_should_stop

* fix: cli and event_loop memory leaks

* style: remove commented out code

* ci: fix pvs warnings

* fix: unit tests, event_loop crash

* ci: fix build

* ci: silence pvs warning

* feat: cli gpio

* ci: fix formatting

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* feat: cli completions

* Merge remote-tracking branch 'origin/dev' into portasynthinca3/3928-cli-threads

* merge fixups

* temporarily exclude speaker_debug app

* pvs and unit tests fixups

* feat: commands in fals

* move commands out of flash, code cleanup

* ci: fix errors

* fix: run commands in buffer when stopping session

* speedup cli file transfer

* fix f18

* separate cli_shell into modules

* fix pvs warning

* fix qflipper refusing to connect

* remove temp debug logs

* remove erroneous conclusion

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* unit test for the fix

* improve thread stdio callback signatures

* pipe stdout timeout

* update api symbols

* fix f18, formatting

* fix pvs warnings

* increase stack size, hope to fix unit tests

* cli completions

* more key combos

* commands in fals

* move commands out of flash

* ci: fix errors

* speedup cli file transfer

* merge fixups

* fix f18

* cli: revert flag changes

* cli: fix formatting

* cli, fbt: loopback perf benchmark

* thread, event_loop: subscribing to thread flags

* cli: signal internal events using thread flags, improve performance

* fix f18, formatting

* event_loop: fix crash

* storage_cli: increase write_chunk buffer size again

* cli: explanation for order=0

* thread, event_loop: thread flags callback refactor

* cli: increase stack size

* cli: rename cli_app_should_stop -> cli_is_pipe_broken_or_is_etx_next_char

* cli: use plain array instead of mlib for history

* cli: prepend file name to static fns

* cli: fix formatting

* cli_shell: increase stack size

* cli_shell: give up pipe to command thread

* fix formatting

* fix: format

* fix merge

* fix. merge.

* cli_shell: fix detach ordering

* desktop: record_cli -> record_cli_vcp

* cli: fix spelling, reload/remove ext cmds on card mount/unmount

* cli: fix race conditions and formatting

* scripts: wait for CTS to go high before starting flipper

* scripts: better race condition fix

* REVERT THIS: test script race condition fix

* Revert "REVERT THIS: test script race condition fix"

This reverts commit 3b028d29b07212755872c5706c8c6a58be551636.

* REVERT THIS: test script fix

* scripts: sleep?

* cli: updated oplist for CliCommandTree

* Revert "REVERT THIS: test script fix"

This reverts commit e9846318549ce092ef422ff97522ba51916163be.

* cli: mention memory leak in FL ticket

---------

Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com>
Co-authored-by: あく <alleteam@gmail.com>
Co-authored-by: hedger <hedger@nanode.su>
2025-04-03 21:39:53 +04:00
Anna Antonenko 24fbfd1663 [FL-3956] CLI autocomplete and other sugar (#4115)
* feat: FuriThread stdin

* ci: fix f18

* feat: stdio callback context

* feat: FuriPipe

* POTENTIALLY EXPLOSIVE pipe welding

* fix: non-explosive welding

* Revert welding

* docs: furi_pipe

* feat: pipe event loop integration

* update f18 sdk

* f18

* docs: make doxygen happy

* fix: event loop not triggering when pipe attached to stdio

* fix: partial stdout in pipe

* allow simultaneous in and out subscription in event loop

* feat: vcp i/o

* feat: cli ansi stuffs and history

* feat: more line editing

* working but slow cli rewrite

* restore previous speed after 4 days of debugging 🥲

* fix: cli_app_should_stop

* fix: cli and event_loop memory leaks

* style: remove commented out code

* ci: fix pvs warnings

* fix: unit tests, event_loop crash

* ci: fix build

* ci: silence pvs warning

* feat: cli gpio

* ci: fix formatting

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* feat: cli completions

* Merge remote-tracking branch 'origin/dev' into portasynthinca3/3928-cli-threads

* merge fixups

* temporarily exclude speaker_debug app

* pvs and unit tests fixups

* feat: commands in fals

* move commands out of flash, code cleanup

* ci: fix errors

* fix: run commands in buffer when stopping session

* speedup cli file transfer

* fix f18

* separate cli_shell into modules

* fix pvs warning

* fix qflipper refusing to connect

* remove temp debug logs

* remove erroneous conclusion

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* unit test for the fix

* improve thread stdio callback signatures

* pipe stdout timeout

* update api symbols

* fix f18, formatting

* fix pvs warnings

* increase stack size, hope to fix unit tests

* cli completions

* more key combos

* cli: revert flag changes

* cli: fix formatting

* cli, fbt: loopback perf benchmark

* thread, event_loop: subscribing to thread flags

* cli: signal internal events using thread flags, improve performance

* fix f18, formatting

* event_loop: fix crash

* storage_cli: increase write_chunk buffer size again

* cli: explanation for order=0

* thread, event_loop: thread flags callback refactor

* cli: increase stack size

* cli: rename cli_app_should_stop -> cli_is_pipe_broken_or_is_etx_next_char

* cli: use plain array instead of mlib for history

* cli: prepend file name to static fns

* cli: fix formatting

* cli_shell: increase stack size

* fix merge

* fix merge

* cli_shell: fix autocomplete up/down logic

* cli_shell: don't add empty line to history

* cli_shell: fix history recall

* cli_shell: find manually typed command in history

* cli_shell: different up/down completions navigation

* fix formatting

* cli_shell: fix memory leak

* cli_shell: silence pvs warning

* test_pipe: fix race condition

* storage_cli: terminate on pipe broken

---------

Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com>
Co-authored-by: あく <alleteam@gmail.com>
2025-04-03 17:07:47 +04:00
Anna Antonenko 13333edd30 [FL-3954, FL-3955] New CLI architecture (#4111)
* feat: FuriThread stdin

* ci: fix f18

* feat: stdio callback context

* feat: FuriPipe

* POTENTIALLY EXPLOSIVE pipe welding

* fix: non-explosive welding

* Revert welding

* docs: furi_pipe

* feat: pipe event loop integration

* update f18 sdk

* f18

* docs: make doxygen happy

* fix: event loop not triggering when pipe attached to stdio

* fix: partial stdout in pipe

* allow simultaneous in and out subscription in event loop

* feat: vcp i/o

* feat: cli ansi stuffs and history

* feat: more line editing

* working but slow cli rewrite

* restore previous speed after 4 days of debugging 🥲

* fix: cli_app_should_stop

* fix: cli and event_loop memory leaks

* style: remove commented out code

* ci: fix pvs warnings

* fix: unit tests, event_loop crash

* ci: fix build

* ci: silence pvs warning

* feat: cli gpio

* ci: fix formatting

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* feat: cli completions

* Merge remote-tracking branch 'origin/dev' into portasynthinca3/3928-cli-threads

* merge fixups

* temporarily exclude speaker_debug app

* pvs and unit tests fixups

* feat: commands in fals

* move commands out of flash, code cleanup

* ci: fix errors

* fix: run commands in buffer when stopping session

* speedup cli file transfer

* fix f18

* separate cli_shell into modules

* fix pvs warning

* fix qflipper refusing to connect

* remove temp debug logs

* remove erroneous conclusion

* Fix memory leak during event loop unsubscription

* Event better memory leak fix

* unit test for the fix

* improve thread stdio callback signatures

* pipe stdout timeout

* update api symbols

* fix f18, formatting

* fix pvs warnings

* increase stack size, hope to fix unit tests

* cli: revert flag changes

* cli: fix formatting

* cli, fbt: loopback perf benchmark

* thread, event_loop: subscribing to thread flags

* cli: signal internal events using thread flags, improve performance

* fix f18, formatting

* event_loop: fix crash

* storage_cli: increase write_chunk buffer size again

* cli: explanation for order=0

* thread, event_loop: thread flags callback refactor

* cli: increase stack size

* cli: rename cli_app_should_stop -> cli_is_pipe_broken_or_is_etx_next_char

* cli: use plain array instead of mlib for history

* cli: prepend file name to static fns

* cli: fix formatting

* cli_shell: increase stack size

* cli: fix rpc lockup

* cli: better lockup fix

* cli: fix f18

* fix merge

---------

Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com>
Co-authored-by: あく <alleteam@gmail.com>
2025-04-02 22:10:10 +04:00
MX c9201a3bde Merge remote-tracking branch 'OFW/dev' into dev 2025-04-01 22:55:16 +03:00
Anna Antonenko 0103b8c7c5 [FL-3961] New JS value destructuring (#4135)
* js: value destructuring and tests

* js: temporary fix to see size impact

* js_val: reduce code size 1

* i may be stupid.

* test: js_value args

* Revert "js: temporary fix to see size impact"

This reverts commit f51d726dbafc4300d3552020de1c3b8f9ecd3ac1.

* pvs: silence warnings

* style: formatting

* pvs: silence warnings?

* pvs: silence warnings??

* js_value: redesign declaration types for less code

* js: temporary fix to see size impact

* style: formatting

* pvs: fix helpful warnings

* js_value: reduce .rodata size

* pvs: fix helpful warning

* js_value: reduce code size 1

* fix build error

* style: format

* Revert "js: temporary fix to see size impact"

This reverts commit d6a46f01794132e882e03fd273dec24386a4f8ba.

* style: format

---------

Co-authored-by: hedger <hedger@users.noreply.github.com>
2025-04-01 18:50:08 +04:00
MX 9f4b1aead7 Merge remote-tracking branch 'OFW/dev' into dev [ci skip] 2025-02-23 18:35:22 +03:00
Anna Antonenko ef024e8086 [FL-3958] Stdio API improvements (#4110)
* improve thread stdio callback signatures
* pipe stdout timeout
* update api symbols

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2025-02-22 08:11:27 +09:00
MX 13dd10182e Merge remote-tracking branch 'OFW/dev' into dev 2025-02-21 04:11:41 +03:00
Anna Antonenko 16d18a79a9 [FL-3900] Update heap implementation (#4123)
* furi: update heap4 to latest
* debug: heap under/overflow testing app
* fix formatting
* silence pvs warnings
* Linker: symbols without type
* Infrared: fix crash in universal remotes on long back press
* Infrared: properly fix incorrect input handling behavior and crash in universal remote. Fix same issue in hid_app.
* FreeRTOSConfig: explicit cast to uint in configTOTAL_HEAP_SIZE
* Format sources
* C and C++ compatible version of stm32wb55_linker.h

Co-authored-by: あく <alleteam@gmail.com>
2025-02-21 10:04:02 +09:00
MX f242eef26f Merge remote-tracking branch 'OFW/dev' into dev 2025-02-21 03:08:00 +03:00
Anna Antonenko 7c5c5d4749 [FL-3734] UART framing mode selection (#4121)
* HAL: feat: uart framing
* JS: feat: uart framing
* fix formatting
* fix pvs warning
* HAL: flash impact reduction attempt 1
* HAL: flash impact reduction attempt 2
* fix compile error
* HAL: finalize flash impact reduction
* HAL: remove user-facing magic numbers

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2025-02-21 04:54:38 +09:00
MX aef8a97ab4 Merge remote-tracking branch 'OFW/dev' into dev 2025-02-20 18:40:54 +03:00
Astra 2817666eb9 [FL-3774] Fix 5V on GPIO (#4103)
* Move OTG controls to the power service
* Accessor: add missing power service import
* Power: add is_otg_enabled to info and properly handle OTG enable with VBUS voltage present
* Power: method naming
* Power: add backward compatibility with old-style use of furi_hal_power
* Scripts: lower MIN_GAP_PAGES to 1
* SubGhz: fix incorrect logging tag
* SubGhz: delegate OTG management to power service
* Power: fix condition race, various improvements

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
2025-02-20 12:37:52 +09:00
MX 2ff9e34082 Merge remote-tracking branch 'OFW/dev' into dev 2025-02-17 20:15:26 +03:00
Anna Antonenko 4895ae5d0d [FL-3957] EventLoop unsubscribe fix (#4109)
* Fix memory leak during event loop unsubscription
* Event better memory leak fix
* unit test for the fix

Co-authored-by: Georgii Surkov <georgii.surkov@outlook.com>
2025-02-17 06:57:23 +09:00
MX 85cba9fd8d Merge remote-tracking branch 'OFW/dev' into dev 2025-02-13 19:58:15 +03:00
Yukai Li 59fe896ce8 nfc: Enable MFUL sync poller to be provided with passwords (#4050)
* nfc: Enable MFUL sync poller to be provided with passwords
* Sync targret api versions

Co-authored-by: あく <alleteam@gmail.com>
2025-02-13 19:31:56 +09:00
Anna Antonenko e27f82f041 [FL-3925, FL-3942, FL-3944] JS features & bugfixes (SDK 0.2) (#4075)
* feat: JS GPIO PWM, JS GUI Widget view; fix: JS EvtLoop stop on request, JS EvtLoop stop on error
* fix: f18 build
* docs: widget
* fix: js unit test
* change feature naming

Co-authored-by: あく <alleteam@gmail.com>
2025-02-13 17:50:38 +09:00
MX 189c87cb08 Merge remote-tracking branch 'OFW/dev' into dev 2024-12-24 14:04:07 +03:00