diff --git a/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs b/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs index aa397a7c3..f4c8e400c 100644 --- a/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs +++ b/AgroBase/AgroBase/Models/Modules/MovimentacaoModel.cs @@ -174,14 +174,7 @@ namespace AgroBase.Models.Modules } } - public SensorModel SensorTemperaturaMotor - { - get - { - var sNTC = Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?.FirstOrDefault(x => x.Componente == S_Code.sNTC && x.ID.Contains(Mod_ID)); - return sNTC; - } - } + public SensorModel SensorTemperaturaMotor => Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Sensores?.FirstOrDefault(x => x.Inicializado && x.Componente == S_Code.sNTC && x.ID.Contains(Mod_ID)); public bool Comandar { get; set; } = false; public bool AlarmeSensores { get; set; } = false; @@ -511,34 +504,10 @@ namespace AgroBase.Models.Modules public DateTime UltimoEnvio { get; set; } public int DelayEnvio { get; set; } = 500; - public SensorServoModel Servo - { - get - { - return Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Servos? - .FirstOrDefault(x => x.ID.Contains(Mod_ID)); - } - } - - private double VelocidadeAtual => - FuncoesMatematicas.CalculaVelocidadePercentualMs(Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.VelocidadeMedia ?? 0); - - private bool StatusControleEmFreio => - (Variaveis.OperacaoEmAndamento.Controle?.TiposControle? - .FirstOrDefault(x => x.Tipo == T_Code.Mov)?.UltimaDirecao - ?? Direcao.Parado) == Direcao.EmFreio; - - // leitura atual do ângulo (ou null) - private int AnguloLido - { - get - { - var v = Servo?.ValoresLeituras? - .FirstOrDefault(x => x.funcao == FuncoesPinout.ServoAnguloLeitura)? - .atual?.valor ?? 0; - return (int)v; - } - } + public SensorServoModel Servo => Variaveis.OperacaoEmAndamento.DispSen?.Dados?.Servos?.FirstOrDefault(x => x.Inicializado && x.ID.Contains(Mod_ID)); + private double VelocidadeAtual => FuncoesMatematicas.CalculaVelocidadePercentualMs(Variaveis.OperacaoEmAndamento.Sensoriamento?.Movimentacao?.VelocidadeMedia ?? 0); + private bool StatusControleEmFreio => Variaveis.OperacaoEmAndamento.DispMvd?.Dados?.Modulos?.FirstOrDefault(x => x.Modulo_ID == Mod_ID)?.MovMotor?.Leitura?.Freado ?? false; + private int? AnguloLido => (int?)Servo?.ValoresLeituras?.FirstOrDefault(x => x.funcao == FuncoesPinout.ServoAnguloLeitura)?.atual?.valor; // histerese de velocidade private bool VelocidadeOkHisterese(int sp, double atual) @@ -637,7 +606,7 @@ namespace AgroBase.Models.Modules // Regra: envia quando (a) houve transição de modo, (b) alvo mudou significativamente, // ou (c) não atingiu o alvo atual (com tolerância). bool alvoMudou = Math.Abs(AnguloControle - anguloAntigo) > 0; - bool atingiu = AtingiuSPComTol(AnguloLido, AnguloControle); + bool atingiu = AnguloLido != null && AtingiuSPComTol(AnguloLido, AnguloControle); // histerese de velocidade apenas para DEFINIR o alvo (já considerado acima). // Não use VelocidadeOk para forçar reenvio — isso causa “chatters” de comando. @@ -655,9 +624,9 @@ namespace AgroBase.Models.Modules private void EnviarComandoModulo() { - if (EnviarComando && UltimoEnvio.AddMilliseconds(DelayEnvio) < DateTime.Now) + if (EnviarComando && UltimoEnvio.AddMilliseconds(DelayEnvio) < DateTime.Now && Servo != null) { - GeneralJoystick.EnviarComandoSensoriamento(S_Code.sSRV, Servo.ID, AnguloControle); + GeneralJoystick.EnviarComandoSensoriamento(Servo.Componente, Servo.ID, AnguloControle, Forcar: true); UltimoEnvio = DateTime.Now; } } diff --git a/Firmware/Modulos/IComponenteCan.h b/Firmware/Modulos/IComponenteCan.h index 13600d2f2..8ca2404b7 100644 --- a/Firmware/Modulos/IComponenteCan.h +++ b/Firmware/Modulos/IComponenteCan.h @@ -41,6 +41,39 @@ public: } } } + + template + static void ProcessarComponenteCAN( + T& componente, + const std::vector& posicoes, + bool todosIDs, + int id_num, + bool enviarStatus, + bool todosDados, + CanMessagePosicaoDados posicao, + std::function&)> enviarDadosFunc + ) { + if (todosIDs || componente.ID_Num == id_num) { + componente.RequisitarDados(); + + if (enviarStatus) { + enviarDadosFunc(componente.MontarMensagemCAN(CanMessagePosicaoDados::Status)); + } + + if (componente.Iniciado) { + if (todosDados) { + for (auto p : posicoes) { + if (p == CanMessagePosicaoDados::Status) continue; + enviarDadosFunc(componente.MontarMensagemCAN(p)); + } + } else { + if (posicao != CanMessagePosicaoDados::Status || !enviarStatus) { + enviarDadosFunc(componente.MontarMensagemCAN(posicao)); + } + } + } + } + } }; #endif \ No newline at end of file diff --git a/Firmware/Modulos/ReleModel_v2.h b/Firmware/Modulos/ReleModel_v2.h new file mode 100644 index 000000000..3724cab64 --- /dev/null +++ b/Firmware/Modulos/ReleModel_v2.h @@ -0,0 +1,129 @@ +#include "SerialService.h" +#include "Pinout.h" +#include "Utils.h" +#include "IComponenteCAN.h" + +#ifndef ReleModel_v2 +#define ReleModel_v2 + +class Rele_v2 : public ComponenteCAN { + public: + String ID; + uint8_t ID_Num = 0; + PinoModel _pino; + bool Iniciado = false; + + Rele_v2() {} + + Rele_v2( + const String& id, + uint8_t idNum, + bool atuacaoNivelAlto, + int pino, + TiposBarramentos tipoBarramento + ) : + ID(id), + ID_Num(idNum), + _pino(PinoModel(pino, tipoBarramento, _OUTPUT)), + AtuacaoNivelAlto(atuacaoNivelAlto) + { + } + + void Inicializar() { + if (Iniciado) { + MostrarLog("Rele ja inicializado"); + return; + } + if (_pino.Definido()) { + bool nivelInicial = AtuacaoNivelAlto ? false : true; + _pino.Conectar(nivelInicial); + _Status = Estado::Desligado; + Iniciado = true; + MostrarLog("Rele iniciado"); + } + else { + MostrarLog("Rele nao iniciado"); + } + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Rele nao esta inicializado"); + return; + } + AtualizarStatus(Estado::Desligado); + _pino.Desconectar(); + Iniciado = false; + MostrarLog("Rele desligado"); + } + + void RequisitarDados() { + if (!Iniciado) return; + AtualizarLeitura(); + } + + void ProcessarComando(std::vector& data) { + if (!Iniciado) return; + if (data.size() < 3) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + if (idNum != ID_Num) return; + switch (posicao) { + case CanMessagePosicaoDados::Command1: { + Estado novoEstado = (Estado)data[2]; + AtualizarStatus(novoEstado); + break; + } + } + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + case CanMessagePosicaoDados::Dados1: { + data.push_back(static_cast(_Status)); + break; + } + } + + return data; + } + + private: + bool DebugMode = true; + + bool AtuacaoNivelAlto = true; + Estado _Status = Desligado; + + void AtualizarStatus(Estado novoEstado) { + bool ligado = (novoEstado == Estado::Ligado); + bool nivelPino = AtuacaoNivelAlto ? ligado : !ligado; + MostrarLog("Atualizando status do rele de " + String(_Status) + " para " + String(novoEstado)); + _pino.set(nivelPino); + _Status = novoEstado; + } + + void AtualizarLeitura() { + bool nivelPino = _pino.get(); + bool ligado = AtuacaoNivelAlto ? nivelPino : !nivelPino; + _Status = ligado ? Estado::Ligado : Estado::Desligado; + } + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[RLE " + ID + "] " + mensagem); + } + } + + }; + + + +#endif \ No newline at end of file diff --git a/Firmware/Modulos/SensorCorrenteModel_v2.h b/Firmware/Modulos/SensorCorrenteModel_v2.h new file mode 100644 index 000000000..b4ba99460 --- /dev/null +++ b/Firmware/Modulos/SensorCorrenteModel_v2.h @@ -0,0 +1,218 @@ +#include "SerialService.h" +#include "I2CService.h" +#include "Utils.h" +#include "IComponenteCAN.h" +#include +#include +#include +#include +#include + +#ifndef SensorCorrenteModel_v2 +#define SensorCorrenteModel_v2 + +class SensorCorrente_v2 : public ComponenteCAN { + public: + String ID; + uint8_t ID_Num = 0; + uint8_t _Endereco = 0; + TiposShuntCorrente _A_Shunt = TiposShuntCorrente::INA228_10A; + int _CanalMUX = -1; + bool isINA219 = false; + + bool Iniciado = false; + + float busVoltage = 0; + float current = 0; + float power = 0; + float energy = 0; + float charge = 0; + uint16_t codAlarme = 0; + float temperature = 0; + + SensorCorrente_v2() {} + + SensorCorrente_v2( + const String& id, + uint8_t idNum, + uint8_t endereco, + TiposShuntCorrente tipoShunt, + int canalMux = -1 + ) : + ID(id), + ID_Num(idNum), + _Endereco(endereco), + _A_Shunt(tipoShunt), + _CanalMUX(canalMux) + { + } + + void Inicializar() { + if (Iniciado) { + MostrarLog("Sensor ja inicializado"); + return; + } + + if (!I2CService::SolicitarAcessoI2C(ID_Num, _CanalMUX)) { + MostrarLog("Falha ao solicitar acesso I2C"); + return; + } + + isINA219 = (_A_Shunt == TiposShuntCorrente::INA219_3A2); + + bool encontrado = I2CService::VerificaEnderecoBarramento(_Endereco); + if (!encontrado) { + Iniciado = false; + MostrarLog("Endereco I2C nao encontrado: " + String(_Endereco)); + I2CService::LiberarAcessoI2C(ID_Num); + return; + } + + if (isINA219) { + sINA219 = Adafruit_INA219(_Endereco); + Iniciado = sINA219.begin(); + + if (Iniciado) { + sINA219.setCalibration_32V_2A(); + MostrarLog("INA219 iniciado no canal " + String(_CanalMUX)); + } else { + MostrarLog("Falha ao iniciar INA219"); + } + } + else { + sINA228 = Adafruit_INA228(); + Iniciado = sINA228.begin(_Endereco); + + if (Iniciado) { + ConfigurarShuntINA228(); + sINA228.setAveragingCount(INA228_COUNT_16); + sINA228.setCurrentConversionTime(INA228_TIME_280_us); + MostrarLog("INA228 iniciado no canal " + String(_CanalMUX)); + } else { + MostrarLog("Falha ao iniciar INA228"); + } + } + + I2CService::LiberarAcessoI2C(ID_Num); + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Sensor nao esta inicializado"); + return; + } + + Iniciado = false; + MostrarLog("Sensor desligado"); + } + + void RequisitarDados() { + if (!Iniciado) return; + AferirCorrente(); + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + + case CanMessagePosicaoDados::Dados1: { + uint16_t volts = (uint16_t)(busVoltage * 100.0f); + uint16_t amps = (uint16_t)(current / 10.0f); + uint16_t watts = (uint16_t)(power / 10.0f); + + data.push_back(volts >> 8); data.push_back(volts & 0xFF); + data.push_back(amps >> 8); data.push_back(amps & 0xFF); + data.push_back(watts >> 8); data.push_back(watts & 0xFF); + break; + } + + case CanMessagePosicaoDados::Dados2: { + if (isINA219) break; + + uint16_t wh = (uint16_t)(energy / 10.0f); + uint16_t temp = (uint16_t)(temperature * 100.0f); + + data.push_back(wh >> 8); data.push_back(wh & 0xFF); + data.push_back(temp >> 8); data.push_back(temp & 0xFF); + data.push_back(codAlarme >> 8); data.push_back(codAlarme & 0xFF); + break; + } + } + + return data; + } + + private: + bool DebugMode = true; + SimpleKalmanFilter filtro = SimpleKalmanFilter(10, 10, 0.05); + Adafruit_INA219 sINA219; + Adafruit_INA228 sINA228; + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[COR " + ID + "] " + mensagem); + } + } + + void ConfigurarShuntINA228() { + if (_A_Shunt == TiposShuntCorrente::INA228_10A) { + sINA228.setShunt(0.015, 10.0); + } + else if (_A_Shunt == TiposShuntCorrente::INA228_50A) { + sINA228.setShunt(0.0015, 50.0); + } + else if (_A_Shunt == TiposShuntCorrente::INA228_100A) { + sINA228.setShunt(0.00075, 100.0); + } + } + + void AferirCorrente() { + if (!Iniciado) return; + if (!I2CService::SolicitarAcessoI2C(ID_Num, _CanalMUX)) return; + + if (isINA219) { + busVoltage = sINA219.getBusVoltage_V(); + float leituraCorrente = sINA219.getCurrent_mA(); + current = filtro.updateEstimate(leituraCorrente); + power = sINA219.getPower_mW(); + } + else { + busVoltage = sINA228.getBusVoltage_V(); + float leituraCorrente = sINA228.getCurrent_mA(); + current = filtro.updateEstimate(leituraCorrente); + power = sINA228.getPower_mW(); + temperature = sINA228.readDieTemp(); + energy = sINA228.readEnergy(); + charge = sINA228.readCharge(); + codAlarme = (uint16_t)LerRegistradorINA(0x0B, 2); + } + + I2CService::LiberarAcessoI2C(ID_Num); + } + + uint32_t LerRegistradorINA(uint8_t reg, uint8_t bytes) { + uint8_t buffer[4] = {0}; + if (bytes > 4) return 0; + + if (!I2CService::LeituraSegura(_Endereco, buffer, bytes, reg)) { + MostrarLog("Falha na leitura do registrador 0x" + String(reg, HEX)); + return 0; + } + + uint32_t valor = 0; + for (uint8_t i = 0; i < bytes; i++) { + valor = (valor << 8) | buffer[i]; + } + + return valor; + } +}; + +#endif \ No newline at end of file diff --git a/Firmware/Modulos/SensorMagneticoModel_v2.h b/Firmware/Modulos/SensorMagneticoModel_v2.h new file mode 100644 index 000000000..b57ba3420 --- /dev/null +++ b/Firmware/Modulos/SensorMagneticoModel_v2.h @@ -0,0 +1,136 @@ +#include "SerialService.h" +#include "I2CService.h" +#include "Utils.h" +#include "IComponenteCAN.h" +#include + +#ifndef SensorMagneticoModel_v2 +#define SensorMagneticoModel_v2 + +class SensorMagnetico_v2 : public ComponenteCAN { + public: + String ID; + uint8_t ID_Num = 0; + uint8_t _Endereco = 0x36; + int _CanalMUX = -1; + + bool Iniciado = false; + uint16_t raw = 0; + float angle = 0; + + SensorMagnetico_v2() {} + + SensorMagnetico_v2( + const String& id, + uint8_t idNum, + uint8_t endereco = 0x36, + int canalMux = -1 + ) : + ID(id), + ID_Num(idNum), + _Endereco(endereco), + _CanalMUX(canalMux) + { + } + + void Inicializar() { + if (Iniciado) { + MostrarLog("Sensor ja inicializado"); + return; + } + + if (!I2CService::SolicitarAcessoI2C(ID_Num, _CanalMUX)) { + MostrarLog("Falha ao solicitar acesso I2C"); + return; + } + + bool encontrado = I2CService::VerificaEnderecoBarramento(_Endereco); + Iniciado = encontrado; + + if (!Iniciado) { + MostrarLog("Sensor nao iniciado, endereco " + String(_Endereco) + " nao encontrado"); + } else { + MostrarLog("Sensor iniciado"); + } + + I2CService::LiberarAcessoI2C(ID_Num); + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Sensor nao esta inicializado"); + return; + } + + Iniciado = false; + MostrarLog("Sensor desligado"); + } + + void RequisitarDados() { + if (!Iniciado) return; + AferirAngulo(); + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + + case CanMessagePosicaoDados::Dados1: { + uint16_t ang100 = (uint16_t)round(angle * 100.0f); + data.push_back(raw >> 8); + data.push_back(raw & 0xFF); + data.push_back(ang100 >> 8); + data.push_back(ang100 & 0xFF); + break; + } + } + + return data; + } + + private: + bool DebugMode = true; + static const uint8_t REG_RAW_ANGLE = 0x0C; + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[MAG " + ID + "] " + mensagem); + } + } + + void AferirAngulo() { + if (!Iniciado) return; + if (!I2CService::SolicitarAcessoI2C(ID_Num, _CanalMUX)) return; + + raw = LerRawAngle(); + angle = RawToDegrees(raw); + + I2CService::LiberarAcessoI2C(ID_Num); + } + + uint16_t LerRawAngle() { + uint8_t buffer[2] = {0}; + + if (!I2CService::LeituraSegura(_Endereco, buffer, 2, REG_RAW_ANGLE)) { + MostrarLog("Falha na leitura do RAW_ANGLE"); + return 0; + } + + uint16_t valor = ((uint16_t)buffer[0] << 8) | buffer[1]; + valor &= 0x0FFF; + return valor; + } + + float RawToDegrees(uint16_t valorRaw) { + return (valorRaw * 360.0f) / 4096.0f; + } +}; + +#endif \ No newline at end of file diff --git a/Firmware/Modulos/SensorTemperaturaNtcModel.h b/Firmware/Modulos/SensorTemperaturaNtcModel.h new file mode 100644 index 000000000..d4b749f0d --- /dev/null +++ b/Firmware/Modulos/SensorTemperaturaNtcModel.h @@ -0,0 +1,151 @@ +#include "SerialService.h" +#include "Pinout.h" +#include "Utils.h" +#include "IComponenteCAN.h" +#include + +#ifndef SensorTemperaturaNtcModel +#define SensorTemperaturaNtcModel + +class SensorTemperaturaNtc : public ComponenteCAN { + public: + String ID; + uint8_t ID_Num = 0; + PinoModel _pino; + + int leitura = 0; + double temperatura = -1; + double tensao = 0; + + bool Iniciado = false; + bool Checando = false; + + float OffsetTemperatura = 0.0f; + + SensorTemperaturaNtc() {} + + SensorTemperaturaNtc( + const String& id, + uint8_t idNum, + int pino, + TiposBarramentos tipoBarramento, + int canalMux = -1, + float offsetTemperatura = 0.0f + ) : + ID(id), + ID_Num(idNum), + _pino(PinoModel(pino, tipoBarramento, _INPUT, ANALOGICO, idNum, canalMux)), + OffsetTemperatura(offsetTemperatura) + { + } + + void Inicializar() { + if (Iniciado) { + MostrarLog("Sensor ja inicializado"); + return; + } + + leitura = 0; + temperatura = -1; + tensao = 0; + + _pino.Conectar(); + + Iniciado = _pino.Definido(); + + MostrarLog(Iniciado ? "Sensor iniciado" : "Sensor nao iniciado"); + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Sensor nao esta inicializado"); + return; + } + + _pino.Desconectar(); + + Iniciado = false; + + MostrarLog("Sensor desligado"); + } + + void RequisitarDados() { + if (!Iniciado) return; + AferirTemperatura(); + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + + case CanMessagePosicaoDados::Dados1: { + int16_t leituraInt = static_cast(round(temperatura * 100.0f)); + data.push_back((uint8_t)(leitura >> 8)); + data.push_back((uint8_t)(leitura & 0xFF)); + data.push_back((uint8_t)(leituraInt >> 8)); + data.push_back((uint8_t)(leituraInt & 0xFF)); + break; + } + } + + return data; + } + + private: + bool DebugMode = true; + // SimpleKalmanFilter filtro = SimpleKalmanFilter(5, 15, 0.01); + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[TMP " + ID + "] " + mensagem); + } + } + + void AferirTemperatura() { + leitura = _pino.get(1); + // leitura = filtro.updateEstimate(leitura); + + temperatura = CalcularTemperatura((float)leitura, OffsetTemperatura); + + MostrarLog("Leitura: " + String(leitura) + + ", Tensao: " + String(tensao) + + ", Temperatura: " + String(temperatura)); + } + + float CalcularTemperatura(float leituraAdc, float offset = 0.0f) { + const float Vs = 5.0f; + const float Beta = 3950.0f; + const float To = 298.15f; + const float Ro = 10000.0f; + const float adcMax = 4095.0f; + static constexpr float divisor = 1.0f; + static constexpr float vOffset = (2.516f / 3.036f); + + if (leituraAdc < 200.0f) return -1.0f; + + float Vadc = leituraAdc / adcMax * Vs; + Vadc = Vadc * divisor * vOffset; + + tensao = Vadc; + + if (Vadc <= 0.001f) return -100.0f; + if (Vadc >= Vs) return NAN; + + float Rt = Ro * (Vadc / (Vs - Vadc)); + float T = 1.0f / (1.0f / To + log(Rt / Ro) / Beta); + float Tc = T - 273.15f + offset; + + return roundf(Tc * 100.0f) / 100.0f; + } +}; + + + +#endif \ No newline at end of file diff --git a/Firmware/Modulos/ServoAgroModel_v2.h b/Firmware/Modulos/ServoAgroModel_v2.h new file mode 100644 index 000000000..9dcadab9a --- /dev/null +++ b/Firmware/Modulos/ServoAgroModel_v2.h @@ -0,0 +1,128 @@ +#include "SerialService.h" +#include "Pinout.h" +#include "Utils.h" +#include "IComponenteCAN.h" +#include + +#ifndef ServoAgroModel_v2 +#define ServoAgroModel_v2 + +class ServoAgro_v2 : public ComponenteCAN { + public: + String ID; + uint8_t ID_Num = 0; + bool Incremental = false; + bool Iniciado = false; + PinoModel _pino; + + ServoAgro_v2() {} + + ServoAgro_v2( + const String& id, + uint8_t idNum, + bool incremental, + int pino, + TiposBarramentos tipoBarramento + ) : + ID(id), + ID_Num(idNum), + Incremental(incremental), + _pino(PinoModel(pino, tipoBarramento, _OUTPUT)) + { + } + + void Inicializar() { + if (Iniciado) { + MostrarLog("Servo ja inicializado"); + return; + } + if (_pino.Definido()) { + _Servo.attach(_pino.num); + AtualizarAngulo(Incremental ? 0 : 180); + Iniciado = true; + MostrarLog("Servo iniciado"); + } + else { + MostrarLog("Servo nao iniciado"); + } + } + + void Desligar() { + if (!Iniciado) { + MostrarLog("Servo nao esta inicializado"); + return; + } + + if (_pino.Definido()) { + _Servo.detach(); + } + + MostrarLog("Servo Desligado"); + + Iniciado = false; + } + + void RequisitarDados() { + if (!Iniciado) return; + } + + void ProcessarComando(std::vector& data) { + if (!Iniciado) return; + if (data.size() < 3) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + if (idNum != ID_Num) return; + switch (posicao) { + case CanMessagePosicaoDados::Command1: { + int novoAngulo = (int)data[2]; + AtualizarAngulo(novoAngulo); + break; + } + } + } + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back(static_cast(posicao)); + data.push_back(ID_Num); + switch (posicao) { + case CanMessagePosicaoDados::Status: { + data.push_back(Iniciado ? 1 : 0); + break; + } + case CanMessagePosicaoDados::Dados1: { + data.push_back(static_cast(_Angulo)); + break; + } + } + return data; + } + + + private: + bool DebugMode = true; + + Servo _Servo; + int _Angulo = 0; + + void AtualizarAngulo(int novoAngulo) { + novoAngulo = constrain(novoAngulo, 0, 180); + MostrarLog("Angulo atualizado de " + String(_Angulo) + " para " + String(novoAngulo)); + _Angulo = novoAngulo; + _Servo.write(_Angulo); + } + + void MostrarLog(String mensagem) { + if (DebugMode) { + PrintTela("[SRV " + ID + "] " + mensagem); + } + } + +}; + + + + + + +#endif \ No newline at end of file diff --git a/Firmware/Modulos/SinaleiroModel_v2.h b/Firmware/Modulos/SinaleiroModel_v2.h new file mode 100644 index 000000000..9eef60a47 --- /dev/null +++ b/Firmware/Modulos/SinaleiroModel_v2.h @@ -0,0 +1,153 @@ +#include "SerialService.h" +#include "Pinout.h" +#include "Utils.h" +#include "IComponenteCAN.h" + +#ifndef SinaleiroModel +#define SinaleiroModel + +class Sinaleiro_v2 : public ComponenteCAN { + public: + String ID; + uint8_t ID_Num = 0; + PinoModel _pino; + bool Iniciado = false; + + int _StatusID = 0; + StatusLED _Status = Apagado; + StatusLED _StatusLeitura = Apagado; + + int _Qtd = 0; + int _TempoMs = 0; + int _PausaMs = 0; + + // controle interno (não era exposto antes) + bool _estadoAtual = false; + int _piscadasAtual = 0; + bool _emPausa = false; + unsigned long _lastMillis = 0; + + Sinaleiro_v2() {} + + Sinaleiro_v2( + const String& id, + uint8_t idNum, + int pino, + TiposBarramentos tipoBarramento + ) : + ID(id), + ID_Num(idNum), + _pino(PinoModel(pino, tipoBarramento, _OUTPUT)) + {} + + void Inicializar() { + if (Iniciado) return; + if (_pino.Definido()) { + _pino.Conectar(false); + Iniciado = true; + } + } + + void AtualizarEstado(unsigned long agora) { + if (!Iniciado) return; + + if (_Status != StatusLED::Piscando) { + _pino.set(_Status == StatusLED::Aceso); + _StatusLeitura = _Status; + return; + } + + // modo piscando + if (_piscadasAtual < _Qtd) { + if (!_emPausa && (agora - _lastMillis >= _TempoMs)) { + _estadoAtual = !_estadoAtual; + _pino.set(_estadoAtual); + _lastMillis = agora; + + if (!_estadoAtual) { + _piscadasAtual++; + } + } + } + else { + // pausa + if (!_emPausa) { + _pino.set(false); + _emPausa = true; + _lastMillis = agora; + } + + if (agora - _lastMillis >= _PausaMs) { + _emPausa = false; + _piscadasAtual = 0; + _lastMillis = agora; + } + } + + _StatusLeitura = StatusLED::Piscando; + } + + void ProcessarComando(std::vector& data) { + if (!Iniciado) return; + if (data.size() < 7) return; + + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t idNum = data[1]; + if (idNum != ID_Num) return; + + if (posicao == CanMessagePosicaoDados::Command1) { + _StatusID = data[2]; + _Status = (StatusLED)data[3]; + _Qtd = data[4]; + _TempoMs = (uint16_t)data[5] * 10; + _PausaMs = (uint16_t)data[6] * 10; + + // reset ciclo + _piscadasAtual = 0; + _emPausa = false; + _lastMillis = millis(); + } + } + + void RequisitarDados() {} + + std::vector MontarMensagemCAN(CanMessagePosicaoDados posicao) { + std::vector data; + data.push_back((uint8_t)posicao); + data.push_back(ID_Num); + + switch (posicao) { + case Status: + data.push_back(Iniciado ? 1 : 0); + break; + case Dados1: + data.push_back(_StatusID); + data.push_back(_StatusLeitura); + break; + } + + return data; + } +}; + +class LedManager { + public: + std::vector leds; + + void Adicionar(Sinaleiro_v2* led) { + leds.push_back(led); + } + + void Atualizar() { + unsigned long agora = millis(); + for (auto* led : leds) { + if (led != nullptr && led->Iniciado) { + led->AtualizarEstado(agora); + } + } + } +}; + + + +#endif \ No newline at end of file diff --git a/Firmware/Sensoriamento/Sensoriamento_v22/.theia/launch.json b/Firmware/Sensoriamento/Sensoriamento_v22/.theia/launch.json new file mode 100644 index 000000000..9a49ac9ff --- /dev/null +++ b/Firmware/Sensoriamento/Sensoriamento_v22/.theia/launch.json @@ -0,0 +1,8 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + "version": "0.2.0", + "configurations": [ + + ] +} diff --git a/Firmware/Sensoriamento/Sensoriamento_v22/Sensoriamento_v22.ino b/Firmware/Sensoriamento/Sensoriamento_v22/Sensoriamento_v22.ino new file mode 100644 index 000000000..9d5d90e7d --- /dev/null +++ b/Firmware/Sensoriamento/Sensoriamento_v22/Sensoriamento_v22.ino @@ -0,0 +1,416 @@ +// Dispositivo: Sensoriamento +// Versão Firmware: 22 +// Ultima atualização: 20/03/2026 +// Atualização: Firmware mock + +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SerialService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\CanService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\EepromService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\I2CService.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Utils.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\Pinout.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ServoAgroModel_v2.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\ReleModel_v2.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SinaleiroModel_v2.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorTemperaturaNtcModel.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorCorrenteModel_v2.h" +#include "C:\ZendionInc\agrobot_base\Firmware\Modulos\SensorMagneticoModel_v2.h" + + +// Configurações do CAN +uint8_t CanID = 0x11; +CanService canService(CanID); + +//LoRaService loraService(&canService); + +#define D_Code Sen +int VERSION = 22; +String Mod_ID = "Sen"; + +#define _pinoLED RGB_BUILTIN + +bool Conectado = false; +bool Conectar = false; + +int _TaxaAmostragem = 1000; +volatile bool RequisitarDados = false; +int latenciaLoop = 0; +int qtdEnviosStatus = 0; +int maxEnviosStatus = 5; + +#pragma region SINALEIROS +Sinaleiro_v2 sLED_Manual("LEDMN", 21, 37, TiposBarramentos::CONTROLADOR); +Sinaleiro_v2 sLED_Automatico("LEDAT", 22, 35, TiposBarramentos::CONTROLADOR); +Sinaleiro_v2 sLED_Operacao("LEDOP", 23, 36, TiposBarramentos::CONTROLADOR); + +Sinaleiro_v2* ObterSinaleiroPorId(uint8_t idNum) { + switch (idNum) { + case 21: return &sLED_Manual; + case 22: return &sLED_Automatico; + case 23: return &sLED_Operacao; + default: return nullptr; + } +} + +LedManager ledManager; +void LedTask(void* pv) { + while (true) { + ledManager.Atualizar(); + vTaskDelay(pdMS_TO_TICKS(10)); // 100 Hz + } +} +#pragma endregion + +#pragma region SERVOS +ServoAgro_v2 sSRV_FreioET("FROET", 41, true, 45, TiposBarramentos::CONTROLADOR); +ServoAgro_v2 sSRV_FreioDT("FRODT", 43, false, 47, TiposBarramentos::CONTROLADOR); + +ServoAgro_v2* ObterServoPorId(uint8_t idNum) { + switch (idNum) { + case 41: return &sSRV_FreioET; + case 43: return &sSRV_FreioDT; + default: return nullptr; + } +} +#pragma endregion + +#pragma region RELES +Rele_v2 sRLE_CoolerIn("RLCIN", 81, true, 39, TiposBarramentos::CONTROLADOR); +Rele_v2 sRLE_CoolerOut("RLCOUT", 82, true, 40, TiposBarramentos::CONTROLADOR); + +Rele_v2* ObterRelePorId(uint8_t idNum) { + switch (idNum) { + case 81: return &sRLE_CoolerIn; + case 82: return &sRLE_CoolerOut; + default: return nullptr; + } +} +#pragma endregion + +#pragma region TEMPERATURA NTC +SensorTemperaturaNtc sNTC_MotorET("TMVET", 1, 0, TiposBarramentos::EXPANSOR_ADS, -1, 0.0f); +SensorTemperaturaNtc sNTC_MotorDT("TMVDT", 3, 1, TiposBarramentos::EXPANSOR_ADS, -1, 0.0f); +SensorTemperaturaNtc sNTC_MotorEF("TMVEF", 2, 2, TiposBarramentos::EXPANSOR_ADS, -1, 0.0f); +SensorTemperaturaNtc sNTC_MotorDF("TMVDF", 4, 3, TiposBarramentos::EXPANSOR_ADS, -1, 0.0f); + +SensorTemperaturaNtc* ObterTempNtcPorId(uint8_t idNum) { + switch (idNum) { + case 1: return &sNTC_MotorET; + case 2: return &sNTC_MotorEF; + case 3: return &sNTC_MotorDT; + case 4: return &sNTC_MotorDF; + default: return nullptr; + } +} +#pragma endregion + +#pragma region CORRENTE +SensorCorrente_v2 sCOR_3V0 ("COR_AB3V", 11, 0x40, TiposShuntCorrente::INA219_3A2, 5); +SensorCorrente_v2 sCOR_5V0 ("COR_AB5V", 12, 0x40, TiposShuntCorrente::INA219_3A2, 4); +SensorCorrente_v2 sCOR_7V2 ("COR_AB7V2", 13, 0x40, TiposShuntCorrente::INA219_3A2, 2); +SensorCorrente_v2 sCOR_12V ("COR_AB12V", 14, 0x40, TiposShuntCorrente::INA228_50A, 3); +SensorCorrente_v2 sCOR_19V ("COR_AB19V", 15, 0x40, TiposShuntCorrente::INA228_10A, 1); +SensorCorrente_v2 sCOR_24V ("COR_AB24V", 16, 0x40, TiposShuntCorrente::INA228_50A, 6); +SensorCorrente_v2 sCOR_36V ("COR_AB36V", 17, 0x40, TiposShuntCorrente::INA228_100A, 7); + +SensorCorrente_v2* ObterSensorCorrentePorId(uint8_t idNum) { + switch (idNum) { + case 11: return &sCOR_3V0; + case 12: return &sCOR_5V0; + case 13: return &sCOR_7V2; + case 14: return &sCOR_12V; + case 15: return &sCOR_19V; + case 16: return &sCOR_24V; + case 17: return &sCOR_36V; + default: return nullptr; + } +} +#pragma endregion + +#pragma region MAGNETICOS +SensorMagnetico_v2 sMAG_MotorET("MAG_ET", 91, 0x36, 1); +SensorMagnetico_v2 sMAG_MotorDT("MAG_DT", 92, 0x36, 2); +SensorMagnetico_v2 sMAG_MotorEF("MAG_EF", 93, 0x36, 3); +SensorMagnetico_v2 sMAG_MotorDF("MAG_DF", 94, 0x36, 4); + +SensorMagnetico_v2* ObterSensorMagneticoPorId(uint8_t idNum) { + switch (idNum) { + case 91: return &sMAG_MotorET; + case 92: return &sMAG_MotorDT; + case 93: return &sMAG_MotorEF; + case 94: return &sMAG_MotorDF; + default: return nullptr; + } +} +#pragma endregion + +void MostrarLog(String mensagem) { + bool _debugMode = false; + if (_debugMode) { + PrintTela(String("[SEN] ") + mensagem); + } +} + +void inicializarDependenciasI2C() { + I2CService::IniciarI2C(); + I2CService::IniciarMUX(); + I2CService::IniciarMCP(); +} + +void setup() { + delay(2000); + + inicializarDependenciasI2C(); + + sSRV_FreioET.Inicializar(); + sSRV_FreioDT.Inicializar(); + sRLE_CoolerIn.Inicializar(); + sRLE_CoolerOut.Inicializar(); + sLED_Manual.Inicializar(); + sLED_Automatico.Inicializar(); + sLED_Operacao.Inicializar(); + sNTC_MotorET.Inicializar(); + sNTC_MotorDT.Inicializar(); + sNTC_MotorEF.Inicializar(); + sNTC_MotorDF.Inicializar(); + sCOR_3V0.Inicializar(); + sCOR_5V0.Inicializar(); + sCOR_7V2.Inicializar(); + sCOR_12V.Inicializar(); + sCOR_19V.Inicializar(); + sCOR_24V.Inicializar(); + sCOR_36V.Inicializar(); + sMAG_MotorET.Inicializar(); + sMAG_MotorDT.Inicializar(); + sMAG_MotorEF.Inicializar(); + sMAG_MotorDF.Inicializar(); + + ledManager.Adicionar(&sLED_Manual); + ledManager.Adicionar(&sLED_Automatico); + ledManager.Adicionar(&sLED_Operacao); + xTaskCreatePinnedToCore(LedTask, "LedTask", 3000, NULL, 1, NULL, tskNO_AFFINITY); + + // Registrar callback para processar mensagens CAN recebidas + canService.setReceiveCallback([](int packetSize, int senderId, CanMessagePosicaoDados posicao, byte* data, int dataLength) { + std::vector fullData; + fullData.push_back(static_cast(posicao)); // Primeiro byte é sempre a posicao + for (int i = 0; i < dataLength; i++) { + fullData.push_back(data[i]); + } + + ProcessarFrameCAN(posicao, fullData); + }); + + canService.begin(); +} + +void loop() { + if (!RequisitarDados) { + enviarLogsPeriodicamente(); + } + + delay(1); +} + +// Função para enviar logs do sensor periodicamente +unsigned long ultimoEnvioLogs = 0; +const unsigned long intervaloEnvioLogs = 1000; // 1 segundo +void enviarLogsPeriodicamente() { + unsigned long tempoAtual = millis(); + // Verifica se o intervalo de 5 segundos já passou + if (tempoAtual - ultimoEnvioLogs >= intervaloEnvioLogs) { + ultimoEnvioLogs = tempoAtual; // Atualiza o tempo do último envio + + enviarDadosSensores(canService.ID_Num_sTOD, CanMessagePosicaoDados::DadosAll); + } +} + +void enviarDadosSensores(uint8_t id_num, CanMessagePosicaoDados posicao) { + if (Conectado || posicao == CanMessagePosicaoDados::Status) { + unsigned long startLoop = millis(); + + bool enviarStatus = qtdEnviosStatus >= maxEnviosStatus && posicao != CanMessagePosicaoDados::Status; + bool todosDados = posicao == CanMessagePosicaoDados::DadosAll; + bool todosIDs = id_num == canService.ID_Num_sTOD; + + if (id_num == canService.ID_Num_sMOD) { + EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION)); + return; + } + + MostrarLog("Atualizando dados dos sensores..."); + + if (todosIDs && enviarStatus) { + EnviarDadosCAN(canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION)); + } + + ComponenteCAN::ProcessarComponenteCAN(sSRV_FreioET, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sSRV_FreioDT, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + ComponenteCAN::ProcessarComponenteCAN(sRLE_CoolerIn, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sRLE_CoolerOut, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + ComponenteCAN::ProcessarComponenteCAN(sLED_Manual, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sLED_Automatico, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sLED_Operacao, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + ComponenteCAN::ProcessarComponenteCAN(sNTC_MotorET, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sNTC_MotorDT, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sNTC_MotorEF, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sNTC_MotorDF, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + ComponenteCAN::ProcessarComponenteCAN(sCOR_3V0, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sCOR_5V0, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sCOR_7V2, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sCOR_12V, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sCOR_19V, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sCOR_24V, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sCOR_36V, {CanMessagePosicaoDados::Dados1, CanMessagePosicaoDados::Dados2}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + ComponenteCAN::ProcessarComponenteCAN(sMAG_MotorET, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sMAG_MotorDT, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sMAG_MotorEF, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + ComponenteCAN::ProcessarComponenteCAN(sMAG_MotorDF, {CanMessagePosicaoDados::Dados1}, todosIDs, id_num, enviarStatus, todosDados, posicao, EnviarDadosCAN); + + if (enviarStatus) { + qtdEnviosStatus = 0; + } + else { + qtdEnviosStatus++; + } + + latenciaLoop = millis() - startLoop; + + if (posicao == CanMessagePosicaoDados::DadosAll) { + EnviarDadosCAN(canService.MontarFrameReqDadosFim(latenciaLoop)); + } + + MostrarLog("Ciclo concluido, latencia de loop: " + String(latenciaLoop)); + } +} + +void EnviarDadosCAN(std::vector data) { + if (data.size() > 2) { + canService.adicionarMensagemFila(data); + } +} + +void ProcessarFrameCAN(CanMessagePosicaoDados posicao, std::vector data) { + if (data.size() < 1) return; + + F_Code funcao = canService.FuncaoPorPosicao(posicao); + + switch (funcao) { + case F_Code::ReqTx: ProcessarReq(data); break; + case F_Code::CmdTx: ProcessarCmd(data); break; + case F_Code::CfgTx: ProcessarCfg(data); break; + } +} + +void ProcessarReq(std::vector data) { + if (data.size() < 2) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + enviarDadosSensores(id, posicao); +} + +void ProcessarCfg(std::vector data) { + if (data.size() < 4) return; + std::vector _chkRx; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + S_Code componente = DetectarComponente(id); + if (componente == S_Code::sMOD) { + switch (posicao) { + case CanMessagePosicaoDados::Config1: { + if (data.size() < 8) return; + bool conectar = data[2] == 1; + int taxa = data[3] * 10; + bool requisitar = data[4] == 1; + //loraService.AddressBase = data[5]; + int pinoSDA = data[6]; + int pinoSCL = data[7]; + + _TaxaAmostragem = taxa; + RequisitarDados = requisitar; + + if (pinoSDA != PINO_INVALIDO && pinoSCL != PINO_INVALIDO) { + if (I2CService::DefinirPinos(pinoSDA, pinoSCL) || !I2CService::I2CIniciado) { + inicializarDependenciasI2C(); + } + } + + vTaskDelay(pdMS_TO_TICKS(100)); + + Conectado = conectar; + _chkRx = canService.MontarFrameReqStatusMod(D_Code, Conectado, VERSION); + + MostrarLog("Configuracao do modulo concluida"); + break; + } + } + } + + EnviarDadosCAN(_chkRx); +} + +void ProcessarCmd(std::vector data) { + if (data.size() < 2) return; + CanMessagePosicaoDados posicao = (CanMessagePosicaoDados)data[0]; + uint8_t id = data[1]; + S_Code componente = DetectarComponente(id); + switch (componente) { + case sMOD: { + if (data.size() < 3) return; + switch (posicao) { + case CanMessagePosicaoDados::Command1: { + Estado estado = (Estado)data[2]; + if (estado == Estado::Reset) { + delay(100); + esp_restart(); + } + break; + } + } + break; + } + case sSRV: { + ServoAgro_v2* servo = ObterServoPorId(id); + if (servo == nullptr) + return; + servo->ProcessarComando(data); + break; + } + case sRLE: { + Rele_v2* rele = ObterRelePorId(id); + if (rele == nullptr) + return; + rele->ProcessarComando(data); + break; + } + case sLED: { + Sinaleiro_v2* sinaleiro = ObterSinaleiroPorId(id); + if (sinaleiro == nullptr) + return; + sinaleiro->ProcessarComando(data); + break; + } + default: + break; + } +} + +S_Code DetectarComponente(uint8_t idNum) { + if (idNum == canService.ID_Num_sMOD) return S_Code::sMOD; + if (idNum == canService.ID_Num_sTOD) return S_Code::sTOD; + if (idNum == canService.ID_Num_sLRA) return S_Code::sLRA; + if (idNum >= 01 && idNum <= 10) return S_Code::sNTC; + if (idNum >= 11 && idNum <= 20) return S_Code::sCOR; + if (idNum >= 21 && idNum <= 30) return S_Code::sLED; + if (idNum >= 41 && idNum <= 50) return S_Code::sSRV; + if (idNum >= 81 && idNum <= 90) return S_Code::sRLE; + if (idNum >= 91 && idNum <= 100) return S_Code::sMAG; + return S_Code::sVZO; +} + +