Skip to content

Commit

Permalink
Merge pull request #497 from bdring/Devt
Browse files Browse the repository at this point in the history
Devt
  • Loading branch information
bdring authored Jun 18, 2022
2 parents beb6886 + ded755b commit 59aed88
Show file tree
Hide file tree
Showing 56 changed files with 921 additions and 895 deletions.
15 changes: 9 additions & 6 deletions FluidNC/esp32/StepTimer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,15 @@ void IRAM_ATTR stepTimerStop() {

void stepTimerInit(uint32_t frequency, bool (*fn)(void)) {
timer_config_t config = {
.alarm_en = TIMER_ALARM_DIS,
.counter_en = TIMER_PAUSE,
.counter_dir = TIMER_COUNT_UP,
.auto_reload = TIMER_AUTORELOAD_EN,
// .clk_src = TIMER_SRC_CLK_DEFAULT,
.divider = fTimers / frequency,
alarm_en: TIMER_ALARM_DIS,
counter_en: TIMER_PAUSE,
intr_type: TIMER_INTR_LEVEL,
counter_dir: TIMER_COUNT_UP,
auto_reload: TIMER_AUTORELOAD_EN,
divider: fTimers / frequency,
# if SOC_TIMER_GROUP_SUPPORT_XTAL
clk_src: TIMER_SRC_CLK_DEFAULT,
# endif
};
timer_init(TIMER_GROUP_NUM, &config);
timer_set_counter_value(TIMER_GROUP_NUM, 0);
Expand Down
115 changes: 69 additions & 46 deletions FluidNC/src/Channel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,71 +8,94 @@
void Channel::flushRx() {
_linelen = 0;
_lastWasCR = false;
while (_queue.size()) {
_queue.pop();
}
}

bool Channel::lineComplete(char* line, char ch) {
// The objective here is to treat any of CR, LF, or CR-LF
// as a single line ending. When we see CR, we immediately
// complete the line, setting a flag to say that the last
// character was CR. When we see LF, if the last character
// was CR, we ignore the LF because the line has already
// been completed, otherwise we complete the line.
if (ch == '\n') {
if (_lastWasCR) {
_lastWasCR = false;
return false;
}
// if (_discarding) {
// _linelen = 0;
// _discarding = false;
// return nullptr;
// }

// Return the complete line
_line[_linelen] = '\0';
strcpy(line, _line);
_linelen = 0;
return true;
}
_lastWasCR = ch == '\r';
if (_lastWasCR) {
// Return the complete line
_line[_linelen] = '\0';
strcpy(line, _line);
_linelen = 0;
return true;
}
if (ch == '\b') {
// Simple editing for interactive input - backspace erases
if (_linelen) {
--_linelen;
}
return false;
}
if (_linelen < (Channel::maxLine - 1)) {
_line[_linelen++] = ch;
} else {
// report_status_message(Error::Overflow, this);
// _linelen = 0;
// Probably should discard the rest of the line too.
// _discarding = true;
}
return false;
}

Channel* Channel::pollLine(char* line) {
handle();
while (1) {
int ch = read();
int ch;
if (line && _queue.size()) {
ch = _queue.front();
_queue.pop();
} else {
ch = read();
}

// ch will only be negative if read() was called and returned -1
// The _queue path will return only nonnegative character values
if (ch < 0) {
break;
}
if (is_realtime_command(ch)) {
if (realtimeOkay(ch) && is_realtime_command(ch)) {
execute_realtime_command(static_cast<Cmd>(ch), *this);
continue;
}
if (!line) {
// If we are not able to handle a line we save the character
// until later
_queue.push(uint8_t(ch));
continue;
}
// The objective here is to treat any of CR, LF, or CR-LF
// as a single line ending. When we see CR, we immediately
// complete the line, setting a flag to say that the last
// character was CR. When we see LF, if the last character
// was CR, we ignore the LF because the line has already
// been completed, otherwise we complete the line.
if (ch == '\n') {
if (_lastWasCR) {
_lastWasCR = false;
continue;
}
// if (_discarding) {
// _linelen = 0;
// _discarding = false;
// return nullptr;
// }

// Return the complete line
_line[_linelen] = '\0';
strcpy(line, _line);
_linelen = 0;
return this;
}
_lastWasCR = ch == '\r';
if (_lastWasCR) {
// Return the complete line
_line[_linelen] = '\0';
strcpy(line, _line);
_linelen = 0;
if (line && lineComplete(line, ch)) {
return this;
}
if (ch == '\b') {
// Simple editing for interactive input - backspace erases
if (_linelen) {
--_linelen;
}
continue;
}
if (_linelen < (Channel::maxLine - 1)) {
_line[_linelen++] = ch;
} else {
// report_status_message(Error::Overflow, this);
// _linelen = 0;
// Probably should discard the rest of the line too.
// _discarding = true;
}
}
return nullptr;
}

void Channel::ack(Error status) {
switch (status) {
case Error::Ok: // Error::Ok
Expand Down
43 changes: 41 additions & 2 deletions FluidNC/src/Channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

#include "Error.h" // Error
#include <Stream.h>
#include <queue>
#include <freertos/FreeRTOS.h> // TickType_T

class Channel : public Stream {
public:
Expand All @@ -30,6 +32,8 @@ class Channel : public Stream {
bool _addCR = false;
char _lastWasCR = false;

std::queue<uint8_t> _queue;

public:
Channel(const char* name, bool addCR = false) : _name(name), _linelen(0), _addCR(addCR) {}
virtual ~Channel() = default;
Expand All @@ -38,6 +42,41 @@ class Channel : public Stream {
virtual Channel* pollLine(char* line);
virtual void ack(Error status);
const char* name() { return _name; }
virtual int rx_buffer_available() = 0;
virtual void flushRx();

// rx_buffer_available() is the number of bytes that can be sent without overflowing
// a reception buffer, even if the system is busy. Channels that can handle external
// input via an interrupt or other background mechanism should override it to return
// the remaining space that mechanism has available.
virtual int rx_buffer_available() { return 0; };

// flushRx() discards any characters that have already been received. It is used
// after a reset, so that anything already sent will not be processed.
virtual void flushRx();

// realtimeOkay() returns true if the channel can currently interpret the character as
// a Grbl realtime character. Some situations where it might return false are when
// the channel is being used for file upload or if the channel is doing line editing
// and is in the middle of an escape sequence that could include what would otherwise
// be a realtime character.
virtual bool realtimeOkay(char c) { return true; }

// lineComplete() accumulates the character into the line, returning true if a line
// end is seen.
virtual bool lineComplete(char* line, char c);

virtual size_t timedReadBytes(char* buffer, size_t length, TickType_t timeout) {
setTimeout(timeout);
return readBytes(buffer, length);
}
size_t timedReadBytes(uint8_t* buffer, size_t length, TickType_t timeout) { return timedReadBytes((char*)buffer, length, timeout); }

bool setCr(bool on) {
bool retval = _addCR;
_addCR = on;
return retval;
}

int peek() override { return -1; }
int read() override { return -1; }
int available() override { return 0; }
};
71 changes: 44 additions & 27 deletions FluidNC/src/Control.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,47 +5,64 @@

#include "Protocol.h" // rtSafetyDoor, etc

Control::Control() :
_safetyDoor(rtSafetyDoor, "Door", 'D'), _reset(rtReset, "Reset", 'R'), _feedHold(rtFeedHold, "FeedHold", 'H'),
_cycleStart(rtCycleStart, "CycleStart", 'S'), _macro0(rtButtonMacro0, "Macro 0", '0'), _macro1(rtButtonMacro1, "Macro 1", '1'),
_macro2(rtButtonMacro2, "Macro 2", '2'), _macro3(rtButtonMacro3, "Macro 3", '3') {}
Control::Control() {
// The SafetyDoor pin must be defined first because it is checked explicity in safety_door_ajar()
_pins.push_back(new ControlPin(rtSafetyDoor, "safety_door_pin", 'D'));
_pins.push_back(new ControlPin(rtReset, "reset_pin", 'R'));
_pins.push_back(new ControlPin(rtFeedHold, "feed_hold_pin", 'H'));
_pins.push_back(new ControlPin(rtCycleStart, "cycle_start_pin", 'S'));
_pins.push_back(new ControlPin(rtButtonMacro0, "macro0_pin", '0'));
_pins.push_back(new ControlPin(rtButtonMacro1, "macro1_pin", '1'));
_pins.push_back(new ControlPin(rtButtonMacro2, "macro2_pin", '2'));
_pins.push_back(new ControlPin(rtButtonMacro3, "macro3_pin", '3'));
}

void Control::init() {
_safetyDoor.init();
_reset.init();
_feedHold.init();
_cycleStart.init();
_macro0.init();
_macro1.init();
_macro2.init();
_macro3.init();
for (auto pin : _pins) {
pin->init();
}
}

void Control::group(Configuration::HandlerBase& handler) {
handler.item("safety_door_pin", _safetyDoor._pin);
handler.item("reset_pin", _reset._pin);
handler.item("feed_hold_pin", _feedHold._pin);
handler.item("cycle_start_pin", _cycleStart._pin);
handler.item("macro0_pin", _macro0._pin);
handler.item("macro1_pin", _macro1._pin);
handler.item("macro2_pin", _macro2._pin);
handler.item("macro3_pin", _macro3._pin);
for (auto pin : _pins) {
handler.item(pin->_legend, pin->_pin);
}
}

String Control::report() {
return _safetyDoor.report() + _reset.report() + _feedHold.report() + _cycleStart.report() + _macro0.report() + _macro1.report() +
_macro2.report() + _macro3.report();
String Control::report_status() {
String ret = "";
for (auto pin : _pins) {
if (pin->get()) {
ret += pin->_letter;
}
}
return ret;
}

bool Control::stuck() {
return _safetyDoor.get() || _reset.get() || _feedHold.get() || _cycleStart.get() || _macro0.get() || _macro1.get() || _macro2.get() ||
_macro3.get();
for (auto pin : _pins) {
if (pin->get()) {
return true;
}
}
return false;
}

bool Control::startup_check() {
bool ret = false;
for (auto pin : _pins) {
if (pin->get()) {
log_error(pin->_legend << " is active at startup");
ret = true;
}
}
return ret;
}

// Returns if safety door is ajar(T) or closed(F), based on pin state.
bool Control::system_check_safety_door_ajar() {
bool Control::safety_door_ajar() {
// If a safety door pin is not defined, this will return false
// because that is the default for the value field, which will
// never be changed for an undefined pin.
return _safetyDoor.get();
return _pins[0]->get();
}
21 changes: 7 additions & 14 deletions FluidNC/src/Control.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,32 +5,25 @@

#include "Configuration/Configurable.h"
#include "ControlPin.h"
#include <vector>

class Control : public Configuration::Configurable {
// private:
// TODO: Should we not just put this in an array so we can enumerate it easily?
public:
ControlPin _safetyDoor;
ControlPin _reset;
ControlPin _feedHold;
ControlPin _cycleStart;
ControlPin _macro0;
ControlPin _macro1;
ControlPin _macro2;
ControlPin _macro3;

public:
Control();

std::vector<ControlPin*> _pins;

// Initializes control pins.
void init();

// Configuration handlers.
void group(Configuration::HandlerBase& handler) override;

bool stuck();
bool system_check_safety_door_ajar();
String report();
bool safety_door_ajar();
String report_status();

bool startup_check();

~Control() = default;
};
23 changes: 11 additions & 12 deletions FluidNC/src/ControlPin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@
void IRAM_ATTR ControlPin::handleISR() {
bool pinState = _pin.read();
_value = pinState;
if (pinState) {
_rtVariable = pinState;

// Rate limit control pin events so switch bounce does not cause multiple events
if (pinState && (_debounceEnd == 0 || ((getCpuTicks() - _debounceEnd) >= 0))) {
_debounceEnd = usToEndTicks(debounceUs);
// We use 0 to mean that the debounce lockout is inactive,
// so if the end time happens to be 0, bump it up by one tick.
if (_debounceEnd == 0) {
_debounceEnd = 1;
}
_rtVariable = true;
}
}

Expand All @@ -25,16 +33,7 @@ void ControlPin::init() {
_pin.setAttr(attr);
_pin.attachInterrupt(ISRHandler, CHANGE, this);
_rtVariable = false;
_value = _pin.read();
// Control pins must start in inactive state
if (_value) {
log_error(_legend << " pin is active at startup");
rtAlarm = ExecAlarm::ControlPin;
}
}

String ControlPin::report() {
return get() ? String(_letter) : String("");
_value = _pin.read();
}

ControlPin::~ControlPin() {
Expand Down
Loading

0 comments on commit 59aed88

Please sign in to comment.