Программирую STM32
на C\C++
, имеется кольцевой буфер входящих данных (не важно, текстовых или бинарных). Естественно известен формат данных, которые поступают, разделители и все прочее. Буфер имеет размер много меньше, чем принимаемый пакет данных, поэтому ловить конец пакета, и только после этого парсить пакет не вариант. Необходим именно динамический парсер данных. На ум приходит следующий вариант: объявляем переменную, которая указывает этап парсинга, и в цикле while оператора switch постепенно переключаемся между этапами парсинга.
uint8_t Stage;
bool PacketProcess;
PacketProcess = false;
while (!PacketProcess)
{
switch (Stage)
{
case 0: // ожидаем появления в буфере команды
if (в буфере есть команда)
{
принимаем команду;
Stage = 1;
}
break;
case 1: // ожидаем появления в буфере разделителя (например запятая)
if (в буфере есть разделитель)
{
считываем разделитель;
Stage = 2;
}
break;
case 2: // ожидаем появления в буфере данных 1
if (в буфере есть данные 1)
{
принимаем данные 1;
Stage = 3;
}
break;
case 3: // ожидаем появления в буфере разделителя (например запятая)
if (в буфере есть разделитель)
{
считываем разделитель;
Stage = 4;
}
case 4: // ожидаем появления в буфере данных 2
if (в буфере есть данные 2)
{
принимаем данные 2;
Stage = 5;
}
break;
case 5: // ожидаем появления в буфере конца пакета
if (в буфере есть конец пакета)
{
считываем конец пакета;
Stage = 0;
PacketProcess = true;
}
break;
}
}
При увеличении команд парсер распухает в геометрической прогрессии.
Вопрос собственно в следующем: как грамотней организовать алгоритм?
Как вариант, парсить подструктуры в пакете, желательно делая их маленькими, и парьсить что пришло, а не ожидать строгий порядок данных. Важно, чтобы буфер был размером с самую большую структуру + запас на входящие данные пока вы парсите. Было бы проще, если бы был указан примерный формат пакета. Я бы делал парсер по такому подобию:
enum structureMarker {part_one, part_two, part_three, etc};
pasePartOne(ptr* begin, ptr* end, dataStructOne& data)
{
// ... some parsing logic
}
while(hasdata())
{
if(isSubDataDelimeter(pDataHead))
{
switch(getMarkerType(pParsedTail+1))
{
case part_one: pasePartOne(pParsedTail+1, pDataHead, fullstruct.one); break;
case part_two: ... /// etc
... /// etc
}
}
}
чтобы избавиться от распухания кода парсера нужно либо делать парсинг самых простых типов объединенных в что-то типа структур с ключами (но это дает оверхед), но зато парсеров будет меньше. Тип подструктуры можно определять по размеру(не очень, но "хитрый финт"), либо по первому байту. Таким образом код парсера будет по-проще.
Может так:
struct element el;
while (1) {
GetElement(&el);
if ( TypOfElement(&el) == END_OF_PKT) break;
if ( TypOfElement(&el) == DELIMITER) continue;
if ( TypOfElement(&el) == DATA) PackData(&el);
}
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Делаю приложение под андроид на JavaScriptПриложение билджу с помощью cordova, но проблема в том, что я использую api одного сервиса и его ключ прописан...