ВходНаше всё Теги codebook 无线电组件 Поиск Опросы Закон Четверг
21 ноября
976673 Топик полностью
fk0, легенда (06.02.2020 11:16 - 11:22, просмотров: 365) ответил Evgeny_CD на 1) Про дураков ничего не писал 2)Хочется сделать универсального для любого канала шириной 1 байт 3)Спасибо! Столь тонкая оптимизация была оставлена на потом. Именно поэтому идея табличного кодера и декодера - чтобы можно было мапить на любые коды.
Кстати я не прав. В PPP в качестве заголовка кадра используется последовательность 7E FF и не просто так: в бинарном виде это o01111110Po11111111P, где o -- нулевой старт-бит, P -- единичный стоп-бит. Можно показать, что 7E при любых сдвигах вправо-влево (нарушении битовой синхронизации) неизбежно вызывает ошибку, а FF позволяет после ошибочного фрейма синхронизироваться правильно:
Варианты сдвига:

xxxxxxxxxo01111110Po11111111P
xxxxxxxxo01111110Po11111111P  - ошибка в стоп бите у 7F, затем FF без ошибок
         ^

xxxxxxxo01111110Po11111111P
xxxxxxo01111110Po11111111P
xxxxxo01111110Po11111111P
xxxxo01111110Po11111111P
xxxo01111110Po11111111P
xxo01111110Po11111111P  - 7Е и FF принимаются не правильно, следующий байт синхронизируется правильно
                   ^

xo01111110Po11111111P  - ошибка в стоп-бите у 7F, затем FF без ошибок
         ^

o01111110Po11111111P  - 7F FF нет ошибок
Поэтому можно сказать, что комбинация 7E FF в преамбуле восстанавливает синхронизацию. И для синхронного канала (строго говоря, там 7E появится вообще в данных не может, из-за бит-стаффинга), и для асинхронного, как показано выше. Но для асинхронного канала комбинаций восстанавливающих синхронизацию больше. Последовательность вида AA или 55 конечно вообще не подойдёт, это анти-паттерн. Нули плохи -- слишком широкий "старт-бит". А вот FF, где из нулей только очень "узкий" старт-бит подходит как нельзя лучше: собственно там нулевой только старт-бит, так что ошибиться с временем старта невозможно вообще. Честно говоря не понимаю, почему в PPP приняли 7E, видимо для совместимости с HDLC. Если на последнюю плюнуть, то можно принять преамбулой и разделителем пакетов пару байт FF FF. Если синхронизация в предыдущем пакете нарушена, то после приёма первого FF, который будет принят неправильно, следующий байт будет уже правильным. Т.е. при передаче между пакетами вставляется FF FF, а при парсинге достаточно одного FF для распознания пакета. Речь про асинхронные каналы (RS-232, RS-485 и т.п.) Кстати как грязный хак ещё посылка BREAK, но на уровне API современных ОС их сложно смешать с потоком данных. Идею можно развить. Выше я писал, что мол удобно использовать код 0 для разделения записей, для чего диапазон [0, 1) исключается из пространства кодов используемых для кодирования чисел, длин строк и т.п. На самом деле там без разницы какой код. Идея только в том, что если поток данных положить в память, то найти начало следующей записи можно с помощью memchr(3). А какой именно байт искать без разницы. Если нужно искать не 0, а FF, то достаточно проксорить весь поток с FF. Т.е. схема кодирования получается такая: числа отображаются на диапазон в едином пространстве беззнаковых чисел, диапазон зависит от типа числа, и кодируются в LEB 128, строки предваряются тегом длины и копируются как есть, и при этом не используют код с символом 0, в конце записи ставится байт 0, в начале два нуля, затем весь поток инвертируется и отсылается. Почему аж три нуля (FF) между записями -- гарантии, что записи передаются непрерывним потоком нет, между записями/пакетами может быть мусор, поэтому любая запись всегда начинается с FF FF. Есть ещё и другая проблема: преамбула. В том же PPP она достаточно сложная, случайно не возникнет. При работе с RS-485 выбирают сложную (не FF с одним нулевым битом). Затем, чтоб случайная помеха не инициировала приём пакета состоящего целиком из мусора. По крайней мере на это будет тратиться время CPU и возможно батарейка. В описываемом случае (моё предложение по кодированию из другого сообщения) отличить осмысленную преамбулу от других данных -- невозможно. Т.к. может быть только один байт исключённый из использования (изначально 0, но путём ксорки с нужным байтом можно получить любой). В связи с этим предлагается преамбулу не просто добавлять как байты, а кодировать в начало записи/пакета отдельным значением в LEB128. Тогда можно сказать, что всегда после FF должны идти строго такие-то байты, и таким образом отличить поток мусора от данных. И тогда можно не добавлять лишний 0 или FF в начало каждой записи/пакета, т.е. добавлять только один в начале и один в конце. Т.к. начало пакета теперь определяется по преамбуле.
[ZX]