#include "SerialService.h" #include "Pinout.h" #include "IComponenteCAN.h" #ifndef SensorFluxoModel_v2_h #define SensorFluxoModel_v2_h class SensorFluxo_v2 : public ComponenteCAN { public: SensorFluxo_v2( const String& id, uint8_t idNum, int pino, TiposBarramentos barramento = CONTROLADOR ) : _ID(id), ID_Num(idNum), _pino(pino, barramento, _INPUT_PULLUP, DIGITAL) { } String _ID; uint8_t ID_Num = 0; PinoModel _pino; bool Iniciado = false; unsigned long tempoAnterior = 0; unsigned int _Pulsos = 0; unsigned long _PeriodoTotal = 0; bool ultimaLeitura = false; unsigned long _UltimoPulsoMs = 0; unsigned int _PulsosLeitura = 0; unsigned long _PeriodoTotalLeitura = 0; float _Vazao = 0.0f; // Protege a janela de pulsos e o snapshot contra acessos concorrentes // do loop rapido, task de telemetria e controle da bomba. portMUX_TYPE _stateMux = portMUX_INITIALIZER_UNLOCKED; void Inicializar() { if (Iniciado) { MostrarLog("Sensor ja inicializado"); return; } _pino.Conectar(); Iniciado = _pino.Definido(); if (Iniciado) { ResetarEstado(); MostrarLog("Sensor iniciado"); } else { MostrarLog("Sensor nao iniciado"); } } void Desligar() { if (!Iniciado) { MostrarLog("Sensor nao esta inicializado"); return; } _pino.Desconectar(); ResetarEstado(); _PulsosLeitura = 0; _PeriodoTotalLeitura = 0; _Vazao = 0.0f; Iniciado = false; MostrarLog("Sensor desligado"); } void Loop() { if (!Iniciado) return; bool leituraAtual = (_pino.get() == 1); unsigned long tempoAtual = millis(); portENTER_CRITICAL(&_stateMux); if (leituraAtual != ultimaLeitura) { //MostrarLog("Mudou: ultima=" + String(ultimaLeitura) + " atual=" + String(leituraAtual)); if (leituraAtual && !ultimaLeitura) { unsigned long intervalo = tempoAtual - tempoAnterior; tempoAnterior = tempoAtual; _Pulsos++; _PeriodoTotal += intervalo; _UltimoPulsoMs = tempoAtual; //MostrarLog("SUBIDA! Pulsos=" + String(_Pulsos) + " Periodo=" + String(_PeriodoTotal) + " Intervalo=" + String(intervalo)); } ultimaLeitura = leituraAtual; } portEXIT_CRITICAL(&_stateMux); } void RequisitarDados() { AtualizarLeitura(); } 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: { unsigned int pulsosLeitura; unsigned long periodoLeitura; float vazao; portENTER_CRITICAL(&_stateMux); pulsosLeitura = _PulsosLeitura; periodoLeitura = _PeriodoTotalLeitura; vazao = _Vazao; portEXIT_CRITICAL(&_stateMux); uint16_t vazaoEscalada = (uint16_t)(vazao * 100.0f); data.push_back((uint8_t)pulsosLeitura); data.push_back((uint8_t)(periodoLeitura >> 8)); data.push_back((uint8_t)(periodoLeitura & 0xFF)); data.push_back((uint8_t)(vazaoEscalada >> 8)); data.push_back((uint8_t)(vazaoEscalada & 0xFF)); break; } default: break; } return data; } void ObterAmostragemAtual(unsigned int& pulsos, unsigned long& periodoMs) { portENTER_CRITICAL(&_stateMux); pulsos = _Pulsos; periodoMs = _PeriodoTotal; portEXIT_CRITICAL(&_stateMux); } // Snapshot somente-leitura para a malha rapida da bomba. A bomba nao chama // Loop(), nao reinicia a janela e nao disputa a aquisicao do sensor. void ObterSnapshotControle( unsigned int& pulsos, unsigned long& periodoMs, unsigned long& ultimoPulsoMs ) { portENTER_CRITICAL(&_stateMux); pulsos = _Pulsos; periodoMs = _PeriodoTotal; ultimoPulsoMs = _UltimoPulsoMs; portEXIT_CRITICAL(&_stateMux); } private: bool DebugMode = false; void AtualizarLeitura() { if (!Iniciado) return; unsigned int pulsos; unsigned long periodoMs; unsigned long agora = millis(); portENTER_CRITICAL(&_stateMux); pulsos = _Pulsos; periodoMs = _PeriodoTotal; _Pulsos = 0; _PeriodoTotal = 0; tempoAnterior = agora; portEXIT_CRITICAL(&_stateMux); float vazao = CalcularVazao(pulsos, periodoMs); portENTER_CRITICAL(&_stateMux); _PulsosLeitura = pulsos; _PeriodoTotalLeitura = periodoMs; _Vazao = vazao; portEXIT_CRITICAL(&_stateMux); } void ResetarEstado() { bool leituraInicial = (_pino.get() == 1); portENTER_CRITICAL(&_stateMux); _Pulsos = 0; _PeriodoTotal = 0; tempoAnterior = millis(); ultimaLeitura = leituraInicial; _UltimoPulsoMs = 0; portEXIT_CRITICAL(&_stateMux); } void ReiniciarAmostragem() { portENTER_CRITICAL(&_stateMux); _Pulsos = 0; _PeriodoTotal = 0; tempoAnterior = millis(); portEXIT_CRITICAL(&_stateMux); } float CalcularVazao(uint16_t pulsos, unsigned long periodoMs) { if (periodoMs == 0) return 0.0f; float frequenciaHz = ((float)pulsos) * 1000.0f / (float)periodoMs; float q_L_min = (frequenciaHz + 3.0f) / 8.1f; if (q_L_min < 0.0f) q_L_min = 0.0f; if (q_L_min > 10.0f) q_L_min = 10.0f; float q_mL_s = q_L_min * (1000.0f / 60.0f); return q_mL_s; } void MostrarLog(String mensagem) { if (DebugMode) { PrintTela("[FLX " + _ID + "] " + mensagem); } } }; #endif