Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Обработка массивов с неполными пакетами
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Atlantis-
Здравствуйте!
Никак не соображу, как лучше обрабатывать массивы данных с неполным пакетом в конце. Конкретный пример: на ПК приходит массив данных:
пакет1(16 байт), пакет2(32 байта), неполный пакет (от 1 до 15 байт). Каждый пакет содержит байт, указывающий кол-во данных в пакете
Вроде как надо неполный пакет сохранить и потом склеить во время следующей посылки, а обрабатывать несколько полных пакетов, но как это все вычислить, может кто подскажет?
esaulenka
Если это ПК, то никто не мешает сделать буфер не из байтов, а из пакетов (длина каждого - максимально возможная по протоколу).
А дальше выгребать из массива побайтно и перекладывать в этот буфер. По окончании буфера запомнить состояние "работаем с пакетом №3, в нём 5 байт из N", при появлении следующего "массива" продолжить разбор.
Буфер из пакетов, само собой, закольцованный.
CrimsonPig
Цитата(esaulenka @ Oct 19 2015, 16:15) *
Буфер из пакетов, само собой, закольцованный.


А зачем закольцованый ? sm.gif
На самом деле, слишком общий вопрос и и мало данных.. На общий вопрос соответствующий ответ:
- опишите свои пакеты структурой данных (классом) с состоянием (длина, сколько данных в него надо принять до состояния "заполненности" итп)
- организуйте FIFO - очередь пакетов, например, с помощью списка указателей на эти структуры (std::list, например), тогда недопринятый пакет всегда будет в конце списка. Принятые пакеты удаляем с головы.

Кроме этого, возможно реализовать примерно еще 764 других варианта решеня поставленной задачи sm.gif
zltigo
QUOTE (Atlantis- @ Oct 19 2015, 18:02) *
...может кто подскажет?

Может для начала подскажете, а в чем "проблема" ?
megajohn
Цитата(Atlantis- @ Oct 19 2015, 18:02) *
обрабатывать несколько полных пакетов, но как это все вычислить, может кто подскажет?


дык банально

считать ОДИН БАЙТ "длина пакета"
если УСПЕШНО, то считать N-БАЙТ ( где N это длина пакета )
если УСПЕШНО, то передать в обработку, иначе снова считывать ( пока не будет собран весь пакет )
Dog Pawlowa
Цитата(megajohn @ Oct 19 2015, 20:30) *
дык банально


Банально, если протоколом предусмотрено обнаружение начала пакета. Наличие только длины это не обеспечивает.
Так что автор наступил на грабли.
Или временное разделение пакетов, или там STX/ETX и проч.
Надежда, что пакеты засинхронизируются намертво, не работает.
smalcom
вообще контрольная сумма у пакета должна быть. если протоколом не предусмотрено, то это хижина глистов.
Atlantis-
Цитата(megajohn @ Oct 19 2015, 20:30) *
дык банально

считать ОДИН БАЙТ "длина пакета"
если УСПЕШНО, то считать N-БАЙТ ( где N это длина пакета )
если УСПЕШНО, то передать в обработку, иначе снова считывать ( пока не будет собран весь пакет )

так то оно так, но байт "длина пакета" в пакете не первый, поэтому бывает, что в неполном пакете этого байта нет

Цитата(esaulenka @ Oct 19 2015, 18:15) *
Если это ПК, то никто не мешает сделать буфер не из байтов, а из пакетов (длина каждого - максимально возможная по протоколу).
А дальше выгребать из массива побайтно и перекладывать в этот буфер. По окончании буфера запомнить состояние "работаем с пакетом №3, в нём 5 байт из N", при появлении следующего "массива" продолжить разбор.
Буфер из пакетов, само собой, закольцованный.

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

Цитата(zltigo @ Oct 19 2015, 18:44) *
Может для начала подскажете, а в чем "проблема" ?

В точном определении неполного пакета.
toweroff
Вы бы хоть формат пакета привели, а то тут сейчас "разведем тучки ручками"
Atlantis-
Цитата(toweroff @ Oct 20 2015, 10:44) *
Вы бы хоть формат пакета привели, а то тут сейчас "разведем тучки ручками"

[0] счетчик
[1] кол-во данных (16, 32, 48, 64...128)
[2] номера датчиков
[3] данные
...

Если данных нет - приходит три нуля.
smalcom
добавьте контрольную сумму и проблема отпадёт
Dog Pawlowa
Цитата(Atlantis- @ Oct 20 2015, 10:50) *
[0] счетчик
...

