Files
sigrok_iso7816_stream/README_RUS.md
T
catarrh 3e39032802 v1.9.6: ETU lock validation, hunt recovery, resync + ATR acceptance
The audit's P1 robustness findings:

- _etu_candidate() validates a measured burst: requires >=2 usable
  spacings, rejects a guard-dominated burst (all-zero data: 10-ETU LOW
  runs + a 2-5 ETU HIGH guard) and a lone 10-ETU spacing.  A failed
  measurement leaves bit_samples unset instead of committing the
  clock_skip*3 fallback.
- _confirm_etu() no longer counts a dropped frame (empty bits) as
  parity-OK, and a rejected measurement clears bit_samples,
  _etu_measured and _clock_skip_confident (was: kept sampling at the
  rejected rate).
- Hunt ETU recovery keys off _etu_measured: handle_atr pre-seeds
  bit_samples, so the old "bit_samples is None" condition never fired.
- resync_idle() waits on the DATA idle level (plus RST/VCC edges,
  bounded) instead of spinning on wait({'skip': 0}) at one sample.
- ATR acceptance: a DATA-state 0x3B/0x3F is a candidate only before the
  first APDU (_apdu_seen); a parsed ATR is ignored on any parity error
  or when it is a bare TS+T0.  A data run misread at a frame boundary
  could fabricate an ATR and force clock_skip=372 for the capture.
- Inverse convention per ISO 7816-3 7.1/8.1: idle HIGH and a falling
  start bit in both conventions, msb-first inverse data, raw moments
  5-7 TS-pattern detection (a real inverse TS reads as 0x03 through
  the direct reader), and a TS parity exemption (the inverse pattern
  is odd over moments 2-10).  Spec-verified; no inverse capture in the
  corpus.

Validation: 117/117 unit tests (18 new); the 10-trace suite is
unchanged from v1.9.5 (APDU/CHKSUM/CONCAT/BAD_FCS identical,
RESULT: OK everywhere); compare_baseline.sh reports IDENTICAL.
VERSION -> 1.9.6.
2026-10-20 18:02:14 +03:00

41 KiB
Raw Blame History

English version: README.md

sigrok_iso7816_stream

Форк svenso/sigrok_iso7816 с живым GSMTAP-UDP-стримингом: дешёвый логический анализатор FX2 (клон Saleae) ведёт себя как сниффер SIMtrace2:

