agrobot_base/Firmware/Modulos/SensorFluxoModel_v2.h

236 lines
5.9 KiB
C++

#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<uint8_t> MontarMensagemCAN(CanMessagePosicaoDados posicao) {
std::vector<uint8_t> data;
data.push_back(static_cast<uint8_t>(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