Сами то как предполагаете достичь пакетной синхронизации?
Вот включился контроллер, или компьютер, и начал принимать с десятого байта в пакете, и дальше что?

Вот немцы правы - у них принципы передачи данных стандартизованы, время тратится на суть проекта, а не на познание банальных протоколов передачи данных.
Atlantis-
Цитата(Dog Pawlowa @ Oct 20 2015, 12:41) *
Сами то как предполагаете достичь пакетной синхронизации?
Вот включился контроллер, или компьютер, и начал принимать с десятого байта в пакете, и дальше что?

Вот немцы правы - у них принципы передачи данных стандартизованы, время тратится на суть проекта, а не на познание банальных протоколов передачи данных.

У меня никогда такого не было, чтобы не с первого принимал... А каким образом можно засинхронизироваться? И о каких принципах речь?
Dog Pawlowa
Цитата(Atlantis- @ Oct 20 2015, 13:31) *
А каким образом можно засинхронизироваться? И о каких принципах речь?

Ну самый примитивный стандартный протокол STX текст ETX checksum тайм-аут
Переводите свои данные в текст, обрамляете служебными символами STX/ETX и добавляете контрольную сумму.
Приемник знает, как однозначно найти начало и конец пакета.
Даже если начал принимать с середины, сможет отбросить мусор.
mcheb
Цитата(Atlantis- @ Oct 20 2015, 13:31) *
У меня никогда такого не было, чтобы не с первого принимал... А каким образом можно засинхронизироваться? И о каких принципах речь?

http://electronix.ru/forum/index.php?showtopic=130550
Форум надо читать, а не только писать
Atlantis-
Цитата(mcheb @ Oct 20 2015, 13:48) *
http://electronix.ru/forum/index.php?showtopic=130550
Форум надо читать, а не только писать

Спасибо за ссылку. Но меня пока другой вопрос беспокоит...
Переделал пакеты так, что в нулевом байте теперь общее кол-во данных.
Сделал по принципу
Цитата
считать ОДИН БАЙТ "длина пакета"
если УСПЕШНО, то считать N-БАЙТ ( где N это длина пакета )
если УСПЕШНО, то передать в обработку, иначе снова считывать ( пока не будет собран весь пакет )


на самом деле сделал еще один массив. если в нем остается неполный буфер, то переписываю его в начало этого массива, а потом копирую туда же приемный буфер. вроде бы должно работать...и работает, но сбивается через разное время...беда
toweroff
Вот так попробуйте

[STX][LEN][DATA][CRC]

STX - какой-то байт, например FA
его и парсим из буфера, пока не наткнемся
потом читаем [LEN] и вычитываем длину данных [DATA]
вычитываем [CRC] и сравниваем с рассчитанной

откуда считать CRC - тут уж как Вам угодно. Или всего пакета, или только [DATA]
как считать CRC - тут тоже все зависит от размера пакета. От простого XOR до CRC32
CrimsonPig
Цитата(Atlantis- @ Oct 20 2015, 15:59) *
на самом деле сделал еще один массив. если в нем остается неполный буфер, то переписываю его в начало этого массива, а потом копирую туда же приемный буфер. вроде бы должно работать...и работает, но сбивается через разное время...беда


кстати, есть такое понятие, как flow control. Что вы будете делать, когда отправляющая сторона шлет данные слегка быстрее, чем принимающая сторона их обрабатывает ?
smalcom
Цитата
так, что в нулевом байте теперь общее кол-во данных.

возникла помеха, пришёл 0xFE. Каковы действия вашей программы? ))))
А также как она потом снова синхронизируется на начало пакета?
CrimsonPig
Цитата(toweroff @ Oct 20 2015, 16:26) *
[STX][LEN][DATA][CRC]

STX - какой-то байт, например FA
его и парсим из буфера, пока не наткнемся
потом читаем [LEN] и вычитываем длину данных [DATA]
вычитываем [CRC] и сравниваем с рассчитанной

откуда считать CRC - тут уж как Вам угодно. Или всего пакета, или только [DATA]
как считать CRC - тут тоже все зависит от размера пакета. От простого XOR до CRC32


