#include "GasolineGenerator.hpp" GasolineGenerator::GasolineGenerator() { } /** * @brief Initialize the Gasoline Generator. * * @note This does not start the generator, it only initializes the input and output cards, * * @param inputCard The digital input card used for monitoring the generator state * @param outputCard The digital output card used for controlling the generator components * @param config The configuration settings for the generator, pins are of input and output cards specified earlier. */ void GasolineGenerator::initialize(DigitalInputCard *inputCard, DigitalOutputCard *outputCard, const GasolineGeneratorConfig &config) { this->config = &config; this->inputCard = inputCard; this->outputCard = outputCard; // Initialize all outputs to safe state setIgnitionSystem(false); setStarter(false); setCarburetorValve(false); // Close for startup // Set debounce time for power output sensor if enabled if (config.usePowerOutputSensor) { this->inputCard->setDebounceTime(config.powerOutputSensorPin, POWER_SENSOR_DEBOUNCE_MS); } // Set debounce time for toggle pin if enabled if (config.useTogglePin) { this->inputCard->setDebounceTime(config.togglePin, POWER_SENSOR_DEBOUNCE_MS); } // Register input change callback this->inputCard->registerCallback([this](uint8_t pin, bool state) { this->handleInputChanges(pin, state); }); state = GeneratorState::STOPPED; } /** * @brief Main loop for the Gasoline Generator. * * This function should be called periodically to handle the generator state machine. */ void GasolineGenerator::loop() { unsigned long currentTime = (xTaskGetTickCount() * 1000) / configTICK_RATE_HZ; switch (state) { case GeneratorState::STARTING: handleStartupSequence(currentTime); break; case GeneratorState::RUNNING: // Monitor engine status and handle any issues if (config->usePowerOutputSensor) { bool hasPowerOutput = inputCard->digitalRead(config->powerOutputSensorPin); if (!hasPowerOutput) { // Engine stopped unexpectedly - no power output detected isEngineRunning = false; shutdown(); } } break; case GeneratorState::SHUTTING_DOWN: // Complete shutdown sequence state = GeneratorState::STOPPED; break; case GeneratorState::STOPPED: default: // Nothing to do in stopped state break; } } /** * @brief Start the gasoline generator. * * This function initiates the startup sequence for the generator. * It will close the carburetor valve, power up the ignition system, * and engage the starter relay to start the engine. */ void GasolineGenerator::start() { if (state != GeneratorState::STOPPED) { return; // Already starting or running } state = GeneratorState::STARTING; startupStartTime = (xTaskGetTickCount() * 1000) / configTICK_RATE_HZ; ignitionStartTime = 0; isEngineRunning = false; starterEngaged = false; // Step 1: Close carburetor valve for rich mixture setCarburetorValve(false); // Step 2: Power up ignition system setIgnitionSystem(true); ignitionStartTime = (xTaskGetTickCount() * 1000) / configTICK_RATE_HZ; } /** * @brief Shutdown the gasoline generator. * * This function stops the generator by turning off all systems, * including the starter, ignition system, and carburetor valve. */ void GasolineGenerator::shutdown() { // Turn off all systems setStarter(false); setIgnitionSystem(false); setCarburetorValve(false); // Close carburetor valve state = GeneratorState::STOPPED; isEngineRunning = false; } /** * @brief Set the carburetor valve state. * * @param open If true, opens the carburetor valve; if false, closes it. * The actual pin state is reversed based on the configuration. */ void GasolineGenerator::setCarburetorValve(bool open) { bool pinState = config->carburetorValveReverse ? !open : open; outputCard->digitalWrite(config->carburetorValvePin, pinState); } /** * @brief Set the ignition system state. * * @param enable If true, powers the ignition system; if false, turns it off. */ void GasolineGenerator::setIgnitionSystem(bool enable) { outputCard->digitalWrite(config->ignitionSystemPowerRelayPin, enable); } /** * @brief Set the starter relay state. * * @param enable If true, engages the starter; if false, disengages it. */ void GasolineGenerator::setStarter(bool enable) { outputCard->digitalWrite(config->starterRelayPin, enable); starterEngaged = enable; } /** * @brief Handle the startup sequence of the gasoline generator. * * This function manages the timing and state transitions during the startup process, * including engaging the starter and checking for successful engine start. * * @param currentTime The current time in milliseconds since system start. */ void GasolineGenerator::handleStartupSequence(unsigned long currentTime) { // Step 3: After ignition delay, engage starter if (ignitionStartTime > 0 && (currentTime - ignitionStartTime) >= IGNITION_DELAY_MS && !starterEngaged) { setStarter(true); } // Check if we have power output AND starter is off (engine is running independently) if (config->usePowerOutputSensor) { bool hasPowerOutput = inputCard->digitalRead(config->powerOutputSensorPin); if (hasPowerOutput && !starterEngaged && !isEngineRunning) { onEngineStarted(); } } else { // No power sensor - fallback to time-based detection if ((currentTime - startupStartTime) >= (IGNITION_DELAY_MS + 3000) && !isEngineRunning) { onEngineStarted(); } } // Timeout protection - stop starter after maximum duration if (ignitionStartTime > 0 && (currentTime - ignitionStartTime) >= (IGNITION_DELAY_MS + STARTER_DURATION_MS)) { setStarter(false); if (!isEngineRunning) { // Failed to start shutdown(); } } } /** * @brief Callback function called when the engine has successfully started. * * This function is called when the engine starts successfully after engaging the starter. * It turns off the starter, opens the carburetor valve, and transitions to the RUNNING state. */ void GasolineGenerator::onEngineStarted() { isEngineRunning = true; // Turn off starter setStarter(false); // Open carburetor valve for normal operation setCarburetorValve(true); state = GeneratorState::RUNNING; } /** * @brief Handle input changes from the digital input card. * * This function processes changes in the state of input pins, particularly for the power output sensor * and toggle switch. It checks if the engine has started or stopped based on the power output sensor state, * and handles toggle switch presses to start/stop the generator. * * @param pin The pin number that changed state. * @param state The new state of the pin (true for HIGH, false for LOW). */ void GasolineGenerator::handleInputChanges(uint8_t pin, bool state) { // Handle power output sensor changes if (pin == config->powerOutputSensorPin) { if (state && this->state == GeneratorState::STARTING && !starterEngaged && !isEngineRunning) { // Power detected during startup with starter off - engine has started successfully onEngineStarted(); } else if (!state && this->state == GeneratorState::RUNNING) { // Power lost during operation - engine may have stopped isEngineRunning = false; shutdown(); } } // Handle toggle pin changes if (pin == config->togglePin && config->useTogglePin) { if (state) // Toggle switch pressed (rising edge) { if (this->state == GeneratorState::STOPPED) { // Start the generator start(); } else if (this->state == GeneratorState::RUNNING) { // Stop the generator shutdown(); } // Ignore toggle during STARTING and SHUTTING_DOWN states } } }