1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-02 02:42:36 +02:00

Fixed a bunch of bugs. Needs a lot more bug fixing probably.

This commit is contained in:
Stefan de Bruijn
2021-03-25 22:52:24 +01:00
parent ceebe6f262
commit faf8f44888
18 changed files with 229 additions and 82 deletions

View File

@@ -22,9 +22,9 @@
# include "src/Grbl.h" # include "src/Grbl.h"
void setup() { void setup() {
# ifdef PIN_DEBUG // # ifdef PIN_DEBUG
sleep(1000); delay(2000);
# endif // # endif
Serial.begin(115200); Serial.begin(115200);
grbl_init(); grbl_init();

View File

@@ -1,45 +1,8 @@
name: "6 Pack Controller StepStick XYZ" name: "Debug config"
board: bdring-6pack board: Debug-board
i2so:
bck: gpio.22
ws: gpio.17
data: gpio.21
axes: axes:
number_axis: 3 number_axis: 3
x:
steps_per_mm: 800
max_rate: 2000
acceleration: 25
max_travel: 1000
home_mpos: 10
gang1:
endstop:
dual: gpio.33:low # or: positive: gpio.33:low, negative: gpio.34:low
tmc_2130:
step: gpio.4
direction: gpio.16
run_current: 1.0
hold_current: 0.25
microsteps: 255
stallguard: 0
y:
gang1:
endstop: gpio.32:low
stepstick:
step: gpio.18
direction: gpio.18
gang2:
endstop: gpio.34:low
stepstick:
step: gpio.19
direction: gpio.19
coolant: coolant:
flood: gpio.12 flood: gpio.2
mist: gpio.13

View File

@@ -0,0 +1,13 @@
#include "AfterParse.h"
#include "Configurable.h"
#include <cstring>
namespace Configuration
{
void AfterParse::handleDetail(const char* name, Configurable* value) {
value->afterParse();
value->handle(*this);
}
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <vector>
#include "../Pin.h"
#include "HandlerBase.h"
namespace Configuration
{
class Configurable;
class AfterParse : public HandlerBase
{
AfterParse(const AfterParse&) = delete;
AfterParse& operator=(const AfterParse&) = delete;
protected:
void handleDetail(const char* name, Configurable* value) override;
bool matchesUninitialized(const char* name) override { return false; }
HandlerType handlerType() override { return HandlerType::AfterParse; }
public:
AfterParse() = default;
void handle(const char* name, bool& value) override { }
void handle(const char* name, int& value) override { }
void handle(const char* name, float& value) override { }
void handle(const char* name, double& value) override { }
void handle(const char* name, StringRange& value) override { }
void handle(const char* name, Pin& value) override { }
};
}

View File

@@ -20,8 +20,9 @@ namespace Configuration
virtual void validate() const = 0; virtual void validate() const = 0;
virtual void handle(HandlerBase& handler) = 0; virtual void handle(HandlerBase& handler) = 0;
virtual void afterParse() {}
// virtual const char* name() const = 0; // virtual const char* name() const = 0;
virtual ~Configurable() {} virtual ~Configurable() {}
}; };
} }

View File

@@ -5,8 +5,9 @@ namespace Configuration
enum struct HandlerType enum struct HandlerType
{ {
Parser, Parser,
AfterParse,
Runtime, Runtime,
Generator, Generator,
Validator Validator
}; };
} }

View File

@@ -33,7 +33,7 @@ namespace Configuration
handleLegacy(value, str); handleLegacy(value, str);
} }
else { else {
warn("Incorrect setting '" << start << "': cannot find '='."); log_warn("Incorrect setting '" << start << "': cannot find '='.");
} }
return true; return true;
} }
@@ -53,7 +53,7 @@ namespace Configuration
} }
if (!handled) { if (!handled) {
warn("Cannot find handler for $" << index << ". Setting was ignored."); log_warn("Cannot find handler for $" << index << ". Setting was ignored.");
} }
} }
} }

