1
0
mirror of https://github.com/bdring/Grbl_Esp32.git synced 2025-09-01 02:21:46 +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"
void setup() {
# ifdef PIN_DEBUG
sleep(1000);
# endif
// # ifdef PIN_DEBUG
delay(2000);
// # endif
Serial.begin(115200);
grbl_init();

View File

@@ -1,45 +1,8 @@
name: "6 Pack Controller StepStick XYZ"
board: bdring-6pack
i2so:
bck: gpio.22
ws: gpio.17
data: gpio.21
name: "Debug config"
board: Debug-board
axes:
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:
flood: gpio.12
mist: gpio.13
flood: gpio.2

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 handle(HandlerBase& handler) = 0;
virtual void afterParse() {}
// virtual const char* name() const = 0;
virtual ~Configurable() {}
};
}
}

View File

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

View File

@@ -33,7 +33,7 @@ namespace Configuration
handleLegacy(value, str);
}
else {
warn("Incorrect setting '" << start << "': cannot find '='.");
log_warn("Incorrect setting '" << start << "': cannot find '='.");
}
return true;
}
@@ -53,7 +53,7 @@ namespace Configuration
}
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 column_;
const char* description_;
const char* current_;
public:
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;
column_ = 1;
while (start != current) {
@@ -18,12 +19,14 @@ namespace Configuration {
++line_;
column_ = 1;
}
++column_;
++start;
}
}
inline int LineNumber() const { return line_; }
inline int ColumnNumber() const { return column_; }
inline const char* Near() const { return current_; }
inline const char* What() const { return description_; }
};
}

View File

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

View File

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

View File

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

View File

@@ -25,12 +25,14 @@
void grbl_init() {
try {
Serial.println("Initializing WiFi...");
WiFi.persistent(false);
WiFi.disconnect(true);
WiFi.enableSTA(false);
WiFi.enableAP(false);
WiFi.mode(WIFI_OFF);
Serial.println("Initializing serial communications...");
// Setup serial baud rate and interrupts
serial_init();
grbl_msg_sendf(
@@ -41,19 +43,26 @@ void grbl_init() {
#ifdef MACHINE_NAME
report_machine_type(CLIENT_SERIAL);
#endif
// Load Grbl settings from non-volatile storage
Serial.println("Initializing settings...");
settings_init();
MachineConfig::instance()->load();
#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!
i2s_out_init();
#endif
Serial.println("Initializing steppers...");
stepper_init(); // Configure stepper pins and interrupt timers
Serial.println("Initializing axes...");
MachineConfig::instance()->_axes->read_settings();
MachineConfig::instance()->_axes->init();
Serial.println("Initializing system...");
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.
@@ -79,10 +88,15 @@ void grbl_init() {
sys.state = State::Alarm;
}
#endif
Serial.println("Initializing spindle...");
Spindles::Spindle::select();
Serial.println("Initializing WiFi-config...");
#ifdef ENABLE_WIFI
WebUI::wifi_config.begin();
#endif
Serial.println("Initializing Bluetooth...");
#ifdef ENABLE_BLUETOOTH
WebUI::bt_config.begin();
#endif

View File

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

View File

@@ -2,8 +2,20 @@
#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:
DebugStream(const char* name);
void add(char c) override;
@@ -12,8 +24,34 @@ public:
#include "StringStream.h"
#define debug(x) { DebugStream ss("DBG "); ss << x; }
#define info(x) { DebugStream ss("INFO"); ss << x; }
#define warn(x) { DebugStream ss("WARN"); ss << x; }
#define error(x) { DebugStream ss("ERR "); ss << x; }
// Note: these '{'..'}' scopes are here for a reason: the destructor should flush.
#define log_debug(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/Validator.h"
#include "Configuration/AfterParse.h"
#include "Configuration/ParseException.h"
#include <SPIFFS.h>
#include <cstdio>
#include <cstring>
// TODO FIXME: Split this file up into several files, perhaps put it in some folder and namespace Machine?
void Endstops::validate() const {
if (!_dual.undefined()) {
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);
Motors::MotorFactory::handle(handler, _motor);
}
void Gang::afterParse() {
if (_motor == nullptr) {
_motor = new Motors::Nullmotor();
}
}
Gang::~Gang() {
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:
bool Axis::hasMotor(const Motors::Motor* const motor) const {
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[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]);
}
}
}
void Axes::afterParse() {
for (size_t i = 0; i < MAX_NUMBER_AXIS; ++i) {
if (_axis[i] == nullptr) {
_axis[i] = new Axis();
}
}
}
Axes::~Axes() {
for (int i = 0; i < MAX_NUMBER_AXIS; ++i) {
delete _axis[i];
@@ -337,24 +362,61 @@ void MachineConfig::handle(Configuration::HandlerBase& handler) {
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) {
if (!SPIFFS.begin(true)) {
error("An error has occurred while mounting SPIFFS");
log_fatal("An error has occurred while mounting SPIFFS");
return false;
}
FILE* file = fopen(filename, "rb");
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;
}
// 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
// in trouble with this, we can cut it in pieces and read it per chunk.
fseek(file, 0, SEEK_END);
auto filesize = ftell(file);
log_debug("Configuration file is " << int(filesize) << " bytes.");
fseek(file, 0, SEEK_SET);
char* buffer = new char[filesize];
char* buffer = new char[filesize + 1];
long pos = 0;
while (pos < filesize) {
@@ -366,11 +428,14 @@ bool MachineConfig::load(const char* filename) {
}
fclose(file);
buffer[filesize] = 0;
log_debug("Read config file:\r\n" << buffer);
if (pos != filesize) {
delete[] buffer;
error("There was an error reading the config file");
log_error("There was an error reading the config file");
return false;
}
@@ -381,27 +446,28 @@ bool MachineConfig::load(const char* filename) {
Configuration::Parser parser(input.begin(), input.end());
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()) {
info("Parsing key " << parser.key().str());
log_info("Parsing key " << parser.key().str());
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 {
Configuration::Validator validator;
machine->validate();
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;
@@ -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.
} 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) {
// Get rid of buffer and return
error("Configuration loading failed: " << ex.what());
} catch (std::exception& ex) { error("Configuration validation error: " << ex.what()); } catch (...) {
log_error("Configuration loading failed: " << ex.what());
} catch (std::exception& ex) {
// Log exception:
log_error("Configuration validation error: " << ex.what());
} catch (...) {
// 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

View File

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

View File

@@ -30,7 +30,7 @@
void Probe::init() {
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
_probePin.setAttr(Pin::Attr::Input);
#else

View File

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