diff --git a/lib/polymech-base/src/components/Extruder.h b/lib/polymech-base/src/components/Extruder.h index 645747a3..f083163d 100644 --- a/lib/polymech-base/src/components/Extruder.h +++ b/lib/polymech-base/src/components/Extruder.h @@ -1,15 +1,16 @@ -#ifndef PLUNGER_H -#define PLUNGER_H +#ifndef EXTRUDER_H +#define EXTRUDER_H + +#include "config.h" #ifdef ENABLE_EXTRUDER -#include "config.h" -#include -#include -#include "./SAKO_VFD.h" #include "./3PosAnalog.h" #include "./POT.h" +#include "./SAKO_VFD.h" #include "enums.h" +#include +#include #include // Component Constants @@ -17,110 +18,123 @@ #define EXTRUDER_COMPONENT_NAME "Extruder" // Speed Presets (in 0.01 Hz units for SAKO_VFD) -#define EXTRUDER_SPEED_SLOW_HZ 10 // 10.00 Hz +#define EXTRUDER_SPEED_SLOW_HZ 10 // 10.00 Hz #define EXTRUDER_SPEED_MEDIUM_HZ 25 // 25.00 Hz -#define EXTRUDER_SPEED_FAST_HZ 50 // 50.00 Hz (currently unused, but defined) +#define EXTRUDER_SPEED_FAST_HZ 50 // 50.00 Hz (currently unused, but defined) // Speed POT Configuration for Extruding (multiplier for MEDIUM speed) -// POT value 0-100. Example: 0 maps to 0.5x, 50 maps to 1.0x, 100 maps to 1.5x MEDIUM speed. +// POT value 0-100. Example: 0 maps to 0.5x, 50 maps to 1.0x, 100 maps to 1.5x +// MEDIUM speed. #define EXTRUDER_SPEED_POT_MIN_MULTIPLIER 0.5f #define EXTRUDER_SPEED_POT_MAX_MULTIPLIER 1.5f // Overload POT Configuration and Jamming (using VFD Torque %) // POT value 0-100. Maps to a torque threshold in percent (0-100). // SAKO_VFD component now provides getTorque() returning 0-100. -#define EXTRUDER_OVERLOAD_POT_MIN_TORQUE_PERCENT 50 // Example: 50% Torque -#define EXTRUDER_OVERLOAD_POT_MAX_TORQUE_PERCENT 95 // Example: 95% Torque -#define PLUNGER_JAMMED_DURATION_MS 2000 // Time torque must be above threshold to be JAMMED -#define EXTRUDER_VFD_READ_INTERVAL_MS 200 // How often to check VFD torque for jamming -#define EXTRUDER_AUTO_MODE_HOLD_DURATION_MS 2000 // Time joystick must be held for auto mode +#define EXTRUDER_OVERLOAD_POT_MIN_TORQUE_PERCENT 50 // Example: 50% Torque +#define EXTRUDER_OVERLOAD_POT_MAX_TORQUE_PERCENT 95 // Example: 95% Torque +#define PLUNGER_JAMMED_DURATION_MS \ + 2000 // Time torque must be above threshold to be JAMMED +#define EXTRUDER_VFD_READ_INTERVAL_MS \ + 200 // How often to check VFD torque for jamming +#define EXTRUDER_AUTO_MODE_HOLD_DURATION_MS \ + 2000 // Time joystick must be held for auto mode // Modbus Configuration -#define EXTRUDER_MB_BASE_ADDRESS EXTRUDER_COMPONENT_ID // Using component ID as base +#define EXTRUDER_MB_BASE_ADDRESS \ + EXTRUDER_COMPONENT_ID // Using component ID as base #define EXTRUDER_MB_STATE_OFFSET 0 #define EXTRUDER_MB_COMMAND_OFFSET 1 #define EXTRUDER_MB_BLOCK_COUNT 2 -#define EXTRUDER_MAX_RUN_TIME_MEDIUM_SPEED_MS 15000 // Max runtime at medium speed +#define EXTRUDER_MAX_RUN_TIME_MEDIUM_SPEED_MS \ + 15000 // Max runtime at medium speed enum class ExtruderModbusCommand : short { - NO_COMMAND = 0, - CMD_EXTRUDE = 2, - CMD_STOP = 3, - CMD_INFO = 4 + NO_COMMAND = 0, + CMD_EXTRUDE = 2, + CMD_STOP = 3, + CMD_INFO = 4 }; // Extruder States enum class ExtruderState : uint8_t { - IDLE, - EXTRUDING_MANUAL, // Joystick held UP, VFD forwarding, monitoring for auto-mode hold time - EXTRUDING_AUTO, // Auto-extruding after joystick hold, VFD forwarding - STOPPING, // Transition state to stop VFD - JAMMED, - RESETTING_JAM // State to handle reset after jam + IDLE, + EXTRUDING_MANUAL, // Joystick held UP, VFD forwarding, monitoring for + // auto-mode hold time + EXTRUDING_AUTO, // Auto-extruding after joystick hold, VFD forwarding + STOPPING, // Transition state to stop VFD + JAMMED, + RESETTING_JAM // State to handle reset after jam }; class Extruder : public Component { public: - Extruder(Component* owner, SAKO_VFD* vfd, Pos3Analog* joystick = nullptr, POT* speedPot = nullptr, POT* overloadPot = nullptr); - ~Extruder() override = default; + Extruder(Component *owner, SAKO_VFD *vfd, Pos3Analog *joystick = nullptr, + POT *speedPot = nullptr, POT *overloadPot = nullptr); + ~Extruder() override = default; - short setup() override; - short loop() override; - short info() override; - short debug() override; - short serial_register(Bridge* b) override; - short init(); - short reset(); + short setup() override; + short loop() override; + short info() override; + short debug() override; + short serial_register(Bridge *b) override; + short init(); + short reset(); - // Modbus TCP Interface - ModbusBlockView* mb_tcp_blocks() const override; - void mb_tcp_register(ModbusTCP* mgr) override; - short mb_tcp_read(MB_Registers* reg) override; - short mb_tcp_write(MB_Registers* reg, short networkValue) override; + // Modbus TCP Interface + ModbusBlockView *mb_tcp_blocks() const override; + void mb_tcp_register(ModbusTCP *mgr) override; + short mb_tcp_read(MB_Registers *reg) override; + short mb_tcp_write(MB_Registers *reg, short networkValue) override; - // Public commands for serial/external control - short cmd_extrude(); - short cmd_stop(); + // Public commands for serial/external control + short cmd_extrude(); + short cmd_stop(); private: - SAKO_VFD* _vfd; - Pos3Analog* _joystick; - POT* _speedPot; - POT* _overloadPot; + SAKO_VFD *_vfd; + Pos3Analog *_joystick; + POT *_speedPot; + POT *_overloadPot; - ExtruderState _currentState; - Pos3Analog::E_POS3_DIRECTION _lastJoystickDirection; + ExtruderState _currentState; + Pos3Analog::E_POS3_DIRECTION _lastJoystickDirection; - uint16_t _currentSpeedPotValue; // 0-100, defaults to 100 if pot is null - uint16_t _currentOverloadPotValue; // 0-100, defaults to 100 if pot is null - float _calculatedExtrudingSpeedHz; // Calculated speed for extruding (0.01Hz units) - uint8_t _calculatedOverloadThresholdPercent; // Calculated torque threshold (0-100%) + uint16_t _currentSpeedPotValue; // 0-100, defaults to 100 if pot is null + uint16_t _currentOverloadPotValue; // 0-100, defaults to 100 if pot is null + float _calculatedExtrudingSpeedHz; // Calculated speed for extruding (0.01Hz + // units) + uint8_t _calculatedOverloadThresholdPercent; // Calculated torque threshold + // (0-100%) - unsigned long _lastStateChangeTimeMs; - unsigned long _jammedStartTimeMs; - unsigned long _lastVfdReadTimeMs; - unsigned long _joystickHoldStartTimeMs; // Timer for joystick hold duration - short _modbusCommandRegisterValue; // Holds the current value of the Modbus command register - unsigned long _operationStartTimeMs; // Start time of current extrude operation - unsigned long _currentMaxOperationTimeMs; // Calculated max duration for current operation + unsigned long _lastStateChangeTimeMs; + unsigned long _jammedStartTimeMs; + unsigned long _lastVfdReadTimeMs; + unsigned long _joystickHoldStartTimeMs; // Timer for joystick hold duration + short _modbusCommandRegisterValue; // Holds the current value of the Modbus + // command register + unsigned long + _operationStartTimeMs; // Start time of current extrude operation + unsigned long _currentMaxOperationTimeMs; // Calculated max duration for + // current operation - // Helper methods - void _handleIdleState(); - void _handleExtrudingManualState(); - void _handleExtrudingAutoState(); - void _handleStoppingState(); - void _handleJammedState(); - void _handleResettingJamState(); + // Helper methods + void _handleIdleState(); + void _handleExtrudingManualState(); + void _handleExtrudingAutoState(); + void _handleStoppingState(); + void _handleJammedState(); + void _handleResettingJamState(); - void _updatePotValues(); - void _checkVfdForJam(); - void _transitionToState(ExtruderState newState); + void _updatePotValues(); + void _checkVfdForJam(); + void _transitionToState(ExtruderState newState); - // VFD interaction wrappers - void _vfdStartForward(uint16_t frequencyCentiHz); - void _vfdStartReverse(uint16_t frequencyCentiHz); - void _vfdStop(); - void _vfdResetJam(); + // VFD interaction wrappers + void _vfdStartForward(uint16_t frequencyCentiHz); + void _vfdStartReverse(uint16_t frequencyCentiHz); + void _vfdStop(); + void _vfdResetJam(); }; #endif -#endif // EXTRUDER_H \ No newline at end of file +#endif // EXTRUDER_H \ No newline at end of file diff --git a/lib/polymech-base/src/components/Plunger.cpp b/lib/polymech-base/src/components/Plunger.cpp index eac84e66..8d7b6cf6 100644 --- a/lib/polymech-base/src/components/Plunger.cpp +++ b/lib/polymech-base/src/components/Plunger.cpp @@ -1,767 +1,737 @@ #include "Plunger.h" -#include #include "PlungerSettings.h" +#include const bool debug_jam = false; const bool debug_states = false; -const char *_plungerStateToString(PlungerState state) -{ - switch (state) - { - case PlungerState::IDLE: - return "IDLE"; - case PlungerState::HOMING_MANUAL: - return "HOMING_MANUAL"; - case PlungerState::HOMING_AUTO: - return "HOMING_AUTO"; - case PlungerState::PLUNGING_MANUAL: - return "PLUNGING_MANUAL"; - case PlungerState::PLUNGING_AUTO: - return "PLUNGING_AUTO"; - case PlungerState::STOPPING: - return "STOPPING"; - case PlungerState::JAMMED: - return "JAMMED"; - case PlungerState::RESETTING_JAM: - return "RESETTING_JAM"; - case PlungerState::RECORD: - return "RECORD"; - case PlungerState::REPLAY: - return "REPLAY"; - case PlungerState::FILLING: - return "FILLING"; - case PlungerState::POST_FLOW: - return "POST_FLOW"; - default: - return "UNKNOWN_STATE"; - } +const char *_plungerStateToString(PlungerState state) { + switch (state) { + case PlungerState::IDLE: + return "IDLE"; + case PlungerState::HOMING_MANUAL: + return "HOMING_MANUAL"; + case PlungerState::HOMING_AUTO: + return "HOMING_AUTO"; + case PlungerState::PLUNGING_MANUAL: + return "PLUNGING_MANUAL"; + case PlungerState::PLUNGING_AUTO: + return "PLUNGING_AUTO"; + case PlungerState::STOPPING: + return "STOPPING"; + case PlungerState::JAMMED: + return "JAMMED"; + case PlungerState::RESETTING_JAM: + return "RESETTING_JAM"; + case PlungerState::RECORD: + return "RECORD"; + case PlungerState::REPLAY: + return "REPLAY"; + case PlungerState::FILLING: + return "FILLING"; + case PlungerState::POST_FLOW: + return "POST_FLOW"; + default: + return "UNKNOWN_STATE"; + } } -const char *_fillStateToString(FillState state) -{ - switch (state) - { - case FillState::NONE: - return "NONE"; - case FillState::PLUNGING: - return "PLUNGING"; - case FillState::PLUNGED: - return "PLUNGED"; - case FillState::HOMING: - return "HOMING"; - case FillState::HOMED: - return "HOMED"; - default: - return "UNKNOWN_FILL_STATE"; - } +const char *_fillStateToString(FillState state) { + switch (state) { + case FillState::NONE: + return "NONE"; + case FillState::PLUNGING: + return "PLUNGING"; + case FillState::PLUNGED: + return "PLUNGED"; + case FillState::HOMING: + return "HOMING"; + case FillState::HOMED: + return "HOMED"; + default: + return "UNKNOWN_FILL_STATE"; + } } -const char *_postFlowStateToString(PostFlowState state) -{ - switch (state) - { - case PostFlowState::NONE: - return "NONE"; - case PostFlowState::POST_FLOW_STOPPING: - return "STOPPING"; - case PostFlowState::POST_FLOW_STARTING: - return "STARTING"; - case PostFlowState::POST_FLOW_COMPLETE: - return "COMPLETE"; - default: - return "UNKNOWN_POST_FLOW_STATE"; - } +const char *_postFlowStateToString(PostFlowState state) { + switch (state) { + case PostFlowState::NONE: + return "NONE"; + case PostFlowState::POST_FLOW_STOPPING: + return "STOPPING"; + case PostFlowState::POST_FLOW_STARTING: + return "STARTING"; + case PostFlowState::POST_FLOW_COMPLETE: + return "COMPLETE"; + default: + return "UNKNOWN_POST_FLOW_STATE"; + } } -Plunger::Plunger(Component *owner, DELTA_VFD *vfd, Joystick *joystick, POT *speedPot, POT *torquePot) - : NetworkComponent(PLUNGER_MB_BASE_ADDRESS, PLUNGER_COMPONENT_NAME, COMPONENT_KEY_PLUNGER, Component::COMPONENT_DEFAULT, owner), - _vfd(vfd), - _joystick(joystick), - _speedPot(speedPot), - _torquePot(torquePot), - _currentFillState(FillState::NONE), +Plunger::Plunger(Component *owner, DELTA_VFD *vfd, Joystick *joystick, + POT *speedPot, POT *torquePot) + : NetworkComponent(PLUNGER_MB_BASE_ADDRESS, PLUNGER_COMPONENT_NAME, + COMPONENT_KEY_PLUNGER, Component::COMPONENT_DEFAULT, + owner), + _vfd(vfd), _joystick(joystick), _speedPot(speedPot), + _torquePot(torquePot), _currentFillState(FillState::NONE), _lastJoystickDirection(Joystick::E_POSITION::CENTER), - _currentSpeedPotValue(0), - _currentTorquePotValue(0), - _calculatedPlungingSpeedHz(0), - _lastStateChangeTimeMs(0), - _jammedStartTimeMs(0), - _lastVfdReadTimeMs(0), - _joystickHoldStartTimeMs(0), - _operationStartTimeMs(0), - _currentMaxOperationTimeMs(0), - _joystickReleasedSinceAutoStart(false), - _autoModeEnabled(true), - _lastDiagnosticLogTimeMs(0), - _lastImmediateStopCheckTimeMs(0), - _lastStateLogTimeMs(0), - _recordedPlungeDurationMs(0), - _recordModeStartTimeMs(0), - _fillOperationStartTimeMs(0), - _postFlowStartTimeMs(0), - _currentPostFlowState(PostFlowState::NONE), + _currentSpeedPotValue(0), _currentTorquePotValue(0), + _calculatedPlungingSpeedHz(0), _lastStateChangeTimeMs(0), + _jammedStartTimeMs(0), _lastVfdReadTimeMs(0), _joystickHoldStartTimeMs(0), + _operationStartTimeMs(0), _currentMaxOperationTimeMs(0), + _joystickReleasedSinceAutoStart(false), _autoModeEnabled(true), + _lastDiagnosticLogTimeMs(0), _lastImmediateStopCheckTimeMs(0), + _lastStateLogTimeMs(0), _recordedPlungeDurationMs(0), + _recordModeStartTimeMs(0), _fillOperationStartTimeMs(0), + _postFlowStartTimeMs(0), _currentPostFlowState(PostFlowState::NONE), _eventsDelegate(nullptr), m_state(this, PLUNGER_MB_STATE_OFFSET, "Plunger State"), - m_command(this, PLUNGER_MB_COMMAND_OFFSET, "Plunger Command") -{ - setNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS); + m_command(this, PLUNGER_MB_COMMAND_OFFSET, "Plunger Command") { + setNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS); } -short Plunger::init() -{ - _vfdResetJam(); - _vfdStop(); - _transitionToState(PlungerState::IDLE); - _lastJoystickDirection = Joystick::E_POSITION::CENTER; - _lastStateChangeTimeMs = millis(); - _jammedStartTimeMs = 0; - _lastVfdReadTimeMs = 0; - _joystickHoldStartTimeMs = 0; - _operationStartTimeMs = 0; - _currentMaxOperationTimeMs = 0; - _lastDiagnosticLogTimeMs = 0; - _lastImmediateStopCheckTimeMs = 0; - _lastStateLogTimeMs = 0; - m_command.update(static_cast(E_PlungerCommand::NO_COMMAND)); - _joystickReleasedSinceAutoStart = false; - _autoModeEnabled = true; +short Plunger::init() { + _vfdResetJam(); + _vfdStop(); + _transitionToState(PlungerState::IDLE); + _lastJoystickDirection = Joystick::E_POSITION::CENTER; + _lastStateChangeTimeMs = millis(); + _jammedStartTimeMs = 0; + _lastVfdReadTimeMs = 0; + _joystickHoldStartTimeMs = 0; + _operationStartTimeMs = 0; + _currentMaxOperationTimeMs = 0; + _lastDiagnosticLogTimeMs = 0; + _lastImmediateStopCheckTimeMs = 0; + _lastStateLogTimeMs = 0; + m_command.update(static_cast(E_PlungerCommand::NO_COMMAND)); + _joystickReleasedSinceAutoStart = false; + _autoModeEnabled = true; - bool loadSettings = true; + bool loadSettings = true; - if (loadSettings) - { - if (_settings.load()) - { - L_INFO("[%s] Settings loaded from file during init.", name.c_str()); + if (loadSettings) { + if (_settings.load()) { + L_INFO("[%s] Settings loaded from file during init.", name.c_str()); + } else { + Log.warningln( + "[%s] Could not load settings from file during init, using " + "compile-time defaults. Attempting to save defaults to create file.", + name.c_str()); + if (_settings.save()) { // Attempt to save the current (compile-time + // default) settings + L_INFO("[%s] Default settings saved to file during init.", + name.c_str()); + } else { + L_ERROR("[%s] Failed to save default settings to file during init.", + name.c_str()); + } + } + } + _updatePotValues(); // Recalculates _calculatedPlungingSpeedHz based on + // potentially loaded _settings.speedFastHz + _recordedPlungeDurationMs = _settings.replayDurationMs; + + _recordModeStartTimeMs = 0; + _joystickRecordHoldTimer.detach(); + _replayPlungeTimer.detach(); + + _currentFillState = FillState::NONE; + _fillOperationStartTimeMs = 0; + _fillSubStateTimer.detach(); + _joystickFillHoldTimer.detach(); + + _postFlowStartTimeMs = 0; + _currentPostFlowState = PostFlowState::NONE; + _postFlowSubStateTimer.detach(); + return E_OK; +} + +short Plunger::setup() { + NetworkComponent::setup(); + + const uint16_t baseAddr = mb_tcp_base_address(); + + m_state.initNotify(static_cast(PlungerState::IDLE), true, + NetworkValue_ThresholdMode::DIFFERENCE); + m_state.initModbus(baseAddr + MB_OFS_STATE, 1, this->id, this->slaveId, + FN_READ_HOLD_REGISTER, + "Plunger " + "State:(0:Idle,1:HomingMan,2:HomingAuto,3:PlungingMan,4:" + "PlungingAuto,5:Stopping,6:Jammed,7:ResettingJam,8:Record," + "9:Replay,10:Filling,11:PostFlow)", + this->name.c_str()); + registerBlock(m_state.getRegisterInfo()); + + m_command.initNotify(static_cast(E_PlungerCommand::NO_COMMAND), + true, NetworkValue_ThresholdMode::DIFFERENCE); + m_command.initModbus( + baseAddr + MB_OFS_COMMAND, 1, this->id, this->slaveId, + FN_WRITE_HOLD_REGISTER, + "Plunger Command:(0:None,1:Home,2:Plunge,3:Stop,4:Info,5:Fill,6:Replay)", + this->name.c_str()); + registerBlock(m_command.getRegisterInfo()); + + return this->init(); +} + +void Plunger::_updatePotValues() { + if (!_speedPot || !_torquePot) { + return; + } + _currentSpeedPotValue = _speedPot->getValue(); + _currentTorquePotValue = _torquePot->getValue(); + _calculatedPlungingSpeedHz = + (_currentSpeedPotValue / 100.0f) * (_settings.speedFastHz * 100.0f); +} + +void Plunger::_vfdStartForward(uint16_t frequencyCentiHz) { + L_INFO("Plunger::_vfdStartForward: frequencyCentiHz: %d", frequencyCentiHz); + _vfd->setFrequency(frequencyCentiHz); // DELTA_VFD::setFrequency expects + // 0.01Hz units (centiHz) + _vfd->run(); +} + +void Plunger::_vfdStartReverse(uint16_t frequencyCentiHz) { + L_INFO("Plunger::_vfdStartReverse: frequencyCentiHz: %d", frequencyCentiHz); + _vfd->setFrequency(frequencyCentiHz); // DELTA_VFD::setFrequency expects + // 0.01Hz units (centiHz) + _vfd->reverse(); +} + +void Plunger::_vfdStop() { _vfd->stop(); } + +void Plunger::_vfdResetJam() { _vfd->resetFault(); } + +void Plunger::_checkVfdForJam() { + unsigned long currentTimeMs = millis(); + if (debug_jam && currentTimeMs - _lastDiagnosticLogTimeMs > 5000) { + uint16_t diagCurrentMa = 0; + bool diagReadSuccess = _vfd->getOutputCurrent(diagCurrentMa); + L_INFO("[%s] --- DIAGNOSTIC LOG (debug_jam active) ---", name.c_str()); + L_INFO("State: %s, FillState: %s, PostFlowState: %s", + _plungerStateToString(static_cast(m_state.getValue())), + (m_state.getValue() == static_cast(PlungerState::FILLING) + ? _fillStateToString(_currentFillState) + : "N/A"), + (m_state.getValue() == static_cast(PlungerState::POST_FLOW) + ? _postFlowStateToString(_currentPostFlowState) + : "N/A")); + L_INFO("VFD Running (reported): %d, VFD Fault (reported): %d", + _vfd->isRunning(), _vfd->hasFault()); + L_INFO("VFD Current Read Success: %d, Current: %u mA", diagReadSuccess, + diagCurrentMa); + L_INFO("JammedStartTime: %lu ms (ago: %lu ms if active)", + _jammedStartTimeMs, + (_jammedStartTimeMs > 0 ? currentTimeMs - _jammedStartTimeMs : 0)); + L_INFO("JoystickHoldStartTime: %lu ms", _joystickHoldStartTimeMs); + L_INFO("OperationStartTime: %lu ms, CurrentMaxOpTime: %lu ms", + _operationStartTimeMs, _currentMaxOperationTimeMs); + L_INFO("FillOperationStartTime: %lu ms", _fillOperationStartTimeMs); + _lastDiagnosticLogTimeMs = currentTimeMs; + } + + uint16_t vfdOutputCurrentMa = 0; + bool readSuccess = _vfd->getOutputCurrent(vfdOutputCurrentMa); + if (!readSuccess) { + return; + } + + bool motorExpectedActive = false; + PlungerState currentState = static_cast(m_state.getValue()); + if (currentState == PlungerState::HOMING_MANUAL || + currentState == PlungerState::HOMING_AUTO || + currentState == PlungerState::PLUNGING_MANUAL || + currentState == PlungerState::PLUNGING_AUTO || + currentState == PlungerState::RECORD || + (currentState == PlungerState::POST_FLOW && + _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) || + (currentState == PlungerState::FILLING && + (_currentFillState == FillState::PLUNGING || + _currentFillState == FillState::HOMING))) { + motorExpectedActive = true; + } + + if (_vfd->hasFault()) { + _transitionToState(PlungerState::JAMMED); + return; + } + + if (!motorExpectedActive) { + if (_jammedStartTimeMs != 0) { + _jammedStartTimeMs = 0; + } + return; + } + + float torqueMultiplier = 1.0f; + uint16_t adjustedJamThresholdMa = _settings.currentJamThresholdMa; + + bool isPlungingState = (currentState == PlungerState::PLUNGING_MANUAL || + currentState == PlungerState::PLUNGING_AUTO || + currentState == PlungerState::RECORD || + (currentState == PlungerState::FILLING && + _currentFillState == FillState::PLUNGING)); + + if (currentState == PlungerState::POST_FLOW && + _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) { + adjustedJamThresholdMa = _settings.currentPostFlowMa; + } else if (isPlungingState) { + torqueMultiplier = (100.0f - _currentTorquePotValue) / 100.0f; + adjustedJamThresholdMa = static_cast( + _settings.currentJamThresholdMa * torqueMultiplier); + } + + if (vfdOutputCurrentMa >= adjustedJamThresholdMa) { + if (_jammedStartTimeMs == 0) { + _jammedStartTimeMs = millis(); + } + + unsigned long jamDurationTargetMs = 0; + if (currentState == PlungerState::FILLING) { + if (_currentFillState == FillState::PLUNGING) + jamDurationTargetMs = _settings.jammedDurationMs; + else if (_currentFillState == FillState::HOMING) + jamDurationTargetMs = _settings.jammedDurationHomingMs; + } else if (currentState == PlungerState::POST_FLOW && + _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) { + jamDurationTargetMs = _settings.jammedDurationMs; + } else if (currentState == PlungerState::HOMING_MANUAL || + currentState == PlungerState::HOMING_AUTO) { + jamDurationTargetMs = _settings.jammedDurationHomingMs; + } else if (currentState == PlungerState::PLUNGING_MANUAL || + currentState == PlungerState::PLUNGING_AUTO || + currentState == PlungerState::RECORD) { + jamDurationTargetMs = _settings.jammedDurationMs; + } + + if (_jammedStartTimeMs > 0 && + (millis() - _jammedStartTimeMs > _settings.maxUniversalJamTimeMs)) { + L_ERROR("[%s] UNIVERSAL JAM TIMEOUT! Current %u mA for >%lums. State: " + "%s, FillState: %s. JAMMED.", + name.c_str(), vfdOutputCurrentMa, millis() - _jammedStartTimeMs, + _plungerStateToString(currentState), + currentState == PlungerState::FILLING + ? _fillStateToString(_currentFillState) + : "N/A"); + _transitionToState(PlungerState::JAMMED); + return; + } + + if (jamDurationTargetMs > 0 && _jammedStartTimeMs > 0 && + (millis() - _jammedStartTimeMs > jamDurationTargetMs)) { + if (currentState == PlungerState::PLUNGING_AUTO && + _settings.enablePostFlow) { + _transitionToState(PlungerState::POST_FLOW); + } else if (currentState == PlungerState::FILLING) { + _vfdStop(); + if (_currentFillState == FillState::PLUNGING) { + _currentFillState = FillState::PLUNGED; + _fillSubStateTimer.once_ms(_settings.fillPlungedWaitDurationMs, + &Plunger::_fillSubStateTimerRelay, this); + _jammedStartTimeMs = 0; + } else if (_currentFillState == FillState::HOMING) { + _currentFillState = FillState::HOMED; + _fillSubStateTimer.once_ms(_settings.fillHomedWaitDurationMs, + &Plunger::_fillSubStateTimerRelay, this); + _jammedStartTimeMs = 0; } - else - { - Log.warningln("[%s] Could not load settings from file during init, using compile-time defaults. Attempting to save defaults to create file.", name.c_str()); - if (_settings.save()) - { // Attempt to save the current (compile-time default) settings - L_INFO("[%s] Default settings saved to file during init.", name.c_str()); - } - else - { - L_ERROR("[%s] Failed to save default settings to file during init.", name.c_str()); - } - } - } - _updatePotValues(); // Recalculates _calculatedPlungingSpeedHz based on potentially loaded _settings.speedFastHz - _recordedPlungeDurationMs = _settings.replayDurationMs; - - _recordModeStartTimeMs = 0; - _joystickRecordHoldTimer.detach(); - _replayPlungeTimer.detach(); - - _currentFillState = FillState::NONE; - _fillOperationStartTimeMs = 0; - _fillSubStateTimer.detach(); - _joystickFillHoldTimer.detach(); - - _postFlowStartTimeMs = 0; - _currentPostFlowState = PostFlowState::NONE; - _postFlowSubStateTimer.detach(); - return E_OK; -} - -short Plunger::setup() -{ - NetworkComponent::setup(); - - const uint16_t baseAddr = mb_tcp_base_address(); - - m_state.initNotify(static_cast(PlungerState::IDLE), true, NetworkValue_ThresholdMode::DIFFERENCE); - m_state.initModbus(baseAddr + MB_OFS_STATE, 1, this->id, this->slaveId, FN_READ_HOLD_REGISTER, "Plunger State:(0:Idle,1:HomingMan,2:HomingAuto,3:PlungingMan,4:PlungingAuto,5:Stopping,6:Jammed,7:ResettingJam,8:Record,9:Replay,10:Filling,11:PostFlow)", this->name.c_str()); - registerBlock(m_state.getRegisterInfo()); - - m_command.initNotify(static_cast(E_PlungerCommand::NO_COMMAND), true, NetworkValue_ThresholdMode::DIFFERENCE); - m_command.initModbus(baseAddr + MB_OFS_COMMAND, 1, this->id, this->slaveId, FN_WRITE_HOLD_REGISTER, "Plunger Command:(0:None,1:Home,2:Plunge,3:Stop,4:Info,5:Fill,6:Replay)", this->name.c_str()); - registerBlock(m_command.getRegisterInfo()); - - return this->init(); -} - -void Plunger::_updatePotValues() -{ - if(!_speedPot || !_torquePot) - { - return; - } - _currentSpeedPotValue = _speedPot->getValue(); - _currentTorquePotValue = _torquePot->getValue(); - _calculatedPlungingSpeedHz = (_currentSpeedPotValue / 100.0f) * (_settings.speedFastHz * 100.0f); -} - -void Plunger::_vfdStartForward(uint16_t frequencyCentiHz) -{ - L_INFO("Plunger::_vfdStartForward: frequencyCentiHz: %d", frequencyCentiHz); - _vfd->setFrequency(frequencyCentiHz); // DELTA_VFD::setFrequency expects 0.01Hz units (centiHz) - _vfd->run(); -} - -void Plunger::_vfdStartReverse(uint16_t frequencyCentiHz) -{ - L_INFO("Plunger::_vfdStartReverse: frequencyCentiHz: %d", frequencyCentiHz); - _vfd->setFrequency(frequencyCentiHz); // DELTA_VFD::setFrequency expects 0.01Hz units (centiHz) - _vfd->reverse(); -} - -void Plunger::_vfdStop() -{ - _vfd->stop(); -} - -void Plunger::_vfdResetJam() -{ - _vfd->resetFault(); -} - -void Plunger::_checkVfdForJam() -{ - unsigned long currentTimeMs = millis(); - if (debug_jam && currentTimeMs - _lastDiagnosticLogTimeMs > 5000) - { - uint16_t diagCurrentMa = 0; - bool diagReadSuccess = _vfd->getOutputCurrent(diagCurrentMa); - L_INFO("[%s] --- DIAGNOSTIC LOG (debug_jam active) ---", name.c_str()); - L_INFO("State: %s, FillState: %s, PostFlowState: %s", - _plungerStateToString(static_cast(m_state.getValue())), - (m_state.getValue() == static_cast(PlungerState::FILLING) ? _fillStateToString(_currentFillState) : "N/A"), - (m_state.getValue() == static_cast(PlungerState::POST_FLOW) ? _postFlowStateToString(_currentPostFlowState) : "N/A")); - L_INFO("VFD Running (reported): %d, VFD Fault (reported): %d", _vfd->isRunning(), _vfd->hasFault()); - L_INFO("VFD Current Read Success: %d, Current: %u mA", diagReadSuccess, diagCurrentMa); - L_INFO("JammedStartTime: %lu ms (ago: %lu ms if active)", _jammedStartTimeMs, (_jammedStartTimeMs > 0 ? currentTimeMs - _jammedStartTimeMs : 0)); - L_INFO("JoystickHoldStartTime: %lu ms", _joystickHoldStartTimeMs); - L_INFO("OperationStartTime: %lu ms, CurrentMaxOpTime: %lu ms", _operationStartTimeMs, _currentMaxOperationTimeMs); - L_INFO("FillOperationStartTime: %lu ms", _fillOperationStartTimeMs); - _lastDiagnosticLogTimeMs = currentTimeMs; - } - - uint16_t vfdOutputCurrentMa = 0; - bool readSuccess = _vfd->getOutputCurrent(vfdOutputCurrentMa); - if (!readSuccess) - { - return; - } - - bool motorExpectedActive = false; - PlungerState currentState = static_cast(m_state.getValue()); - if (currentState == PlungerState::HOMING_MANUAL || currentState == PlungerState::HOMING_AUTO || - currentState == PlungerState::PLUNGING_MANUAL || currentState == PlungerState::PLUNGING_AUTO || - currentState == PlungerState::RECORD || - (currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) || - (currentState == PlungerState::FILLING && - (_currentFillState == FillState::PLUNGING || _currentFillState == FillState::HOMING))) - { - motorExpectedActive = true; - } - - if (_vfd->hasFault()) - { + } else { _transitionToState(PlungerState::JAMMED); - return; + } + } else if (_jammedStartTimeMs > 0) { } - - if (!motorExpectedActive) + } else // Current is NOT above threshold + { + if (_jammedStartTimeMs != 0) // If it *was* timing a jam { - if (_jammedStartTimeMs != 0) - { - _jammedStartTimeMs = 0; - } - return; - } - - float torqueMultiplier = 1.0f; - uint16_t adjustedJamThresholdMa = _settings.currentJamThresholdMa; - - bool isPlungingState = (currentState == PlungerState::PLUNGING_MANUAL || - currentState == PlungerState::PLUNGING_AUTO || - currentState == PlungerState::RECORD || - (currentState == PlungerState::FILLING && _currentFillState == FillState::PLUNGING)); - - if (currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) - { - adjustedJamThresholdMa = _settings.currentPostFlowMa; - } - else if (isPlungingState) - { - torqueMultiplier = (100.0f - _currentTorquePotValue) / 100.0f; - adjustedJamThresholdMa = static_cast(_settings.currentJamThresholdMa * torqueMultiplier); - } - - if (vfdOutputCurrentMa >= adjustedJamThresholdMa) - { - if (_jammedStartTimeMs == 0) - { - _jammedStartTimeMs = millis(); - } - - unsigned long jamDurationTargetMs = 0; - if (currentState == PlungerState::FILLING) - { - if (_currentFillState == FillState::PLUNGING) - jamDurationTargetMs = _settings.jammedDurationMs; - else if (_currentFillState == FillState::HOMING) - jamDurationTargetMs = _settings.jammedDurationHomingMs; - } - else if (currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) - { - jamDurationTargetMs = _settings.jammedDurationMs; - } - else if (currentState == PlungerState::HOMING_MANUAL || currentState == PlungerState::HOMING_AUTO) - { - jamDurationTargetMs = _settings.jammedDurationHomingMs; - } - else if (currentState == PlungerState::PLUNGING_MANUAL || currentState == PlungerState::PLUNGING_AUTO || currentState == PlungerState::RECORD) - { - jamDurationTargetMs = _settings.jammedDurationMs; - } - - if (_jammedStartTimeMs > 0 && (millis() - _jammedStartTimeMs > _settings.maxUniversalJamTimeMs)) - { - L_ERROR("[%s] UNIVERSAL JAM TIMEOUT! Current %u mA for >%lums. State: %s, FillState: %s. JAMMED.", - name.c_str(), vfdOutputCurrentMa, millis() - _jammedStartTimeMs, - _plungerStateToString(currentState), - currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A"); - _transitionToState(PlungerState::JAMMED); - return; - } - - if (jamDurationTargetMs > 0 && _jammedStartTimeMs > 0 && (millis() - _jammedStartTimeMs > jamDurationTargetMs)) - { - if (currentState == PlungerState::PLUNGING_AUTO && _settings.enablePostFlow) - { - _transitionToState(PlungerState::POST_FLOW); - } - else if (currentState == PlungerState::FILLING) - { - _vfdStop(); - if (_currentFillState == FillState::PLUNGING) - { - _currentFillState = FillState::PLUNGED; - _fillSubStateTimer.once_ms(_settings.fillPlungedWaitDurationMs, &Plunger::_fillSubStateTimerRelay, this); - _jammedStartTimeMs = 0; - } - else if (_currentFillState == FillState::HOMING) - { - _currentFillState = FillState::HOMED; - _fillSubStateTimer.once_ms(_settings.fillHomedWaitDurationMs, &Plunger::_fillSubStateTimerRelay, this); - _jammedStartTimeMs = 0; - } - } - else - { - _transitionToState(PlungerState::JAMMED); - } - } - else if (_jammedStartTimeMs > 0) - { - } - } - else // Current is NOT above threshold - { - if (_jammedStartTimeMs != 0) // If it *was* timing a jam - { - _jammedStartTimeMs = 0; - } + _jammedStartTimeMs = 0; } + } } -short Plunger::loop() -{ - NetworkComponent::loop(); - _updatePotValues(); - _checkVfdForJam(); - if(!m_enabled.getValue()) - { - return E_OK; +short Plunger::loop() { + NetworkComponent::loop(); + _updatePotValues(); + _checkVfdForJam(); + if (!m_enabled.getValue()) { + return E_OK; + } + if (debug_states) { + unsigned long currentTimeMs = millis(); + if (currentTimeMs - _lastStateLogTimeMs >= 10000) { + L_INFO("[%s] --- STATE LOG DUMP (debug_states active) ---", name.c_str()); + L_INFO(" CurrentTime: %lu ms", currentTimeMs); + L_INFO( + " State: %s (%d)", + _plungerStateToString(static_cast(m_state.getValue())), + m_state.getValue()); + if (m_state.getValue() == static_cast(PlungerState::FILLING)) { + L_INFO(" FillState: %s (%d)", _fillStateToString(_currentFillState), + static_cast(_currentFillState)); + } + if (m_state.getValue() == + static_cast(PlungerState::POST_FLOW)) { + L_INFO(" PostFlowState: %s (%d)", + _postFlowStateToString(_currentPostFlowState), + static_cast(_currentPostFlowState)); + } + L_INFO(" Timers (ms):"); + L_INFO(" OperationStart: %d (Max: %d)", _operationStartTimeMs, + _currentMaxOperationTimeMs); + L_INFO(" JammedStart: %lu", _jammedStartTimeMs); + L_INFO(" JoystickHoldStart: %lu", _joystickHoldStartTimeMs); + L_INFO(" FillOperationStart: %lu", _fillOperationStartTimeMs); + L_INFO(" PostFlowStart: %lu", _postFlowStartTimeMs); + L_INFO(" RecordModeStart: %lu", _recordModeStartTimeMs); + L_INFO(" LastStateChange: %lu", _lastStateChangeTimeMs); + _lastStateLogTimeMs = currentTimeMs; + L_INFO("[%s] --- END STATE LOG DUMP ---", name.c_str()); } - if (debug_states) - { - unsigned long currentTimeMs = millis(); - if (currentTimeMs - _lastStateLogTimeMs >= 10000) - { - L_INFO("[%s] --- STATE LOG DUMP (debug_states active) ---", name.c_str()); - L_INFO(" CurrentTime: %lu ms", currentTimeMs); - L_INFO(" State: %s (%d)", _plungerStateToString(static_cast(m_state.getValue())), m_state.getValue()); - if (m_state.getValue() == static_cast(PlungerState::FILLING)) - { - L_INFO(" FillState: %s (%d)", _fillStateToString(_currentFillState), static_cast(_currentFillState)); - } - if (m_state.getValue() == static_cast(PlungerState::POST_FLOW)) - { - L_INFO(" PostFlowState: %s (%d)", _postFlowStateToString(_currentPostFlowState), static_cast(_currentPostFlowState)); - } - L_INFO(" Timers (ms):"); - L_INFO(" OperationStart: %d (Max: %d)", _operationStartTimeMs, _currentMaxOperationTimeMs); - L_INFO(" JammedStart: %lu", _jammedStartTimeMs); - L_INFO(" JoystickHoldStart: %lu", _joystickHoldStartTimeMs); - L_INFO(" FillOperationStart: %lu", _fillOperationStartTimeMs); - L_INFO(" PostFlowStart: %lu", _postFlowStartTimeMs); - L_INFO(" RecordModeStart: %lu", _recordModeStartTimeMs); - L_INFO(" LastStateChange: %lu", _lastStateChangeTimeMs); - _lastStateLogTimeMs = currentTimeMs; - L_INFO("[%s] --- END STATE LOG DUMP ---", name.c_str()); - } - } - Joystick::E_POSITION currentJoystickDir = static_cast(_joystick->getValue()); - if (_operationStartTimeMs > 0 && _currentMaxOperationTimeMs > 0) - { - bool isMonitoredState = false; - PlungerState currentState = static_cast(m_state.getValue()); - if (currentState == PlungerState::HOMING_MANUAL || currentState == PlungerState::HOMING_AUTO || - currentState == PlungerState::PLUNGING_MANUAL || currentState == PlungerState::PLUNGING_AUTO || - currentState == PlungerState::RECORD || currentState == PlungerState::REPLAY) - { - isMonitoredState = true; - } - else if (currentState == PlungerState::FILLING && - (_currentFillState == FillState::PLUNGING || _currentFillState == FillState::HOMING)) - { - isMonitoredState = true; - } - else if (currentState == PlungerState::POST_FLOW && _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) - { - isMonitoredState = true; - } - - if (isMonitoredState && (millis() - _operationStartTimeMs > _currentMaxOperationTimeMs)) - { - Log.warningln("[%s] GENERIC MAX OPERATION TIME (%lu ms) EXCEEDED! State: %s, FillState: %s, PostFlowState: %s. Transitioning to JAMMED.", - name.c_str(), _currentMaxOperationTimeMs, - _plungerStateToString(currentState), - currentState == PlungerState::FILLING ? _fillStateToString(_currentFillState) : "N/A", - currentState == PlungerState::POST_FLOW ? _postFlowStateToString(_currentPostFlowState) : "N/A"); - _transitionToState(PlungerState::JAMMED); - } - } - + } + Joystick::E_POSITION currentJoystickDir = + static_cast(_joystick->getValue()); + if (_operationStartTimeMs > 0 && _currentMaxOperationTimeMs > 0) { + bool isMonitoredState = false; PlungerState currentState = static_cast(m_state.getValue()); - switch (currentState) - { - case PlungerState::IDLE: - _handleIdleState(); - break; - case PlungerState::HOMING_MANUAL: - _handleHomingManualState(); - break; - case PlungerState::HOMING_AUTO: - _handleHomingAutoState(); - break; - case PlungerState::PLUNGING_MANUAL: - _handlePlungingManualState(); - break; - case PlungerState::PLUNGING_AUTO: - _handlePlungingAutoState(); - break; - case PlungerState::STOPPING: - _handleStoppingState(); - break; - case PlungerState::JAMMED: - _handleJammedState(); - break; - case PlungerState::RESETTING_JAM: - _handleResettingJamState(); - break; - case PlungerState::RECORD: - _handleRecordState(); - break; - case PlungerState::REPLAY: - _handleReplayState(); - break; - case PlungerState::FILLING: // Re-added case - _handleFillingState(); - break; - case PlungerState::POST_FLOW: - _handlePostFlowState(); - break; - default: - Log.warningln("[%s] Unknown state: %d. Transitioning to IDLE.", name.c_str(), static_cast(currentState)); - _transitionToState(PlungerState::IDLE); - break; + if (currentState == PlungerState::HOMING_MANUAL || + currentState == PlungerState::HOMING_AUTO || + currentState == PlungerState::PLUNGING_MANUAL || + currentState == PlungerState::PLUNGING_AUTO || + currentState == PlungerState::RECORD || + currentState == PlungerState::REPLAY) { + isMonitoredState = true; + } else if (currentState == PlungerState::FILLING && + (_currentFillState == FillState::PLUNGING || + _currentFillState == FillState::HOMING)) { + isMonitoredState = true; + } else if (currentState == PlungerState::POST_FLOW && + _currentPostFlowState == PostFlowState::POST_FLOW_STARTING) { + isMonitoredState = true; } - _lastJoystickDirection = currentJoystickDir; + + if (isMonitoredState && + (millis() - _operationStartTimeMs > _currentMaxOperationTimeMs)) { + Log.warningln( + "[%s] GENERIC MAX OPERATION TIME (%lu ms) EXCEEDED! State: %s, " + "FillState: %s, PostFlowState: %s. Transitioning to JAMMED.", + name.c_str(), _currentMaxOperationTimeMs, + _plungerStateToString(currentState), + currentState == PlungerState::FILLING + ? _fillStateToString(_currentFillState) + : "N/A", + currentState == PlungerState::POST_FLOW + ? _postFlowStateToString(_currentPostFlowState) + : "N/A"); + _transitionToState(PlungerState::JAMMED); + } + } + + PlungerState currentState = static_cast(m_state.getValue()); + switch (currentState) { + case PlungerState::IDLE: + _handleIdleState(); + break; + case PlungerState::HOMING_MANUAL: + _handleHomingManualState(); + break; + case PlungerState::HOMING_AUTO: + _handleHomingAutoState(); + break; + case PlungerState::PLUNGING_MANUAL: + _handlePlungingManualState(); + break; + case PlungerState::PLUNGING_AUTO: + _handlePlungingAutoState(); + break; + case PlungerState::STOPPING: + _handleStoppingState(); + break; + case PlungerState::JAMMED: + _handleJammedState(); + break; + case PlungerState::RESETTING_JAM: + _handleResettingJamState(); + break; + case PlungerState::RECORD: + _handleRecordState(); + break; + case PlungerState::REPLAY: + _handleReplayState(); + break; + case PlungerState::FILLING: // Re-added case + _handleFillingState(); + break; + case PlungerState::POST_FLOW: + _handlePostFlowState(); + break; + default: + Log.warningln("[%s] Unknown state: %d. Transitioning to IDLE.", + name.c_str(), static_cast(currentState)); + _transitionToState(PlungerState::IDLE); + break; + } + _lastJoystickDirection = currentJoystickDir; + return E_OK; +} + +short Plunger::info() { + L_INFO("--- Plunger Info (ID: %d, Name: %s) ---", id, name.c_str()); + L_INFO("State: %d, LastJoy: %d, CurrentJoy: %d", + static_cast(m_state.getValue()), + static_cast(_lastJoystickDirection), + static_cast(_joystick->getValue())); + + L_INFO("SpeedPOT: %d, TorquePOT: %d", _currentSpeedPotValue, + _currentTorquePotValue); + uint16_t freq = 0; + uint16_t current = 0; + bool freqValid = _vfd->getFrequency(freq); + bool currentOk = _vfd->getOutputCurrent(current); + + L_INFO("VFD: Running=%s, Fault=%s, FreqSet=%d Hz, OutputCurrent=%d", + _vfd->isRunning() ? "YES" : "NO", _vfd->hasFault() ? "YES" : "NO", + freqValid ? (static_cast(freq)) : -1, + currentOk ? static_cast(current) : -1); + + L_INFO("--- Plunger Settings ---"); + _settings.print(); + + return E_OK; +} + +short Plunger::debug() { return info(); } + +short Plunger::cmd_plunge() { + if (!_autoModeEnabled) { + return 1; + } + if (m_state.getValue() == static_cast(PlungerState::IDLE)) { + _vfdStartForward(static_cast(_calculatedPlungingSpeedHz)); + _transitionToState(PlungerState::PLUNGING_AUTO); return E_OK; + } else { + return 1; + } } -short Plunger::info() -{ - L_INFO("--- Plunger Info (ID: %d, Name: %s) ---", id, name.c_str()); - L_INFO("State: %d, LastJoy: %d, CurrentJoy: %d", - static_cast(m_state.getValue()), - static_cast(_lastJoystickDirection), - static_cast(_joystick->getValue())); - - L_INFO("SpeedPOT: %d, TorquePOT: %d", - _currentSpeedPotValue, _currentTorquePotValue); - uint16_t freq = 0; - uint16_t current = 0; - bool freqValid = _vfd->getFrequency(freq); - bool currentOk = _vfd->getOutputCurrent(current); - - L_INFO("VFD: Running=%s, Fault=%s, FreqSet=%d Hz, OutputCurrent=%d", - _vfd->isRunning() ? "YES" : "NO", - _vfd->hasFault() ? "YES" : "NO", - freqValid ? (static_cast(freq)) : -1, - currentOk ? static_cast(current) : -1); - - L_INFO("--- Plunger Settings ---"); - _settings.print(); - +short Plunger::cmd_home() { + if (!_autoModeEnabled) { + return 1; + } + if (m_state.getValue() == static_cast(PlungerState::IDLE)) { + _vfdStartReverse(static_cast(_settings.speedSlowHz * 100.0f)); + _transitionToState(PlungerState::HOMING_AUTO); return E_OK; + } else { + return 1; + } } -short Plunger::debug() -{ - return info(); -} - -short Plunger::cmd_plunge() -{ - if (!_autoModeEnabled) - { - return 1; - } - if (m_state.getValue() == static_cast(PlungerState::IDLE)) - { - _vfdStartForward(static_cast(_calculatedPlungingSpeedHz)); - _transitionToState(PlungerState::PLUNGING_AUTO); - return E_OK; - } - else - { - return 1; - } -} - -short Plunger::cmd_home() -{ - if (!_autoModeEnabled) - { - return 1; - } - if (m_state.getValue() == static_cast(PlungerState::IDLE)) - { - _vfdStartReverse(static_cast(_settings.speedSlowHz * 100.0f)); - _transitionToState(PlungerState::HOMING_AUTO); - return E_OK; - } - else - { - return 1; - } -} - -short Plunger::cmd_stop() -{ - _transitionToState(PlungerState::STOPPING); - _vfdStop(); - _vfdResetJam(); - return E_OK; +short Plunger::cmd_stop() { + _transitionToState(PlungerState::STOPPING); + _vfdStop(); + _vfdResetJam(); + return E_OK; } // Definition for cmd_fill -short Plunger::cmd_fill() -{ - if (m_state.getValue() != static_cast(PlungerState::IDLE)) - { - Log.warningln("[%s] cmd_fill ignored. Not IDLE. Current State: %s", - name.c_str(), _plungerStateToString(static_cast(m_state.getValue()))); - return 1; - } - if (!_autoModeEnabled) - { - Log.warningln("[%s] cmd_fill ignored. Auto mode is disabled.", name.c_str()); - return 1; - } - L_INFO("[%s] cmd_fill: Initiating FILLING sequence.", name.c_str()); - _currentFillState = FillState::PLUNGING; - _joystickReleasedSinceAutoStart = false; - _vfdStartForward(static_cast(_settings.speedFillPlungeHz * 100.0f)); - _operationStartTimeMs = millis(); - _currentMaxOperationTimeMs = _settings.defaultMaxOperationDurationMs; - _transitionToState(PlungerState::FILLING); - return E_OK; +short Plunger::cmd_fill() { + if (m_state.getValue() != static_cast(PlungerState::IDLE)) { + Log.warningln( + "[%s] cmd_fill ignored. Not IDLE. Current State: %s", name.c_str(), + _plungerStateToString(static_cast(m_state.getValue()))); + return 1; + } + if (!_autoModeEnabled) { + Log.warningln("[%s] cmd_fill ignored. Auto mode is disabled.", + name.c_str()); + return 1; + } + L_INFO("[%s] cmd_fill: Initiating FILLING sequence.", name.c_str()); + _currentFillState = FillState::PLUNGING; + _joystickReleasedSinceAutoStart = false; + _vfdStartForward(static_cast(_settings.speedFillPlungeHz * 100.0f)); + _operationStartTimeMs = millis(); + _currentMaxOperationTimeMs = _settings.defaultMaxOperationDurationMs; + _transitionToState(PlungerState::FILLING); + return E_OK; } -short Plunger::cmd_save_settings() -{ - if (_settings.save()) - { - return E_OK; - } - else - { - L_ERROR("[%s] Failed to save settings via command.", name.c_str()); - return 1; - } +short Plunger::cmd_save_settings() { + if (_settings.save()) { + return E_OK; + } else { + L_ERROR("[%s] Failed to save settings via command.", name.c_str()); + return 1; + } } // Definition for reset -short Plunger::reset() -{ - //_vfdStop(); - //_vfdResetJam(); - return this->init(); +short Plunger::reset() { + //_vfdStop(); + //_vfdResetJam(); + return this->init(); } -void Plunger::setAutoModeEnabled(bool enabled) -{ - if (_autoModeEnabled != enabled) { - _autoModeEnabled = enabled; - _fireEvent(enabled ? PlungerEvent::AUTO_MODE_ENABLED : PlungerEvent::AUTO_MODE_DISABLED); - } -} -bool Plunger::isAutoModeEnabled() const -{ - return _autoModeEnabled; +void Plunger::setAutoModeEnabled(bool enabled) { + if (_autoModeEnabled != enabled) { + _autoModeEnabled = enabled; + _fireEvent(enabled ? PlungerEvent::AUTO_MODE_ENABLED + : PlungerEvent::AUTO_MODE_DISABLED); + } } +bool Plunger::isAutoModeEnabled() const { return _autoModeEnabled; } // Definition for cmd_enableAutoMode -short Plunger::cmd_enableAutoMode() -{ - setAutoModeEnabled(true); - return E_OK; +short Plunger::cmd_enableAutoMode() { + setAutoModeEnabled(true); + return E_OK; } // Definition for cmd_disableAutoMode -short Plunger::cmd_disableAutoMode() -{ - setAutoModeEnabled(false); - return E_OK; +short Plunger::cmd_disableAutoMode() { + setAutoModeEnabled(false); + return E_OK; } // Method to serialize current settings to a JsonDocument -void Plunger::getSettingsJson(JsonDocument& doc) const { - _settings.toJson(doc); // Utilize the existing method in PlungerSettings +void Plunger::getSettingsJson(JsonDocument &doc) const { + _settings.toJson(doc); // Utilize the existing method in PlungerSettings } // Method to update settings from a JsonObject and then save them -bool Plunger::updateSettingsFromJson(const JsonObject& json) { - if (!_settings.fromJson(json)) { // Utilize the existing method in PlungerSettings - L_ERROR("[%s] Failed to update settings from JSON in updateSettingsFromJson.", name.c_str()); - return false; - } - if (!_settings.save()) { - L_ERROR("[%s] Failed to save updated settings in updateSettingsFromJson.", name.c_str()); - return false; - } - _recordedPlungeDurationMs = _settings.replayDurationMs; - _updatePotValues(); - - L_INFO("[%s] Settings updated via web API:", name.c_str()); - _settings.print(); - - return true; +bool Plunger::updateSettingsFromJson(const JsonObject &json) { + if (!_settings.fromJson( + json)) { // Utilize the existing method in PlungerSettings + L_ERROR( + "[%s] Failed to update settings from JSON in updateSettingsFromJson.", + name.c_str()); + return false; + } + if (!_settings.save()) { + L_ERROR("[%s] Failed to save updated settings in updateSettingsFromJson.", + name.c_str()); + return false; + } + _recordedPlungeDurationMs = _settings.replayDurationMs; + _updatePotValues(); + + L_INFO("[%s] Settings updated via web API:", name.c_str()); + _settings.print(); + + return true; } -short Plunger::mb_tcp_write(MB_Registers *reg, short networkValue) -{ - short result = NetworkComponent::mb_tcp_write(reg, networkValue); - if (result != E_NOT_IMPLEMENTED) { - return result; - } - uint16_t address = reg->startAddress; - if (address == (_baseAddress + MB_OFS_COMMAND)) - { - E_PlungerCommand cmd = static_cast(networkValue); - - short cmdResult = E_OK; - switch (cmd) - { - case E_PlungerCommand::CMD_HOME: - cmdResult = this->cmd_home(); - break; - case E_PlungerCommand::CMD_PLUNGE: - cmdResult = this->cmd_plunge(); - break; - case E_PlungerCommand::CMD_STOP: - cmdResult = this->cmd_stop(); - break; - case E_PlungerCommand::CMD_INFO: - cmdResult = this->info(); - break; - case E_PlungerCommand::CMD_FILL: - cmdResult = this->cmd_fill(); - break; - case E_PlungerCommand::CMD_REPLAY: - cmdResult = this->cmd_replay(); - break; - case E_PlungerCommand::NO_COMMAND: - L_INFO("[%s] Modbus NO_COMMAND received.", name.c_str()); - break; - default: - Log.warningln("[%s] Unknown Modbus command received: %d", name.c_str(), networkValue); - cmdResult = E_INVALID_PARAMETER; - break; - } +short Plunger::mb_tcp_write(MB_Registers *reg, short networkValue) { + short result = NetworkComponent::mb_tcp_write(reg, networkValue); + if (result != E_NOT_IMPLEMENTED) { + return result; + } + uint16_t address = reg->startAddress; + if (address == (_baseAddress + MB_OFS_COMMAND)) { + E_PlungerCommand cmd = static_cast(networkValue); - m_command.update(networkValue); - - return cmdResult; + short cmdResult = E_OK; + switch (cmd) { + case E_PlungerCommand::CMD_HOME: + cmdResult = this->cmd_home(); + break; + case E_PlungerCommand::CMD_PLUNGE: + cmdResult = this->cmd_plunge(); + break; + case E_PlungerCommand::CMD_STOP: + cmdResult = this->cmd_stop(); + break; + case E_PlungerCommand::CMD_INFO: + cmdResult = this->info(); + break; + case E_PlungerCommand::CMD_FILL: + cmdResult = this->cmd_fill(); + break; + case E_PlungerCommand::CMD_REPLAY: + cmdResult = this->cmd_replay(); + break; + case E_PlungerCommand::NO_COMMAND: + L_INFO("[%s] Modbus NO_COMMAND received.", name.c_str()); + break; + default: + Log.warningln("[%s] Unknown Modbus command received: %d", name.c_str(), + networkValue); + cmdResult = E_INVALID_PARAMETER; + break; } - - return E_INVALID_PARAMETER; + + m_command.update(networkValue); + + return cmdResult; + } + + return E_INVALID_PARAMETER; } -short Plunger::mb_tcp_read(MB_Registers *reg) -{ - short result = NetworkComponent::mb_tcp_read(reg); - if (result != E_NOT_IMPLEMENTED) { - return result; - } - - return E_INVALID_PARAMETER; +short Plunger::mb_tcp_read(MB_Registers *reg) { + short result = NetworkComponent::mb_tcp_read(reg); + if (result != E_NOT_IMPLEMENTED) { + return result; + } + + return E_INVALID_PARAMETER; } -short Plunger::cmd_load_default_settings() -{ - if (loadDefaultSettings()) { - return E_OK; - } else { - L_ERROR("[%s] Failed to load or apply default settings via command.", name.c_str()); - return 1; - } -} - -bool Plunger::loadDefaultSettings(const char* defaultPath, const char* operationalPath) { - PlungerSettings tempSettings = _settings; - if (!tempSettings.load(defaultPath)) { - L_ERROR("[%s] Failed to load settings from default file: %s", name.c_str(), defaultPath); - return false; - } - _settings = tempSettings; - if (!_settings.save(operationalPath)) { - L_ERROR("[%s] Failed to save the loaded default settings to operational path: %s", name.c_str(), operationalPath); - return false; - } - _recordedPlungeDurationMs = _settings.replayDurationMs; - _updatePotValues(); - return true; -} - -short Plunger::cmd_replay() -{ - if (m_state.getValue() != static_cast(PlungerState::IDLE)) - { - Log.warningln("[%s] cmd_replay ignored. Not IDLE. Current State: %s", name.c_str(), _plungerStateToString(static_cast(m_state.getValue()))); - return 1; - } - if (_recordedPlungeDurationMs <= 50) { // Same check as in _handleReplayState - Log.warningln("[%s] cmd_replay ignored. Invalid or zero replay duration (%lu ms).", name.c_str(), _recordedPlungeDurationMs); - return 1; - } - if (!_autoModeEnabled) // Consider if replay should be subject to autoModeEnabled - { - Log.warningln("[%s] cmd_replay ignored. Auto mode is disabled.", name.c_str()); - return 1; - } - _transitionToState(PlungerState::REPLAY); +short Plunger::cmd_load_default_settings() { + if (loadDefaultSettings()) { return E_OK; + } else { + L_ERROR("[%s] Failed to load or apply default settings via command.", + name.c_str()); + return 1; + } } -void Plunger::_fireEvent(PlungerEvent event, int16_t val) -{ - if (_eventsDelegate) - { - _eventsDelegate->onPlungerEvent(this, event, val); - } +bool Plunger::loadDefaultSettings(const char *defaultPath, + const char *operationalPath) { + PlungerSettings tempSettings = _settings; + if (!tempSettings.load(defaultPath)) { + L_ERROR("[%s] Failed to load settings from default file: %s", name.c_str(), + defaultPath); + return false; + } + _settings = tempSettings; + if (!_settings.save(operationalPath)) { + L_ERROR("[%s] Failed to save the loaded default settings to operational " + "path: %s", + name.c_str(), operationalPath); + return false; + } + _recordedPlungeDurationMs = _settings.replayDurationMs; + _updatePotValues(); + return true; +} + +short Plunger::cmd_replay() { + if (m_state.getValue() != static_cast(PlungerState::IDLE)) { + Log.warningln( + "[%s] cmd_replay ignored. Not IDLE. Current State: %s", name.c_str(), + _plungerStateToString(static_cast(m_state.getValue()))); + return 1; + } + if (_recordedPlungeDurationMs <= 50) { // Same check as in _handleReplayState + Log.warningln( + "[%s] cmd_replay ignored. Invalid or zero replay duration (%lu ms).", + name.c_str(), _recordedPlungeDurationMs); + return 1; + } + if (!_autoModeEnabled) // Consider if replay should be subject to + // autoModeEnabled + { + Log.warningln("[%s] cmd_replay ignored. Auto mode is disabled.", + name.c_str()); + return 1; + } + _transitionToState(PlungerState::REPLAY); + return E_OK; +} + +void Plunger::_fireEvent(PlungerEvent event, int16_t val) { + if (_eventsDelegate) { + _eventsDelegate->onPlungerEvent(this, event, val); + } } diff --git a/lib/polymech-base/src/components/RestServer.cpp b/lib/polymech-base/src/components/RestServer.cpp index 191d6d6b..b4e781e3 100644 --- a/lib/polymech-base/src/components/RestServer.cpp +++ b/lib/polymech-base/src/components/RestServer.cpp @@ -701,7 +701,7 @@ void RESTServer::getSystemInfoHandler(AsyncWebServerRequest *request) doc["freeHeapKb"] = ESP.getFreeHeap() / 1024; doc["maxFreeBlockKb"] = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT) / 1024; doc["fragmentationPercent"] = static_cast(owner)->getHeapFragmentation(); - doc["cpuTicks"] = (uint32_t)esp_cpu_get_ccount(); + doc["cpuTicks"] = (uint32_t)esp_cpu_get_cycle_count(); doc["loopDurationMs"] = owner->getLoopDurationUs(); // --- Calculate Average CPU Load --- float cpuLoadPercent = -1.0; // Default value if stats are unavailable @@ -1618,7 +1618,7 @@ void RESTServer::handleWebSocketMessage(AsyncWebSocketClient *client, void *arg, responseDoc["freeHeapKb"] = ESP.getFreeHeap() / 1024.0; responseDoc["maxFreeBlockKb"] = heap_caps_get_largest_free_block(MALLOC_CAP_DEFAULT) / 1024.0; responseDoc["fragmentationPercent"] = static_cast(owner)->getHeapFragmentation(); - responseDoc["cpuTicks"] = (uint32_t)esp_cpu_get_ccount(); + responseDoc["cpuTicks"] = (uint32_t)esp_cpu_get_cycle_count(); responseDoc["loopDurationMs"] = owner->getLoopDurationUs(); // --- Calculate Average CPU Load --- float cpuLoadPercent = -1.0; // Default value if stats are unavailable diff --git a/lib/polymech-base/src/esp32_compat.h b/lib/polymech-base/src/esp32_compat.h index 54bcdec1..5d895d1c 100644 --- a/lib/polymech-base/src/esp32_compat.h +++ b/lib/polymech-base/src/esp32_compat.h @@ -2,24 +2,32 @@ #define ESP32_COMPAT_H #include +#if __has_include() +#include +#endif // Include esp_cpu.h for all ESP32 variants -#if defined(ESP32) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C3) || defined(ESP32P4) +#if defined(ESP32) || defined(ESP32S2) || defined(ESP32S3) || defined(ESP32C3) || defined(ESP32P4) || defined(CONFIG_IDF_TARGET_ESP32P4) #include #endif -// ESP-IDF v5.x and later renamed esp_cpu_get_ccount to esp_cpu_get_cycle_count. -// For compatibility, we provide esp_cpu_get_cycle_count if it doesn't exist +// Include esp_idf_version.h for version checking +#if __has_include() +#include +#endif + +// ESP-IDF v5.x renamed esp_cpu_get_ccount to esp_cpu_get_cycle_count. +// We use esp_cpu_get_cycle_count in the code. +// For legacy versions (IDF < 5.0), we map it back to esp_cpu_get_ccount. +#if defined(ESP_IDF_VERSION) && ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0) #ifndef esp_cpu_get_cycle_count #define esp_cpu_get_cycle_count esp_cpu_get_ccount #endif +#endif // ESP32-P4 compatibility layer #ifdef CONFIG_IDF_TARGET_ESP32P4 -// ESP32-P4 specific compatibility -#ifndef esp_cpu_get_cycle_count -#define esp_cpu_get_cycle_count esp_cpu_get_ccount -#endif +// P4 Stub if needed (currently using native esp_cpu_get_cycle_count) #endif // ArduinoLog compatibility diff --git a/package.json b/package.json index bc1c3f85..ccd5c022 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,10 @@ "build": "pio run -e waveshare", "build:p4": "pio run -e esp32-p4-evboard", "upload:p4": "pio run -e esp32-p4-evboard -t upload", - "monitor:p4": "pio device monitor --filter esp32_exception_decoder -e esp32-p4-evboard", + "monitor:p4": "pio device monitor --filter esp32_exception_decoder -e esp32-p4-evboard -b 115200", + "update:p4": "npm run build:p4 && npm run upload:p4", + "uploadfs:p4": "pio run -e esp32-p4-evboard -t uploadfs", + "build:p4:fs": "pio run -e esp32-p4-evboard -t uploadfs", "build:dev": "cross-env DEV_IP_OVERRIDE_STA_IP=192.168.1.251 pio run -e waveshare", "update:dev": "npm run build:dev && npm run upload", "idf:build": "bash scripts/idf-build.sh", @@ -52,6 +55,7 @@ "web:build-dist": "cd ../web/packages/modbus-ui && npm run build", "web:uploadfs": "pio run -t uploadfs -e waveshare", "web:uploadfs-release": "pio run -t uploadfs -e waveshare-release", + "web:uploadfs:p4": "pio run -t uploadfs -e esp32-p4-evboard", "web:clean": "rm -rf data/*", "web:update": "npm run web:clean && npm run web:build-dist && npm run web:sync && npm run web:uploadfs", "web:update-release": "npm run web:clean && npm run web:build-dist && npm run web:sync && npm run web:uploadfs-release", diff --git a/platform.ini.md b/platform.ini.md new file mode 100644 index 00000000..a6324cbf --- /dev/null +++ b/platform.ini.md @@ -0,0 +1,6 @@ +-DCONFIG_ASYNC_TCP_STACK_SIZE=1024 +-DCONFIG_ASYNC_TCP_QUEUE_SIZE=4 +-DCONFIG_ASYNC_TCP_PRIORITY=2 +-DCONFIG_ASYNC_TCP_MAX_ACK_TIME=500 +-DCONFIG_ASYNC_TCP_RUNNING_CORE=1 +-DASYNCWEBSERVER_USE_CHUNK_INFLIGHT=0 diff --git a/platformio-p4.ini b/platformio-p4.ini new file mode 100644 index 00000000..5fa2f11b --- /dev/null +++ b/platformio-p4.ini @@ -0,0 +1,117 @@ +;-D DEV_IP_OVERRIDE_STA_IP=${sysenv.DEV_IP_OVERRIDE_STA_IP} + +[common] +;extra_scripts = scripts/LittleFSBuilder.py +extra_scripts = scripts/strip_elf.py +lib_ignore = WebServer +upload_protocol = esptool +debug_init_break = tbreak setup +monitor_filters = esp32_exception_decoder +board_upload.speed = 115200 +board_build.mcu = esp32s3 +board_build.variant = esp32s3 +board_build.filesystem = littlefs + +[env:waveshare_base] +extends = common +debug_tool = esp-builtin +platform = espressif32 +board = esp32-s3-devkitc-1 +framework = arduino +monitor_filters = esp32_exception_decoder +board_build.flash_mode = dio +board_build.prsam_type = opi +build_flags = + -std=gnu++17 + -I src + -I lib/polymech-base/src +board_build.extra_flags = + -DBOARD_HAS_PSRAM + -DARDUINO_ESP32S3_DEV + -DARDUINO_USB_MODE=1 + -DWS_MAX_QUEUED_MESSAGES=64 + -DWS_SEND_QUEUE_SIZE=64 + -DWS_MIN_SEND_INTERVAL_MS=10 + -DPROJECT_DIR="\"${PROJECT_DIR}\"" +lib_deps = + https://github.com/eModbus/eModbus.git + https://github.com/janelia-arduino/Vector.git + https://github.com/thijse/Arduino-Log.git + https://github.com/bblanchon/ArduinoJson.git + https://github.com/ESP32Async/ESPAsyncWebServer.git + +[env:waveshare] +monitor_filters = esp32_exception_decoder +extends = env:waveshare_base +lib_deps = + ${env:waveshare_base.lib_deps} +board_build.extra_flags = + ${env:waveshare_base.board_build.extra_flags} + -DARDUINO_USB_CDC_ON_BOOT=1 + -DLOG_LEVEL=LOG_LEVEL_INFO + -DENABLE_LOGGING + -DWS_MAX_QUEUED_MESSAGES=16 + -DWS_SEND_QUEUE_SIZE=16 + -DWS_MIN_SEND_INTERVAL_MS=80 + +[env:waveshare-release] +monitor_filters = esp32_exception_decoder +build_type = release +extends = env:waveshare_base +board_build.extra_flags = + ${env:waveshare_base.board_build.extra_flags} + -DARDUINO_USB_CDC_ON_BOOT=0 + -DLOG_LEVEL=0 + -DDISABLE_LOGGING + -DPIO_DISABLE_LOGGER + -DCONFIG_LOG_DEFAULT_LEVEL=0 + -DCONFIG_LOG_MAXIMUM_LEVEL=0 + -DLOG_LOCAL_LEVEL=0 + -Wl,--gc-sections +lib_ignore = WebServer +lib_deps = + ${env:waveshare_base.lib_deps} + +[env:waveshare-release-debug] +monitor_filters = esp32_exception_decoder +build_type = release +extends = env:waveshare_base +board_build.extra_flags = + ${env:waveshare_base.board_build.extra_flags} + -DARDUINO_USB_CDC_ON_BOOT=0 + -DLOG_LEVEL=LOG_LEVEL_INFO + -DENABLE_LOGGING + -Wl,--gc-sections +lib_ignore = WebServer +lib_deps = + ${env:waveshare_base.lib_deps} + + +[env:esp32-p4-evboard] +extra_scripts = scripts/LittleFSBuilder.py +lib_ignore = WebServer +upload_protocol = esptool +debug_init_break = tbreak setup +monitor_filters = esp32_exception_decoder +board_upload.speed = 115200 +board_build.filesystem = littlefs +platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip +board = esp32-p4-evboard +framework = arduino +monitor_speed = 115200 +lib_deps = + ${env:waveshare_base.lib_deps} +build_flags = + -DARDUINO_USB_MODE=1 + -DARDUINO_USB_CDC_ON_BOOT=0 + -DLOG_LEVEL=LOG_LEVEL_INFO + -DENABLE_LOGGING + -DWS_MAX_QUEUED_MESSAGES=16 + -DWS_SEND_QUEUE_SIZE=16 + -DWS_MIN_SEND_INTERVAL_MS=80 + -DENABLE_P4_MIN + -std=gnu++17 + -I src + -I lib/polymech-base/src + -DPROJECT_DIR="\"${PROJECT_DIR}\"" + diff --git a/platformio.ini b/platformio.ini index 44ce64ba..970ab541 100644 --- a/platformio.ini +++ b/platformio.ini @@ -85,25 +85,3 @@ board_build.extra_flags = lib_ignore = WebServer lib_deps = ${env:waveshare_base.lib_deps} - - -;[env:esp32-p4-evboard] -;extra_scripts = scripts/LittleFSBuilder.py -;lib_ignore = WebServer -;upload_protocol = esptool -;debug_init_break = tbreak setup -;monitor_filters = esp32_exception_decoder -;board_upload.speed = 115200 -;board_build.filesystem = littlefs -;platform = https://github.com/pioarduino/platform-espressif32/releases/download/55.03.30-2/platform-espressif32.zip -;board = esp32-p4-evboard -;framework = arduino -;monitor_speed = 115200 -;lib_deps = -; ${env:waveshare_base.lib_deps} -;build_flags = -; -DARDUINO_USB_MODE=1 -; -DARDUINO_USB_CDC_ON_BOOT=1 -; -std=gnu++17 -; -I src -; -I lib/polymech-base/src diff --git a/scripts/bundle-mesint.sh b/scripts/bundle-mesint.sh index ebdda3c4..3f834705 100644 --- a/scripts/bundle-mesint.sh +++ b/scripts/bundle-mesint.sh @@ -2,6 +2,7 @@ sh scripts/create-bundle.sh sh scripts/build-deps.sh cp ./clients/mesint/master/* ./dist/data/ + osr-sync zip --source=./dist/ --target=./clients/mesint/master.zip --cwd=./dist --profile=./sync-clients.json --verbose --debug # sh scripts/create-bundle.sh diff --git a/scripts/bundle-ph.sh b/scripts/bundle-ph.sh index 1eddf4c9..d9cbe0a2 100644 --- a/scripts/bundle-ph.sh +++ b/scripts/bundle-ph.sh @@ -1,5 +1,6 @@ sh scripts/create-bundle.sh +sh scripts/build-deps.sh + cp ./clients/plastichub/master/* ./dist/data/ + osr-sync zip --source=./dist/ --target=./clients/plastichub/master.zip --cwd=./dist --profile=./sync-clients.json --verbose --debug - - diff --git a/scripts/bundle-plastiq.sh b/scripts/bundle-plastiq.sh index ff8954f2..2791f16e 100644 --- a/scripts/bundle-plastiq.sh +++ b/scripts/bundle-plastiq.sh @@ -1,9 +1,9 @@ sh scripts/create-bundle.sh +sh scripts/build-deps.sh + cp ./clients/plastiq/master/* ./dist/data/ osr-sync zip --source=./dist/ --target=./clients/plastiq/master.zip --cwd=./dist --profile=./sync-clients.json --verbose --debug -sh scripts/create-bundle.sh cp ./clients/plastiq/slave/* ./dist/data/ osr-sync zip --source=./dist/ --target=./clients/plastiq/slave.zip --cwd=./dist --profile=./sync-clients.json --verbose --debug - diff --git a/scripts/deploy-plastiq.sh b/scripts/deploy-plastiq.sh index de96cabf..cca160df 100644 --- a/scripts/deploy-plastiq.sh +++ b/scripts/deploy-plastiq.sh @@ -4,7 +4,7 @@ # Define local and remote paths LOCAL_DIR="./clients/plastiq" -GDRIVE_DIR="polymech.info:/httpdocs/plastiq" +GDRIVE_DIR="pm-site:/plastiq" rclone copy "${LOCAL_DIR}/" "${GDRIVE_DIR}" --progress --transfers 4 --include "*.zip" --verbose diff --git a/scripts/upload_littlefs.py b/scripts/upload_littlefs.py index 63887da0..15a194c8 100644 --- a/scripts/upload_littlefs.py +++ b/scripts/upload_littlefs.py @@ -241,9 +241,9 @@ def main(): # pm-fw-cli.exe dump --targethost=http:// --directory=./backup backup_args = ["dump", f"--targethost=http://{target_host_ip}", "--directory=./backup"] if not run_pm_cli(backup_args): - print("❌ Backup failed. Aborting update.") - return 1 - print("✅ Backup completed successfully.") + print("🔶 Warning: Backup failed. Proceeding with update anyway...") + else: + print("✅ Backup completed successfully.") # --- 2. FIRMWARE/FS UPDATE --- print("\n=== PHASE 2: FIRMWARE UPDATE ===") @@ -282,12 +282,7 @@ def main(): # pm-fw-cli.exe restore --directory=./backup --targethost=http:// restore_args = ["restore", "--directory=./backup", f"--targethost=http://{target_host_ip}"] if not run_pm_cli(restore_args): - print("❌ Restore failed.") - # We don't abort reset here, usually we still want to reset? - # But if restore failed, maybe we should stop. - # User said: "assume the worst :)", implying logs will help. - # But if restore fails, maybe we shouldn't reset to avoid bootlooping on bad config? - # For now, we'll try to proceed to Reset because the firmware was just updated. + print("🔶 Warning: Restore failed. Proceeding with reset anyway...") else: print("✅ Restore completed successfully.") diff --git a/scripts/web.sh b/scripts/web.sh index c622a9bf..db8e4093 100644 --- a/scripts/web.sh +++ b/scripts/web.sh @@ -2,7 +2,8 @@ cp -r ./config/* ./data/ rm ./data/assets/*.js rm ./data/assets/*.css -pm-config patch-app --src=./data/index.html --dst ./data/index.html +pm-fw-cli patch-app --src=./data/index.html --dst ./data/index.html + #rm ./data/assets/*.gz #rm ./data/assets/*.woff #rm ./data/assets/*.woff2 diff --git a/src/PHApp.cpp b/src/PHApp.cpp index 453e7361..5319e770 100644 --- a/src/PHApp.cpp +++ b/src/PHApp.cpp @@ -1,18 +1,18 @@ #include -#include +#include #include #include -#include +#include #include "./PHApp.h" -#include "./config.h" #include "./config-modbus.h" -#include "esp32_compat.h" +#include "./config.h" #include "Settings.h" +#include "esp32_compat.h" #include -#include #include +#include #ifdef ENABLE_MODBUS_TCP #include @@ -23,31 +23,30 @@ #include #if defined(ENABLE_AMPERAGE_BUDGET_MANAGER) -void PHApp_onWarmupComplete(Component *owner) -{ +void PHApp_onWarmupComplete(Component *owner) { PHApp *app = static_cast(owner); - if (app) - { + if (app) { bool wasInitializing = false; #ifdef ENABLE_PROFILE_TEMPERATURE - for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; i++) - { - if (app->tempProfiles[i] != nullptr && app->tempProfiles[i]->getCurrentStatus() == PlotStatus::INITIALIZING) - { + for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; i++) { + if (app->tempProfiles[i] != nullptr && + app->tempProfiles[i]->getCurrentStatus() == + PlotStatus::INITIALIZING) { wasInitializing = true; break; } } #endif - if (wasInitializing) - { - // TODO: Implement any logic that should occur when the warmup is complete. - LS_INFO("PHApp received warmup complete notification from AmperageBudgetManager."); + if (wasInitializing) { + // TODO: Implement any logic that should occur when the warmup is + // complete. + LS_INFO("PHApp received warmup complete notification from " + "AmperageBudgetManager."); #ifdef ENABLE_FEEDBACK_BUZZER - if (app->feedbackBuzzer_0) - { - app->feedbackBuzzer_0->setMode(FeedbackBuzzer::E_BuzzerMode::MODE_FAST_BLINK, 3000); + if (app->feedbackBuzzer_0) { + app->feedbackBuzzer_0->setMode( + FeedbackBuzzer::E_BuzzerMode::MODE_FAST_BLINK, 3000); } #endif } @@ -91,56 +90,60 @@ ModbusServerTCPasync mb; // // Factory : Instances // -#define ADD_RELAY(relayNum, relayPin, relayKey, relayAddr) \ - relay_##relayNum = new Relay(this, relayPin, relayKey, relayAddr); \ +#define ADD_RELAY(relayNum, relayPin, relayKey, relayAddr) \ + relay_##relayNum = new Relay(this, relayPin, relayKey, relayAddr); \ components.push_back(relay_##relayNum); #ifdef ENABLE_SOLENOID_0 -#define ADD_SOLENOID(solenoidNum, solenoidPin, solenoidKey, solenoidAddr) \ - solenoid_##solenoidNum = new Solenoid(this, solenoidPin, solenoidKey, solenoidAddr); \ +#define ADD_SOLENOID(solenoidNum, solenoidPin, solenoidKey, solenoidAddr) \ + solenoid_##solenoidNum = \ + new Solenoid(this, solenoidPin, solenoidKey, solenoidAddr); \ components.push_back(solenoid_##solenoidNum); #endif -#define ADD_POT(potNum, potPin, potKey, potAddr, ...) \ - pot_##potNum = new POT(this, potPin, potKey, potAddr, ##__VA_ARGS__); \ +#define ADD_POT(potNum, potPin, potKey, potAddr, ...) \ + pot_##potNum = new POT(this, potPin, potKey, potAddr, ##__VA_ARGS__); \ components.push_back(pot_##potNum); -#define ADD_POS3ANALOG(posNum, switchPin1, switchPin2, switchKey, switchAddr) \ - pos3Analog_##posNum = new Pos3Analog(this, switchPin1, switchPin2, switchKey, switchAddr); \ +#define ADD_POS3ANALOG(posNum, switchPin1, switchPin2, switchKey, switchAddr) \ + pos3Analog_##posNum = \ + new Pos3Analog(this, switchPin1, switchPin2, switchKey, switchAddr); \ components.push_back(pos3Analog_##posNum); #ifdef ENABLE_PID -#define ADD_PID(pidNum, nameStr, doPin, csPin, clkPin, outPin, key) \ - pidController_##pidNum = new PIDController(key, nameStr, doPin, csPin, clkPin, outPin); \ +#define ADD_PID(pidNum, nameStr, doPin, csPin, clkPin, outPin, key) \ + pidController_##pidNum = \ + new PIDController(key, nameStr, doPin, csPin, clkPin, outPin); \ components.push_back(pidController_##pidNum); #endif Logger *g_logger = nullptr; -void PHApp::printRegisters() -{ +void PHApp::printRegisters() { L_VERBOSE(F("--- Entering PHApp::printRegisters ---")); #if ENABLED(HAS_MODBUS_REGISTER_DESCRIPTIONS) Log.setShowLevel(false); - Serial.print("| Name | ID | Address | RW | Function Code | Number Addresses |Register Description| \n"); + Serial.print("| Name | ID | Address | RW | Function Code | Number " + "Addresses |Register Description| \n"); Serial.print("|------|----------|----|----|----|----|-------|\n"); short size = components.size(); L_VERBOSE(F("PHApp::printRegisters - Processing %d components..."), size); - for (int i = 0; i < size; i++) - { + for (int i = 0; i < size; i++) { Component *component = components[i]; - if (!component) - { + if (!component) { L_ERROR(F("PHApp::printRegisters - Found NULL component at index %d"), i); continue; } - L_VERBOSE(F("PHApp::printRegisters - Component %d: ID=%d, Name=%s"), i, component->id, component->name.c_str()); - // if (!(component->nFlags & 1 << OBJECT_NET_CAPS::E_NCAPS_MODBUS)) // <-- Modbus flag check might be different now + L_VERBOSE(F("PHApp::printRegisters - Component %d: ID=%d, Name=%s"), i, + component->id, component->name.c_str()); + // if (!(component->nFlags & 1 << OBJECT_NET_CAPS::E_NCAPS_MODBUS)) // <-- + // Modbus flag check might be different now // { // continue; // } - // Log.verbose("| %s | %d | %d | %s | %d | %d | %s |\n", // <-- Calls to removed ModbusGateway methods + // Log.verbose("| %s | %d | %d | %s | %d | %d | %s |\n", // <-- Calls to + // removed ModbusGateway methods // component->name.c_str(), // component->id, // component->getAddress(), @@ -149,59 +152,51 @@ void PHApp::printRegisters() // component->getNumberAddresses(), // component->getRegisterDescription().c_str()); Log.verbose("| %s | %d | - | - | - | - | - |\n", // <-- Simplified output - component->name.c_str(), - component->id); + component->name.c_str(), component->id); } Log.setShowLevel(true); #endif L_VERBOSE(F("--- Exiting PHApp::printRegisters ---")); } -short PHApp::reset(short val0, short val1) -{ +short PHApp::reset(short val0, short val1) { _state = APP_STATE::RESET; _error = E_OK; -#if defined(ESP32) || defined(ESP8266) // Use ESP.restart() for ESP32 and ESP8266 +#if defined(ESP32) || \ + defined(ESP8266) // Use ESP.restart() for ESP32 and ESP8266 ESP.restart(); #else return E_NOT_IMPLEMENTED; #endif return E_OK; } -short PHApp::list(short val0, short val1) -{ +short PHApp::list(short val0, short val1) { uchar s = components.size(); - for (uchar i = 0; i < s; i++) - { + for (uchar i = 0; i < s; i++) { Component *component = components[i]; - if (component) - { - L_VERBOSE("PHApp::list - %d | %s (ID: %d)", i, component->name.c_str(), component->id); - } - else - { + if (component) { + L_VERBOSE("PHApp::list - %d | %s (ID: %d)", i, component->name.c_str(), + component->id); + } else { Log.warningln("PHApp::list - NULL component at index %d", i); } } return E_OK; } -short PHApp::setup() -{ +short PHApp::setup() { _state = APP_STATE::RESET; _error = E_OK; #ifdef ENABLE_PROFILER - if (initialFreeHeap == 0 && initialCpuTicks == 0) - { + if (initialFreeHeap == 0 && initialCpuTicks == 0) { initialFreeHeap = ESP.getFreeHeap(); - initialCpuTicks = esp_cpu_get_ccount(); + initialCpuTicks = esp_cpu_get_cycle_count(); } #endif #ifndef DISABLE_SERIAL_LOGGING // Serial Setup Serial.begin(SERIAL_BAUD_RATE); - while (!Serial && !Serial.available()) - { + while (!Serial && !Serial.available()) { } #endif @@ -215,8 +210,7 @@ short PHApp::setup() // Log Setup #if defined(ENABLE_LOGGER) #if defined(ENABLE_LOGGING_TARGET_PRINT) - if (logger_0) - { + if (logger_0) { Serial.begin(SERIAL_BAUD_RATE); logger_0->addPrintTarget(&Serial); } @@ -251,8 +245,7 @@ short PHApp::setup() #endif // Network short networkSetupResult = setupNetwork(); - if (networkSetupResult != E_OK) - { + if (networkSetupResult != E_OK) { L_ERROR("Network setup failed with error code: %d", networkSetupResult); } @@ -263,16 +256,15 @@ short PHApp::setup() #endif #ifdef ENABLE_LOGGER -#if defined(ENABLE_LOGGING_TARGET_WEBSOCKET) && defined(ENABLE_WEBSERVER) && defined(ENABLE_WEBSOCKET) - if (logger_0 && webServer) - { +#if defined(ENABLE_LOGGING_TARGET_WEBSOCKET) && defined(ENABLE_WEBSERVER) && \ + defined(ENABLE_WEBSOCKET) + if (logger_0 && webServer) { logger_0->addWebSocketTarget(webServer); L_INFO("WebSocket logging target added."); } #endif #if defined(ENABLE_LOGGING_TARGET_FILE) && defined(ENABLE_LITTLEFS) - if (logger_0) - { + if (logger_0) { logger_0->addFileTarget(); L_INFO("File logging target added."); } @@ -290,89 +282,87 @@ short PHApp::setup() #endif #ifdef ENABLE_POT0 - ADD_POT(0, MB_ANALOG_0, COMPONENT_KEY_ANALOG_0, MB_ADDR_AUX_2, POTDampingAlgorithm::DAMPING_EMA, true); + ADD_POT(0, MB_ANALOG_0, COMPONENT_KEY_ANALOG_0, MB_ADDR_AUX_2, + POTDampingAlgorithm::DAMPING_EMA, true); #endif #ifdef ENABLE_POT1 - ADD_POT(1, MB_ANALOG_1, COMPONENT_KEY_ANALOG_1, MB_ADDR_AUX_3, POTDampingAlgorithm::DAMPING_EMA, true); + ADD_POT(1, MB_ANALOG_1, COMPONENT_KEY_ANALOG_1, MB_ADDR_AUX_3, + POTDampingAlgorithm::DAMPING_EMA, true); #endif #if (defined(AUX_ANALOG_3POS_SWITCH_0) && (defined(AUX_ANALOG_3POS_SWITCH_1))) - ADD_POS3ANALOG(0, AUX_ANALOG_3POS_SWITCH_0, AUX_ANALOG_3POS_SWITCH_1, COMPONENT_KEY_MB_ANALOG_3POS_SWITCH_0, MB_ADDR_AUX_3); + ADD_POS3ANALOG(0, AUX_ANALOG_3POS_SWITCH_0, AUX_ANALOG_3POS_SWITCH_1, + COMPONENT_KEY_MB_ANALOG_3POS_SWITCH_0, MB_ADDR_AUX_3); #endif #if (defined(MB_ANALOG_3POS_SWITCH_2) && (defined(MB_ANALOG_3POS_SWITCH_3))) - // ADD_POS3ANALOG(1, MB_ANALOG_3POS_SWITCH_2, MB_ANALOG_3POS_SWITCH_3, COMPONENT_KEY_MB_ANALOG_3POS_SWITCH_1, MB_R_SWITCH_1); // <-- Temporarily disable + // ADD_POS3ANALOG(1, MB_ANALOG_3POS_SWITCH_2, MB_ANALOG_3POS_SWITCH_3, + // COMPONENT_KEY_MB_ANALOG_3POS_SWITCH_1, MB_R_SWITCH_1); // <-- Temporarily + // disable #endif #ifdef MB_GPIO_MB_MAP_7 // --- Define configuration for the MB_GPIO group --- std::vector gpioConfigs; gpioConfigs.reserve(2); // Reserve space for 2 elements - gpioConfigs.push_back( - GPIO_PinConfig( - E_GPIO_7, // pinNumber: The physical pin to manage - E_GPIO_TYPE_ANALOG_INPUT, // pinType: Treat as analog input - 300, // startAddress: Modbus register address - E_FN_CODE::FN_READ_HOLD_REGISTER, // type: Map to a Holding Register - MB_ACCESS_READ_ONLY, // access: Allow Modbus read only - 1000, // opIntervalMs: Update interval in milliseconds - "GPIO_6", // name: Custom name for this pin - "GPIO_Group" // group: Group name for this pin - )); + gpioConfigs.push_back(GPIO_PinConfig( + E_GPIO_7, // pinNumber: The physical pin to manage + E_GPIO_TYPE_ANALOG_INPUT, // pinType: Treat as analog input + 300, // startAddress: Modbus register address + E_FN_CODE::FN_READ_HOLD_REGISTER, // type: Map to a Holding Register + MB_ACCESS_READ_ONLY, // access: Allow Modbus read only + 1000, // opIntervalMs: Update interval in milliseconds + "GPIO_6", // name: Custom name for this pin + "GPIO_Group" // group: Group name for this pin + )); - gpioConfigs.push_back( - GPIO_PinConfig( - E_GPIO_15, // pinNumber: The physical pin to manage - E_GPIO_TYPE_ANALOG_INPUT, // pinType: Treat as analog input - 301, // startAddress: Modbus register address - E_FN_CODE::FN_READ_HOLD_REGISTER, // type: Map to a Holding Register - MB_ACCESS_READ_ONLY, // access: Allow Modbus read only - 1000, // opIntervalMs: Update interval in milliseconds - "GPIO_15", // name: Custom name for this pin - "GPIO_Group" // group: Group name for this pin - )); + gpioConfigs.push_back(GPIO_PinConfig( + E_GPIO_15, // pinNumber: The physical pin to manage + E_GPIO_TYPE_ANALOG_INPUT, // pinType: Treat as analog input + 301, // startAddress: Modbus register address + E_FN_CODE::FN_READ_HOLD_REGISTER, // type: Map to a Holding Register + MB_ACCESS_READ_ONLY, // access: Allow Modbus read only + 1000, // opIntervalMs: Update interval in milliseconds + "GPIO_15", // name: Custom name for this pin + "GPIO_Group" // group: Group name for this pin + )); const short gpioGroupId = COMPONENT_KEY_GPIO_MAP; // Using defined key gpio_0 = new MB_GPIO(this, gpioGroupId, gpioConfigs); components.push_back(gpio_0); #endif #ifdef PIN_ANALOG_LEVEL_SWITCH_0 - analogLevelSwitch_0 = new AnalogLevelSwitch( - this, // owner - PIN_ANALOG_LEVEL_SWITCH_0, // analogPin - ALS_0_NUM_LEVELS, // numLevels - ALS_0_ADC_STEP, // levelStep - ALS_0_ADC_OFFSET, // adcValueOffset - ID_ANALOG_LEVEL_SWITCH_0, // id - ALS_0_MB_ADDR // modbusAddress - ); - if (analogLevelSwitch_0) - { + analogLevelSwitch_0 = + new AnalogLevelSwitch(this, // owner + PIN_ANALOG_LEVEL_SWITCH_0, // analogPin + ALS_0_NUM_LEVELS, // numLevels + ALS_0_ADC_STEP, // levelStep + ALS_0_ADC_OFFSET, // adcValueOffset + ID_ANALOG_LEVEL_SWITCH_0, // id + ALS_0_MB_ADDR // modbusAddress + ); + if (analogLevelSwitch_0) { components.push_back(analogLevelSwitch_0); - L_INFO(F("AnalogLevelSwitch_0 initialized. Pin:%d, ID:%d, Levels:%d, Step:%d, Offset:%d, Smooth:%d(Fixed), Debounce:%d(Fixed), MB:%d"), - PIN_ANALOG_LEVEL_SWITCH_0, ID_ANALOG_LEVEL_SWITCH_0, ALS_0_NUM_LEVELS, - ALS_0_ADC_STEP, ALS_0_ADC_OFFSET, - ALS_SMOOTHING_SIZE, - ALS_DEBOUNCE_COUNT, - ALS_0_MB_ADDR); - } - else - { + L_INFO(F("AnalogLevelSwitch_0 initialized. Pin:%d, ID:%d, Levels:%d, " + "Step:%d, Offset:%d, Smooth:%d(Fixed), Debounce:%d(Fixed), MB:%d"), + PIN_ANALOG_LEVEL_SWITCH_0, ID_ANALOG_LEVEL_SWITCH_0, + ALS_0_NUM_LEVELS, ALS_0_ADC_STEP, ALS_0_ADC_OFFSET, + ALS_SMOOTHING_SIZE, ALS_DEBOUNCE_COUNT, ALS_0_MB_ADDR); + } else { L_ERROR(F("AnalogLevelSwitch_0 initialization failed.")); } #endif #ifdef ENABLE_STATUS - statusLight_0 = new StatusLight(this, - STATUS_WARNING_PIN, - COMPONENT_KEY_FEEDBACK_0, - MB_MONITORING_STATUS_FEEDBACK_0); // Keep original address for now, add to config-modbus.h later if needed + statusLight_0 = new StatusLight( + this, STATUS_WARNING_PIN, COMPONENT_KEY_FEEDBACK_0, + MB_MONITORING_STATUS_FEEDBACK_0); // Keep original address for now, add to + // config-modbus.h later if needed components.push_back(statusLight_0); - statusLight_1 = new StatusLight(this, - STATUS_ERROR_PIN, - COMPONENT_KEY_FEEDBACK_1, - MB_MONITORING_STATUS_FEEDBACK_1); // Keep original address for now + statusLight_1 = new StatusLight( + this, STATUS_ERROR_PIN, COMPONENT_KEY_FEEDBACK_1, + MB_MONITORING_STATUS_FEEDBACK_1); // Keep original address for now components.push_back(statusLight_1); #else statusLight_0 = NULL; @@ -381,95 +371,90 @@ short PHApp::setup() L_INFO("PHApp::setup - Base App::setup() called."); #ifdef PIN_LED_FEEDBACK_0 - ledFeedback_0 = new LEDFeedback( - this, // owner - PIN_LED_FEEDBACK_0, // pin - LED_PIXEL_COUNT_0, // pixelCount - ID_LED_FEEDBACK_0, // id - LED_FEEDBACK_0_MB_ADDR // modbusAddress + ledFeedback_0 = new LEDFeedback(this, // owner + PIN_LED_FEEDBACK_0, // pin + LED_PIXEL_COUNT_0, // pixelCount + ID_LED_FEEDBACK_0, // id + LED_FEEDBACK_0_MB_ADDR // modbusAddress ); - if (ledFeedback_0) - { + if (ledFeedback_0) { components.push_back(ledFeedback_0); L_INFO(F("LEDFeedback_0 initialized. Pin:%d, Count:%d, ID:%d, MB:%d"), - PIN_LED_FEEDBACK_0, LED_PIXEL_COUNT_0, - ID_LED_FEEDBACK_0, LED_FEEDBACK_0_MB_ADDR); - } - else - { + PIN_LED_FEEDBACK_0, LED_PIXEL_COUNT_0, ID_LED_FEEDBACK_0, + LED_FEEDBACK_0_MB_ADDR); + } else { L_ERROR(F("LEDFeedback_0 initialization failed.")); } #endif #ifdef ENABLE_JOYSTICK - joystick_0 = new Joystick( - this, // owner - PIN_JOYSTICK_UP, // UP pin - PIN_JOYSTICK_DOWN, // DOWN pin - PIN_JOYSTICK_LEFT, // LEFT pin - PIN_JOYSTICK_RIGHT, // RIGHT pin - MB_ADDR_AUX_7 // modbusAddress + joystick_0 = new Joystick(this, // owner + PIN_JOYSTICK_UP, // UP pin + PIN_JOYSTICK_DOWN, // DOWN pin + PIN_JOYSTICK_LEFT, // LEFT pin + PIN_JOYSTICK_RIGHT, // RIGHT pin + MB_ADDR_AUX_7 // modbusAddress ); - if (joystick_0) - { + if (joystick_0) { components.push_back(joystick_0); - } - else - { + } else { L_ERROR(F("Joystick_0 initialization failed.")); } #endif #ifdef PIN_AUX_1 - pushButton_1 = new PushButton(this, PIN_AUX_1, COMPONENT_KEY_PUSH_BUTTON_0, MB_IREG_ANALOG_0); + pushButton_1 = new PushButton(this, PIN_AUX_1, COMPONENT_KEY_PUSH_BUTTON_0, + MB_IREG_ANALOG_0); components.push_back(pushButton_1); #endif #ifdef ENABLE_FEEDBACK_3C - feedback3C_0 = new Feedback3C(this, - GPIO_PIN_CH4, - GPIO_PIN_CH5, - GPIO_PIN_CH6, - COMPONENT_KEY_FEEDBACK_0, - MB_ADDR_FEEDBACK_0); + feedback3C_0 = new Feedback3C(this, GPIO_PIN_CH4, GPIO_PIN_CH5, GPIO_PIN_CH6, + COMPONENT_KEY_FEEDBACK_0, MB_ADDR_FEEDBACK_0); components.push_back(feedback3C_0); #endif #ifdef ENABLE_FEEDBACK_BUZZER - feedbackBuzzer_0 = new FeedbackBuzzer(this, - GPIO_PIN_CH3, - COMPONENT_KEY_FEEDBACK_1, - MB_ADDR_AUX_9); + feedbackBuzzer_0 = new FeedbackBuzzer( + this, GPIO_PIN_CH3, COMPONENT_KEY_FEEDBACK_1, MB_ADDR_AUX_9); components.push_back(feedbackBuzzer_0); #endif // Systems : Hydraulic Cylinder - Loadcell sensor - RS485 #ifdef ENABLE_SOLENOID_0 - uint32_t solenoid0Addr = appSettings->get("SOLENOID_0_MB_ADDR", (uint32_t)MB_ADDR_SOLENOID_0); + uint32_t solenoid0Addr = + appSettings->get("SOLENOID_0_MB_ADDR", (uint32_t)MB_ADDR_SOLENOID_0); ADD_SOLENOID(0, PIN_SOLENOID_0, COMPONENT_KEY_SOLENOID_0, solenoid0Addr); #endif #ifdef ENABLE_SOLENOID_1 - uint32_t solenoid1Addr = appSettings->get("SOLENOID_1_MB_ADDR", (uint32_t)MB_ADDR_SOLENOID_1); + uint32_t solenoid1Addr = + appSettings->get("SOLENOID_1_MB_ADDR", (uint32_t)MB_ADDR_SOLENOID_1); ADD_SOLENOID(1, PIN_SOLENOID_1, COMPONENT_KEY_SOLENOID_1, MB_ADDR_SOLENOID_1); #endif #ifdef ENABLE_LOADCELL_0 - uint32_t slaveId0 = appSettings->get("LOADCELL_SLAVE_ID_0", (uint32_t)LOADCELL_SLAVE_ID_0); - loadCell_0 = new Loadcell(this, slaveId0, LOADCELL_READ_INTERVAL, COMPONENT_KEY_LOADCELL_0); + uint32_t slaveId0 = + appSettings->get("LOADCELL_SLAVE_ID_0", (uint32_t)LOADCELL_SLAVE_ID_0); + loadCell_0 = new Loadcell(this, slaveId0, LOADCELL_READ_INTERVAL, + COMPONENT_KEY_LOADCELL_0); components.push_back(static_cast(loadCell_0)); #endif #ifdef ENABLE_LOADCELL_1 - uint32_t slaveId1 = appSettings->get("LOADCELL_SLAVE_ID_1", (uint32_t)LOADCELL_SLAVE_ID_1); - loadCell_1 = new Loadcell(this, slaveId1, LOADCELL_READ_INTERVAL, COMPONENT_KEY_LOADCELL_1); + uint32_t slaveId1 = + appSettings->get("LOADCELL_SLAVE_ID_1", (uint32_t)LOADCELL_SLAVE_ID_1); + loadCell_1 = new Loadcell(this, slaveId1, LOADCELL_READ_INTERVAL, + COMPONENT_KEY_LOADCELL_1); components.push_back(static_cast(loadCell_1)); #endif #ifdef ENABLE_PRESS_CYLINDER - pressCylinder_0 = new PressCylinder(this, COMPONENT_KEY_PRESS_CYLINDER_0, MB_ADDR_PRESS_CYLINDER_0, joystick_0, pushButton_1); + pressCylinder_0 = + new PressCylinder(this, COMPONENT_KEY_PRESS_CYLINDER_0, + MB_ADDR_PRESS_CYLINDER_0, joystick_0, pushButton_1); #ifdef ENABLE_LOADCELL_0 if (loadCell_0) pressCylinder_0->addLoadcell(loadCell_0); @@ -490,11 +475,9 @@ short PHApp::setup() #endif #ifdef ENABLE_OPERATOR_SWITCH - operatorSwitch_0 = new OperatorSwitch(this, - PIN_OPERATOR_SWITCH_STOP, - PIN_OPERATOR_SWITCH_CYCLE, - COMPONENT_KEY_OPERATOR_SWITCH, - MB_ADDR_AUX_8); + operatorSwitch_0 = new OperatorSwitch( + this, PIN_OPERATOR_SWITCH_STOP, PIN_OPERATOR_SWITCH_CYCLE, + COMPONENT_KEY_OPERATOR_SWITCH, MB_ADDR_AUX_8); components.push_back(operatorSwitch_0); #endif @@ -510,14 +493,16 @@ short PHApp::setup() #ifdef ENABLE_NETWORK_VALUE_TEST L_INFO("PHApp::setup - Initializing NetworkValueTest..."); - networkValueTest = new NetworkValueTest(this, COMPONENT_KEY_TEST_NV, MB_ADDR_AUX_TEST_NV); + networkValueTest = + new NetworkValueTest(this, COMPONENT_KEY_TEST_NV, MB_ADDR_AUX_TEST_NV); networkValueTest->owner = this; components.push_back(networkValueTest); #endif #ifdef ENABLE_NETWORK_VALUE_TEST_PB L_INFO("PHApp::setup - Initializing NetworkValueTestPB..."); - networkValueTestPB = new NetworkValueTestPB(this, COMPONENT_KEY_TEST_NV_PB, MB_ADDR_AUX_TEST_NV + 10); + networkValueTestPB = new NetworkValueTestPB(this, COMPONENT_KEY_TEST_NV_PB, + MB_ADDR_AUX_TEST_NV + 10); networkValueTestPB->owner = this; components.push_back(networkValueTestPB); #endif @@ -529,18 +514,20 @@ short PHApp::setup() #endif #ifdef ENABLE_DELTA_VFD - vfd_2 = new DELTA_VFD(this, MB_DELTA_VFD_SLAVE_ID, MB_DELTA_VFD_READ_INTERVAL); + vfd_2 = + new DELTA_VFD(this, MB_DELTA_VFD_SLAVE_ID, MB_DELTA_VFD_READ_INTERVAL); components.push_back(vfd_2); #endif // Temperature #ifdef ENABLE_PROFILE_TEMPERATURE - for (ushort i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) - { + for (ushort i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) { // Assign unique ID: COMPONENT_KEY_PROFILE_START (910) + slot index ushort profileComponentId = COMPONENT_KEY_PROFILE_START + i; - ushort baseAddr = MB_HREG_TEMP_PROFILE_BASE + (i * TEMP_PROFILE_REGISTER_COUNT); - tempProfiles[i] = new TemperatureProfile(this, i, profileComponentId, baseAddr); + ushort baseAddr = + MB_HREG_TEMP_PROFILE_BASE + (i * TEMP_PROFILE_REGISTER_COUNT); + tempProfiles[i] = + new TemperatureProfile(this, i, profileComponentId, baseAddr); tempProfiles[i]->setEventsDelegate(this); components.push_back(tempProfiles[i]); } @@ -548,31 +535,29 @@ short PHApp::setup() #endif #ifdef ENABLE_PROFILE_PRESSURE - for (ushort i = 0; i < PROFILE_PRESSURE_COUNT; ++i) - { + for (ushort i = 0; i < PROFILE_PRESSURE_COUNT; ++i) { ushort profileComponentId = COMPONENT_KEY_PRESSURE_PROFILE_START + i; - ushort baseAddr = MB_HREG_PRESSURE_PROFILE_BASE + (i * PRESSURE_PROFILE_REGISTER_COUNT); - pressureProfiles[i] = new PressureProfile(this, i, profileComponentId, baseAddr); + ushort baseAddr = + MB_HREG_PRESSURE_PROFILE_BASE + (i * PRESSURE_PROFILE_REGISTER_COUNT); + pressureProfiles[i] = + new PressureProfile(this, i, profileComponentId, baseAddr); pressureProfiles[i]->setEventsDelegate(this); components.push_back(pressureProfiles[i]); } #endif #ifdef ENABLE_PROFILE_SIGNAL_PLOT - for (int i = 0; i < PROFILE_SIGNAL_PLOT_COUNT; i++) - { + for (int i = 0; i < PROFILE_SIGNAL_PLOT_COUNT; i++) { ushort profileComponentId = COMPONENT_KEY_SIGNAL_PLOT_START + i; - ushort modbusAddress = MB_HREG_SIGNAL_PLOT_BASE + (i * SIGNAL_PLOT_REGISTER_COUNT); + ushort modbusAddress = + MB_HREG_SIGNAL_PLOT_BASE + (i * SIGNAL_PLOT_REGISTER_COUNT); signalPlots[i] = new SignalPlot(this, i, profileComponentId, modbusAddress); signalPlots[i]->setEventsDelegate(this); components.push_back(signalPlots[i]); #ifdef ENABLE_MODBUS_TCP - if (modbusManager != nullptr) - { + if (modbusManager != nullptr) { signalPlots[i]->setModbusTCP(modbusManager); - } - else - { + } else { L_ERROR("PHApp::setup - SignalPlot %d: modbusManager is nullptr", i); } #endif @@ -584,7 +569,8 @@ short PHApp::setup() const int8_t PID2_THERMO_CS = 5; // Example Chip Select pin const int8_t PID2_THERMO_CLK = 18; // Example SCK pin const int8_t PID2_OUTPUT_PIN = 23; // Example PWM/Output pin - ADD_PID(0, "PID Temp Controller 2", PID2_THERMO_DO, PID2_THERMO_CS, PID2_THERMO_CLK, PID2_OUTPUT_PIN, COMPONENT_KEY_PID_2); + ADD_PID(0, "PID Temp Controller 2", PID2_THERMO_DO, PID2_THERMO_CS, + PID2_THERMO_CLK, PID2_OUTPUT_PIN, COMPONENT_KEY_PID_2); #endif // RS485 #ifdef ENABLE_RS485 @@ -593,7 +579,8 @@ short PHApp::setup() #endif #ifdef ENABLE_AMPERAGE_BUDGET_MANAGER - pidManagerAmperage = new AmperageBudgetManager(this, MB_ADDR_AMPERAGE_BUDGET_BASE); + pidManagerAmperage = + new AmperageBudgetManager(this, MB_ADDR_AMPERAGE_BUDGET_BASE); #if defined(ENABLE_OMRON_E5) && defined(ENABLE_PROFILE_TEMPERATURE) pidManagerAmperage->setCanUseCallback(&PHApp_canUsePID); pidManagerAmperage->setOnWarmupCompleteCallback(&PHApp_onWarmupComplete); @@ -636,15 +623,12 @@ short PHApp::setup() return E_OK; } -short PHApp::onRun() -{ +short PHApp::onRun() { App::onRun(); #ifdef ENABLE_MODBUS_TCP - for (Component *comp : components) - { - if (comp && comp->hasNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS)) - { + for (Component *comp : components) { + if (comp && comp->hasNetCapability(OBJECT_NET_CAPS::E_NCAPS_MODBUS)) { comp->mb_tcp_register(modbusManager); } } @@ -668,18 +652,14 @@ short PHApp::onRun() #if ENABLED(ENABLE_AMPERAGE_BUDGET_MANAGER, ENABLE_OMRON_E5) RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevicesInManager = rs485->deviceManager.getMaxDevices(); - for (int i = 0; i < numDevicesInManager; ++i) - { - if (devices[i] != nullptr) - { + for (int i = 0; i < numDevicesInManager; ++i) { + if (devices[i] != nullptr) { Component *comp = devices[i]; - if (comp == nullptr || comp->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + if (comp == nullptr || comp->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) { continue; } - if (!pidManagerAmperage->addManagedDevice(static_cast(comp))) - { + if (!pidManagerAmperage->addManagedDevice(static_cast(comp))) { L_ERROR("Failed to add OmronE5 device to AmperageBudgetManager"); } } @@ -688,16 +668,13 @@ short PHApp::onRun() #if ENABLED(ENABLE_TEMPERATURE_PROFILES, ENABLE_OMRON_E5, ENABLE_MODBUS_TCP) tempProfiles[0]->disable(); - if (tempProfiles[0] && rs485) - { + if (tempProfiles[0] && rs485) { RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevicesInManager = rs485->deviceManager.getMaxDevices(); int targetRegisterIndex = 0; // Dedicated index for _targetRegisters - for (int i = 0; i < numDevicesInManager; i++) - { + for (int i = 0; i < numDevicesInManager; i++) { Component *comp = devices[i]; - if (comp == nullptr || comp->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + if (comp == nullptr || comp->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) { continue; } } @@ -709,12 +686,9 @@ short PHApp::onRun() #endif #ifdef ENABLE_RUNTIME_STATE - if (runtimeState) - { - for (auto *component : components) - { - if (component && component->hasPersistence(E_PF_ENABLED)) - { + if (runtimeState) { + for (auto *component : components) { + if (component && component->hasPersistence(E_PF_ENABLED)) { runtimeState->addManagedComponent(component); } } @@ -724,49 +698,41 @@ short PHApp::onRun() // setAllOmronComWrite(true, false); return E_OK; } -short PHApp::serial_register(Bridge *bridge) -{ +short PHApp::serial_register(Bridge *bridge) { /* - bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, C_STR("list"), (ComponentFnPtr)&PHApp::list); - bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, C_STR("reset"), (ComponentFnPtr)&PHApp::reset); - bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, C_STR("printRegisters"), (ComponentFnPtr)&PHApp::printRegisters); - bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, C_STR("load"), (ComponentFnPtr)&PHApp::load); + bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, + C_STR("list"), (ComponentFnPtr)&PHApp::list); + bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, + C_STR("reset"), (ComponentFnPtr)&PHApp::reset); + bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, + C_STR("printRegisters"), (ComponentFnPtr)&PHApp::printRegisters); + bridge->registerMemberFunction(COMPONENT_KEY_BASE::COMPONENT_KEY_APP, this, + C_STR("load"), (ComponentFnPtr)&PHApp::load); */ return E_OK; } -short PHApp::onWarning(short code) -{ - return E_OK; -} -short PHApp::onError(short id, short code) -{ - if (code == getLastError()) - { +short PHApp::onWarning(short code) { return E_OK; } +short PHApp::onError(short id, short code) { + if (code == getLastError()) { return code; } Log.error(F("* App:onError - component=%d code=%d" CR), id, code); setLastError(code); #ifdef ENABLE_STATUS - if (statusLight_0) - { - switch (id) - { - case COMPONENT_KEY_PLUNGER: - { + if (statusLight_0) { + switch (id) { + case COMPONENT_KEY_PLUNGER: { #if defined(ENABLE_PLUNGER) - case (short)PlungerState::IDLE: - { + case (short)PlungerState::IDLE: { statusLight_1->set(0, 0); break; } - case (short)PlungerState::JAMMED: - { + case (short)PlungerState::JAMMED: { statusLight_1->set(1, 1); break; } - default: - { + default: { statusLight_1->set(1, 0); break; } @@ -778,22 +744,16 @@ short PHApp::onError(short id, short code) #endif return code; } -short PHApp::onStop(short val) -{ - return E_OK; -} -short PHApp::clearError() -{ +short PHApp::onStop(short val) { return E_OK; } +short PHApp::clearError() { setLastError(E_OK); return E_OK; } -short PHApp::loop() -{ +short PHApp::loop() { App::loop(); - if (millis() - _last_cycle_loop_ms >= LOOP_CYCLE_INTERVAL) - { + if (millis() - _last_cycle_loop_ms >= LOOP_CYCLE_INTERVAL) { _last_cycle_loop_ms = millis(); loopCycle(); #ifdef ENABLE_PROFILE_TEMPERATURE @@ -802,8 +762,8 @@ short PHApp::loop() } #ifdef ENABLE_RUNTIME_STATE - if (runtimeState && (millis() - _last_runtime_save_ms >= RUNTIME_STATE_SAVE_INTERVAL)) - { + if (runtimeState && + (millis() - _last_runtime_save_ms >= RUNTIME_STATE_SAVE_INTERVAL)) { _last_runtime_save_ms = millis(); updateRuntimeState(); } @@ -822,22 +782,16 @@ short PHApp::loop() return E_OK; } -short PHApp::loopWeb() -{ +short PHApp::loopWeb() { #if defined(ENABLE_WIFI) && defined(ENABLE_WEBSERVER) - if (webServer != nullptr) - { + if (webServer != nullptr) { webServer->loop(); } #endif return E_OK; } -short PHApp::getAppState(short val) -{ - return _state; -} -PHApp::PHApp() : App() -{ +short PHApp::getAppState(short val) { return _state; } +PHApp::PHApp() : App() { name = "PHApp"; webServer = nullptr; pidController_0 = nullptr; @@ -872,22 +826,19 @@ PHApp::PHApp() : App() appSettings = nullptr; #ifdef ENABLE_PROFILE_TEMPERATURE // Initialize the array elements to nullptr - for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) - { + for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) { tempProfiles[i] = nullptr; } #endif #ifdef ENABLE_PROFILE_PRESSURE - for (int i = 0; i < PROFILE_PRESSURE_COUNT; ++i) - { + for (int i = 0; i < PROFILE_PRESSURE_COUNT; ++i) { pressureProfiles[i] = nullptr; } #endif #ifdef ENABLE_PROFILE_SIGNAL_PLOT - for (int i = 0; i < PROFILE_SIGNAL_PLOT_COUNT; ++i) - { + for (int i = 0; i < PROFILE_SIGNAL_PLOT_COUNT; ++i) { signalPlots[i] = nullptr; } #endif @@ -898,11 +849,10 @@ PHApp::PHApp() : App() // WiFi settings are now initialized by WiFiNetworkSettings constructor } -void PHApp::cleanupComponents() -{ - L_INFO("PHApp::cleanupComponents - Cleaning up %d components...", components.size()); - for (Component *comp : components) - { +void PHApp::cleanupComponents() { + L_INFO("PHApp::cleanupComponents - Cleaning up %d components...", + components.size()); + for (Component *comp : components) { delete comp; } components.clear(); // Clear the vector AFTER deleting objects @@ -937,22 +887,19 @@ void PHApp::cleanupComponents() pressCylinder_0 = nullptr; appSettings = nullptr; #ifdef ENABLE_PROFILE_TEMPERATURE - // Clean up temperature profiles (they were also added to components vector, so already deleted there) - // Ensure the pointers in the array are nulled - for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) - { + // Clean up temperature profiles (they were also added to components vector, + // so already deleted there) Ensure the pointers in the array are nulled + for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) { tempProfiles[i] = nullptr; } #endif #ifdef ENABLE_PROFILE_PRESSURE - for (int i = 0; i < PROFILE_PRESSURE_COUNT; ++i) - { + for (int i = 0; i < PROFILE_PRESSURE_COUNT; ++i) { pressureProfiles[i] = nullptr; } #endif #ifdef ENABLE_WEBSERVER - if (webServer) - { + if (webServer) { delete webServer; webServer = nullptr; } @@ -971,24 +918,17 @@ void PHApp::cleanupComponents() #endif L_INFO("PHApp::cleanupComponents - Cleanup complete."); } -PHApp::~PHApp() -{ - cleanupComponents(); -} -short PHApp::setAppState(short newState) -{ - if (_state != newState) - { +PHApp::~PHApp() { cleanupComponents(); } +short PHApp::setAppState(short newState) { + if (_state != newState) { _state = (APP_STATE)newState; } return E_OK; } #ifdef ENABLE_SETTINGS -short PHApp::loadAppSettings() -{ - if (!appSettings->load("/settings.json")) - { +short PHApp::loadAppSettings() { + if (!appSettings->load("/settings.json")) { L_WARN("Failed to load settings, using defaults."); } @@ -997,8 +937,7 @@ short PHApp::loadAppSettings() setAppPidLag(appSettings->get("PID_LAG_COMPENSATION", true), false); #if defined(ENABLE_OMRON_E5) && defined(ENABLE_RS485) - if (!rs485) - { + if (!rs485) { L_ERROR("RS485 not initialized, cannot apply settings to Omron devices."); return E_NOT_INITIALIZED; } @@ -1006,49 +945,38 @@ short PHApp::loadAppSettings() RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevicesInManager = rs485->deviceManager.getMaxDevices(); - for (int i = 0; i < numDevicesInManager; ++i) - { + for (int i = 0; i < numDevicesInManager; ++i) { RTU_Base *device = devices[i]; - if (device == nullptr || device->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + if (device == nullptr || + device->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) { continue; } bool foundInSettings = false; bool shouldBeEnabled = false; - for (uint8_t p = 0; p < appSettings->partitionCount; ++p) - { + for (uint8_t p = 0; p < appSettings->partitionCount; ++p) { PartitionConfig &partition = appSettings->partitions[p]; - for (uint8_t c = 0; c < partition.controllerCount; ++c) - { + for (uint8_t c = 0; c < partition.controllerCount; ++c) { ControllerConfig &controller = partition.controllers[c]; - if (device->slaveId == controller.slaveId) - { + if (device->slaveId == controller.slaveId) { foundInSettings = true; shouldBeEnabled = controller.enabled; break; } } - if (foundInSettings) - { + if (foundInSettings) { break; } } - if (foundInSettings) - { - if (shouldBeEnabled) - { + if (foundInSettings) { + if (shouldBeEnabled) { device->enable(); - } - else - { + } else { device->disable(); } - } - else - { + } else { device->disable(); } } @@ -1058,35 +986,30 @@ short PHApp::loadAppSettings() #endif #ifdef ENABLE_PID -short PHApp::getPid2Register(short offset, short unused) -{ - if (!pidController_0) - { +short PHApp::getPid2Register(short offset, short unused) { + if (!pidController_0) { L_ERROR("Serial Command Error: PID Controller 2 not initialized."); return E_INVALID_PARAMETER; // Use defined error code } - if (offset < 0 || offset >= PID_2_REGISTER_COUNT) - { + if (offset < 0 || offset >= PID_2_REGISTER_COUNT) { L_ERROR("Serial Command Error: Invalid PID2 offset %d.", offset); return E_INVALID_PARAMETER; } short address = MB_HREG_PID_2_BASE_ADDRESS + offset; short value = pidController_0->mb_tcp_read(address); - Log.noticeln("PID2 Register Offset %d (Addr %d) Value: %d", offset, address, value); + Log.noticeln("PID2 Register Offset %d (Addr %d) Value: %d", offset, address, + value); // Optionally send value back over serial if needed by the protocol return E_OK; } -short PHApp::setPid2Register(short offset, short value) -{ - if (!pidController_0) - { +short PHApp::setPid2Register(short offset, short value) { + if (!pidController_0) { L_ERROR("Serial Command Error: PID Controller 2 not initialized."); return E_INVALID_PARAMETER; // Use defined error code } - if (offset < 0 || offset >= PID_2_REGISTER_COUNT) - { + if (offset < 0 || offset >= PID_2_REGISTER_COUNT) { L_ERROR("Serial Command Error: Invalid PID2 offset %d.", offset); return E_INVALID_PARAMETER; } @@ -1094,61 +1017,56 @@ short PHApp::setPid2Register(short offset, short value) short address = MB_HREG_PID_2_BASE_ADDRESS + offset; short result = pidController_0->mb_tcp_write(address, value); - if (result == E_OK) - { - Log.noticeln("PID2 Register Offset %d (Addr %d) set to: %d", offset, address, value); - } - else - { - L_ERROR("PID2 Register Offset %d (Addr %d) failed to set to %d. Error: %d", offset, address, value, result); + if (result == E_OK) { + Log.noticeln("PID2 Register Offset %d (Addr %d) set to: %d", offset, + address, value); + } else { + L_ERROR("PID2 Register Offset %d (Addr %d) failed to set to %d. Error: %d", + offset, address, value, result); } return result; } #endif -short PHApp::onMessage(int id, E_CALLS verb, E_MessageFlags flags, void *user, Component *src) -{ +short PHApp::onMessage(int id, E_CALLS verb, E_MessageFlags flags, void *user, + Component *src) { #if defined(ENABLE_INFLUXDB) && defined(ENABLE_OMRON_E5) // Intercept messages from Omron PID controllers to log their data. - if (verb == E_CALLS::EC_USER && src && src->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + if (verb == E_CALLS::EC_USER && src && + src->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) { // Log.infoln("PHApp::onMessage - OmronE5"); // We know it's an OmronE5, so we can safely cast it. OmronE5 *omron = static_cast(src); uint16_t sp, pv; // Ensure both SP and PV are valid before logging - if (omron->getSP(sp) && omron->getPV(pv)) - { + if (omron->getSP(sp) && omron->getPV(pv)) { Point p("pid_controller"); // Create a local Point p.addTag("slaveId", String(omron->slaveId)); p.addField("sp", sp); p.addField("pv", pv); p.addField("isHeating", omron->isHeating()); influxDb_0->write(p); - } - else - { + } else { Log.errorln("PHApp::onMessage - OmronE5 - SP or PV not valid"); } } #endif #if ENABLED(ENABLE_RS485, ENABLE_WEBSERVER, ENABLE_WEBSOCKET) - if (verb == E_CALLS::EC_USER && user != nullptr && webServer != nullptr) - { + if (verb == E_CALLS::EC_USER && user != nullptr && webServer != nullptr) { MB_UpdateData *update = static_cast(user); - return webServer->onMessage(id, E_CALLS::EC_USER, E_MessageFlags::E_MF_NONE, user, src); + return webServer->onMessage(id, E_CALLS::EC_USER, E_MessageFlags::E_MF_NONE, + user, src); } - if (verb == E_CALLS::EC_PROTOBUF_UPDATE && user != nullptr) - { + if (verb == E_CALLS::EC_PROTOBUF_UPDATE && user != nullptr) { PB_UpdateData *update = static_cast(user); - return webServer->onMessage(id, E_CALLS::EC_PROTOBUF_UPDATE, E_MessageFlags::E_MF_NONE, user, src); + return webServer->onMessage(id, E_CALLS::EC_PROTOBUF_UPDATE, + E_MessageFlags::E_MF_NONE, user, src); } #endif - if (verb == E_CALLS::EC_DISPATCH && user != nullptr) - { + if (verb == E_CALLS::EC_DISPATCH && user != nullptr) { JsonDocument *doc = static_cast(user); this->broadcast(BROADCAST_ERROR_MESSAGE, *doc); return E_OK; @@ -1160,36 +1078,30 @@ short PHApp::onMessage(int id, E_CALLS verb, E_MessageFlags flags, void *user, C * @brief Retrieves a component by its ID. * * @param id The ID of the component to retrieve. - * @return A pointer to the component with the specified ID, or nullptr if not found. - * @note Top-Level PHApp cant be part of components vector, so we need to handle it separately. + * @return A pointer to the component with the specified ID, or nullptr if not + * found. + * @note Top-Level PHApp cant be part of components vector, so we need to handle + * it separately. */ -Component *PHApp::byId(ushort id) -{ +Component *PHApp::byId(ushort id) { Component *comp = App::byId(id); - if (comp) - { + if (comp) { return comp; - } - else if (id == COMPONENT_KEY_APP) - { + } else if (id == COMPONENT_KEY_APP) { return this; } return nullptr; } -short PHApp::init(short arg1, short arg2) -{ +short PHApp::init(short arg1, short arg2) { #if ENABLED(ENABLE_AMPERAGE_BUDGET_MANAGER, ENABLE_OMRON_E5) RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevicesInManager = rs485->deviceManager.getMaxDevices(); - for (int i = 0; i < numDevicesInManager; ++i) - { - if (devices[i] != nullptr) - { + for (int i = 0; i < numDevicesInManager; ++i) { + if (devices[i] != nullptr) { Component *comp = devices[i]; - if (comp == nullptr || comp->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + if (comp == nullptr || comp->type != COMPONENT_TYPE::COMPONENT_TYPE_PID) { continue; } @@ -1203,86 +1115,88 @@ short PHApp::init(short arg1, short arg2) } #ifdef ENABLE_PROFILE_SIGNAL_PLOT -void PHApp::startSignalPlot(short slotId) -{ - if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && signalPlots[slotId] != nullptr) - { - L_INFO("PHApp: Starting SignalPlot in slot %d (triggered by TemperatureProfile).", slotId); +void PHApp::startSignalPlot(short slotId) { + if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && + signalPlots[slotId] != nullptr) { + L_INFO("PHApp: Starting SignalPlot in slot %d (triggered by " + "TemperatureProfile).", + slotId); signalPlots[slotId]->start(); - } - else - { - Log.warningln("PHApp: Could not start SignalPlot. Invalid slotId %d or plot not initialized.", slotId); + } else { + Log.warningln("PHApp: Could not start SignalPlot. Invalid slotId %d or " + "plot not initialized.", + slotId); } } -void PHApp::stopSignalPlot(short slotId) -{ - if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && signalPlots[slotId] != nullptr) - { - L_INFO("PHApp: Stopping SignalPlot in slot %d (triggered by TemperatureProfile).", slotId); +void PHApp::stopSignalPlot(short slotId) { + if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && + signalPlots[slotId] != nullptr) { + L_INFO("PHApp: Stopping SignalPlot in slot %d (triggered by " + "TemperatureProfile).", + slotId); signalPlots[slotId]->stop(); - } - else - { - Log.warningln("PHApp: Could not stop SignalPlot. Invalid slotId %d or plot not initialized.", slotId); + } else { + Log.warningln("PHApp: Could not stop SignalPlot. Invalid slotId %d or plot " + "not initialized.", + slotId); } } -void PHApp::enableSignalPlot(short slotId, bool enable) -{ - if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && signalPlots[slotId] != nullptr) - { - if (enable) - { - L_INFO("PHApp: Enabling SignalPlot in slot %d (triggered by TemperatureProfile).", slotId); +void PHApp::enableSignalPlot(short slotId, bool enable) { + if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && + signalPlots[slotId] != nullptr) { + if (enable) { + L_INFO("PHApp: Enabling SignalPlot in slot %d (triggered by " + "TemperatureProfile).", + slotId); signalPlots[slotId]->enable(enable); - } - else - { - L_INFO("PHApp: Disabling SignalPlot in slot %d (triggered by TemperatureProfile).", slotId); + } else { + L_INFO("PHApp: Disabling SignalPlot in slot %d (triggered by " + "TemperatureProfile).", + slotId); signalPlots[slotId]->disable(); } - } - else - { - Log.warningln("PHApp: Could not enable/disable SignalPlot. Invalid slotId %d or plot not initialized.", slotId); + } else { + Log.warningln("PHApp: Could not enable/disable SignalPlot. Invalid slotId " + "%d or plot not initialized.", + slotId); } } -void PHApp::pauseSignalPlot(short slotId) -{ - if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && signalPlots[slotId] != nullptr) - { - L_INFO("PHApp: Pausing SignalPlot in slot %d (triggered by TemperatureProfile).", slotId); +void PHApp::pauseSignalPlot(short slotId) { + if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && + signalPlots[slotId] != nullptr) { + L_INFO("PHApp: Pausing SignalPlot in slot %d (triggered by " + "TemperatureProfile).", + slotId); signalPlots[slotId]->pause(); - } - else - { - Log.warningln("PHApp: Could not pause SignalPlot. Invalid slotId %d or plot not initialized.", slotId); + } else { + Log.warningln("PHApp: Could not pause SignalPlot. Invalid slotId %d or " + "plot not initialized.", + slotId); } } -void PHApp::resumeSignalPlot(short slotId) -{ - if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && signalPlots[slotId] != nullptr) - { - L_INFO("PHApp: Resuming SignalPlot in slot %d (triggered by TemperatureProfile).", slotId); +void PHApp::resumeSignalPlot(short slotId) { + if (slotId >= 0 && slotId < PROFILE_SIGNAL_PLOT_COUNT && + signalPlots[slotId] != nullptr) { + L_INFO("PHApp: Resuming SignalPlot in slot %d (triggered by " + "TemperatureProfile).", + slotId); signalPlots[slotId]->resume(); - } - else - { - Log.warningln("PHApp: Could not resume SignalPlot. Invalid slotId %d or plot not initialized.", slotId); + } else { + Log.warningln("PHApp: Could not resume SignalPlot. Invalid slotId %d or " + "plot not initialized.", + slotId); } } #endif // ENABLE_PROFILE_SIGNAL_PLOT #ifdef ENABLE_INFLUXDB -void PHApp::testInfluxDB() -{ - if (influxDb_0 && (millis() - _last_influx_test_ms >= 5000)) - { +void PHApp::testInfluxDB() { + if (influxDb_0 && (millis() - _last_influx_test_ms >= 5000)) { _last_influx_test_ms = millis(); Point p("test_data"); // Create a local Point @@ -1294,37 +1208,30 @@ void PHApp::testInfluxDB() p.addField("on-off-1", random(2)); p.addField("on-off-2", random(2)); - if (influxDb_0->write(p) == E_OK) - { + if (influxDb_0->write(p) == E_OK) { Log.infoln("PHApp: Sent test data to InfluxDB."); } } } #endif -bool PHApp::isSlave() const -{ - return _is_slave; -} +bool PHApp::isSlave() const { return _is_slave; } -short PHApp::setSlave(bool value, bool sync) -{ +short PHApp::setSlave(bool value, bool sync) { _is_slave = value; - bool enabled = !value; // When slave=true, disable components; when slave=false, enable them + bool enabled = !value; // When slave=true, disable components; when + // slave=false, enable them #if defined(ENABLE_RS485) && defined(ENABLE_OMRON_E5) - if (rs485) - { + if (rs485) { RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevices = rs485->deviceManager.getMaxDevices(); - for (int i = 0; i < numDevices; ++i) - { - if (devices[i] != nullptr && devices[i]->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + for (int i = 0; i < numDevices; ++i) { + if (devices[i] != nullptr && + devices[i]->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) { OmronE5 *omron = static_cast(devices[i]); - if (omron) - { + if (omron) { omron->enable(enabled); } } @@ -1333,74 +1240,58 @@ short PHApp::setSlave(bool value, bool sync) #endif #ifdef ENABLE_AMPERAGE_BUDGET_MANAGER - if (pidManagerAmperage) - { + if (pidManagerAmperage) { pidManagerAmperage->enable(enabled); } #endif #ifdef ENABLE_LOADCELL_0 - if (loadCell_0) - { + if (loadCell_0) { loadCell_0->enable(enabled); } #endif #ifdef ENABLE_LOADCELL_1 - if (loadCell_1) - { + if (loadCell_1) { loadCell_1->enable(enabled); } #endif #ifdef ENABLE_PROFILE_TEMPERATURE - for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) - { - if (tempProfiles[i] != nullptr) - { + for (int i = 0; i < PROFILE_TEMPERATURE_COUNT; ++i) { + if (tempProfiles[i] != nullptr) { tempProfiles[i]->enable(enabled); } } #endif - if (sync) - { + if (sync) { updateRuntimeState(); } return E_OK; } -bool PHApp::getAllOmronStop() const -{ - return _all_omron_stop; -} +bool PHApp::getAllOmronStop() const { return _all_omron_stop; } -short PHApp::setAllOmronStop(bool value, bool sync) -{ +short PHApp::setAllOmronStop(bool value, bool sync) { _all_omron_stop = value; #if defined(ENABLE_RS485) && defined(ENABLE_OMRON_E5) - if (!rs485) - { + if (!rs485) { L_INFO("PHApp: No RS485 found"); return E_OK; } RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevices = rs485->deviceManager.getMaxDevices(); - for (int i = 0; i < numDevices; ++i) - { - if (devices[i] != nullptr && devices[i]->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + for (int i = 0; i < numDevices; ++i) { + if (devices[i] != nullptr && + devices[i]->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) { OmronE5 *omron = static_cast(devices[i]); - if (omron && omron->enabled()) - { - if (value) - { + if (omron && omron->enabled()) { + if (value) { omron->stop(); - } - else - { + } else { omron->run(); } } @@ -1414,74 +1305,59 @@ short PHApp::setAllOmronStop(bool value, bool sync) return E_OK; } -bool PHApp::getAllOmronComWrite() const -{ - return _all_omron_com_write; -} +bool PHApp::getAllOmronComWrite() const { return _all_omron_com_write; } -short PHApp::setAllOmronComWrite(bool value, bool sync) -{ +short PHApp::setAllOmronComWrite(bool value, bool sync) { _all_omron_com_write = value; #if defined(ENABLE_RS485) && defined(ENABLE_OMRON_E5) - if (!rs485) - { + if (!rs485) { L_INFO("PHApp: No RS485 found"); return E_OK; } RTU_Base *const *devices = rs485->deviceManager.getDevices(); int numDevices = rs485->deviceManager.getMaxDevices(); - for (int i = 0; i < numDevices; ++i) - { - if (devices[i] != nullptr && devices[i]->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) - { + for (int i = 0; i < numDevices; ++i) { + if (devices[i] != nullptr && + devices[i]->type == COMPONENT_TYPE::COMPONENT_TYPE_PID) { OmronE5 *omron = static_cast(devices[i]); - if (omron && omron->enabled()) - { + if (omron && omron->enabled()) { omron->setCommsWriting(value); } } } #endif - if (sync) - { + if (sync) { updateRuntimeState(); } return E_OK; } -short PHApp::setAppWarmup(bool value, bool sync) -{ +short PHApp::setAppWarmup(bool value, bool sync) { _app_warmup = value; - if (appSettings) - { + if (appSettings) { appSettings->set("heating", "ALWAYS_WARMUP", value); appSettings->save(); } - if (sync) - { + if (sync) { updateRuntimeState(); } return E_OK; } -short PHApp::setAppPidLag(bool value, bool sync) -{ +short PHApp::setAppPidLag(bool value, bool sync) { _app_pid_lag = value; - if (appSettings) - { + if (appSettings) { appSettings->set("heating", "PID_LAG_COMPENSATION", value); appSettings->save(); } - if (sync) - { + if (sync) { updateRuntimeState(); } return E_OK; } -void app_main() -{ +void app_main() { // Arduino will still call setup()/loop() } \ No newline at end of file diff --git a/src/PHApp.h b/src/PHApp.h index 49b96929..6d9f88fb 100644 --- a/src/PHApp.h +++ b/src/PHApp.h @@ -65,6 +65,7 @@ class InfluxDB; class IFTTTWebhook; class OmronE5; class DELTA_VFD; +class Settings; #if defined(ENABLE_AMPERAGE_BUDGET_MANAGER) bool PHApp_canUsePID(Component *owner, OmronE5 *device); diff --git a/src/PHAppState.cpp b/src/PHAppState.cpp index 2a6336a8..14937477 100644 --- a/src/PHAppState.cpp +++ b/src/PHAppState.cpp @@ -53,11 +53,14 @@ short PHApp::restoreState() } } } -#endif setAllOmronComWrite(runtimeState->allOmronComWrite, false); setAllOmronStop(runtimeState->allOmronStop, false); setAllOmronComWrite(runtimeState->allOmronComWrite, false); + L_INFO("Omron Stop state restored: %d", runtimeState->allOmronStop); + L_INFO("Slave state restored: %d", runtimeState->isSlave); + L_INFO("Omron Com Write state restored: %d", runtimeState->allOmronComWrite); +#endif for (const auto &state : runtimeState->loadedManagedComponents) { Component *comp = this->byId(state.id); @@ -72,10 +75,6 @@ short PHApp::restoreState() } } runtimeState->loadedManagedComponents.clear(); - - L_INFO("Omron Stop state restored: %d", runtimeState->allOmronStop); - L_INFO("Slave state restored: %d", runtimeState->isSlave); - L_INFO("Omron Com Write state restored: %d", runtimeState->allOmronComWrite); return E_OK; #else return E_OK; diff --git a/src/PHAppWeb.cpp b/src/PHAppWeb.cpp index f2180c4e..1c72143a 100644 --- a/src/PHAppWeb.cpp +++ b/src/PHAppWeb.cpp @@ -753,6 +753,7 @@ short PHApp::registerWebSocketHandlers(RESTServer *instance) client->text(responseStr); }); #endif +#ifdef ENABLE_AMPERAGE_BUDGET_MANAGER // Binary inspector for AmperageBudgetManager instance->registerWsCommandHandler("get_amp_state", [this](AsyncWebSocketClient *client, JsonVariant &json) { @@ -787,6 +788,9 @@ short PHApp::registerWebSocketHandlers(RESTServer *instance) } }); #endif +#endif + +#ifdef ENABLE_RS485 instance->registerWsCommandHandler("get_pending_ops", [this](AsyncWebSocketClient *client, JsonVariant &json) { RS485* rs485 = static_cast(this->byId(COMPONENT_KEY_RS485)); @@ -904,6 +908,7 @@ short PHApp::registerWebSocketHandlers(RESTServer *instance) String responseStr; serializeJson(responseDoc, responseStr); client->text(responseStr); }); +#endif return E_OK; } diff --git a/src/config-4-min.h b/src/config-4-min.h new file mode 100644 index 00000000..f9d0661d --- /dev/null +++ b/src/config-4-min.h @@ -0,0 +1,62 @@ +#ifndef CONFIG_4_MIN_H +#define CONFIG_4_MIN_H + +/** + * Minimal configuration for ESP32-P4 bring-up. + * Disables most peripherals and logic to isolate issues. + */ + +// --- Disable Features --- +#define DISABLE_MODBUS_TCP +#define DISABLE_RS485 +#define DISABLE_RS485_DEVICES + +// Disable Drivers/Components +#undef ENABLE_OMRON_E5 +#undef ENABLE_SAKO_VFD +#undef ENABLE_DELTA_VFD +#undef ENABLE_HY_VFD +#undef ENABLE_LOADCELL_0 +#undef ENABLE_LOADCELL_1 +#undef ENABLE_SOLENOID_0 +#undef ENABLE_SOLENOID_1 +#undef ENABLE_PRESS_CYLINDER +#undef ENABLE_JOYSTICK +#undef ENABLE_OPERATOR_SWITCH +#undef ENABLE_RELAYS +#undef ENABLE_STATUS +#undef ENABLE_FEEDBACK_3C +#undef ENABLE_FEEDBACK_BUZZER +#undef ENABLE_PID +#undef ENABLE_PROFILE_TEMPERATURE +#undef ENABLE_PROFILE_PRESSURE +#undef ENABLE_PROFILE_SIGNAL_PLOT +#undef ENABLE_MB_SCRIPT +#undef ENABLE_SETTINGS +#undef ENABLE_MODBUS_MIRROR +#undef ENABLE_EXTRUDER +#undef ENABLE_PLUNGER +#undef ENABLE_SETTINGS +#undef ENABLE_AMPERAGE_BUDGET_MANAGER +#undef PROFILE_SIGNAL_PLOT_COUNT +#undef PROFILE_TEMPERATURE_COUNT +#undef PROFILE_PRESSURE_COUNT +#undef NUM_OMRON_DEVICES + +#define NUM_OMRON_DEVICES 0 +#define PROFILE_PRESSURE_COUNT 0 +#define PROFILE_TEMPERATURE_COUNT 0 +#define PROFILE_SIGNAL_PLOT_COUNT 0 + +// Disable Profiler for now to reduce overhead +// #undef ENABLE_PROFILER + +// --- Drivers Override --- +// (Ensure these are definitely off if undef isn't enough due to logic order) +// You might need to check how these are used. If #ifdef ENABLE_X is used, #undef is fine. + +// Override Baud Rate to match P4 monitor_speed +#undef SERIAL_BAUD_RATE +#define SERIAL_BAUD_RATE 115200 + +#endif // CONFIG_4_MIN_H diff --git a/src/config-user.h b/src/config-user.h index 35ee0e34..da509b2c 100644 --- a/src/config-user.h +++ b/src/config-user.h @@ -2,7 +2,7 @@ #define CONFIG_USER_H #define ENABLE_OMRON_E5 -#define NUM_OMRON_DEVICES 4 +#define NUM_OMRON_DEVICES 8 #define ENABLE_AMPERAGE_BUDGET_MANAGER #define ENABLE_JOYSTICK @@ -26,4 +26,4 @@ #undef HMI_NAME #define HMI_NAME "cassandra" -#endif // CONFIG_USER_H \ No newline at end of file +#endif // CONFIG_USER_H diff --git a/src/config-validate.h b/src/config-validate.h index 1cc578ff..01193631 100644 --- a/src/config-validate.h +++ b/src/config-validate.h @@ -23,100 +23,113 @@ */ // WiFi and Network Features -#if (defined(ENABLE_WEBSERVER) || defined(ENABLE_REST_SERVER) || defined(ENABLE_WEBSOCKET) || defined(ENABLE_MODBUS_TCP)) && !defined(ENABLE_WIFI) - #error "Network features (WebServer, REST, WebSocket, ModbusTCP) require ENABLE_WIFI to be defined." +#if (defined(ENABLE_WEBSERVER) || defined(ENABLE_REST_SERVER) || \ + defined(ENABLE_WEBSOCKET) || defined(ENABLE_MODBUS_TCP)) && \ + !defined(ENABLE_WIFI) +#error \ + "Network features (WebServer, REST, WebSocket, ModbusTCP) require ENABLE_WIFI to be defined." #endif #ifdef ENABLE_LOGGING_TARGET_WEBSOCKET - #if !defined(ENABLE_LOGGER) - #error "ENABLE_LOGGING_TARGET_WEBSOCKET requires ENABLE_LOGGER." - #endif - #if !defined(ENABLE_WEBSOCKET) - #error "ENABLE_LOGGING_TARGET_WEBSOCKET requires ENABLE_WEBSOCKET." - #endif +#if !defined(ENABLE_LOGGER) +#error "ENABLE_LOGGING_TARGET_WEBSOCKET requires ENABLE_LOGGER." +#endif +#if !defined(ENABLE_WEBSOCKET) +#error "ENABLE_LOGGING_TARGET_WEBSOCKET requires ENABLE_WEBSOCKET." +#endif #endif #ifdef ENABLE_LOGGING_TARGET_FILE - #if !defined(ENABLE_LOGGER) - #error "ENABLE_LOGGING_TARGET_FILE requires ENABLE_LOGGER." - #endif - #if !defined(ENABLE_LITTLEFS) - #error "ENABLE_LOGGING_TARGET_FILE requires ENABLE_LITTLEFS." - #endif +#if !defined(ENABLE_LOGGER) +#error "ENABLE_LOGGING_TARGET_FILE requires ENABLE_LOGGER." +#endif +#if !defined(ENABLE_LITTLEFS) +#error "ENABLE_LOGGING_TARGET_FILE requires ENABLE_LITTLEFS." +#endif #endif - // RS485 and dependant components -#if (defined(ENABLE_OMRON_E5) || defined(ENABLE_SAKO_VFD)) && !defined(ENABLE_RS485) - #error "Omron E5 and SAKO VFD components require ENABLE_RS485." +#if (defined(ENABLE_OMRON_E5) || defined(ENABLE_SAKO_VFD)) && \ + !defined(ENABLE_RS485) +#error "Omron E5 and SAKO VFD components require ENABLE_RS485." #endif // High-level component dependencies #ifdef ENABLE_EXTRUDER - #if !defined(ENABLE_SAKO_VFD) - #error "ENABLE_EXTRUDER requires ENABLE_SAKO_VFD." - #endif +#if !defined(ENABLE_SAKO_VFD) +#error "ENABLE_EXTRUDER requires ENABLE_SAKO_VFD." +#endif #endif #ifdef ENABLE_PLUNGER - #if !defined(ENABLE_SAKO_VFD) && !defined(ENABLE_DELTA_VFD) - #error "ENABLE_PLUNGER requires ENABLE_SAKO_VFD or ENABLE_DELTA_VFD." - #endif - #if !defined(ENABLE_JOYSTICK) - #warning "ENABLE_PLUNGER is typically used with ENABLE_JOYSTICK for manual control." - #endif - #if !defined(MB_ANALOG_0) || !defined(MB_ANALOG_1) - #error "ENABLE_PLUNGER requires MB_ANALOG_0 and MB_ANALOG_1 for position feedback." - #endif +#if !defined(ENABLE_DELTA_VFD) +#error "ENABLE_PLUNGER requires ENABLE_DELTA_VFD." +#endif +#if !defined(ENABLE_JOYSTICK) +#warning \ + "ENABLE_PLUNGER is typically used with ENABLE_JOYSTICK for manual control." +#endif +#if !defined(MB_ANALOG_0) || !defined(MB_ANALOG_1) +#error \ + "ENABLE_PLUNGER requires MB_ANALOG_0 and MB_ANALOG_1 for position feedback." +#endif #endif #ifdef ENABLE_PRESS_CYLINDER - #if !defined(ENABLE_SOLENOID_0) - #error "ENABLE_PRESS_CYLINDER requires ENABLE_SOLENOID_0." - #endif - #if !defined(ENABLE_LOADCELL) - // #warning "ENABLE_PRESS_CYLINDER is typically used with ENABLE_LOADCELL for force feedback." - #endif +#if !defined(ENABLE_SOLENOID_0) +#error "ENABLE_PRESS_CYLINDER requires ENABLE_SOLENOID_0." +#endif +#if !defined(ENABLE_LOADCELL) +// #warning "ENABLE_PRESS_CYLINDER is typically used with ENABLE_LOADCELL for +// force feedback." +#endif #endif // Profile dependencies #if defined(ENABLE_PROFILE_TEMPERATURE) && !defined(ENABLE_OMRON_E5) - #error "ENABLE_PROFILE_TEMPERATURE requires ENABLE_OMRON_E5 to control heaters." +#error "ENABLE_PROFILE_TEMPERATURE requires ENABLE_OMRON_E5 to control heaters." #endif -#if (defined(ENABLE_PROFILE_TEMPERATURE) || defined(ENABLE_PROFILE_SIGNAL_PLOT)) && !defined(ENABLE_LITTLEFS) - #error "Temperature and Signal Profiles require LittleFS (ENABLE_LITTLEFS) to be enabled for storing plot data." +#if (defined(ENABLE_PROFILE_TEMPERATURE) || \ + defined(ENABLE_PROFILE_SIGNAL_PLOT)) && \ + !defined(ENABLE_LITTLEFS) +#error \ + "Temperature and Signal Profiles require LittleFS (ENABLE_LITTLEFS) to be enabled for storing plot data." #endif #ifdef ENABLE_AMPERAGE_BUDGET_MANAGER - #if !defined(ENABLE_OMRON_E5) - #error "ENABLE_AMPERAGE_BUDGET_MANAGER requires ENABLE_OMRON_E5." - #endif +#if !defined(ENABLE_OMRON_E5) +#error "ENABLE_AMPERAGE_BUDGET_MANAGER requires ENABLE_OMRON_E5." +#endif #endif // Platform-specific features #ifdef ENABLE_OPERATOR_SWITCH - #if !defined(PIN_OPERATOR_SWITCH_STOP) || !defined(PIN_OPERATOR_SWITCH_CYCLE) - #error "ENABLE_OPERATOR_SWITCH requires PIN_OPERATOR_SWITCH_STOP and PIN_OPERATOR_SWITCH_CYCLE to be defined (typically for ESP32 platform)." - #endif +#if !defined(PIN_OPERATOR_SWITCH_STOP) || !defined(PIN_OPERATOR_SWITCH_CYCLE) +#error \ + "ENABLE_OPERATOR_SWITCH requires PIN_OPERATOR_SWITCH_STOP and PIN_OPERATOR_SWITCH_CYCLE to be defined (typically for ESP32 platform)." +#endif #endif #ifdef ENABLE_FEEDBACK_3C - #if !defined(GPIO_PIN_CH4) || !defined(GPIO_PIN_CH5) || !defined(GPIO_PIN_CH6) - #error "ENABLE_FEEDBACK_3C requires GPIO_PIN_CH4, GPIO_PIN_CH5, and GPIO_PIN_CH6 to be defined (typically for ESP32 platform)." - #endif +#if !defined(GPIO_PIN_CH4) || !defined(GPIO_PIN_CH5) || !defined(GPIO_PIN_CH6) +#error \ + "ENABLE_FEEDBACK_3C requires GPIO_PIN_CH4, GPIO_PIN_CH5, and GPIO_PIN_CH6 to be defined (typically for ESP32 platform)." +#endif #endif #ifdef ENABLE_FEEDBACK_BUZZER - #if !defined(GPIO_PIN_CH3) - #error "ENABLE_FEEDBACK_BUZZER requires GPIO_PIN_CH3 to be defined (typically for ESP32 platform)." - #endif +#if !defined(GPIO_PIN_CH3) +#error \ + "ENABLE_FEEDBACK_BUZZER requires GPIO_PIN_CH3 to be defined (typically for ESP32 platform)." +#endif #endif #ifdef ENABLE_SOLENOID_0 - #if !defined(PIN_SOLENOID_0) - #error "ENABLE_SOLENOID_0 requires PIN_SOLENOID_0 to be defined (typically for ESP32 platform)." - #endif +#if !defined(PIN_SOLENOID_0) +#error \ + "ENABLE_SOLENOID_0 requires PIN_SOLENOID_0 to be defined (typically for ESP32 platform)." +#endif #endif /** @} */ // end of config_validation group diff --git a/src/config.h b/src/config.h index e216ea03..e703b5cf 100644 --- a/src/config.h +++ b/src/config.h @@ -3,6 +3,7 @@ #include #include + #include "config_adv.h" /////////////////////////////////////////////////////////////////////////////////////////////////// @@ -28,8 +29,7 @@ // // Component IDs // -typedef enum COMPONENT_KEY -{ +typedef enum COMPONENT_KEY { COMPONENT_KEY_LOGGER = 10, COMPONENT_KEY_SETTINGS = 11, COMPONENT_KEY_RUNTIME_STATE = 250, @@ -250,7 +250,7 @@ using namespace machinecontrol; // Motor // #define ENABLE_SAKO_VFD -#define MB_SAKO_VFD_SLAVE_ID 20 +// #define MB_SAKO_VFD_SLAVE_ID 30 #define MB_SAKO_VFD_READ_INTERVAL 100 // #define ENABLE_DELTA_VFD @@ -337,14 +337,26 @@ using namespace machinecontrol; #define ENABLE_WEBSERVER_WIFI_SETTINGS #define HMI_NAME "cassandra" +/////////////////////////////////////////// +// Test only +#define MB_SAKO_VFD_SLAVE_ID 30 +#define ENABLE_SAKO_VFD +// #define ENABLE_EXTRUDER +#define ENABLE_DELTA_VFD +#define ENABLE_PLUNGER + /////////////////////////////////////////////////////////////////////////////////////////////////// // // Configs (in this order!) // #include "config-extern.h" // External config settings - PlatformIO config +#include "config-network.h" // Network config settings #include "config-user.h" // User config settings - Overrides #include "config-validate.h" // Validate config settings (cheap compiler checks) -#include "config-network.h" // Network config settings + +#ifdef ENABLE_P4_MIN +#include "config-4-min.h" +#endif #include "app-logger.h" diff --git a/src/version.h b/src/version.h index 07d0284a..3cdab283 100644 --- a/src/version.h +++ b/src/version.h @@ -1,5 +1,5 @@ #ifndef VERSION_H #define VERSION_H -#define VERSION "0.9.0|piq-last|06711e05bf741268fe2feb829263a10b70050385" +#define VERSION "0.9.0|piq-last|fb402903d3aae592d0cc9f96d8ee5ef5570c4630" #define PACKAGE_URL "https://polymech.info/en/resources/cassandra/" #endif \ No newline at end of file