[C++, Анализ и проектирование систем, ООП, Программирование, Программирование микроконтроллеров] Micro Property — минималистичный сериализатор двоичных данных для embedded систем
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Micro Property — библиотека для сериализации данных с минимальными накладными расходами. Она разработана для использования в микроконтроллерах и различных встраиваемых устройствах с ограничениями по размеру памяти, которым приходится работать по низкоскоростным линиям связи.
Конечно, я знаю про такие форматы как xml, json, bson, yaml, protobuf, Thrift, ASN.1. Даже нашел экзотический Tree, который сам является убийцей JSON, XML, YAML и иже с ними.
Так почему же они все не подошли? Зачем я был вынужден написать еще один сериализатор?
Исходные требования
Прежде чем начинать расхваливать собственное творение (а как же без этого? ;-), следует начать с того, для каких целей вообще потребовался сериализатор данных.
Представим, что требуется доработать распределенную систему, состоящую из нескольких сотен устройств разных типов (более десяти типов устройств, выполняющих разные функции). Они объединены в группы, которые обмениваются между собой данными по последовательным линиям связи по протоколу Modbus RTU.
Также, часть этих устройств подключены к общей линии связи CAN, которая и обеспечивает передачу данных в рамках всей системы в целом. Скорость передачи данных по линии связи Modbus до 115200 Бод, а скорость по шине CAN ограничена скоростью до 50кБод из-за её протяженности и присутствия серьезных индустриальных помех.
Устройства в подавляющем большинстве разработаны на микроконтроллерах серий STM32F1x и STM32F2x. Хотя часть из них работает и на STM32F4x. Ну и конечно, Windows/Linux на базе системы с x86 микропроцессорами в качестве контроллеров верхнего уровня.
Для оценки объема данных, которые обрабатываются и передаются между устройствами или хранятся в качестве настроек/параметров работы: В одном случае — 2 числа по 1 байт и 6 чисел по 4 байта, в другом — 11 чисел по 1 байту и 1 число 4 байта и т.д. Для справки, размер данных в стандартном кадре CAN — до 8 байт, а во фрейме Modbus, до 252 байт полезных данных.
Если вы еще не прониклись глубиной кроличьей норы, добавьте к этим вводным данным: необходимость вести учет версий протокола и версий прошивок для разных типов устройств, а так же наличие требования к сохранению совместимости не только с существующими на текущий момент форматами данных, но и обеспечение совместной работы устройств с будущими поколения, которые тоже не стоят на месте и постоянно развиваются и перерабатываются по мере развития функционала и нахождения косяков в реализациях. Плюс, взаимодействие с внешними системами, расширение требований и т.д.
Первоначально, из-за ограниченности ресурсов и низких скоростей линий связи для обмена данными использовался бинарный формат который был привязанный только к регистрам Modbus. Но такая реализация не прошла первую же проверку на совместимость и расширяемость.
Поэтому, при переработке архитектуры пришлось отказаться от использования стандартных Modbus регистров. И даже не из-за того, что кроме этого протокола используются и другие линии связи, а сколько из-за чрезмерной ограниченности организации структур данных, основанных на 16-битных регистрах.
Ведь в будущем, при неизбежной эволюции системы, может потребоваться, (а по факту, уже потребовалось), передавать текстовые строки или массивы. В теории, их тоже можно отображать на карту Modbus регистров, но это получается масло масляное, т.к. выходит абстракция над абстракцией.
Конечно, можно передавать данные как двоичный блоб с привязкой к версии протокола и типу блока. И хотя на первый взгляд такая идея может показалось здравой, ведь фиксируя определенные требования к архитектуре, можно раз и навсегда определить форматы данных, чем существенно сэкономить на накладных расходах, которые будут неизбежны при использовании таких форматов, как XML или JSON.
Чтобы было удобнее сравнивать варинаты, для себя я составил такую табличку:
SPL
Передача двоичных данных без идентификации полей:
Плюсы:
- Минимальные накладные расходы. В идеале их вообще быть не должно, но в реальности требуется указывать в каждом фрагменте версию протокола и тип передаваемых данных.
Минусы:
- Требуется контролировать однозначную идентификацию блоков данных на более высоком уровне, в том числе и вручную организационными методами.
- Необходимо анализировать и управлять версионностью данных. В противном случае, рано или обязательно получим несовместимость бинарных форматов.
- Сложности с идентификацией одинаковых данных в разных бинарных пакетах. Например, дата и время в одном пакете передается в его начале, а во втором пакете в середине данных. И идентифицировать эти данные будет невозможно, если не знать формат каждого.
- Сложности с передачей бинарных данные переменной длинны, в том числе текстовых строк.
Передача двоичных данных с идентификацией полей:
Минусы:
- Неизбежные накладные расходы для передачи имени и типа данных для каждого поля.
Плюсы:
- Не требуется управлять версионностью на уровне бинарных данных. А в случае возникновения такой необходимости, номер версии можно передавать как одно и полей данных пакета.
- Возможность сквозной идентификации данных в любом сообщении, что обеспечивает совместимость как в настоящий момент, так и в отдаленной перспективе.
И только представишь себе, как несколько сотен устройств начинают обмениваться между собой двоичными данными, пусть даже с привязкой каждого сообщения к версии протокола и/или типу устройства, то необходимость использование сериализатора с именованными полями сразу становится очевидной. Ведь даже простая интерполяция сложности поддержки подобного решения в целом, пусть и через совсем непродолжительное время, вынуждает схватится за голову.
И это, даже не принимая в расчет ожидаемые хотелки заказчика по наращиванию функционала, наличия обязательных косяков в реализации и «мелкие», на первый взгляд, доработки, которые обязательно привнесут с собой особую пикантность поиска периодически возникающих косяков в слаженной работе подобного зоопарка …
А какие есть варианты?
После подобных рассуждений невольно приходишь к выводу, что требуется с самого начала закладывать универсальную идентификацию бинарных данных, в том числе и при обмене пакетами по низкоскоросным линиям связи.
И вот когда я пришел к выводу, что без сериализатора не обойтись, то сперва посмотрел на существующие решения, которые уже зарекомендовали себя с самой лучшей стороны, и которые уже используются во множестве проектов.
Основные форматы xml, json, yaml и другие текстовые варианты с очень удобным и простым формальным синтаксисом, который хорошо подходит для обработки документов и одновременно удобен для чтения и редактирования человеком, пришлось сразу отбросить. И как раз из-за своего удобства и простоты они имеют очень большие накладные расходы при хранении бинарных данных, которые как раз и требовалось обрабатывать.
Поэтому, в виду ограниченности ресурсов и низкоскоростных линий связи, было решено использовать бинарный формат представления данных. Но и в случае форматов, умеющих преобразовывать данные в бинарное представление, таких как Protocol Buffers, Flat Buffers, ASN.1 или Apache Thrift, накладные расходы при сериализации данных, а так же общее удобство их применения не способствовало к немедленному внедрению любой из подобных библиотек.
Лучше всего по совокупности параметров подходил формат BSON, который имеет минимальный оверхед. И я серьезно рассматривал возможность его применения. Но в результате, все же решил отказаться и от него, т. к. при прочих равных условиях даже у BSON будут неприемлемые накладные расходы.
Кому-то может показаться странным, что приходится беспокоиться о десятке лишних байт, но к сожалению, этот десяток байт должен будет передаваться каждый раз при отправке сообщения. А в случае работы по низкоскоростным линиям связи, даже лишний десяток байт в каждой посылке имеют значение.
Другими словами, когда оперируешь десятком байт, начинаешь считать каждый из них. А ведь в сеть вместе с данными еще передаются адреса устройств, контрольные суммы пакетов и другая информация, специфичная для каждой линии связи и протокола.
Что получилось
В результате раздумий и нескольких экспериментов получился сериализатор со следующими особенностями и характеристиками:
- Оверхед для данных фиксированного размера — 1 байт (без учета длинны имени поля данных). Так как использовать данный формат предполагается в устройствах, работающих по протоколам CAN и Modbus, то для хранения размера можно ограничиться одним байтом.
- Оверхед для данных переменного размера, таких как блоб, текстовая строка или массив — 2 байта. (так же без учета длинны имени поля данных).
- Ограничения на размер имени поля — 16 байт.
- В качестве идентификатора поля используется текстовая строка с завершающим нулевым символом, которая обрабатывается как бинарные данные, т.е. без учета завершающего нуля. Вместо текстовой строки в качестве идентификаторов полей, можно использовать целые числа или произвольные бинарные данные, размером до 16 байт.
- Максимальный размер полей данных переменной длинны (блоб, текстовая строка или массив) — 252 байта (т.к. размеры полей хранятся в одном байте).
- Общий размер сериализованных данных — без ограничений.
- При работе память не выделяется. Все действия происходят только с внешним буфером без внутреннего выделения и освобождения памяти.
- Возможен режим работы «только чтение», например для работы с настройками приложения, которые сохранены в программной памяти микроконтроллера. В том числе, корректно отрабатывается ситуация, когда данные размещены в очищенной флеш-памяти (заполненной 0xFF).
- В режиме редактирования поддерживается только добавление новых данных до заполнения буфера. Возможность обновления полей штатным способом не реализована, потому что для изначальных задач подобный функционал не требовался. Хотя при необходимости есть возможность редактировать данные по указателю в буфере.
- Ну а в случае крайней необходимости, можно будет попробовать добавить возможность обновления полей. Для этого даже оставлен в резерве один из типов.
Поддерживаемые типы данных:
- Целые числа размером от 8 до 64 бит с преобразованием в сетевой порядок байт и обратно.
- Логические значения и числа с плавающей запятой одинарной и двойной точности.
- Двоичные данные переменной длинны (блоб или массив байт).
- Текстовые строки — двоичные данные с завершающим нулевым символом в конце. При сериализации строк после данных записывается нулевой символ, чтобы потом было удобно с ними работать как с обычными строками, без необходимости копировать данные в промежуточный буфер или высчитывать количество символов в строке. Хотя есть возможность выстрелить себе в ногу и сохранить текстовую строку с нулевым символом в где нибудь в середине строки ;-)
- Одномерные массивы для всех типов целых и вещественных чисел. При работе с массивами целых чисел, они автоматически преобразуются в сетевой порядок байт и обратно.
Хотелось бы отметить отдельно
Реализация сделана на С++ x11 в единственном заголовочном файле с использованием механизма шаблонов SFINAE (Substitution failure is not an error).
Поддерживается корректное чтение данных в буфер (переменную) бОльшего размера, чем сохраненный тип данных. Например, целое число 8 бит можно прочитать в переменную от 8 до 64 бит. Подумываю, может быть стоит добавить упаковку целых чисел, размер которых превышает 8 бит, на предмет возможности их передачи числом меньшего размера.
Сериализованные массивы можно читать как копированием в указанную область памяти, так и получением обычной ссылки на данные в исходном буфере, если хочется избежать копирования, в тех случаях, когда оно не требуется. Но данной возможностью следует пользоваться с осторожностью, т. к. данные сохраняются в сетевом порядке, который может отличаться между машинами.
Сериализация структур или более сложных объектов даже не планировалась. Структуры вообще опасно передавать в бинарном виде из-за возможного выравнивания её полей. Но если эта проблема все же решается относительно простым способом, то все равно будет проблема конвертации в сетевой порядок байт и обратно всех полей объектов, содержащих целые числа.
Тем более, в случае крайней необходимости, структуры всегда можно сохранять и восстанавливать как массив байт. Естественно, в этом случае конвертация целых чисел необходимо будет выполнять вручную.
Реализация
Реализация находится тут: https://github.com/rsashka/microprop
Как пользоваться, написано в примерах с различной степенью подробности:
Быстрое использование
SPL
#include "microprop.h"
Microprop prop(buffer, sizeof (buffer));// Создать сериализатор и назначить ему буфер
prop.FieldExist(string || integer); // Проверить наличие поля с указанным ID
prop.FieldType(string || integer); // Получить тип данных поля
prop.Append(string || integer, value); // Добавить данные
prop.Read(string || integer, value); // Прочитать данные
Медленное и вдумчивое использование
SPL
#include "microprop.h"
Microprop prop(buffer, sizeof (buffer)); // Создать сериализатор
prop.AssignBuffer(buffer, sizeof (buffer)); // Назначить буфер
prop.AssignBuffer((const)buffer, sizeof (buffer)); // Назначить read only буфер
prop.AssignBuffer(buffer, sizeof (buffer), true); // Тоже read only буфер
prop.FieldNext(ptr); // Получить указатель на следующее поле
prop.FieldName(string || integer, size_t *length = nullptr); // Указатель на ID поля
prop.FieldDataSize(string || integer); // Размер сериализованных данных
// Дальше все прозрачно
prop.Append(string || blob || integer, value || array);
prop.Read(string || blob || integer, value || array);
prop.Append(string || blob || integer, uint8_t *, size_t);
prop.Read(string || blob || integer, uint8_t *, size_t);
prop.AppendAsString(string || blob || integer, string);
const char * ReadAsString(string || blob || integer);
Пример реализации с использованием enum в качестве идентификатора данных
SPL
class Property : public Microprop {
public:
enum ID {
ID1, ID2, ID3
};
template <typename ... Types>
inline const uint8_t * FieldExist(ID id, Types ... arg) {
return Microprop::FieldExist((uint8_t) id, arg...);
}
template <typename ... Types>
inline size_t Append(ID id, Types ... arg) {
return Microprop::Append((uint8_t) id, arg...);
}
template <typename T>
inline size_t Read(ID id, T & val) {
return Microprop::Read((uint8_t) id, val);
}
inline size_t Read(ID id, uint8_t *data, size_t size) {
return Microprop::Read((uint8_t) id, data, size);
}
template <typename ... Types>
inline size_t AppendAsString(ID id, Types ... arg) {
return Microprop::AppendAsString((uint8_t) id, arg...);
}
template <typename ... Types>
inline const char * ReadAsString(ID id, Types... arg) {
return Microprop::ReadAsString((uint8_t) id, arg...);
}
};
Код выложен под лицензией MIT, так что пользуйтесь на здоровье.
Буду рад любому фидбеку, в том числе и замечаниям и/или предложениям.
===========
Источник:
habr.com
===========
Похожие новости:
- [C++] C++ enum <-> string? Легко
- [Программирование, Фриланс] Какой язык программирования выбрать
- [JavaScript, Node.JS, Программирование, Разработка веб-сайтов] Руководство по Express.js. Часть 3 (перевод)
- [Java, Программирование] Что нового в Java 15? (перевод)
- [.NET, C#, ООП, Программирование] Творческое использование методов расширения в C# (перевод)
- [Программирование, Управление персоналом] Полюбите программиста
- [JavaScript, ReactJS, Программирование] Почему я разочаровался в хуках (перевод)
- [Анализ и проектирование систем, Работа с 3D-графикой] Ежегодная конференция Bentley Systems для профессионалов в области инфраструктуры запускается в цифровом формате
- [Python, Программирование] Напишем и поймем Decision Tree на Python с нуля! Часть 2. Основы Python, необходимые для генерации Decision Tree (перевод)
- [C++, Программирование] Антипаттерн “константа размера массива” (перевод)
Теги для поиска: #_c++, #_analiz_i_proektirovanie_sistem (Анализ и проектирование систем), #_oop (ООП), #_programmirovanie (Программирование), #_programmirovanie_mikrokontrollerov (Программирование микроконтроллеров), #_open_source, #_open_source_software, #_mikrokontrollery (микроконтроллеры), #_serializatsija (сериализация), #_biblioteka_s++ (библиотека с++), #_c++, #_analiz_i_proektirovanie_sistem (
Анализ и проектирование систем
), #_oop (
ООП
), #_programmirovanie (
Программирование
), #_programmirovanie_mikrokontrollerov (
Программирование микроконтроллеров
)
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:34
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Micro Property — библиотека для сериализации данных с минимальными накладными расходами. Она разработана для использования в микроконтроллерах и различных встраиваемых устройствах с ограничениями по размеру памяти, которым приходится работать по низкоскоростным линиям связи. Конечно, я знаю про такие форматы как xml, json, bson, yaml, protobuf, Thrift, ASN.1. Даже нашел экзотический Tree, который сам является убийцей JSON, XML, YAML и иже с ними. Так почему же они все не подошли? Зачем я был вынужден написать еще один сериализатор? Исходные требования Прежде чем начинать расхваливать собственное творение (а как же без этого? ;-), следует начать с того, для каких целей вообще потребовался сериализатор данных. Представим, что требуется доработать распределенную систему, состоящую из нескольких сотен устройств разных типов (более десяти типов устройств, выполняющих разные функции). Они объединены в группы, которые обмениваются между собой данными по последовательным линиям связи по протоколу Modbus RTU. Также, часть этих устройств подключены к общей линии связи CAN, которая и обеспечивает передачу данных в рамках всей системы в целом. Скорость передачи данных по линии связи Modbus до 115200 Бод, а скорость по шине CAN ограничена скоростью до 50кБод из-за её протяженности и присутствия серьезных индустриальных помех. Устройства в подавляющем большинстве разработаны на микроконтроллерах серий STM32F1x и STM32F2x. Хотя часть из них работает и на STM32F4x. Ну и конечно, Windows/Linux на базе системы с x86 микропроцессорами в качестве контроллеров верхнего уровня. Для оценки объема данных, которые обрабатываются и передаются между устройствами или хранятся в качестве настроек/параметров работы: В одном случае — 2 числа по 1 байт и 6 чисел по 4 байта, в другом — 11 чисел по 1 байту и 1 число 4 байта и т.д. Для справки, размер данных в стандартном кадре CAN — до 8 байт, а во фрейме Modbus, до 252 байт полезных данных. Если вы еще не прониклись глубиной кроличьей норы, добавьте к этим вводным данным: необходимость вести учет версий протокола и версий прошивок для разных типов устройств, а так же наличие требования к сохранению совместимости не только с существующими на текущий момент форматами данных, но и обеспечение совместной работы устройств с будущими поколения, которые тоже не стоят на месте и постоянно развиваются и перерабатываются по мере развития функционала и нахождения косяков в реализациях. Плюс, взаимодействие с внешними системами, расширение требований и т.д. Первоначально, из-за ограниченности ресурсов и низких скоростей линий связи для обмена данными использовался бинарный формат который был привязанный только к регистрам Modbus. Но такая реализация не прошла первую же проверку на совместимость и расширяемость. Поэтому, при переработке архитектуры пришлось отказаться от использования стандартных Modbus регистров. И даже не из-за того, что кроме этого протокола используются и другие линии связи, а сколько из-за чрезмерной ограниченности организации структур данных, основанных на 16-битных регистрах. Ведь в будущем, при неизбежной эволюции системы, может потребоваться, (а по факту, уже потребовалось), передавать текстовые строки или массивы. В теории, их тоже можно отображать на карту Modbus регистров, но это получается масло масляное, т.к. выходит абстракция над абстракцией. Конечно, можно передавать данные как двоичный блоб с привязкой к версии протокола и типу блока. И хотя на первый взгляд такая идея может показалось здравой, ведь фиксируя определенные требования к архитектуре, можно раз и навсегда определить форматы данных, чем существенно сэкономить на накладных расходах, которые будут неизбежны при использовании таких форматов, как XML или JSON. Чтобы было удобнее сравнивать варинаты, для себя я составил такую табличку:SPLПередача двоичных данных без идентификации полей:
Плюсы:
Минусы:
Передача двоичных данных с идентификацией полей: Минусы:
Плюсы:
И только представишь себе, как несколько сотен устройств начинают обмениваться между собой двоичными данными, пусть даже с привязкой каждого сообщения к версии протокола и/или типу устройства, то необходимость использование сериализатора с именованными полями сразу становится очевидной. Ведь даже простая интерполяция сложности поддержки подобного решения в целом, пусть и через совсем непродолжительное время, вынуждает схватится за голову. И это, даже не принимая в расчет ожидаемые хотелки заказчика по наращиванию функционала, наличия обязательных косяков в реализации и «мелкие», на первый взгляд, доработки, которые обязательно привнесут с собой особую пикантность поиска периодически возникающих косяков в слаженной работе подобного зоопарка … А какие есть варианты? После подобных рассуждений невольно приходишь к выводу, что требуется с самого начала закладывать универсальную идентификацию бинарных данных, в том числе и при обмене пакетами по низкоскоросным линиям связи. И вот когда я пришел к выводу, что без сериализатора не обойтись, то сперва посмотрел на существующие решения, которые уже зарекомендовали себя с самой лучшей стороны, и которые уже используются во множестве проектов. Основные форматы xml, json, yaml и другие текстовые варианты с очень удобным и простым формальным синтаксисом, который хорошо подходит для обработки документов и одновременно удобен для чтения и редактирования человеком, пришлось сразу отбросить. И как раз из-за своего удобства и простоты они имеют очень большие накладные расходы при хранении бинарных данных, которые как раз и требовалось обрабатывать. Поэтому, в виду ограниченности ресурсов и низкоскоростных линий связи, было решено использовать бинарный формат представления данных. Но и в случае форматов, умеющих преобразовывать данные в бинарное представление, таких как Protocol Buffers, Flat Buffers, ASN.1 или Apache Thrift, накладные расходы при сериализации данных, а так же общее удобство их применения не способствовало к немедленному внедрению любой из подобных библиотек. Лучше всего по совокупности параметров подходил формат BSON, который имеет минимальный оверхед. И я серьезно рассматривал возможность его применения. Но в результате, все же решил отказаться и от него, т. к. при прочих равных условиях даже у BSON будут неприемлемые накладные расходы. Кому-то может показаться странным, что приходится беспокоиться о десятке лишних байт, но к сожалению, этот десяток байт должен будет передаваться каждый раз при отправке сообщения. А в случае работы по низкоскоростным линиям связи, даже лишний десяток байт в каждой посылке имеют значение.
Другими словами, когда оперируешь десятком байт, начинаешь считать каждый из них. А ведь в сеть вместе с данными еще передаются адреса устройств, контрольные суммы пакетов и другая информация, специфичная для каждой линии связи и протокола. Что получилось В результате раздумий и нескольких экспериментов получился сериализатор со следующими особенностями и характеристиками:
Поддерживаемые типы данных:
Хотелось бы отметить отдельно Реализация сделана на С++ x11 в единственном заголовочном файле с использованием механизма шаблонов SFINAE (Substitution failure is not an error). Поддерживается корректное чтение данных в буфер (переменную) бОльшего размера, чем сохраненный тип данных. Например, целое число 8 бит можно прочитать в переменную от 8 до 64 бит. Подумываю, может быть стоит добавить упаковку целых чисел, размер которых превышает 8 бит, на предмет возможности их передачи числом меньшего размера. Сериализованные массивы можно читать как копированием в указанную область памяти, так и получением обычной ссылки на данные в исходном буфере, если хочется избежать копирования, в тех случаях, когда оно не требуется. Но данной возможностью следует пользоваться с осторожностью, т. к. данные сохраняются в сетевом порядке, который может отличаться между машинами. Сериализация структур или более сложных объектов даже не планировалась. Структуры вообще опасно передавать в бинарном виде из-за возможного выравнивания её полей. Но если эта проблема все же решается относительно простым способом, то все равно будет проблема конвертации в сетевой порядок байт и обратно всех полей объектов, содержащих целые числа. Тем более, в случае крайней необходимости, структуры всегда можно сохранять и восстанавливать как массив байт. Естественно, в этом случае конвертация целых чисел необходимо будет выполнять вручную. Реализация Реализация находится тут: https://github.com/rsashka/microprop Как пользоваться, написано в примерах с различной степенью подробности: Быстрое использованиеSPL#include "microprop.h"
Microprop prop(buffer, sizeof (buffer));// Создать сериализатор и назначить ему буфер prop.FieldExist(string || integer); // Проверить наличие поля с указанным ID prop.FieldType(string || integer); // Получить тип данных поля prop.Append(string || integer, value); // Добавить данные prop.Read(string || integer, value); // Прочитать данные Медленное и вдумчивое использованиеSPL#include "microprop.h"
Microprop prop(buffer, sizeof (buffer)); // Создать сериализатор prop.AssignBuffer(buffer, sizeof (buffer)); // Назначить буфер prop.AssignBuffer((const)buffer, sizeof (buffer)); // Назначить read only буфер prop.AssignBuffer(buffer, sizeof (buffer), true); // Тоже read only буфер prop.FieldNext(ptr); // Получить указатель на следующее поле prop.FieldName(string || integer, size_t *length = nullptr); // Указатель на ID поля prop.FieldDataSize(string || integer); // Размер сериализованных данных // Дальше все прозрачно prop.Append(string || blob || integer, value || array); prop.Read(string || blob || integer, value || array); prop.Append(string || blob || integer, uint8_t *, size_t); prop.Read(string || blob || integer, uint8_t *, size_t); prop.AppendAsString(string || blob || integer, string); const char * ReadAsString(string || blob || integer); Пример реализации с использованием enum в качестве идентификатора данныхSPLclass Property : public Microprop {
public: enum ID { ID1, ID2, ID3 }; template <typename ... Types> inline const uint8_t * FieldExist(ID id, Types ... arg) { return Microprop::FieldExist((uint8_t) id, arg...); } template <typename ... Types> inline size_t Append(ID id, Types ... arg) { return Microprop::Append((uint8_t) id, arg...); } template <typename T> inline size_t Read(ID id, T & val) { return Microprop::Read((uint8_t) id, val); } inline size_t Read(ID id, uint8_t *data, size_t size) { return Microprop::Read((uint8_t) id, data, size); } template <typename ... Types> inline size_t AppendAsString(ID id, Types ... arg) { return Microprop::AppendAsString((uint8_t) id, arg...); } template <typename ... Types> inline const char * ReadAsString(ID id, Types... arg) { return Microprop::ReadAsString((uint8_t) id, arg...); } }; Код выложен под лицензией MIT, так что пользуйтесь на здоровье. Буду рад любому фидбеку, в том числе и замечаниям и/или предложениям. =========== Источник: habr.com =========== Похожие новости:
Анализ и проектирование систем ), #_oop ( ООП ), #_programmirovanie ( Программирование ), #_programmirovanie_mikrokontrollerov ( Программирование микроконтроллеров ) |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 12:34
Часовой пояс: UTC + 5