Jump to content

    

Помогите правильно обработать байт-стаффинг

Коллеги, лет 20 назад делал подобную штуку,проблем не было, а сейчас что-то запутался,старею. Внешнее покупное изделие регулярно раз в секунду шлёт мне сообщения. В каждом сообщении может быть несколько блоков данных. В начале каждого блока стоит макер начала - байт 0х10, в конце маркер окончания, два байта 0х10 и 0х03. Если в отправляемом блоке данных попадается код 0х10 то он передаётся два раза. Я в принятом сообщении ищу маркеры начала и конца блока,блок копирую в промежуточный массив для разбора, а при копировании ищу два подряд стоящих 0х10 и один из них пропускаю. И так с каждым блоком. Работает, но примерно каждое десятое сообщение получаю битым. Подозреваю что иногда происходит неправильное определение начала и конца блока. Ведь если внутри блока попадётся пара 0х10 и 0х03 маркер конца будет определён неверно. На что следует обратить внимание?

Share this post


Link to post
Share on other sites
1 hour ago, _sda said:

Ведь если внутри блока попадётся пара 0х10 и 0х03 маркер конца будет определён неверно. На что следует обратить внимание?

Внутри сообщения границы между блоками будут отмечены тройками:  0х10, 0х03 и 0x10..

Edited by blackfin
Опечатка..

Share this post


Link to post
Share on other sites

Вах, шайтан! Точно, только тройка будет 0х10, 0х03 и 0x10

Спасибо! Сейчас проверю.

p.s. А если в внутри блока будет такая тройка? У меня там время передаётся - 16 часов, 3 минуты 16 секунд. Кирдык.

Похоже нужно как то хитрее...

Походу нужно проверять не три байта а пять...

13 10 03 10 5C

Но Вы меня натолкнули на эту мысль, спасибо!

p.p.s. тогда как быть с последним блоком? Опять засада...

Share this post


Link to post
Share on other sites
26 minutes ago, _sda said:

А если в внутри блока будет такая тройка?

Эту ошибку не обойти никак. Можно только уменьшить вероятность её появления.

После вставки байта 0x10 комбинация 0x10, 0x03, 0x10 превратится в 0x10, 0x10, 0x03, 0x10, 0x10, что соответствует границе между блоками.

Можно, конечно, запретить такую комбинацию из пяти байт в качестве маркера конца блока, но тогда есть вероятность потерять границу блока который заканчивается на 0x10, в том случае, если следующий блок начинается с 0x10. В этом случае возникает комбинация из шести байт: 0x10, 0x10, 0x10, 0x03, 0x10, 0x10 которая как раз и соответствует маркеру окончания блока.

Share this post


Link to post
Share on other sites
11 минут назад, blackfin сказал:

Можно, конечно, запретить такую комбинацию из пяти байт в качестве маркера конца блока, но тогда есть вероятность потерять границу блока который заканчивается на 0x10, в том случае, если следующий блок начинается с 0x10. В этом случае возникает комбинация: 0x10, 0x10, 0x10, 0x03, 0x10, 0x10 которая как раз и соответствует маркеру окончания блока.

Согласен, увеличивая длину цепочки уменьшаем вероятность ложного обнаружения маркера.

11 минут назад, blackfin сказал:

Эту ошибку не обойти никак. Можно только уменьшить вероятность её появления.

А мне сейчас показалось что можно. Что если за критерий конца взять цепочку 0x10, 0x10, 0x10, 0x03 или 0x10, 0x03 с нечётным количеством байт 0х10 перед байтом 0х03? Что скажете?

Share this post


Link to post
Share on other sites
31 minutes ago, _sda said:

Что если за критерий конца взять цепочку 0x10, 0x10, 0x10, 0x03 или 0x10, 0x03 с нечётным количеством байт 0х10 перед байтом 0х03? Что скажете?

Похоже, что это правильное решение.. ;)

 

Share this post


Link to post
Share on other sites
3 минуты назад, blackfin сказал:

Похоже, что это правильное решение.. ;)

