699 lines
27 KiB
C#
699 lines
27 KiB
C#
using AgroBase.Models;
|
|
using AgroMonitor;
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.IO.Ports;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using static AgroBase.Models.Enums;
|
|
using static AgroBase.Services.LoRaEspService;
|
|
|
|
namespace AgroBase.Services
|
|
{
|
|
public class LoRaBaseService
|
|
{
|
|
public static SerialPort _PortaLoRa;
|
|
public static bool Iniciado
|
|
{
|
|
get
|
|
{
|
|
if (_PortaLoRa != null && !_PortaLoRa.IsOpen)
|
|
{
|
|
try
|
|
{
|
|
_PortaLoRa.Open();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine(ex.Message);
|
|
_PortaLoRa = null;
|
|
}
|
|
}
|
|
return _PortaLoRa != null && _PortaLoRa.IsOpen;
|
|
}
|
|
}
|
|
|
|
private static DateTime UltimaLeituraMensagem = DateTime.Now.AddMinutes(-1);
|
|
|
|
private static AsyncTaskTimerModel tmrLeitura;
|
|
private static AsyncTaskTimerModel tmrProcessamento;
|
|
private static ConcurrentQueue<byte[]> _filaTx = new ConcurrentQueue<byte[]>();
|
|
private static readonly ConcurrentQueue<(bool, byte[])> _filaRx = new ConcurrentQueue<(bool, byte[])>();
|
|
private static List<byte> _bufferAtual = new List<byte>();
|
|
private static bool _recebendo = false;
|
|
private static DateTime _inicioRecepcao;
|
|
private static TipoRecepcao _tipoAtual = TipoRecepcao.Nenhum;
|
|
private static int _tamanhoEsperadoConfig = 0;
|
|
private enum TipoRecepcao
|
|
{
|
|
Nenhum,
|
|
Config,
|
|
Mensagem
|
|
}
|
|
|
|
public static Dictionary<string, byte> CodigosFuncoes = new Dictionary<string, byte>()
|
|
{
|
|
{ "ComandoConfiguracao", 0xc0 },
|
|
{ "RespostaConfiguracao", 0xc1 },
|
|
{ "Mensagem", 0xe1 },
|
|
};
|
|
public static Dictionary<string, byte> CodigosTipoTransmissao = new Dictionary<string, byte>()
|
|
{
|
|
{ "Normal", 0x00 },
|
|
{ "Fixed", 0x40 },
|
|
};
|
|
public static Dictionary<int, byte> CodigosBaudRates = new Dictionary<int, byte>()
|
|
{
|
|
{ 1200, 0x00 },
|
|
{ 2400, 0x20 },
|
|
{ 4800, 0x40 },
|
|
{ 9600, 0x60 },
|
|
{ 19200, 0x80 },
|
|
{ 38400, 0xa0 },
|
|
{ 57600, 0xc0 },
|
|
{ 115200, 0xe0 },
|
|
};
|
|
public static Dictionary<double, byte> CodigosAirRates = new Dictionary<double, byte>()
|
|
{
|
|
{ 2.4, 0x00 },
|
|
{ 4.8, 0x01 },
|
|
{ 9.6, 0x02 },
|
|
{ 19.2, 0x03 },
|
|
{ 38.4, 0x04 },
|
|
{ 62.5, 0x05 },
|
|
};
|
|
public static Dictionary<int, byte> CodigosPacketSizes = new Dictionary<int, byte>()
|
|
{
|
|
{ 200, 0x00 },
|
|
{ 128, 0x40 },
|
|
{ 64, 0x80 },
|
|
{ 32, 0xc0 },
|
|
};
|
|
public static Dictionary<int, byte> CodigosWorCycles = new Dictionary<int, byte>()
|
|
{
|
|
{ 500, 0x00 },
|
|
{ 1000, 0x01 },
|
|
{ 1500, 0x02 },
|
|
{ 2000, 0x03 },
|
|
{ 2500, 0x04 },
|
|
{ 3000, 0x05 },
|
|
{ 3500, 0x06 },
|
|
{ 4000, 0x07 },
|
|
};
|
|
public static Dictionary<int, byte> CodigosPowers = new Dictionary<int, byte>()
|
|
{
|
|
{ 22, 0x00 },
|
|
{ 17, 0x01 },
|
|
{ 13, 0x02 },
|
|
{ 10, 0x03 },
|
|
};
|
|
private static List<LoRaMensagemModel> MensagensRecebidas = new List<LoRaMensagemModel>();
|
|
|
|
public static LoRaParametrosModel parametrosModel { get; set; } = new LoRaParametrosModel()
|
|
{
|
|
address = 0x01,
|
|
channel = 0x41,
|
|
tranMode = CodigosTipoTransmissao["Fixed"],
|
|
baudRate = CodigosBaudRates[9600],
|
|
airRate = CodigosAirRates[2.4],
|
|
packetSize = CodigosPacketSizes[32],
|
|
worCycle = CodigosWorCycles[2000],
|
|
power = CodigosPowers[22],
|
|
};
|
|
|
|
public static LoRaMensagemModel MensagemPendente
|
|
{
|
|
get
|
|
{
|
|
if (MensagensRecebidas.Any(x => !x.Lido && x.Momento > UltimaLeituraMensagem))
|
|
{
|
|
var Mensagem = MensagensRecebidas.OrderBy(x => x.Momento).Where(x => !x.Lido && x.Momento > UltimaLeituraMensagem).FirstOrDefault();
|
|
Mensagem.Lido = true;
|
|
return Mensagem;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
public static int MensagensEnviadas { get; set; } = 0;
|
|
public static readonly object _dadosOperacaoLock = new object();
|
|
public static List<LoRaProtocoloTransmissaoModel> LeituraDadosOperacao = new List<LoRaProtocoloTransmissaoModel>();
|
|
|
|
private static AsyncTaskTimerModel tmrEnvio;
|
|
private static AsyncTaskTimerModel tmrPing;
|
|
|
|
|
|
public static async Task<bool> VerificaPortaLoRa(SerialPort porta)
|
|
{
|
|
if (!(tmrLeitura?.IsRunning ?? false))
|
|
{
|
|
tmrLeitura = new AsyncTaskTimerModel("tmrLeitura_LoRa", tmrLeitura_Tick, 5);
|
|
tmrLeitura.Start();
|
|
}
|
|
if (!(tmrProcessamento?.IsRunning ?? false))
|
|
{
|
|
tmrProcessamento = new AsyncTaskTimerModel("tmrProcessamento_LoRa", tmrProcessamento_Tick, 10);
|
|
tmrProcessamento.Start();
|
|
}
|
|
|
|
porta.Close();
|
|
|
|
_PortaLoRa = new SerialPort();
|
|
_PortaLoRa.BaudRate = 9600;
|
|
_PortaLoRa.PortName = porta.PortName;
|
|
|
|
var comando = ComandoRequisitarParametros();
|
|
|
|
DateTime Inicio = DateTime.Now;
|
|
|
|
if (!EnviarComando(comando))
|
|
{
|
|
_PortaLoRa.Close();
|
|
return false;
|
|
}
|
|
|
|
bool Respondido() => parametrosModel.UltimaLeitura > Inicio;
|
|
await FuncoesGlobais.AguardarCondicaoAsync(Respondido, 1000, 100);
|
|
|
|
if (Respondido())
|
|
{
|
|
DefinirDispositivo();
|
|
return Iniciado;
|
|
}
|
|
|
|
_PortaLoRa.Close();
|
|
_PortaLoRa = null;
|
|
|
|
return false;
|
|
}
|
|
|
|
private static void DefinirDispositivo()
|
|
{
|
|
SerialService.DispositivosMapeados.Add(new DispositivoDetalhesModel()
|
|
{
|
|
Dispositivo = T_Code.Lra,
|
|
Endereco = _PortaLoRa.PortName,
|
|
Versao = "220"
|
|
});
|
|
|
|
IniciarRotinas();
|
|
}
|
|
|
|
public static void IniciarRotinas()
|
|
{
|
|
PararRotinas();
|
|
|
|
tmrEnvio = new AsyncTaskTimerModel("tmrEnvio", tmrEnvio_Tick, 50);
|
|
tmrEnvio.Start();
|
|
|
|
tmrPing = new AsyncTaskTimerModel("tmrPing", tmrPing_Tick, VariaveisEquipamento.TempoEntrePingsConexao);
|
|
tmrPing.Start();
|
|
}
|
|
|
|
public static void PararRotinas()
|
|
{
|
|
tmrEnvio?.Dispose();
|
|
tmrPing?.Dispose();
|
|
}
|
|
|
|
private static async Task tmrLeitura_Tick()
|
|
{
|
|
while ((_PortaLoRa?.IsOpen ?? false) && (_PortaLoRa?.BytesToRead ?? 0) > 0)
|
|
{
|
|
byte b = (byte)_PortaLoRa.ReadByte();
|
|
|
|
if (!_recebendo)
|
|
{
|
|
if (b == CodigosFuncoes["RespostaConfiguracao"])
|
|
{
|
|
_recebendo = true;
|
|
_bufferAtual.Clear();
|
|
_bufferAtual.Add(b);
|
|
_tipoAtual = TipoRecepcao.Config;
|
|
_inicioRecepcao = DateTime.Now;
|
|
}
|
|
else if (b == (byte)LoRaCaracteresEspeciais.BeginMsg)
|
|
{
|
|
_recebendo = true;
|
|
_bufferAtual.Clear();
|
|
_bufferAtual.Add(b);
|
|
_tipoAtual = TipoRecepcao.Mensagem;
|
|
_inicioRecepcao = DateTime.Now;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_bufferAtual.Add(b);
|
|
|
|
if (_tipoAtual == TipoRecepcao.Config)
|
|
{
|
|
if (_bufferAtual.Count == 3)
|
|
{
|
|
_tamanhoEsperadoConfig = _bufferAtual[2];
|
|
}
|
|
else if (_bufferAtual.Count == 3 + _tamanhoEsperadoConfig)
|
|
{
|
|
_filaRx.Enqueue((true, _bufferAtual.ToArray()));
|
|
_bufferAtual.Clear();
|
|
_recebendo = false;
|
|
_tipoAtual = TipoRecepcao.Nenhum;
|
|
}
|
|
}
|
|
else if (_tipoAtual == TipoRecepcao.Mensagem)
|
|
{
|
|
if (b == (byte)LoRaCaracteresEspeciais.EndMsg)
|
|
{
|
|
_filaRx.Enqueue((false, _bufferAtual.ToArray()));
|
|
_bufferAtual.Clear();
|
|
_recebendo = false;
|
|
_tipoAtual = TipoRecepcao.Nenhum;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ⏱️ Timeout de segurança
|
|
if (_recebendo && (DateTime.Now - _inicioRecepcao).TotalMilliseconds > 500)
|
|
{
|
|
_bufferAtual.Clear();
|
|
_recebendo = false;
|
|
_tipoAtual = TipoRecepcao.Nenhum;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task tmrProcessamento_Tick()
|
|
{
|
|
while (_filaRx.TryDequeue(out var item))
|
|
{
|
|
if (item.Item1)
|
|
{
|
|
ProcessarRespostaConfiguracao(item.Item2);
|
|
}
|
|
else
|
|
{
|
|
ProcessarMensagemLoRaCAN(item.Item2);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static async Task tmrEnvio_Tick()
|
|
{
|
|
if (_filaTx.TryDequeue(out var buffer))
|
|
{
|
|
EnviarComando(buffer);
|
|
await Task.Delay(100);
|
|
}
|
|
}
|
|
|
|
private static void ProcessarRespostaConfiguracao(byte[] buffer)
|
|
{
|
|
Console.WriteLine($"Dados de parametrizacao recebidos do modulo: {FuncoesGlobais.ConverterComandoBytesParaTexto(buffer)}");
|
|
|
|
int numBytes = buffer[2];
|
|
if (numBytes != 6 && numBytes != 11)
|
|
{
|
|
Console.WriteLine("Número de bytes de dados não esperado.");
|
|
return;
|
|
}
|
|
|
|
byte[] data = buffer;
|
|
|
|
byte address = data[4];
|
|
byte baudAndAirRate = data[5];
|
|
byte baud = (byte)(baudAndAirRate & 0b11100000);
|
|
byte airRate = (byte)((baudAndAirRate & 0b00011100) >> 2);
|
|
byte packetSizeAndPower = data[6];
|
|
byte packetSize = (byte)((packetSizeAndPower & 0b11000000));
|
|
byte power = (byte)(packetSizeAndPower & 0b00000011);
|
|
byte channel = data[7];
|
|
byte tranModeAndWorCycle = data[8];
|
|
byte tranMode = (byte)(tranModeAndWorCycle & 0b01000000);
|
|
byte worCycle = (byte)(tranModeAndWorCycle & 0b00000111);
|
|
|
|
if (parametrosModel == null)
|
|
{
|
|
parametrosModel = new LoRaParametrosModel();
|
|
}
|
|
|
|
parametrosModel.address = address;
|
|
parametrosModel.baudRate = baud;
|
|
parametrosModel.airRate = airRate;
|
|
parametrosModel.packetSize = packetSize;
|
|
parametrosModel.power = power;
|
|
parametrosModel.channel = channel;
|
|
parametrosModel.tranMode = tranMode;
|
|
parametrosModel.worCycle = worCycle;
|
|
|
|
parametrosModel.UltimaLeitura = DateTime.Now;
|
|
|
|
Console.WriteLine("Parâmetros atualizados com sucesso.");
|
|
}
|
|
|
|
private static void ProcessarMensagemLoRaCAN(byte[] mensagem)
|
|
{
|
|
if (mensagem.Length < 6) return; // Tamanho mínimo: Begin + Size + Remetente + Dest + Check + End
|
|
|
|
byte size = mensagem[1];
|
|
if (mensagem.Length != size + 6) return; // Tamanho real esperado
|
|
|
|
byte remetente = mensagem[2];
|
|
byte destinatario = mensagem[3];
|
|
byte[] dados = mensagem.Skip(4).Take(size).ToArray();
|
|
byte checksum = mensagem[4 + size];
|
|
byte end = mensagem[5 + size];
|
|
|
|
if (checksum != (byte)(dados.Sum(x => x) % 256)) return;
|
|
if (end != (byte)LoRaCaracteresEspeciais.EndMsg) return;
|
|
|
|
// Aqui você pode aplicar a lógica CAN-style, como extrair posição, idNum, etc.
|
|
// Exemplo:
|
|
if (dados.Length >= 2)
|
|
{
|
|
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)dados[0];
|
|
byte idNum = dados[1];
|
|
|
|
Console.WriteLine($"Dados LoRa recebidos do rover {posicao.ToString()} ({((DadosLoRaParse)posicao).ToString()}) " + string.Join(" ", dados));
|
|
|
|
LoRaProtocoloTransmissaoModel equipamento = LeituraDadosOperacao.FirstOrDefault(x => x.EnderecoCarro == remetente);
|
|
if (equipamento == null)
|
|
{
|
|
equipamento = new LoRaProtocoloTransmissaoModel()
|
|
{
|
|
EnderecoCarro = remetente,
|
|
Coordenadas = new LoRaProtocoloTransmissaoCoordenadasModel(),
|
|
CodigoFalha = 0,
|
|
Momento = DateTime.Now,
|
|
Operacao = new LoRaProtocoloTransmissaoOperacaoModel(),
|
|
Sensores = new LoRaProtocoloTransmissaoSensoresModel(),
|
|
RecebidoEm = DateTime.Now,
|
|
};
|
|
LeituraDadosOperacao.Add(equipamento);
|
|
}
|
|
|
|
equipamento.RecebidoEm = DateTime.Now;
|
|
|
|
switch ((DadosLoRaParse)posicao)
|
|
{
|
|
case DadosLoRaParse.GpsLatitude:
|
|
{
|
|
equipamento.Coordenadas.Latitude = LoRaSerializer.DescompactarCoordenada(dados.Skip(2).ToArray());
|
|
break;
|
|
}
|
|
case DadosLoRaParse.GpsLongitude:
|
|
{
|
|
equipamento.Coordenadas.Longitude = LoRaSerializer.DescompactarCoordenada(dados.Skip(2).ToArray());
|
|
break;
|
|
}
|
|
case DadosLoRaParse.GpsGerais:
|
|
{
|
|
double _altitude = LoRaSerializer.DescompactarDecimal(dados, 2);
|
|
double _velocidade = LoRaSerializer.DescompactarDecimal(dados, 4);
|
|
double _orientacao = LoRaSerializer.DescompactarDecimal(dados, 6);
|
|
|
|
equipamento.Coordenadas.Orientacao = _orientacao;
|
|
equipamento.Coordenadas.Altitude = _altitude;
|
|
equipamento.Coordenadas.Velocidade = _velocidade;
|
|
break;
|
|
}
|
|
case DadosLoRaParse.GpsQualidade:
|
|
{
|
|
bool _inicializado = dados[2] == 1;
|
|
TiposCorrecaoGPS _fix = (TiposCorrecaoGPS)((int)dados[3]);
|
|
int _n_satelites = (int)dados[4];
|
|
double _precisao = LoRaSerializer.DescompactarDecimal(dados, 5);
|
|
|
|
equipamento.Coordenadas.Inicializado = _inicializado;
|
|
equipamento.Coordenadas.Correcao = _fix;
|
|
equipamento.Coordenadas.NSatelites = _n_satelites;
|
|
equipamento.Coordenadas.Precisao = _precisao;
|
|
break;
|
|
}
|
|
case DadosLoRaParse.ComandoControle:
|
|
{
|
|
Direcao _direcao = (Direcao)((int)dados[2]);
|
|
int _velocidade_sp =(int)dados[3];
|
|
TipoMovimentoDirecional _tipo = (TipoMovimentoDirecional)((int)dados[4]);
|
|
int _angulo_sp = (int)dados[5];
|
|
int _velocidade_mp = (int)dados[6];
|
|
|
|
equipamento.Controle.direcao = _direcao;
|
|
equipamento.Controle.percentual_velocidade_sp = _velocidade_sp;
|
|
equipamento.Controle.tipo_movimento = _tipo;
|
|
equipamento.Controle.angulo_sp = _angulo_sp;
|
|
equipamento.Controle.velocidade_mp = _velocidade_mp;
|
|
break;
|
|
}
|
|
case DadosLoRaParse.DadosOperacao:
|
|
{
|
|
StatusOperacao _status_operacao = (StatusOperacao)((int)dados[2]);
|
|
StatusCarroMapa _status_carro = (StatusCarroMapa)((int)dados[3]);
|
|
int _percentual_operacao = (int)dados[4];
|
|
int _percentual_rua = (int)dados[5];
|
|
int _idx_rua = (int)dados[6];
|
|
|
|
equipamento.Operacao.statusOperacao = _status_operacao;
|
|
equipamento.Operacao.statusCarro = _status_carro;
|
|
equipamento.Operacao.PercentualOperacao = _percentual_operacao;
|
|
equipamento.Operacao.PercentualRua = _percentual_rua;
|
|
equipamento.Operacao.idxRuaAtual = _idx_rua;
|
|
break;
|
|
}
|
|
case DadosLoRaParse.DadosSensores:
|
|
{
|
|
int _percentual_bateria = (int)dados[2];
|
|
int _temperatura_motores = (int)dados[3];
|
|
int _temperatura_campo = (int)dados[4];
|
|
int _distancia_percorrida = (int)dados[5];
|
|
int _velocidade = (int)dados[6];
|
|
|
|
equipamento.Sensores.PercentualBateria = _percentual_bateria;
|
|
equipamento.Sensores.TemperaturaMotores = _temperatura_motores;
|
|
equipamento.Sensores.TemperaturaCampo = _temperatura_campo;
|
|
equipamento.Sensores.DistanciaPercorrida = _distancia_percorrida;
|
|
equipamento.Sensores.Velocidade = _velocidade;
|
|
break;
|
|
}
|
|
case DadosLoRaParse.DadosPulverizador:
|
|
{
|
|
int _percentual_reservatorio = dados.Length < 3 ? 0 : (int)dados[2];
|
|
int _pressao_linha = dados.Length < 4 ? 0 : (int)dados[3];
|
|
int _ervas_identificadas = dados.Length < 5 ? 0 : (int)dados[4];
|
|
int _herbicida_consumido = dados.Length < 6 ? 0 : (int)dados[5];
|
|
int _herbicida_por_erva = dados.Length < 7 ? 0 : (int)dados[6];
|
|
int _percentual_ervas_terreno = dados.Length < 8 ? 0 : (int)dados[7];
|
|
|
|
equipamento.Sensores.PercentualReservatorio = _percentual_reservatorio;
|
|
equipamento.Sensores.PressaoLinha = _pressao_linha;
|
|
equipamento.Sensores.ErvasIdentificadas = _ervas_identificadas;
|
|
equipamento.Sensores.HerbicidaConsumido = _herbicida_consumido;
|
|
equipamento.Sensores.HerbicidaPorErva = _herbicida_por_erva;
|
|
equipamento.Sensores.PercentualErvasTerreno = _percentual_ervas_terreno;
|
|
break;
|
|
}
|
|
case DadosLoRaParse.DadosControle:
|
|
{
|
|
|
|
break;
|
|
}
|
|
case DadosLoRaParse.DadosLivre:
|
|
{
|
|
MensagensRecebidas.Add(new LoRaMensagemModel()
|
|
{
|
|
channel = parametrosModel.channel,
|
|
Destinatario = destinatario,
|
|
Remetente = remetente,
|
|
Data = dados,
|
|
Lido = false,
|
|
Momento = DateTime.Now,
|
|
Mensagem = string.Join("", dados.Select(x => x.ToString("X")))
|
|
});
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public static async Task<(bool, LoRaParametrosModel)> RequisitarParametrosModuloAsync()
|
|
{
|
|
byte[] command = ComandoRequisitarParametros();
|
|
DateTime inicio = DateTime.Now;
|
|
|
|
// Envia o comando para a porta COM
|
|
EnviarComando(command);
|
|
|
|
bool Respondido() => parametrosModel.UltimaLeitura > inicio;
|
|
await FuncoesGlobais.AguardarCondicaoAsync(Respondido, 1000, 100);
|
|
|
|
return (Respondido(), parametrosModel);
|
|
}
|
|
|
|
public static async Task<(bool, LoRaParametrosModel)> ConfigurarModuloAsync(LoRaParametrosModel Parametros)
|
|
{
|
|
parametrosModel = Parametros;
|
|
|
|
byte[] command = ComandoConfigurarModulo();
|
|
Console.WriteLine($"Comando de configuracao do LoRa enviado: {FuncoesGlobais.ConverterComandoBytesParaTexto(command)}");
|
|
DateTime inicio = DateTime.Now;
|
|
|
|
// Envia o comando para a porta COM
|
|
EnviarComando(command);
|
|
|
|
bool Respondido() => parametrosModel.UltimaLeitura > inicio;
|
|
await FuncoesGlobais.AguardarCondicaoAsync(Respondido, 1000, 100);
|
|
|
|
if (Respondido())
|
|
{
|
|
return (true, parametrosModel);
|
|
}
|
|
else
|
|
{
|
|
return (false, null);
|
|
}
|
|
}
|
|
|
|
public static List<byte[]> EnviarDadosLoRa(byte[] bytes, byte targetAddress)
|
|
{
|
|
List<byte[]> Partes = new List<byte[]>();
|
|
|
|
byte addressHigh = (byte)(targetAddress == 0xFF ? 0xFF : 0x00);
|
|
byte channel = parametrosModel.channel;
|
|
byte remetente = parametrosModel.address;
|
|
|
|
int maxPacketSize = CodigosPacketSizes.FirstOrDefault(x => x.Value == parametrosModel.packetSize).Key - 10;
|
|
int overhead = 1 + 1 + 1 + 1 + 1 + 1; // Begin + Size + Remetente + Dest + Checksum + End
|
|
int maxDataLength = maxPacketSize - overhead;
|
|
|
|
for (int i = 0; i < bytes.Length; i += maxDataLength)
|
|
{
|
|
int length = Math.Min(maxDataLength, bytes.Length - i);
|
|
byte[] dataFragment = new byte[length];
|
|
Array.Copy(bytes, i, dataFragment, 0, length);
|
|
|
|
byte checksum = (byte)(dataFragment.Sum(b => b) % 256);
|
|
|
|
byte prefix = (byte)LoRaCaracteresEspeciais.BeginMsg;
|
|
byte suffix = (byte)LoRaCaracteresEspeciais.EndMsg;
|
|
byte dataSize = (byte)dataFragment.Length;
|
|
|
|
byte[] mensagem = new byte[3 + 1 + 1 + 1 + 1 + length + 1 + 1]; // 3 físicos + protocolo
|
|
mensagem[0] = addressHigh;
|
|
mensagem[1] = targetAddress;
|
|
mensagem[2] = channel;
|
|
|
|
mensagem[3] = prefix;
|
|
mensagem[4] = dataSize;
|
|
mensagem[5] = remetente;
|
|
mensagem[6] = targetAddress;
|
|
|
|
Array.Copy(dataFragment, 0, mensagem, 7, length);
|
|
mensagem[7 + length] = checksum;
|
|
mensagem[8 + length] = suffix;
|
|
|
|
Partes.Add(mensagem);
|
|
}
|
|
|
|
foreach (var parte in Partes)
|
|
{
|
|
_filaTx.Enqueue(parte);
|
|
}
|
|
|
|
return Partes;
|
|
}
|
|
|
|
|
|
|
|
private static bool EnviarComando(byte[] Comando)
|
|
{
|
|
try
|
|
{
|
|
if (_PortaLoRa != null)
|
|
{
|
|
if (!_PortaLoRa.IsOpen)
|
|
{
|
|
_PortaLoRa.Open();
|
|
}
|
|
if (_PortaLoRa.IsOpen)
|
|
{
|
|
Console.WriteLine($"Dados enviados LoRa: {Comando.Length}");
|
|
MensagensEnviadas++;
|
|
return SerialService.EnviarDadosPortaSerial(_PortaLoRa, Comando, 0, Comando.Length);
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static byte[] ComandoConfigurarModulo()
|
|
{
|
|
byte[] command = new byte[] {
|
|
CodigosFuncoes["ComandoConfiguracao"],
|
|
0x00,
|
|
0x06,
|
|
0x00,
|
|
parametrosModel.address,
|
|
parametrosModel.baudAndAirRate,
|
|
parametrosModel.packetSizeAndPower,
|
|
parametrosModel.channel,
|
|
parametrosModel.tranModeAndWorCycle,
|
|
};
|
|
return command;
|
|
}
|
|
|
|
public static byte[] ComandoRequisitarParametros()
|
|
{
|
|
// caractere GET parametros, iniciando em qual registrador, quantidade registros
|
|
byte[] command = new byte[] { CodigosFuncoes["RespostaConfiguracao"], 0x00, 0x0b };
|
|
return command;
|
|
}
|
|
|
|
|
|
public static async Task tmrPing_Tick()
|
|
{
|
|
if (VariaveisMonitoramento.EnviarDadosEmBroadcast)
|
|
{
|
|
EnviarDadosPosicao();
|
|
}
|
|
else
|
|
{
|
|
foreach (var Equipamento in VariaveisMonitoramento.EquipamentosConectados.Where(x => x.Key != parametrosModel.address))
|
|
{
|
|
EnviarDadosPosicao(Equipamento.Key);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void EnviarDadosPosicao(byte EnderecoDestinatario = 0xFF)
|
|
{
|
|
if (Iniciado)
|
|
{
|
|
List<byte[]> dadosEnvio = LoRaSerializer.SerializeGPS(GPSService.UltimaLeitura);
|
|
|
|
foreach (var payload in dadosEnvio)
|
|
{
|
|
EnviarDadosLoRa(payload, EnderecoDestinatario);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void EnviarDadosComandoControle(OperacaoControleBaseModel Controle, byte EnderecoDestinatario)
|
|
{
|
|
if (Iniciado)
|
|
{
|
|
byte[] dadosEnvio = LoRaSerializer.SerializeComandoControle(Controle);
|
|
|
|
EnviarDadosLoRa(dadosEnvio, EnderecoDestinatario);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|