<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Семён сохраняет полезное_)</title><generator>teletype.in</generator><description><![CDATA[Канал о электронике и связи.
Демократии тут нет и не будет! Бан раздается за любое &quot;Ну очевидно, же&quot;]]></description><image><url>https://img4.teletype.in/files/72/cd/72cd0ee4-dcf9-4ee2-a039-0a50d64b3566.png</url><title>Семён сохраняет полезное_)</title><link>https://teletype.in/@pole_sam</link></image><link>https://teletype.in/@pole_sam?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/pole_sam?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/pole_sam?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Mon, 28 Sep 2026 12:30:01 GMT</pubDate><lastBuildDate>Mon, 28 Sep 2026 12:30:01 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@pole_sam/0Ddri2A1-yN</guid><link>https://teletype.in/@pole_sam/0Ddri2A1-yN?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/0Ddri2A1-yN?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>Как из неуправляемого коммутатора сделали управляемый или как я купил очередную хрень и сделал из неё другую</title><pubDate>Sun, 20 Sep 2026 17:55:01 GMT</pubDate><description><![CDATA[Однажды мне попался на озоне медиаконвертер с 4 портами RJ-45(8P8C) и одним портом для оптики. Стоил он недорого(их и сейчас можно найти за 2 тысячи) и мне было интересно на чем он устроен и что можно из него сделать(а ещё если он будет вовсе глупый то использовать по прямому назначению). Так прошел год после покупки и у меня недоходили руки до него. Недавно время всё таки нашлось. Итак я сделал из медиаконвертера управляемый свитч.]]></description><content:encoded><![CDATA[
  <p id="keJG">Однажды мне попался на озоне медиаконвертер с 4 портами RJ-45(8P8C) и одним портом для оптики. Стоил он недорого(их и сейчас можно найти за 2 тысячи) и мне было интересно на чем он устроен и что можно из него сделать(а ещё если он будет вовсе глупый то использовать по прямому назначению). Так прошел год после покупки и у меня недоходили руки до него. Недавно время всё таки нашлось. Итак я сделал из медиаконвертера управляемый свитч.<br /></p>
  <p id="S6uD">Начнем с того что обнаружилось на плате медиаконвертера.</p>
  <p id="mVEF"><strong>RTL8367S-CG</strong> — управляемый коммутатор второго уровня, пять встроенных<br />приёмопередатчиков на гигабит плюс два расширенных порта. На нашей плате<br />наружу выведены четыре разъёма и один под оптику.</p>
  <p id="A5Cp">Рядом с ним на плате стоит <strong>FT24C32A</strong> — микросхема памяти на 32 килобита<br />(4 КБ) с двухбайтовой адресацией, откликается на адрес <code>0x50</code>.</p>
  <p id="v1JM">В качестве управляющей платы я взял <strong>WeAct STM32G431 Core Board.  </strong>На плате стоит STM32G431CB, а в нем: Cortex-M4F на 170 МГц, 128 КБ флеш-памяти,<br />32 КБ оперативной. Определение платы уже есть в дереве Zephyr под именем<br /><code>weact_stm32g431_core</code>, и в нём всё, что нужно. Ровно 48 МГц для USB — обязательное требование, и делитель Q подобран<br />именно под него. Взят он потому-что был просто под рукой. И да для данной задачи это over. </p>
  <h2 id="3-выводы-коммутатора-и-выбор-режима">Выводы коммутатора и выбор режима</h2>
  <p id="rRAU">Самая ценная выкладка из документации на RTL8367S-CG была в том:</p>
  <p id="m3td"><strong>Отдельных выводов MDC/MDIO у микросхемы нет.</strong> Это те же две линии что и I2C. Какую из двух ролей они играют, задаёт состояние вывода <strong><code>SMI_SEL</code></strong><br />(совмещён с GPIO52, <code>LAN0LED0</code>/<code>LED_CK</code>) в момент сброса.</p>
  <p id="BH5e">Второй страппинг: <strong><code>EEPROM_MOD</code>/<code>LAN4LED0</code></strong> задаёт размер памяти —<br />низкий уровень означает до 16 кбит (24C02…24C16), высокий — больше<br />(24C32…24C256). У нас стоит 24C32, значит вывод должен быть в высоком<br />состоянии.</p>
  <h2 id="4-служебный-протокол-realtek-smi">Служебный протокол Realtek SMI</h2>
  <p id="UWuU">Протокол внешне напоминает I²C, но им не является: у него свои условия<br />начала и конца посылки. Поэтому аппаратный контроллер I²C использовать<br />нельзя — обмен формируется программно.</p>
  <h3 id="код-команды">Код команды</h3>
  <p id="xJyR">Первый байт собирается из трёх частей:</p>
  <pre id="LGiJ">  1011    +    100    +    К       =  1011 100К
  4 бита       3 бита      1 бит</pre>
  <p id="qHIO">где <code>К</code> — направление: 1 означает чтение, 0 — запись.</p>
  <h3 id="последовательность-чтения-регистра">Последовательность чтения регистра</h3>
  <pre id="sxfh">START
0xB9                → подтверждение
младший байт адреса → подтверждение
старший байт адреса → подтверждение
младший байт данных ← выдаём подтверждение (0)
старший байт данных ← выдаём отказ (1)
STOP</pre>
  <p id="Vdx5">Запись отличается тем, что после старшего байта адреса передаются младший<br />и старший байты данных, каждый с подтверждением.</p>
  <p id="gmak">Порядок байт: <strong>младший вперёд</strong> и для адреса, и для данных.</p>
  <h3 id="условия-начала-и-конца">Условия начала и конца</h3>
  <p id="v2Kb">Начало посылки отличается от I²C тем, что спад линии данных приходится<br />на <strong>второй</strong> такт, а не на первый:</p>
  <pre id="G39G">SCK: __/‾‾\__/‾‾‾‾‾‾\__
SDA: ‾‾‾‾‾‾‾‾‾‾‾‾\_____/‾‾
         такт 1    такт 2</pre>
  <p id="z9Yr">Конец посылки содержит несколько добавочных тактов - коммутатору нужно<br />время завершить внутреннюю операцию.</p>
  <h3 id="самое-важное-способ-управления-линиями">Самое важное: способ управления линиями</h3>
  <p id="uC8J"><strong>Линии необходимо вести активно в оба уровня.</strong> На открытом стоке, когда<br />единицу отдаёт подтягивающий резистор, коммутатор <strong>не отвечает вовсе</strong> -<br />ни на одной скорости, ни при каком назначении выводов.</p>
  <h3 id="тайминги">Тайминги</h3>
  <p id="e1wr">Задержка между сменами уровней у Realtek - 1 микросекунда. У нас по<br />умолчанию 2 мкс, и обмен устойчиво работает в диапазоне 1…10 мкс. Скорость<br />на работоспособность не влияла: перебор от нулевой задержки до 100 мкс при<br />открытом стоке не дал ни одного ответа.</p>
  <h2 id="5-открытие-доступа-к-регистрам">5. Открытие доступа к регистрам</h2>
  <p id="0NNG">Регистр номера чипа <code>0x1300</code> упорно читался нулями, хотя соседние регистры<br />отдавали осмысленные значения. Разгадка нашлась в исходниках изготовителя:<br />при запуске он записывает особое значение в отдельный регистр.</p>
  <pre id="Nv2T">записать 0x0249 в регистр 0x13C2</pre>
  <p id="I2tT">Проверка на железе и тут!</p>
  <p id="ZHm7"><code>0x6367</code> - это и есть опознавательный номер RTL8367. Заодно опыт доказал,<br />что <strong>запись в регистры работает</strong>: записанное значение изменило поведение<br />микросхемы.</p>
  <p id="xR3x">Прошивка делает это сама при запуске, выждав перед этим три секунды —<br />столько коммутатору нужно на собственную инициализацию после включения. Поймал при ребуте коммутатора по питанию.</p>
  <h2 id="6-карта-регистров">6. Карта регистров</h2>
  <p id="G28i">Официальный заголовок Realtek <code>rtl8367c_reg.h</code> содержит около двадцати трёх<br />тысяч строк определений. Переписывать это руками бессмысленно, поэтому<br />карта построил разбором заголовка.</p>
  <p id="AhUW">Привязка полей к регистрам делается по самому длинному совпадающему<br />префиксу имени — иначе поля похоже названных регистров достаются не тем<br />владельцам.</p>
  <h2 id="7-состояние-портов">7. Состояние портов</h2>
  <p id="XwNx">Один регистр на порт, начиная с <code>0x1352</code>:</p>
  <pre id="KId1">адрес = 0x1352 + номер порта</pre>
  <p id="98dx">Расшифровка проверена вживую. При подключении кабеля регистр изменился<br />так:</p>
  <pre id="1ENq">было  0x00e0 = 0000 0000 1110 0000
стало 0x00f5 = 0000 0000 1111 0101
                          ↑  ↑ ↑ ↑
                          │  │ │ └─ бит 0: скорость 100 Мбит/с
                          │  │ └─── бит 2: полный дуплекс
                          │  └───── бит 4: появилась связь
                          └──────── биты 5-7 не изменились
</pre>
  <p id="xGPD">Поднялись ровно три ожидаемых разряда, остальное осталось на месте.</p>
  <p id="CBbZ">Соответствие разъёмов портам: физический разъём <strong>1</strong> — это порт <strong>0</strong><br />внутри микросхемы.</p>
  <h2 id="8-счётчики">8. Счётчики</h2>
  <p id="OSY9">Коммутатор ведёт 59 счётчиков на каждый порт. Они лежат не в обычных<br />регистрах: нужно задать номер счётчика и забрать значение из окна.</p>
  <p id="DHom"><code>0x1004 -</code>номер нужного счётчика</p>
  <p id="FDxx"><code>0x1005 -</code>состояние, разряд 0 - занятость, разряд 1 - идёт сброс</p>
  <p id="uGkf"><code>0x1000</code>…<code>0x1003 -</code>окно из четырёх регистров со значением</p>
  <h3 id="вычисление-номера">Вычисление номера</h3>
  <pre id="aBEJ">смещение = 0x7C × номер_порта
если номер_порта &gt; 7: смещение += 68
для каждого предыдущего счётчика: смещение += его_длина
</pre>
  <p id="xaDz">Длина счётчика — 4 регистра (64 разряда) для объёмов в байтах и<br />2 регистра (32 разряда) для остальных. Шаг между наборами разных портов —<br /><code>0x7C</code>, то есть 124 регистра.</p>
  <h3 id="порядок-обращения">Порядок обращения</h3>
  <ol id="9PSA">
    <li id="cMNX">Прочитать <code>0x1004</code>. Если там уже лежит нужный номер, записать другой —<br />иначе коммутатор не станет обновлять окно.</li>
    <li id="TjIZ">Записать <code>смещение &gt;&gt; 2</code> в <code>0x1004</code>.</li>
    <li id="pMyW">Дождаться сброса разряда занятости в <code>0x1005</code>.</li>
    <li id="j2fZ">Прочитать окно. Для счётчика длиной 4 регистра чтение начинается<br />с <code>0x1003</code>, для длиной 2 — с <code>0x1000 + ((смещение + 1) mod 4)</code>.<br />Дальше адрес <strong>убывает</strong>, а значение собирается сдвигом влево на 16.</li>
  </ol>
  <p id="MOJg">Отдельно стоит счётчик отброшенных изученных записей: он не привязан<br />к порту и лежит по фиксированному смещению <code>0x420</code>.</p>
  <h2 id="9-виртуальные-сети">9. Виртуальные сети</h2>
  <p id="1jb4">Два уровня описания.</p>
  <h3 id="записи-членства-32-штуки-по-4-регистра">Записи членства: 32 штуки по 4 регистра</h3>
  <pre id="OHLv">адрес = 0x0728 + номер_записи × 4</pre>
  <p id="wrsL">Раскладка по словам:</p>
  <p id="cRb1">0 - маска портов-членов, 11 разрядов</p>
  <p id="x1ph">1 - группа фильтрации, 4 разряда</p>
  <p id="Nj97">2 - разряд 0 - приоритет включён, 1–3 - приоритет, 4 - учёт включён, 5–10 - номер счётчика</p>
  <p id="v8gk">3 - номер сети, 13 разрядов</p>
  <h3 id="привязка-порта-к-записи">Привязка порта к записи</h3>
  <pre id="oBqA">адрес = 0x0700 + номер_порта / 2</pre>
  <p id="54Sx">По два порта на регистр: порт с чётным номером в младшей половине, со<br />следующим - в старшей. В каждой половине разряды 0–4 содержат номер<br />записи членства, разряды 5–7 - приоритет.</p>
  <p id="HOlI">Обратите внимание: порт ссылается <strong>не на номер сети напрямую</strong>, а на<br />номер записи членства.</p>
  <h3 id="таблица-на-4096-сетей-3-слова-на-запись">Таблица на 4096 сетей: 3 слова на запись</h3>
  <p id="1BgD">0 - разряды 0–7 - маска членов, 8–15 - маска портов без метки</p>
  <p id="IZyV">1 - 0-3 группа фильтрации, 4 приоритет включён, 5–7 приоритет, 8 учёт включён, 9–13 номер счётчика, 14 раздельное изучение адресов</p>
  <p id="bvGy">2 - 0-2 старшие разряды маски членов, 3–5 старшие разряды маски без метки, 6 старший разряд номера счётчика</p>
  <p id="9UVY">Маски портов разрезаны между словами 0 и 2, потому что портов<br />одиннадцать, а в байт помещается восемь.</p>
  <h2 id="10-доступ-к-внутренним-таблицам">10. Доступ к внутренним таблицам</h2>
  <p id="8x1F">Таблицы сетей, изученных адресов и правил разбора доступны через общее<br />окно:</p>
  <p id="rJpy"><code>0x0500 - </code>вид таблицы и направление обращения</p>
  <p id="sggv"><code>0x0501 - </code>номер записи</p>
  <p id="dEzB"><code>0x0510</code>…<code>0x0519 - </code>окно записи</p>
  <p id="3RNW"><code>0x0520</code>…<code>0x0529 - </code>окно чтения</p>
  <p id="qJGJ">Слово управления собирается так:</p>
  <pre id="Du3J">команда = (направление &lt;&lt; 3) | вид_таблицы</pre>
  <p id="fzeH">Правила разбора - 1</p>
  <p id="XfOR">Действия разбора - 2</p>
  <p id="h1Kh">Сети - 3</p>
  <p id="UclR">Изученные адреса - 4</p>
  <p id="wdpP">Группы рассылки  - 5</p>
  <p id="z10B">Направление: 0 — чтение, 1 — запись.</p>
  <h2 id="11-прочие-подсистемы">11. Прочие подсистемы</h2>
  <h3 id="зеркалирование-трафика">Зеркалирование трафика</h3>
  <p id="8A8p">Регистр <code>0x121C</code>:</p>
  <p id="QYBD">0–3 - порт-источник</p>
  <p id="RkY0">4–7 - порт-приёмник копии</p>
  <p id="b3ii">9 - копировать принятое</p>
  <p id="VuNp">10 - копировать переданное</p>
  <p id="BkRd">Дополнительно <code>0x12FB</code> содержит маску портов-источников (11 разрядов).</p>
  <h3 id="изоляция-портов">Изоляция портов</h3>
  <pre id="aP3G">адрес = 0x08A2 + номер_порта</pre>
  <p id="rTTr">Одиннадцатиразрядная маска: каким портам этот порт вправе пересылать<br />кадры. Позволяет развести абонентов, не прибегая к виртуальным сетям.</p>
  <h3 id="ограничение-скорости">Ограничение скорости</h3>
  <p id="drJY">Приём -<code>0x000F + номер_порта × 2</code>, два регистра</p>
  <p id="uELI">Передача -<code>PORT&lt;n&gt;_EGRESSBW_CTRL0/1</code></p>
  <p id="banD">Первый регистр хранит младшие 16 разрядов, второй — разряды 16–18. Счёт<br />идёт в единицах по <strong>8 килобит в секунду</strong>, поэтому заданное значение<br />округляется вниз до кратного.</p>
  <h2 id="12-что-лежало-в-памяти-на-плате">12. Что лежало в памяти на плате</h2>
  <p id="gwlP">Содержимое микросхемы вычитано целиком — 4096 байт. Ожидалась таблица<br />вида «адрес регистра — значение», которую коммутатор загружает при<br />включении. Оказалось иное.</p>
  <p id="b3TV">Начало образа:</p>
  <pre id="TaJr">0000: b7 0d 02 0a 71 e4 f5 a8 d2 af 22 00 00 02 0c d3</pre>
  <p id="4xw0">0x00 - <code>b7 0d - </code>заголовок: <code>0x0DB7</code> = 3511, длина</p>
  <p id="PU18">0x02 -<code>02 0a 71 - LJMP 0x0A71</code> — вектор сброса</p>
  <p id="0fvp">0x05 - <code>e4 f5 a8 d2 af 22 - CLR A</code> / <code>MOV IE,A</code> / <code>SETB EA</code> / <code>RET</code></p>
  <p id="LrZq">0x0D - <code>02 0c d3 - LJMP 0x0CD3</code> - вектор прерывания таймера</p>
  <p id="VeQs">Это <strong>исполняемый код архитектуры 8051</strong>. Если считать, что адресу<br /><code>0x0000</code> соответствует смещение 2, таблица векторов прерываний сходится<br />идеально.</p>
  <p id="91ag">Характерные команды по всему объёму: <code>e4</code> (<code>CLR A</code>), <code>90 xx xx</code><br />(<code>MOV DPTR</code>), <code>12 xx xx</code> (<code>LCALL</code>), <code>02</code> (<code>LJMP</code>), <code>22</code> (<code>RET</code>),<br /><code>7f</code>/<code>7e</code>/<code>7d</code> (загрузка регистров).</p>
  <p id="AFR0">В конце образа: по смещению <code>0x0FE0</code> — байты <code>d1 a1 cd a4 ca a1</code>, которые<br />в кодировке GB2312 складываются в иероглифы; по смещению <code>0x0FF6</code> —<br /><code>20 16 10 25</code>, очень похоже на дату 25 октября 2016 года.</p>
  <h3 id="проверка-догадки">Проверка догадки</h3>
  <p id="bpFr">В открытой библиотеке для этого семейства нашёлся готовый образ памяти,<br />причём именно для FT24C32A в корпусе SOIC8 — той же микросхемы:</p>
  <pre id="eLbH">наш образ:  b7 0d 02 0a 71 e4 f5 a8 d2 af 22 00 00 02 0c d3
