Протокол и библиотека для преобразования произвольных массивов байтов в переходы SignalChange
и обратно. Решение рассчитано на передачу через многоканальный (RGBW) источник света/приёмник и умеет не только обнаруживать, но и исправлять отдельные ошибки без повторной передачи кадров.
- Каждый кадр начинается преамбулой (длинный импульс + пауза) с магическим номером
0xC39A
и завершается эндером0x51AA
. - Заголовок содержит длину полезной нагрузки и CRC8-ATM по данным. Дополнительных версионных байтов больше нет.
- Цветовая четырёхуровневая модуляция теперь непрерывна: после каждого цвета сразу включается следующий, без «чёрных» разделителей. Кроме преамбулы и хвостовой паузы выключенное состояние не используется.
- Для каждого полубайта используется код Хэмминга (7,4) и дублирование блоков. Декодер выполняет перебор допустимых альтернатив и может восстановить кадр даже при потере нескольких цветовых переходов.
- Подробная статистика (магические несоответствия, попытки коррекции, количество неоднозначных переходов) помогает оценить качество канала.
Поле | Размер (байт) | Описание |
---|---|---|
Magic | 2 | 0xC39A — позволяет быстро выровнять поток |
Payload Length | 2 | Длина полезных данных |
Payload | N | Пользовательские данные |
CRC8 | 1 | Контрольная сумма полезной нагрузки |
Ender | 2 | 0x51AA — окончание кадра |
По умолчанию единичный временной «тик» — 600 мкс. Преамбула: 16 тиков белого света и 8 тиков паузы. Первый рабочий цвет — красный, далее энкодер чередует цвета так, чтобы одинаковые не соседствовали. После кадра автоматически добавляется «тишина» на 12 тиков, чтобы разделить кадры.
#include "datapacklib.h"
using namespace datapack;
Encoder encoder;
Decoder decoder(
[](const std::uint8_t* data, std::size_t len, void*) {
// обработка полезных данных
std::vector<std::uint8_t> payload(data, data + len);
// ...
});
std::vector<std::uint8_t> payloadBytes = {/* ... */};
datapack::SignalBuffer signal;
if (encoder.encode(payloadBytes.data(), payloadBytes.size(), signal))
{
for (std::size_t i = 0; i < signal.size(); ++i)
{
decoder.feed(signal[i]);
}
}
SignalChange::level
может принимать одно из пяти значений (Off
, White
, Red
, Green
, Blue
). Для передачи полезных данных используются только цвета; «выключенное» (Off
) встречается только в преамбуле и в завершающем промежутке между кадрами.
Декодер можно создавать один раз и вызывать feed
при каждом наблюдаемом изменении уровня (значение и длительность в микросекундах). Когда кадр успешно собран или восстановлен после исправлений, вызывается переданный коллбэк.
datapacklib.js
теперь реализует ту же схему кодирования, что и минималистичная C++-библиотека в этом репозитории. Модуль распространяется в формате UMD: его можно подключить через <script>
на веб-странице, импортировать как CommonJS-модуль в Node.js или бандлить любым инструментом.
<script src="datapacklib.js"></script>
<script>
const {
LightLevel,
setSendData,
getSendCommands,
feed,
getReceivedData,
setOnPacketReceived,
} = datapack;
const payload = 'Hello, IR! Привет мир!';
setOnPacketReceived(({ index, word }) => {
console.log('Packet', index, '=>', word.toString(16));
});
setSendData(payload);
const commands = getSendCommands();
// эмулируем передачу: просто подаём закодированные сигналы в декодер
commands.forEach((cmd) => feed(cmd));
const rawBytes = getReceivedData();
console.log('Decoded string:', new TextDecoder().decode(rawBytes));
</script>
В Node.js аналогичные функции доступны через const datapack = require('./datapacklib.js');
. Модуль предоставляет:
LightLevel
— перечисление уровней освещения.setSendData(input)
— принимает строку,ArrayBuffer
,Uint8Array
или массив байтов и формирует внутренний буфер слов.getSendCommands()
— возвращает массив{ value, duration }
для отправки.feed({ value, duration })
— подать наблюдаемый переход в декодер.setOnPacketReceived(callback)
— коллбэк при успешном восстановлении пакета.getReceivedData()
/getReceivedWords()
— срезы накопленных данных.setMinDuration(value)
иsetSignalDuration(value)
— настройка временных параметров.resetEncoder()
иresetDecoder()
— очистка внутренних буферов.
g++ -std=c++17 -Wall -Wextra example.cpp datapacklib.cpp -o datapack_demo
./datapack_demo
ProtocolConfig
позволяет менять длительности импульсов, допуск, базовый цвет для запуска цепочки, коэффициент избыточности (1–3 копии блоков), макс. длину полезной нагрузки, magic/ender и т.д. Все проверки выполняются как на стороне энкодера (возвращает false
при ошибке), так и на стороне декодера.