Какой я молодец:dirol:

Тогда и после 0х03 ничего проверять не нужно, последний блок нормально проверится.

Спасибо за диалог!

Share this post


Link to post
Share on other sites

Ага... Прямо по теме стаффинга: "Одна голова - хорошо, а две головы - хорошо-хорошо." ;)

Share this post


Link to post
Share on other sites
3 часа назад, _sda сказал:

В начале каждого блока стоит макер начала - байт 0х10, в конце маркер окончания, два байта 0х10 и 0х03. Если в отправляемом блоке данных попадается код 0х10 то он передаётся два раза.

Какой-то странный и излишне сложный метод... А если в начале кадра данных будет идти 0x03? Тогда после кодирования это начало будет выглядеть как конец кадра.

Мне известно 3 основных способа кодонезависимого кодирования:

 

1. А-ля SLIP.

Выбираем два спец.значения символа == X и == Y. Где X - будет маркер конца, Y - код для экранирования спец.значений встретившихся в блоке данных. При кодировании кадр обрамляется в начале и в конце значением X, а если внутри блока данных встретится значение X или Y, то оно заменяется на пару Y,X1 или на пару Y,Y1 соответственно (где X1, Y1 - любые выбранные значения не равные X и не равные Y).

Если необходимо, то таким методом можно добавить бОльшее число спец.значений символов для целей управления в канале (например - для управления потоком). Все эти значения должны экранироваться символом Y.

Плюсы: Простота (проще других методов); лёгкая возможность добавления дополнительных спец.значений.

Минусы: Большая потенциальная избыточность в некоторых случаях.

 

2. Байт-стаффинг по типу бит-стаффинга.

Начало и конец кадра в канале маркируется последовательностью из N символов со значением == X. Если внутри блока данных встретится (N-1) символов со значением == X, то после них вставляется любое значение != X. В конце кадра (перед хвостовыми N символами X) также всегда вставляется любое значение != X (хотя другой способ: делать это только если при кодировании текущий счётчик символов X не равен 0).

Плюсы: В случае больших кадров данных, избыточность будет минимальной из всех методов.

Минусы: В случае маленьких кадров плюс превратится в минус.

 

3. COBS. https://ru.wikipedia.org/wiki/Вставка_байтов_с_фиксированной_избыточностью

COBS мне нравится больше всех. И если я не ограничен в выборе, то использую обычно его.

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

Минусы: Сложнее других методов.

 

Есть конечно еще всякие неоптимальные методы, типа представления в виде ASCII значений (MIME, UUENCODE и т.п.). Их не рассматриваю.

 

Любой из этих методов - кодонезависим. А значит включившись в любой момент в любую точку потока кодированных данных можно правильно выделить кадр данных из потока символов вне зависимости от его содержимого.

1 час назад, _sda сказал:

Что если за критерий конца взять цепочку 0x10, 0x10, 0x10, 0x03 или 0x10, 0x03 с нечётным количеством байт 0х10 перед байтом 0х03? Что скажете?

Так всё-таки Вы создаёте что-то своё и нет необходимости в совместимости с готовым устройством, работающим в конкретном кодировании?

Тогда я бы посоветовал использовать один из 3-х методов, что я описал выше. Они проще и предсказуемее.

Share this post


Link to post
Share on other sites

1).Я в топе сказал что принимаю данные из покупного изделия. Что имеем то имеем...

2).Протокол организован так, что первым байтом 0х03 никогда не будет.

Share this post


Link to post
Share on other sites
11 минут назад, _sda сказал:

1).Я в топе сказал что принимаю данные из покупного изделия. Что имеем то имеем...

Понятно. Всё равно - кривоватый метод. Он даже не кодонезависимый. Ибо - включившись в любой произвольный момент в поток кодированных данных, невозможно однозначно определить границы кадра и правильно декодировать кадр из потока. Придётся применять дополнительные методы валидации кадра.

Share this post


Link to post
Share on other sites

Да, это оно. Куда я смотрел... Тут английским по белому всё написано про odd...

Столько времени потерял.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now