эталонный:  fc 09 02 07 37 e4 f5 a8 d2 af 22 00 00 02 09 44
            └──┬──┘ └───┬──┘ └────────┬───────┘ └─┬─┘ └──┬──┘
            заголовок  LJMP      одинаковый код  нули  LJMP
</pre>
  <p id="Ejt0">Совпадает структура: заголовок с длиной, переход на начало программы,<br /><strong>побайтово одинаковый</strong> стартовый код, нули, вектор прерывания.<br />Содержимое разное (другая версия прошивки, у эталона длина <code>0x09FC</code> =<br />2556), но формат тот же.</p>
  <p id="Nu2E"><strong>ядро 8051 встроено в сам RTL8367S</strong>, и в памяти лежит его<br />прошивка. Коммутатор при включении сам вычитывает её по тем же линиям,<br />выступая на шине ведущим.</p>
  <h2 id="13-архитектура-решения">13. Архитектура решения</h2>
  <h3 id="почему-логика-на-компьютере">Почему логика на компьютере</h3>
  <p id="zYGO">Карта регистров содержит 4079 позиций. Реализовывать их обслуживание в<br />прошивке значило бы перепрошивать плату ради каждой новой возможности.<br />Поэтому разделение такое:</p>
  <p id="kzpN">Прошивка на Zephyr v4.4.2 на STM32 - прозрачный мост к регистрам</p>
  <p id="LPj2">Программа на Python - карта регистров, подсистемы, веб-интерфейс</p>
  <h3 id="машинный-протокол">Машинный протокол</h3>
  <p id="DQNX">У оболочки на плате два набора команд. Один для кожаных - с подписями и<br />пояснениями. Второй для программы - со строгим ответом:</p>
  <p id="qA0o"><code>m r &lt;адрес&gt; [кол-во] - </code>прочитать подряд идущие регистры</p>
  <p id="ovUB"><code>m w &lt;адрес&gt; &lt;знач&gt;… - </code>записать подряд идущие регистры</p>
  <p id="0hji"><code>m m &lt;адрес&gt; &lt;маска&gt; &lt;знач&gt; - </code>изменить только отмеченные разряды</p>
  <p id="Qju6"><code>m i - </code>номер чипа, версия, режим</p>
  <p id="9uGF"><code>m u - </code>открыть доступ к регистрам</p>
  <p id="9U4Q"><code>m s [мкс] - </code>показать или задать полутакт шины</p>
  <p id="xAOc">Ответ всегда одной строкой: <code>+ &lt;значения&gt;</code> при успехе, <code>- &lt;код&gt;</code> при<br />отказе, все числа шестнадцатеричные. Пример:</p>
  <pre id="oE1r">m r 1352 8
+ 00e0 00e0 00e0 00f5 0086 0000 0000 0000</pre>
  <p id="emck">Команда изменения разрядов существует отдельно неспроста: читать и писать<br />по очереди небезопасно, потому что между двумя обращениями регистр может<br />изменить сам коммутатор. Прошивка делает это неделимо.</p>
  <h3 id="связь-с-платой">Связь с платой</h3>
  <p id="zV0X">Плата отдаётся системе как виртуальный последовательный порт с<br />опознавательными признаками <code>2FE3:0001</code> и названием <code>RTL8367S Manager</code>.<br />Программа ищет её по этим признакам, поэтому смена имени устройства<br />(<code>/dev/ttyACM0</code> против <code>/dev/ttyACM1</code>) ни на что не влияет — а меняется<br />оно охотно, поскольку рядом подключён отладчик.</p>
  <h2 id="источники">Источники</h2>
  <ul id="UBEu">
    <li id="0HF6"><a href="https://www.unikeyic.com/media/datasheet/ee/09/56ff/ee/d621a0c96c0b0157c1ae4aae7c9cf12e.pdf" target="_blank">RTL8367S-CG, техническое описание</a></li>
    <li id="Rd2w"><a href="https://github.com/shiroichiheisen/Realtek-Unmanaged-Switch-Arduino-Library" target="_blank">Realtek Unmanaged Switch Arduino Library</a> — эталонная реализация обмена, карта регистров, образ памяти</li>
    <li id="gy9z"><a href="https://github.com/libc0607/Realtek_switch_hacking" target="_blank">Realtek_switch_hacking</a> — первоисточник файлов изготовителя</li>
    <li id="sIHc"><a href="https://lwn.net/Articles/883059/" target="_blank">Драйверы realtek в ядре Linux</a> — два независимых интерфейса управления</li>
    <li id="eMeL"><a href="https://www.kernel.org/doc/Documentation/devicetree/bindings/net/dsa/realtek-smi.txt" target="_blank">Описание привязки realtek-smi в Linux</a></li>
  </ul>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@pole_sam/ejN-g2kqhSy</guid><link>https://teletype.in/@pole_sam/ejN-g2kqhSy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/ejN-g2kqhSy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>Трафик без data bearer: как передавать данные, если есть только служебный канал</title><pubDate>Sat, 12 Sep 2026 20:08:24 GMT</pubDate><description><![CDATA[Иногда бывает так: модем подключён, сеть есть, но привычного IP-интерфейса (ppp0, wwan0) — нет. Либо оператор заблокировал data bearer, либо устройство работает в режиме «только сигнализация». При этом диагностический порт (Qualcomm DIAG, Gobinet, QXDM) доступен, и через него идёт служебный трафик: NAS, RRC, SIB, paging.]]></description><content:encoded><![CDATA[
  <p id="kdmc">Иногда бывает так: модем подключён, сеть есть, но привычного IP-интерфейса (ppp0, wwan0) — нет. Либо оператор заблокировал data bearer, либо устройство работает в режиме «только сигнализация». При этом диагностический порт (Qualcomm DIAG, Gobinet, QXDM) доступен, и через него идёт служебный трафик: NAS, RRC, SIB, paging.</p>
  <p id="XMiJ">В таких условиях можно организовать передачу пользовательских данных, используя служебный канал как транспорт. Ниже — рабочий подход, проверенный на Qualcomm MSM8916, USB-модемах и Android-устройствах с root.</p>
  <hr />
  <h2 id="data-bearer">Что доступно, если нет data bearer</h2>
  <p id="JOgZ">Обычный сценарий работы модема:</p>
  <pre id="v2bg">UE &lt;--RRC/NAS--&gt; eNB &lt;--S1-AP--&gt; MME
 |                              |
 +------IP (PPP/NCM/MBIM)------+</pre>
  <p id="zHLI">При отсутствии data bearer IP-канал не поднимается. Но диагностический порт остаётся активным:</p>
  <pre id="rP35">UE &lt;--DIAG (USB/ADB)--&gt; Host (Linux/Android)
       ^
       | сырые L2/L3 фреймы: BCCH, CCCH, DCCH, DTCH</pre>
  <p id="XVWm">Через DIAG можно:</p>
  <ul id="0Dwg">
    <li id="hzNq">принимать и декодировать служебные сообщения (NAS, RRC, SIB);</li>
    <li id="DtVx">в некоторых случаях — инкапсулировать пользовательские данные в DTCH-подобные фреймы;</li>
    <li id="Y7c8">использовать туннелирование поверх существующих сигнальных процедур.</li>
  </ul>
  <hr />
  <h2 id="Hdqc">Инструментарий</h2>
  <p id="QRFb">Для работы понадобятся:</p>
  <ul id="XjOj">
    <li id="An7J"><strong>QCSuper</strong> — утилита для захвата и декодирования радиофреймов с Qualcomm-модемов.github+1</li>
    <li id="22lu"><strong>Wireshark</strong> — для анализа pcap-файлов.</li>
    <li id="syGe"><strong>ADB</strong> (если модем встроен в Android) или <strong>USB-модем с DIAG-портом</strong> (например, разлоченный Quectel).</li>
    <li id="xSC6"><strong>socat / netcat</strong> — для организации туннелей.</li>
    <li id="FLOI"><strong>AT-команды</strong> для включения диагностического режима.</li>
  </ul>
  <hr />
  <h2 id="dDwo">Включение диагностического порта</h2>
  <h2 id="usb--quectel-thales">Для USB-модема (Quectel, Thales и др.)</h2>
  <pre id="qaes"># Найти порт модема
mmcli -L

# Включить DIAG (Qualcomm)
mmcli -m &lt;modem-index&gt; --command=&quot;AT$QCDMG&quot;</pre>
  <p id="GjoP">После этого появится устройство <code>/dev/ttyUSBx</code> (обычно ttyUSB0 или ttyUSB2) — это и есть DIAG-порт.</p>
  <h2 id="android">Для Android-устройства</h2>
  <pre id="liIv"># Включить отладку по USB
adb devices

# Проверить доступ
adb shell

# Включить DIAG (требует root)
adb shell &quot;su -c &#x27;setprop sys.usb.config diag,adb&#x27;&quot;</pre>
  <p id="elwd">На некоторых устройствах требуется прописать правило udev:</p>
  <pre id="RvFl"># Узнать VID:PID
lsusb

# Создать правило
sudo nano /etc/udev/rules.d/51-android.rules
# Добавить строку:
SUBSYSTEM==&quot;usb&quot;, ATTR{idVendor}==&quot;&lt;VID&gt;&quot;, ATTR{idProduct}==&quot;&lt;PID&gt;&quot;, MODE=&quot;0666&quot;, GROUP=&quot;plugdev&quot;

# Перезагрузить правила
sudo udevadm control --reload-rules</pre>
  <hr />
  <h2 id="qcsuper">Захват трафика через QCSuper</h2>
  <h2 id="8HIu">Базовый запуск</h2>
  <pre id="2rsj"># Для USB-модема
qcsuper --usb-modem /dev/ttyUSB0 --wireshark-live --decrypt-nas --reassemble-sibs --include-ip-traffic

# Для Android через ADB
qcsuper --adb --wireshark-live --decrypt-nas --reassemble-sibs</pre>
  <p id="vM3L">По умолчанию QCSuper показывает только сигнальные фреймы. Опция <code>--include-ip-traffic</code> добавляет пользовательский IP-трафик, если он есть.</p>
  <h2 id="wireshark">Что видно в Wireshark</h2>
  <ul id="ZkpU">
    <li id="7VCI"><strong>BCCH</strong> — широковещательные SIB (информация о соте);</li>
    <li id="C400"><strong>PCCH</strong> — paging;</li>
    <li id="GtZY"><strong>CCCH/DCCH</strong> — сигнальные сообщения (attach, authentication, bearer setup);</li>
    <li id="zNiw"><strong>DTCH</strong> — зашифрованный пользовательский трафик (если data bearer активен).</li>
  </ul>
  <p id="4H5V">Если data bearer отсутствует, DTCH будет пустым или отсутствовать. Но это не значит, что передача данных невозможна.</p>
  <hr />
  <h2 id="m0XP">Организация туннеля поверх служебного трафика</h2>
  <h2 id="MgZd">Идея</h2>
  <p id="vi7D">Поскольку прямой IP-канал недоступен, можно:</p>
  <ol id="F9m0">
    <li id="3A8G">Инкапсулировать пользовательские данные в сигнальные сообщения (например, в NAS или RRC);</li>
    <li id="NChk">Использовать существующий DTCH как транспорт, даже если он не поднимает PPP;</li>
    <li id="lU9v">Организовать туннель между двумя устройствами, где одно выступает как «модем», а другое — как шлюз.</li>
  </ol>
  <h2 id="socat">Пример: туннель через socat</h2>
  <p id="Zxbg">Предположим, у вас есть:</p>
  <ul id="gIPc">
    <li id="0CO4"><strong>Устройство A</strong> — модем с DIAG-портом (например, Raspberry Pi с USB-модемом);</li>
    <li id="byLr"><strong>Устройство B</strong> — шлюз с доступом в интернет.</li>
  </ul>
  <p id="q9Gr">На <strong>устройстве A</strong>:</p>
  <pre id="adKg"># Открыть порт для ретрансляции DIAG-трафика
socat TCP-LISTEN:12345,reuseaddr,fork /dev/ttyUSB0,raw,echo=0</pre>
  <p id="kGFk">На <strong>устройстве B</strong>:</p>
  <pre id="MgXo"># Создать виртуальный COM-порт, подключённый к устройству A
socat PTY,link=/dev/virtualTTY0,raw,echo=0 TCP:&lt;IP-устройства-A&gt;:12345

