-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
345 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
![License: MIT](https://img.shields.io/badge/License-MIT-green.svg) | ||
![author](https://img.shields.io/badge/author-AlexGyver-informational.svg) | ||
# Hamming | ||
Библиотека для упаковки и распаковки данных по алгоритму Хэмминга (избыточные данные для восстановления) | ||
- Порядок алгоритма 4-8 (чем выше, тем надёжнее) | ||
- Восстановление данных, повреждённых при пересылке | ||
- Принимает любой тип данных | ||
|
||
### Совместимость | ||
Совместима со всеми Arduino платформами (используются Arduino-функции) | ||
|
||
## Содержание | ||
- [Установка](#install) | ||
- [Инициализация](#init) | ||
- [Использование](#usage) | ||
- [Пример](#example) | ||
- [Версии](#versions) | ||
- [Баги и обратная связь](#feedback) | ||
|
||
<a id="install"></a> | ||
## Установка | ||
- Библиотеку можно найти по названию **Hamming** и установить через менеджер библиотек в: | ||
- Arduino IDE | ||
- Arduino IDE v2 | ||
- PlatformIO | ||
- [Скачать библиотеку](https://github.com/GyverLibs/Hamming/archive/refs/heads/main.zip) .zip архивом для ручной установки: | ||
- Распаковать и положить в *C:\Program Files (x86)\Arduino\libraries* (Windows x64) | ||
- Распаковать и положить в *C:\Program Files\Arduino\libraries* (Windows x32) | ||
- Распаковать и положить в *Документы/Arduino/libraries/* | ||
- (Arduino IDE) автоматическая установка из .zip: *Скетч/Подключить библиотеку/Добавить .ZIP библиотеку…* и указать скачанный архив | ||
- Читай более подробную инструкцию по установке библиотек [здесь](https://alexgyver.ru/arduino-first/#%D0%A3%D1%81%D1%82%D0%B0%D0%BD%D0%BE%D0%B2%D0%BA%D0%B0_%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA) | ||
|
||
<a id="init"></a> | ||
## Инициализация | ||
```cpp | ||
Hamming<5> buf; // <> - порядок кода (4-8) | ||
``` | ||
|
||
<a id="usage"></a> | ||
## Использование | ||
```cpp | ||
bool pack(T &data); // запаковать данные любого типа в буфер | ||
int unpack(uint8_t* data, int size); // распаковать данные. возврат: 0 ОК, 1 исправлены ошибки, 2 и 3 - есть неисправленные ошибки | ||
uint8_t status(); // возврат: 0 ОК, 1 исправлены ошибки, 2 и 3 - есть неисправленные ошибки | ||
int length(); // размер буфера (больше чем размер входных данных) | ||
void stop(); // освободить буфер | ||
uint8_t *buffer; // внутренний буфер | ||
``` | ||
<a id="example"></a> | ||
## Пример | ||
Остальные примеры смотри в **examples**! | ||
```cpp | ||
#include <Hamming.h> | ||
void setup() { | ||
Serial.begin(9600); | ||
// создали дату (любой тип) | ||
char data0[] = "Hello, world! Lorem Ipsum"; | ||
// запаковали | ||
Hamming<5> buf; // <> - порядок кода (4-8) | ||
// пакуем во внутренний буфер buf.buffer | ||
buf.pack(data0); // 12мс | ||
// запакованные данные хранятся в buf.buffer с размером buf.length() | ||
// можно их "отправить" | ||
// ======== "ПЕРЕДАЧА" ======== | ||
// проебали часть (два байта!) | ||
buf.buffer[5] = 0; | ||
buf.buffer[6] = 0; | ||
// ======== "ПРИЁМ" ======== | ||
// распаковываем. Порядок в <> такой же! | ||
Hamming<5> buf2; | ||
// передаём "принятые" запакованные данные и их длину (её тоже надо передать или знать) | ||
buf2.unpack(buf.buffer, buf.length()); // 6мс | ||
// выводим как строку | ||
Serial.println((char*)buf2.buffer); | ||
// выводим статус распаковки | ||
Serial.println(buf2.status()); | ||
} | ||
void loop() { | ||
} | ||
``` | ||
|
||
<a id="versions"></a> | ||
## Версии | ||
- v1.0 | ||
|
||
<a id="feedback"></a> | ||
## Баги и обратная связь | ||
При нахождении багов создавайте **Issue**, а лучше сразу пишите на почту [alex@alexgyver.ru](mailto:alex@alexgyver.ru) | ||
Библиотека открыта для доработки и ваших **Pull Request**'ов! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#include <Hamming.h> | ||
void setup() { | ||
Serial.begin(9600); | ||
|
||
// создали дату (любой тип) | ||
char data0[] = "Hello, world! Lorem Ipsum"; | ||
|
||
// запаковали | ||
Hamming<5> buf; // <> - порядок кода (4-8) | ||
// пакуем во внутренний буфер buf.buffer | ||
buf.pack(data0); // 12мс | ||
|
||
// запакованные данные хранятся в buf.buffer с размером buf.length() | ||
// можно их "отправить" | ||
|
||
// ======== "ПЕРЕДАЧА" ======== | ||
|
||
// проебали часть (два байта!) | ||
buf.buffer[5] = 0; | ||
buf.buffer[6] = 0; | ||
|
||
// ======== "ПРИЁМ" ======== | ||
|
||
// распаковываем. Порядок в <> такой же! | ||
Hamming<5> buf2; | ||
|
||
// передаём "принятые" запакованные данные и их длину (её тоже надо передать или знать) | ||
buf2.unpack(buf.buffer, buf.length()); // 6мс | ||
|
||
// выводим как строку | ||
Serial.println((char*)buf2.buffer); | ||
|
||
// выводим статус распаковки | ||
Serial.println(buf2.status()); | ||
} | ||
|
||
void loop() { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
####################################### | ||
# Syntax Coloring Map For Hamming | ||
####################################### | ||
|
||
####################################### | ||
# Datatypes (KEYWORD1) | ||
####################################### | ||
Hamming KEYWORD1 | ||
|
||
####################################### | ||
# Methods and Functions (KEYWORD2) | ||
####################################### | ||
|
||
pack KEYWORD2 | ||
unpack KEYWORD2 | ||
status KEYWORD2 | ||
length KEYWORD2 | ||
stop KEYWORD2 | ||
buffer KEYWORD2 | ||
|
||
####################################### | ||
# Constants (LITERAL1) | ||
####################################### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
name=Hamming | ||
version=1.0 | ||
author=AlexGyver <alex@alexgyver.ru> | ||
maintainer=AlexGyver <alex@alexgyver.ru> | ||
sentence=Library for pack and unpack data by Hamming algorithm | ||
paragraph=Library for pack and unpack data by Hamming algorithm | ||
category=Data Processing | ||
url=https://github.com/GyverLibs/Hamming | ||
architectures=* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/* | ||
Библиотека для упаковки и распаковки данных по алгоритму Хэмминга (избыточные данные для восстановления) | ||
Документация: | ||
GitHub: https://github.com/GyverLibs/Hamming | ||
Возможности: | ||
- Порядок алгоритма 4-8 (чем выше, тем надёжнее) | ||
- Восстановление данных, повреждённых при пересылке | ||
- Принимает любой тип данных | ||
AlexGyver, alex@alexgyver.ru | ||
https://alexgyver.ru/ | ||
MIT License | ||
Версии: | ||
v1.0 - релиз | ||
*/ | ||
|
||
#ifndef Hamming_h | ||
#define Hamming_h | ||
template <uint8_t HAM_SIZE = 5> // порядок алгоритма (4-8) | ||
class Hamming { | ||
public: | ||
// запаковать данные в буфер | ||
template <typename T> | ||
bool pack(T &data) { | ||
// 0. Считаем и создаём буфер | ||
int size = sizeof(T); // байтов даты | ||
uint8_t signif = chunkSizeB - (HAM_SIZE + 1); // битов даты на чанк | ||
chunkAmount = (size * 8 + signif - 1) / signif; // колво чанков (целоч. деление) | ||
bytes = chunkAmount * chunkSize; // размер буфера, байт | ||
if (buffer) free(buffer); // освобождаем старый | ||
buffer = (uint8_t*)malloc(bytes); // выделяем | ||
if (!buffer) return 0; // не удалось создать | ||
uint8_t buf[bytes]; // ещё буфер | ||
memset(buf, 0, bytes); // чисти чисти | ||
memset(buffer, 0, bytes); // чисти чисти | ||
uint8_t *ptr = (const uint8_t*) &data; // для чтения даты | ||
int ptrCount = 0; | ||
|
||
for (int chunk = 0; chunk < chunkAmount; chunk++) { // каждый чанк | ||
// 1. Заполняем дату, минуя ячейки Хэмминга (0,1,2,4,8...) | ||
for (uint8_t i = 0; i < chunkSizeB; i++) { | ||
if ((i & (i - 1)) != 0) { // проверка на степень двойки | ||
write(buf, chunk * chunkSizeB + i, read(ptr, ptrCount++)); // переписываем побитно | ||
} | ||
} | ||
|
||
// 2. Считаем и пишем parity для зон Хэмминга | ||
uint8_t parityH = 0; | ||
for (uint8_t i = 0; i < chunkSizeB; i++) { | ||
for (uint8_t j = 0; j < HAM_SIZE; j++) { | ||
// если это ячейка хэмминга и бит стоит, инвертируем текущий parity | ||
if ((i & (1 << j)) && read(buf, chunk * chunkSizeB + i)) parityH ^= (1 << j); | ||
} | ||
} | ||
for (uint8_t i = 0; i < HAM_SIZE; i++) { | ||
write(buf, chunk * chunkSizeB + (1 << i), (parityH >> i) & 1); // переписываем parity ячеек хэмминга | ||
} | ||
|
||
// 3. Считаем и пишем общий parity | ||
uint8_t count = 0; | ||
for (uint8_t i = 1; i < chunkSizeB; i++) { | ||
if (read(buf, chunk * chunkSizeB + i)) count++; // считаем | ||
} | ||
write(buf, chunk * chunkSizeB, count & 1); // пишем | ||
} | ||
|
||
// 4. Перемешиваем | ||
for (uint8_t i = 0, k = 0; i < chunkSizeB; i++) { | ||
for (uint8_t j = 0; j < chunkAmount; j++) { | ||
write(buffer, k++, read(buf, i + j * chunkSizeB)); | ||
} | ||
} | ||
return 1; | ||
} | ||
|
||
// распаковать данные | ||
// возврат: 0 ОК, 1 исправлены ошибки, 2 и 3 - есть неисправленные ошибки | ||
int unpack(uint8_t* data, int size) { | ||
// 0. Считаем и создаём буфер | ||
uint8_t signif = chunkSizeB - (HAM_SIZE + 1); // битов даты на чанк | ||
if (size & chunkSize != 0) return 0; // не кратно размеру чанка | ||
chunkAmount = size / chunkSize; // колво чанков | ||
bytes = chunkAmount * signif / 8; // размер буфера, байт (округл. вниз) | ||
if (buffer) free(buffer); // чисти старый | ||
buffer = (uint8_t*)malloc(bytes); // выделяем | ||
if (!buffer) return 0; // не удалось создать | ||
memset(buffer, 0, bytes); // чисти чисти | ||
uint8_t buf[size]; | ||
int ptrCount = 0; | ||
stat = 0; | ||
|
||
// 1. Разбираем мешанину обратно | ||
for (uint8_t i = 0, k = 0; i < chunkSizeB; i++) { | ||
for (uint8_t j = 0; j < chunkAmount; j++) { | ||
write(buf, i + j * chunkSizeB, read(data, k++)); | ||
} | ||
} | ||
|
||
for (int chunk = 0; chunk < chunkAmount; chunk++) { // каждый чанк | ||
// 2. Получаем хэш ошибки и общий parity | ||
uint8_t sum = 0, count = 0; | ||
for (uint8_t i = 0; i < chunkSizeB; i++) { | ||
if (read(buf, chunk * chunkSizeB + i)) { | ||
sum ^= i; | ||
if (i > 0) count++; | ||
} | ||
} | ||
|
||
// 3. Анализируем результат | ||
if (sum != 0) { // 1+ err | ||
if (read(buf, chunk * chunkSizeB) == (count & 1)) stat = max(stat, 2); // 2 err | ||
else toggle(buf, chunk * chunkSizeB + sum); // fix err | ||
stat = max(stat, 1); | ||
} else { | ||
if (read(buf, chunk * chunkSizeB) != (count & 1)) stat = max(stat, 3); // parity err | ||
} | ||
|
||
// 4. Собираем дату из ячеек Хэмминга | ||
for (uint8_t i = 0; i < chunkSizeB; i++) { | ||
if ((i & (i - 1)) != 0) { // проверка на степень двойки | ||
write(buffer, ptrCount++, read(buf, chunk * chunkSizeB + i)); // переписываем побитно | ||
} | ||
} | ||
} | ||
return stat; | ||
} | ||
|
||
// возврат: 0 ОК, 1 исправлены ошибки, 2 и 3 - есть неисправленные ошибки | ||
uint8_t status() { | ||
return stat; | ||
} | ||
|
||
// размер буфера (больше чем размер входных данных) | ||
int length() { | ||
return bytes; | ||
} | ||
|
||
// деструктор | ||
~Hamming() { | ||
stop(); | ||
} | ||
|
||
// освободить буфер | ||
void stop() { | ||
if (buffer) free(buffer); | ||
} | ||
|
||
// внутренний буфер | ||
uint8_t *buffer = NULL; | ||
|
||
private: | ||
void set(uint8_t* buf, int num) { | ||
bitSet(buf[num >> 3], num & 0b111); | ||
} | ||
void clear(uint8_t* buf, int num) { | ||
bitClear(buf[num >> 3], num & 0b111); | ||
} | ||
void write(uint8_t* buf, int num, bool state) { | ||
state ? set(buf, num) : clear(buf, num); | ||
} | ||
bool read(uint8_t* buf, int num) { | ||
return bitRead(buf[num >> 3], num & 0b111); | ||
} | ||
void toggle(uint8_t* buf, int num) { | ||
read(buf, num) ? clear(buf, num) : set(buf, num); | ||
} | ||
uint8_t stat; | ||
int bytes = 0; | ||
int chunkAmount = 0; | ||
const uint8_t chunkSizeB = (1 << HAM_SIZE); // вес чанка в битах | ||
const uint8_t chunkSize = (1 << HAM_SIZE) >> 3; // вес чанка в байтах | ||
}; | ||
#endif |