View File

@@ -5,12 +5,13 @@ namespace Configuration {
int line_; int line_;
int column_; int column_;
const char* description_; const char* description_;
const char* current_;
public: public:
ParseException() = default; ParseException() = default;
ParseException(const ParseException&) = default; ParseException(const ParseException&) = default;
ParseException(const char* start, const char* current, const char* description) : description_(description) { ParseException(const char* start, const char* current, const char* description) : description_(description), current_(current) {
line_ = 1; line_ = 1;
column_ = 1; column_ = 1;
while (start != current) { while (start != current) {
@@ -18,12 +19,14 @@ namespace Configuration {
++line_; ++line_;
column_ = 1; column_ = 1;
} }
++column_;
++start; ++start;
} }
} }
inline int LineNumber() const { return line_; } inline int LineNumber() const { return line_; }
inline int ColumnNumber() const { return column_; } inline int ColumnNumber() const { return column_; }
inline const char* Near() const { return current_; }
inline const char* What() const { return description_; } inline const char* What() const { return description_; }
}; };
} }

View File

@@ -14,7 +14,7 @@ namespace Configuration {
protected: protected:
void handleDetail(const char* name, Configuration::Configurable* value) override { void handleDetail(const char* name, Configuration::Configurable* value) override {
if (value != nullptr && parser_.is(name)) { if (value != nullptr && parser_.is(name)) {
debug("Parsing configurable " << name); log_debug("Parsing configurable " << name);
parser_.enter(); parser_.enter();
for (; !parser_.isEndSection(); parser_.moveNext()) { for (; !parser_.isEndSection(); parser_.moveNext()) {

View File

@@ -176,7 +176,7 @@ namespace Configuration {
} }
// Skip more whitespaces // Skip more whitespaces
while (!Eof() && IsSpace()) { while (!Eof() && IsWhiteSpace()) {
Inc(); Inc();
} }

View File

@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "TokenKind.h" #include "TokenKind.h"
#include "../Logging.h"
namespace Configuration { namespace Configuration {
@@ -24,7 +25,7 @@ namespace Configuration {
inline bool IsWhiteSpace() { inline bool IsWhiteSpace() {
char c = Current(); char c = Current();
return c == ' ' || c == '\t' || c == '\f'; return c == ' ' || c == '\t' || c == '\f' || c == '\r';
} }
inline bool IsEndLine() { return Current() == '\n'; } inline bool IsEndLine() { return Current() == '\n'; }

View File

@@ -25,12 +25,14 @@
void grbl_init() { void grbl_init() {
try { try {
Serial.println("Initializing WiFi...");
WiFi.persistent(false); WiFi.persistent(false);
WiFi.disconnect(true); WiFi.disconnect(true);
WiFi.enableSTA(false); WiFi.enableSTA(false);
WiFi.enableAP(false); WiFi.enableAP(false);
WiFi.mode(WIFI_OFF); WiFi.mode(WIFI_OFF);
Serial.println("Initializing serial communications...");
// Setup serial baud rate and interrupts // Setup serial baud rate and interrupts
serial_init(); serial_init();
grbl_msg_sendf( grbl_msg_sendf(
@@ -41,19 +43,26 @@ void grbl_init() {
#ifdef MACHINE_NAME #ifdef MACHINE_NAME
report_machine_type(CLIENT_SERIAL); report_machine_type(CLIENT_SERIAL);
#endif #endif
// Load Grbl settings from non-volatile storage // Load Grbl settings from non-volatile storage
Serial.println("Initializing settings...");
settings_init(); settings_init();
MachineConfig::instance()->load(); MachineConfig::instance()->load();
#ifdef USE_I2S_OUT #ifdef USE_I2S_OUT
Serial.println("Initializing I2SO...");
// The I2S out must be initialized before it can access the expanded GPIO port. Must be initialized _after_ settings! // The I2S out must be initialized before it can access the expanded GPIO port. Must be initialized _after_ settings!
i2s_out_init(); i2s_out_init();
#endif #endif
Serial.println("Initializing steppers...");
stepper_init(); // Configure stepper pins and interrupt timers stepper_init(); // Configure stepper pins and interrupt timers
Serial.println("Initializing axes...");
MachineConfig::instance()->_axes->read_settings(); MachineConfig::instance()->_axes->read_settings();
MachineConfig::instance()->_axes->init(); MachineConfig::instance()->_axes->init();
Serial.println("Initializing system...");
system_ini(); // Configure pinout pins and pin-change interrupt (Renamed due to conflict with esp32 files) system_ini(); // Configure pinout pins and pin-change interrupt (Renamed due to conflict with esp32 files)
memset(sys_position, 0, sizeof(sys_position)); // Clear machine position. memset(sys_position, 0, sizeof(sys_position)); // Clear machine position.
@@ -79,10 +88,15 @@ void grbl_init() {
sys.state = State::Alarm; sys.state = State::Alarm;
} }
#endif #endif
Serial.println("Initializing spindle...");
Spindles::Spindle::select(); Spindles::Spindle::select();
Serial.println("Initializing WiFi-config...");
#ifdef ENABLE_WIFI #ifdef ENABLE_WIFI
WebUI::wifi_config.begin(); WebUI::wifi_config.begin();
#endif #endif
Serial.println("Initializing Bluetooth...");
#ifdef ENABLE_BLUETOOTH #ifdef ENABLE_BLUETOOTH
WebUI::bt_config.begin(); WebUI::bt_config.begin();
#endif #endif

View File

@@ -16,6 +16,8 @@ DebugStream::~DebugStream() { std::cout << ']' << std::endl; }
#else #else
#include <Arduino.h>
DebugStream::DebugStream(const char* name) { DebugStream::DebugStream(const char* name) {
Serial.print("["); Serial.print("[");
Serial.print(name); Serial.print(name);

View File

@@ -2,8 +2,20 @@
#include "SimpleOutputStream.h" #include "SimpleOutputStream.h"
class DebugStream : public SimpleOutputStream // How to use logging? Well, the basics are pretty simple:
{ //
// - The syntax is like standard iostream's.
// - It is simplified though, so no ios or iomanip. But should be sufficient.
// - But, you wrap it in an 'info', 'debug', 'warn', 'error' or 'fatal'.
//
// The streams here ensure the data goes where it belongs, without too much
// buffer space being wasted.
//
// Example:
//
// log_info("Twelve is written as " << 12 << ", isn't it");
class DebugStream : public SimpleOutputStream {
public: public:
DebugStream(const char* name); DebugStream(const char* name);
void add(char c) override; void add(char c) override;
@@ -12,8 +24,34 @@ public:
#include "StringStream.h" #include "StringStream.h"
#define debug(x) { DebugStream ss("DBG "); ss << x; } // Note: these '{'..'}' scopes are here for a reason: the destructor should flush.
#define info(x) { DebugStream ss("INFO"); ss << x; } #define log_debug(x) \
#define warn(x) { DebugStream ss("WARN"); ss << x; } { \
#define error(x) { DebugStream ss("ERR "); ss << x; } DebugStream ss("DBG "); \
ss << x; \
}
#define log_info(x) \
{ \
DebugStream ss("INFO"); \
ss << x; \
}
#define log_warn(x) \
{ \
DebugStream ss("WARN"); \
ss << x; \
}
#define log_error(x) \
{ \
DebugStream ss("ERR "); \
ss << x; \
}
#define log_fatal(x) \
{ \
DebugStream ss("FATAL "); \
ss << x; \
Assert(false, "A fatal error occurred."); \
}

View File

@@ -8,12 +8,15 @@
#include "Configuration/ParserHandler.h" #include "Configuration/ParserHandler.h"
#include "Configuration/Validator.h" #include "Configuration/Validator.h"
#include "Configuration/AfterParse.h"
#include "Configuration/ParseException.h" #include "Configuration/ParseException.h"
#include <SPIFFS.h> #include <SPIFFS.h>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
// TODO FIXME: Split this file up into several files, perhaps put it in some folder and namespace Machine?
void Endstops::validate() const { void Endstops::validate() const {
if (!_dual.undefined()) { if (!_dual.undefined()) {
Assert(_positive.undefined(), "If dual endstops are defined, you cannot also define positive and negative endstops"); Assert(_positive.undefined(), "If dual endstops are defined, you cannot also define positive and negative endstops");
@@ -36,6 +39,11 @@ void Gang::handle(Configuration::HandlerBase& handler) {
handler.handle("endstops", _endstops); handler.handle("endstops", _endstops);
Motors::MotorFactory::handle(handler, _motor); Motors::MotorFactory::handle(handler, _motor);
} }
void Gang::afterParse() {
if (_motor == nullptr) {
_motor = new Motors::Nullmotor();
}
}
Gang::~Gang() { Gang::~Gang() {
delete _motor; delete _motor;
@@ -57,6 +65,14 @@ void Axis::handle(Configuration::HandlerBase& handler) {
} }
} }
void Axis::afterParse() {
for (size_t i = 0; i < MAX_NUMBER_GANGED; ++i) {
if (_gangs[i] == nullptr) {
_gangs[i] = new Gang();
}
}
}
// Checks if a motor matches this axis: // Checks if a motor matches this axis:
bool Axis::hasMotor(const Motors::Motor* const motor) const { bool Axis::hasMotor(const Motors::Motor* const motor) const {
for (uint8_t gang_index = 0; gang_index < MAX_NUMBER_GANGED; gang_index++) { for (uint8_t gang_index = 0; gang_index < MAX_NUMBER_GANGED; gang_index++) {
@@ -284,12 +300,21 @@ void Axes::handle(Configuration::HandlerBase& handler) {
tmp[0] = allAxis[a]; tmp[0] = allAxis[a];
tmp[1] = '\0'; tmp[1] = '\0';
if (handler.handlerType() == Configuration::HandlerType::Runtime || handler.handlerType() == Configuration::HandlerType::Parser) { if (handler.handlerType() == Configuration::HandlerType::Runtime || handler.handlerType() == Configuration::HandlerType::Parser ||
handler.handlerType() == Configuration::HandlerType::AfterParse) {
handler.handle(tmp, _axis[a]); handler.handle(tmp, _axis[a]);
} }
} }
} }
void Axes::afterParse() {
for (size_t i = 0; i < MAX_NUMBER_AXIS; ++i) {
if (_axis[i] == nullptr) {
_axis[i] = new Axis();
}
}
}
Axes::~Axes() { Axes::~Axes() {
for (int i = 0; i < MAX_NUMBER_AXIS; ++i) { for (int i = 0; i < MAX_NUMBER_AXIS; ++i) {
delete _axis[i]; delete _axis[i];
@@ -337,24 +362,61 @@ void MachineConfig::handle(Configuration::HandlerBase& handler) {
handler.handle("laser_mode", _laserMode); handler.handle("laser_mode", _laserMode);
} }
void MachineConfig::afterParse() {
if (_axes == nullptr) {
log_info("Axes config missing; building default axes.");
_axes = new Axes();
}
if (_coolant == nullptr) {
log_info("Coolant control config missing; building default coolant.");
_coolant = new CoolantControl();
}
if (_spi == nullptr) {
log_info("SPI config missing; building default SPI bus.");
_spi = new SPIBus();
}
if (_probe == nullptr) {
log_info("Probe config missing; building default probe.");
_probe = new Probe();
}
}
bool MachineConfig::load(const char* filename) { bool MachineConfig::load(const char* filename) {
if (!SPIFFS.begin(true)) { if (!SPIFFS.begin(true)) {
error("An error has occurred while mounting SPIFFS"); log_fatal("An error has occurred while mounting SPIFFS");
return false; return false;
} }
FILE* file = fopen(filename, "rb"); FILE* file = fopen(filename, "rb");
if (!file) { if (!file) {
error("There was an error opening the config file for reading"); log_fatal("There was an error opening the config file for reading");
return false; return false;
} }
// Regardless of what we do next, we _always_ want a MachineConfig instance.
// instance() is by reference, so we can just get rid of an old instance and
// create a new one here:
{
auto& machineConfig = instance();
if (machineConfig != nullptr) {
delete machineConfig;
}
machineConfig = new MachineConfig();
}
MachineConfig* machine = instance();
// Let's just read the entire file in one chunk for now. If we get // Let's just read the entire file in one chunk for now. If we get
// in trouble with this, we can cut it in pieces and read it per chunk. // in trouble with this, we can cut it in pieces and read it per chunk.
fseek(file, 0, SEEK_END); fseek(file, 0, SEEK_END);
auto filesize = ftell(file); auto filesize = ftell(file);
log_debug("Configuration file is " << int(filesize) << " bytes.");
fseek(file, 0, SEEK_SET); fseek(file, 0, SEEK_SET);
char* buffer = new char[filesize]; char* buffer = new char[filesize + 1];
long pos = 0; long pos = 0;
while (pos < filesize) { while (pos < filesize) {
@@ -366,11 +428,14 @@ bool MachineConfig::load(const char* filename) {
} }
fclose(file); fclose(file);
buffer[filesize] = 0;
log_debug("Read config file:\r\n" << buffer);
if (pos != filesize) { if (pos != filesize) {
delete[] buffer; delete[] buffer;
error("There was an error reading the config file"); log_error("There was an error reading the config file");
return false; return false;
} }
@@ -381,27 +446,28 @@ bool MachineConfig::load(const char* filename) {
Configuration::Parser parser(input.begin(), input.end()); Configuration::Parser parser(input.begin(), input.end());
Configuration::ParserHandler handler(parser); Configuration::ParserHandler handler(parser);
// Instance is by reference, so we can just get rid of an old instance and
// create a new one here:
if (instance() != nullptr) {
delete instance();
}
instance() = new MachineConfig();
MachineConfig* machine = instance();
for (; !parser.isEndSection(); parser.moveNext()) { for (; !parser.isEndSection(); parser.moveNext()) {
info("Parsing key " << parser.key().str()); log_info("Parsing key " << parser.key().str());
machine->handle(handler); machine->handle(handler);
} }
info("Done parsing machine config."); log_info("Done parsing machine config. Running after-parse tasks");
try {
Configuration::AfterParse afterParse;
machine->afterParse();
machine->handle(afterParse);
} catch (std::exception& ex) { log_info("Validation error: " << ex.what()); }
log_info("Validating machine config");
try { try {
Configuration::Validator validator; Configuration::Validator validator;
machine->validate();
machine->handle(validator); machine->handle(validator);
} catch (std::exception& ex) { info("Validation error: " << ex.what()); } } catch (std::exception& ex) { log_info("Validation error: " << ex.what()); }
info("Done validating machine config."); log_info("Done validating machine config.");
succesful = true; succesful = true;
@@ -410,13 +476,20 @@ bool MachineConfig::load(const char* filename) {
// That way, we can always check if the yaml is there, and if it's not, load the yaml.new. // That way, we can always check if the yaml is there, and if it's not, load the yaml.new.
} catch (const Configuration::ParseException& ex) { } catch (const Configuration::ParseException& ex) {
error("Configuration parse error: " << ex.What() << " @ " << ex.LineNumber() << ":" << ex.ColumnNumber()); auto startNear = ex.Near();
auto endNear = (startNear + 10) > (buffer + filesize) ? (buffer + filesize) : (startNear + 10);
StringRange near(startNear, endNear);
log_error("Configuration parse error: " << ex.What() << " @ " << ex.LineNumber() << ":" << ex.ColumnNumber() << " near " << near);
} catch (const AssertionFailed& ex) { } catch (const AssertionFailed& ex) {
// Get rid of buffer and return // Get rid of buffer and return
error("Configuration loading failed: " << ex.what()); log_error("Configuration loading failed: " << ex.what());
} catch (std::exception& ex) { error("Configuration validation error: " << ex.what()); } catch (...) { } catch (std::exception& ex) {
// Log exception:
log_error("Configuration validation error: " << ex.what());
} catch (...) {
// Get rid of buffer and return // Get rid of buffer and return
error("Unknown error occurred while processing configuration file."); log_error("Unknown error occurred while processing configuration file.");
} }
// Get rid of buffer and return // Get rid of buffer and return

View File

@@ -7,6 +7,8 @@
#include "CoolantControl.h" #include "CoolantControl.h"
#include "Probe.h" #include "Probe.h"
// TODO FIXME: Split this file up into several files, perhaps put it in some folder and namespace Machine?
namespace Motors { namespace Motors {
class Motor; class Motor;
} }
@@ -35,6 +37,7 @@ public:
// Configuration system helpers: // Configuration system helpers:
void validate() const override; void validate() const override;
void handle(Configuration::HandlerBase& handler) override; void handle(Configuration::HandlerBase& handler) override;
void afterParse() override;
~Gang(); ~Gang();
}; };
@@ -85,6 +88,7 @@ public:
// Configuration system helpers: // Configuration system helpers:
void validate() const override; void validate() const override;
void handle(Configuration::HandlerBase& handler) override; void handle(Configuration::HandlerBase& handler) override;
void afterParse() override;
// Checks if a motor matches this axis: // Checks if a motor matches this axis:
bool hasMotor(const Motors::Motor* const motor) const; bool hasMotor(const Motors::Motor* const motor) const;
@@ -119,6 +123,7 @@ public:
// Configuration helpers: // Configuration helpers:
void validate() const override; void validate() const override;
void handle(Configuration::HandlerBase& handler) override; void handle(Configuration::HandlerBase& handler) override;
void afterParse() override;
~Axes(); ~Axes();
}; };
@@ -199,7 +204,7 @@ public:
} else if (ch != ' ') { } else if (ch != ' ') {
// For convenience / layouting. // For convenience / layouting.
return false; return false;
} }
} }
if (tmp > 255) { if (tmp > 255) {
return false; return false;
@@ -325,6 +330,7 @@ public:
} }
void validate() const override; void validate() const override;
void afterParse() override;
void handle(Configuration::HandlerBase& handler) override; void handle(Configuration::HandlerBase& handler) override;
bool load(const char* file = "/spiffs/config.yaml"); bool load(const char* file = "/spiffs/config.yaml");

View File

@@ -30,7 +30,7 @@
void Probe::init() { void Probe::init() {
static bool show_init_msg = true; // used to show message only once. static bool show_init_msg = true; // used to show message only once.
if (_probePin != Pin::UNDEFINED) { if (!_probePin.undefined()) {
#ifdef DISABLE_PROBE_PIN_PULL_UP #ifdef DISABLE_PROBE_PIN_PULL_UP
_probePin.setAttr(Pin::Attr::Input); _probePin.setAttr(Pin::Attr::Input);
#else #else

View File

@@ -59,4 +59,4 @@ inline SimpleOutputStream& operator<<(SimpleOutputStream& lhs, StringRange v) {
inline SimpleOutputStream& operator<<(SimpleOutputStream& lhs, const Pin& v) { inline SimpleOutputStream& operator<<(SimpleOutputStream& lhs, const Pin& v) {
lhs.add(v); lhs.add(v);
return lhs; return lhs;
} }