Очень хорошо. Только вот при удачном сбое можно потерять синхронизацию _навсегда_ sm.gif
Пример: начали принимать с середины пакета, до первого байта [STX], который оказался частью случайных данных. Теперь читаем [LEN] байт, [LEN] при этом мусор, потому что тоже часть данных, а не заголовка пакета. [CRC] низачто не совпадает. И по кругу теперь до скончания времен.
Не даром люди напридумывали всяких дурацких протоколов с байтстаффиггом и прочими неинтересными вещами, правда ?

smalcom
Цитата
Теперь читаем [LEN] байт

интересно, а кто это так делает? Обыно процедура следующая.
Читаем заголовок, читаем длину, подбиваем контрольную сумму. Не совпало - вернулись на следующий байт после бывшего заголовка и повторяем процедурку.

Цитата
байтстаффиггом

придуман для других целей, связанных с аппаратурой.
Atlantis-
У меня сложная система, 8 микроконтроллеров (1) считывают данные с датчиков, передают их на другой МК (2), тот передает на USB МК (3) и дальше, по изохронному каналу, в ПК. Раз уж пошел такой разговор, какой протокол лучше сделать? В настоящий момент у меня контрольная сумма считается после приема данных от датчиков (1-й МК), там же, кстати, добавляется начало пакета и конец пакета. 2-й МК может отправить данные 3-му от 1, 2, 3, 4 датчиков или может ничего не отправить, если данных нет (частота опроса МК-в номер 1 в два раза меньше). 2-й МК сейчас отправляет посылку, вид которой я привел ранее.
smalcom
Цитата
какой протокол лучше сделать

если ничего сверхъестественного не нада, то простейший формат уже приведён выше

[STX][LEN][DATA][CRC]

следует учитывать, что CRC8 эффективен при длине пакета где-то до 30-40 байт. При больших размерах нужен CRC16.
Alexashka
Цитата(smalcom @ Oct 20 2015, 20:51) *
Обыно процедура следующая.
Читаем заголовок, читаем длину, подбиваем контрольную сумму. Не совпало - вернулись на следующий байт после бывшего заголовка и повторяем процедурку.

Я реализовал немного иначе, структура пакета следующая: SYNCHRO, ADRESS, LENTH, CRC_ZAG, DATA, CRC_DAT. В начале заголовка синхрослово (2 байта) по которому начинаю принимать пакет, потом идет адрес и длина блока данных (LENGTH), всё это завершается CRC_ZAG, которая подтверждает что заголовок и длина (LENGTH) в порядке. Далее принимаем указанную длину данных и завершаем процедуру проверкой второй CRC_DAT.
Скажу, что этот протокол с минимальными правками четко работает даже в сильно зашумленном канале радио.

Если в начале приема пропустили заголовок пакета и в данных оказалась пара байт совпадающая с SYNCHRO, ошибка будет обнаружена всего лишь через 3 следующих байта -когда будет принят CRC_ZAG (CRC8). Если контр.сумма не совпала просто продолжаем искать во входящем потоке SYNCHRO. Так что синхронизация быстро восстанавливается.
Atlantis-
Цитата(smalcom @ Oct 20 2015, 20:07) *
если ничего сверхъестественного не нада, то простейший формат уже приведён выше

[STX][LEN][DATA][CRC]

следует учитывать, что CRC8 эффективен при длине пакета где-то до 30-40 байт. При больших размерах нужен CRC16.

А что если размер пакета всегда один и тот же. Можно выкинуть [LEN] ? И ничего страшного, если [STX] будет не одно число, а ряд чисел?
У меня 8 датчиков и я хотел бы на месте [STX] писать номер датчика (1,2,...7,8). А количество данных от датчика у меня всегда одинаковое.
Dog Pawlowa
Цитата(Atlantis- @ Nov 11 2015, 10:21) *
А что если размер пакета всегда один и тот же. Можно выкинуть [LEN] ? И ничего страшного, если [STX] будет не одно число, а ряд чисел?
У меня 8 датчиков и я хотел бы на месте [STX] писать номер датчика (1,2,...7,8). А количество данных от датчика у меня всегда одинаковое.

Какое-то дежавю.
STX и ETX(который уже почему-то выкинули) - коды ASCII, не входящие в текст (цифры и буквы).
Соответственно данные должны быть текстом.
Тогда протокол легко и просто обеспечивает выделение пакета, а с помощью контрольной суммы - его правильность.

Выкинуть можно все, просто нужно определить альтернативные правила для выделения пакета. Скажем, тайм-аут.
Или маркеры начала-конца с байт-стаффингом.

Но опять наблюдается потеря логики.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.