4327 lines
184 KiB
C#
4327 lines
184 KiB
C#
using AgroBase.Services;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using static AgroBase.Models.Enums;
|
|
using System.Globalization;
|
|
using Newtonsoft.Json;
|
|
|
|
namespace AgroBase.Models.Modules
|
|
{
|
|
public class SensoriamentoModel : DispositivoBaseModel
|
|
{
|
|
public T_Code Dispositivo { get; set; } = T_Code.Sen;
|
|
public string Modulo_ID { get; set; } = T_Code.Sen.ToString();
|
|
public byte _EnderecoCAN_Tx { get; set; } = 0x11;
|
|
public byte _EnderecoCAN_Rx { get; set; } = 0x11;
|
|
public int _TaxaAmostragem { get; set; } = 1000;
|
|
public double FrequenciaBase
|
|
{
|
|
get
|
|
{
|
|
return _TaxaAmostragem > 0
|
|
? 1000.0 / _TaxaAmostragem
|
|
: 0.0;
|
|
}
|
|
}
|
|
public bool RequisitarDados { get; set; } = true;
|
|
public static int TempoLimiteConexao { get; set; } = 8000;
|
|
private const int IntervaloDescobertaDesconectadoMs = 2000;
|
|
private const int IntervaloReenvioComandoMs = 1500;
|
|
private readonly object _estadoLock = new object();
|
|
private readonly object _registradorLock = new object();
|
|
private DateTime _ultimaDescobertaEnviada = DateTime.MinValue;
|
|
private DateTime _ultimaRespostaDescoberta = DateTime.MinValue;
|
|
|
|
[JsonIgnore]
|
|
internal object EstadoSyncRoot => _estadoLock;
|
|
|
|
[JsonIgnore]
|
|
private bool ModeloRuntimeAtivo =>
|
|
ReferenceEquals(Variaveis.OperacaoEmAndamento?.DispSen?.Dados, this);
|
|
|
|
public bool Conectado
|
|
{
|
|
get
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
DateTime agora = DateTime.Now;
|
|
return DadosLeitura != null &&
|
|
DadosLeitura.UltimoComandoRespondido != DateTime.MinValue &&
|
|
DadosLeitura.UltimoComandoRespondido.AddMilliseconds(Math.Max(1, TempoLimiteConexao)) > agora;
|
|
}
|
|
}
|
|
}
|
|
|
|
[JsonIgnore]
|
|
public bool TelemetriaRecente => Conectado;
|
|
|
|
[JsonIgnore]
|
|
public bool FirmwareDeclarouConectado
|
|
{
|
|
get
|
|
{
|
|
lock (_estadoLock)
|
|
return DadosLeitura?.Conectado == true;
|
|
}
|
|
}
|
|
|
|
[JsonIgnore]
|
|
internal bool ModuloIdentificado
|
|
{
|
|
get
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
return _ultimaRespostaDescoberta != DateTime.MinValue &&
|
|
DadosLeitura?.Dispositivo == Dispositivo;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool ConexaoAtiva => TelemetriaRecente;
|
|
public SensoriamentoMensagemJsonModel DadosLeitura { get; set; } = new SensoriamentoMensagemJsonModel();
|
|
public static PinoutDataModel Pinout { get; set; }
|
|
public static List<FuncoesPinout> Funcoes { get; set; } = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.SDA,
|
|
FuncoesPinout.SCL,
|
|
};
|
|
public List<SensorModel> Sensores { get; set; }
|
|
public List<SensorSinaleiroModel> Sinaleiros { get; set; }
|
|
public List<SensorReleModel> Reles { get; set; }
|
|
public List<SensorServoModel> Servos { get; set; }
|
|
public UltrasonicA05Configuracoes ConfiguracaoSensorUltrassom { get; set; }
|
|
|
|
[JsonIgnore]
|
|
private readonly SenHandler _SenHandler = new SenHandler();
|
|
|
|
public CoulombCounterService ContadorCarga = new CoulombCounterService(VariaveisEquipamento.CorrenteMaximaBateria);
|
|
public CoolerControlService CoolerControl = new CoolerControlService();
|
|
|
|
[JsonIgnore]
|
|
public AsyncTaskTimerModel tmrRegistrador;
|
|
private int _TempoReconexaoComponentes = 5;
|
|
private int _VezesLeituraReconexao = 0;
|
|
|
|
public static SensoriamentoModel CarregarParametrosIniciais()
|
|
{
|
|
var obj = new SensoriamentoModel()
|
|
{
|
|
_EnderecoCAN_Tx = 0x11,
|
|
_EnderecoCAN_Rx = 0x11,
|
|
_TaxaAmostragem = 1000,
|
|
RequisitarDados = true,
|
|
// 21 ~ 23
|
|
Sinaleiros = new List<SensorSinaleiroModel>()
|
|
{
|
|
new SensorSinaleiroModel()
|
|
{
|
|
ID = "LEDMN",
|
|
ID_Num = 21,
|
|
Descricao = "Sinaleiro indicação de modo Manual ativo",
|
|
Componente = S_Code.sLED,
|
|
Controlar = true,
|
|
Mandatorio = true,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Sinaleiro,
|
|
},
|
|
Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Apagado),
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.StatusLedID,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.StatusLedLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
},
|
|
}
|
|
},
|
|
new SensorSinaleiroModel()
|
|
{
|
|
ID = "LEDAT",
|
|
ID_Num = 22,
|
|
Descricao = "Sinaleiro indicação de modo Automático ativo",
|
|
Componente = S_Code.sLED,
|
|
Controlar = true,
|
|
Mandatorio = true,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Sinaleiro,
|
|
},
|
|
Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Apagado),
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.StatusLedID,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.StatusLedLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
},
|
|
}
|
|
},
|
|
new SensorSinaleiroModel()
|
|
{
|
|
ID = "LEDOP",
|
|
ID_Num = 23,
|
|
Descricao = "Sinaleiro indicação do status da operação ativa",
|
|
Componente = S_Code.sLED,
|
|
Controlar = true,
|
|
Mandatorio = true,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Sinaleiro,
|
|
},
|
|
Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Apagado),
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.StatusLedID,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.StatusLedLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
},
|
|
}
|
|
},
|
|
},
|
|
Sensores = new List<SensorModel>()
|
|
{
|
|
// sTMP 1 ~ 5
|
|
new SensorModel()
|
|
{
|
|
ID = "TMVET",
|
|
Descricao = "Temperatura Motor Esquerdo Trás",
|
|
ID_Num = 1,
|
|
Componente = S_Code.sNTC,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.TMP,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 80,
|
|
minimo = 5,
|
|
nominal = 25,
|
|
unidade_medida = "ºC",
|
|
offset = -39.9,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "TMVEF",
|
|
Descricao = "Temperatura Motor Esquerdo Frente",
|
|
ID_Num = 2,
|
|
Componente = S_Code.sNTC,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.TMP,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 80,
|
|
minimo = 5,
|
|
nominal = 25,
|
|
unidade_medida = "ºC",
|
|
offset = -0.5,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "TMVDT",
|
|
Descricao = "Temperatura Motor Direito Trás",
|
|
ID_Num = 3,
|
|
Componente = S_Code.sNTC,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.TMP,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 80,
|
|
minimo = 5,
|
|
nominal = 25,
|
|
unidade_medida = "ºC",
|
|
offset = -15.9,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "TMVDF",
|
|
Descricao = "Temperatura Motor Direito Frente",
|
|
ID_Num = 4,
|
|
Componente = S_Code.sNTC,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.TMP,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 80,
|
|
minimo = 5,
|
|
nominal = 25,
|
|
unidade_medida = "ºC",
|
|
offset = -3.6,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "TBAT",
|
|
Descricao = "Temperatura da bateria",
|
|
ID_Num = 5,
|
|
Componente = S_Code.sNTC,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.TMP,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 50,
|
|
minimo = 5,
|
|
nominal = 25,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
},
|
|
}
|
|
},
|
|
// sCOR 11 ~ 17
|
|
new SensorModel()
|
|
{
|
|
ID = "AB3V",
|
|
Descricao = "Corrente no Barramento 3V",
|
|
ID_Num = 11,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA219_3A2).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "5",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 3.4,
|
|
minimo = 3.0,
|
|
nominal = 3.3,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 500,
|
|
minimo = 30,
|
|
nominal = 100,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
maximo = 60,
|
|
minimo = 0,
|
|
nominal = 25,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "AB5V",
|
|
Descricao = "Corrente no Barramento 5V",
|
|
ID_Num = 12,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA219_3A2).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "4",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 5.3,
|
|
minimo = 4.75,
|
|
nominal = 5.1,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 800,
|
|
minimo = 100,
|
|
nominal = 430,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
maximo = 60,
|
|
minimo = 0,
|
|
nominal = 25,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "AB7V2",
|
|
Descricao = "Corrente no Barramento 7,2V",
|
|
ID_Num = 13,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA219_3A2).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "2",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 7.4,
|
|
minimo = 7.0,
|
|
nominal = 7.2,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 3000,
|
|
minimo = 0,
|
|
nominal = 10,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
maximo = 60,
|
|
minimo = 0,
|
|
nominal = 25,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "AB12V",
|
|
Descricao = "Corrente no Barramento 12V",
|
|
ID_Num = 14,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA228_50A).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "3",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 12.5,
|
|
minimo = 11.5,
|
|
nominal = 12.0,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 10000,
|
|
minimo = 50,
|
|
nominal = 500,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 60,
|
|
minimo = 0,
|
|
nominal = 25,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "AB19V",
|
|
Descricao = "Corrente no Barramento 19V",
|
|
ID_Num = 15,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA228_10A).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 19.2,
|
|
minimo = 18.6,
|
|
nominal = 19.0,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 6500,
|
|
minimo = 1000,
|
|
nominal = 5500,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 70,
|
|
minimo = 0,
|
|
nominal = 50,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "AB24V",
|
|
Descricao = "Corrente no Barramento 24V",
|
|
ID_Num = 16,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA228_50A).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "6",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 24.3,
|
|
minimo = 23.5,
|
|
nominal = 24.0,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 20000,
|
|
minimo = 100,
|
|
nominal = 700,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 60,
|
|
minimo = 0,
|
|
nominal = 25,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "AB36V",
|
|
Descricao = "Corrente no Barramento 36V",
|
|
ID_Num = 17,
|
|
Componente = S_Code.sCOR,
|
|
Aferir = true,
|
|
Mandatorio = true,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x40",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Shunt",
|
|
Valor = ((int)TiposShuntCorrente.INA228_100A).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "7",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Tensao,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 42.5,
|
|
minimo = 31.0,
|
|
nominal = 37.5,
|
|
unidade_medida = "V"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Corrente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 75000,
|
|
minimo = 200,
|
|
nominal = 3500,
|
|
unidade_medida = "mA"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Potencia,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
unidade_medida = "mW"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Energia,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
unidade_medida = "mW/h"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 60,
|
|
minimo = 0,
|
|
nominal = 35,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.CodAlarme,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 2,
|
|
}
|
|
}
|
|
},
|
|
// Torre 31 ~ 37
|
|
new SensorModel()
|
|
{
|
|
ID = "LUZABT",
|
|
Descricao = "Luminosidade Ambiente",
|
|
ID_Num = 31,
|
|
Componente = S_Code.sLUZ,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x29",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LuzAmbiente,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 80000,
|
|
minimo = 50,
|
|
nominal = 10000,
|
|
unidade_medida = "Lux"
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "IUVABT",
|
|
Descricao = "Indice de radiacao UV Ambiente",
|
|
ID_Num = 32,
|
|
Componente = S_Code.sIUV,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.LuzUV,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LuzUV,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 11.0,
|
|
minimo = 0.0,
|
|
nominal = 5.0,
|
|
unidade_medida = "IUV"
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "MQ2",
|
|
Descricao = "Gas e Fumaca",
|
|
ID_Num = 33,
|
|
Componente = S_Code.sGAS,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Gas,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Tipo",
|
|
Valor = ((int)TipoSensorGas.MQ2).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true,
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Gas,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 600.0,
|
|
minimo = 0.0,
|
|
nominal = 50.0,
|
|
unidade_medida = "PPM"
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "MQ7",
|
|
Descricao = "Monoxido de carbono",
|
|
ID_Num = 34,
|
|
Componente = S_Code.sGAS,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Gas,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Tipo",
|
|
Valor = ((int)TipoSensorGas.MQ7).ToString(),
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true,
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Gas,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 400.0,
|
|
minimo = 0.0,
|
|
nominal = 25.0,
|
|
unidade_medida = "PPM"
|
|
}
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "QLDABT",
|
|
Descricao = "Qualidade do ar",
|
|
ID_Num = 35,
|
|
Componente = S_Code.sQAR,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.TVOC,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 1000.0,
|
|
minimo = 0.0,
|
|
nominal = 150.0,
|
|
unidade_medida = "PPB"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.ECO2,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 2000.0,
|
|
minimo = 400.0,
|
|
nominal = 600.0,
|
|
unidade_medida = "PPM"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.AQI,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 2,
|
|
analise_health = true,
|
|
maximo = 3.0,
|
|
minimo = 1.0,
|
|
nominal = 1.5,
|
|
unidade_medida = "AQI"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 50.0,
|
|
minimo = 0.0,
|
|
nominal = 25.0,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Umidade,
|
|
posicao = CanMessagePosicaoDados.Dados2,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 90.0,
|
|
minimo = 20.0,
|
|
nominal = 60.0,
|
|
unidade_medida = "%"
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "SHTABT",
|
|
Descricao = "Temperatura e Umidade Ambiente",
|
|
ID_Num = 36,
|
|
Componente = S_Code.sSHT,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x44",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = false
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Temperatura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true,
|
|
maximo = 50.0,
|
|
minimo = 0.0,
|
|
nominal = 25.0,
|
|
unidade_medida = "ºC"
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Umidade,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 90.0,
|
|
minimo = 20.0,
|
|
nominal = 60.0,
|
|
unidade_medida = "%"
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "CHVABT",
|
|
Descricao = "Chuva",
|
|
ID_Num = 37,
|
|
Componente = S_Code.sCHV,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Chuva,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "-1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Chuva,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
analise_health = true,
|
|
maximo = 100.0,
|
|
minimo = 0.0,
|
|
nominal = 10.0,
|
|
unidade_medida = "%"
|
|
}
|
|
}
|
|
},
|
|
// sMAG 91 ~ 94
|
|
new SensorModel()
|
|
{
|
|
ID = "MAGET",
|
|
Descricao = "Angulo Direcional ET",
|
|
ID_Num = 91,
|
|
Componente = S_Code.sMAG,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x36",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "1",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
unidade_medida = ""
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraAngulo,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
unidade_medida = "°"
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "MAGDT",
|
|
Descricao = "Angulo Direcional DT",
|
|
ID_Num = 92,
|
|
Componente = S_Code.sMAG,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x36",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "2",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
unidade_medida = ""
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraAngulo,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
unidade_medida = "°"
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "MAGEF",
|
|
Descricao = "Angulo Direcional EF",
|
|
ID_Num = 93,
|
|
Componente = S_Code.sMAG,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x36",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "3",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
unidade_medida = ""
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraAngulo,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
unidade_medida = "°"
|
|
},
|
|
}
|
|
},
|
|
new SensorModel()
|
|
{
|
|
ID = "MAGDF",
|
|
Descricao = "Angulo Direcional DF",
|
|
ID_Num = 94,
|
|
Componente = S_Code.sMAG,
|
|
Aferir = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.I2C,
|
|
},
|
|
Parametros = new List<SensorParametroModel>()
|
|
{
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Endereço I2C",
|
|
Valor = "0x36",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
new SensorParametroModel()
|
|
{
|
|
Descricao = "Canal MUX",
|
|
Valor = "4",
|
|
QtdBytes = 1,
|
|
Escalar = false,
|
|
Enviar = true
|
|
},
|
|
},
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraBruta,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
unidade_medida = ""
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.LeituraAngulo,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 1,
|
|
unidade_medida = "°"
|
|
},
|
|
}
|
|
},
|
|
|
|
},
|
|
// 41 ~ 44
|
|
Servos = new List<SensorServoModel>()
|
|
{
|
|
new SensorServoModel()
|
|
{
|
|
ID = "FROET",
|
|
ID_Num = 41,
|
|
Descricao = "Freio Motor ET",
|
|
Componente = S_Code.sSRV,
|
|
Controlar = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Servo,
|
|
},
|
|
AnguloNeutro = 0,
|
|
_AnguloControle = 0,
|
|
UltimoAnguloDesejado = 0,
|
|
Incremental = true,
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.ServoAnguloLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true
|
|
},
|
|
}
|
|
},
|
|
new SensorServoModel()
|
|
{
|
|
ID = "FROEF",
|
|
ID_Num = 42,
|
|
Descricao = "Freio Motor EF",
|
|
Componente = S_Code.sSRV,
|
|
Controlar = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Servo,
|
|
},
|
|
AnguloNeutro = 0,
|
|
_AnguloControle = 0,
|
|
UltimoAnguloDesejado = 0,
|
|
Incremental = true,
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.ServoAnguloLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true
|
|
},
|
|
}
|
|
},
|
|
new SensorServoModel()
|
|
{
|
|
ID = "FRODT",
|
|
ID_Num = 43,
|
|
Descricao = "Freio Motor DT",
|
|
Componente = S_Code.sSRV,
|
|
Controlar = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Servo,
|
|
},
|
|
AnguloNeutro = 180,
|
|
_AnguloControle = 180,
|
|
UltimoAnguloDesejado = 180,
|
|
Incremental = false,
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.ServoAnguloLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true
|
|
},
|
|
}
|
|
},
|
|
new SensorServoModel()
|
|
{
|
|
ID = "FRODF",
|
|
ID_Num = 44,
|
|
Descricao = "Freio Motor DF",
|
|
Componente = S_Code.sSRV,
|
|
Controlar = false,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Servo,
|
|
},
|
|
AnguloNeutro = 180,
|
|
_AnguloControle = 180,
|
|
UltimoAnguloDesejado = 180,
|
|
Incremental = false,
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.ServoAnguloLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
analise_health = true
|
|
},
|
|
}
|
|
},
|
|
},
|
|
// 81 ~ 82
|
|
Reles = new List<SensorReleModel>()
|
|
{
|
|
new SensorReleModel()
|
|
{
|
|
ID = "RLCIN",
|
|
ID_Num = 81,
|
|
Descricao = "Rele Cooler Entrada",
|
|
Componente = S_Code.sRLE,
|
|
Controlar = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Cooler,
|
|
},
|
|
AtuacaoNivelAlto = true,
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.EstadoLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
}
|
|
},
|
|
new SensorReleModel()
|
|
{
|
|
ID = "RLCOUT",
|
|
ID_Num = 82,
|
|
Descricao = "Rele Cooler Saida",
|
|
Componente = S_Code.sRLE,
|
|
Controlar = true,
|
|
Mandatorio = false,
|
|
Funcoes = new List<FuncoesPinout>()
|
|
{
|
|
FuncoesPinout.Cooler,
|
|
},
|
|
AtuacaoNivelAlto = true,
|
|
ValoresLeituras = new List<SensorValoresLeituraModel>()
|
|
{
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.Iniciado,
|
|
posicao = CanMessagePosicaoDados.Status,
|
|
indice = 0,
|
|
},
|
|
new SensorValoresLeituraModel()
|
|
{
|
|
funcao = FuncoesPinout.EstadoLeitura,
|
|
posicao = CanMessagePosicaoDados.Dados1,
|
|
indice = 0,
|
|
},
|
|
}
|
|
},
|
|
},
|
|
};
|
|
|
|
obj.ValidarConfiguracaoProduto();
|
|
return obj;
|
|
}
|
|
|
|
private void ValidarConfiguracaoProduto()
|
|
{
|
|
if (Sensores == null || Sinaleiros == null || Reles == null || Servos == null)
|
|
throw new InvalidOperationException("Cadastro do sensoriamento está incompleto.");
|
|
|
|
var componentes = new List<(string tipo, string id, int idNum, S_Code codigo, List<SensorValoresLeituraModel> leituras)>();
|
|
|
|
componentes.AddRange((Sensores ?? new List<SensorModel>())
|
|
.Where(x => x != null)
|
|
.Select(x => ("Sensor", x.ID, x.ID_Num, x.Componente, x.ValoresLeituras)));
|
|
componentes.AddRange((Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
.Where(x => x != null)
|
|
.Select(x => ("Sinaleiro", x.ID, x.ID_Num, x.Componente, x.ValoresLeituras)));
|
|
componentes.AddRange((Reles ?? new List<SensorReleModel>())
|
|
.Where(x => x != null)
|
|
.Select(x => ("Relé", x.ID, x.ID_Num, x.Componente, x.ValoresLeituras)));
|
|
componentes.AddRange((Servos ?? new List<SensorServoModel>())
|
|
.Where(x => x != null)
|
|
.Select(x => ("Servo", x.ID, x.ID_Num, x.Componente, x.ValoresLeituras)));
|
|
|
|
var idsReservados = new HashSet<int>()
|
|
{
|
|
Variaveis.ID_Num_sMOD,
|
|
Variaveis.ID_Num_sTOD,
|
|
};
|
|
|
|
var idsForaDoProtocolo = componentes
|
|
.Where(x => x.idNum < byte.MinValue || x.idNum > byte.MaxValue || idsReservados.Contains(x.idNum))
|
|
.Select(x => x.idNum)
|
|
.Distinct()
|
|
.ToList();
|
|
|
|
if (idsForaDoProtocolo.Count > 0)
|
|
throw new InvalidOperationException(
|
|
"Sensoriamento possui ID_Num fora do intervalo CAN ou reservado: " +
|
|
string.Join(", ", idsForaDoProtocolo)
|
|
);
|
|
|
|
var idsNumericosDuplicados = componentes
|
|
.GroupBy(x => x.idNum)
|
|
.Where(x => x.Count() > 1)
|
|
.Select(x => x.Key)
|
|
.ToList();
|
|
|
|
if (idsNumericosDuplicados.Count > 0)
|
|
throw new InvalidOperationException(
|
|
"Sensoriamento possui ID_Num duplicado(s): " + string.Join(", ", idsNumericosDuplicados)
|
|
);
|
|
|
|
var idsDuplicados = componentes
|
|
.Where(x => !string.IsNullOrWhiteSpace(x.id))
|
|
.GroupBy(x => x.id, StringComparer.OrdinalIgnoreCase)
|
|
.Where(x => x.Count() > 1)
|
|
.Select(x => x.Key)
|
|
.ToList();
|
|
|
|
if (idsDuplicados.Count > 0)
|
|
throw new InvalidOperationException(
|
|
"Sensoriamento possui ID duplicado(s): " + string.Join(", ", idsDuplicados)
|
|
);
|
|
|
|
var codigosSensoresSuportados = new HashSet<S_Code>()
|
|
{
|
|
S_Code.sNTC,
|
|
S_Code.sCOR,
|
|
S_Code.sIMU,
|
|
S_Code.sGAS,
|
|
S_Code.sSHT,
|
|
S_Code.sLUZ,
|
|
S_Code.sIUV,
|
|
S_Code.sQAR,
|
|
S_Code.sCHV,
|
|
S_Code.sMAG,
|
|
};
|
|
|
|
foreach (var componente in componentes)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(componente.id))
|
|
throw new InvalidOperationException($"{componente.tipo} com ID_Num={componente.idNum} não possui ID textual.");
|
|
|
|
bool codigoValido =
|
|
(componente.tipo == "Sensor" && codigosSensoresSuportados.Contains(componente.codigo)) ||
|
|
(componente.tipo == "Sinaleiro" && componente.codigo == S_Code.sLED) ||
|
|
(componente.tipo == "Relé" && componente.codigo == S_Code.sRLE) ||
|
|
(componente.tipo == "Servo" && componente.codigo == S_Code.sSRV);
|
|
|
|
if (!codigoValido)
|
|
throw new InvalidOperationException(
|
|
$"{componente.tipo} {componente.id} possui código incompatível: {componente.codigo}."
|
|
);
|
|
|
|
if (componente.leituras == null || componente.leituras.Count == 0)
|
|
throw new InvalidOperationException($"{componente.tipo} {componente.id} não possui ValoresLeituras.");
|
|
|
|
if (componente.leituras.Any(x => x == null))
|
|
throw new InvalidOperationException($"{componente.tipo} {componente.id} possui leitura nula no cadastro.");
|
|
|
|
foreach (var grupo in componente.leituras.Where(x => x != null).GroupBy(x => x.posicao))
|
|
{
|
|
var indices = grupo.Select(x => x.indice).OrderBy(x => x).ToList();
|
|
var esperados = Enumerable.Range(0, indices.Count).ToList();
|
|
|
|
if (!indices.SequenceEqual(esperados))
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"{componente.tipo} {componente.id} possui índices inválidos em {grupo.Key}: " +
|
|
string.Join(", ", indices)
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public void LimparDados<T>(T _dados)
|
|
{
|
|
var Dados = _dados as SensoriamentoModel;
|
|
|
|
if (Dados == null)
|
|
return;
|
|
|
|
/*
|
|
* O início de uma operação não representa perda física do SEN.
|
|
* Preservamos conexão, inicialização, telemetria e timestamps para
|
|
* impedir um snapshot falso de módulo/componentes desconectados.
|
|
* Somente as intenções de controle retornam a um estado seguro.
|
|
*/
|
|
lock (Dados.EstadoSyncRoot)
|
|
{
|
|
Dados.Reles?.Where(x => x != null).ToList().ForEach(x =>
|
|
{
|
|
x.StatusControle = Estado.Desligado;
|
|
x.UltimoEstadoDesejado = Estado.Desligado;
|
|
x.UltimoComandoEnviado = DateTime.MinValue;
|
|
});
|
|
|
|
Dados.Servos?.Where(x => x != null).ToList().ForEach(x =>
|
|
{
|
|
x._AnguloControle = x.AnguloNeutro;
|
|
x.UltimoAnguloDesejado = x.AnguloNeutro;
|
|
x.UltimoComandoEnviado = DateTime.MinValue;
|
|
});
|
|
|
|
Dados.Sinaleiros?.Where(x => x != null).ToList().ForEach(x =>
|
|
{
|
|
x.Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Apagado);
|
|
x.UltimoComportamentoDesejado = null;
|
|
x.UltimoComandoEnviado = DateTime.MinValue;
|
|
});
|
|
|
|
}
|
|
}
|
|
|
|
public void ReiniciarLeituras(SensoriamentoModel Dados)
|
|
{
|
|
ReiniciarLeituras(Dados, apagarValoresLeituras: true);
|
|
}
|
|
|
|
public void ReiniciarLeituras(SensoriamentoModel Dados, bool apagarValoresLeituras)
|
|
{
|
|
if (Dados == null || !apagarValoresLeituras)
|
|
return;
|
|
|
|
lock (Dados.EstadoSyncRoot)
|
|
{
|
|
foreach (var rele in Dados.Reles ?? new List<SensorReleModel>())
|
|
{
|
|
if (rele == null) continue;
|
|
rele.Inicializado = false;
|
|
ReiniciarValores(rele.ValoresLeituras);
|
|
}
|
|
|
|
foreach (var sinaleiro in Dados.Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
{
|
|
if (sinaleiro == null) continue;
|
|
sinaleiro.Inicializado = false;
|
|
ReiniciarValores(sinaleiro.ValoresLeituras);
|
|
}
|
|
|
|
foreach (var sensor in Dados.Sensores ?? new List<SensorModel>())
|
|
{
|
|
if (sensor == null) continue;
|
|
sensor.Inicializado = false;
|
|
ReiniciarValores(sensor.ValoresLeituras);
|
|
}
|
|
|
|
foreach (var servo in Dados.Servos ?? new List<SensorServoModel>())
|
|
{
|
|
if (servo == null) continue;
|
|
servo.Inicializado = false;
|
|
ReiniciarValores(servo.ValoresLeituras);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void ReiniciarValores(IEnumerable<SensorValoresLeituraModel> valores)
|
|
{
|
|
if (valores == null)
|
|
return;
|
|
|
|
foreach (var leitura in valores.Where(x => x != null))
|
|
leitura.atual = new CanCommandFreqModel<dynamic>();
|
|
}
|
|
|
|
public async Task<bool> VerificaDispositivoConectado()
|
|
{
|
|
var op = Variaveis.OperacaoEmAndamento;
|
|
|
|
if (!CanManager.CanService.IsConnected) return false;
|
|
|
|
if (op?.DispSen == null || !ReferenceEquals(op.DispSen.Dados, this)) return false;
|
|
|
|
CanManager.CanService.RegistrarHandler(_EnderecoCAN_Rx, _SenHandler);
|
|
|
|
DateTime Inicio = DateTime.Now;
|
|
RequisitarDadosDescoberta();
|
|
|
|
bool Respondido()
|
|
{
|
|
lock (_estadoLock)
|
|
return _ultimaRespostaDescoberta > Inicio;
|
|
}
|
|
|
|
await FuncoesGlobais.AguardarCondicaoAsync(Respondido, 500, 50);
|
|
|
|
if (Respondido())
|
|
{
|
|
DefinirDispositivo();
|
|
op.DispSen?.EnviarProtocolosConfiguracao();
|
|
}
|
|
|
|
return Conectado;
|
|
}
|
|
|
|
private void DefinirDispositivo()
|
|
{
|
|
var op = Variaveis.OperacaoEmAndamento;
|
|
|
|
if (op?.Sensoriamento?.Operacao == null || !ReferenceEquals(op.DispSen?.Dados, this))
|
|
return;
|
|
|
|
T_Code dispositivoDeclarado;
|
|
int versao;
|
|
|
|
lock (_estadoLock)
|
|
{
|
|
dispositivoDeclarado = DadosLeitura?.Dispositivo ?? default(T_Code);
|
|
versao = DadosLeitura?.Versao ?? 0;
|
|
}
|
|
|
|
if (dispositivoDeclarado != Dispositivo)
|
|
{
|
|
Variaveis.MostrarLog(
|
|
$"[SEN/DESCOBERTA] Resposta ignorada: esperado={Dispositivo}, recebido={dispositivoDeclarado}"
|
|
);
|
|
return;
|
|
}
|
|
|
|
bool novoMapeamento = false;
|
|
|
|
lock (SerialService.DispositivosMapeados)
|
|
{
|
|
if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == Dispositivo && x.Mod_ID == Modulo_ID))
|
|
return;
|
|
|
|
SerialService.AdicionarOuAtualizarDispositivoMapeado(new DispositivoDetalhesModel()
|
|
{
|
|
Endereco = CanManager.CanService._portName,
|
|
Dispositivo = dispositivoDeclarado,
|
|
Versao = versao.ToString(),
|
|
Mod_ID = Modulo_ID,
|
|
});
|
|
|
|
novoMapeamento = true;
|
|
}
|
|
|
|
/* Uma redescoberta não pode apagar o estado já consolidado. */
|
|
if (op.Sensoriamento.Operacao.ModsCalibragem == null)
|
|
op.Sensoriamento.Operacao.ModsCalibragem = new Dictionary<T_Code, Dictionary<string, bool>>();
|
|
|
|
if (!op.Sensoriamento.Operacao.ModsCalibragem.ContainsKey(Dispositivo))
|
|
op.Sensoriamento.Operacao.ModsCalibragem[Dispositivo] = new Dictionary<string, bool>();
|
|
|
|
if (novoMapeamento)
|
|
op.Sensoriamento.InserirLog(Dispositivo, StatusModulo.Conectado, 0, "Dispositivo conectado");
|
|
}
|
|
|
|
internal void ConfirmarMapeamentoAposDescoberta(DateTime respostaEm)
|
|
{
|
|
lock (_estadoLock)
|
|
_ultimaRespostaDescoberta = respostaEm;
|
|
|
|
DefinirDispositivo();
|
|
}
|
|
|
|
private void RequisitarDadosDescoberta()
|
|
{
|
|
var dispSen = Variaveis.OperacaoEmAndamento?.DispSen;
|
|
|
|
if (dispSen == null || !ReferenceEquals(dispSen.Dados, this))
|
|
return;
|
|
|
|
lock (_estadoLock)
|
|
_ultimaDescobertaEnviada = DateTime.Now;
|
|
|
|
dispSen.AdicionarMensagemFila(Variaveis.ID_Num_sMOD, CanMessagePosicaoDados.Status, CanMessagePosicaoDados.Status, null, true, false, true);
|
|
}
|
|
|
|
private void ManterDescobertaAtiva(DateTime agora)
|
|
{
|
|
DateTime ultimaDescoberta;
|
|
bool identificado;
|
|
|
|
lock (_estadoLock)
|
|
{
|
|
ultimaDescoberta = _ultimaDescobertaEnviada;
|
|
identificado = _ultimaRespostaDescoberta != DateTime.MinValue &&
|
|
DadosLeitura?.Dispositivo == Dispositivo;
|
|
}
|
|
|
|
if (Conectado && identificado)
|
|
return;
|
|
|
|
if ((agora - ultimaDescoberta).TotalMilliseconds < IntervaloDescobertaDesconectadoMs)
|
|
return;
|
|
|
|
RequisitarDadosDescoberta();
|
|
}
|
|
|
|
public void RequisitarDadosModulo(int ID_Num, CanMessagePosicaoDados posicaoTx, CanMessagePosicaoDados posicaoRx, bool aguardaResposta)
|
|
{
|
|
if (!ModeloRuntimeAtivo)
|
|
return;
|
|
|
|
Variaveis.OperacaoEmAndamento?.DispSen?.AdicionarMensagemFila(ID_Num, posicaoTx, posicaoRx, null, aguardaResposta);
|
|
}
|
|
|
|
public (int, CanMessagePosicaoDados, byte[]) ProtocoloComandoReset()
|
|
{
|
|
return (
|
|
Variaveis.ID_Num_sMOD,
|
|
CanMessagePosicaoDados.Command1,
|
|
new byte[]
|
|
{
|
|
(byte)Estado.Reset
|
|
}
|
|
);
|
|
}
|
|
|
|
public List<(int, CanMessagePosicaoDados, byte[])> ProtocoloConfiguracao(bool Conectar)
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
|
|
bool firmwareConectado = DadosLeitura?.Conectado == true;
|
|
|
|
if (!firmwareConectado)
|
|
config.AddRange(ModConfig(Conectar));
|
|
|
|
bool configurarTodos = !firmwareConectado && Conectar;
|
|
|
|
/*
|
|
* Reconfigura todos após a conexão do módulo e, durante a
|
|
* operação, somente componentes ausentes ou indevidamente
|
|
* ativos. Isso permite recuperar um canal sem resetar o SEN.
|
|
*/
|
|
config.AddRange(SinaleirosConfig(Conectar, configurarTodos));
|
|
config.AddRange(ServosConfig(Conectar, configurarTodos));
|
|
config.AddRange(RelesConfig(Conectar, configurarTodos));
|
|
config.AddRange(SensoresConfig(Conectar, configurarTodos));
|
|
|
|
return config;
|
|
}
|
|
}
|
|
|
|
private List<(int, CanMessagePosicaoDados, byte[])> ModConfig(bool Conectar)
|
|
{
|
|
int periodoSegundos = Math.Max(
|
|
1,
|
|
Math.Min(byte.MaxValue, _TaxaAmostragem / 1000)
|
|
);
|
|
|
|
var config1 = new List<byte>
|
|
{
|
|
(byte)(Conectar ? 1 : 0),
|
|
(byte)periodoSegundos,
|
|
(byte)(RequisitarDados ? 1 : 0),
|
|
|
|
// Campo reservado do protocolo.
|
|
// Antigamente era LoRaParametrosBase.address.
|
|
// A firmware ainda espera esta posição antes de SDA/SCL.
|
|
0x00,
|
|
};
|
|
|
|
if (Pinout != null)
|
|
{
|
|
byte[] pinout =
|
|
PinoutModel.PinoProtocolo(Pinout, Funcoes, false);
|
|
|
|
if (pinout != null)
|
|
config1.AddRange(pinout);
|
|
}
|
|
|
|
return new List<(int, CanMessagePosicaoDados, byte[])>()
|
|
{
|
|
(
|
|
Variaveis.ID_Num_sMOD,
|
|
CanMessagePosicaoDados.Config1,
|
|
config1.ToArray()
|
|
),
|
|
};
|
|
}
|
|
|
|
public List<(int, CanMessagePosicaoDados, byte[])> SensoresConfig(bool Conectar, bool ConfigurarTodos)
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
|
|
|
|
foreach (var sensor in (Sensores ?? new List<SensorModel>())
|
|
.Where(x => x != null && ((x.Aferir && (ConfigurarTodos || x.Inicializado != Conectar)) || (!x.Aferir && x.Inicializado))))
|
|
{
|
|
bool conectarComponente = Conectar && sensor.Aferir;
|
|
(CanMessagePosicaoDados posicao, byte[] payload) = sensor.ProtocoloConfiguracao(Pinout, conectarComponente, Dispositivo);
|
|
|
|
if (payload != null)
|
|
config.Add((sensor.ID_Num, posicao, payload));
|
|
}
|
|
|
|
return config;
|
|
}
|
|
}
|
|
|
|
private List<(int, CanMessagePosicaoDados, byte[])> SinaleirosConfig(bool Conectar, bool ConfigurarTodos)
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
|
|
|
|
foreach (var sinaleiro in (Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
.Where(x => x != null && ((x.Controlar && (ConfigurarTodos || x.Inicializado != Conectar)) || (!x.Controlar && x.Inicializado))))
|
|
{
|
|
bool conectarComponente = Conectar && sinaleiro.Controlar;
|
|
(CanMessagePosicaoDados posicao, byte[] payload) = sinaleiro.ProtocoloConfiguracao(Pinout, conectarComponente);
|
|
|
|
if (payload != null)
|
|
config.Add((sinaleiro.ID_Num, posicao, payload));
|
|
}
|
|
|
|
return config;
|
|
}
|
|
}
|
|
|
|
private List<(int, CanMessagePosicaoDados, byte[])> RelesConfig(bool Conectar, bool ConfigurarTodos)
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
|
|
|
|
foreach (var rele in (Reles ?? new List<SensorReleModel>())
|
|
.Where(x => x != null && ((x.Controlar && (ConfigurarTodos || x.Inicializado != Conectar)) || (!x.Controlar && x.Inicializado))))
|
|
{
|
|
bool conectarComponente = Conectar && rele.Controlar;
|
|
(CanMessagePosicaoDados posicao, byte[] payload) = rele.ProtocoloConfiguracao(Pinout, conectarComponente);
|
|
|
|
if (payload != null)
|
|
config.Add((rele.ID_Num, posicao, payload));
|
|
}
|
|
|
|
return config;
|
|
}
|
|
}
|
|
|
|
private List<(int, CanMessagePosicaoDados, byte[])> ServosConfig(bool Conectar, bool ConfigurarTodos)
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
var config = new List<(int, CanMessagePosicaoDados, byte[])>();
|
|
|
|
foreach (var servo in (Servos ?? new List<SensorServoModel>())
|
|
.Where(x => x != null && ((x.Controlar && (ConfigurarTodos || x.Inicializado != Conectar)) || (!x.Controlar && x.Inicializado))))
|
|
{
|
|
bool conectarComponente = Conectar && servo.Controlar;
|
|
(CanMessagePosicaoDados posicao, byte[] payload) = servo.ProtocoloConfiguracao(Pinout, conectarComponente);
|
|
|
|
if (payload != null)
|
|
config.Add((servo.ID_Num, posicao, payload));
|
|
}
|
|
|
|
return config;
|
|
}
|
|
}
|
|
|
|
public void IniciarRegistrador()
|
|
{
|
|
ValidarConfiguracaoProduto();
|
|
|
|
lock (_registradorLock)
|
|
{
|
|
if (tmrRegistrador?.IsRunning ?? false)
|
|
return;
|
|
|
|
LimparDados(this);
|
|
|
|
var timerAnterior = tmrRegistrador;
|
|
tmrRegistrador = null;
|
|
timerAnterior?.Dispose();
|
|
|
|
int intervaloSeguro = Math.Max(1, _TaxaAmostragem);
|
|
tmrRegistrador = new AsyncTaskTimerModel("tmrRegistrador_" + T_Code.Sen.ToString(), tmrRegistrador_Tick, intervaloSeguro);
|
|
tmrRegistrador.Start();
|
|
}
|
|
}
|
|
|
|
public void PararRegistrador()
|
|
{
|
|
AsyncTaskTimerModel timer;
|
|
|
|
lock (_registradorLock)
|
|
{
|
|
timer = tmrRegistrador;
|
|
tmrRegistrador = null;
|
|
}
|
|
|
|
timer?.Dispose();
|
|
}
|
|
|
|
public async Task tmrRegistrador_Tick()
|
|
{
|
|
var op = Variaveis.OperacaoEmAndamento;
|
|
|
|
if (Variaveis.Fechando || op?.DispSen == null || !ReferenceEquals(op.DispSen.Dados, this))
|
|
return;
|
|
|
|
tmrRegistrador?.SetInterval(Math.Max(1, _TaxaAmostragem));
|
|
|
|
if (SerialService.DispositivosMapeados.Any(x => x.Dispositivo == Dispositivo) && (_VezesLeituraReconexao >= _TempoReconexaoComponentes))
|
|
{
|
|
op.DispAtu?.EnviarProtocolosConfiguracao();
|
|
|
|
_VezesLeituraReconexao = 0;
|
|
}
|
|
else
|
|
{
|
|
_VezesLeituraReconexao++;
|
|
}
|
|
|
|
AtualizaComponentesIniciados();
|
|
ManterDescobertaAtiva(DateTime.Now);
|
|
|
|
if (!ModeloRuntimeAtivo)
|
|
return;
|
|
|
|
if (Conectado)
|
|
{
|
|
if (RequisitarDados)
|
|
RequisitarDadosModulo(Variaveis.ID_Num_sTOD, CanMessagePosicaoDados.DadosAll, CanMessagePosicaoDados.DadosAll, true);
|
|
|
|
VerificaControleLeitura();
|
|
}
|
|
|
|
await Task.CompletedTask;
|
|
}
|
|
|
|
private void VerificaControleLeitura()
|
|
{
|
|
if (Variaveis.Fechando || !ModeloRuntimeAtivo || !Conectado || !FirmwareDeclarouConectado || !ModuloIdentificado)
|
|
return;
|
|
|
|
DateTime agora = DateTime.Now;
|
|
|
|
lock (_estadoLock)
|
|
{
|
|
foreach (var sinaleiro in (Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
.Where(x => x != null && x.Inicializado))
|
|
{
|
|
SensorSinaleiroComportamentoModel comportamentoDesejado =
|
|
sinaleiro.Controlar
|
|
? sinaleiro.Comportamento
|
|
: VariaveisEquipamento.ComportamentoLedPorStatus();
|
|
|
|
if (comportamentoDesejado == null)
|
|
comportamentoDesejado = VariaveisEquipamento.ComportamentoLedPorStatus();
|
|
|
|
bool comportamentoDivergente =
|
|
comportamentoDesejado.statusLED != sinaleiro._StatusLed ||
|
|
comportamentoDesejado.id != sinaleiro._StatusLedId;
|
|
|
|
bool desejoMudou = sinaleiro.UltimoComportamentoDesejado != comportamentoDesejado;
|
|
|
|
if ((comportamentoDivergente || desejoMudou) &&
|
|
PodeReenviarComando(sinaleiro.UltimoComandoEnviado, desejoMudou, agora))
|
|
{
|
|
if (TentarEnviarComando(
|
|
() => GeneralJoystick.EnviarComandoSensoriamento(sinaleiro.Componente, sinaleiro.ID, comportamentoDesejado),
|
|
sinaleiro.ID))
|
|
{
|
|
sinaleiro.UltimoComandoEnviado = agora;
|
|
sinaleiro.UltimoComportamentoDesejado = CopiarComportamento(comportamentoDesejado);
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var rele in (Reles ?? new List<SensorReleModel>())
|
|
.Where(x => x != null && x.Inicializado))
|
|
{
|
|
Estado estadoDesejado =
|
|
rele.Controlar && rele.StatusControle == Estado.Ligado
|
|
? Estado.Ligado
|
|
: Estado.Desligado;
|
|
|
|
bool estadoDivergente = estadoDesejado != rele._EstadoLeitura;
|
|
bool desejoMudou = estadoDesejado != rele.UltimoEstadoDesejado;
|
|
|
|
if ((estadoDivergente || desejoMudou) &&
|
|
PodeReenviarComando(rele.UltimoComandoEnviado, desejoMudou, agora))
|
|
{
|
|
if (TentarEnviarComando(
|
|
() => GeneralJoystick.EnviarComandoSensoriamento(rele.Componente, rele.ID, estadoDesejado),
|
|
rele.ID))
|
|
{
|
|
rele.UltimoComandoEnviado = agora;
|
|
rele.UltimoEstadoDesejado = estadoDesejado;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach (var servo in (Servos ?? new List<SensorServoModel>())
|
|
.Where(x => x != null && x.Inicializado))
|
|
{
|
|
double anguloDesejado = servo.Controlar ? servo._AnguloControle : servo.AnguloNeutro;
|
|
bool anguloDivergente = Math.Abs(anguloDesejado - servo._AnguloLeiutra) > 1.0;
|
|
bool desejoMudou = Math.Abs(anguloDesejado - servo.UltimoAnguloDesejado) > 0.01;
|
|
|
|
if ((anguloDivergente || desejoMudou) &&
|
|
PodeReenviarComando(servo.UltimoComandoEnviado, desejoMudou, agora))
|
|
{
|
|
if (TentarEnviarComando(
|
|
() => GeneralJoystick.EnviarComandoSensoriamento(servo.Componente, servo.ID, anguloDesejado),
|
|
servo.ID))
|
|
{
|
|
servo.UltimoComandoEnviado = agora;
|
|
servo.UltimoAnguloDesejado = anguloDesejado;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool TentarEnviarComando(Action enviar, string componenteId)
|
|
{
|
|
try
|
|
{
|
|
enviar();
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog($"[SEN/TX] Falha ao comandar {componenteId}: {ex}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static bool PodeReenviarComando(DateTime ultimoEnvio, bool desejoMudou, DateTime agora)
|
|
{
|
|
return desejoMudou ||
|
|
ultimoEnvio == DateTime.MinValue ||
|
|
(agora - ultimoEnvio).TotalMilliseconds >= IntervaloReenvioComandoMs;
|
|
}
|
|
|
|
private static SensorSinaleiroComportamentoModel CopiarComportamento(SensorSinaleiroComportamentoModel origem)
|
|
{
|
|
if (origem == null)
|
|
return null;
|
|
|
|
return new SensorSinaleiroComportamentoModel()
|
|
{
|
|
id = origem.id,
|
|
statusOperacao = origem.statusOperacao,
|
|
statusLED = origem.statusLED,
|
|
QtdPiscadas = origem.QtdPiscadas,
|
|
TempoMs = origem.TempoMs,
|
|
PausaMs = origem.PausaMs,
|
|
};
|
|
}
|
|
|
|
private void AtualizaComponentesIniciados()
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
DateTime agora = DateTime.Now;
|
|
bool moduloComTelemetria =
|
|
DadosLeitura != null &&
|
|
DadosLeitura.UltimoComandoRespondido != DateTime.MinValue &&
|
|
DadosLeitura.UltimoComandoRespondido.AddMilliseconds(Math.Max(1, TempoLimiteConexao)) > agora;
|
|
|
|
if (!moduloComTelemetria)
|
|
{
|
|
if (DadosLeitura != null)
|
|
DadosLeitura.Conectado = false;
|
|
|
|
_ultimaRespostaDescoberta = DateTime.MinValue;
|
|
}
|
|
|
|
foreach (var led in (Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
.Where(x => x != null && x.Inicializado && LeituraExpirada(x.UltimaLeitura, agora)))
|
|
led.Inicializado = false;
|
|
|
|
foreach (var rele in (Reles ?? new List<SensorReleModel>())
|
|
.Where(x => x != null && x.Inicializado && LeituraExpirada(x.UltimaLeitura, agora)))
|
|
rele.Inicializado = false;
|
|
|
|
foreach (var servo in (Servos ?? new List<SensorServoModel>())
|
|
.Where(x => x != null && x.Inicializado && LeituraExpirada(x.UltimaLeitura, agora)))
|
|
servo.Inicializado = false;
|
|
|
|
foreach (var sensor in (Sensores ?? new List<SensorModel>())
|
|
.Where(x => x != null && x.Inicializado && LeituraExpirada(x.UltimaLeitura, agora)))
|
|
sensor.Inicializado = false;
|
|
}
|
|
}
|
|
|
|
private static bool LeituraExpirada(DateTime ultimaLeitura, DateTime agora)
|
|
{
|
|
return ultimaLeitura == DateTime.MinValue ||
|
|
ultimaLeitura.AddMilliseconds(Math.Max(1, TempoLimiteConexao)) < agora;
|
|
}
|
|
|
|
public void AtualizarStatusSinaleiros(ModoOperacao Modo, StatusOperacao _statusOperacao)
|
|
{
|
|
lock (_estadoLock)
|
|
{
|
|
var ledMn = Sinaleiros?.FirstOrDefault(x => x?.ID == "LEDMN");
|
|
var ledAt = Sinaleiros?.FirstOrDefault(x => x?.ID == "LEDAT");
|
|
var ledOp = Sinaleiros?.FirstOrDefault(x => x?.ID == "LEDOP");
|
|
|
|
if (ledMn != null)
|
|
ledMn.Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(Modo == ModoOperacao.Manual ? StatusLED.Aceso : StatusLED.Apagado);
|
|
|
|
if (ledAt != null)
|
|
ledAt.Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(Modo == ModoOperacao.Manual ? StatusLED.Apagado : StatusLED.Aceso);
|
|
|
|
if (ledOp != null)
|
|
ledOp.Comportamento = VariaveisEquipamento.ComportamentoLedPorStatus(StatusLED.Piscando, status_operacao: _statusOperacao);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public class SensorModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
public bool Aferir { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Liberado
|
|
{
|
|
get
|
|
{
|
|
return !Mandatorio || (Aferir && Inicializado);
|
|
}
|
|
}
|
|
public bool Inicializado { get; set; }
|
|
public DateTime UltimaLeitura
|
|
{
|
|
get
|
|
{
|
|
return ValoresLeituras?
|
|
.Where(x => x?.atual != null)
|
|
.OrderByDescending(x => x.atual.lidoEm)
|
|
.FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
|
|
}
|
|
}
|
|
public List<FuncoesPinout> Funcoes { get; set; }
|
|
public List<SensorParametroModel> Parametros { get; set; }
|
|
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
|
|
|
|
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel Pinout, bool conectar, T_Code Dispositivo)
|
|
{
|
|
List<byte> config = new List<byte>
|
|
{
|
|
(byte)Componente,
|
|
(byte)(conectar ? 1 : 0),
|
|
};
|
|
|
|
var _pinout = Pinout?.Clone();
|
|
if (_pinout?.Pinos != null)
|
|
{
|
|
_pinout.Pinos = _pinout.Pinos.Where(x => x != null && x.ComponenteID == ID).ToList();
|
|
if (_pinout.Pinos.Count > 0)
|
|
{
|
|
bool enviaBarramento = Dispositivo == T_Code.Sen;
|
|
|
|
byte[] pinos = PinoutModel.PinoProtocolo(_pinout, Funcoes ?? new List<FuncoesPinout>(), enviaBarramento);
|
|
if (pinos != null)
|
|
config.AddRange(pinos);
|
|
}
|
|
}
|
|
|
|
foreach (var parametro in Parametros ?? new List<SensorParametroModel>())
|
|
{
|
|
if (parametro?.Enviar == true)
|
|
{
|
|
byte[] paramBytes = parametro.InterpretarParametro();
|
|
if (paramBytes != null)
|
|
config.AddRange(paramBytes);
|
|
}
|
|
}
|
|
|
|
return (CanMessagePosicaoDados.Config1, config.ToArray());
|
|
}
|
|
|
|
}
|
|
|
|
public class SensorSinaleiroModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
public bool Controlar { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Liberado => !Mandatorio || (Controlar && Inicializado);
|
|
public List<FuncoesPinout> Funcoes { get; set; }
|
|
public SensorSinaleiroComportamentoModel Comportamento { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
public DateTime UltimaLeitura
|
|
{
|
|
get
|
|
{
|
|
return ValoresLeituras?
|
|
.Where(x => x?.atual != null)
|
|
.OrderByDescending(x => x.atual.lidoEm)
|
|
.FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
|
|
}
|
|
}
|
|
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
|
|
public int _StatusLedId => (int)(ValoresLeituras?.FirstOrDefault(x => x?.funcao == FuncoesPinout.StatusLedID)?.atual?.valor ?? 99);
|
|
public StatusLED _StatusLed => (StatusLED)(ValoresLeituras?.FirstOrDefault(x => x?.funcao == FuncoesPinout.StatusLedLeitura)?.atual?.valor ?? StatusLED.Apagado);
|
|
|
|
|
|
public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue;
|
|
public SensorSinaleiroComportamentoModel UltimoComportamentoDesejado { get; set; }
|
|
|
|
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
|
|
{
|
|
var pino = pinout?.Pinos?.FirstOrDefault(p => p?.ComponenteID == ID);
|
|
List<byte> config = new List<byte>
|
|
{
|
|
(byte)Componente,
|
|
(byte)(conectar ? 1 : 0),
|
|
(byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR),
|
|
(byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO)
|
|
};
|
|
|
|
return (CanMessagePosicaoDados.Config1, config.ToArray());
|
|
}
|
|
|
|
public (int, CanMessagePosicaoDados, byte[]) ProtocoloComando()
|
|
{
|
|
var comportamento = Comportamento ?? new SensorSinaleiroComportamentoModel()
|
|
{
|
|
id = 0,
|
|
statusLED = StatusLED.Apagado,
|
|
};
|
|
|
|
List<byte> frame = new List<byte>
|
|
{
|
|
(byte)Math.Max(0, Math.Min(byte.MaxValue, comportamento.id)),
|
|
(byte)comportamento.statusLED,
|
|
(byte)Math.Max(0, Math.Min(byte.MaxValue, comportamento.QtdPiscadas)),
|
|
(byte)Math.Max(0, Math.Min(byte.MaxValue, comportamento.TempoMs / 10)),
|
|
(byte)Math.Max(0, Math.Min(byte.MaxValue, comportamento.PausaMs / 10))
|
|
};
|
|
|
|
return (ID_Num, CanMessagePosicaoDados.Command1, frame.ToArray());
|
|
}
|
|
|
|
}
|
|
|
|
public class SensorReleModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
public List<FuncoesPinout> Funcoes { get; set; }
|
|
public bool Controlar { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Liberado
|
|
{
|
|
get
|
|
{
|
|
return !Mandatorio || (Controlar && Inicializado);
|
|
}
|
|
}
|
|
public bool AtuacaoNivelAlto { get; set; }
|
|
public Estado StatusControle { get; set; }
|
|
public bool Inicializado { get; set; }
|
|
public DateTime UltimaLeitura
|
|
{
|
|
get
|
|
{
|
|
return ValoresLeituras?
|
|
.Where(x => x?.atual != null)
|
|
.OrderByDescending(x => x.atual.lidoEm)
|
|
.FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
|
|
}
|
|
}
|
|
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
|
|
public Estado _EstadoLeitura => (Estado)(ValoresLeituras?.FirstOrDefault(x => x?.funcao == FuncoesPinout.EstadoLeitura)?.atual?.valor ?? 0);
|
|
|
|
|
|
public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue;
|
|
public Estado UltimoEstadoDesejado { get; set; } = Estado.Desligado;
|
|
|
|
|
|
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
|
|
{
|
|
var pino = pinout?.Pinos?.FirstOrDefault(p => p?.ComponenteID == ID);
|
|
List<byte> config = new List<byte>
|
|
{
|
|
(byte)Componente,
|
|
(byte)(conectar ? 1 : 0),
|
|
(byte)(AtuacaoNivelAlto ? 1 : 0),
|
|
(byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR),
|
|
(byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO)
|
|
};
|
|
|
|
return (CanMessagePosicaoDados.Config1, config.ToArray());
|
|
}
|
|
|
|
public (int, CanMessagePosicaoDados, byte[]) ProtocoloComando()
|
|
{
|
|
return (
|
|
ID_Num,
|
|
CanMessagePosicaoDados.Command1,
|
|
new byte[]
|
|
{
|
|
(byte)StatusControle
|
|
}
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
public class SensorServoModel
|
|
{
|
|
public string ID { get; set; }
|
|
public int ID_Num { get; set; }
|
|
public string Descricao { get; set; }
|
|
public S_Code Componente { get; set; }
|
|
public List<FuncoesPinout> Funcoes { get; set; }
|
|
public bool Incremental { get; set; }
|
|
|
|
public bool Controlar { get; set; }
|
|
public bool Mandatorio { get; set; }
|
|
public bool Liberado
|
|
{
|
|
get
|
|
{
|
|
return !Mandatorio || (Controlar && Inicializado);
|
|
}
|
|
}
|
|
public int AnguloNeutro { get; set; }
|
|
public int _AnguloControle { get; set; }
|
|
public int _AnguloLeiutra => (int)(ValoresLeituras?.FirstOrDefault(x => x?.funcao == FuncoesPinout.ServoAnguloLeitura)?.atual?.valor ?? -1);
|
|
public bool Inicializado { get; set; }
|
|
public DateTime UltimaLeitura
|
|
{
|
|
get
|
|
{
|
|
return ValoresLeituras?
|
|
.Where(x => x?.atual != null)
|
|
.OrderByDescending(x => x.atual.lidoEm)
|
|
.FirstOrDefault()?.atual?.lidoEm ?? DateTime.MinValue;
|
|
}
|
|
}
|
|
public List<SensorValoresLeituraModel> ValoresLeituras { get; set; }
|
|
|
|
public DateTime UltimoComandoEnviado { get; set; } = DateTime.MinValue;
|
|
public double UltimoAnguloDesejado { get; set; } = 0;
|
|
|
|
public (CanMessagePosicaoDados, byte[]) ProtocoloConfiguracao(PinoutDataModel pinout, bool conectar)
|
|
{
|
|
var pino = pinout?.Pinos?.FirstOrDefault(p => p?.ComponenteID == ID);
|
|
|
|
List<byte> config = new List<byte>
|
|
{
|
|
(byte)Componente,
|
|
(byte)(conectar ? 1 : 0),
|
|
(byte)(Incremental ? 1 : 0),
|
|
(byte)(pino?.Barramento ?? TiposBarramentos.CONTROLADOR),
|
|
(byte)(pino?.Pino ?? PinoutUtils.PINO_INVALIDO)
|
|
};
|
|
|
|
return (CanMessagePosicaoDados.Config1, config.ToArray());
|
|
}
|
|
|
|
public (int, CanMessagePosicaoDados, byte[]) ProtocoloComando()
|
|
{
|
|
int anguloSeguro = Math.Max(0, Math.Min(180, _AnguloControle));
|
|
|
|
return (
|
|
ID_Num,
|
|
CanMessagePosicaoDados.Command1,
|
|
new byte[]
|
|
{
|
|
(byte)anguloSeguro
|
|
}
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public class SensorSinaleiroComportamentoModel
|
|
{
|
|
public int id { get; set; }
|
|
public StatusOperacao? statusOperacao { get; set; }
|
|
public StatusLED statusLED { get; set; }
|
|
public int QtdPiscadas { get; set; } = 0;
|
|
public int TempoMs { get; set; } = 0;
|
|
public int PausaMs { get; set; } = 0;
|
|
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (obj == null || GetType() != obj.GetType())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
SensorSinaleiroComportamentoModel other = (SensorSinaleiroComportamentoModel)obj;
|
|
return statusLED == other.statusLED &&
|
|
QtdPiscadas == other.QtdPiscadas &&
|
|
TempoMs == other.TempoMs &&
|
|
PausaMs == other.PausaMs &&
|
|
statusOperacao == other.statusOperacao &&
|
|
id == other.id;
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
unchecked // Permite overflow de inteiros
|
|
{
|
|
int hash = 17;
|
|
hash = hash * 23 + statusLED.GetHashCode();
|
|
hash = hash * 23 + QtdPiscadas.GetHashCode();
|
|
hash = hash * 23 + TempoMs.GetHashCode();
|
|
hash = hash * 23 + PausaMs.GetHashCode();
|
|
hash = hash * 23 + id.GetHashCode();
|
|
hash = hash * 23 + statusOperacao.GetHashCode();
|
|
return hash;
|
|
}
|
|
}
|
|
|
|
public static bool operator ==(SensorSinaleiroComportamentoModel left, SensorSinaleiroComportamentoModel right)
|
|
{
|
|
if (ReferenceEquals(left, right))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if ((object)left == null || (object)right == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return left.Equals(right);
|
|
}
|
|
|
|
public static bool operator !=(SensorSinaleiroComportamentoModel left, SensorSinaleiroComportamentoModel right)
|
|
{
|
|
return !(left == right);
|
|
}
|
|
}
|
|
|
|
public class SensorParametroModel
|
|
{
|
|
public string Descricao { get; set; }
|
|
public string Valor { get; set; }
|
|
public int QtdBytes { get; set; }
|
|
public bool Escalar { get; set; }
|
|
public bool Enviar { get; set; }
|
|
|
|
|
|
public byte[] InterpretarParametro()
|
|
{
|
|
if (QtdBytes != 1 && QtdBytes != 2)
|
|
throw new InvalidOperationException($"Parâmetro '{Descricao}' possui QtdBytes inválido: {QtdBytes}.");
|
|
|
|
string valor = (Valor ?? string.Empty).Replace(",", ".").Trim();
|
|
if (valor.Length == 0)
|
|
throw new FormatException($"Parâmetro '{Descricao}' não possui valor.");
|
|
|
|
// HEX direto
|
|
if (valor.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
uint parsedHex;
|
|
if (!uint.TryParse(valor.Substring(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out parsedHex))
|
|
throw new FormatException($"Valor hexadecimal inválido em '{Descricao}': {Valor}.");
|
|
|
|
uint maximo = QtdBytes == 1 ? byte.MaxValue : ushort.MaxValue;
|
|
if (parsedHex > maximo)
|
|
throw new OverflowException($"Valor de '{Descricao}' não cabe em {QtdBytes} byte(s): {Valor}.");
|
|
|
|
if (QtdBytes == 1)
|
|
return new byte[] { (byte)parsedHex };
|
|
|
|
return new byte[]
|
|
{
|
|
(byte)(parsedHex >> 8),
|
|
(byte)(parsedHex & 0xFF),
|
|
};
|
|
}
|
|
|
|
// FLOAT com ou sem ponto
|
|
double numero;
|
|
if (!double.TryParse(valor, NumberStyles.Float, CultureInfo.InvariantCulture, out numero))
|
|
throw new FormatException($"Valor numérico inválido em '{Descricao}': {Valor}.");
|
|
|
|
double escalado = Escalar ? numero * 100.0 : numero;
|
|
if (double.IsNaN(escalado) || double.IsInfinity(escalado))
|
|
throw new OverflowException($"Valor não finito em '{Descricao}': {Valor}.");
|
|
|
|
if (escalado < int.MinValue || escalado > int.MaxValue)
|
|
throw new OverflowException($"Valor fora do intervalo inteiro em '{Descricao}': {Valor}.");
|
|
|
|
int final = (int)escalado;
|
|
|
|
if (QtdBytes == 1)
|
|
{
|
|
if (final < sbyte.MinValue || final > byte.MaxValue)
|
|
throw new OverflowException($"Valor de '{Descricao}' não cabe em 1 byte: {final}.");
|
|
|
|
return new byte[] { unchecked((byte)final) };
|
|
}
|
|
|
|
if (final < short.MinValue || final > ushort.MaxValue)
|
|
throw new OverflowException($"Valor de '{Descricao}' não cabe em 2 bytes: {final}.");
|
|
|
|
ushort codificado = unchecked((ushort)final);
|
|
|
|
return new byte[] {
|
|
(byte)(codificado >> 8),
|
|
(byte)(codificado & 0xFF)
|
|
};
|
|
}
|
|
}
|
|
|
|
public class SensorValoresLeituraModel
|
|
{
|
|
public FuncoesPinout funcao { get; set; }
|
|
public CanMessagePosicaoDados posicao { get; set; }
|
|
public int indice { get; set; }
|
|
public double minimo { get; set; }
|
|
public double maximo { get; set; }
|
|
public double nominal { get; set; }
|
|
public double offset { get; set; } = 0.0;
|
|
public CanCommandFreqModel<dynamic> atual { get; set; } = new CanCommandFreqModel<dynamic>();
|
|
public bool analise_health { get; set; } = false;
|
|
public string unidade_medida { get; set; }
|
|
}
|
|
|
|
public class SensoriamentoMensagemJsonModel
|
|
{
|
|
public DateTime Momento { get; set; }
|
|
public bool Conectado { get; set; }
|
|
public T_Code Dispositivo { get; set; }
|
|
public int Versao { get; set; }
|
|
public string Mod_ID { get; set; }
|
|
public int LatenciaLoop { get; set; }
|
|
public Dictionary<CanMessagePosicaoDados, byte[]> StatusI2C { get; set; }
|
|
public DateTime UltimoComandoRespondido { get; set; } = DateTime.MinValue;
|
|
}
|
|
|
|
public class SenHandler : ICanMessageHandler
|
|
{
|
|
public T_Code Dispositivo { get; set; } = T_Code.Sen;
|
|
private readonly object _logFrameLock = new object();
|
|
private DateTime _ultimoLogFrameInvalido = DateTime.MinValue;
|
|
private int _framesInvalidosSuprimidos = 0;
|
|
|
|
private void LogFrameInvalido(string motivo)
|
|
{
|
|
lock (_logFrameLock)
|
|
{
|
|
DateTime agora = DateTime.Now;
|
|
if ((agora - _ultimoLogFrameInvalido).TotalMilliseconds < 1000)
|
|
{
|
|
_framesInvalidosSuprimidos++;
|
|
return;
|
|
}
|
|
|
|
string suprimidos = _framesInvalidosSuprimidos > 0
|
|
? $"; suprimidos={_framesInvalidosSuprimidos}"
|
|
: string.Empty;
|
|
|
|
Variaveis.MostrarLog($"[SEN/RX] Frame descartado: {motivo}{suprimidos}");
|
|
_ultimoLogFrameInvalido = agora;
|
|
_framesInvalidosSuprimidos = 0;
|
|
}
|
|
}
|
|
|
|
private bool FrameValido(byte[] data, S_Code componente, CanMessagePosicaoDados posicao, out string motivo)
|
|
{
|
|
motivo = null;
|
|
|
|
if (data == null || data.Length < 2)
|
|
{
|
|
motivo = "payload nulo ou menor que 2 bytes";
|
|
return false;
|
|
}
|
|
|
|
int minimo;
|
|
|
|
switch (componente)
|
|
{
|
|
case S_Code.sMOD:
|
|
minimo =
|
|
posicao == CanMessagePosicaoDados.Status ? 5 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados2 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados3 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados4 ? 8 :
|
|
-1;
|
|
break;
|
|
case S_Code.sTOD:
|
|
minimo = posicao == CanMessagePosicaoDados.DadosAll ? 4 : -1;
|
|
break;
|
|
case S_Code.sNTC:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 8 : -1;
|
|
break;
|
|
case S_Code.sCOR:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados2 ? 8 : -1;
|
|
break;
|
|
case S_Code.sLED:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 4 : -1;
|
|
break;
|
|
case S_Code.sRLE:
|
|
case S_Code.sSRV:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 3 : -1;
|
|
break;
|
|
case S_Code.sIMU:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados2 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados3 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados4 ? 8 :
|
|
posicao == CanMessagePosicaoDados.Dados5 ? 8 : -1;
|
|
break;
|
|
case S_Code.sGAS:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 8 : -1;
|
|
break;
|
|
case S_Code.sSHT:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 6 : -1;
|
|
break;
|
|
case S_Code.sLUZ:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 6 : -1;
|
|
break;
|
|
case S_Code.sIUV:
|
|
case S_Code.sCHV:
|
|
case S_Code.sMAG:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 6 : -1;
|
|
break;
|
|
case S_Code.sQAR:
|
|
minimo = posicao == CanMessagePosicaoDados.Status ? 3 :
|
|
posicao == CanMessagePosicaoDados.Dados1 ? 7 :
|
|
posicao == CanMessagePosicaoDados.Dados2 ? 6 : -1;
|
|
break;
|
|
default:
|
|
motivo = $"componente não suportado ({componente})";
|
|
return false;
|
|
}
|
|
|
|
if (minimo < 0)
|
|
{
|
|
motivo = $"posição {posicao} não suportada para {componente}";
|
|
return false;
|
|
}
|
|
|
|
if (data.Length < minimo)
|
|
{
|
|
motivo = $"payload curto para {componente}/{posicao}: {data.Length} < {minimo}";
|
|
return false;
|
|
}
|
|
|
|
if (componente == S_Code.sMOD && posicao == CanMessagePosicaoDados.Status && data[3] > 1)
|
|
{
|
|
motivo = $"flag Conectado inválida no sMOD: {data[3]}";
|
|
return false;
|
|
}
|
|
|
|
if (componente != S_Code.sMOD && posicao == CanMessagePosicaoDados.Status && data[2] > 1)
|
|
{
|
|
motivo = $"flag Iniciado inválida em {componente}: {data[2]}";
|
|
return false;
|
|
}
|
|
|
|
if (componente == S_Code.sLED && posicao == CanMessagePosicaoDados.Dados1 &&
|
|
!Enum.IsDefined(typeof(StatusLED), (StatusLED)data[3]))
|
|
{
|
|
motivo = $"status de LED inválido: {data[3]}";
|
|
return false;
|
|
}
|
|
|
|
if (componente == S_Code.sRLE && posicao == CanMessagePosicaoDados.Dados1 &&
|
|
!Enum.IsDefined(typeof(Estado), (Estado)data[2]))
|
|
{
|
|
motivo = $"estado de relé inválido: {data[2]}";
|
|
return false;
|
|
}
|
|
|
|
if (componente == S_Code.sSRV && posicao == CanMessagePosicaoDados.Dados1 && data[2] > 180)
|
|
{
|
|
motivo = $"ângulo de servo inválido: {data[2]}";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private double ConverterByteParaDouble(byte[] data, int idx)
|
|
{
|
|
int raw = (data[idx] << 8) | data[idx + 1];
|
|
short _short = (short)raw;
|
|
double _value = _short / 100.0;
|
|
|
|
return _value;
|
|
}
|
|
|
|
private double ConverterBytesParaDouble32(byte[] data, int idx)
|
|
{
|
|
int valor = (data[idx] << 24) | (data[idx + 1] << 16) | (data[idx + 2] << 8) | data[idx + 3];
|
|
return valor / 100.0;
|
|
}
|
|
|
|
private double ConverterValorEscala(byte[] data, int idx, double escala)
|
|
{
|
|
int raw = (data[idx] << 8) | data[idx + 1];
|
|
return raw * escala;
|
|
}
|
|
|
|
private ushort Converter2BytesU16(byte[] data, int idx)
|
|
{
|
|
return (ushort)((data[idx] << 8) | data[idx + 1]);
|
|
}
|
|
|
|
private short Converter2BytesI16(byte[] data, int idx)
|
|
{
|
|
ushort raw = Converter2BytesU16(data, idx);
|
|
return unchecked((short)raw);
|
|
}
|
|
|
|
private double ConverterAngle100(byte[] data, int idx)
|
|
{
|
|
ushort v = (ushort)((data[idx] << 8) | data[idx + 1]);
|
|
return v / 100.0;
|
|
}
|
|
|
|
private double ConverterTemperaturaNtc(byte[] data, int idx)
|
|
{
|
|
short raw = Converter2BytesI16(data, idx);
|
|
|
|
// Sentinel enviado pela firmware para temperatura inválida.
|
|
if (raw == short.MinValue)
|
|
return double.NaN;
|
|
|
|
return raw / 100.0;
|
|
}
|
|
|
|
private double ConverterTensaoNtc(byte[] data, int idx)
|
|
{
|
|
ushort milivolts = Converter2BytesU16(data, idx);
|
|
|
|
// Sentinel 0xFFFF enviado pela firmware para tensão inválida.
|
|
if (milivolts == ushort.MaxValue)
|
|
return double.NaN;
|
|
|
|
return milivolts / 1000.0;
|
|
}
|
|
|
|
|
|
#region DIAGNOSTICO
|
|
private static bool Bit(byte valor, int bit)
|
|
{
|
|
return (valor & (1 << bit)) != 0;
|
|
}
|
|
|
|
private void LogDiagnosticoI2CDados1(byte[] data)
|
|
{
|
|
byte estado = data[2];
|
|
byte tca = data[3];
|
|
|
|
bool i2c =
|
|
Bit(estado, 0);
|
|
|
|
bool mux =
|
|
Bit(estado, 1);
|
|
|
|
bool muxOk =
|
|
Bit(estado, 2);
|
|
|
|
bool recovery =
|
|
Bit(estado, 3);
|
|
|
|
bool pendente =
|
|
Bit(estado, 4);
|
|
|
|
bool sda =
|
|
Bit(estado, 5);
|
|
|
|
bool scl =
|
|
Bit(estado, 6);
|
|
|
|
bool possuiFalha =
|
|
Bit(estado, 7);
|
|
|
|
|
|
bool rdyConfigurado =
|
|
Bit(tca, 0);
|
|
|
|
bool rdy =
|
|
Bit(tca, 1);
|
|
|
|
bool enConfigurado =
|
|
Bit(tca, 2);
|
|
|
|
bool en =
|
|
Bit(tca, 3);
|
|
|
|
bool quarentenaMux =
|
|
Bit(tca, 4);
|
|
|
|
bool quarentenaAds =
|
|
Bit(tca, 5);
|
|
|
|
|
|
int geracao =
|
|
data[4];
|
|
|
|
int recoveries =
|
|
data[5];
|
|
|
|
int falhasRecovery =
|
|
data[6];
|
|
|
|
int falhasTx =
|
|
data[7];
|
|
|
|
|
|
string tcaRdy =
|
|
rdyConfigurado
|
|
? (rdy ? "HIGH" : "LOW")
|
|
: "NA";
|
|
|
|
string tcaEn =
|
|
enConfigurado
|
|
? (en ? "HIGH" : "LOW")
|
|
: "NA";
|
|
|
|
|
|
Variaveis.MostrarLog(
|
|
"[SEN/I2C] BASE" +
|
|
$" | wire={(i2c ? 1 : 0)}" +
|
|
$" mux={(mux ? 1 : 0)}" +
|
|
$" mux_ok={(muxOk ? 1 : 0)}" +
|
|
$" recovery={(recovery ? 1 : 0)}" +
|
|
$" pendente={(pendente ? 1 : 0)}" +
|
|
$" SDA={(sda ? 1 : 0)}" +
|
|
$" SCL={(scl ? 1 : 0)}" +
|
|
$" TCA_RDY={tcaRdy}" +
|
|
$" TCA_EN={tcaEn}" +
|
|
$" geracao={geracao}" +
|
|
$" recoveries={recoveries}" +
|
|
$" falhas_recovery={falhasRecovery}" +
|
|
$" falhas_tx={falhasTx}" +
|
|
$" q_mux={(quarentenaMux ? 1 : 0)}" +
|
|
$" q_ads={(quarentenaAds ? 1 : 0)}" +
|
|
$" historico_falha={(possuiFalha ? 1 : 0)}"
|
|
);
|
|
}
|
|
|
|
private void LogDiagnosticoI2CDados2(byte[] data)
|
|
{
|
|
byte idFalha = data[2];
|
|
byte canalFalha = data[3];
|
|
|
|
byte muxEsperado = data[4];
|
|
byte muxValidado = data[5];
|
|
byte muxQuarentena = data[6];
|
|
byte inasIniciados = data[7];
|
|
|
|
|
|
string idFalhaTxt =
|
|
idFalha == 0xFF
|
|
? "nenhum"
|
|
: NomeIdI2CDebug(idFalha);
|
|
|
|
string canalFalhaTxt =
|
|
canalFalha == 0xFF
|
|
? "nenhum"
|
|
: canalFalha.ToString();
|
|
|
|
|
|
Variaveis.MostrarLog(
|
|
"[SEN/I2C] TOPO" +
|
|
$" | ultimo_id={idFalhaTxt}" +
|
|
$" ultimo_canal={canalFalhaTxt}" +
|
|
$" mux_esperado=0x{muxEsperado:X2}" +
|
|
$" mux_validado=0x{muxValidado:X2}" +
|
|
$" q_mux=0x{muxQuarentena:X2}" +
|
|
$" q_mux_sensores={DecodificarQuarentenaMux(muxQuarentena)}" +
|
|
$" ina_mask=0x{inasIniciados:X2}" +
|
|
$" inas={DecodificarInaMask(inasIniciados)}"
|
|
);
|
|
}
|
|
|
|
private void LogDiagnosticoI2CDados3(byte[] data)
|
|
{
|
|
if (data == null || data.Length < 8)
|
|
return;
|
|
|
|
ushort maxAdsMs = Converter2BytesU16(data, 2);
|
|
ushort timeoutsAds = Converter2BytesU16(data, 4);
|
|
ushort readyDropsAds = Converter2BytesU16(data, 6);
|
|
|
|
Console.WriteLine(
|
|
"[AGROBASE] [SEN/I2C] ADS | " +
|
|
$"max_ms={maxAdsMs} " +
|
|
$"timeouts={timeoutsAds} " +
|
|
$"ready_drops={readyDropsAds}"
|
|
);
|
|
|
|
}
|
|
|
|
private void LogDiagnosticoI2CDados4(byte[] data)
|
|
{
|
|
if (data == null || data.Length < 8)
|
|
return;
|
|
|
|
ushort maxStart = Converter2BytesU16(data, 2);
|
|
ushort maxRead = Converter2BytesU16(data, 4);
|
|
ushort falhasIo = Converter2BytesU16(data, 6);
|
|
|
|
Console.WriteLine(
|
|
"[AGROBASE] [SEN/I2C] ADS_IO | " +
|
|
$"start_max={maxStart}ms " +
|
|
$"read_max={maxRead}ms " +
|
|
$"io_fail={falhasIo}"
|
|
);
|
|
}
|
|
|
|
private static string NomeIdI2CDebug(byte id)
|
|
{
|
|
switch (id)
|
|
{
|
|
case 11: return "AB3V(11)";
|
|
case 12: return "AB5V(12)";
|
|
case 13: return "AB7V2(13)";
|
|
case 14: return "AB12V(14)";
|
|
case 15: return "AB19V(15)";
|
|
case 16: return "AB24V(16)";
|
|
case 17: return "AB36V(17)";
|
|
|
|
case 200:
|
|
return "MUX(200)";
|
|
|
|
case 201:
|
|
return "MCP(201)";
|
|
|
|
default:
|
|
return id.ToString();
|
|
}
|
|
}
|
|
|
|
private static string DecodificarInaMask(byte mask)
|
|
{
|
|
string[] nomes =
|
|
{
|
|
"AB3V",
|
|
"AB5V",
|
|
"AB7V2",
|
|
"AB12V",
|
|
"AB19V",
|
|
"AB24V",
|
|
"AB36V"
|
|
};
|
|
|
|
var ativos =
|
|
new List<string>();
|
|
|
|
for (int i = 0; i < nomes.Length; i++)
|
|
{
|
|
if ((mask & (1 << i)) != 0)
|
|
ativos.Add(nomes[i]);
|
|
}
|
|
|
|
return ativos.Count > 0
|
|
? string.Join(",", ativos)
|
|
: "nenhum";
|
|
}
|
|
|
|
private static string DecodificarQuarentenaMux(byte mask)
|
|
{
|
|
var itens = new List<string>();
|
|
|
|
for (int canal = 0; canal < 8; canal++)
|
|
{
|
|
if ((mask & (1 << canal)) == 0)
|
|
continue;
|
|
|
|
string nome;
|
|
|
|
switch (canal)
|
|
{
|
|
case 1:
|
|
nome = "CH1/AB19V";
|
|
break;
|
|
|
|
case 2:
|
|
nome = "CH2/AB7V2";
|
|
break;
|
|
|
|
case 3:
|
|
nome = "CH3/AB12V";
|
|
break;
|
|
|
|
case 4:
|
|
nome = "CH4/AB5V";
|
|
break;
|
|
|
|
case 5:
|
|
nome = "CH5/AB3V";
|
|
break;
|
|
|
|
case 6:
|
|
nome = "CH6/AB24V";
|
|
break;
|
|
|
|
case 7:
|
|
nome = "CH7/AB36V";
|
|
break;
|
|
|
|
default:
|
|
nome = $"CH{canal}";
|
|
break;
|
|
}
|
|
|
|
itens.Add(nome);
|
|
}
|
|
|
|
return itens.Count > 0
|
|
? string.Join(",", itens)
|
|
: "nenhum";
|
|
}
|
|
|
|
#endregion
|
|
|
|
|
|
private bool TryDetectarComponenteDoID_Num(SensoriamentoModel dados, int ID_Num, out S_Code componente, out string motivo)
|
|
{
|
|
componente = default(S_Code);
|
|
motivo = null;
|
|
|
|
if (ID_Num == Variaveis.ID_Num_sMOD)
|
|
{
|
|
componente = S_Code.sMOD;
|
|
return true;
|
|
}
|
|
|
|
if (ID_Num == Variaveis.ID_Num_sTOD)
|
|
{
|
|
componente = S_Code.sTOD;
|
|
return true;
|
|
}
|
|
|
|
if (dados == null)
|
|
{
|
|
motivo = "modelo do SEN indisponível";
|
|
return false;
|
|
}
|
|
|
|
var encontrados = new List<S_Code>();
|
|
|
|
encontrados.AddRange((dados.Sensores ?? new List<SensorModel>())
|
|
.Where(x => x != null && x.ID_Num == ID_Num)
|
|
.Select(x => x.Componente));
|
|
encontrados.AddRange((dados.Reles ?? new List<SensorReleModel>())
|
|
.Where(x => x != null && x.ID_Num == ID_Num)
|
|
.Select(x => x.Componente));
|
|
encontrados.AddRange((dados.Sinaleiros ?? new List<SensorSinaleiroModel>())
|
|
.Where(x => x != null && x.ID_Num == ID_Num)
|
|
.Select(x => x.Componente));
|
|
encontrados.AddRange((dados.Servos ?? new List<SensorServoModel>())
|
|
.Where(x => x != null && x.ID_Num == ID_Num)
|
|
.Select(x => x.Componente));
|
|
|
|
if (encontrados.Count == 0)
|
|
{
|
|
motivo = $"ID_Num desconhecido ({ID_Num})";
|
|
return false;
|
|
}
|
|
|
|
if (encontrados.Count > 1)
|
|
{
|
|
motivo = $"ID_Num ambíguo ({ID_Num}); ocorrências={encontrados.Count}";
|
|
return false;
|
|
}
|
|
|
|
componente = encontrados[0];
|
|
return true;
|
|
}
|
|
|
|
private void AtualizarDados(SensoriamentoModel Dados, int CompID_Num, CanMessagePosicaoDados Posicao, S_Code componente, List<dynamic> Parametros)
|
|
{
|
|
if (Dados == null)
|
|
throw new InvalidOperationException("Modelo do SEN indisponível durante atualização.");
|
|
|
|
var sensor = Dados.Sensores?.FirstOrDefault(x => x?.ID_Num == CompID_Num);
|
|
var rele = Dados.Reles?.FirstOrDefault(x => x?.ID_Num == CompID_Num);
|
|
var sinaleiro = Dados.Sinaleiros?.FirstOrDefault(x => x?.ID_Num == CompID_Num);
|
|
var servo = Dados.Servos?.FirstOrDefault(x => x?.ID_Num == CompID_Num);
|
|
|
|
List<SensorValoresLeituraModel> valoresLeituras = null;
|
|
|
|
if (sensor != null) valoresLeituras = sensor.ValoresLeituras;
|
|
else if (rele != null) valoresLeituras = rele.ValoresLeituras;
|
|
else if (sinaleiro != null) valoresLeituras = sinaleiro.ValoresLeituras;
|
|
else if (servo != null) valoresLeituras = servo.ValoresLeituras;
|
|
|
|
var leiturasDaPosicao = valoresLeituras?
|
|
.Where(x => x != null && x.posicao == Posicao)
|
|
.OrderBy(x => x.indice)
|
|
.ToList();
|
|
|
|
if (leiturasDaPosicao == null || leiturasDaPosicao.Count == 0)
|
|
throw new InvalidOperationException($"Sem mapeamento de leitura para {componente}/{CompID_Num}/{Posicao}.");
|
|
|
|
if (Parametros == null || Parametros.Count < leiturasDaPosicao.Count)
|
|
throw new InvalidOperationException(
|
|
$"Parâmetros insuficientes para {componente}/{CompID_Num}/{Posicao}: " +
|
|
$"recebidos={Parametros?.Count ?? 0}, esperados={leiturasDaPosicao.Count}."
|
|
);
|
|
|
|
foreach (var valor in leiturasDaPosicao)
|
|
{
|
|
int indice = valor.indice;
|
|
if (indice < 0 || indice >= Parametros.Count)
|
|
throw new InvalidOperationException($"Índice de leitura inválido em {componente}/{CompID_Num}/{Posicao}: {indice}.");
|
|
|
|
if (valor.atual == null)
|
|
valor.atual = new CanCommandFreqModel<dynamic>();
|
|
|
|
dynamic v = Parametros[indice];
|
|
if (v is sbyte || v is byte || v is short || v is ushort || v is int || v is uint ||
|
|
v is long || v is ulong || v is float || v is double || v is decimal)
|
|
{
|
|
v += valor.offset;
|
|
valor.atual.valor = v;
|
|
}
|
|
else
|
|
{
|
|
valor.atual.valor = v;
|
|
}
|
|
|
|
if (valor.funcao == FuncoesPinout.Iniciado && valor.posicao == CanMessagePosicaoDados.Status)
|
|
{
|
|
if (!(v is bool))
|
|
throw new InvalidOperationException($"Status Iniciado não booleano em {componente}/{CompID_Num}: {v}.");
|
|
|
|
bool iniciado = (bool)v;
|
|
if (sensor != null) sensor.Inicializado = iniciado;
|
|
if (rele != null) rele.Inicializado = iniciado;
|
|
if (sinaleiro != null) sinaleiro.Inicializado = iniciado;
|
|
if (servo != null) servo.Inicializado = iniciado;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void ProcessarMensagem(CanMessage mensagem)
|
|
{
|
|
if (mensagem?.DataRx == null || mensagem.DataRx.Length < 2)
|
|
{
|
|
LogFrameInvalido("payload nulo ou incompleto");
|
|
return;
|
|
}
|
|
|
|
CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)mensagem.DataRx[0];
|
|
byte ID_Num = mensagem.DataRx[1];
|
|
var data = mensagem.DataRx;
|
|
|
|
var op = Variaveis.OperacaoEmAndamento;
|
|
var Dados = op?.DispSen?.Dados;
|
|
|
|
if (Dados == null)
|
|
{
|
|
LogFrameInvalido("operação ou modelo do SEN indisponível");
|
|
return;
|
|
}
|
|
|
|
S_Code componente;
|
|
string motivoDeteccao;
|
|
|
|
lock (Dados.EstadoSyncRoot)
|
|
{
|
|
if (!TryDetectarComponenteDoID_Num(Dados, ID_Num, out componente, out motivoDeteccao))
|
|
{
|
|
LogFrameInvalido(motivoDeteccao);
|
|
return;
|
|
}
|
|
|
|
string motivoFrame;
|
|
if (!FrameValido(data, componente, posicao, out motivoFrame))
|
|
{
|
|
LogFrameInvalido($"ID={ID_Num}; {motivoFrame}");
|
|
return;
|
|
}
|
|
|
|
Variaveis.MostrarLog($"[SEN] Componente={componente.ToString()}, ID_Num={ID_Num}, Data={FuncoesGlobais.ConverterComandoBytesParaTexto(data)}");
|
|
|
|
try
|
|
{
|
|
if (Dados.DadosLeitura == null)
|
|
Dados.DadosLeitura = new SensoriamentoMensagemJsonModel();
|
|
|
|
switch (componente)
|
|
{
|
|
case S_Code.sMOD:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
T_Code tipoModulo = (T_Code)data[2];
|
|
|
|
if (tipoModulo != T_Code.Sen)
|
|
{
|
|
LogFrameInvalido($"sMOD destinado a {tipoModulo}, esperado={T_Code.Sen}");
|
|
return;
|
|
}
|
|
|
|
bool conectado = data[3] == 1;
|
|
int versao = data[4];
|
|
Dados.DadosLeitura.Conectado = conectado;
|
|
Dados.DadosLeitura.Dispositivo = tipoModulo;
|
|
Dados.DadosLeitura.Versao = versao;
|
|
Dados.DadosLeitura.Mod_ID = Dados.Modulo_ID;
|
|
break;
|
|
}
|
|
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
LogDiagnosticoI2CDados1(data);
|
|
break;
|
|
}
|
|
|
|
case CanMessagePosicaoDados.Dados2:
|
|
{
|
|
LogDiagnosticoI2CDados2(data);
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados3:
|
|
{
|
|
LogDiagnosticoI2CDados3(data);
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados4:
|
|
{
|
|
LogDiagnosticoI2CDados4(data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!(Dados.DadosLeitura?.StatusI2C?.Any() ?? false))
|
|
Dados.DadosLeitura.StatusI2C = new Dictionary<CanMessagePosicaoDados, byte[]>();
|
|
Dados.DadosLeitura.StatusI2C[posicao] = data;
|
|
|
|
break;
|
|
}
|
|
case S_Code.sTOD:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.DadosAll:
|
|
{
|
|
double latenciaLoop = ConverterByteParaDouble(data, 2) * 100;
|
|
Dados.DadosLeitura.LatenciaLoop = Convert.ToInt32(latenciaLoop);
|
|
//Console.WriteLine($"[SEN] Ciclo concluido. Latencia de loop: {latenciaLoop} ms");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sNTC:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
ushort raw = Converter2BytesU16(data, 2);
|
|
double temperatura = ConverterTemperaturaNtc(data, 4);
|
|
double tensao = ConverterTensaoNtc(data, 6);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { raw, temperatura, tensao });
|
|
//Variaveis.MostrarLog($"[SEN] sNTC | ID_Num: {ID_Num} | Posicao: {posicao} | Leitura: {raw} | Temperatura: {temperatura} | Tensao: {tensao}");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sCOR:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
double busVoltage = ConverterByteParaDouble(data, 2); // continua igual
|
|
double current = ConverterByteParaDouble(data, 4) * 1000.0; // volts / 100, amps * 10 (volta para mA)
|
|
double power = ConverterByteParaDouble(data, 6) * 1000.0; // volta para mW
|
|
//Console.WriteLine($"[AB36V] Tensao {busVoltage}, Corrente: {current}, Power: {power}");
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { busVoltage, current, power });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados2:
|
|
{
|
|
double energia = ConverterByteParaDouble(data, 2) * 1000.0; // volta para mWh
|
|
double temperatura = ConverterByteParaDouble(data, 4); // volta para °C
|
|
double codAlarme = ConverterByteParaDouble(data, 6) * 100; // volta para °C
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { energia, temperatura, codAlarme });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sLED:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
int statusId = data[2];
|
|
StatusLED statusLeitura = (StatusLED)data[3];
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { statusId, statusLeitura });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sRLE:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
Estado estado = (Estado)data[2];
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { estado });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sSRV:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
int angulo = data[2];
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { angulo });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sIMU:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
double roll = ConverterByteParaDouble(data, 2);
|
|
double pitch = ConverterByteParaDouble(data, 4);
|
|
double yaw = ConverterByteParaDouble(data, 6);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { roll, pitch, yaw });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados2:
|
|
{
|
|
double temperatura = ConverterByteParaDouble(data, 2);
|
|
double pressao = ConverterValorEscala(data, 4, 10);
|
|
double altitude = ConverterValorEscala(data, 6, 10);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { temperatura, pressao, altitude });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados3:
|
|
{
|
|
double accX = ConverterByteParaDouble(data, 2);
|
|
double accY = ConverterByteParaDouble(data, 4);
|
|
double accZ = ConverterByteParaDouble(data, 6);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { accX, accY, accZ });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados4:
|
|
{
|
|
double gyrX = ConverterByteParaDouble(data, 2);
|
|
double gyrY = ConverterByteParaDouble(data, 4);
|
|
double gyrZ = ConverterByteParaDouble(data, 6);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { gyrX, gyrY, gyrZ });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados5:
|
|
{
|
|
double magX = ConverterByteParaDouble(data, 2);
|
|
double magY = ConverterByteParaDouble(data, 4);
|
|
double magZ = ConverterByteParaDouble(data, 6);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { magX, magY, magZ });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sGAS:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
ushort raw = Converter2BytesU16(data, 2);
|
|
double ppm = ConverterBytesParaDouble32(data, 4);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { raw, ppm });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sSHT:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
double temperatura = ConverterByteParaDouble(data, 2);
|
|
double umidade = ConverterByteParaDouble(data, 4);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { temperatura, umidade });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sLUZ:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
double lux = ConverterBytesParaDouble32(data, 2);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { lux });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sIUV:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
ushort raw = Converter2BytesU16(data, 2);
|
|
double iuv = ConverterByteParaDouble(data, 4);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { raw, iuv });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sQAR:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
double tvoc = ConverterByteParaDouble(data, 2);
|
|
double eco2 = ConverterByteParaDouble(data, 4);
|
|
int aqi = data[6];
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { tvoc, eco2, aqi });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados2:
|
|
{
|
|
double temperatura = ConverterByteParaDouble(data, 2);
|
|
double umidade = ConverterByteParaDouble(data, 4);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { temperatura, umidade });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sCHV:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
ushort raw = Converter2BytesU16(data, 2);
|
|
double percentual = ConverterByteParaDouble(data, 4);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { raw, percentual });
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case S_Code.sMAG:
|
|
{
|
|
switch (posicao)
|
|
{
|
|
case CanMessagePosicaoDados.Status:
|
|
{
|
|
bool Iniciado = data[2] == 1;
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { Iniciado });
|
|
break;
|
|
}
|
|
case CanMessagePosicaoDados.Dados1:
|
|
{
|
|
ushort raw = Converter2BytesU16(data, 2);
|
|
double angle = ConverterAngle100(data, 4);
|
|
AtualizarDados(Dados, ID_Num, posicao, componente, new List<dynamic>() { raw, angle });
|
|
//Console.WriteLine($"[sMAG] {ID_Num}, Raw: {raw}, Angulo: {angle}");
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
DateTime respostaEm = DateTime.Now;
|
|
Dados.DadosLeitura.Momento = respostaEm;
|
|
Dados.DadosLeitura.UltimoComandoRespondido = respostaEm;
|
|
|
|
if (componente == S_Code.sMOD)
|
|
Dados.ConfirmarMapeamentoAposDescoberta(respostaEm);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFrameInvalido(
|
|
$"erro ao processar {componente}/{ID_Num}/{posicao}: " +
|
|
$"{ex.GetType().Name}: {ex.Message}"
|
|
);
|
|
return;
|
|
}
|
|
}
|
|
|
|
var opAtual = Variaveis.OperacaoEmAndamento;
|
|
if (!ReferenceEquals(opAtual?.DispSen?.Dados, Dados))
|
|
{
|
|
LogFrameInvalido("snapshot do SEN substituído durante o processamento");
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
opAtual?.DispMvd?.Dados?.AtualizarDadosSensoresExternos(componente, ID_Num);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Variaveis.MostrarLog(
|
|
$"[SEN/RX] Falha ao propagar sensor externo {componente}/{ID_Num}: {ex}"
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|