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;
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);