diff --git a/FluidNC/src/Spindles/PlasmaSpindle.cpp b/FluidNC/src/Spindles/PlasmaSpindle.cpp new file mode 100644 index 000000000..e5ba6b28e --- /dev/null +++ b/FluidNC/src/Spindles/PlasmaSpindle.cpp @@ -0,0 +1,122 @@ +#include "PlasmaSpindle.h" + +#include "../System.h" // sys.abort + +/* + +PlasmaSpindle: + output_pin: gpio.13 + enable_pin: gpio.14 + arc_ok_pin: 'gpio.33:low' + arc_wait_ms: 1200 + tool_num: 0 + speed_map: 0=0.00% 1=100.00% + off_on_alarm: true + atc: + m6_macro: + +Ideas: + + - Maybe arc_wait_ms disables that feature + +*/ + +namespace Spindles { + + void PlasmaSpindle::init() { + if (_arc_ok_pin.defined()) { + _arcOkEventPin = new ArcOkEventPin("ArcOK", _arc_ok_pin, this); + _arcOkEventPin->init(); + } + + _arc_on = false; + + _enable_pin.setAttr(Pin::Attr::Output); + _arc_ok_pin.setAttr(Pin::Attr::Input); + + if (_speeds.size() == 0) { + // The default speed map for an On/Off spindle is off - 0% - + // for speed 0 and on - 100% - for any nonzero speedl + // In other words there is a step transition right at 0. + linearSpeeds(1, 100.0f); + } + setupSpeeds(1); + init_atc(); + config_message(); + } + + // prints the startup message of the spindle config + void PlasmaSpindle ::config_message() { + log_info(name() << " Ena:" << _enable_pin.name() << " Arc OK:" << _arc_ok_pin.name() << atc_info()); + } + + void PlasmaSpindle::setState(SpindleState state, SpindleSpeed speed) { + if (sys.abort) { + return; // Block during abort. + } + + // We always use mapSpeed() with the unmodified input speed so it sets + // sys.spindle_speed correctly. + uint32_t dev_speed = speed; // no mapping + if (state == SpindleState::Disable) { + _arc_on = false; + set_enable(false); + + } else { + // check arc OK is not on before starting + if (_arcOkEventPin->get()) { + log_error(name() << " arc_ok active before starting plasma"); + mc_critical(ExecAlarm::SpindleControl); + return; + } + + if (!wait_for_arc_ok()) { + return; + } + _arc_on = true; + set_enable(true); + } + } + + bool IRAM_ATTR PlasmaSpindle::wait_for_arc_ok() { + uint32_t wait_until_ms = millis() + _max_arc_wait; + while (millis() < wait_until_ms) { + if (_arcOkEventPin->get()) { + _arc_on = true; + return true; + } + protocol_execute_realtime(); + delay_ms(1); + } + _arc_on = false; + gc_state.modal.spindle = SpindleState::Disable; + mc_critical(ExecAlarm::SpindleControl); + log_error(name() << " failed to get arc OK signal"); + return false; // failed to get arc_ok + } + + void IRAM_ATTR PlasmaSpindle::set_output(uint32_t dev_speed) {} + + void IRAM_ATTR PlasmaSpindle::setSpeedfromISR(uint32_t dev_speed) {} + + void IRAM_ATTR PlasmaSpindle::set_enable(bool enable) { + if (_disable_with_zero_speed && sys.spindle_speed == 0) { + enable = false; + } + + _enable_pin.synchronousWrite(enable); + } + + void PlasmaSpindle::set_direction(bool Clockwise) {} + + void PlasmaSpindle::deinit() { + stop(); + _enable_pin.setAttr(Pin::Attr::Input); + _arc_ok_pin.setAttr(Pin::Attr::Input); + } + + // Configuration registration + namespace { + SpindleFactory::InstanceBuilder registration("PlasmaSpindle"); + } +} diff --git a/FluidNC/src/Spindles/PlasmaSpindle.h b/FluidNC/src/Spindles/PlasmaSpindle.h new file mode 100644 index 000000000..b1d535d87 --- /dev/null +++ b/FluidNC/src/Spindles/PlasmaSpindle.h @@ -0,0 +1,110 @@ +// Copyright (c) 2020 - Bart Dring +// Use of this source code is governed by a GPLv3 license that can be found in the LICENSE file. + +#pragma once + +/* + Experimental Plasma Spindle +*/ + +#include "Spindle.h" +#include "esp32-hal.h" // millis() +#include "../MotionControl.h" // mc_critical + +namespace Spindles { + // This is for an on/off spindle all RPMs above 0 are on + class PlasmaSpindle : public Spindle { + private: + class ArcOkEventPin : public EventPin { + private: + bool _value = false; + Pin* _pin = nullptr; + PlasmaSpindle* _parent; + + public: + ArcOkEventPin(const char* legend, Pin& pin, PlasmaSpindle* parent) : EventPin(nullptr, legend), _pin(&pin), _parent(parent) {} + + void init() { + if (_pin->undefined()) { + return; + } + _value = _pin->read(); + _pin->report(_legend); + _pin->setAttr(Pin::Attr::Input); + _pin->registerEvent(static_cast(this)); + update(_pin->read()); + } + void update(bool state) { _value = state; } + + // Differs from the base class version by sending the event on either edge + void trigger(bool active) override { + update(active); + if (!active && _parent->_arc_on) { + _parent->_arc_on = false; + send_alarm(ExecAlarm::AbortCycle); + } + } + + bool get() { return _value; } + }; + + private: + ArcOkEventPin* _arcOkEventPin; + + protected: + // This includes all items except direction_pin. direction_pin applies + // to most but not all of OnOff's derived classes. Derived classes that + // do not support direction_pin can invoke OnOff::groupCommon() instead + // of OnOff::group() + void groupCommon(Configuration::HandlerBase& handler) { + handler.item("enable_pin", _enable_pin); + handler.item("arc_ok_pin", _arc_ok_pin); + handler.item("arc_wait_ms", _max_arc_wait, 0, 3000); + Spindle::group(handler); + } + + public: + PlasmaSpindle(const char* name) : Spindle(name) {} + + PlasmaSpindle(const PlasmaSpindle&) = delete; + PlasmaSpindle(PlasmaSpindle&&) = delete; + PlasmaSpindle& operator=(const PlasmaSpindle&) = delete; + PlasmaSpindle& operator=(PlasmaSpindle&&) = delete; + + void init() override; + + void setSpeedfromISR(uint32_t dev_speed) override; + void setState(SpindleState state, SpindleSpeed speed) override; + void config_message() override; + + // Methods introduced by this base clase + virtual void set_direction(bool Clockwise); + virtual void set_enable(bool enable); + + bool wait_for_arc_ok(); + + // Configuration handlers: + void validate() override { Spindle::validate(); } + + void group(Configuration::HandlerBase& handler) override { groupCommon(handler); } + + virtual ~PlasmaSpindle() {} + + protected: + Pin _enable_pin; + Pin _arc_ok_pin; + + uint32_t _max_arc_wait = 1000; + + // TO DO. These are not used in the class + // _disable_with_zero_speed forces a disable when speed is 0 + bool _disable_with_zero_speed = false; + // _zero_speed_with_disable forces speed to 0 when disabled + bool _zero_speed_with_disable = false; + + bool _arc_on = false; + bool use_delay_settings() const override { return false; } + virtual void set_output(uint32_t speed); + virtual void deinit(); + }; +}