Enviando Bytes

Geralmente, a tecnologia permite enviar 51 bytes. Se você diminuir seu fator de espalhamento (ou seja, aumentar a taxa de dados), ocasionalmente poderá enviar ainda mais dados. No entanto, quanto mais bytes você enviar, mais tempo no ar será necessário para transmitir o pacote de dados e mais cedo você atingirá o tempo máximo alocado. Portanto, não se pergunte quantos Bytes você pode enviar. Em vez disso, pergunte a quantidade mínima deles para realizar o trabalho.

Enviando Números Grandes

Quer saber como enviar intervalos maiores que 255?

Índice

Se os valores possíveis que você precisa suportar não começarem em zero e você souber o valor mínimo, comece indexando nesse número.

Por exemplo, imagine que esperaríamos valores entre 3.400 e 3.600.

No dispositivo, codificaríamos isso como:

int meuVal = 3450;
int minhaBase = 3400;
byte payload[] = { meuVal - minhaBase };

E nas funções de payload do aplicativo, use isto:

var minhaBase = 3400;
decoded.meuVal = bytes[0] + minhaBase;

Ao contrário, na função de codificação do payload da aplicação teríamos:

var meuVal = 3450;
var minhaBase = 3400;
var bytes = [meuVal - minhaBase];

E no dispositivo, decodifique isso com:

int minhaBase = 3400;
int meuVal = payload[0] + minhaBase;

Como você pode ver, desde que o valor mínimo seja conhecido e o intervalo de nosso valor seja 256 ou menos, ainda podemos usar um único Byte sem suar muito.

Arredondando

Agora, e se o intervalo for maior que 256? A próxima pergunta é: você precisa saber o valor exato? Se o seu sensor tiver um alcance de 400 e uma margem de erro de 2, você não perderia nenhum significado ao arredondar o valor. Tanto 299 quanto 300 seriam arredondados para o mesmo valor se fossem divididos pela margem de erro de 2, portanto, seria 150, o que é bom, pois está abaixo de 255. No dispositivo, codificaríamos isso como:

int meuVal = 300;
int margemDeErro = 2
byte payload[] = { round(meuVal / margemDeErro) };

E nas funções de carga útil do aplicativo, faça o inverso:

var margemDeErro = 2;
decoded.meuVal = bytes[0] * margemDeErro;
Usar palavras

Uma palavra é geralmente dois Bytes. Ao usar palavras, você obtém uma grande variedade de valores: até 65536 (2562). Um exemplo de palavra é encontrado no tipo de dados int . Além disso, o Arduino vem com comandos highByte() e lowByte() que você pode usar para extrair o Byte esquerdo e direito de uma palavra. Isso torna muito fácil codificar e decodificar.

Por exemplo, para codificar um pacote de dados para Arduino, você pode usar isto:

int meuVal = 20000;
byte payload[2];
payload[0] = highByte(meuVal);
payload[1] = lowByte(meuVal);

Para decodificar o mesmo payload, você usaria isto:

decoded.meuVal = (bytes[0] << 8) + bytes[1];

Na primeira linha de código aqui, você vê (bytes[0] << 8). O comando << indica que o número designado de bytes deve ser deslocado para a esquerda. Neste caso, os 8 bits do primeiro byte são deslocados oito posições para a esquerda. Falaremos mais sobre a troca de bits a seguir.

Encode (payload functions):  

var meuVal = 20000;
var bytes = [];
bytes[0] = (meuVal & 0xFF00) >> 8;
bytes[1] = (meuVal & 0x00FF);

Nunca viu '&' usado dessa maneira antes? Isto é um Bitwise AND. Usado dessa forma, o lado direito da expressão atuará como uma máscara zerar um byte para que possamos trabalhar apenas com o outro.

Decode (Arduino):

int meuVal = (payload[0] << 8) + payload[1];

Deslocamento de bits

Se o intervalo de valores esperados for maior que 65536, podemos usar o mesmo truque. A única diferença é que temos que mudar manualmente os bits quando codificamos no Arduino, por exemplo, assim como fizemos na função payload.

Digamos que precisamos codificar um valor long , que usa 4 bytes, para um intervalo de até 4294967296 valores.

Encode (Arduino):

