707 lines
21 KiB
C++
707 lines
21 KiB
C++
// LoRaService.h
|
|
|
|
#ifndef LoRaService_h
|
|
#define LoRaService_h
|
|
|
|
#include "SerialService.h"
|
|
#include "CanService.h"
|
|
#include <Arduino.h>
|
|
#include <vector>
|
|
#include <map>
|
|
|
|
class LoRaService {
|
|
public:
|
|
|
|
enum LoRaMode {
|
|
NORMAL,
|
|
WAKE_UP,
|
|
POWER_SAVING,
|
|
CONFIG
|
|
};
|
|
|
|
enum CodigosFuncoes {
|
|
CfgTx = 0xC0,
|
|
CfgRx = 0xC1,
|
|
Msg = 0xE1,
|
|
WrongMode = 0xFC,
|
|
BeginMsg = 0xAA,
|
|
EndMsg = 0x55,
|
|
};
|
|
|
|
struct LoRaParametrosModel {
|
|
uint8_t address;
|
|
uint8_t baudAndAirRate;
|
|
uint8_t packetSizeAndPower;
|
|
uint8_t channel;
|
|
uint8_t tranModeAndWorCycle;
|
|
};
|
|
|
|
|
|
|
|
LoRaService(CanService* canService) {
|
|
_canService = canService;
|
|
}
|
|
|
|
bool Conectado = false;
|
|
bool Configurado = false;
|
|
byte AddressBase = 0x01;
|
|
|
|
// Inicializa pinos e UART
|
|
void Inicializar(uint8_t baudRate) {
|
|
Configurado = false;
|
|
|
|
_baudRate = encontrarChavePorValor(CodigosBaudRates, baudRate, 9600);
|
|
|
|
PrintTela("[LRA] Iniciando LoRa nos pinos TXD=" + String(_pinTXD) + ", RXD=" + String(_pinRXD) + ", baudRate=" + String(_baudRate) + "...");
|
|
|
|
// Inicializa GPIOs
|
|
pinMode(_pinM0, OUTPUT);
|
|
pinMode(_pinM1, OUTPUT);
|
|
pinMode(_pinAUX, INPUT);
|
|
|
|
_serialLoRa = &Serial2;
|
|
if (Conectado) {
|
|
_serialLoRa->end();
|
|
}
|
|
_serialLoRa->begin(_baudRate, SERIAL_8N1, _pinTXD, _pinRXD);
|
|
|
|
// Coloca o módulo em modo normal
|
|
setLoRaMode(NORMAL);
|
|
|
|
vTaskDelay(500); // Aguarda estabilização
|
|
|
|
// Testa conexão
|
|
Conectado = checkLoRaConnected();
|
|
if (Conectado) {
|
|
PrintTela("[LRA] E220 detectado!");
|
|
|
|
if (LraTaskRxHandle == NULL) {
|
|
lraQueueRx = xQueueCreate(50, sizeof(std::vector<uint8_t>));
|
|
if (lraQueueRx == NULL) {
|
|
PrintTela("[LRA] Falha ao criar fila RX!");
|
|
}
|
|
xTaskCreatePinnedToCore(LoRaService::LraTaskRxWrapper, "LraTaskRx", 4096, this, 3, &LraTaskRxHandle, APP_CPU_NUM);
|
|
}
|
|
|
|
if (LraTaskTxHandle == NULL) {
|
|
lraQueueTx = xQueueCreate(50, sizeof(std::vector<uint8_t>));
|
|
if (lraQueueTx == NULL) {
|
|
PrintTela("[LRA] Falha ao criar fila TX!");
|
|
}
|
|
xTaskCreatePinnedToCore(LoRaService::LraTaskTxWrapper, "LraTaskTx", 4096, this, 3, &LraTaskTxHandle, APP_CPU_NUM);
|
|
}
|
|
|
|
if (LraTaskProcessHandle == NULL) {
|
|
xTaskCreatePinnedToCore(LoRaService::LraTaskProcessWrapper, "LraTaskProcess", 4096, this, 2, &LraTaskProcessHandle, APP_CPU_NUM);
|
|
}
|
|
} else {
|
|
PrintTela("[LRA] E220 não detectado.");
|
|
}
|
|
}
|
|
|
|
|
|
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
|
|
std::vector<uint8_t> data;
|
|
data.push_back(_canService->ID_Num_sLRA);
|
|
data.push_back(static_cast<uint8_t>(posicao));
|
|
switch (posicao) {
|
|
case CanMessagePosicaoDados::Status: {
|
|
data.push_back(Conectado ? 1 : 0);
|
|
data.push_back(Configurado ? 1 : 0);
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados::Dados1: {
|
|
data.push_back(parametrosAtual.address);
|
|
data.push_back(parametrosAtual.baudAndAirRate);
|
|
data.push_back(parametrosAtual.packetSizeAndPower);
|
|
data.push_back(parametrosAtual.channel);
|
|
data.push_back(parametrosAtual.tranModeAndWorCycle);
|
|
break;
|
|
}
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void EnviarComando(std::vector<uint8_t> dados) {
|
|
if (dados.size() < 3) return;
|
|
uint8_t idNum = dados[1];
|
|
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)dados[2];
|
|
switch (posicao) {
|
|
case CanMessagePosicaoDados::Command1: {
|
|
bool sucesso = requisitarParametrosLoRa();
|
|
EnviarDadosCAN(MontarMensagemCAN(CanMessagePosicaoDados::Dados1));
|
|
break;
|
|
}
|
|
default: {
|
|
AdicionarMensagemFilaLoRa(dados);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool AdicionarMensagemFilaLoRa(std::vector<uint8_t> dados) {
|
|
if (xQueueSend(lraQueueTx, &dados, 0) != pdTRUE) {
|
|
PrintTela("[LRA] Fila TX cheia! Mensagem descartada.");
|
|
return false;
|
|
}
|
|
else {
|
|
PrintTela("[LRA] Mensagem adicionada na fila TX");
|
|
return true;
|
|
}
|
|
}
|
|
|
|
std::vector<uint8_t> ConfigurarModulo(std::vector<uint8_t> data) {
|
|
std::vector<uint8_t> status;
|
|
if (data.size() < 3) return status;
|
|
uint8_t idNum = data[1];
|
|
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[2];
|
|
PrintTela("[LRA] Recebido comando ConfigurarModulo: posicao = " + String((int)posicao));
|
|
switch (posicao) {
|
|
case CanMessagePosicaoDados::Config1: {
|
|
if (data.size() < 8) return data;
|
|
_pinM0 = data[3];
|
|
_pinM1 = data[4];
|
|
_pinAUX = data[5];
|
|
_pinRXD = data[6];
|
|
_pinTXD = data[7];
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados::Config2: {
|
|
if (data.size() < 8) return data;
|
|
if (_pinRXD == 0 || _pinTXD == 0) {
|
|
PrintTela("[LRA] Erro ao iniciar E220, pinout ainda nao definido!");
|
|
return status;
|
|
}
|
|
uint8_t baudField = data[4] & 0xE0; // bits 5,6,7 (baudrate)
|
|
Inicializar(baudField);
|
|
EnviarDadosCAN(MontarMensagemCAN(CanMessagePosicaoDados::Status));
|
|
if (Conectado) {
|
|
if (requisitarParametrosLoRa()) {
|
|
EnviarDadosCAN(MontarMensagemCAN(CanMessagePosicaoDados::Dados1));
|
|
Configurado =
|
|
parametrosAtual.address == data[3] &&
|
|
parametrosAtual.baudAndAirRate == data[4] &&
|
|
parametrosAtual.packetSizeAndPower == data[5] &&
|
|
parametrosAtual.channel == data[6] &&
|
|
parametrosAtual.tranModeAndWorCycle == data[7];
|
|
if (!Configurado) {
|
|
Configurado = configurarModuloLoRa(
|
|
data[3], // address
|
|
data[4], // baudAndAirRate
|
|
data[5], // packetSizeAndPower
|
|
data[6], // channel
|
|
data[7] // tranModeAndWorCycle
|
|
);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
private:
|
|
|
|
bool recebendo = false;
|
|
int bytesEsperados = -1;
|
|
int addrRemetente = -1;
|
|
int addrDestinatario = -1;
|
|
std::vector<uint8_t> buffer;
|
|
unsigned long ultimoByteRecebido = 0;
|
|
const unsigned long timeoutRecebimentoMs = 100; // por exemplo, 100ms
|
|
|
|
void reiniciarEstado() {
|
|
recebendo = false;
|
|
bytesEsperados = -1;
|
|
addrRemetente = -1;
|
|
addrDestinatario = -1;
|
|
buffer.clear();
|
|
}
|
|
|
|
|
|
QueueHandle_t lraQueueRx;
|
|
TaskHandle_t LraTaskRxHandle = NULL;
|
|
static void LraTaskRxWrapper(void *pvParameters) {
|
|
LoRaService *service = static_cast<LoRaService*>(pvParameters);
|
|
service->LraTaskRx(pvParameters);
|
|
}
|
|
|
|
void LraTaskRx(void* pvParameters) {
|
|
LoRaService* instance = (LoRaService*)pvParameters;
|
|
while (true) {
|
|
if (!Conectado || !Configurado) {
|
|
vTaskDelay(1000);
|
|
continue;
|
|
}
|
|
if (recebendo && (millis() - ultimoByteRecebido > timeoutRecebimentoMs)) {
|
|
PrintTela("[LRA] Timeout de recebimento. Reiniciando estado.");
|
|
reiniciarEstado();
|
|
}
|
|
while (currentMode == LoRaMode::NORMAL && instance->_serialLoRa->available()) {
|
|
uint8_t byteRecebido = instance->_serialLoRa->read();
|
|
ultimoByteRecebido = millis(); // <- atualiza o tempo
|
|
PrintTela("byteRecebido=" + String(byteRecebido));
|
|
|
|
if (!recebendo) {
|
|
if (byteRecebido == CodigosFuncoes::BeginMsg) {
|
|
reiniciarEstado();
|
|
PrintTela("[LRA] Iniciou o recebimento dos dados LoRa");
|
|
recebendo = true;
|
|
}
|
|
}
|
|
else {
|
|
if (bytesEsperados == -1) {
|
|
bytesEsperados = byteRecebido;
|
|
//PrintTela("[LRA] Definindo bytesEsperados = " + String(bytesEsperados));
|
|
}
|
|
else if (addrRemetente == -1) {
|
|
addrRemetente = byteRecebido;
|
|
//PrintTela("[LRA] Definindo addrRemetente = " + String(addrRemetente));
|
|
}
|
|
else if (addrDestinatario == -1) {
|
|
addrDestinatario = byteRecebido;
|
|
//PrintTela("[LRA] Definindo addrDestinatario = " + String(addrDestinatario));
|
|
if (addrDestinatario != parametrosAtual.address) {
|
|
PrintTela("[LRA] Mensagem para outro ID, descartando");
|
|
reiniciarEstado();
|
|
}
|
|
}
|
|
else {
|
|
buffer.push_back(byteRecebido);
|
|
|
|
bool protocoloCompleto = addrRemetente != -1 && addrDestinatario != -1 && buffer.size() == bytesEsperados + 2; // +2 = checksum + end
|
|
PrintTela("[LRA] protocoloCompleto = " + String(protocoloCompleto) + ", bufferSize = " + buffer.size() + ", bytesEsperados = " + String(bytesEsperados));
|
|
|
|
if (protocoloCompleto) {
|
|
if (buffer.back() == CodigosFuncoes::EndMsg) {
|
|
buffer.pop_back(); // remove 0x55 (EndMsg)
|
|
|
|
uint8_t checksumRecebido = buffer.back();
|
|
buffer.pop_back(); // remove checksum
|
|
|
|
uint8_t soma = 0;
|
|
for (size_t i = 0; i < buffer.size(); ++i) {
|
|
soma += buffer[i];
|
|
}
|
|
|
|
if ((soma % 256) == checksumRecebido) {
|
|
PrintTela("[LRA] Mensagem LoRa recebida de " + String(addrRemetente) + " com checksum válido");
|
|
|
|
if (buffer.size() >= 2) {
|
|
if (xQueueSend(lraQueueRx, &buffer, 0) != pdTRUE) {
|
|
PrintTela("[LRA] Fila RX cheia! Mensagem descartada.");
|
|
}
|
|
else {
|
|
PrintTela("[LRA] Mensagem adicionada na fila RX");
|
|
}
|
|
}
|
|
} else {
|
|
PrintTela("[LRA] Checksum inválido. Descartando.");
|
|
}
|
|
}
|
|
|
|
reiniciarEstado();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
vTaskDelay(1);
|
|
}
|
|
}
|
|
|
|
QueueHandle_t lraQueueTx;
|
|
TaskHandle_t LraTaskTxHandle = NULL;
|
|
static void LraTaskTxWrapper(void *pvParameters) {
|
|
LoRaService *service = static_cast<LoRaService*>(pvParameters);
|
|
service->LraTaskTx(pvParameters);
|
|
}
|
|
|
|
void LraTaskTx(void* pvParameters) {
|
|
LoRaService *service = static_cast<LoRaService*>(pvParameters);
|
|
std::vector<uint8_t> msg;
|
|
while (true) {
|
|
if (!Conectado || !Configurado) {
|
|
vTaskDelay(1000);
|
|
continue;
|
|
}
|
|
if (xQueueReceive(service->lraQueueTx, &msg, portMAX_DELAY) == pdTRUE) {
|
|
service->EnviarDadosLoRa(msg);
|
|
}
|
|
vTaskDelay(1);
|
|
}
|
|
}
|
|
|
|
TaskHandle_t LraTaskProcessHandle = NULL;
|
|
static void LraTaskProcessWrapper(void *pvParameters) {
|
|
LoRaService *service = static_cast<LoRaService*>(pvParameters);
|
|
service->LraTaskProcess(pvParameters);
|
|
}
|
|
|
|
void LraTaskProcess(void* pvParameters) {
|
|
LoRaService *service = static_cast<LoRaService*>(pvParameters);
|
|
std::vector<uint8_t> msg;
|
|
while (true) {
|
|
if (!Conectado || !Configurado) {
|
|
vTaskDelay(1000);
|
|
continue;
|
|
}
|
|
if (xQueueReceive(service->lraQueueRx, &msg, portMAX_DELAY) == pdTRUE) {
|
|
service->EnviarDadosCAN(msg);
|
|
}
|
|
vTaskDelay(1);
|
|
}
|
|
}
|
|
|
|
|
|
CanService* _canService;
|
|
HardwareSerial* _serialLoRa;
|
|
uint8_t _pinTXD;
|
|
uint8_t _pinRXD;
|
|
uint8_t _pinM0;
|
|
uint8_t _pinM1;
|
|
uint8_t _pinAUX;
|
|
int _baudRate = 9600;
|
|
LoRaMode currentMode = NORMAL;
|
|
LoRaParametrosModel parametrosAtual;
|
|
int commandTimeout = 1000;
|
|
|
|
// Métodos internos
|
|
// Define o modo do LoRa
|
|
bool setLoRaMode(LoRaMode mode) {
|
|
if (mode == currentMode) return true;
|
|
|
|
// Ajusta os pinos M0 e M1 conforme o modo desejado
|
|
switch (mode) {
|
|
case NORMAL:
|
|
digitalWrite(_pinM0, LOW);
|
|
digitalWrite(_pinM1, LOW);
|
|
break;
|
|
case WAKE_UP:
|
|
digitalWrite(_pinM0, HIGH);
|
|
digitalWrite(_pinM1, LOW);
|
|
break;
|
|
case POWER_SAVING:
|
|
digitalWrite(_pinM0, LOW);
|
|
digitalWrite(_pinM1, HIGH);
|
|
break;
|
|
case CONFIG:
|
|
digitalWrite(_pinM0, HIGH);
|
|
digitalWrite(_pinM1, HIGH);
|
|
break;
|
|
}
|
|
|
|
PrintTela("[LRA] Modo alterado de " + String(currentMode) + " para " + String(mode));
|
|
|
|
currentMode = mode;
|
|
|
|
vTaskDelay(100); // Aguarda sinalização inicial de troca
|
|
|
|
// ESPERA o AUX ir para HIGH, indicando que a troca completou
|
|
unsigned long timeout = millis() + commandTimeout;
|
|
while (digitalRead(_pinAUX) == LOW) {
|
|
if (millis() > timeout) {
|
|
PrintTela("[LRA] Erro: Timeout aguardando AUX após mudança de modo.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
vTaskDelay(100); // Manual pede 2ms após AUX ficar HIGH
|
|
return true;
|
|
}
|
|
|
|
// Verifica se o E220 responde
|
|
bool checkLoRaConnected() {
|
|
PrintTela("[LRA] Verificando se o E220 esta conectado...");
|
|
|
|
if (!setLoRaMode(CONFIG)) {
|
|
PrintTela("[LRA] Falha ao mudar para CONFIG!");
|
|
return false;
|
|
}
|
|
|
|
bool conectado = false;
|
|
|
|
// Lista de possíveis baud rates (em ordem dos mais prováveis)
|
|
const uint32_t baudRates[] = { 9600, 19200, 38400, 57600, 115200, 4800, 2400, 1200 };
|
|
const int totalBauds = sizeof(baudRates) / sizeof(baudRates[0]);
|
|
|
|
int tentativaAtual = -1; // -1 = usar o baudrate já setado primeiro
|
|
|
|
while (!conectado && tentativaAtual < totalBauds) {
|
|
if (tentativaAtual >= 0) {
|
|
// Se estamos tentando outra taxa, mudar a serial:
|
|
_serialLoRa->end();
|
|
_serialLoRa->begin(baudRates[tentativaAtual], SERIAL_8N1, _pinTXD, _pinRXD);
|
|
_baudRate = baudRates[tentativaAtual];
|
|
PrintTela("[LRA] Tentando BaudRate: " + String(_baudRate));
|
|
}
|
|
|
|
// Limpa buffers antes de testar
|
|
limparBufferLoRa();
|
|
|
|
_serialLoRa->write(CodigosFuncoes::CfgRx);
|
|
|
|
unsigned long startTime = millis();
|
|
while (millis() - startTime < commandTimeout) {
|
|
if (_serialLoRa->available()) {
|
|
uint8_t dado = _serialLoRa->read();
|
|
if (dado == CodigosFuncoes::CfgRx) {
|
|
conectado = true;
|
|
break;
|
|
}
|
|
}
|
|
vTaskDelay(1);
|
|
}
|
|
|
|
tentativaAtual++;
|
|
}
|
|
|
|
limparBufferLoRa();
|
|
|
|
setLoRaMode(NORMAL);
|
|
|
|
if (conectado) {
|
|
PrintTela("[LRA] E220 conectado com baudRate " + String(_baudRate));
|
|
} else {
|
|
PrintTela("[LRA] Falha ao conectar no E220!");
|
|
}
|
|
|
|
return conectado;
|
|
}
|
|
|
|
// Método que monta o comando de configuração
|
|
bool configurarModuloLoRa(byte addr, byte baud, byte packet, byte channel, byte worCycle) {
|
|
if (!setLoRaMode(CONFIG)) {
|
|
PrintTela("[LRA] Falha ao mudar para CONFIG!");
|
|
return false;
|
|
}
|
|
|
|
PrintTela("[LRA] Configurando modulo...");
|
|
|
|
limparBufferLoRa();
|
|
|
|
uint8_t command[9] = {
|
|
CodigosFuncoes::CfgTx, // Código para configurar
|
|
0x00, // Registro inicial
|
|
0x06, // Quantidade de registros
|
|
0x00, // Reservado
|
|
addr,
|
|
baud,
|
|
packet,
|
|
channel,
|
|
worCycle
|
|
};
|
|
|
|
_serialLoRa->write(command, sizeof(command));
|
|
PrintTela("[LRA] Comando de configuração enviado!");
|
|
|
|
unsigned long startTime = millis();
|
|
bool sucesso = false;
|
|
|
|
while (millis() - startTime < commandTimeout) {
|
|
if (_serialLoRa->available()) {
|
|
uint8_t cabecalho = _serialLoRa->read();
|
|
if (cabecalho == CodigosFuncoes::CfgRx) { // 0xC1 é Resposta de Configuração
|
|
sucesso = true;
|
|
PrintTela("[LRA] Confirmação de configuração recebida!");
|
|
} else {
|
|
PrintTela("[LRA] Resposta inesperada: 0x" + String(cabecalho));
|
|
}
|
|
break;
|
|
}
|
|
vTaskDelay(10);
|
|
}
|
|
|
|
setLoRaMode(NORMAL);
|
|
|
|
return sucesso;
|
|
}
|
|
|
|
// Método que requisita a leitura dos parâmetros atuais
|
|
bool requisitarParametrosLoRa() {
|
|
PrintTela("Entrou aqui 3");
|
|
if (!setLoRaMode(CONFIG)) {
|
|
PrintTela("[LRA] Falha ao mudar para CONFIG!");
|
|
return false;
|
|
}
|
|
|
|
PrintTela("[LRA] Requisitando parametros do modulo...");
|
|
|
|
limparBufferLoRa();
|
|
|
|
uint8_t command[3] = { CodigosFuncoes::CfgRx, 0x00, 0x0B };
|
|
|
|
_serialLoRa->write(command, sizeof(command));
|
|
PrintTela("[LRA] Comando de requisição enviado!");
|
|
|
|
unsigned long startTime = millis();
|
|
bool sucesso = false;
|
|
|
|
while (!sucesso && millis() - startTime < commandTimeout) {
|
|
if (_serialLoRa->available()) {
|
|
uint8_t cabecalho = _serialLoRa->read();
|
|
if (cabecalho == CodigosFuncoes::CfgRx) { // Cabeçalho de resposta correta
|
|
PrintTela("[LRA] Cabecalho recebido corretamente.");
|
|
uint8_t startAddr = _serialLoRa->read(); // Deve ser 0x00
|
|
uint8_t dataLen = _serialLoRa->read(); // Deve ser 0x0B
|
|
|
|
if (startAddr == command[1] && dataLen == command[2]) {
|
|
PrintTela("[LRA] Parâmetros recebidos corretamente.");
|
|
|
|
// Agora ler os registros
|
|
uint8_t addh = _serialLoRa->read(); // byte 0
|
|
uint8_t addl = _serialLoRa->read(); // byte 1
|
|
parametrosAtual.address = addl; // usa só o ADDL (0~255)
|
|
|
|
// Continua normalmente
|
|
parametrosAtual.baudAndAirRate = _serialLoRa->read(); // byte 2
|
|
parametrosAtual.packetSizeAndPower = _serialLoRa->read(); // byte 3
|
|
parametrosAtual.channel = _serialLoRa->read(); // byte 4
|
|
parametrosAtual.tranModeAndWorCycle = _serialLoRa->read(); // byte 5
|
|
|
|
// Lê e ignora os 5 bytes restantes (6~10)
|
|
for (int i = 0; i < (0x0B - 6); i++) {
|
|
_serialLoRa->read();
|
|
}
|
|
|
|
sucesso = true;
|
|
}
|
|
else {
|
|
PrintTela("[LRA] Dados Corrompidos: startAddr=" + String(startAddr) + ", dataLen=" + String(dataLen));
|
|
}
|
|
} else if (cabecalho == CodigosFuncoes::WrongMode) {
|
|
PrintTela("[LRA] Modo invalido!");
|
|
}
|
|
}
|
|
vTaskDelay(10);
|
|
}
|
|
|
|
limparBufferLoRa();
|
|
|
|
setLoRaMode(NORMAL);
|
|
|
|
return sucesso;
|
|
}
|
|
|
|
// Limpa buffer anterior
|
|
void limparBufferLoRa() {
|
|
while (_serialLoRa->available()) {
|
|
_serialLoRa->read();
|
|
}
|
|
}
|
|
|
|
std::vector<uint8_t> MontarFrameLoRa(uint16_t destino, uint8_t canal, const std::vector<uint8_t>& payloadApp) {
|
|
std::vector<uint8_t> frame;
|
|
|
|
// Cabeçalho fixo LoRa (modo Fixed)
|
|
frame.push_back((destino >> 8) & 0xFF); // Addr High (geralmente 0x00)
|
|
frame.push_back(destino & 0xFF); // Addr Low
|
|
frame.push_back(canal); // Canal
|
|
|
|
// Estrutura do payload
|
|
frame.push_back(CodigosFuncoes::BeginMsg); // 0xAA
|
|
frame.push_back(payloadApp.size()); // Tamanho do payload
|
|
frame.push_back(parametrosAtual.address); // rementente
|
|
frame.push_back(destino); // destinatario
|
|
|
|
frame.insert(frame.end(), payloadApp.begin(), payloadApp.end());
|
|
|
|
// Calcula checksum (soma dos dados de payload)
|
|
uint8_t soma = 0;
|
|
for (uint8_t b : payloadApp) {
|
|
soma += b;
|
|
}
|
|
uint8_t checksum = soma % 256;
|
|
frame.push_back(checksum); // Checksum
|
|
|
|
frame.push_back(CodigosFuncoes::EndMsg); // 0x55
|
|
|
|
PrintTela("Frame LoRa montado: ", false);
|
|
for (int i = 0; i < frame.size(); i++) {
|
|
PrintTela(String(frame[i]) + " ", false);
|
|
}
|
|
PrintTela("");
|
|
|
|
return frame;
|
|
}
|
|
|
|
bool EnviarDadosCAN(std::vector<uint8_t> dados) {
|
|
_canService->adicionarMensagemFila(dados);
|
|
return true;
|
|
}
|
|
|
|
bool EnviarDadosLoRa(std::vector<uint8_t> dados) {
|
|
PrintTela("Enviando dados via LoRa para o endereco " + String(AddressBase) + " no canal " + String(parametrosAtual.channel));
|
|
std::vector<uint8_t> dadosLora = MontarFrameLoRa(AddressBase, parametrosAtual.channel, dados);
|
|
_serialLoRa->write(dadosLora.data(), dadosLora.size());
|
|
_serialLoRa->flush();
|
|
PrintTela("Dados enviados");
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
std::map<String, uint8_t> CodigosTipoTransmissao = {
|
|
{"Normal", 0x00},
|
|
{"Fixed", 0x40},
|
|
};
|
|
|
|
std::map<int, uint8_t> CodigosBaudRates = {
|
|
{1200, 0x00},
|
|
{2400, 0x20},
|
|
{4800, 0x40},
|
|
{9600, 0x60},
|
|
{19200, 0x80},
|
|
{38400, 0xA0},
|
|
{57600, 0xC0},
|
|
{115200, 0xE0},
|
|
};
|
|
|
|
std::map<double, uint8_t> CodigosAirRates = {
|
|
{2.4, 0x02},
|
|
{4.8, 0x03},
|
|
{9.6, 0x04},
|
|
{19.2, 0x05},
|
|
{38.4, 0x06},
|
|
{62.5, 0x67},
|
|
};
|
|
|
|
std::map<int, uint8_t> CodigosPacketSizes = {
|
|
{200, 0x00},
|
|
{128, 0x40},
|
|
{64, 0x80},
|
|
{32, 0xC0},
|
|
};
|
|
|
|
std::map<int, uint8_t> CodigosWorCycles = {
|
|
{500, 0x00},
|
|
{1000, 0x01},
|
|
{1500, 0x02},
|
|
{2000, 0x03},
|
|
{2500, 0x04},
|
|
{3000, 0x05},
|
|
{3500, 0x06},
|
|
{4000, 0x07},
|
|
};
|
|
|
|
std::map<int, uint8_t> CodigosPowers = {
|
|
{22, 0x00},
|
|
{17, 0x01},
|
|
{13, 0x02},
|
|
{10, 0x03},
|
|
};
|
|
|
|
template<typename K, typename V>
|
|
K encontrarChavePorValor(const std::map<K, V>& mapa, V valorProcurado, K valorDefault) {
|
|
for (const auto& par : mapa) {
|
|
if (par.second == valorProcurado) {
|
|
return par.first;
|
|
}
|
|
}
|
|
return valorDefault;
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|