#ifndef MuxService_h #define MuxService_h #include "SerialService.h" #include #include #include #include class I2CService { public: static const constexpr uint8_t enderecoMux = 0x70; static const constexpr uint8_t enderecoMcp = 0x20; static const constexpr uint8_t enderecoAds = 0x48; static bool I2CIniciado; static bool MuxIniciado; static bool McpIniciado; static bool AdsIniciado; static int canalAtivo; static int idAtualUsandoI2C; static Adafruit_MCP23X17 mcp; static Adafruit_ADS1115 ads; static SemaphoreHandle_t i2cMutex; static void DefinirPinos(int sda, int scl) { _pinoSDA = sda; _pinoSCL = scl; } static bool IniciarI2C() { if (I2CIniciado) { Wire.end(); delay(10); } I2CIniciado = Wire.begin(_pinoSDA, _pinoSCL); //Wire.setTimeout(50); PrintTela("[I2C] I2C inicializado nos pinos SDA=" + String(_pinoSDA) + " e SCL=" + String(_pinoSCL) + " - Res " + I2CIniciado); if (i2cMutex == nullptr) { i2cMutex = xSemaphoreCreateMutex(); } idAtualUsandoI2C = -1; tempoEntradaI2C = 0; return I2CIniciado; } static bool VerificaEnderecoBarramento(byte _Endereco, uint32_t timeoutMs = 50) { if (!I2CIniciado) return false; //Wire.setTimeout(timeoutMs); unsigned long t0 = millis(); Wire.beginTransmission(_Endereco); byte error = Wire.endTransmission(); if ((millis() - t0) > timeoutMs) { PrintTela("[I2C] Timeout verificando endereco " + String(_Endereco)); return false; } return error == 0; } static bool SolicitarAcessoI2C(int idSensor = 0, int canalMux = -1, uint32_t timeoutMs = 200) { if (!I2CIniciado) { PrintTela("[I2C] Solicitacao de acesso negada para o sensor " + String(idSensor) + " - I2C Nao inicializado"); return false; } TickType_t timeoutTicks = pdMS_TO_TICKS(timeoutMs); if (xSemaphoreTake(i2cMutex, timeoutTicks) != pdTRUE) { PrintTela("[I2C] Timeout ao tentar acessar o I2C - ID: " + String(idSensor)); return false; } // Troca canal se necessário if (canalMux >= 0 && !TrocarCanalMux(canalMux)) { xSemaphoreGive(i2cMutex); // Libera caso a troca de canal falhe return false; } idAtualUsandoI2C = idSensor; tempoEntradaI2C = millis(); return true; } static void LiberarAcessoI2C(int idSensor = 0) { if (idSensor == idAtualUsandoI2C) { idAtualUsandoI2C = -1; xSemaphoreGive(i2cMutex); } } static int QuemEstaUsando() { return idAtualUsandoI2C; } static void VerificarI2CPreso() { if (idAtualUsandoI2C >= 0 && (millis() - tempoEntradaI2C > LimiteTempoI2C)) { PrintTela("[I2C] Semáforo preso pelo ID %d — forçando liberação!\n", idAtualUsandoI2C); LiberarAcessoI2C(idAtualUsandoI2C); IniciarI2C(); } } static bool LeituraSegura(uint8_t addr, uint8_t* buffer, size_t qtd, uint8_t reg = 0xFF, uint32_t timeoutMs = 50) { //Wire.setTimeout(timeoutMs); unsigned long t0 = millis(); if (reg != 0xFF) { Wire.beginTransmission(addr); Wire.write(reg); if (Wire.endTransmission(false) != 0) { PrintTela("[I2C] Falha ao endTransmission (leitura)"); return false; } delay(1); // <----- ADICIONAR este delay aqui } size_t received = Wire.requestFrom((int)addr, (int)qtd); if (received != qtd || (millis() - t0) > timeoutMs) { PrintTela("[I2C] Timeout ou leitura incompleta"); return false; } for (size_t i = 0; i < qtd; i++) { if (Wire.available()) { buffer[i] = Wire.read(); } else { PrintTela("[I2C] Dados insuficientes disponíveis"); return false; } } return true; } static bool EscritaSegura(uint8_t addr, const uint8_t* dados, size_t qtd, uint32_t timeoutMs = 50) { //Wire.setTimeout(timeoutMs); unsigned long t0 = millis(); Wire.beginTransmission(addr); for (size_t i = 0; i < qtd; i++) { Wire.write(dados[i]); } int resultado = Wire.endTransmission(); if ((millis() - t0) > timeoutMs || resultado != 0) { PrintTela("[I2C] Falha na escrita ou timeout"); return false; } return true; } static bool TrocarCanalMux(int canalMux) { if (MuxIniciado && canalMux >= 0 && canalMux < 9) { if (canalMux != canalAtivo) { Wire.beginTransmission(enderecoMux); Wire.write(1 << canalMux); Wire.endTransmission(); PrintTela("[MUX] Canal alterado de " + String(canalAtivo) + " para " + String(canalMux)); canalAtivo = canalMux; } return true; } PrintTela("[MUX] Nao foi possivel trocar o canal para " + String(canalMux)); return false; } static void IniciarMUX(byte endereco = enderecoMux, bool Mandatorio = false) { if (!I2CIniciado) { PrintTela("[MUX] Impossivel iniciar TCA9548A, I2C nao iniciado!"); return; } PrintTela("[MUX] Iniciando TCA9548A..."); if (!MuxIniciado) { SolicitarAcessoI2C(); Wire.beginTransmission(endereco); MuxIniciado = (Wire.endTransmission() == 0); if (!MuxIniciado) { PrintTela("[MUX] TCA9548A nao Iniciado, endereco " + String(endereco) + " nao encontrado no barramento"); if (Mandatorio) { PrintTela("[MUX] Conexão obrigatória, tentando novamente em 5 segundos..."); delay(5000); IniciarMUX(endereco, Mandatorio); } else { PrintTela("[MUX] TCA9548A nao mandatorio, continuando o fluxo..."); } } else { canalAtivo = -1; // Nenhum canal ativo ainda idAtualUsandoI2C = -1; i2cMutex = xSemaphoreCreateMutex(); PrintTela("[MUX] TCA9548A Iniciado"); } LiberarAcessoI2C(); } else { PrintTela("[MUX] TCA9548A ja Iniciado"); } } static void IniciarMCP(byte endereco = enderecoMcp, bool Mandatorio = false) { if (!I2CIniciado) { PrintTela("[MCP] Impossivel iniciar MCP23X17, I2C nao iniciado!"); return; } PrintTela("[MCP] Iniciando MCP23X17..."); if (!McpIniciado) { SolicitarAcessoI2C(); McpIniciado = mcp.begin_I2C(endereco, &Wire); if (!McpIniciado) { PrintTela("[MCP] Erro ao iniciar MCP23X17!"); if (Mandatorio) { PrintTela("[MCP] Conexão obrigatória, tentando novamente em 5 segundos..."); delay(5000); IniciarMCP(endereco, Mandatorio); } else { PrintTela("[MCP] MCP23X17 nao mandatorio, continuando o fluxo..."); } } else { PrintTela("[MCP] MCP23X17 Iniciado"); } LiberarAcessoI2C(); } else { PrintTela("[MCP] MCP23X17 ja Iniciado"); } } static void IniciarADS(byte endereco = enderecoAds, bool Mandatorio = false) { if (!I2CIniciado) { PrintTela("[ADS] Impossivel iniciar ADS1115, I2C nao iniciado!"); return; } PrintTela("[ADS] Iniciando ADS1115..."); if (!AdsIniciado) { SolicitarAcessoI2C(); AdsIniciado = ads.begin(endereco, &Wire); if (!AdsIniciado) { PrintTela("[ADS] Erro ao iniciar ADS1115!"); if (Mandatorio) { PrintTela("[ADS] Conexão obrigatória, tentando novamente em 5 segundos..."); delay(5000); IniciarADS(endereco, Mandatorio); } else { PrintTela("[ADS] ADS1115 nao mandatorio, continuando o fluxo..."); } } else { ads.setGain(GAIN_ONE); PrintTela("[ADS] ADS1115 Iniciado"); } LiberarAcessoI2C(); } else { PrintTela("[ADS] ADS1115 ja Iniciado"); } } private: static int _pinoSDA; static int _pinoSCL; static unsigned long tempoEntradaI2C; static unsigned long LimiteTempoI2C; }; int I2CService::_pinoSDA = 1; int I2CService::_pinoSCL = 2; unsigned long I2CService::LimiteTempoI2C = 100; bool I2CService::I2CIniciado = false; bool I2CService::MuxIniciado = false; bool I2CService::McpIniciado = false; Adafruit_MCP23X17 I2CService::mcp; Adafruit_ADS1115 I2CService::ads; bool I2CService::AdsIniciado = false; int I2CService::canalAtivo = -1; int I2CService::idAtualUsandoI2C = -1; unsigned long I2CService::tempoEntradaI2C = 0; SemaphoreHandle_t I2CService::i2cMutex = nullptr; #endif