long lng = 200000L;
byte payload[4];
payload[0] = (int) ((lng & 0xFF000000) >> 24 );
payload[1] = (int) ((lng & 0x00FF0000) >> 16 );
payload[2] = (int) ((lng & 0x0000FF00) >> 8  );
payload[3] = (int) ((lng & 0X000000FF)       );

Decode (payload functions):

decoded.meuVal = (bytes[0] << 24)
             + (bytes[1] << 16)
             + (bytes[2] << 8)
              + (bytes[3]);
Enviando Números Negativos

Para saber a diferença entre -100 e 100, você precisará de um tipo de dados signed . Eles definem o bit mais alto (mais à esquerda) como 1 para indicar que é um número negativo. Isso significa, porém, que, em uma palavra, por exemplo, apenas 15 dos 16 bits estão disponíveis para o número real, limitando o intervalo de 65536 a 32768.

  • Index, Round e Shift: Os tipos de dados que usamos até agora são todos signed, o que significa que todos os truques funcionam tão bem quanto para valores negativos. Só fique atento ao valor máximo.
  • Tipos de dados unsigned:  se você não espera números negativos e precisa de um intervalo maior, use explicitamente os tipos de dados unsigned int ou unsigned long.

Enviando Decimais

Até agora, lidamos apenas com números inteiros. E se você precisar de mais precisão? A resposta é muito semelhante à forma como indexamos ou arredondamos números grandes. Simplesmente multiplique e divida o valor conforme você o codifica e decodifica. Por exemplo,

Encode (Arduino):

float meuVal = 1,22;
byte payload[1];
payload[0] = round(meuVal * 100);

Decode (payload functions):

decoded.meuVal = bytes[0] / 100;

Encode (payload functions):

bytes[0] = Math.round(1.22 * 100);

Decode (Arduino):

float meuVal = payload[0] / 100,00;

Observação

O exemplo acima usa “100.00”, não simplesmente “100”. Se ambos forem inteiros, o Arduino/C/C++ também fará a matemática usando inteiros, resultando em 1 em vez de 1,22.



Enviando vários números

Frequentemente, você desejará enviar vários valores em uma única mensagem. Comece codificando cada número individual em um buffer de Bytes e, em seguida, combine-os em um único buffer.

Encode (Arduino):

byte payloadA[] = { 0xF0 };
byte payloadB[] = { 0xF0, 0x0F };
byte payloadC[] = { 0xF0, 0x0F, 0xFF };
int sizeofPayloadA = sizeof(payloadA);
int sizeofPayloadB = sizeof(payloadB);
int sizeofPayloadC = sizeof(payloadC);  
byte payload[sizeofPayloadA + sizeofPayloadB + sizeofPayloadC];  
memcpy(payload, payloadA, sizeofPayloadA);
memcpy(payload + sizeofPayloadA, payloadB, sizeofPayloadB);
memcpy(payload + sizeofPayloadA + sizeofPayloadB, payloadC, sizeofPayloadC);

Você pode se perguntar por que memcpy() aceita payload + sizeOfPayloadA, já que eles parecem ser categoricamente diferentes. Para entender por que isso funciona, pense nisso como uma instrução para copiar para o buffer de payload, mas somente depois de mover o ponto para o qual ela copiará, com o comprimento dos payloads que adicionamos até agora.

decoded.myValA = bytes.slice(0, 2);
decoded.myValB = bytes.slice(2, 5);
// Decode both byte arrays as we did before

Encode (payload function)

var bytes = bytesA.concat(bytesB);

Decode (Arduino):

var payloadA[2];
var payloadB[3];
memcpy(payloadA)

Enviando texto

A abordagem para enviar texto é simples: não envie. O texto usa muitos bytes. O Unicode define mais de 128.000 caracteres, o que exigiria três Bytes por caractere para codificar! Raramente há bons motivos para usar texto em vez de números, além de transmitir a entrada de texto enviada pelos usuários.

No entanto, se não houver como contornar isso, aqui está como codificar uma string:

var myVal =
"Hello";
var l = myVal.length();
byte payload[l + 1];
myVal.getBytes(payload, l + 1);

E aqui está como decodificar uma string:

decoded.myVal =
String.fromCharCode.apply(null, bytes);

Last modified: Tuesday, October 11, 2022, 3:58 PM