The emitted bit is the running phase, so a shift accepted before the tag answers
toggles curPhase once too often and the rest of the word comes back complemented.
pskFindFirstPhaseShift judged its first measured length, but waveStart starts as
wherever the caller began looking - that length is part of a wave, not a wave,
and any gap beating fc was taken as a shift. Baseline on the first peak instead.
pskRawDemod_ext separately trusted a shift under one bit period in; the clock is
known by then, so look again from a bit period in.
Both are needed - dropping either leaves one of the tags measured inverting on
most reads.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
aggregate_bits sized each run of like waves in bits and then forced a zero to
one. That is right mid-stream, where a run rounding to nothing would drop a bit
the tag did send. On the leading run it is wrong: a single subcarrier wave is
about fchigh samples against a bit period of clk, so it rounds to no bits and
was made into one anyway - a bit the tag never sent, shifting every bit after it
and dragging startIdx back by most of a bit period.
Skip a leading run that rounds to nothing and let the next transition be first.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The samples before the first level change were counted as bits, and where no
edge arrives inside ten clocks the long-run flush fired first and invented ten
of them out of the quiet lead-in. The count sat on a rounding boundary, so one
sample of jitter in that edge added or dropped a leading bit and rotated the
rest of the word - while startIdx, derived from the same count, held i % clk and
could name no sample.
A level change can only fall on a bit boundary, so start there and report it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Simulation now completes the full exchange with a genuine Paxton reader in
password mode, and crypto mode read/write passes Proxmark-to-Proxmark.
Firmware:
- SOF was one bit period short. The lead-in that compensated for the lost
head half bit was removed and nothing replaced it, so readers rejected
every answer with a second START_AUTH. Default is now 6.
- The edge-detect threshold was latched before being measured, so the value
chosen depended on whether the Proxmark was in a field when sim started.
It is now measured on field entry and re-armed when the reader leaves.
- The percentile walk latched on run-scoped variables, so one attempt made
outside a field poisoned every later one.
- Field loss was detected from TIMESTAMP, which is free-running MCU time and
never stalls. Detect it from receive silence instead.
- Frames of a length the protocol does not have no longer reach the state
machine; our own modulation tail was resetting the session and breaking
every write.
- A dropped edge merges two or three reader bit periods into one gap. Those
bits were discarded; they are now recovered by decomposition, which is what
made crypto mode work (AUTH decode 15% -> 100%).
- Threshold selection is limited to 20 and 32 and settles in under 25 ms.
Client:
- lf hitag info printed a hardcoded 0x06 and reported 'Password mode' for
every tag. It now reads page 3, takes -k (4 bytes password, 6 bytes
crypto), and says so when the config cannot be read.
- lf hitag restore: writes a dump back in dependency order - user pages,
then key material, then config last - validates the config byte, and
prints the credential the tag will require afterwards.
- lf hitag crack2 now reports why it failed instead of a bare 'fail'.
- trace list: bit count moved to its own column, relative mode shows a
Frame Delay Time row rather than renaming Start/End, --frame and -r
rejected together.
Using "data load" on very large trace files (e.g. dumps with 700k samples,
such as COTAG dumps) was causing crashes on some platforms due to stack overflow
since VLA temporary buffers were used.
Replace VLAs in computeSignalProperties() and removeSignalOffset() with
heap-allocated buffers instead.
* .h include only the strict minimum for their own parsing
* this forces all files to include explicitment their needs and not count on far streched dependencies
* this helps Makefile to rebuild only the minimum
* according to this rule, most standalone .h are now gone
* big app.h is gone
* remove seldom __cplusplus, if c++ happens, everything will have to be done properly anyway
* all unrequired include were removed
* split common/ into common/ (client+arm) and common_arm/ (os+bootloader)
* bring zlib to common/
* bring stuff not really/not yet used in common back to armsrc/ or client/
* bring liblua into client/
* bring uart into client/
* move some portions of code around (dbprint, protocols,...)
* rename unused files into *_disabled.[ch] to make it explicit
* rename soft Uarts between 14a, 14b and iclass, so a standalone could use several without clash
* remove PrintAndLogDevice
* move deprecated-hid-flasher from client to tools
* Makefiles
* treat deps in armsrc/ as in client/
* client: stop on warning (-Werror), same as for armsrc/
Tested on:
* all standalone modes
* Linux