# Запустить QCSuper с туннелированием
qcsuper --usb-modem /dev/virtualTTY0 --wireshark-live --include-ip-traffic</pre>
  <p id="yp0c">Теперь можно захватывать трафик удалённо, а при необходимости — модифицировать его на лету (например, внедрять пользовательские данные в DTCH).</p>
  <hr />
  <h2 id="icmp-dns-http">Обход блокировок: ICMP, DNS, HTTP-туннели</h2>
  <p id="Y121">Если оператор блокирует обычный data bearer, но пропускает ICMP или DNS, можно использовать их как транспорт:</p>
  <h2 id="icmp--ping">ICMP-туннель (ping)</h2>
  <pre id="y00N">import socket, struct

def create_packet(id, data):
    ICMP_ECHO_REQUEST = 8
    header = struct.pack(&#x27;bbHHh&#x27;, ICMP_ECHO_REQUEST, 0, 0, id, 1)
    data = data + b&quot;\x00&quot; * ((len(data) % 2))
    # checksum calculation omitted for brevity
    return header + data

sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
packet = create_packet(1, b&quot;Hello, world!&quot;)
sock.sendto(packet, (&quot;8.8.8.8&quot;, 0))</pre>
  <p id="2yrf">Такой подход позволяет передавать данные внутри ICMP Echo Request, обходя блокировки на уровне L3.</p>
  <h2 id="dns">DNS-туннель</h2>
  <p id="psV2">DNS-запросы обычно не блокируются. Можно кодировать данные в поддоменах:</p>
  <pre id="HrvM"># Пример отправки данных через DNS
dig data12345.tunnel.example.com</pre>
  <p id="4kOr">На стороне сервера — парсить запросы и извлекать данные.</p>
  <h2 id="httphttps">HTTP/HTTPS-туннель</h2>
  <p id="j8pd">Если доступен HTTP/HTTPS (даже без полноценного data bearer), можно использовать:</p>
  <pre id="JN3F"># Через curl
curl -X POST -d @data.bin https://tunnel.example.com/upload

# Через socat
socat TCP-LISTEN:8080,reuseaddr,fork EXEC:&#x27;curl -X POST -d @- https://tunnel.example.com&#x27;</pre>
  <hr />
  <h2 id="diag">Практический пример: передача данных через DIAG</h2>
  <p id="AXJI">Допустим, нужно передать файл с устройства на сервер, но PPP не поднимается.</p>
  <h2 id="1">Шаг 1: Подготовка</h2>
  <ul id="kFg9">
    <li id="Yc0a">Включить DIAG на модеме (AT$QCDMG);</li>
    <li id="354w">Убедиться, что QCSuper видит фреймы;</li>
    <li id="7UCP">На сервере — запустить socat для приёма данных.</li>
  </ul>
  <h2 id="2">Шаг 2: Кодирование данных</h2>
  <p id="lqwt">Пользовательские данные можно внедрять в:</p>
  <ul id="RhZh">
    <li id="L2kd"><strong>NAS-сообщения</strong> (например, в поля, которые не проверяются сетью);</li>
    <li id="IChF"><strong>RRC-сообщения</strong> (если есть возможность модифицировать их на уровне модема);</li>
    <li id="PBMd"><strong>DTCH</strong> (если он активен, но не поднимает PPP).</li>
  </ul>
  <h2 id="a7wJ"><strong>Ссылки:</strong></h2>
  <ul id="KC4p">
    <li id="pWFH">QCSuper: <a href="https://github.com/P1sec/QCSuper" target="_blank">https://github.com/P1sec/QCSuper</a></li>
    <li id="Rf3N">Включение DIAG на модемах: <a href="https://forum.digikey.com/t/cellular-layer3-tracing-possibility-for-qualcomm-based-modules-2g-3g-4g-lte-m-nb-iot/27228" target="_blank">https://forum.digikey.com/t/cellular-layer3-tracing-possibility-for-qualcomm-based-modules-2g-3g-4g-lte-m-nb-iot/27228</a></li>
    <li id="jiwi">ICMP-туннели: <a href="https://habr.com/ru/companies/ruvds/articles/763600/" target="_blank">https://habr.com/ru/companies/ruvds/articles/763600/</a></li>
    <li id="o0Nj">Приём служебного GSM-трафика: <a href="https://habr.com/ru/companies/timeweb/articles/947684/" target="_blank">https://habr.com/ru/companies/timeweb/articles/947684/</a></li>
  </ul>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@pole_sam/6P1lAhU6ATQ</guid><link>https://teletype.in/@pole_sam/6P1lAhU6ATQ?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/6P1lAhU6ATQ?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>Малоизвестные разработчики чипсетов LTE и GSM</title><pubDate>Sun, 06 Sep 2026 21:09:59 GMT</pubDate><description><![CDATA[Когда речь заходит о модемах LTE и GSM, на ум сразу приходят Qualcomm, MediaTek, Huawei и Samsung. Но за пределами этого «большого клуба» существовал и продолжает существовать целый пласт компаний, чьи чипы работали в миллионах устройств, но остались в тени. Многие из них были поглощены, закрыты или перепрофилированы, оставив после себя лишь упоминания в спецификациях и старых пресс-релизах.]]></description><content:encoded><![CDATA[
  <p id="nojF">Когда речь заходит о модемах LTE и GSM, на ум сразу приходят Qualcomm, MediaTek, Huawei и Samsung. Но за пределами этого «большого клуба» существовал и продолжает существовать целый пласт компаний, чьи чипы работали в миллионах устройств, но остались в тени. Многие из них были поглощены, закрыты или перепрофилированы, оставив после себя лишь упоминания в спецификациях и старых пресс-релизах.</p>
  <h2 id="single-mode-lte-altair--sequans">Пионеры single-mode LTE: Altair и Sequans</h2>
  <p id="1oxz"><strong>Altair Semiconductor</strong> (Израиль) — одна из первых компаний, выпустивших коммерческий LTE-чипсет. Их FourGee-3100 (Cat. 3, 100 Мбит/с) появился на рынке ещё в 2009 году и стал первым сертифицированным Verizon решением для LTE-сетей. Позже вышли FourGee-3800 (Cat. 4, 150 Мбит/с) и FourGee-3802 (Cat. 6, 300 Мбит/с) с поддержкой LTE-Advanced. В 2014 году Altair была приобретена Sony и переименована в Sony Semiconductor Israel, но бренд Altair сохранился для IoT-линейки (ALT1160, ALT1250 — Cat-M1/NB-IoT).</p>
  <p id="40jn"><strong>Sequans Communications</strong> (Франция) — начинала с WiMAX, но к 2011 году полностью переключилась на LTE. Их первый LTE-чип Colibri вышел в 2010 году, а позже компания стала известна благодаря Calliope (Cat. 1 для IoT) и Monarch (первый в мире single-chip Cat-M1/NB-IoT). Sequans поставляла чипы для China Mobile, SK Telecom, Verizon и других операторов, но осталась в нише IoT-модулей, не попав в массовый смартфонный рынок.</p>
  <h2 id="2010--gct-leadcore-innofidei">«Второй эшелон» 2010-х: GCT, Leadcore, Innofidei</h2>
  <p id="kCOZ"><strong>GCT Semiconductor</strong> (США/Корея) — разработчик single-mode LTE-чипов серии GDM724x, которые использовались в USB-донглах, CPE, M2M-устройствах и даже некоторых смартфонах. Их решения коммерчески доступны с 2010 года и до сих пор встречаются в IoT-модулях.</p>
  <p id="TP8K"><strong>Leadcore Technology</strong> (Китай) — дочерняя компания Datang Telecom, известная чипами LC1761, LC1860 и другими LTE-решениями для китайского рынка. Поддерживали TD-LTE и FDD, но остались в основном внутри экосистемы китайских OEM.</p>
  <p id="iE2r"><strong>Innofidei</strong> (Япония) — ещё один игрок, предлагавший single-mode LTE-чипсеты в начале 2010-х, но так и не вышедший на массовый рынок. Компания упоминается в отчётах ABI Research как один из пяти вендоров single-mode LTE, но широкой известности не получила.</p>
  <h2 id="icera-st-ericsson-renesas-mobile">Поглощённые и исчезнувшие: Icera, ST-Ericsson, Renesas Mobile</h2>
  <p id="W8Nt"><strong>Icera</strong> (Великобритания) — основана в 2002 году, специализировалась на software-defined модемах с архитектурой на базе custom DSP. Их чипы ICE8040/ICE8060 поддерживали 2G/3G/4G и использовались в смартфонах и планшетах. В 2011 году NVIDIA приобрела Icera за $367 млн, но к 2015 году свернула baseband-бизнес, так и не сумев конкурировать с Qualcomm.</p>
  <p id="OPBs"><strong>ST-Ericsson</strong> (совместное предприятие STMicroelectronics и Ericsson) — выпускала multimode-модемы Thor M7400/M7450 и платформы NovaThor (L8540, L8580) с интеграцией LTE Cat. 4, HSPA+, GSM, TD-SCDMA. Несмотря на технологическую продвинутость (28 нм, FDSOI, carrier aggregation), компания не выдержала конкуренции и была ликвидирована в 2013 году.</p>
  <p id="HIoE"><strong>Renesas Mobile</strong> (Япония) — наследник wireless-бизнеса Nokia, приобретённого Renesas в 2010 году. Разрабатывала multimode LTE-чипы, но в 2013 году продала LTE-активы Broadcom за $164 млн, фактически выйдя из рынка.</p>
  <h2 id="beceem-wavesat-comsys">Забытые имена: Beceem, Wavesat, Comsys</h2>
  <p id="NTfk"><strong>Beceem Communications</strong> (Израиль) — лидер рынка WiMAX-чипов, который к 2010 году выпустил первый multimode-чип BCS500 с поддержкой LTE и WiMAX. В том же году была приобретена Broadcom за $316 млн, но после сворачивания WiMAX-направления технологии Beceem так и не стали массовыми в LTE-сегменте.</p>
  <p id="EVbm"><strong>Wavesat</strong> (Израиль) — разработчик WiMAX-чипов Odyssey 9000, позднее поглощённый Cavium Networks в 2011 году.</p>
  <p id="Ylpf"><strong>Comsys</strong> (Израиль) — поставляла baseband-решения CM1125 для GSM/EDGE/WiMAX/LTE, но осталась в нише IP-лицензирования и не вышла на массовый рынок чипов.</p>
  <h2 id="spreadtrumunisoc-hisilicon-sanechips">Китайские игроки: Spreadtrum/UNISOC, HiSilicon, Sanechips</h2>
  <p id="jmNU"><strong>Spreadtrum</strong> (позже UNISOC) — начинала с GSM/GPRS-чипов для ультрабюджетных телефонов, позже добавила LTE. Сегодня UNISOC — один из крупнейших вендоров LTE-платформ для IoT и бюджетных смартфонов.</p>
  <p id="ToPc"><strong>HiSilicon</strong> (дочерняя Huawei) — разрабатывала LTE-чипы Balong для устройств Huawei и Honor, а также для внешних OEM.</p>
  <p id="sGnK"><strong>Sanechips</strong> (бывшая ZTE Microelectronics) — поставляла LTE-решения для оборудования ZTE и партнёров.</p>
  <h2 id="oFWJ"><strong>Почему они исчезли?</strong></h2>
  <p id="Pb5T">Рынок baseband-модемов — один из самых безжалостных в полупроводниковой индустрии. За период с 2010 по 2015 год из него ушли десятки компаний: Texas Instruments, Freescale, NXP, Infineon, Renesas Mobile, ST-Ericsson, Broadcom, NVIDIA/Icera, и это только верхушка айсберга. Причины их ухода не случайны — они системны и повторяются из кейса в кейс. Разберем их:</p>
  <h2 id="1----rd">1. Экстремальные затраты на R&amp;D при низкой маржинальности</h2>
  <p id="OcmL">Разработка multimode LTE-модема (GSM/UMTS/LTE, все мировые диапазоны, carrier aggregation, VoLTE) требует команды в 2000–3000 инженеров и ежегодных инвестиций в сотни миллионов долларов. При этом рынок быстро консолидировался: к 2014 году(время внедрения LTE) Qualcomm контролировала более 50% выручки, MediaTek и Intel делили ещё 30%, а всем остальным оставались крохи.</p>
  <p id="e4AS"><strong>Broadcom</strong> — хрестоматийный пример. Компания инвестировала около $3 млрд в baseband-бизнес (включая покупку Beceem за $316 млн и активов Renesas Mobile за $164 млн), но так и не смогла выйти на долю рынка выше 5%. В 2014 году Broadcom закрыла подразделение, уволив 2500 сотрудников.</p>
  <blockquote id="6S7L">«Мы увидели ухудшающуюся экономику этого бизнеса: цены и маржи падали, а ряд игроков не заботились о прибыли и были готовы работать в убыток ради присутствия на рынке. Чтобы выжить, нужна была доля рынка в топ-2 или топ-3. Мы были номер четыре или пять — это нежизнеспособно».<br />— Скотт Макгрегор, CEO Broadcom (2015)</blockquote>
  <p id="9eA3"><strong>NVIDIA/Icera</strong> — похожая история. После покупки Icera за $367 млн в 2011 году NVIDIA выпустила Tegra 4i с интегрированным модемом i500, но не смогла привлечь ни одного крупного OEM. К 2015 году компания свернула baseband-разработку, сославшись на доминирование Qualcomm и агрессивное ценообразование MediaTek.</p>
  <blockquote id="q1y0">«Я пытался найти способы продолжить разработку модемов. После тщательного анализа стало ясно: это просто неосуществимо. Другие компании сталкиваются с теми же ограничениями».<br />— Дженсен Хуанг, CEO NVIDIA (2015)</blockquote>
  <h2 id="2---12">2. Зависимость от 1–2 крупных клиентов</h2>
  <p id="WtUC"><strong>ST-Ericsson</strong> — классический кейс «смерти от зависимости». Совместное предприятие STMicroelectronics и Ericsson, созданное в 2009 году, к 2012 году потеряло двух ключевых клиентов: Nokia и Sony Ericsson. Nokia, переходя на Windows Phone и затем на Android, сократила заказы, а Sony Ericsson и вовсе исчезла как бренд.</p>
  <p id="EKRR">В 2012 году ST-Ericsson потеряла почти $1 млрд, а в 2013 году совместное предприятие было ликвидировано. Общие убытки с 2009 по 2013 год составили $2,7 млрд при выручке $7,82 млрд.</p>
  <blockquote id="wApF">«Главная причина провала — чрезмерная зависимость от Nokia и Sony Ericsson. Оба производителя пострадали от перехода рынка на Apple и Samsung, и это ударило по ST-Ericsson».<br />— аналитик Carnegie Bank (2013)</blockquote>
  <p id="3xbv">Ericsson попыталась продолжить бизнес самостоятельно, но к 2014 году закрыла и это направление, сославшись на «снижение цен, рост затрат на R&amp;D и сужение рынка».</p>
  <h2 id="3---qualcomm">3. Патентная монополия Qualcomm</h2>
  <p id="Dy0S">Qualcomm владела (и владеет) ключевыми патентами на CDMA, UMTS и LTE, что давало ей двойное преимущество:</p>
  <ul id="Wmgy">
    <li id="Pnq4"><strong>Лицензионные отчисления</strong> с каждого проданного устройства (3–5% от цены смартфона).</li>
    <li id="5XdU"><strong>Перекрёстное лицензирование</strong>: конкуренты вынуждены были покупать патенты у Qualcomm, чтобы легально выпускать свои чипы.</li>
  </ul>
  <p id="Ep8t">Это создавало «налоговый барьер»: даже если конкурент делал технически сопоставимый модем, его себестоимость оказывалась выше из-за патентных выплат.</p>
  <p id="FSWL"><strong>NVIDIA</strong> в 2016 году даже подала иск против Qualcomm, утверждая, что та «незаконно раздавила» её baseband-бизнес (включая Icera) через злоупотребление доминирующим положением. Иск так и не привёл к восстановлению бизнеса, но показал, насколько патентная сила Qualcomm влияла на рынок.</p>
  <h2 id="4---oem">4. Вертикальная интеграция OEM-производителей</h2>
  <p id="eV0W">К 2013–2015 годам крупнейшие OEM-производители начали разрабатывать собственные модемы:</p>
  <ul id="RiQn">
    <li id="Hiqq"><strong>Samsung</strong> — Exynos с интегрированными LTE-модемами.</li>
    <li id="rigH"><strong>Apple</strong> — переход на Qualcomm, а затем на собственные модемы (с 2023 года).</li>
    <li id="zM2A"><strong>Huawei</strong> — HiSilicon Balong.</li>
    <li id="gSCy"><strong>Xiaomi, OPPO, vivo</strong> — инвестиции в UNISOC и собственные R&amp;D-центры.</li>
  </ul>
  <p id="9dJV">Это сократило «открытый» рынок для независимых вендоров modem-чипов. Оставшиеся игроки (Qualcomm, MediaTek, UNISOC) боролись за оставшихся OEM, а мелкие компании просто не находили покупателей.</p>
  <h2 id="5">5. Ценовая война и «игроки, которым не важна прибыль»</h2>
  <p id="yWIA">Рынок LTE-модемов превратился в «красный океан» с агрессивным демпингом. MediaTek, Spreadtrum (UNISOC) и китайские вендоры готовы были работать с минимальной маржой ради доли рынка.</p>
  <p id="YFpk"><strong>Broadcom</strong> прямо указывала на это в 2014 году:</p>
  <blockquote id="0gpd">«На рынке было несколько игроков, которым было всё равно, зарабатывают они или нет. У них были стратегические императивы присутствовать в этом бизнесе любой ценой. Broadcom — коммерческая компания, мы так не работаем».</blockquote>
  <p id="XVbn">Это создавало ситуацию, когда даже технологически продвинутые решения (например, NovaThor L8580 от ST-Ericsson с 28 нм FDSOI и LTE Cat. 4) не могли конкурировать по цене с более простыми чипами MediaTek и Qualcomm.</p>
  <h2 id="6">6. Неспособность выйти на «критическую массу»</h2>
  <p id="55od">Аналитики сходились во мнении: чтобы выжить на рынке baseband-модемов, нужна доля рынка не менее 10–15%, а лучше - 20%. Ниже этого порога R&amp;D-затраты на новую генерацию (LTE-Advanced, Cat. 6/9/12, 5G) становились неподъёмными.<strong>GCT, Sequans, Altair</strong> выжили именно потому, что ушли в ниши (IoT, M2M, CPE), где требования ниже, а конкуренция слабее. Но в массовом сегменте смартфонов они не смогли набрать критическую массу и остались «вторым эшелоном».</p>
  <h2 id="7">7. Технологическая гонка: отставание на поколение = смерть</h2>
  <p id="Q8yO">Рынок модемов развивался быстрее, чем рынок connectivity-чипов (Wi-Fi, Bluetooth). Если за одно поколение baseband (2–3 года) проходило два поколения connectivity, то интеграция их в один чип становилась проблемой: baseband отставал, а connectivity — нет.</p>
  <p id="Higw"><strong>Broadcom</strong> пыталась решить это через покупку Beceem и Renesas Mobile, но так и не смогла синхронизировать циклы разработки. В итоге компания продала/закрыла baseband-бизнес, сосредоточившись на Wi-Fi, Ethernet и других направлениях.</p>
  <h2 id="8">8. «Эффект домино»: закрытия порождали новые закрытия</h2>
  <p id="9moz">Когда одна крупная компания уходила с рынка, это создавало цепную реакцию:</p>
  <ul id="sYAZ">
    <li id="ZFtA">Поставщики IP и инструментов теряли клиентов.</li>
    <li id="elog">Инженеры увольнялись и уходили в Qualcomm/MediaTek.</li>
    <li id="hMWl">OEM-производители переставали сертифицировать «рискованные» чипы.</li>
  </ul>
  <p id="F3Mk"><strong>ST-Ericsson</strong> после закрытия в 2013 году оставила после себя «пустоту»: Ericsson попыталась продолжить, но к 2014 году закрыла и этот бизнес. Аналогично, после ухода Broadcom в 2014 году на рынке остались только Qualcomm, Intel, MediaTek и горстка нишевых игроков.</p>
  <h2 id="MFwL">Intel: самый дорогой провал на рынке модемов</h2>
  <p id="s6uc"><strong>Intel</strong> — отдельная и, пожалуй, самая болезненная глава в истории baseband-рынка. Компания потратила на развитие модемного бизнеса более <strong>$10 млрд</strong> (включая покупку Infineon Wireless за $1,4 млрд в 2011 году), но в апреле 2019 года полностью вышла из сегмента смартфонных модемов, продав остатки Apple за $1 млрд — то есть с <strong>мульти-миллиардным убытком</strong>.</p>
  <h2 id="intel">Почему Intel проиграл</h2>
  <p id="GhZA"><strong>1. Зависимость от одного клиента.</strong> К 2018 году Apple была фактически единственным крупным заказчиком смартфонных модемов Intel. Когда Apple заключила сделку с Qualcomm, Intel потеряла последний якорь.macrumors</p>
  <blockquote id="dZRy">«После объявления Apple и Qualcomm мы оценили перспективы заработка на поставках этой технологии для смартфонов и пришли к выводу, что просто не видим пути к прибыли».<br />— Боб Свон, CEO Intel (апрель 2019)</blockquote>
  <p id="MSoZ"><strong>2. Технологическое отставание.</strong> По данным инсайдеров, Intel столкнулась с серьёзными проблемами при разработке 5G-модемов:</p>
  <ul id="hoM4">
    <li id="JRmb"><strong>Тепловыделение</strong>: XMM 8160 перегревался и требовал сложной системы охлаждения.</li>
    <li id="mbci"><strong>Энергопотребление</strong>: 5G-модем Intel потреблял значительно больше, чем решения Qualcomm, что критично для смартфонов.</li>
    <li id="iq7O"><strong>Сроки</strong>: Intel не успевала к релизу iPhone 2020 с готовым 5G-чипом.</li>
  </ul>
  <p id="UWeV"><strong>3. Патентная война Qualcomm.</strong> Intel поддерживала Apple в судебном процессе против Qualcomm, надеясь, что победа Apple откроет рынок. Но когда Apple сдалась и подписала 6-летний договор с Qualcomm, Intel оказалась в изоляции.</p>
  <blockquote id="n0Bh">«Intel не смогла преодолеть искусственные и непреодолимые барьеры для честной конкуренции, созданные схемой Qualcomm, и была вынуждена выйти с рынка в этом году».<br />— Роджерс, юрист Intel (декабрь 2019)</blockquote>
  <p id="9FuT"><strong>4. Экономика не складывалась.</strong> Даже с Apple в качестве единственного крупного клиента бизнес не был прибыльным. Intel оценивала общие затраты на разработку и acquisitions (Infineon, Beceem-конкуренты и т.д.) в <strong>$10+ млрд</strong>, а выручка так и не покрыла эти инвестиции.</p>
  <h2 id="intel">Что осталось после Intel</h2>
  <ul id="XtKT">
    <li id="HIin"><strong>Apple</strong> получила ~2200 инженеров, IP и оборудование для разработки собственных 5G-модемов (которые, появились в iPhone).</li>
    <li id="VgqD"><strong>Intel</strong> сохранила R&amp;D по 5G для <strong>PC, IoT, автомобилей и сетевой инфраструктуры</strong>, но полностью вышла из смартфонного сегмента.</li>
    <li id="dObZ"><strong>Qualcomm</strong> укрепила монополию: после ухода Intel и Apple–Qualcomm settlement на рынке смартфонных модемов остались Qualcomm, MediaTek, Samsung и UNISOC.</li>
  </ul>
  <h2 id="w9cC">Итог</h2>
  <p id="HEfG">Intel стала последним крупным игроком, который попытался бросить вызов Qualcomm на рынке smartphone modems — и проиграл. История Intel подтверждает общее правило: без доли рынка ≥15–20%, без 3–5 крупных OEM-клиентов и без способности выдерживать патентное давление Qualcomm baseband-бизнес обречён на убытки.</p>
  <blockquote id="U02i">«В бизнесе смартфонных модемов стало очевидно: нет ясного пути к прибыльности и положительной отдаче».<br />— Боб Свон, CEO </blockquote>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@pole_sam/uLxXaREJc5k</guid><link>https://teletype.in/@pole_sam/uLxXaREJc5k?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/uLxXaREJc5k?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>Как превратить бинарный CP-лог модема SIMCom A7665E в читаемый</title><pubDate>Sat, 29 Aug 2026 19:53:33 GMT</pubDate><description><![CDATA[Отладочные логи мобильных модемов часто выглядят как поток непонятных бинарных данных. Внутри могут находиться сообщения о регистрации в сети, выборе PLMN, параметрах serving cell, APN, IP-адресах и состоянии протоколов LTE. Однако без знания транспортного формата и таблицы сообщений прошивки этот поток практически бесполезен.]]></description><content:encoded><![CDATA[
  <h2 id="V5dc">Введение</h2>
  <p id="hip4">Отладочные логи мобильных модемов часто выглядят как поток непонятных бинарных данных. Внутри могут находиться сообщения о регистрации в сети, выборе PLMN, параметрах serving cell, APN, IP-адресах и состоянии протоколов LTE. Однако без знания транспортного формата и таблицы сообщений прошивки этот поток практически бесполезен.</p>
  <p id="8DSu">В этой статье разберём, как устроено распознавание debug-лога модема SIMCom A7665E на базе ASR «Crane» ASR1603. Цель — пройти весь путь от байтов, поступающих через USB, до человекочитаемой строки:</p>
  <pre id="EHs6">байтовый поток → бинарная запись → форматное сообщение → декодированные аргументы</pre>
  <p id="OK8k">Практически задача состоит из двух независимых частей:</p>
  <ul id="OVAH">
    <li id="lzEQ">определить границы бинарных записей;</li>
    <li id="iawi">понять смысл каждой записи по её идентификаторам и payload.</li>
  </ul>
  <p id="xfbd">Первую проблему можно решить детерминированно. Вторая требует базы форматных строк, соответствующей конкретной сборке прошивки.</p>
  <hr />
  <h2 id="1">1. Исходные условия</h2>
  <p id="AabM">В качестве устройства используется модем SIMCom A7665E</p>
  <p id="DqWX">Важно не перепутать этот поток с Qualcomm DIAG. CP-log ASR имеет другой бинарный формат, поэтому инструменты, рассчитанные на Qualcomm DIAG, например <code>qc_debug_monitor</code>, его не распознают.</p>
  <p id="Wzic">Итоговая архитектура декодера выглядит так:</p>
  <pre id="6HGy">/dev/ttyUSBx
     │
     │ AT+ECPLOG=1
     ▼
поток бинарных данных
     │
     ▼
asr_proto.py
байты → Record
     │
     ▼
asr_mdb.py
(msg_type, fmt_id) + payload → строка
     │
     ▼
asr_debug_monitor.py
захват, фильтрация, цветной вывод, replay</pre>
  <p id="6CmS">Такое разделение ответственности удобно по нескольким причинам:</p>
  <ul id="zNWc">
    <li id="kPUJ">транспортный парсер не зависит от базы форматов;</li>
    <li id="uxvp">декодер семантики не зависит от последовательного порта;</li>
    <li id="xZzW">один и тот же протокол можно использовать в CLI, web-мониторе или тестовой системе;</li>
    <li id="vhVC">каждый слой можно тестировать отдельно.</li>
  </ul>
  <hr />
  <h2 id="2--cp-log">2. Поиск CP-log-порта</h2>
  <h2 id="ttyusb0">Почему нельзя полагаться на <code>ttyUSB0</code></h2>
  <p id="CrGd">После перезагрузки модема Linux может назначить интерфейсам другие имена:</p>
  <pre id="96W4">до перезагрузки:     ttyUSB0, ttyUSB1, ttyUSB2
после перезагрузки:  ttyUSB3, ttyUSB4, ttyUSB5</pre>
  <p id="UqhE">Поэтому поиск порта по имени ненадёжен. Лучше использовать USB VID и номер интерфейса в USB-топологии.</p>
  <p id="RQey">В рассматриваемом устройстве CP-log находится на интерфейсе <code>#2</code>. В <code>pyserial</code> его можно найти по полю <code>location</code>:</p>
  <pre id="JMin">from serial.tools import list_ports

MODEM_VID = 0x1e0e
DEBUG_IFACE = 2

def find_debug_port(iface=DEBUG_IFACE, vid=MODEM_VID):
    fallback = None

    for port in list_ports.comports():
        if port.vid != vid:
            continue

        location = port.location or &quot;&quot;

        if location.endswith(f&quot;:1.{iface}&quot;):
            return port.device

        fallback = fallback or port.device

    return fallback</pre>
  <p id="NG7a">Ключевая проверка:</p>
  <pre id="rKri">location.endswith(&quot;:1.2&quot;)</pre>
  <p id="MAVU">Номер <code>ttyUSBx</code> может измениться, а номер USB-интерфейса в конкретной композиции обычно остаётся постоянным.</p>
  <h2 id="8Voq">Включение потока</h2>
  <p id="MSSK">CP-log не начинает передаваться автоматически. Сначала на тот же порт необходимо отправить AT-команду:</p>
  <pre id="AIQx">ENABLE_CMD = b&quot;AT+ECPLOG=1\r\n&quot;
DISABLE_CMD = b&quot;AT+ECPLOG=0\r\n&quot;</pre>
  <p id="iM0M">Пример открытия устройства:</p>
  <pre id="JJrL">import serial
import time

def open_device(device, baudrate=115200):
    ser = serial.Serial(device, baudrate, timeout=0.2)

    ser.reset_input_buffer()
    ser.write(ENABLE_CMD)
    ser.flush()

    time.sleep(0.4)

    # Удаляем эхо команды и текстовый ответ OK
    ser.reset_input_buffer()

    return ser</pre>
  <p id="1IyD">Здесь есть важная особенность: после <code>AT+ECPLOG=1</code> модем сначала может вернуть обычный текстовый ответ:</p>
  <pre id="8Ysu">AT+ECPLOG=1
OK</pre>
  <p id="vPCD">Затем начинается бинарный поток. Если не очистить входной буфер, парсер может попытаться интерпретировать ASCII-ответ как начало бинарной записи.</p>
  <p id="H6GH">При завершении работы полезно отключить лог:</p>
  <pre id="VVAC">ser.write(DISABLE_CMD)
ser.flush()
time.sleep(0.1)
ser.reset_input_buffer()
ser.close()</pre>
  <hr />
  <h2 id="3">3. Формат бинарной записи</h2>
  <h2 id="ubjE">Как была найдена граница сообщений</h2>
  <p id="fsPk">В дампе регулярно повторяется последовательность:</p>
  <pre id="bBVb">маленькое число → несколько нулей → полезная нагрузка</pre>
  <p id="PrUW">Это позволяет предположить, что первые два байта являются длиной записи в формате little-endian.</p>
  <p id="iVXc">Алгоритм проверки простой:</p>
  <ol id="ltNT">
    <li id="GBQz">прочитать первые два байта;</li>
    <li id="gqSf">интерпретировать их как <code>u16</code>;</li>
    <li id="uoWO">перейти вперёд на указанное количество байт;</li>
    <li id="MD6Q">проверить, похожи ли следующие два байта на очередную длину;</li>
    <li id="l7Ub">повторить процедуру до конца буфера.</li>
  </ol>
  <p id="ZIYu">Если цепочка проходит через весь дамп без рассинхронизации, гипотеза подтверждается.</p>
  <p id="6Alv">Такой формат обладает свойством самосинхронизации: если в поток попал мусор, длина обычно выходит за разумные пределы, и парсер может начать поиск следующей потенциальной записи.</p>
  <h2 id="7rQZ">Заголовок</h2>
  <p id="Nurd">Аргументы сообщения</p>
  <p id="VSwH">В Python структура описывается так:</p>
  <pre id="Ub4l">import struct

HDR = struct.Struct(&quot;&lt;HHHHHHI&quot;)
HDR_LEN = HDR.size  # 16 байт</pre>
  <p id="aj7y">Порядок полей:</p>
  <pre id="CwfQ">length, flags, channel, seq, msg_type, fmt_id, timestamp</pre>
  <h2 id="ygey">Таймстамп</h2>
  <p id="hfGU">Поле <code>timestamp</code> не является временем в микросекундах или миллисекундах. Экспериментальное сопоставление с известными интервалами показало, что устройство использует частоту 32768 Гц:</p>
  <pre id="InD3">TS_HZ = 32768

def timestamp_seconds(timestamp):
    return timestamp / TS_HZ</pre>
  <p id="aoWG">Например:</p>
  <pre id="01r3">timestamp = 2 572 383
time      = 2 572 383 / 32 768 ≈ 78.503 с</pre>
  <p id="2Nmr">Это абсолютное время работы устройства до момента включения ECPLOG. В пользовательском интерфейсе удобнее вычесть timestamp первой записи и показывать относительное время:</p>
  <pre id="ut3n">[+0.000000] ...
[+0.003174] ...
[+0.006287] ...</pre>
  <hr />
  <h2 id="4">4. Потоковый парсер</h2>
  <p id="gX1F">Парсер должен корректно работать в двух режимах:</p>
  <ul id="zva4">
    <li id="45NA">с готовым бинарным файлом;</li>
    <li id="X9Zh">с живым потоком, где одна запись может прийти несколькими частями.</li>
  </ul>
  <h2 id="3y14">Разбор одной записи</h2>
  <pre id="Eg2b">MIN_REC = 16
MAX_REC = 16384

def take_record(buf, offset, flush=False):
    end = len(buf)

    if offset + 2 &gt; end:
        return None, offset, True

    length = buf[offset] | (buf[offset + 1] &lt;&lt; 8)

    if length &lt; MIN_REC or length &gt; MAX_REC:
        # Некорректная длина: пробуем синхронизацию со следующего байта
        return None, offset + 1, False

    if offset + length &gt; end:
        if flush:
            # Финальный обрезанный хвост
            return None, offset + 1, False

        # Для живого потока ждём следующую порцию данных
        return None, offset, True

    fields = HDR.unpack_from(buf, offset)

    record = {
        &quot;length&quot;: fields[0],
        &quot;flags&quot;: fields[1],
        &quot;channel&quot;: fields[2],
        &quot;seq&quot;: fields[3],
        &quot;msg_type&quot;: fields[4],
        &quot;fmt_id&quot;: fields[5],
        &quot;timestamp&quot;: fields[6],
        &quot;payload&quot;: bytes(
            buf[offset + HDR_LEN:offset + length]
        ),
        &quot;offset&quot;: offset,
    }

    return record, offset + length, False</pre>
  <h2 id="HLZH">Инкрементальный режим</h2>
  <pre id="pfxt">class StreamParser:
    def __init__(self):
        self.buffer = bytearray()

    def feed(self, chunk):
        self.buffer.extend(chunk)

        offset = 0
        end = len(self.buffer)

        while offset &lt; end:
            record, next_offset, need_more = take_record(
                self.buffer,
                offset,
                flush=False
            )

            if need_more:
                break

            offset = next_offset

            if record is not None:
                yield record

        if offset:
            del self.buffer[:offset]

        # Защита от бесконечного роста при потере синхронизации
        if len(self.buffer) &gt; 1 &lt;&lt; 20:
            del self.buffer[:len(self.buffer) - (1 &lt;&lt; 16)]</pre>
  <p id="udSn">Если в середине записи пришёл только заголовок и часть payload, она остаётся во внутреннем буфере. Следующий вызов <code>feed()</code> продолжает разбор.</p>
  <hr />
  <h2 id="5">5. Разбор первой записи</h2>
  <p id="bfmo">Рассмотрим пример записи размером 34 байта:</p>
  <pre id="eTHt">22 00 | 00 00 | 00 00 | 01 00 | 2b 00 | 96 14 |
5f 40 27 00 |
02 00 63 00 78 08 12 00 01 00 00 00 02 00 00 00 00 00</pre>
  <p id="YQni">Разметка:</p>
  <pre id="7mcY">length     flags      channel    seq
22 00      00 00      00 00      01 00

msg_type   fmt_id     timestamp
2b 00      96 14      5f 40 27 00

payload
02 00 63 00 78 08 12 00 01 00 00 00 02 00 00 00 00 00</pre>
  <p id="QS7G">В данном случае <code>msg_type = 0x2b</code> соответствует текстовой записи. Однако payload содержит бинарный префикс, поэтому его нельзя безусловно интерпретировать как обычную C-строку.</p>
  <hr />
  <h2 id="6">6. Типы сообщений</h2>
  <p id="v9sT">Поле <code>msg_type</code> определяет, как нужно обрабатывать запись:</p>
  <pre id="dnnO">TYPE_TEXT = 0x2B

TYPE_NAMES = {
    0x2B: &quot;TEXT&quot;,
    0x1D: &quot;TRACE&quot;,
    0x17: &quot;SIGNAL&quot;,
    0x1A: &quot;T1A&quot;,
    0x16: &quot;T16&quot;,
    0x0E: &quot;T0E&quot;,
    0x03: &quot;T03&quot;,
}</pre>
  <h2 id="text">TEXT-записи</h2>
  <p id="nzXJ">TEXT-записи уже содержат готовые фрагменты текста. Их можно декодировать без базы форматных строк, извлекая печатные ASCII-последовательности.</p>
  <pre id="tIqc">def printable_runs(data, min_run=3):
    runs = []
    current = bytearray()

    for byte in data:
        if 32 &lt;= byte &lt; 127:
            current.append(byte)
        else:
            if len(current) &gt;= min_run:
                runs.append(current.decode(&quot;latin-1&quot;))
            current.clear()

    if len(current) &gt;= min_run:
        runs.append(current.decode(&quot;latin-1&quot;))

    return runs</pre>
  <p id="689M">Для текстовых записей достаточно использовать короткий порог:</p>
  <pre id="lsqx">runs = printable_runs(payload, min_run=3)
text = &quot; &quot;.join(runs)</pre>
  <h2 id="terse">Terse-записи</h2>
  <p id="upv9">Terse-записи содержат не сам текст, а:</p>
  <ul id="cu0T">
    <li id="uY5y">идентификатор форматной строки;</li>
    <li id="Y65C">бинарные аргументы.</li>
  </ul>
  <p id="Dc7q">Их можно представить как удалённый вызов:</p>
  <pre id="TC9k">diagPrintf(&quot;Serving Cell: rsrp = %d&quot;, rsrp);</pre>
  <p id="UXSP">На провод передаются только:</p>
  <pre id="95Ot">fmt_id + бинарное значение rsrp</pre>
  <p id="qqtj">Сама строка формата находится в базе данных прошивки.</p>
  <hr />
  <h2 id="7--fileline">7. Записи <code>file:line</code> без базы</h2>
  <p id="ObEZ">Часть assert-сообщений содержит имя исходного файла и номер строки:</p>
  <pre id="TfgR">rrcdsutils.c\0\xa2\x0a\x00\x00</pre>
  <p id="dSCI">То есть payload имеет вид:</p>
  <pre id="lgBf">имя файла + NUL + номер строки u32</pre>
  <p id="95nX">Такой формат можно распознать независимо от версии базы:</p>
  <pre id="ahNy">import re

SOURCE_RE = re.compile(
    r&quot;\.(c|h|cpp|cc|cxx)$&quot;,
    re.IGNORECASE
)

def decode_file_line(payload):
    nul = payload.find(b&quot;\x00&quot;)

    if nul &lt; 4:
        return None

    raw_name = payload[:nul]

    if not all(32 &lt;= byte &lt; 127 for byte in raw_name):
        return None

    name = raw_name.decode(&quot;latin-1&quot;)

    if not SOURCE_RE.search(name):
        return None

    name = name.replace(&quot;\\&quot;, &quot;/&quot;).rsplit(&quot;/&quot;, 1)[-1]

    if len(payload) &lt; nul + 5:
        return None

    line = int.from_bytes(
        payload[nul + 1:nul + 5],
        &quot;little&quot;
    )

    return name, line</pre>
  <p id="ZL5B">Пример результата:</p>
  <pre id="nsPi">rrcdsutils.c:2722</pre>
  <p id="ViNf">Строгая проверка необходима: случайный бинарный payload тоже может содержать печатные байты. Условие с расширением исходного файла снижает вероятность ложного распознавания.</p>
  <hr />
  <h2 id="8">8. База форматных строк</h2>
  <h2 id="m7nZ">Зачем нужна база</h2>
  <p id="RaAb">Terse-сообщение само по себе неполно. Например, запись может содержать:</p>
  <pre id="abea">msg_type = 0x1d
fmt_id   = 0x0b3d
payload  = бинарные аргументы</pre>
  <p id="pBj1">Чтобы понять, что означают эти байты, нужна запись из базы:</p>
  <pre id="Q0pV">&quot;updates ( %ld , %d ) measUpdateTime: ( 0x%lx ) , ( rsrp = %d )&quot;</pre>
  <p id="84n3">В случае ASR используется база <code>cp_MDB.txt</code> формата CATStudio <code>TxtDbHeader</code>.</p>
  <h2 id="mUgJ">Секции базы</h2>
  <p id="uQjt">Наиболее важны три секции:</p>
  <ul id="aBYu">
    <li id="WO2u"><code>EnumValsRes</code> — таблица форматных строк;</li>
    <li id="h2CU"><code>Enums</code> — преобразование числовых значений в имена;</li>
    <li id="QZXW"><code>Signals</code> — описания структур для <code>%S{...}</code>.</li>
  </ul>
  <h2 id="1Mvd">Извлечение секций</h2>
  <p id="wnB3">В начале файла находится индекс с байтовыми смещениями:</p>
  <pre id="0pPl">EnumValsRes,1234,987654
Enums,987654,1048576
Signals,1048576,4567890</pre>
  <p id="Ehs3">Пример загрузки:</p>
  <pre id="KyHY">def parse_sections(raw):
    marker = raw.find(b&quot;&lt;end&gt;&quot;)

    if marker &lt; 0:
        return {}

    header = raw[:marker].decode(
        &quot;latin-1&quot;,
        &quot;replace&quot;
    )

    sections = {}

    for line in header.splitlines():
        parts = line.split(&quot;,&quot;)

        if len(parts) != 3:
            continue

        name, start, end = parts

        if start.isdigit() and end.isdigit():
            sections[name] = (
                int(start),
                int(end)
            )

    return sections</pre>
  <h2 id="Rmba">Таблица форматных строк</h2>
  <p id="ylkW">Строка в <code>EnumValsRes</code> выглядит примерно так:</p>
  <pre id="FhHA">table,id,flag,flag,GROUP,MODULE,NAME,diagPrintf(&quot;формат&quot;, args);</pre>
  <p id="bb2Y">Запятые могут встречаться внутри самой форматной строки, поэтому разделять строку нужно только по первым семи запятым:</p>
  <pre id="NoFM">parts = line.split(&quot;,&quot;, 7)</pre>
  <p id="bFob">Для поддержки всех вариантов вызова используется регулярное выражение:</p>
  <pre id="HPWv">import re

FORMAT_RE = re.compile(
    r&#x27;diag(?:Text|Struct)?Printf\s*\(&#x27;
    r&#x27;\s*&quot;((?:[^&quot;\\]|\\.)*)&quot;&#x27;
)</pre>
  <p id="p2Pr">Оно распознаёт:</p>
  <pre id="VUpv">diagPrintf(...)
TextPrintf(...)
StructPrintf(...)</pre>
  <p id="QmvP">Это исправляет важную ошибку: если искать только <code>diagPrintf</code>, записи <code>diagTextPrintf</code> и <code>diagStructPrintf</code> останутся без форматной строки и будут ошибочно показаны как hex.</p>
  <hr />
  <h2 id="9">9. Подбор подходящей базы</h2>
  <p id="ssBR">База форматных строк должна соответствовать сборке прошивки. Даже если две версии используют один и тот же чипсет, идентификаторы сообщений могут отличаться.</p>
  <p id="AF9D">Для выбора наиболее подходящей базы удобно использовать измеримые метрики.</p>
  <h2 id="key-match">Key-match</h2>
  <p id="jypT">Первая метрика — доля пар <code>(msg_type, fmt_id)</code>, найденных в базе:</p>
  <pre id="VIVM">distinct_keys = {
    (record[&quot;msg_type&quot;], record[&quot;fmt_id&quot;])
    for record in terse_records
}

matched = {
    key for key in distinct_keys
    if key in mdb_entries
}

key_match = len(matched) / len(distinct_keys)</pre>
  <p id="lUoq">Эта метрика показывает, совпадает ли схема идентификаторов.</p>
  <h2 id="scalar-clean">Scalar-clean</h2>
  <p id="mXzA">Вторая метрика проверяет, удалось ли полностью разобрать аргументы скалярных сообщений без маркера <code>&lt;?&gt;</code>.</p>
  <pre id="N5kE">scalar-clean =
число сообщений без underflow /
общее число проверяемых сообщений</pre>
  <p id="p0Vu">Она проверяет уже не только идентификаторы, но и ширины аргументов.</p>
  <hr />
  <h2 id="10---int--16">10. Главная особенность: <code>int</code> занимает 16 бит</h2>
  <p id="Zdfj">Это наиболее нетривиальная часть реверса.</p>
  <h2 id="i6fj">Симптом</h2>
  <p id="f3EN">При стандартной интерпретации printf-аргументов каждый <code>%d</code> ожидает 4 байта. Но результаты выглядели неправильно:</p>
  <pre id="26rT">rsrp = 104922215</pre>
  <p id="T0Lm">или:</p>
  <pre id="9Y9L">rsrp = &lt;?&gt;</pre>
  <p id="1z6P">Причина — payload заканчивался раньше, чем ожидал декодер.</p>
  <h2 id="YdnK">Проверка гипотезы</h2>
  <p id="CTkG">Для каждого сообщения можно вычислить ожидаемый размер аргументов и сравнить его с фактической длиной payload:</p>
  <pre id="spNI">def fit_score(records, short_width):
    exact = 0
    underflow = 0
    leftover = 0

    for record in records:
        fmt = get_format(record)

        if not fmt:
            continue

        required = calculate_argument_size(
            fmt,
            short_width=short_width,
            long_width=4
        )

        actual = len(record[&quot;payload&quot;])

        if required == actual:
            exact += 1
        elif required &gt; actual:
            underflow += 1
        else:
            leftover += 1

    return exact, underflow, leftover</pre>
  <p id="rjXk">При ширине 2 байта количество underflow уменьшается примерно в пять раз.</p>
  <h2 id="gRsK">Практическое правило</h2>
  <p id="1W9r">Для ASR-терс-сообщений используется следующее соответствие:</p>
  <pre id="zjgb">if conversion in &quot;eEfFgG&quot;:
    width = 8 if length in (&quot;l&quot;, &quot;ll&quot;, &quot;L&quot;) else 4
elif conversion == &quot;p&quot;:
    width = 4
elif length == &quot;ll&quot;:
    width = 8
elif length == &quot;hh&quot;:
    width = 1
elif length == &quot;l&quot;:
    width = 4
elif length in (&quot;L&quot;, &quot;z&quot;, &quot;j&quot;, &quot;t&quot;):
    width = 4
elif length == &quot;h&quot;:
    width = 2
else:
    width = 2</pre>
  <p id="bOlS">Значения <code>%d</code> и <code>%i</code> необходимо интерпретировать как знаковые:</p>
  <pre id="1QeR">value = int.from_bytes(
    payload[pos:pos + width],
    &quot;little&quot;,
    signed=conversion in &quot;di&quot;
)</pre>
  <hr />
  <h2 id="11">11. Сквозной пример декодирования</h2>
  <p id="5cVd">Рассмотрим запись:</p>
  <pre id="iLf0">msg_type = 0x1d
fmt_id   = 0x0b3d
payload  = e40c0000 d100 021c0f00 61e4</pre>
  <p id="8Y5t">Форматная строка:</p>
  <pre id="NtiQ">&quot;updates ( %ld , %d ) &#x27;s measUpdateTime: &quot;
&quot;( 0x%lx ) , ( rsrp = %d ) &quot;</pre>
  <p id="m4OD">Результат:</p>
  <pre id="KW0g">updates ( 3300, 209 ) measUpdateTime:
( 0xf1c02 ), ( rsrp = -7071 )</pre>
  <p id="Qibr">При ошибочной ширине <code>%d = 4 байта</code> декодер начал бы читать следующие аргументы с неправильных смещений и в итоге получил бы <code>&lt;?&gt;</code>.</p>
  <hr />
  <h2 id="12--s">12. Поддержка <code>%S{...}</code> и структур</h2>
  <p id="QBRT">Некоторые диагностические сообщения передают не скаляры, а структуры:</p>
  <pre id="4EsE">%S{EmmPrintDebugInfoInd_MobileId}</pre>
  <p id="bCST">Описание полей находится в секции <code>Signals</code>.</p>
  <p id="tL4X">Минимальная модель структуры:</p>
  <pre id="9ngN">structs = {
    &quot;Example&quot;: [
        (&quot;field_a&quot;, &quot;int&quot;, 1, &quot;&quot;),
        (&quot;field_b&quot;, &quot;enum&quot;, 1, &quot;StateType&quot;),
        (&quot;field_c&quot;, &quot;pointer&quot;, 1, &quot;&quot;),
    ]
}</pre>
  <p id="dcrL">Декодер обрабатывает:</p>
  <ul id="JXXS">
    <li id="gWlK">скалярные поля;</li>
    <li id="tGyp">enum;</li>
    <li id="4bsU">указатели;</li>
    <li id="k97N">вложенные структуры;</li>
    <li id="cBXV">массивы;</li>
    <li id="1mQp">рекурсию.</li>
  </ul>
  <p id="0KcX">Упрощённая схема:</p>
  <pre id="ec6w">def decode_struct(name, payload, pos=0, depth=0):
    if depth &gt; 6:
        return f&quot;{{{name}?}}&quot;, pos

    fields = structs.get(name)

    if fields is None:
        return f&quot;{{{name}?}}&quot;, pos

    result = []

    for field_name, field_type, count, detail in fields:
        values = []

        for _ in range(count):
            if field_type == &quot;enum&quot;:
                value = read_u32(payload, pos)
                pos += 4
                value = enums.get(detail, {}).get(
                    value,
                    str(value)
                )

            elif field_type == &quot;pointer&quot;:
                value = read_u32(payload, pos)
                pos += 4
                value = hex(value)

            elif field_type == &quot;int&quot;:
                value = read_u32(payload, pos, signed=True)
                pos += 4

            elif detail in structs:
                value, pos = decode_struct(
                    detail,
                    payload,
                    pos,
                    depth + 1
                )

            else:
                value = &quot;&lt;?&gt;&quot;

            values.append(value)

        rendered = (
            values[0]
            if count == 1
            else &quot;[&quot; + &quot;,&quot;.join(map(str, values)) + &quot;]&quot;
        )

        result.append(f&quot;{field_name}={rendered}&quot;)

    return &quot;{&quot; + &quot;, &quot;.join(result) + &quot;}&quot;, pos</pre>
  <h2 id="vwkz">Почему структуры могут декодироваться неверно</h2>
  <p id="yUmc">Секция <code>Signals</code> из близкой базы может не полностью соответствовать конкретной сборке модема. Например, поля большой EMM-структуры могут иметь другую раскладку или тип.</p>
  <p id="b6JO">В результате появляются значения вроде:</p>
  <pre id="fOaO">mcc = -1727901696</pre>
  <p id="ZHLK">В таких случаях проблема находится не в транспортном парсере, а в несовпадении описания структуры. Исправить её можно только точной базой <code>cp_MDB.txt</code> для конкретной версии прошивки.</p>
  <hr />
  <h2 id="13">13. Приоритет способов декодирования</h2>
  <p id="DAx5">Одна запись может быть распознана несколькими способами. Поэтому форматтеру нужен строгий порядок выбора:</p>
  <pre id="jWY2">1. TEXT-запись
   └─ готовая строка, база не нужна

2. file:line
   └─ имя исходного файла и номер строки

3. terse-декодирование через MDB
   └─ форматная строка + бинарные аргументы

4. встроенная ASCII-строка
   └─ длинный печатный фрагмент внутри payload

5. raw hex
   └─ неизвестный или неподдерживаемый payload</pre>
  <p id="lRIn">Формат вывода может выглядеть так:</p>
  <pre id="HjYG">[+0.000000] [TEXT] +ZDON
[+0.003174] [NAS] New Selected PLMN (250,1)
[+0.006287] [RRC] Serving Cell rsrp=-110.5 dBm
[+0.009460] [ASSERT] rrcdsutils.c:2722</pre>
  <p id="FcLg">Большие необработанные записи лучше скрывать по умолчанию и включать отдельным флагом:</p>
  <pre id="sjDl">./asr_debug_monitor.py --replay capture.bin -t</pre>
  <p id="wJnW">где <code>-t</code> показывает terse-записи, а:</p>
  <pre id="hF41">./asr_debug_monitor.py --replay capture.bin -a</pre>
  <p id="MmN8">показывает все записи, включая объёмные signal-сообщения.</p>
  <hr />
  <h2 id="14----seq">14. Контроль потерь по <code>seq</code></h2>
  <p id="ES8X">Поле <code>seq</code> — 16-битный счётчик записей. Оно позволяет заметить потерю данных на USB или переполнение буфера.</p>
  <p id="8XKj">Поскольку счётчик циклический, сравнение выполняется по модулю 2162^{16}216:</p>
  <pre id="0PEP">def sequence_gap(previous, current):
    return (current - previous - 1) &amp; 0xFFFF</pre>
  <p id="JeNR">Практическая проверка:</p>
  <pre id="GclP">gap = (record.seq - last_seq - 1) &amp; 0xFFFF

if 0 &lt; gap &lt; 0x8000:
    dropped += gap</pre>
  <p id="wWXc">Ограничение <code>gap &lt; 0x8000</code> нужно, чтобы отличать нормальное переполнение счётчика от большого обратного скачка.</p>
  <p id="jGpF">В интерфейсе можно показывать:</p>
  <pre id="Sd1i">[warning] потеряно записей: 12</pre>
  <p id="6So1">Это особенно полезно при высокоскоростном логе, когда USB-порт, пользовательский процесс или внутренний буфер не успевают обработать весь поток.</p>
  <hr />
  <h2 id="15">15. Верификация</h2>
  <p id="EM1m">Декодер необходимо проверять на двух уровнях.</p>
  <h2 id="oR4J">Автономные тесты</h2>
  <p id="Unbt">Полезно протестировать отдельно:</p>
  <ul id="ezl6">
    <li id="8Gqq">разбор заголовка;</li>
    <li id="IifS">length-framing;</li>
    <li id="AMFg">повторную синхронизацию после мусора;</li>
    <li id="qezt">инкрементальный <code>StreamParser</code>;</li>
    <li id="6Eqo">TEXT-записи;</li>
    <li id="47sS"><code>file:line</code>;</li>
    <li id="4BJP">разбор MDB;</li>
    <li id="9Ihr"><code>%S{...}</code>;</li>
    <li id="uOGj"><code>%e{...}</code>;</li>
    <li id="rAzS">16-битные аргументы.</li>
  </ul>
  <p id="cKzK">В исходном проекте такой набор из девяти тестов проходит на синтетической базе и искусственно сформированных записях.</p>
  <h2 id="3dgQ">Сквозная проверка</h2>
  <p id="izYy">Затем необходимо проверить полный путь:</p>
  <pre id="5Aog">A7665E
  → USB CP-log
  → StreamParser
  → MDB decoder
  → человекочитаемый вывод</pre>
  <p id="5uis">В корректно декодированных сообщениях должны распознаваться, например:</p>
  <ul id="tSvn">
    <li id="P5e1"><code>+ZDON</code>;</li>
    <li id="PGLL">выбранная PLMN;</li>
    <li id="ZYBz">serving cell;</li>
    <li id="JbUY">RSRP и RSRQ;</li>
    <li id="j28R">APN;</li>
    <li id="2awn">IP-адрес;</li>
    <li id="gYrv">события NAS и RRC;</li>
    <li id="xncU">сообщения IPC между L1 и protocol stack.</li>
  </ul>
  <hr />
  <h2 id="16">16. Ограничения метода</h2>
  <p id="wdN1">Даже при правильно найденном транспортном формате часть сообщений может оставаться неполностью декодированной.</p>
  <p id="WKFB">Особенно важно различать ошибки разных уровней:</p>
  <pre id="JnVN">неправильная длина записи
    → проблема транспортного парсера

правильная запись, но &lt;?&gt;
    → проблема формата или ширины аргумента

правильный текст, но неверные поля структуры
    → несовпадение Signals с конкретной прошивкой</pre>
  <p id="6NXp">Транспортный формат при этом может быть полностью понятен, даже если семантическая расшифровка остаётся неполной.</p>
  <hr />
  <h2 id="17">17. Запуск декодера</h2>
  <p id="T3fE">Примерный набор команд:</p>
  <pre id="Kj1K">cd /home/sam/work/modems_debug/asr_debug</pre>
  <p id="ThEK">Живой захват с автоматическим поиском порта:</p>
  <pre id="XL0x">./asr_debug_monitor.py</pre>
  <p id="cRFI">Разбор сохранённого файла:</p>
  <pre id="h8Cm">./asr_debug_monitor.py \
    --replay boot_registration.bin</pre>
  <p id="qRL0">Разбор terse-записей:</p>
  <pre id="YfcI">./asr_debug_monitor.py \
    --replay boot_registration.bin \
    -t</pre>
  <p id="oHIg">Вывод всех записей:</p>
  <pre id="QuAd">./asr_debug_monitor.py \
    --replay boot_registration.bin \
    -a</pre>
  <p id="jhVH">Использование точной базы:</p>
  <pre id="yD3T">./asr_debug_monitor.py \
    -m /path/to/exact/cp_MDB.txt</pre>
  <p id="gXAP">Для захвата, переживающего ребут модема, нужен внешний wrapper:</p>
  <ol id="r2E9">
    <li id="luXb">дождаться появления нужного USB-интерфейса;</li>
    <li id="HBc7">открыть порт;</li>
    <li id="oNsb">отправить <code>AT+ECPLOG=1</code>;</li>
    <li id="RCOp">записывать необработанный поток;</li>
    <li id="Fk5F">обнаружить исчезновение порта;</li>
    <li id="DaXC">дождаться повторной USB-энумерации;</li>
    <li id="w0La">открыть новую сессию в отдельном файле.</li>
  </ol>
  <p id="DuEe">Так можно захватывать загрузку модема с самого начала, даже если во время ребута меняются имена <code>ttyUSBx</code>.</p>
  <hr />
  <h2 id="x0s0">Заключение</h2>
  <p id="FRgz">Распознавание бинарного CP-лога ASR состоит из нескольких независимых уровней:</p>
  <pre id="k5L8">USB-порт
  → AT+ECPLOG=1
  → length-framing
  → 16-байтный заголовок
  → msg_type + fmt_id
  → база форматных строк
  → декодирование printf-аргументов
  → структуры, enum и timestamp
  → читаемый трейс</pre>
  <p id="hX32">Самая важная практическая находка — нестандартная упаковка аргументов: обычные <code>%d</code>, <code>%u</code> и <code>%x</code> в terse-сообщениях ASR занимают 2 байта, а <code>%l...</code> — 4 байта. Без этого правила идентификаторы сообщений могут находиться правильно, но значения будут «плыть», а декодер будет регулярно выдавать <code>&lt;?&gt;</code>.</p>
  <p id="0WEU">Второй важный вывод — транспорт и семантику нужно разрабатывать отдельно. Формат записи можно восстановить и протестировать независимо от базы. А база, в свою очередь, может заменяться без изменений в протоколе и потоковом парсере.</p>
  <p id="xDt1">Для полного покрытия остаётся получить точную <code>cp_MDB.txt</code> под прошивку <code>A7665M5_B01V01</code>. После этого должны исчезнуть ошибки в больших структурах, неизвестные enum и большая часть необработанных бинарных хвостов.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@pole_sam/CAcPKudWlw4</guid><link>https://teletype.in/@pole_sam/CAcPKudWlw4?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/CAcPKudWlw4?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>Как используются данные SIM‑карты в GSM (2G): аутентификация, ключи, IMSI, A3/A8</title><pubDate>Sat, 15 Aug 2026 18:36:57 GMT</pubDate><description><![CDATA[Всем привет! В GSM (2G) SIM‑карта хранит постоянный секретный ключ абонента Ki и идентификатор IMSI; при регистрации в сети используется механизм «вызов‑ответ»: сеть посылает случайное число RAND, SIM вычисляет подписанный ответ SRES = A3(Ki, RAND) и сеансовый ключ шифрования Kc = A8(Ki, RAND), после чего сеть проверяет SRES и при успехе включает шифрование A5.]]></description><content:encoded><![CDATA[
  <p id="VDme">Всем привет! В GSM (2G) SIM‑карта хранит постоянный секретный ключ абонента Ki и идентификатор IMSI; при регистрации в сети используется механизм «вызов‑ответ»: сеть посылает случайное число RAND, SIM вычисляет подписанный ответ SRES = A3(Ki, RAND) и сеансовый ключ шифрования Kc = A8(Ki, RAND), после чего сеть проверяет SRES и при успехе включает шифрование A5.</p>
  <p id="uy4r"><strong>Важно: Ki никогда не передаётся по радиоинтерфейсу и не выводится из SIM; вся криптография «вызов‑ответ» выполняется внутри SIM.jucs+2</strong></p>
  <h2 id="2">2. Роли сетевых элементов (кратко)</h2>
  <ul id="Qrmv">
    <li id="dzx6">MS (Mobile Station) = ME (телефон) + SIM.</li>
    <li id="HqES">BTS/BSC — радиодоступ.</li>
    <li id="eIA2">MSC/VLR — коммутация и локальное управление сессиями; VLR хранит «триплеты» аутентификации для абонента.</li>
    <li id="hRa0">HLR — домашний реестр абонентов.</li>
    <li id="ANBL">AuC (Authentication Center) — генерирует RAND, SRES, Kc (триплеты) на основе IMSI и Ki.</li>
  </ul>
  <h2 id="3---gsm-2g">3. Протокол аутентификации GSM (2G): пошагово</h2>
  <p id="VB6Q">Ниже — упрощённая последовательность при регистрации/доступе к услугам.</p>
  <pre id="qj9P">text[MS/SIM]                         [MSC/VLR]                         [HLR/AuC]
    |                                |                                |
    | 1. Location Update / CM Service Request (IMSI или TMSI)         |
    |---------------------------------------------------------------&gt;|
    |                                | 2. Запрос триплетов для IMSI   |
    |                                |------------------------------&gt;|
    |                                | 3. Возврат N триплетов         |
    |                                | (RAND_i, SRES_i, Kc_i)         |
    |                                |&lt;------------------------------|
    |                                |                                |
    | 4. AUTHENTICATION REQUEST      |                                |
    |    (RAND)                      |                                |
    |&lt;-------------------------------|                                |
    | 5. SIM: SRES&#x27; = A3(Ki, RAND)   |                                |
    |     Kc&#x27;   = A8(Ki, RAND)       |                                |
    | 6. AUTHENTICATION RESPONSE     |                                |
    |    (SRES&#x27;)                     |                                |
    |------------------------------&gt;|                                |
    |                                | 7. Проверка: SRES&#x27; == SRES?    |
    |                                |    Если да → аутентификация OK |
    | 8. Cipher Mode Command (A5/x)  |                                |
    |&lt;-------------------------------|                                |
    | 9. Включение шифрования A5/x с Kc&#x27;                               |
    |&lt;================================================================&gt;|</pre>
  <p id="r1XJ">Ключевые моменты:</p>
  <ul id="JYUI">
    <li id="w02J">Сеть заранее получает от AuC «триплеты» (RAND, SRES, Kc) для данного IMSI; при аутентификации она посылает только RAND.</li>
    <li id="3MKM">SIM вычисляет SRES&#x27; и Kc&#x27; по тем же формулам; VLR сравнивает SRES&#x27; с ожидаемым SRES.</li>
    <li id="loVT">После успеха сеть инициирует Cipher Mode Command и далее трафик шифруется A5/x с ключом Kc.</li>
  </ul>
  <h2 id="4--a3--a8">4. Алгоритмы A3 и A8: что именно считается</h2>
  <p id="SMqY">Формально стандарт GSM не фиксирует одну конкретную реализацию A3/A8; операторы выбирают алгоритм (часто COMP128‑1/2/3, milenage‑подобные варианты в 2G‑совместимых реализациях и др.).</p>
  <ul id="w5zA">
    <li id="kg76">A3: SRES = A3(Ki, RAND) → 32‑битный ответ.</li>
    <li id="fNwD">A8: Kc = A8(Ki, RAND) → 64‑битный сеансовый ключ для A5/x.</li>
  </ul>
  <p id="niDa">На практике A3 и A8 часто реализованы как единая функция, выдающая (SRES, Kc) из (Ki, RAND).</p>
  <h2 id="5--imsi">5. Роль IMSI и почему он важен</h2>
  <ul id="MVE8">
    <li id="AHqq">IMSI используется для идентификации абонента в HLR/AuC и получения правильного Ki (и триплетов).</li>
    <li id="LHax">При первой регистрации в новой зоне MS обычно передаёт IMSI (если нет валидного TMSI), что делает IMSI видимым для любой базовой станции в радиусе.</li>
  </ul>
  <ul id="v2Yb">
    <li id="5NY1">В дальнейшем сеть старается использовать TMSI вместо IMSI для конфиденциальности, но IMSI всё равно может быть запрошен (например, при сбоях или специальных процедурах).</li>
    <li id="qoc1">TMSI (Temporary Mobile Subscriber Identity) — это временный идентификатор абонента, который сеть выдаёт мобильному устройству после успешной регистрации, чтобы вместо постоянного IMSI использовать его в радиоканале для повышения конфиденциальности.</li>
  </ul>
  <h2 id="6---gsm-2g---sim">6. Риски безопасности GSM (2G), связанные с SIM и аутентификацией</h2>
  <p id="rEuK">GSM (2G) имеет ряд фундаментальных ограничений, которые напрямую касаются использования данных SIM:</p>
  <ol id="Pgy3">
    <li id="uoRn"><strong>Односторонняя аутентификация</strong></li>
    <ul id="Df8A">
      <li id="4473">Сеть аутентифицирует телефон (MS), но телефон не аутентифицирует сеть.</li>
      <li id="Aoyn">Это позволяет IMSI‑catcher&#x27;у (фейковой базовой станции) притворяться «легальной» сетью: телефон отправляет IMSI/TMSI, проходит «аутентификацию» у злоумышленника, а трафик может не шифроваться или шифроваться слабым алгоритмом.</li>
    </ul>
    <li id="xPOc"><strong>Слабость шифрования A5/1 (и A5/2)</strong></li>
    <ul id="YwyZ">
      <li id="WKaj">A5/1 (64‑битный ключ Kc) уязвим к атакам по заранее вычисленным таблицам (rainbow tables); практическая расшифровка возможна за секунды–минуты на обычном железе.</li>
      <li id="LNgs">A5/2 ещё слабее и практически не защищает.</li>
      <li id="TBQc">Злоумышленник может принудительно переключить сессию на A5/0 (без шифрования) или слабый A5/x.</li>
    </ul>
    <li id="ANCp"><strong>Зависимость от реализации A3/A8</strong></li>
    <ul id="9YIl">
      <li id="n2TF">Ранние популярные реализации (например, COMP128‑1) имели криптографические слабости, позволяющие при достаточном числе запросов извлекать Ki.</li>
      <li id="XaXw">Даже при более стойких A3/A8, 32‑битный SRES и 64‑битный Kc ограничивают криптостойкость по современным меркам.</li>
    </ul>
    <li id="v3LU"><strong>Перехват IMSI</strong></li>
    <ul id="k8J8">
      <li id="XMVy">Поскольку IMSI передаётся в открытом виде при первой регистрации, IMSI‑catcher может собирать IMSI всех устройств в зоне покрытия.</li>
    </ul>
  </ol>
  <p id="VwaX">Эти ограничения — причина, по которой в 3G/4G/5G введена взаимная аутентификация (сеть тоже доказывается абоненту), более длинные ответы (RES вместо SRES), ключи CK/IK и более стойкие алгоритмы (Milenage, AES‑based и др.).</p>
  <h2 id="7----sim">7. Сводная схема «данные SIM → параметры сессии»</h2>
  <pre id="6q7I">textSIM (Ki, IMSI, A3/A8)
       │
       │ IMSI → HLR/AuC → выбор Ki
       │
       └─► AuC: для каждого RAND_i
               SRES_i = A3(Ki, RAND_i)
               Kc_i   = A8(Ki, RAND_i)
               триплет (RAND_i, SRES_i, Kc_i) → VLR

При аутентификации:
  VLR → MS: RAND
  SIM: SRES&#x27; = A3(Ki, RAND)
       Kc&#x27;   = A8(Ki, RAND)
  MS → VLR: SRES&#x27;
  VLR: если SRES&#x27; == SRES → OK, шифрование A5/x с Kc&#x27;</pre>
  <hr />

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@pole_sam/MUgk4kD28C5</guid><link>https://teletype.in/@pole_sam/MUgk4kD28C5?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/MUgk4kD28C5?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>Данные вещательных каналов сотовой вышки (2G/GSM и LTE): что можно получить и как декодировать</title><pubDate>Mon, 03 Aug 2026 07:11:42 GMT</pubDate><description><![CDATA[Сотовая вышка (BTS в 2G, eNodeB в LTE) непрерывно передаёт в эфир «системную информацию» — набор параметров, которые нужны телефону (UE), чтобы обнаружить сеть, синхронизироваться и подготовиться к подключению. Это не «перехват трафика» — это открытые широковещательные (broadcast) данные, которые предназначены для приёма всеми устройствами в зоне покрытия. Их декодирование полностью пассивно, законно в большинстве юрисдикций и не затрагивает трафик абонентов.]]></description><content:encoded><![CDATA[
  <p id="aRmQ">Сотовая вышка (BTS в 2G, eNodeB в LTE) непрерывно передаёт в эфир «системную информацию» — набор параметров, которые нужны телефону (UE), чтобы обнаружить сеть, синхронизироваться и подготовиться к подключению. Это не «перехват трафика» — это открытые широковещательные (broadcast) данные, которые предназначены для приёма всеми устройствами в зоне покрытия. Их декодирование полностью пассивно, законно в большинстве юрисдикций и не затрагивает трафик абонентов.</p>
  <p id="ytlS">Ниже — какие каналы есть, что они несут и что из этого можно понять о вышке и сети.</p>
  <hr />
  <h2 id="1">1. Что вообще вещает вышка</h2>
  <p id="MJ6S">Любая вышка передаёт на нисходящей частоте (downlink) набор логических каналов. Для пассивного наблюдателя важны два класса:</p>
  <ul id="35bH">
    <li id="jnhI"><strong>Каналы синхронизации</strong> — позволяют обнаружить сигнал, получить тайминг и идентификатор соты.</li>
    <li id="WETF"><strong>Вещательные каналы</strong> (BCCH в 2G, BCH/DL-SCH в LTE) — несут системную информацию (System Information) с параметрами сети.</li>
  </ul>
  <p id="o79B">Телефон при включении делает ровно то же самое: ищет сигнал синхронизации, читает системную информацию и решает, можно ли подключиться. С помощью SDR (Software Defined Radio) и открытых инструментов этот процесс можно повторить без телефона.</p>
  <hr />
  <h2 id="2-gsm-2g">2. GSM (2G)</h2>
  <h2 id="4okX">Каналы и сообщения</h2>
  <p id="J1Kn">Вещательные данные GSM передаются на <strong>BCCH</strong> (Broadcast Control Channel), который передаётся непрерывно и служит стабильным опорным «маяком» соты. Основное содержимое BCCH — это сообщения <strong>System Information (SI)</strong>, описанные в <a href="https://www.etsi.org/deliver/etsi_ts/144000_144099/144018/17.00.00_60/ts_144018v170000p.pdf" target="_blank">ETSI TS 144 018</a> (3GPP TS 44.018). </p>
  <h2 id="bcch">Что можно извлечь из BCCH</h2>
  <ul id="4uKZ">
    <li id="Llja"><strong>MCC</strong> (Mobile Country Code) — страна оператора</li>
    <li id="R8mq"><strong>MNC</strong> (Mobile Network Code) — сам оператор</li>
    <li id="qBqZ"><strong>LAC</strong> (Location Area Code) — код зоны местоположения</li>
    <li id="gMDE"><strong>Cell ID (CI)</strong> — идентификатор соты → вместе с MCC+MNC+LAC+CI образует <strong>CGI</strong> (Cell Global Identity)</li>
    <li id="qGAb"><strong>ARFCN</strong> — номер радиоканала → пересчитывается в частоту</li>
    <li id="ZhGq"><strong>BSIC</strong> (Base Station Identity Code) — цветовой код вышки</li>
    <li id="CDVM"><strong>CCCH конфигурация</strong> — сколько каналов paging, AGCH и т.д.</li>
    <li id="Kqfb"><strong>Параметры RACH</strong> — как телефону запрашивать доступ</li>
    <li id="SF4w"><strong>Параметры выбора соты</strong> — минимальный уровень приёма (C1/C2), приоритеты</li>
    <li id="yuDJ"><strong>Список соседей</strong> — частоты соседних сот (для handover/reselection)</li>
    <li id="qVYn"><strong>Признак GPRS/EDGE</strong> — поддерживает ли сота пакетную передачу</li>
    <li id="dznm"><strong>Cell Barring</strong> — заблокирована ли сота для доступа</li>
    <li id="KGy2"><strong>Информация о 3G-соседях</strong> — частоты UMTS</li>
  </ul>
  <h2 id="pvZR">Синхронизация</h2>
  <p id="0KwF">До чтения BCCH нужно сначала найти сигнал. В GSM для этого служат:</p>
  <ul id="GAA5">
    <li id="sECW"><strong>FCCH</strong> (Frequency Correction Channel) — чистый синус на фиксированном смещении, позволяет подстроить частоту приёмника.</li>
    <li id="faTb"><strong>SCH</strong> (Synchronisation Channel) — несёт <strong>BSIC</strong> и номер кадра, позволяет выровнять тайминг.</li>
  </ul>
  <hr />
  <h2 id="3-lte-4g">3. LTE (4G)</h2>
  <h2 id="YrkS">Каналы и сообщения</h2>
  <p id="bWmS">В LTE системная информация разделена на <strong>MIB</strong> (Master Information Block) и набор <strong>SIB</strong> (System Information Blocks), описанные в <a href="https://www.3glteinfo.com/messages/lte/lte-rrc/" target="_blank">3GPP TS 36.331</a>.</p>
  <h2 id="mib">MIB</h2>
  <p id="9cBk">Передаётся на <strong>PBCH</strong> (Physical Broadcast Channel) с периодичностью 40 мс (с повторениями каждые 10 мс). Содержит самый минимум:</p>
  <ul id="mRpc">
    <li id="XPzT"><strong>DL Bandwidth</strong> соты (в числе Resource Blocks: 1.4 / 3 / 5 / 10 / 15 / 20 МГц)</li>
    <li id="qkIW"><strong>PHICH</strong> конфигурация</li>
    <li id="TSb4"><strong>SFN</strong> (System Frame Number)</li>
  </ul>
  <h2 id="sib1">SIB1</h2>
  <p id="zNrI">Передаётся на DL-SCH с периодичностью 80 мс (с повторениями). Несёт:</p>
  <ul id="S5JF">
    <li id="zkK3"><strong>PLMN identity list</strong> (MCC+MNC, может быть несколько)</li>
    <li id="DWYU"><strong>Tracking Area Code (TAC)</strong></li>
    <li id="sYoX"><strong>Cell Identity</strong> — 28-битный E-UTRAN Cell Identifier (ECI). В макросетях часто раскладывается на eNodeB ID (старшие 20 бит) и локальный/секторный Cell ID (младшие 8 бит), но это не универсальное правило</li>
    <li id="HegO"><strong>Cell bar status</strong> (доступна ли сота)</li>
    <li id="1Pxm"><strong>Cell selection info</strong> (минимальный требуемый уровень приёма, Q-RxLevMin)</li>
    <li id="mnBe"><strong>p-Max</strong> — максимальная разрешённая мощность UE</li>
    <li id="e262"><strong>Frequency band indicator</strong></li>
    <li id="iTlj"><strong>TDD конфигурация</strong> (если TDD)</li>
    <li id="Schg"><strong>SI-window length</strong> и <strong>schedulingInfoList</strong> — расписание остальных SIB</li>
    <li id="14cD"><strong>System info value tag</strong> — версия информации</li>
  </ul>
  <h2 id="sib">Остальные SIB</h2>
  <p id="6Nh1">Передаются в сообщениях SystemInformation (SI) по расписанию из SIB1:</p>
  <p id="V15w"><strong>SIB2</strong></p>
  <p id="kzvV">Общая конфигурация радио: параметры RACH, PRACH, UL-частота, ширина UL-канала</p>
  <p id="HXGN"><strong>SIB3</strong></p>
  <p id="smxn">Параметры reselection внутри той же частоты</p>
  <p id="m5Uu"><strong>SIB4</strong></p>
  <p id="Nc2Q">Информация о соседях intra-frequency</p>
  <p id="VVSn"><strong>SIB5</strong></p>
  <p id="AlF6">Информация о соседях inter-frequency (другие частоты LTE)</p>
  <p id="2s0k"><strong>SIB6</strong></p>
  <p id="pT1W">Информация о соседях 3G (UTRA)</p>
  <p id="32EY"><strong>SIB7</strong></p>
  <p id="MbiJ">Информация о соседях 2G (GERAN)</p>
  <p id="CEze"><strong>SIB8</strong></p>
  <p id="CaL0">Информация о соседях CDMA2000</p>
  <p id="XVyR"><strong>SIB9</strong></p>
  <p id="9De5">Home eNodeB identifier (femtocell)</p>
  <p id="CqlW"><strong>SIB10</strong></p>
  <p id="IPfu">ETWS — первичное уведомление (Earthquake &amp; Tsunami Warning)</p>
  <p id="MJCC"><strong>SIB11</strong></p>
  <p id="7udv">ETWS — вторичное уведомление</p>
  <p id="gsFi"><strong>SIB12</strong></p>
  <p id="WhPS">CMAS — коммерческие предупреждения (Cell Broadcast)</p>
  <p id="JZCV"><strong>SIB13</strong></p>
  <p id="a3oO">MBMS/MBSFN-конфигурация</p>
  <p id="iGBQ"><strong>SIB14</strong></p>
  <p id="AX3y">Extended Access Barring (EAB)</p>
  <p id="bJB2"><strong>SIB15</strong></p>
  <p id="V0tN">MBMS Service Area Info</p>
  <p id="DuMz"><strong>SIB16</strong></p>
  <p id="uNqO">Информация о времени (GPS/UTC)</p>
  <hr />
  <h2 id="4">4. Как это декодируется на практике (концептуальный пайплайн)</h2>
  <pre id="A4JK">textSDR-приёмник (I/Q) → настройка на частоту → синхронизация → демодуляция → L2/L3 декодирование → Wireshark / ASN.1</pre>
  <h2 id="gsm-2g">Инструменты для GSM (2G)</h2>
  <ul id="R95X">
    <li id="5MoA"><strong>gr-gsm</strong> (GNU Radio GSM decoder) — основной инструмент. Компоненты:</li>
    <ul id="ZXLZ">
      <li id="01gM"><code>grgsm_scanner</code> — сканирование эфира, поиск вышек, вывод ARFCN, BSIC, Cell ID</li>
      <li id="xGyf"><code>grgsm_capture</code> — запись сигнала в .cfile</li>
      <li id="NTUX"><code>grgsm_decode</code> — декодирование BCCH, SDCCH и др. → GSMTAP в Wireshark</li>
      <li id="aj9f"><code>grgsm_livemon</code> — интерактивный мониторинг одного канала в реальном времени</li>
    </ul>
    <li id="GIBQ"><strong>Wireshark</strong> — анализ декодированных пакетов с фильтром <code>gsmtap</code></li>
    <li id="jqwn"><strong>DragonOS</strong> — готовый Linux-дистрибутив со всем предустановленным</li>
  </ul>
  <p id="BNT1">(<a href="https://github.com/ptrkrysik/gr-gsm/wiki/Usage:-Decoding-How-To" target="_blank">gr-gsm Wiki: Usage</a>, <a href="https://www.rtl-sdr.com/rtl-sdr-tutorial-analyzing-gsm-with-airprobe-and-wireshark/comment-page-1/" target="_blank">RTL-SDR Tutorial</a>)</p>
  <h2 id="lte-4g">Инструменты для LTE (4G)</h2>
  <ul id="hgFk">
    <li id="gIB0"><strong>srsRAN</strong> (бывший srsLTE) — открытый стек 4G/5G. Утилита <code>cell_search</code> находит соты и получает параметры из MIB; для декодирования SIB нужны специальные receive-only конфигурации/примеры srsRAN, LTE-Cell-Scanner или обёртки вроде lte-sib-parser. <code>srsue</code> в режиме только приёма может парсить SIB2–SIB6.</li>
    <li id="bgOg"><strong>LTE-Cell-Scanner</strong> — OpenCL-ускоренный сканер от JiaoXianjun: от I/Q-сэмплов до SIB-сообщений в ASN.1. Поддерживает FDD и TDD, RTL-SDR/HackRF/BladeRF.</li>
    <li id="jAFF"><strong>lte-sib-parser</strong> — обёртка над cell_search и srsue для рекурсивного сканирования по SIB5.</li>
    <li id="T7cP"><strong>free5GRAN</strong> — для 5G NR (MIB + SIB1).</li>
  </ul>
  <p id="PiUa">(<a href="https://github.com/JiaoXianjun/LTE-Cell-Scanner" target="_blank">LTE-Cell-Scanner на GitHub</a>, <a href="https://docs.srsran.com/projects/4g/en/latest/app_notes/source/nbiot/source/index.html" target="_blank">srsRAN docs</a>, <a href="https://github.com/godfuzz3r/lte-sib-parser" target="_blank">lte-sib-parser</a>)</p>
  <hr />
  <h2 id="5"><strong>Что это даёт на практике</strong></h2>
  <ul id="vOM0">
    <li id="sOp2"><strong>Идентификация оператора и страны</strong> по MCC+MNC.</li>
    <li id="NUfU"><strong>Картирование покрытия</strong> — зная Cell ID + частоту + уровень сигнала, можно составить карту расположения и охвата базовых станций (без доступа к базам операторов). Сторонние проекты вроде <a href="https://opencellid.org" target="_blank">OpenCelliD</a> и <a href="https://cellmapper.net" target="_blank">CellMapper</a> агрегируют именно такие данные.</li>
    <li id="PAqV"><strong>Понимание топологии сети</strong> — какие соты являются соседями, какие частоты используются в зоне, какие поколения (2G/3G/LTE) присутствуют.</li>
    <li id="3Cwh"><strong>Оценка нагрузки</strong> — косвенно, по количеству paging-сообщений (но это уже не чисто broadcast, аpaging-канал, требующий чуть более активного прослушивания CCCH).</li>
    <li id="lcAw"><strong>Проверка конфигурации</strong> — для исследовательских и образовательных целей: какая ширина канала, какие параметры RACH, закрыта ли сота и т.д.</li>
    <li id="tQJB"><strong>Косвенная оценка активности</strong> — по объёму paging-трафика можно грубо судить о нагрузке, но это не системная информация и не позволяет отслеживать конкретных абонентов.</li>
  </ul>
  <hr />
  <h2 id="6---broadcast">6. Чего из broadcast-данных получить нельзя</h2>
  <p id="HGWU">Важно зафиксировать границы:</p>
  <ul id="feIE">
    <li id="GVDG"><strong>GPS-координаты вышки</strong> не передаются в эфир. Координаты можно определить только косвенно — по триангуляции сигнала или по внешним базам данных (OpenCelliD).</li>
    <li id="RBrj"><strong>Содержимое звонков, SMS и интернет-трафика</strong> — не относится к broadcast и может быть зашифровано. В GSM может использоваться A5/0 (без шифрования), A5/1 или A5/3; в LTE — SNOW 3G или AES. Перехват и расшифровка трафика выходят за рамки данной заметки.</li>
    <li id="NgN6"><strong>IMSI абонентов</strong> не передаётся в broadcast/System Information. В 2G/3G/LTE постоянный идентификатор может появляться в отдельных процедурах идентификации до установления защиты, но это не вещательные данные. В 5G для этого используется SUCI.</li>
    <li id="DYr9"><strong>Точная нагрузка/количество абонентов</strong> — broadcast не несёт такой информации. Paging-канал может дать лишь грубую оценку совокупной активности сети и не является средством отслеживания конкретных абонентов.</li>
    <li id="VE1L"><strong>Точное местоположение абонента</strong> — требует данных из ядра сети (core network) или активного слежения за конкретным устройством, что выходит далеко за рамки пассивного декодирования вещательных каналов.</li>
  </ul>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@pole_sam/t8AbMPpD8pM</guid><link>https://teletype.in/@pole_sam/t8AbMPpD8pM?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam</link><comments>https://teletype.in/@pole_sam/t8AbMPpD8pM?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=pole_sam#comments</comments><dc:creator>pole_sam</dc:creator><title>POLQA и с чем его едят</title><pubDate>Sat, 18 Jul 2026 18:53:47 GMT</pubDate><description><![CDATA[<img src="https://img1.teletype.in/files/89/f5/89f55740-20d0-46f0-846c-51831fb28972.png"></img>Привет всем! Сегодня постараюсь рассказать о POLQA.
POLQA расшифровывается как Perceptual Objective Listening Quality Analysis. Это full-reference метод: он сравнивает эталонный речевой сигнал с ухудшенной версией после прохождения через сеть, кодек или устройство, а затем вычисляет оценку, близкую к MOS — Mean Opinion Score. Проще говоря, POLQA пытается математически смоделировать то, как человеческое ухо и восприятие оценивают качество речи.]]></description><content:encoded><![CDATA[
  <p id="gnUR">Привет всем! Сегодня постараюсь рассказать о POLQA.<br />POLQA расшифровывается как <em>Perceptual Objective Listening Quality Analysis</em>. Это full-reference метод: он сравнивает эталонный речевой сигнал с ухудшенной версией после прохождения через сеть, кодек или устройство, а затем вычисляет оценку, близкую к MOS — Mean Opinion Score. Проще говоря, POLQA пытается математически смоделировать то, как человеческое ухо и восприятие оценивают качество речи.</p>
  <h3 id="kHVZ"><br /><strong>Зачем он нужен</strong></h3>
  <p id="dx8b">Главная ценность POLQA в том, что он помогает измерять качество голоса <strong>воспроизводимо и сравнимо</strong> между лабораториями, устройствами и сценариями тестирования. Его используют для бенчмаркинга сетей, проверки кодеков, оптимизации VoIP/VoLTE и диагностики проблем с голосом в канале связи. Это особенно важно, когда качество портят не только потери пакетов, но и джиттер, компенсация задержек, time-scaling, шумоподавление и другие современные механизмы обработки.</p>
  <h3 id="X2PH"><br />Что было раньше</h3>
  <p id="42Kf">До POLQA в инженерной практике использовали разные методы объективной оценки качества речи, включая простые энергетические и шумовые метрики, а также более продвинутые психоакустические модели; однако они либо слабо коррелировали с субъективным восприятием, либо были ограничены узким классом искажений. Затем появился PESQ, который стал важным шагом вперед благодаря моделированию слухового восприятия.</p>
  <h3 id="lk6M">Как возник POLQA</h3>
  <p id="OlFK"><br />POLQA создавался как ответ на эти ограничения, то есть преемник PESQ, с акцентом на более точное моделирование восприятия речи в условиях современных телекоммуникаций. PESQ был спроектирован в первую очередь для <strong>узкополосной телефонной речи</strong> и сравнительно стабильных соединений, а не для современных сетей с переменной задержкой, джиттером и более широким частотным диапазоном. PESQ хорошо решал задачу оценки качества для классических телефонных и кодековых сценариев, но в VoIP и IP-сетях сигнал часто сталкивается с <strong>непостоянной задержкой</strong> и адаптацией jitter buffer, из-за чего точное выравнивание эталонного и тестового сигнала становится сложнее. Кроме того, в новых сетях ухудшения связаны не только с кодированием, но и с пакетными потерями, перепаковкой, временными сдвигами и другими эффектами передачи по IP, которые выходят за рамки более ранней модели применения PESQ</p>
  <h2 id="5it9">История создания</h2>
  <p id="ipev">Работы над POLQA начались в ITU-T Study Group 12 в 2006 году под рабочим названием P.OLQA. В 2009–2010 годах прошёл конкурс кандидатов. Лучшие модели от трёх компаний — <strong>OPTICOM</strong> (Германия), <strong>SwissQual</strong> (Rohde &amp; Schwarz, Швейцария) и <strong>TNO</strong> (Нидерланды) — были объединены в единый алгоритм.</p>
  <ul id="U6QE">
    <li id="l8up">Первая редакция — 2011 год.</li>
    <li id="Owkn">Вторая (исправления и улучшения) — 2014 год.</li>
    <li id="USzp">Третья (POLQA v3 / Edition 3) — 2018 год (актуальная), с поддержкой Full Band и оптимизацией под современные сети.</li>
  </ul>
  <p id="GmJM">POLQA разработан специально для новых реалий: VoIP, HD Voice, 3G/4G/VoLTE, 5G, современных кодеков (EVS, Opus и др.).</p>
  <h3 id="xBAw">Основные характеристики</h3>
  <ul id="WiMx">
    <li id="qXU0"><strong>Тип алгоритма</strong>: Full Reference (FR) — требует и reference-сигнал (чистый), и degraded-сигнал (после прохождения через систему).</li>
    <li id="z7JH"><strong>Диапазоны</strong>:</li>
    <ul id="4JQ2">
      <li id="pWdB">Narrowband (NB): 300–3400 Гц (классическая телефония).</li>
      <li id="sbBY">Super-Wideband (SWB): до 14 кГц (HD Voice).</li>
      <li id="ckrD">Full Band (FB, с v3): до 20–24 кГц (48 кГц сэмплирование).</li>
    </ul>
    <li id="N7UG"><strong>Выход</strong>: MOS-LQO (Listening Quality Objective) от 1 (плохо) до 5 (отлично). Также дополнительные индикаторы.</li>
  </ul>
  <h3 id="JvLU">Как работает POLQA (высокоуровнево)</h3>
  <p id="Am7n">Алгоритм состоит из двух основных частей:</p>
  <ol id="ONsb">
    <li id="pe4n"><strong>Temporal Alignment (временное выравнивание)</strong>:</li>
    <ul id="Rucq">
      <li id="0FKJ">Решает сложные проблемы VoIP: внезапные скачки задержки (shift-jitter), постепенное time-scaling (растяжение/сжатие речи), packet loss и т.д.</li>
      <li id="nkpI">Использует macro frame, корреляцию, backtracking (аналог Viterbi алгоритма), обработку pitch-preserving техник (типа PSOLA).</li>
      <li id="OU2F">Оценивает sample rate differences и компенсирует их.</li>
    </ul>
    <li id="bNnX"><strong>Perceptual Model (психоакустическая модель)</strong>:</li>
    <ul id="clVW">
      <li id="T2VU">Моделирует человеческое слуховое восприятие: преобразование в Bark-scale (критические полосы), loudness (Sone), masking effects (частотное и временное).</li>
      <li id="s8my"><strong>Idealization</strong>: &quot;идеализирует&quot; reference-сигнал (убирает мелкие шумы, корректирует timbre/level), чтобы имитировать Absolute Category Rating (ACR) тесты, где слушатели оценивают без прямого сравнения.</li>
      <li id="v0Uq">Вычисляет disturbance density (плотность искажений) отдельно для additive и subtractive distortion, с учётом сильных и слабых эффектов.</li>
      <li id="SrRI">Cognitive model преобразует perceptibility в annoyance (раздражаемость), учитывая level variations, reverberation, noise и т.д.</li>
      <li id="leSV">Финальный mapping в MOS-LQO с полиномиальной коррекцией.</li>
    </ul>
  </ol>

]]></content:encoded></item></channel></rss>