Библиотека кодирования Base64 с Arduino
Base64 — это система кодирования, в которой используются 64 символа, сгруппированные в сообщения, длина которых кратна четырем. Эти сообщения (пакеты данных) при необходимости дополняются символом плюса (поэтому используется 65), часто знаком равенства (=), если закодированная полезная информация имеет меньшую длину.
Используя 64 знака, вы можете работать с 10 цифрами, а также прописными и строчными буквами (26+26) кода. ASCII, проблема в том, что имеется 62, скажем так, однозначных символа плюс два, различающиеся в разных реализациях. Хотя иногда их называют выражением «персонажи ASCII для печати», на самом деле это те, которые варьируются от кода 32 (пробел) до 126 (~), 95 действительно пригодных для печати.
Реализация кодирования Base64 наиболее используемый, из PEM, который также используется MIME, используйте дополнительные знаки «+» и «/» и знак «=» для заполнения, чтобы длина пакетов была кратна четырем. Буквы A-Z занимают позиции 0-25, буквы a-z - позиции 26-51, цифры 0-9 - позиции 52-61, знак плюс (+) - позиции 62, а позицию 63 занимает косая черта (/).
Способ представления данных в формате Base64 состоит из отбора из исходных данных групп 6 бит которые представлены соответствующим кодом. Если остались биты, они заполняются нулями справа. Если полученное количество кодов не кратно четырем, оно заполняется знаками равенства справа.
На следующем изображении показана кодировка ASCII текста («ом») и способа его преобразования в Base64. Поскольку символов 7, окончательное сообщение необходимо будет заполнить знаком равенства в конце. Можно сказать, что текст «ом» в ASCII эквивалент «b2htaW8=" в Base64.
Конкретное использование кодирования Base64 Они также обычно устанавливают максимальную длину строки. Реализация MIME Ограничивает каждую строку 76 символами. Обычно строки разделяются кодом конца строки (CR, представленным значением 0x0D в ASCII) и еще одну новую строку (NL, что соответствует коду ASCII 0x0А).
Неудобства, которые добавляются при реализации кодирования Base64 на устройстве с небольшим количеством ресурсов, как это часто бывает с микроконтроллер заключается в том, что вам придется кодировать по мере поступления информации или с помощью буфер минимум, который также требует предоставления системы, указывающей на достижение конца исходного сообщения, например, путем добавления специального кода или использования контакта, уровень которого (синхронизированный с приемом) указывает на статус сообщения.
Пример кода ниже представляет собой библиотека для Arduino для кодирования в Base64 который реализуется по обоим критериям: кодирование поступающей информации (без буфер) и дождитесь завершения предупреждающего сигнала.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
//base64.h
#include <string.h> // memcpy/strncpy
#define LONGITUD_LINEA 76
#define MASCARA_B64 0B00111111
#define ULTIMO_CODIGO_BASE64 64 // 64 caracteres más el signo igual (empezando a contar desde cero)
#define MAXIMA_LONGITUD_RESULTADO 6 // Máximo número de caracteres del resultado parcial de la codificación. Puede ser 1 si no se ha llegado al final de un bloque (2 bytes en el original, 4 en la conversión), 2 si se ha llegado al final de un bloque, 3 si no se ha llegado al final de un bloque pero se supera la longitud máxima de la línea, 4 si se llega al final de un bloque y se supera la longitud máxima de la línea, 5 si hay que rellenar con un signo igual o 6 si hay que rellenar con dos signos igual
class Base64
{
private:
unsigned char simbolo_base64[ULTIMO_CODIGO_BASE64+1]; // Espacio para la codificación Base64, el relleno (=) una terminación en \0
unsigned int numero_valor; // Posición (empezando en cero) que ocupa el valor que se desea convertir en el mensaje completo original
unsigned int numero_codigo; // Posición del último código calculado. Podría limitarse al ancho de la línea (LONGITUD_LINEA, 76 caracteres) pero usando un contenedor alto se podría implementar también una cuenta estadística
unsigned char resto_base64; // Último resto obtenido al calcular el último código
unsigned char resultado[MAXIMA_LONGITUD_RESULTADO+1]; // Resultado de la conversión actual. Si es terminal puede incluir el caracter 65 (=) una o dos veces
unsigned char contador_caracteres_resultado=0;
void acumular_resultado(unsigned char valor);
public:
Base64();
~Base64();
void iniciar_conversion();
unsigned char *convertir(unsigned char valor_original, bool terminar_conversion);
unsigned char *convertir(unsigned char valor_original);
unsigned char *terminar();
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
|
//base64.cpp
#include “base64.h”
Base64::Base64() // Constructor
{
memcpy(simbolo_base64,“ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=”,ULTIMO_CODIGO_BASE64+1);
iniciar_conversion();
}
Base64::~Base64() // Destructor
{
}
void Base64::iniciar_conversion()
{
numero_valor=0;
numero_codigo=0;
resto_base64=0;
}
unsigned char *Base64::convertir(unsigned char valor_original, bool terminar_conversion) // Valor que se desea convertir a Base64
{
convertir(valor_original);
if(terminar_conversion)
{
terminar();
}
return resultado;
}
unsigned char *Base64::convertir(unsigned char valor_original) // Valor que se desea convertir a Base64
{
unsigned char desplazamiento;
contador_caracteres_resultado=0;
acumular_resultado((valor_original>>(2+(numero_valor%3)*2))|resto_base64);
desplazamiento=4–(numero_valor%3)*2;
resto_base64=(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento;
if(((numero_codigo+1)%4==0))
{
acumular_resultado(resto_base64);
resto_base64=0;
}
numero_valor++;
resultado[contador_caracteres_resultado]=0;
return resultado;
}
unsigned char *Base64::terminar()
{
if(numero_codigo%4)
{
acumular_resultado(resto_base64);
while(numero_codigo%4)
{
acumular_resultado(ULTIMO_CODIGO_BASE64);
}
}
resultado[contador_caracteres_resultado]=0;
iniciar_conversion();
return resultado;
}
void Base64::acumular_resultado(unsigned char valor)
{
numero_codigo++;
resultado[contador_caracteres_resultado++]=simbolo_base64[valor];
if((numero_codigo%LONGITUD_LINEA)==0)
{
resultado[contador_caracteres_resultado++]=13; // CR “\r”
resultado[contador_caracteres_resultado++]=10; // LF “\n”
}
}
|
Основная часть расчета кода Base64 Это делается с помощью выражения:
(valor_original>>(2+(numero_valor%3)*2))|resto_base64
и вычисление остатка с выражением:
(valor_original&(MASCARA_B64>>desplazamiento))<<desplazamiento
,
siendo desplazamiento
значение, которое рассчитывается с помощью выражения:
4-(numero_valor%3)*2
Процесс получения этих выражений состоит из обобщения расчета каждого из четырех кодов. Base64 которые являются результатом представления трех байтов исходного значения.
Base64=((byte_1>>2)|resto)&0b00111111 |
resto=(byte_1&0b00000011)<<4 |
Base64=((byte_2>>4)|resto)&0b00111111 |
resto=(byte_2&0b00001111)<<2 |
Base64=((byte_3>>6)|resto)&0b00111111 |
resto=(byte_3&0b00111111)<<0 |
Base64=((byte_3>>0)|resto)&0b00111111 |
resto=(byte_3&0b00111111)<<0 |
С текстом Base64
Псевдокод выше относится к коду в Base64 это рассчитывается. Выражение было использовано byte_n
для обозначения n-го кодируемого байта. Текст resto
представляет собой оставшиеся биты кодируемого байта. В начале расчета предполагается, что остаток равен нулю
Для наглядности в предыдущем псевдокоде 6-битная маска включена в расчет всех кодов, хотя определить необходимо только последний из них, так как остальные ротируются так, что два самых бита всегда теряются. значительный.
Как можно видеть, четвертый код представляет собой остаток, и нет необходимости впоследствии вычислять остаток; Поэтому необходимо выполнить всего три шага, по одному на каждый закодированный байт. Важно помнить, что если бы третий байт пакета не был закодирован, последний код пришлось бы заполнить нулями справа. Base64 получен.
Обобщая, можно сказать, что поворот вправо выражения, вычисляющего код в Base64 может быть представлено как 2+(numero_byte%3)*2
так, чтобы часть внутри круглых скобок вращалась от нуля до двух, в результате чего на каждом шаге получалось 2, 4 и 6. Конечно, это не единственный способ обобщения, но я выбрал его из соображений функциональности и, прежде всего, ради ясности. Поскольку маска (И) была необходима только в четвертом коде и уже было видно, что вычислять ее не обязательно (это все остаток), то она не включается в итоговое выражение для его упрощения, хотя надо помнить что для типа используемых данных (байт) берутся только 6 младших битов.
Левое вращение остальных можно обобщить аналогично предыдущему. Также можно видеть, что применяемая маска (И) подвергается такому же повороту битов, но в противоположном направлении. По этой причине для расчета смещения 4-(numero_valor%3)*2
перед применением его в смысле, соответствующем каждой части выражения.
В следующем примере показано, как использовать библиотеку для кодирования текстовой строки (помните, что Base64 может использоваться для любого набора данных, например изображения). В следующем коде есть несколько деталей, которые интересно уточнить. Во-первых, для обозначения конца текста вместо аппаратного сигнала или указания длины текста использовался специальный символ (символ ~). Логично, что этот символ не может быть частью закодированных данных.
Второй вопрос, который необходимо учитывать, столь же важный, сколь и очевидный, заключается в том, что декодер в пункте назначения должен знать, как представлена информация, которая его достигает. В тексте присутствуют символы, не входящие в набор ASCII печатные (от 32 до 126), например, буквы с ударением. Arduino будет использовать два байта (UTF-8) для представления этих персонажей. Обычный просто так использовать нельзя \0
в качестве признака завершения текста, поскольку во многих случаях первый байт, которым представлен символ, будет точно равен нулю.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include “base64.h”
char texto_prueba[]=“La bella y graciosa moza marchose a lavar la ropa.\nLa mojó en el arroyuelo y cantando la lavó.\nLa frotó sobre una piedra, la colgó de un abedul.\nDespués de lavar la ropa, la niña se fue al mercado.\nUn pastor vendía ovejas pregonando a viva voz:\nved qué oveja, ved qué lana, ved qué bestia, qué animal.\nLa niña la vio muy flaca, sin embargo le gustó.\nYo te pago veinte escudos y no discutamos más.\nVuelve la niña cantando muy contenta con su oveja.\nCuando llegaron al bosque la ovejita se escapó.\nLa niña desesperada arrojose encima de ella.\nVelozmente y con destreza aferrola por detrás.\nLlegaba por el camino jinete de altivo porte.\nDescendió de su caballo y a la niña le cantó…~”;
char *resultado;
Base64 base64;
void setup()
{
Serial.begin(9600);
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) // ¿Es un Arduino Leonardo (ATmega32U4)?
while(!Serial){}; // Esperar a Arduino Leonardo
#endif
// Mostrar el texto original
unsigned int contador=0;
while(texto_prueba[contador]!=‘~’)
{
//Serial.println(String(texto_prueba[contador])+”=”+String(texto_prueba[contador],DEC));
Serial.print(String(texto_prueba[contador]));
contador++;
}
Serial.println(“\n”);
// Mostrar el texto codificado en Base64
contador=0;
while(texto_prueba[contador]!=‘~’)
{
resultado=base64.convertir(texto_prueba[contador],texto_prueba[contador+1]==‘~’);
byte contador_resultado=0;
while(resultado[contador_resultado]>0)
{
Serial.print(String(resultado[contador_resultado]));
contador_resultado++;
}
contador++;
}
}
void loop()
{
}
|
В строке 26 предыдущего примера показано использование оператора библиотека для Arduino для кодирования в Base64. Необходимо только указать метод convertir
каждый байт, который вы хотите закодировать, и, при необходимости, является ли он последним или, если нет, остановите преобразование с помощью метода terminar
когда ты дойдешь до конца.
Как видно на скриншоте ниже, пример программы библиотека для Arduino для кодирования в Base64 сначала отображает текст, который нужно закодировать в Base64, в данном случае начало знаменитой песни великанов Лес Лютьерс, а затем и результат кодирования в Base64 использование длины строки формата MIME.
Оставить комментарий