agrobot_base/Firmware/Modulos/LoRaService.h

855 lines
26 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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);
MostrarLog("Iniciando LoRa nos pinos TXD=" + String(_pinTXD) + ", RXD=" + String(_pinRXD) + ", baudRate=" + String(_baudRate) + "...");
// Inicializa GPIOs
pinMode(_pinENA, OUTPUT);
digitalWrite(_pinENA, HIGH);
vTaskDelay(100);
digitalWrite(_pinENA, LOW);
vTaskDelay(20);
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) {
MostrarLog("E220 detectado!");
if (LraTaskRxHandle == NULL) {
lraQueueRx = xQueueCreate(50, sizeof(std::vector<uint8_t>));
if (lraQueueRx == NULL) {
MostrarLog("Falha ao criar fila RX!");
}
xTaskCreatePinnedToCore(LoRaService::LraTaskRxWrapper, "LraTaskRx", 4096, this, 14, &LraTaskRxHandle, APP_CPU_NUM);
}
if (LraTaskTxHandle == NULL) {
lraQueueTx = xQueueCreate(50, sizeof(std::vector<uint8_t>));
if (lraQueueTx == NULL) {
MostrarLog("Falha ao criar fila TX!");
}
xTaskCreatePinnedToCore(LoRaService::LraTaskTxWrapper, "LraTaskTx", 4096, this, 13, &LraTaskTxHandle, APP_CPU_NUM);
}
if (LraTaskProcessHandle == NULL) {
xTaskCreatePinnedToCore(LoRaService::LraTaskProcessWrapper, "LraTaskProcess", 4096, this, 15, &LraTaskProcessHandle, APP_CPU_NUM);
}
} else {
MostrarLog("E220 não detectado.");
}
}
std::vector<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(posicao));
data.push_back(_canService->ID_Num_sLRA);
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() < 2) return;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)dados[0];
uint8_t idNum = dados[1];
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) {
MostrarLog("Fila TX cheia! Mensagem descartada.");
return false;
}
else {
MostrarLog("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() < 2) return status;
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0];
uint8_t idNum = data[1];
//MostrarLog("Recebido comando ConfigurarModulo: posicao = " + String((int)posicao));
switch (posicao) {
case CanMessagePosicaoDados::Config1: {
if (data.size() < 8) return data;
_pinENA = data[2];
_pinM0 = data[3];
_pinM1 = data[4];
_pinAUX = data[5];
_pinRXD = data[6];
_pinTXD = data[7];
break;
}
case CanMessagePosicaoDados::Config2: {
if (data.size() < 8) return status;
if (_pinRXD == 0 || _pinTXD == 0) {
MostrarLog("Erro ao iniciar E220, pinout ainda nao definido!");
return status;
}
AddressBase = data[2];
uint8_t addr = data[3]; // address
uint8_t baud = data[4]; // baudAndAirRate
uint8_t packet = data[5]; // packetSizeAndPower
uint8_t channel = data[6]; // channel
uint8_t worCycle = data[7]; // tranModeAndWorCycle
if (DebugMode) {
String log = String("Parametros Config:") +
" 0x" + String(AddressBase, HEX) +
" 0x" + String(addr, HEX) +
" 0x" + String(baud, HEX) +
" 0x" + String(packet, HEX) +
" 0x" + String(channel, HEX) +
" 0x" + String(worCycle, HEX);
MostrarLog(log);
}
uint8_t baudField = baud & 0xE0; // bits 5,6,7 (baudrate)
Inicializar(baudField);
//EnviarDadosCAN(MontarMensagemCAN(CanMessagePosicaoDados::Status));
if (Conectado) {
if (requisitarParametrosLoRa()) {
// Log detalhado do que veio da EEPROM
MostrarLog("EEPROM -> "
"Addr=" + String(parametrosAtual.address, HEX) +
" BaudAir=" + String(parametrosAtual.baudAndAirRate, HEX) +
" PacketPower=" + String(parametrosAtual.packetSizeAndPower, HEX) +
" Channel=" + String(parametrosAtual.channel, HEX) +
" TranModeWor=" + String(parametrosAtual.tranModeAndWorCycle, HEX)
);
MostrarLog("Desejado -> "
"Addr=" + String(addr, HEX) +
" BaudAir=" + String(baud, HEX) +
" PacketPower=" + String(packet, HEX) +
" Channel=" + String(channel, HEX) +
" TranModeWor=" + String(worCycle, HEX)
);
Configurado =
parametrosAtual.address == addr &&
parametrosAtual.baudAndAirRate == baud &&
parametrosAtual.packetSizeAndPower == packet &&
parametrosAtual.channel == channel &&
parametrosAtual.tranModeAndWorCycle== worCycle;
MostrarLog(String("Modulo ja configurado? ") + (Configurado ? "SIM" : "NAO"));
if (!Configurado) {
Configurado = configurarModuloLoRa(addr, baud, packet, channel, worCycle);
if (Configurado) {
std::vector<uint8_t> frame;
frame.push_back(0xFF);
frame.push_back(0xFF);
frame.push_back(channel);
frame.push_back(0x01);
enviarDadosSerial(frame.data(), frame.size(), "PING");
}
}
}
else {
MostrarLog("Sem resposta do modulo ao requisitar parametros");
}
}
EnviarDadosCAN(MontarMensagemCAN(CanMessagePosicaoDados::Status));
EnviarDadosCAN(MontarMensagemCAN(CanMessagePosicaoDados::Dados1));
break;
}
}
return status;
}
private:
bool DebugMode = true;
void MostrarLog(String mensagem) {
if (DebugMode) {
PrintTela("[LORA] " + mensagem);
}
}
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 = 800; // por exemplo, 100ms
const unsigned long tempoEntreEnvios = 200;
void reiniciarEstado() {
recebendo = false;
PausarTX = 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* service = static_cast<LoRaService*>(pvParameters);
while (true) {
if (!Conectado || !Configurado || PausarRX) {
vTaskDelay(500);
continue;
}
if (recebendo && (millis() - ultimoByteRecebido > timeoutRecebimentoMs)) {
MostrarLog("Timeout de recebimento. Reiniciando estado.");
reiniciarEstado();
}
while (currentMode == LoRaMode::NORMAL && service->_serialLoRa->available()) {
uint8_t byteRecebido = service->_serialLoRa->read();
ultimoByteRecebido = millis(); // <- atualiza o tempo
MostrarLog("byteRecebido=0x" + String(byteRecebido, HEX));
if (!recebendo) {
if (byteRecebido == CodigosFuncoes::BeginMsg) {
reiniciarEstado();
MostrarLog("Iniciou o recebimento dos dados LoRa");
recebendo = true;
PausarTX = true;
}
}
else {
if (byteRecebido == CodigosFuncoes::BeginMsg) {
MostrarLog("Re-sync: novo BeginMsg detectado durante recepcao");
reiniciarEstado();
recebendo = true;
PausarTX = true;
continue;
}
if (bytesEsperados == -1) {
bytesEsperados = byteRecebido;
//MostrarLog("Definindo bytesEsperados = " + String(bytesEsperados));
}
else if (addrRemetente == -1) {
addrRemetente = byteRecebido;
//MostrarLog("Definindo addrRemetente = " + String(addrRemetente));
}
else if (addrDestinatario == -1) {
addrDestinatario = byteRecebido;
if (addrDestinatario != parametrosAtual.address && addrDestinatario != 0xFF) {
MostrarLog("Mensagem para outro ID, descartando ate EndMsg");
// drenar ate checksum + 0x55 com base em 'bytesEsperados'
size_t toDrain = (bytesEsperados >= 0 ? bytesEsperados + 2 : 0);
for (size_t i = 0; i < toDrain; ++i) {
uint8_t dump;
if (!service->_serialLoRa->available()) break;
dump = service->_serialLoRa->read();
}
reiniciarEstado();
continue;
}
}
else {
buffer.push_back(byteRecebido);
if (bytesEsperados >= 0 && buffer.size() == (size_t)bytesEsperados) {
// tentar ler checksum e EndMsg com timeouts curtinhos
uint32_t t0 = millis();
while (service->_serialLoRa->available() < 2 && (millis() - t0) < 200) {
vTaskDelay(1);
}
if (service->_serialLoRa->available() >= 2) {
uint8_t cks = service->_serialLoRa->read();
uint8_t endb = service->_serialLoRa->read();
buffer.push_back(cks);
buffer.push_back(endb);
}
else {
MostrarLog("Cauda perdida, adicionando manualmente...");
uint8_t soma = 0;
for (size_t i = 0; i < buffer.size(); ++i) {
soma += buffer[i];
}
buffer.push_back(soma);
buffer.push_back(CodigosFuncoes::EndMsg);
}
}
bool protocoloCompleto = addrRemetente != -1 && addrDestinatario != -1 && buffer.size() == bytesEsperados + 2; // +2 = checksum + end
MostrarLog("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) {
MostrarLog("Mensagem LoRa recebida de " + String(addrRemetente) + " com checksum válido");
if (buffer.size() >= 2) {
if (xQueueSend(lraQueueRx, &buffer, 0) != pdTRUE) {
MostrarLog("Fila RX cheia! Mensagem descartada.");
}
else {
MostrarLog("Mensagem adicionada na fila RX");
}
}
} else {
MostrarLog("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 || PausarTX) {
vTaskDelay(500);
continue;
}
if (xQueueReceive(service->lraQueueTx, &msg, portMAX_DELAY) == pdTRUE) {
service->EnviarDadosLoRa(msg);
}
else {
MostrarLog("Erro ao enviar mensagem lora");
}
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 _pinENA;
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 = 800;
bool PausarTX = false;
bool PausarRX = false;
// Métodos internos
void pauseLoRaTasks() {
// pare produtoras de TX e consumidoras de RX antes de mexer no modo
PausarTX = true; // sua flag para impedir enqueue/envio
PausarRX = true; // idem recepção
vTaskDelay(5);
}
void resumeLoRaTasks() {
PausarTX = false;
PausarRX = false;
}
// Define o modo do LoRa
bool setLoRaMode(LoRaMode mode) {
if (mode == currentMode) return true;
pauseLoRaTasks();
// 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;
}
MostrarLog("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) {
MostrarLog("Erro: Timeout aguardando AUX após mudança de modo.");
resumeLoRaTasks();
return false;
}
}
vTaskDelay(100); // Manual pede 2ms após AUX ficar HIGH
resumeLoRaTasks();
return true;
}
// Verifica se o E220 responde
bool checkLoRaConnected() {
MostrarLog("Verificando se o E220 esta conectado...");
if (!setLoRaMode(CONFIG)) {
MostrarLog("Falha ao verificar se o E220 esta conectado, erro 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];
MostrarLog("Tentando BaudRate: " + String(_baudRate));
}
// Limpa buffers antes de testar
limparBufferLoRa();
uint8_t command[1] = { CodigosFuncoes::CfgRx };
enviarDadosSerial(command, 1, "Check Conectado");
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) {
MostrarLog("E220 conectado com baudRate " + String(_baudRate));
} else {
MostrarLog("Falha ao conectar no E220!");
}
return conectado;
}
// Método que monta o comando de configuração
bool configurarModuloLoRa(byte addr, byte baudAndAir, byte packetAndPower, byte channel, byte tranModeAndworCycle) {
MostrarLog("Configurando modulo...");
if (!setLoRaMode(CONFIG)) {
MostrarLog("Falha ao configurar modulo, erro ao mudar para CONFIG!");
return false;
}
limparBufferLoRa();
uint8_t command[9] = {
CodigosFuncoes::CfgTx, // Código para configurar
0x00, // Registro inicial
0x06, // Quantidade de registros
0x00, // AddrH
addr, // addrL
baudAndAir,
packetAndPower,
channel,
tranModeAndworCycle
};
enviarDadosSerial(command, 9, "Config Modulo");
bool sucesso = receberParametrosModulo(command[1], command[2]);
setLoRaMode(NORMAL);
return sucesso;
}
// Método que requisita a leitura dos parâmetros atuais
bool requisitarParametrosLoRa() {
MostrarLog("Requisitando parametros do modulo...");
if (!setLoRaMode(CONFIG)) {
MostrarLog("Falha ao requisitar parametros do modulo, erro ao mudar para CONFIG!");
return false;
}
limparBufferLoRa();
uint8_t command[3] = { CodigosFuncoes::CfgRx, 0x00, 0x0B };
enviarDadosSerial(command, 3, "Requisitar Parametros");
bool sucesso = receberParametrosModulo(command[1], command[2]);
setLoRaMode(NORMAL);
return sucesso;
}
bool readByteWithTimeout(uint8_t &out, unsigned long toMs = 500) {
unsigned long t0 = millis();
while ((millis() - t0) < toMs) {
if (_serialLoRa && _serialLoRa->available()) {
int r = _serialLoRa->read();
if (r >= 0) {
out = (uint8_t)r;
//MostrarLog("0x" + String(out, HEX));
return true;
}
}
// no ESP32 tem FreeRTOS; se preferir, use vTaskDelay(1);
vTaskDelay(1);
}
return false;
}
bool receberParametrosModulo(uint8_t _startAddr, uint8_t _dataLen) {
unsigned long t0 = millis();
// janela total mais folgada p/ rádio
while ((millis() - t0) < 1500UL) {
uint8_t b = 0;
if (!readByteWithTimeout(b, 500)) {
// não chegou nada ainda, segue tentando até estourar 1.5s
continue;
}
if (b == CodigosFuncoes::CfgRx) {
uint8_t startAddr = 0, dataLen = 0;
if (!readByteWithTimeout(startAddr) || !readByteWithTimeout(dataLen)) {
limparBufferLoRa();
return false;
}
if (startAddr == _startAddr && dataLen == _dataLen) {
uint8_t addh=0, addl=0, bAir=0, pwr=0, ch=0, wor=0;
if (!readByteWithTimeout(addh) || !readByteWithTimeout(addl) ||
!readByteWithTimeout(bAir) || !readByteWithTimeout(pwr) ||
!readByteWithTimeout(ch) || !readByteWithTimeout(wor)) {
limparBufferLoRa();
return false;
}
parametrosAtual.address = addl; // assumindo ADDL como address
parametrosAtual.baudAndAirRate = bAir;
parametrosAtual.packetSizeAndPower = pwr;
parametrosAtual.channel = ch;
parametrosAtual.tranModeAndWorCycle = wor;
uint8_t n1 = 0;
uint8_t n2 = 0;
uint8_t n3 = 0;
uint8_t n4 = 0;
uint8_t n5 = 0;
readByteWithTimeout(n1);
readByteWithTimeout(n2);
readByteWithTimeout(n3);
readByteWithTimeout(n4);
readByteWithTimeout(n5);
MostrarLog(
"0x" + String(startAddr, HEX) + " " +
"0x" + String(dataLen, HEX) + " " +
"0x" + String(addh, HEX) + " " +
"0x" + String(addl, HEX) + " " +
"0x" + String(bAir, HEX) + " " +
"0x" + String(pwr, HEX) + " " +
"0x" + String(ch, HEX) + " " +
"0x" + String(wor, HEX) + " " +
"0x" + String(n1, HEX) + " " +
"0x" + String(n2, HEX) + " " +
"0x" + String(n3, HEX) + " " +
"0x" + String(n4, HEX) + " " +
"0x" + String(n5, HEX) + " " +
""
);
return true;
} else {
// endereçamento diferente: drena os bytes anunciados pra limpar o stream
for (int i = 0; i < dataLen; i++) {
uint8_t dump;
if (!readByteWithTimeout(dump)) break;
}
}
} else if (b == CodigosFuncoes::WrongMode) {
MostrarLog("Resposta WrongMode");
// opcional: logar que o módulo respondeu “modo errado”
// e talvez sair para re-tentar setLoRaMode(CONFIG)
}
// senão, segue laçando e coletando até bater timeout total
}
limparBufferLoRa(); // garantir que não fique lixo
return false;
}
void enviarDadosSerial(const uint8_t* dados, int tamanho, const String& descricao = "") {
if (!_serialLoRa) return;
while (digitalRead(_pinAUX) == LOW) { }
_serialLoRa->write(dados, tamanho);
//_serialLoRa->flush();
uint32_t t0 = millis();
while (digitalRead(_pinAUX) == HIGH && (millis()-t0) < 50) { }
while (digitalRead(_pinAUX) == LOW && (millis()-t0) < 200) { }
delayMicroseconds(1500); // ~12 ms entre frames curtos @9600
if (DebugMode) {
String log = "Enviando [" + descricao + "] (" + String(tamanho) + " bytes): ";
for (size_t i = 0; i < tamanho; i++) {
log += "0x" + String(dados[i], HEX) + " ";
}
MostrarLog(log);
}
}
// 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)
if (destino == 0xFF) {
frame.push_back(0xFF);
frame.push_back(0xFF);
}
else {
frame.push_back((destino >> 8) & 0xFF);
frame.push_back(destino & 0xFF);
}
frame.push_back(static_cast<uint8_t>(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
String log = "Frame LoRa montado: ";
for (int i = 0; i < frame.size(); i++) {
log += "0x" + String(frame[i], HEX) + " ";
}
MostrarLog(log);
return frame;
}
bool EnviarDadosCAN(std::vector<uint8_t> dados) {
_canService->adicionarMensagemFila(dados);
return true;
}
bool EnviarDadosLoRa(std::vector<uint8_t> dados) {
MostrarLog("Enviando dados via LoRa para o endereco 0x" + String(AddressBase, HEX) + " no canal 0x" + String(parametrosAtual.channel, HEX));
std::vector<uint8_t> dadosLora = MontarFrameLoRa(AddressBase, parametrosAtual.channel, dados);
enviarDadosSerial(dadosLora.data(), dadosLora.size(), "Dados LoRa");
//vTaskDelay(pdMS_TO_TICKS(tempoEntreEnvios));
return true;
}
std::map<int, uint8_t> CodigosBaudRates = {
{1200, 0x00},
{2400, 0x20},
{4800, 0x40},
{9600, 0x60},
{19200, 0x80},
{38400, 0xA0},
{57600, 0xC0},
{115200, 0xE0},
};
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