SIM-карта ⇄ ридер (пассивный съём с контактов)
    → логический анализатор FX2 (fx2lafw, 8 каналов, до 24 МГц)
    → sigrok-cli + декодер iso7816
    → GSMTAP UDP :4729  →  [SIMtrace Analyser](https://github.com/anttro/simtrace-analyser) / Wireshark

SIMtrace Analyser — рекомендуемый инструмент для визуализации живых трасс и просмотра сохранённых записей; он также умеет импортировать и экспортировать GSMTAP pcap-файлы (включая PCAP, который этот декодер пишет через опцию pcap_file=<path>).

Съём на практике

Компоненты Компоненты, использованные в сборке

В работе с телефоном Стенд снимает сессию SIM-карты телефона

В работе Стенд снимает сессию картридера

Переходник для SIM Переходник для съёма с SIM

Распиновка переходника Подключение к контактам SIM

Короткий кабель Съём коротким кабелем — меньше площадь контура и артефактов фронта

Подключение короткого кабеля Детали подключения короткого кабеля

Обвязка короткого кабеля Короткий кабель с обвязкой

Подтягивающие резисторы Короткий кабель с внешними подтягивающими резисторами — 10 кОм к GND на VCC (тянет вниз, когда питания нет), 47 кОм к VCC на DATA (быстрее фронт вверх)

Что добавлено поверх upstream

Возможность Описание
Живой поток GSMTAP Каждое декодированное событие отправляется как GSMTAP-SIM UDP-пакет (включено по умолчанию, повторяет поведение simtrace2-sniff)
Правильные sub_types ATR=0x01 и PPS=0x02 теперь корректно помечаются в PCAP (в upstream всё писалось как APDU=0x00)
ATR/PPS в PCAP ATR и объединённые запрос+ответ PPS выводятся как PCAP-пакеты
Отслеживание RST (опционально) rst_detect=true: события assert/deassert сброса (sub_type 0x10)
Отслеживание VCC (опционально) vcc_detect=true: события включения/выключения питания (sub_type 0x11)
PCAP сразу в файл pcap_file=<path> пишет PCAP без перенаправления вывода оболочки
Деглитч стартового бита Деглитч в 2 отсчёта в детекторе стартового бита убирает LOW-глитчи короче ETU от артефактов подтяжки FX2LP и предотвращает смещение байтов на быстрых телефонных трассах
Захват ETU в середине сессии Оценщик ETU по фронтам DATA отбрасывает пачки только со сторожевым интервалом (нулевые данные) и одиночные интервалы, а также сбрасывает скорость, не прошедшую проверку чётности, поэтому трасса с нестандартным F/D захватывается надёжно
Защита ATR / ресинхронизации 0x3B/0x3F в состоянии DATA считается кандидатом в ATR только до первого APDU; кадры с ошибкой чётности или голый TS+T0 игнорируются, а resync_idle действительно ждёт уровень простоя
Инверсная конвенция ATR с TS=0x3F разбирается по ISO 7816-3 7.1: инверсные данные, msb первым, стартовый бит по-прежнему LOW при простое линии HIGH

Опции декодера

Опция По умолчанию Описание
clock_option native native, detect, sample_as_clock (см. FAQ upstream)
protocol auto auto, T=0, T=1
gsmtap_enable true Живой GSMTAP UDP-стриминг
gsmtap_host 127.0.0.1 Хост назначения GSMTAP
gsmtap_port 4729 Порт назначения GSMTAP
pcap_file (пусто) Писать PCAP в этот файл вдобавок к бинарному выводу
rst_detect false Отслеживать события пина RST (требуется назначенный канал rst)
vcc_detect false Отслеживать события пина VCC (требуется назначенный канал vcc)

Каналы: clk, data (обязательные); rst, vcc (опциональные — назначайте только если соответствующий провод физически подключён).

События GSMTAP

Заголовок GSMTAP: версия 2, тип SIM (0x04), UDP-порт 4729.

sub_type Имя Полезная нагрузка
0x00 APDU сырые байты пакета T=0/T=1
0x01 ATR сырые байты ATR
0x02 Запрос PPS сырые байты запроса PPS
0x03 Ответ PPS сырые байты ответа PPS
0x10 Событие RST (кастомное) [direction, level, flags, clk_hz_be32] — частота CLK добавляется, когда известна
0x11 Событие VCC (кастомное) [direction, level, 0x00]

Семантика байтов полезной нагрузки:

  • RST: direction 1 = сброс asserted (высокий→низкий), 0 = deasserted (низкий→высокий); level = уровень линии после перехода.
  • VCC: direction 1 = питание подано (низкий→высокий), 0 = снято (высокий→низкий); level = уровень линии после перехода.

0x00–0x03 совпадают с gsmtap.h из libosmocore: стандартные значения и полезные нагрузки (запрос и ответ PPS отправляются отдельными пакетами). 0x10/0x11 — кастомные расширения, не определённые в gsmtap.h из libosmocore.

События RST несут измеренную частоту CLK, когда она известна: тогда устанавливается бит 0 байта flags, а следом идёт частота как big-endian uint32 в герцах (полезная нагрузка 7 байт). Пока частота не измерена, нагрузка остаётся 3 байта, поэтому потребители, читающие только первые два байта, не затрагиваются. Вместе с F/D, согласованными в ATR/PPS, скорость передачи данных равна clk_hz × D / F бит/с.

Расширения заголовка: флаги вроде GSMTAP_FLAG_BAD_FCS пишутся в байт res заголовка, который официальный gsmtap.h помечает как зарезервированный (RFU). Это собственное расширение данного декодера (upstream simtrace2-sniff никогда не заполняет res); семантика флагов повторяет флаги данных (data flags) USB-протокола simtrace2 и не является частью спецификации libosmocore.

Использование

Быстрый старт после клонирования (см. «Установка» ниже):

./setup.sh   # проверить sigrok-cli, зарегистрировать симлинк декодера
./start.sh   # запись + поток GSMTAP на 127.0.0.1:4729

Умолчания start.sh: выводы D5=CLK, D0=I/O, D4=RST, D2=VCC, частота дискретизации 16 МГц. Переопределяются аргументами:

./start.sh --clk=D1 --data=D6          # другое подключение
./start.sh --no-rst --no-vcc           # только CLK+I/O
./start.sh --host=10.0.28.7            # стримить на удалённый анализатор
./start.sh --pcap=session.pcap         # также записать декодированные события в PCAP
./start.sh --debug                     # полный вывод декодера и sigrok (все
                                       # строки аннотаций + libsigrok -l 4);
                                       # по умолчанию показываются только
                                       # декодированные APDU и предупреждения/ошибки

Подключение

Рекомендуемый способ съёма — короткий кабель с внешними подтягивающими резисторами (см. фото выше): 10 кОм к GND на VCC (тянет вниз без питания) и 47 кОм к VCC на DATA (быстрее фронт вверх). Его распиновка фиксирована и известна заранее — см. таблицу «Распиновка» ниже — и в точности совпадает с умолчаниями start.sh (D5=CLK, D0=I/O, D4=RST, D2=VCC). Автодетект подключения не нужен; выводы не меняются.

Сначала GND. Сначала подключите GND и проверьте его вручную (мультиметром или заведомо исправным контактом) — отсутствующий или плохой контакт земли маскируется под все остальные неисправности сразу: плавающие линии, фантомные стартовые биты, кадры из одних нулей.

Устойчивость к шумным сигналам

Живые записи могут глитчить (фантомный стартовый бит при включении питания раньше сдвигал весь разбор ATR на единицу). Теперь декодер:

  • проверяет байт TS в ATR (0x3B/0x3F по TS 102 221 §5.2.2) и ресинхронизируется на следующем настоящем спаде, если он неверен;
  • никогда не даёт исключению при декодировании убить запись — ошибки логируются, аннотируются, а конечный автомат ресинхронизируется (конец потока по-прежнему завершается чисто);
  • ограничивает продолжение цепочки T=1-блоков, чтобы мусор не мог зациклиться навсегда.

После принятого PPS декодер следует переключению скорости: в режиме native CLK clock_skip становится равным F/D тактов CLK на бит (например, 512/16 = 32), что соответствует новой скорости UART у обеих сторон. Живая запись подтвердила, что сохранение 372 после PPS алиасит весь последующий трафик.

Тёплый сброс (ридер заново подаёт RST примерно каждые ~1.6 с) заставляет карту ответить свежим ATR на стандартных 372 тактах/бит. Декодер заново взводит охоту за ATR по deassert RST: состояние возвращается в FIND START, native-пропуск сбрасывается в 372, счётчик охоты очищается — поэтому повторный ATR разбирается как ATR, а не ошибочно читается как TPDU-трафик на скорости, согласованной PPS. Защита стартового бита в 1.5 ETU дополнительно отбрасывает фантомный 0x00, который глитч на холостом ходу может вставить перед этим ATR. Требуется rst_detect=true (назначенный канал rst); без него сброс в середине сессии всё равно будет прочитан неверно.

Решение проблем при живой записи

start.sh запускает одну --continuous запись, пока вы не нажмёте Ctrl+C (rc=130). stdin отвязан от sigrok-cli, поэтому нажатия клавиш/Enter в терминале не останавливают запись (приглашение sigrok «нажмите любую клавишу для остановки» отключено) — раньше это нажатие ошибочно трактовалось как «преждевременный обрыв», хотя никакой неисправности устройства не было.

Большая часть раннего «шума» в записях (ошибки чётности, мусор из-за неверного кадрирования, дребезг линии VCC) была следствием плохо декодированного конечного автомата, а не железа: переподключение съёма ничего не давало, а переписанный декодер полностью это вылечил (re-arm по тёплому сбросу, защита стартового бита 1.5 ETU, антидребезг VCC 10 мс, сборка обмена T=0). Чистая запись теперь декодируется с нулём мусора — см. проверку vs_reader.py ниже.

Если запись всё-таки завершается сама (rc=0), устройство действительно перестало стримить; обычный подозреваемый — потолок пропускной способности USB у FX2 при длительной высокой частоте дискретизации.

./start.sh --pcap=s.pcap --log=s.log           # также записать события и лог rc=
./start.sh ... --samplerate=24M                # больше запаса по таймингу при необходимости
./start.sh ... --klog                          # также записать журнал ядра
./start.sh ... --debug                         # полный вывод: все строки аннотаций
                                               # + внутренности libsigrok на -l 4
                                               # (по умолчанию: только APDU + предупреждения)

start.sh пишет непрерывный поток на настроенной частоте (по умолчанию 16 МГц) до Ctrl+C (rc=130). Здоровая запись никогда не завершается сама; если FX2 роняет USB-передачу в середине сессии (нестабильное устройство, rc=0 «device stopped streaming»), запись автоматически перезапускается, чтобы не потерять сессию — она перезапускается при каждом rc=0, пока вы не нажмёте Ctrl+C или не сработает --max-restarts=N (по умолчанию 20; 0 = без ограничения), с паузой --restart-delay=S (по умолчанию 2 с). При перезапуске с --pcap=FILE запись каждой сессии пишется в FILE.<N>.<ext>, поэтому перезапуск никогда не перезаписывает предыдущую, а повторяющаяся строка завершения sr_session_stop: session was NULL фильтруется из stderr.

  • --no-loop отключает авто-перезапуск (только одна запись).
  • --loop принудительно включает авто-перезапуск (это поведение по умолчанию).
  • --max-restarts=N ограничивает число перезапусков (по умолчанию 20; 0 = без ограничения).
  • --restart-delay=S — секунды ожидания между перезапусками (по умолчанию 2).
  • --log сохраняет строку вердикта rc= для завершения сессии.
  • Декодер пишет SIGNAL INTEGRITY WARNING, когда ≥ 8 из последних 64 кадров не проходят проверку чётности.
  • Десинхронизированные TPDU (обмены с ошибкой кадрирования) сохраняются, но помечаются GSMTAP_FLAG_BAD_FCS в байте res заголовка GSMTAP — видно в Wireshark как предупреждение BAD-FCS.
  • Заголовок T=0 со структурно некорректным INS (ISO 7816-4 §5.1.2: 0x00 или 0x6x/0x9x) почти всегда сдвинут на один байт из-за лишнего ведущего байта (например, дочитанного остатка SW2 после PACKETEND). Вместо молчаливого отбрасывания всего 5-байтового окна (из-за чего следующий байт становился фиктивным CLA и проглатывал остаток диалога в один CONCAT-пакет) декодер отбрасывает только ведущий байт и перекадрирует остальные, восстанавливая настоящую команду. Каждый потреблённый, но не выведенный байт явно логируется (discarded byte 0x…: reason); отбрасывания холостых 0x00/0xFF ограничены по частоте, отбрасывания не-холостых байтов всегда дают аннотацию декодера.
  • Карта может завершить команду словами SW1 SW2 на первом процедурном байте (ISO 7816-3 §10.3.3), в том числе для case-2 команды с P3 > 0: SW оформляется как статусное слово, а не читается как данные. Ответ короче Le разделяется по статусному слову и пакет помечается BAD_FCS (следующие обмены сохраняются); данные ответа при P3=0 (Le=256) сохраняются.

Производительность: в режиме native CLK декодер один раз калибрует число отсчётов на фронт CLK по первому кадру ATR, а затем продвигает битовую синхронизацию одиночными пропусками отсчётов вместо ожидания на каждый фронт CLK. Переключение скорости по PPS отслеживается через clock_skip = F/D; никакой перекалибровки после PPS или по чётности нет.

Сравнение режимов на железе FX2 (результат A/B)

  • native декодировал реальный трафик (ATR, переключение PPS, 100+ валидных APDU за 12-секундное окно); единственным устойчивым артефактом был «дребезг» линии VCC — звон ~1 кГц, который теперь подавляет антидребезг 10 мс.
  • detect ни разу не дал пригодной сессии на этом стенде: он полностью пропускал переключение скорости по PPS (обработка PPS не срабатывала) и алиасил весь трафик после PPS; вторая попытка поймала мёртвую линию I/O.

native остаётся режимом по умолчанию. Используйте --clock=detect только для офлайн-экспериментов без PPS. Запись, целиком состоящая из нулевых кадров, означает, что съём потерял контакт с линией.

Чётность — чётная по TS 102 221 («чётное число битов, установленных в '1', включая бит чётности»); кадры, не прошедшие проверку, помечаются CHKSUM ERROR, но всё равно декодируются.

Эквивалентные «сырые» команды sigrok-cli:

# Минимум: только CLK+I/O, живой поток на localhost:4729
sigrok-cli -d fx2lafw --config samplerate=12M --continuous \
  -P iso7816:clk=D0:data=D1:clock_option=detect -A iso7816

# Полное подключение: CLK + I/O + RST + VCC с отслеживанием событий линий
sigrok-cli -d fx2lafw --config samplerate=12M --continuous \
  -P iso7816:clk=D5:data=D0:rst=D4:vcc=D2:clock_option=native:rst_detect=true:vcc_detect=true \
  -A iso7816

# Поток на удалённый анализатор / отключить стриминг / писать PCAP-файл
... -P iso7816:...:gsmtap_host=10.0.28.7 ...
... -P iso7816:...:gsmtap_enable=false ...
... -P iso7816:...:pcap_file=trace.pcap ...

# Классический режим upstream: бинарный PCAP в stdout
sigrok-cli -i capture.sr -P iso7816:clk=2:data=0 -B iso7816=pcap > out.pcap

Распиновка

Каналы клона FX2 назначаются через -P iso7816:clk=N:data=N:rst=N:vcc=N. Рекомендуемый съём коротким кабелем (с внешними подтягивающими резисторами) использует фиксированные выводы, которые в точности совпадают с умолчаниями start.sh; --clk/--data/--rst/--vcc переназначают их, если вы подключили иначе:

Канал FX2 Контакт SIM Сигнал
D0 C7 I/O
D2 C1 VCC (только цифровой уровень!)
D4 C2 RST
D5 C3 CLK
GND C5 GND

Входной порог FX2 близок к TTL (~1.4 В): карты класса 1.8 В могут читаться нестабильно; классы 3 В/5 В — нормально.

Частота дискретизации и 8-битный режим (важно): номинальные 24 МГц FX2 доступны только при дискретизации в 8-битном режиме, т.е. когда включены только каналы D0–D7. Включение 9-го канала (A0/аналоговый на клонах CWAV AX) или любого аналогового входа переводит сбор в 16-битный, который libsigrok ограничивает 12 МГц. Поэтому start.sh/start.bat явно передают -C D0,D1,D2,D3,D4,D5,D6,D7 и по умолчанию используют 16 МГц (с комфортным запасом под потолком USB 24 МГц; ~3.3 отсчёта на такт CLK 4.8 МГц). setup.sh/setup.bat проверяют и сообщают фактический максимум вашего железа при том же ограничении.

Установка

Linux

git clone git@github.com:anttro/sigrok_iso7816_stream.git
cd sigrok_iso7816_stream
./setup.sh

setup.sh проверяет, что установлены sigrok-cli и пакет прошивки FX2 (sigrok-firmware-fx2lafw), создаёт симлинк репозитория в ~/.local/share/libsigrokdecode/decoders/iso7816 (пользовательские декодеры перекрывают системные) и опрашивает подключённое устройство на предмет максимальной поддерживаемой частоты дискретизации.

Windows

Предварительные требования:

  1. sigrok-cli — установщик для Windows (0.7.2 x86_64) с sigrok.org/wiki/Downloads. Если он не запускается с ошибкой 0xc0150002, установите Visual C++ 2010 Redistributable (msvcr100.dll требуется встроенному Python-рантайму).
  2. Прошивка fx2lafw поставляется вместе с установщиком — отдельно скачивать не нужно.

Настройка драйвера (донглам FX2 нужен WinUSB, вендорский драйвер не подойдёт):

  • Запустите Zadig, который лежит внутри каталога установки sigrok-cli (также доступен из меню «Пуск»). Выберите устройство FX2 в выпадающем списке и установите драйвер WinUSB.
  • После загрузки прошивки устройство переподключается с другим VID/PID — если оно всё ещё не находится, запустите Zadig второй раз для переподключившегося устройства.
  • Windows привязывает драйверы к USB-порту, когда нет серийного номера: перенос донгла в другой порт может потребовать повторить Zadig.

Затем:

git clone git@github.com:anttro/sigrok_iso7816_stream.git
cd sigrok_iso7816_stream
setup.bat

setup.bat проверяет sigrok-cli и встроенную прошивку, регистрирует декодер этого репозитория через junction в %LOCALAPPDATA%\libsigrokdecode\decoders\iso7816 (подтверждается тем, что sigrok-cli -L показывает iso7816), и опрашивает устройство на предмет поддерживаемых частот дискретизации.

Запись работает так же, как в Linux:

start.bat                   rem запись + поток GSMTAP

Примечание: bat-файлы требуют переводов строк CRLF; репозиторий следит за этим через .gitattributes, поэтому свежий клон в Windows уже корректен.

Заметки и ограничения по детектированию RST/VCC

  • События детектируются асинхронно до первого ATR (включение питания / снятие сброса фиксируются, как только уровень стабилизируется) и на границах пакетов между T=0/T=1 в дальнейшем.
  • Фронты, происходящие целиком внутри передачи пакета, наблюдаются как итоговое изменение уровня на следующей границе; короткие импульсы внутри пакета могут быть пропущены.
  • VCC — только цифровой: декодер видит «питание есть/нет», но никогда не класс напряжения (1.8/3/5 В).
  • RST и VCC используют гистерезис стабильности уровня в 10 мс (масштабируется от частоты дискретизации): новый уровень сообщается только после того, как он непрерывно стабилен ≥ 10 мс — либо потому, что он держится так долго, либо потому, что он закончился, продержавшись столько. Это делает включение и выключение питания симметричными: линия VCC, которая звенит на фронте (шумный/плавающий съём), больше не теряет событие «VCC on» — оно срабатывает, как только линия устанавливается в HIGH, вместо того чтобы быть съеденным дребезгом фронта. RST использует ту же схему, поэтому короткий глитч RST больше не вызывает фантомный re-arm по тёплому сбросу.
  • События VCC в целом ненадёжны — лучше не отслеживать VCC. Плавающий или неподключённый пин съёма VCC всегда читается как HIGH (логическая единица без нагрузки), поэтому декодер постоянно видит «питание подано» и выдаёт ложные события питания при каждом дребезге. Если ваш съём не берёт VCC с чистого нагруженного источника, лучше оставить канал vcc неназначенным (не передавать --vcc) и держать vcc_detect=false; отслеживания RST обычно достаточно, чтобы видеть сбросы. Включайте отслеживание VCC только на съёме с надёжным измерением VCC (и надёжным GND — см. заметки о подключении).
  • Неназначенные опциональные каналы игнорируются, даже если rst_detect/vcc_detect включены (защита через has_channel()).

Тестирование

Проверено на примерах записей из upstream:

# ATR+PPS+54 APDU из записи ридера test_8 (~19 с декодирования)
# Поток GSMTAP проверен через tshark (ATR/APDU разбираются нативно),
# кастомные события 0x10/0x11 — через UDP-слушатель, и сквозным путём
# в сервер SIMtrace Analyser (POST /api/capture/start → decode → stop).

Синтетический генератор VCD, покрывающий краевые случаи RST/VCC, живёт в заметках проекта (projects/SIGROK_ISO7816.md в родительском рабочем пространстве).

Проверка по SDK ридера (tools/vs_reader.py)

На контролируемом стенде (PCSC-ридер под управлением софта) эталонный журнал APDU из SDK ридера можно сравнить с декодированным PCAP:

sigrok-cli -i <trace>.sr \
  -P iso7816:clk=D5:data=D0:rst=D4:vcc=D2:clock_option=native:rst_detect=true:vcc_detect=true:gsmtap_enable=false:pcap_file=out.pcap \
  -A iso7816
python3 tools/vs_reader.py <reader-log>.log out.pcap

vs_reader.py выравнивает каждый обмен из журнала ридера с APDU из записи (побайтовое LCS-совпадение) и классифицирует остатки как proactive/CAT (невидимые для SDK ридера), pre-capture/потерянные или мусор. Запись, начатая в середине сессии, тёплые сбросы которой раньше давали 4 мусорных события, с re-arm и защитой стартового бита декодируется в 0 мусора (RESULT: OK - capture fully explained).

test_7 (4 сброса ATR, фрагментирующих сессию) теперь захватывает все 37/37 обменов ридера (было 10/37 до исправления деглитча). Телефонные трассы Samsung с 16 CLK/ETU (F=512/D=32) теперь разбираются на 924 отдельных обмена T=0 (раньше сливались в 52 APDU завышенного размера).

Воспроизводимые фикстуры трасс (хранятся локально, вне репозитория) покрывают сессии ридера с контролируемого стенда (с эталонными журналами SDK ридера), телефонные записи с гейтированным CLK и записи холодного старта, начинающиеся до включения питания (VCC/RST низкие при t=0). Четыре фикстуры Samsung — холодные старты, снятые новым коротким кабелем (провода 30 мм, внешние подтягивающие резисторы GND→VCC и VCC→DATA), с каналами DATA/VCC/RST/CLK на битах 0/2/4/5; варианты sim2 обрезаны до окна включения питания.

Записи холодного старта (запись начинается до включения питания)

Когда запись начинается до включения питания, декодер должен взвести охоту за ATR, потому что RST всё ещё низкий на отсчёте 0: он инициализирует начальные уровни VCC/RST на первом шаге (вместо того чтобы по умолчанию считать их снятыми) и при низком RST на старте входит в FIND START с очищенным ETU, поэтому переходы DATA при включении питания до ATR не могут зафиксировать фиктивную битовую скорость. Затем он декодирует полный ATR (3b9f96801fc78031e073fe2117574a3382033339001e) с 0 мусора:

sigrok-cli -i <coldboot>.sr \
  -P iso7816:clk=CLK:data=DATA:rst=RST:vcc=VCC:clock_option=native:protocol=T=0:rst_detect=true:vcc_detect=true:gsmtap_enable=false:pcap_file=out.pcap \
  -A iso7816

Снятие RST (deassert), которое приходит, пока разбор ATR уже идёт, больше не перевзводит охоту посреди чтения — оно логирует RST deasserted (hunt/ATR already in progress) и не трогает разбираемый ATR (test_8/test_7 CHKSUM 18→0).

Сценарии записи: ридер (постоянный CLK) и телефон (Clock Stop Mode)

Декодер обрабатывает две физически разные схемы съёма SIM:

  • Запись ридера / постоянный CLK — ридер ведёт ровный CLK всю сессию. В режиме mid-session запись декодируется в 0 мусора (RESULT: OK) относительно эталона из SDK ридера (tools/vs_reader.py <reader-log>.log out.pcap). Записи ридера с тёплыми сбросами используют fallback с синтетическим T=0-ATR.

  • Запись телефона / остановленный CLK — телефон гейтирует или останавливает CLK между передачами (Clock Stop Mode), поэтому ETU не равен стандартным 372 тактам и не может быть выведен из CLK. Запускайте с protocol=T=0; декодер восстанавливает ETU из линии DATA подсчётом фронтов, фиксирует его и декодирует устойчивым к дрейфу edge-list читателем битов. Команды T=0 case 3/4 (например, 80 12/80 14 STK envelope) объединяются в один APDU команда→ответ. Деглитч стартового бита в 2 отсчёта убирает LOW-глитчи короче ETU, вызванные артефактами внутренней подтяжки FX2LP, и предотвращает смещение байтов на быстрых телефонных трассах.

Проверенные скорости данных и ETU

Все трассы декодированы на частоте дискретизации 16 МГц, 0 мусора, RESULT: OK. Начиная с v1.5.0 каждая трасса из набора примеров также сообщает 0 CONCAT (перекадрирование по некорректному INS устранило последнее семейство проглатывания нескольких обменов на 4gmodem/A55_sim2/S21p_sim2).

Трасса Режим CLK ETU (отсчёты) CLK/ETU Конвенция Примечания
test_8 постоянный ~43 372 (стандарт) Direct PC/SC ридер, ATR+PPS+APDU
test_7 постоянный ~43 372 (стандарт) Direct PC/SC ридер, тёплые сбросы
xiaomi гейтированный/остановленный ~53 восстановлен из DATA Direct Телефон, середина сессии
samsung гейтированный/остановленный ~72 16 (F=512/D=32) Direct Телефон, нестандартный F/D, меню STK

Декодер автоопределяет ETU по трассе и выбирает подходящий читатель битов (CLK-синхронный для постоянного CLK, edge-list для гейтированного/ остановленного CLK). Никакой ручной настройки не требуется, кроме clock_option=native и protocol=T=0 для телефонных записей.

Рекомендуемые вызовы:

# Запись ридера (контролируемый стенд, CLK всегда работает)
sigrok-cli -i <trace>.sr \
  -P iso7816:clk=CLK:data=DATA:rst=RST:vcc=VCC:clock_option=native:rst_detect=true:vcc_detect=true:gsmtap_enable=false:pcap_file=out.pcap \
  -A iso7816
python3 tools/vs_reader.py <reader-log>.log out.pcap

# Запись телефона (середина сессии, гейтированный/остановленный CLK)
sigrok-cli -i <phone>.sr \
  -P iso7816:clk=CLK:data=DATA:rst=RST:clock_option=native:rst_detect=true:vcc_detect=false:protocol=T=0:gsmtap_enable=false:pcap_file=out.pcap \
  -A iso7816

Лицензия

GPL-2.0+, как и upstream.