Как бы вы решили эту проблему анализа данных?
-
03-07-2019 - |
Вопрос
Это довольно длинный вопрос, поэтому, пожалуйста, держитесь за меня.
Мы реализуем эмулятор для аппаратного обеспечения, которое разрабатывается в то же время. Идея состоит в том, чтобы дать третьим лицам программное решение для тестирования клиентского программного обеспечения и предоставления оборудования разработчики ориентир для реализации своих прошивок.
Люди, которые написали протокол для оборудования, использовали кастом версия SUN XDR называется INCA_XDR. Это инструмент для сериализации и десериализация сообщений. Он написан на C, и мы хотим избежать нативный код, поэтому мы анализируем данные протокола вручную.
Протокол по своей природе довольно сложный и пакеты данных может иметь много разных структур, но всегда имеет одну и ту же глобальную структуру:
[ГОЛОВА] [ВВЕДЕНИЕ] [ДАННЫЕ] [ХВОСТ]
[HEAD] =
byte sync 0x03
byte length X [MSB] X = length of [HEADER] + [INTRO] + [DATA]
byte length X [LSB] X = length of [HEADER] + [INTRO] + [DATA]
byte check X [MSB] X = crc of [INTRO] [DATA]
byte check X [LSB] X = crc of [INTRO] [DATA]
byte headercheck X X = XOR over [SYNC] [LENGTH] [CHECK]
[INTRO]
byte version 0x03
byte address X X = 0 for point-to-point, 1-254 for specific controller, 255 = broadcast
byte sequence X X = sequence number
byte group X [MSB] X = The category of the message
byte group X [LSB] X = The category of the message
byte type X [MSB] X = The id of the message
byte type X [LSB] X = The id of the message
[DATA] =
The actuall data for the specified message,
this format really differs a lot.
It always starts with a DRCode which is one byte.
It more or less specifies the general structure of
the data, but even within the same structure the data
can mean many different things and have different lenghts.
(I think this is an artifact of the INCA_XDR tool)
[TAIL] =
byte 0x0D
Как видите, много служебных данных, но это потому, что протокол должен работать как с RS232 (точка-многоточка), так и с TCP / IP (p2p).
name size value
drcode 1 1
name 8 contains a name that can be used as a file name (only alphanumeric characters allowed)
timestamp 14 yyyymmddhhmmss contains timestamp of bitmap library
size 4 size of bitmap library to be loaded
options 1 currently no options
Или это может иметь совершенно другую структуру:
name size value
drcode 1 2
lastblock 1 0 - 1 1 indicates last block. Firmware can be stored
blocknumber 2 Indicates block of firmware
blocksize 2 N size of block to load
blockdata N data of block of firmware
Иногда это просто код DRC и никаких дополнительных данных.
В зависимости от группы и поля типа, эмулятор необходимо выполнить определенные действия. Итак, сначала мы посмотрим на те два поля и на основе этого мы знаем, что ожидать от данных и должен разобрать это правильно.
Затем необходимо сгенерировать данные ответа, которые снова много разных структур данных. Некоторые сообщения просто генерируют сообщение ACK или NACK, в то время как другие генерируют реальный ответ с данными.
Мы решили разбить вещи на мелкие кусочки.
Прежде всего, это IDataProcessor.
Классы, реализующие этот интерфейс, несут ответственность для проверки необработанных данных и создания экземпляров класса Message. Они не несут ответственности за связь, им просто передается байт []
Проверка необработанных данных означает проверку заголовка на наличие ошибок контрольной суммы, crc и длины.
Полученное сообщение передается в класс, который реализует IMessageProcessor. Даже если исходные данные считались недействительными, потому что IDataProcessor не имеет Понятие ответных сообщений или чего-либо еще, все, что он делает, проверяет необработанные данные.
Чтобы информировать IMessageProcessor об ошибках, были добавлены некоторые дополнительные свойства к классу сообщений:
bool nakError = false;
bool tailError = false;
bool crcError = false;
bool headerError = false;
bool lengthError = false;
Они не связаны с протоколом и существуют только для IMessageProcessor
IMessageProcessor - это место, где выполняется настоящая работа. Из-за различных групп и типов сообщений я решил используйте F # для реализации интерфейса IMessageProcessor, потому что сопоставление с образцом казалось хорошим способом избежать множества вложенных операторов if / else и caste. (У меня нет опыта работы с F # или даже с другими функциональными языками, кроме LINQ и SQL)
IMessageProcessor анализирует данные и решает, какие методы он должен вызывать на контроллере IHardware. Может показаться излишним иметь IHardwareController, но мы хотим иметь возможность поменять его с другой реализацией и не будет вынужден использовать F # либо. Текущая реализация представляет собой окна WPF, но это может быть окно Cocoa # или просто консоль, например.
IHardwareController также отвечает за управление состоянием, потому что разработчики должны иметь возможность манипулировать аппаратными параметрами и ошибками через пользовательский интерфейс.
Так что, как только IMessageProcessor вызвал правильные методы в IHardwareController, он должен генерировать ответ MEssage. Опять же ... данные в этих ответных сообщениях может иметь много разных структур.
В конце концов IDataFactory используется для преобразования сообщения в необработанные данные протокола готов к отправке в любой класс, отвечающий за общение. (Например, может потребоваться дополнительная инкапсуляция данных)
В этом нет ничего "трудного" о написании этого кода, но все разные Команды и структуры данных требуют много и много
Решение
Я думаю, что F # подходит для представления сообщений в этом домене через различимые объединения; Я воображаю, например.
type Message =
| Message1 of string * DateTime * int * byte //name,timestamp,size,options
| Message2 of bool * short * short * byte[] //last,blocknum,blocksize,data
...
вместе с методами для разбора / разборки сообщений из / в байтовый массив. Как вы говорите, эта работа проста, просто утомительна.
Мне не совсем понятно, как обрабатывать сообщения, но в целом, исходя из вашего описания, кажется, что вы справились с этим. Р>
Меня немного беспокоит ваша «гибкость инструмента» - каковы ваши ограничения? (Например, .Net, должны поддерживаться программистами, которые знают технологии X, Y, Z, должны соответствовать определенным критериям перфоманс ...)
Другие советы
Вот мои 2 цента (предостережение: я не знаю F #): у вас есть точно указанный входной файл, даже с полной грамматикой. Вы хотите сопоставить содержимое файла с действиями. Поэтому я предлагаю вам разобрать файл. F # является функциональным языком, он может соответствовать технике синтаксического анализа, которая называется Разбор рекурсивного спуска . Книга« Эксперт F # » содержит обсуждение анализа рекурсивного спуска.