The audit's P2 items: - ODD_INS: add 0x73 MANAGE SECURE CHANNEL and 0x75 TRANSACT DATA (TS 102 221 Table 10.5); the tools/vs_reader.py mirror and the pinned test are updated. - 9E/9F are SW1: ISO 7816-3 10.3.3 Table 11 makes every 9X value SW1. Remove the fabricated "extended-length procedure byte" that consumed SW2 as a length and lost the status word. - T=1: EOF-guard every block read, bound the M-bit chain with T1_CHAIN_MAX, and drop the caller's duplicate chain loop -- it read the next block after every I-block (usually the peer's R-block) and merged the following I-block's INF into the packet. R/S blocks emit nothing; the (possibly chained) I-block INF is the APDU payload. - Parity: a packet containing a parity-error byte is emitted with GSMTAP_FLAG_BAD_FCS (the CHKSUM annotation was invisible downstream), with a log note when the exchange is otherwise clean. - EOF guards: handle_atr (TA/TB/TC/TD, historical, TCK), handle_pps (request/response fields incl. PPS1-3) and the T=1 block parser return cleanly on a truncated capture instead of raising on None. - Dead code: _edge_read was initialized True and never cleared, so the ATR-based T=0 procedure loop (58 lines) and the 1.5-ETU guard branch were unreachable. Remove the flag, both dead paths and the branch; dedent the live loop (behavior unchanged). - Samplerate scaling: _samples_for_us() replaces the hard-coded 16 MHz thresholds -- start-bit deglitch (0.125 us), min_high floor (0.25 us) and the ETU glitch floor (0.75 us). At 16 MHz the values are unchanged. Validation: 130/130 unit tests (13 new: 9E/9F SW1, parity BAD_FCS, T=1 I/R/S blocks + M chain + truncations + one-block-per-step, PPS truncations, truncated ATR TA, samplerate/ETU-floor vectors); the 10-trace suite is unchanged from v1.9.6 (identical APDU/CHKSUM/CONCAT/ BAD_FCS counts, RESULT: OK); compare_baseline.sh reports IDENTICAL. VERSION -> 1.9.7.
41 KiB
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-карты телефона
Стенд снимает сессию картридера
Съём коротким кабелем — меньше площадь контура и артефактов фронта
Детали подключения короткого кабеля
Короткий кабель с внешними подтягивающими резисторами — 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 отсчёта при 16 МГц, с v1.9.7 масштабируется от частоты дискретизации) убирает 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 |
| Блоки T=1 | Разбор NAD/PCB/LEN/INF/LRC с цепочкой по биту M; INF I-блока выдаётся как APDU, R/S-блоки не выдаются; обрезанная запись завершается чисто |
| Флаг чётности | Пакет с байтом с ошибкой чётности выдаётся с флагом GSMTAP BAD_FCS (не только аннотацией) |
| Пороги от частоты | Деглитч стартового бита, пороги защиты и порог глитча ETU масштабируются от частоты дискретизации, а не считаются от 16 МГц |
Опции декодера
| Опция | По умолчанию | Описание |
|---|---|---|
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:
direction1 = сброс asserted (высокий→низкий), 0 = deasserted (низкий→высокий);level= уровень линии после перехода. - VCC:
direction1 = питание подано (низкий→высокий), 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 (NAD/PCB/LEN/INF/LRC) и ограничивает цепочку по биту M, чтобы мусор не мог зациклиться навсегда.
После принятого 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. Защита стартового бита в
0.5 ETU (edge-ридер) дополнительно отбрасывает фантомный 0x00, который глитч на
холостом ходу может вставить перед этим ATR. Требуется rst_detect=true
(назначенный канал rst); без него сброс в середине сессии всё равно
будет прочитан неверно.
Решение проблем при живой записи
start.sh запускает одну --continuous запись, пока вы не нажмёте
Ctrl+C (rc=130). stdin отвязан от sigrok-cli, поэтому нажатия
клавиш/Enter в терминале не останавливают запись (приглашение sigrok
«нажмите любую клавишу для остановки» отключено) — раньше это нажатие
ошибочно трактовалось как «преждевременный обрыв», хотя никакой
неисправности устройства не было.
Большая часть раннего «шума» в записях (ошибки чётности, мусор из-за
неверного кадрирования, дребезг линии VCC) была следствием плохо
декодированного конечного автомата, а не железа: переподключение съёма
ничего не давало, а переписанный декодер полностью это вылечил (re-arm по
тёплому сбросу, защита стартового бита 0.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
Предварительные требования:
- sigrok-cli — установщик для Windows (0.7.2 x86_64) с
sigrok.org/wiki/Downloads.
Если он не запускается с ошибкой
0xc0150002, установите Visual C++ 2010 Redistributable (msvcr100.dllтребуется встроенному Python-рантайму). - Прошивка 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 14STK 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.


