Update de grbl avec un plus grand buffer et un peu de doc en plus
This commit is contained in:
parent
c24dd1bb34
commit
dd41d3358a
2
Grbl_Esp32-master/.gitattributes
vendored
Normal file
2
Grbl_Esp32-master/.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
22
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
22
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/bug-report.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Use this template to report bugs.
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please answer the following questions.
|
||||
|
||||
What version of the firmware are you using?
|
||||
|
||||
Is the problem repeatable?
|
||||
|
||||
Under what conditions does the bug occur?
|
||||
|
||||
**Important** If you paste firmware code, please use [Markdown Code and Syntax Highlighting](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code) with language C++. Use the three back tick method.
|
||||
|
||||
```C++
|
||||
#define EASIER_TO_READ true
|
||||
```
|
16
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
16
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Please describe the feature you would like implemented**
|
||||
|
||||
**Why do you think this would improve Grbl_ESP32?**
|
||||
|
||||
**What do you need the feature for?**
|
||||
|
||||
**Will this feature appear to a lot of users?**
|
10
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/general-discussion.md
vendored
Normal file
10
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/general-discussion.md
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
name: General Discussion
|
||||
about: A general topic of interest to the group
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
22
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/problem-compiling-firmware.md
vendored
Normal file
22
Grbl_Esp32-master/.github/ISSUE_TEMPLATE/problem-compiling-firmware.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
---
|
||||
name: Problem Compiling Firmware
|
||||
about: Use this template to submit compiling issues
|
||||
title: Problems Compiling Firmware
|
||||
labels: help wanted
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
Please answer the following questions:
|
||||
|
||||
Have you read the [wiki regarding how to compile](https://github.com/bdring/Grbl_Esp32/wiki/Compiling-the-firmware)?
|
||||
|
||||
What version of the Arduino IDE are you using?
|
||||
|
||||
What version (commit date) of the [Arduino core for the ESP32](https://github.com/espressif/arduino-esp32) are you using?
|
||||
|
||||
Are you using the master branch of Grbl_ESP32?
|
||||
|
||||
Have you made any edits or configuration changes (list them) to the firmware?
|
||||
|
||||
Please paste the compiler error text here:
|
6
Grbl_Esp32-master/.gitignore
vendored
Normal file
6
Grbl_Esp32-master/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
.pioenvs/
|
||||
Thumbs.db
|
||||
.DS_Store
|
||||
*.orig
|
||||
embedded/node_modules
|
||||
embedded/dist
|
48
Grbl_Esp32-master/.travis.yml
Normal file
48
Grbl_Esp32-master/.travis.yml
Normal file
@ -0,0 +1,48 @@
|
||||
sudo: false
|
||||
|
||||
language: bash
|
||||
|
||||
os:
|
||||
- linux
|
||||
|
||||
before_script:
|
||||
- "export DISPLAY=:99.0"
|
||||
- sleep 3 # give xvfb some time to start
|
||||
- wget http://downloads.arduino.cc/arduino-1.8.5-linux64.tar.xz
|
||||
- tar xf arduino-1.8.5-linux64.tar.xz
|
||||
- mv arduino-1.8.5 $HOME/arduino_ide
|
||||
- cd $HOME/arduino_ide/hardware
|
||||
- mkdir esp32
|
||||
- cd esp32
|
||||
- git clone https://github.com/espressif/arduino-esp32.git esp32
|
||||
- cd esp32/tools
|
||||
- python get.py
|
||||
- cd ..
|
||||
- mv $TRAVIS_BUILD_DIR/libraries/ESP32SSDP $HOME/arduino_ide/libraries/
|
||||
- mv $TRAVIS_BUILD_DIR/libraries/arduinoWebSockets $HOME/arduino_ide/libraries/
|
||||
|
||||
script:
|
||||
- cd $TRAVIS_BUILD_DIR
|
||||
- source command.sh
|
||||
- export PATH="$HOME/arduino_ide:$PATH"
|
||||
- arduino --board esp32:esp32:esp32:PartitionScheme=min_spiffs,FlashFreq=40 --pref compiler.warning_level=all --save-prefs
|
||||
- sed -n '48,72p;73q' $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -i "s/\/\/#define ENABLE_BLUETOOTH/#define ENABLE_BLUETOOTH/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -i "s/#define ENABLE_BLUETOOTH/\/\/#define ENABLE_BLUETOOTH/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -i "s/\/\/#define ENABLE_WIFI/#define ENABLE_WIFI/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -n '48,72p;73q' $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- build_sketch $TRAVIS_BUILD_DIR/Grbl_Esp32/Grbl_Esp32.ino
|
||||
- sed -i "s/\/\/#define ENABLE_BLUETOOTH/#define ENABLE_BLUETOOTH/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -i "s/#define ENABLE_WIFI/\/\/#define ENABLE_WIFI/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -n '48,72p;73q' $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- build_sketch $TRAVIS_BUILD_DIR/Grbl_Esp32/Grbl_Esp32.ino
|
||||
- sed -i "s/\/\/#define ENABLE_BLUETOOTH/#define ENABLE_BLUETOOTH/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -i "s/\/\/#define ENABLE_WIFI/#define ENABLE_WIFI/g" $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- sed -n '48,72p;73q' $TRAVIS_BUILD_DIR/Grbl_Esp32/config.h
|
||||
- build_sketch $TRAVIS_BUILD_DIR/Grbl_Esp32/Grbl_Esp32.ino
|
||||
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: change
|
||||
on_failure: change
|
198
Grbl_Esp32-master/Grbl_Esp32/BTconfig.cpp
Normal file
198
Grbl_Esp32-master/Grbl_Esp32/BTconfig.cpp
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
BTconfig.cpp - Bluetooth functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
#include <Preferences.h>
|
||||
#include "BluetoothSerial.h"
|
||||
#include "BTconfig.h"
|
||||
#include "commands.h"
|
||||
#include "report.h"
|
||||
|
||||
BTConfig bt_config;
|
||||
BluetoothSerial SerialBT;
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
const uint8_t *esp_bt_dev_get_address(void);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
String BTConfig::_btname = "";
|
||||
String BTConfig::_btclient = "";
|
||||
|
||||
BTConfig::BTConfig(){
|
||||
}
|
||||
|
||||
BTConfig::~BTConfig(){
|
||||
end();
|
||||
}
|
||||
|
||||
static void my_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case ESP_SPP_SRV_OPEN_EVT://Server connection open
|
||||
{
|
||||
char str[18];
|
||||
str[17]='\0';
|
||||
uint8_t * addr = param->srv_open.rem_bda;
|
||||
sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
|
||||
BTConfig::_btclient = str;
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:BT Connected with %s]\r\n", str);
|
||||
}
|
||||
break;
|
||||
|
||||
case ESP_SPP_CLOSE_EVT://Client connection closed
|
||||
grbl_send(CLIENT_ALL,"[MSG:BT Disconnected]\r\n");
|
||||
BTConfig::_btclient="";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *BTConfig::info(){
|
||||
static String result;
|
||||
String tmp;
|
||||
result = "[MSG:";
|
||||
if(Is_BT_on()) {
|
||||
result += "Mode=BT:Name=";
|
||||
result += _btname;
|
||||
result += "(";
|
||||
result += device_address();
|
||||
result += "):Status=";
|
||||
if (SerialBT.hasClient()){
|
||||
result += "Connected with " + _btclient;
|
||||
} else result += "Not connected";
|
||||
}
|
||||
else result+="No BT";
|
||||
result+= "]\r\n";
|
||||
return result.c_str();
|
||||
}
|
||||
/**
|
||||
* Check if BlueTooth string is valid
|
||||
*/
|
||||
|
||||
bool BTConfig::isBTnameValid (const char * hostname){
|
||||
//limited size
|
||||
char c;
|
||||
if (strlen (hostname) > MAX_BTNAME_LENGTH || strlen (hostname) < MIN_BTNAME_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
//only letter and digit
|
||||
for (int i = 0; i < strlen (hostname); i++) {
|
||||
c = hostname[i];
|
||||
if (! (isdigit (c) || isalpha (c) || c == '_') ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* BTConfig::device_address(){
|
||||
const uint8_t* point = esp_bt_dev_get_address();
|
||||
static char str[18];
|
||||
str[17]='\0';
|
||||
sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", (int)point[0], (int)point[1], (int)point[2], (int)point[3], (int)point[4], (int)point[5]);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* begin WiFi setup
|
||||
*/
|
||||
void BTConfig::begin() {
|
||||
Preferences prefs;
|
||||
//stop active services
|
||||
end();
|
||||
prefs.begin(NAMESPACE, true);
|
||||
//Get hostname
|
||||
String defV = DEFAULT_BT_NAME;
|
||||
_btname = prefs.getString(BT_NAME_ENTRY, defV);
|
||||
int8_t wifiMode = prefs.getChar(ESP_RADIO_MODE, DEFAULT_RADIO_MODE);
|
||||
prefs.end();
|
||||
if (wifiMode == ESP_BT) {
|
||||
if (!SerialBT.begin(_btname))
|
||||
{
|
||||
report_status_message(STATUS_BT_FAIL_BEGIN, CLIENT_ALL);
|
||||
} else {
|
||||
SerialBT.register_callback(&my_spp_cb);
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:BT Started with %s]\r\n", _btname.c_str());
|
||||
}
|
||||
|
||||
}else end();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* End WiFi
|
||||
*/
|
||||
void BTConfig::end() {
|
||||
SerialBT.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset ESP
|
||||
*/
|
||||
void BTConfig::reset_settings(){
|
||||
Preferences prefs;
|
||||
prefs.begin(NAMESPACE, false);
|
||||
String sval;
|
||||
int8_t bbuf;
|
||||
bool error = false;
|
||||
sval = DEFAULT_BT_NAME;
|
||||
if (prefs.putString(BT_NAME_ENTRY, sval) == 0){
|
||||
error = true;
|
||||
}
|
||||
bbuf = DEFAULT_RADIO_MODE;
|
||||
if (prefs.putChar(ESP_RADIO_MODE, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
prefs.end();
|
||||
if (error) {
|
||||
grbl_send(CLIENT_ALL,"[MSG:BT reset error]\r\n");
|
||||
} else {
|
||||
grbl_send(CLIENT_ALL,"[MSG:BT reset done]\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if BT is on and working
|
||||
*/
|
||||
bool BTConfig::Is_BT_on(){
|
||||
return btStarted();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle not critical actions that must be done in sync environement
|
||||
*/
|
||||
void BTConfig::handle() {
|
||||
//If needed
|
||||
COMMANDS::wait(0);
|
||||
}
|
||||
|
||||
|
||||
#endif // ENABLE_BLUETOOTH
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
65
Grbl_Esp32-master/Grbl_Esp32/BTconfig.h
Normal file
65
Grbl_Esp32-master/Grbl_Esp32/BTconfig.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
BTconfig.h - Bluetooth functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
|
||||
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
|
||||
#endif
|
||||
|
||||
//Preferences entries
|
||||
#define BT_NAME_ENTRY "BT_NAME"
|
||||
|
||||
//defaults values
|
||||
#define DEFAULT_BT_NAME "btgrblesp"
|
||||
|
||||
|
||||
//boundaries
|
||||
#define MAX_BTNAME_LENGTH 32
|
||||
#define MIN_BTNAME_LENGTH 1
|
||||
|
||||
#define BT_EVENT_DISCONNECTED 0
|
||||
#define BT_EVENT_CONNECTED 1
|
||||
|
||||
|
||||
#ifndef _BT_CONFIG_H
|
||||
#define _BT_CONFIG_H
|
||||
#include "BluetoothSerial.h"
|
||||
extern BluetoothSerial SerialBT;
|
||||
|
||||
class BTConfig {
|
||||
public:
|
||||
BTConfig();
|
||||
~BTConfig();
|
||||
static const char *info();
|
||||
static void BTEvent(uint8_t event);
|
||||
static bool isBTnameValid (const char * hostname);
|
||||
static String BTname(){return _btname;}
|
||||
static const char* device_address();
|
||||
static void begin();
|
||||
static void end();
|
||||
static void handle();
|
||||
static void reset_settings();
|
||||
static bool Is_BT_on();
|
||||
static String _btclient;
|
||||
private :
|
||||
static String _btname;
|
||||
};
|
||||
|
||||
extern BTConfig bt_config;
|
||||
|
||||
#endif
|
131
Grbl_Esp32-master/Grbl_Esp32/Grbl_Esp32.ino
Normal file
131
Grbl_Esp32-master/Grbl_Esp32/Grbl_Esp32.ino
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
Grbl_ESP32.ino - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
// Declare system global variable structure
|
||||
system_t sys;
|
||||
int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
#ifdef DEBUG
|
||||
volatile uint8_t sys_rt_exec_debug;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
|
||||
serial_init(); // Setup serial baud rate and interrupts
|
||||
settings_init(); // Load Grbl settings from EEPROM
|
||||
|
||||
stepper_init(); // Configure stepper pins and interrupt timers
|
||||
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.
|
||||
|
||||
#ifdef USE_PEN_SERVO
|
||||
servo_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_SERVO_AXES
|
||||
init_servos();
|
||||
#endif
|
||||
|
||||
#ifdef USE_PEN_SOLENOID
|
||||
solenoid_init();
|
||||
#endif
|
||||
|
||||
#ifdef USE_MACHINE_INIT
|
||||
machine_init(); // user supplied function for special initialization
|
||||
#endif
|
||||
|
||||
// Initialize system state.
|
||||
#ifdef FORCE_INITIALIZATION_ALARM
|
||||
// Force Grbl into an ALARM state upon a power-cycle or hard reset.
|
||||
sys.state = STATE_ALARM;
|
||||
#else
|
||||
sys.state = STATE_IDLE;
|
||||
#endif
|
||||
|
||||
// Check for power-up and set system alarm if homing is enabled to force homing cycle
|
||||
// by setting Grbl's alarm state. Alarm locks out all g-code commands, including the
|
||||
// startup scripts, but allows access to settings and internal commands. Only a homing
|
||||
// cycle '$H' or kill alarm locks '$X' will disable the alarm.
|
||||
// NOTE: The startup script will run after successful completion of the homing cycle, but
|
||||
// not after disabling the alarm locks. Prevents motion startup blocks from crashing into
|
||||
// things uncontrollably. Very bad.
|
||||
#ifdef HOMING_INIT_LOCK
|
||||
if (bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) { sys.state = STATE_ALARM; }
|
||||
#endif
|
||||
#ifdef ENABLE_WIFI
|
||||
wifi_config.begin();
|
||||
#endif
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
bt_config.begin();
|
||||
#endif
|
||||
inputBuffer.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
// Reset system variables.
|
||||
uint8_t prior_state = sys.state;
|
||||
memset(&sys, 0, sizeof(system_t)); // Clear system struct variable.
|
||||
sys.state = prior_state;
|
||||
sys.f_override = DEFAULT_FEED_OVERRIDE; // Set to 100%
|
||||
sys.r_override = DEFAULT_RAPID_OVERRIDE; // Set to 100%
|
||||
sys.spindle_speed_ovr = DEFAULT_SPINDLE_SPEED_OVERRIDE; // Set to 100%
|
||||
memset(sys_probe_position,0,sizeof(sys_probe_position)); // Clear probe position.
|
||||
sys_probe_state = 0;
|
||||
sys_rt_exec_state = 0;
|
||||
sys_rt_exec_alarm = 0;
|
||||
sys_rt_exec_motion_override = 0;
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
|
||||
// Reset Grbl primary systems.
|
||||
serial_reset_read_buffer(CLIENT_ALL); // Clear serial read buffer
|
||||
|
||||
gc_init(); // Set g-code parser to default state
|
||||
|
||||
spindle_init();
|
||||
coolant_init();
|
||||
limits_init();
|
||||
probe_init();
|
||||
|
||||
plan_reset(); // Clear block buffer and planner variables
|
||||
st_reset(); // Clear stepper subsystem variables
|
||||
// Sync cleared gcode and planner positions to current system position.
|
||||
plan_sync_position();
|
||||
gc_sync_position();
|
||||
|
||||
|
||||
|
||||
// put your main code here, to run repeatedly:
|
||||
report_init_message(CLIENT_ALL);
|
||||
|
||||
// Start Grbl main loop. Processes program inputs and executes them.
|
||||
protocol_main_loop();
|
||||
|
||||
}
|
324
Grbl_Esp32-master/Grbl_Esp32/atari_1020.cpp
Normal file
324
Grbl_Esp32-master/Grbl_Esp32/atari_1020.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
/*
|
||||
atari_1020.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
--------------------------------------------------------------
|
||||
|
||||
This contains all the special features required to control an
|
||||
Atari 1010 Pen Plotter
|
||||
*/
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef ATARI_1020
|
||||
|
||||
#define HOMING_PHASE_FULL_APPROACH 0 // move to right end
|
||||
#define HOMING_PHASE_CHECK 1 // check reed switch
|
||||
#define HOMING_PHASE_RETRACT 2 // retract
|
||||
#define HOMING_PHASE_SHORT_APPROACH 3 // retract
|
||||
|
||||
static TaskHandle_t solenoidSyncTaskHandle = 0;
|
||||
static TaskHandle_t atariHomingTaskHandle = 0;
|
||||
uint16_t solenoid_pull_count;
|
||||
bool atari_homing = false;
|
||||
uint8_t homing_phase = HOMING_PHASE_FULL_APPROACH;
|
||||
uint8_t current_tool;
|
||||
|
||||
void machine_init()
|
||||
{
|
||||
solenoid_pull_count = 0; // initialize
|
||||
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Atari 1020 Solenoid]\r\n");
|
||||
|
||||
// setup PWM channel
|
||||
ledcSetup(SOLENOID_CHANNEL_NUM, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
|
||||
ledcAttachPin(SOLENOID_PEN_PIN, SOLENOID_CHANNEL_NUM);
|
||||
|
||||
pinMode(SOLENOID_DIRECTION_PIN, OUTPUT); // this sets the direction of the solenoid current
|
||||
pinMode(REED_SW_PIN, INPUT_PULLUP); // external pullup required
|
||||
|
||||
// setup a task that will calculate solenoid position
|
||||
xTaskCreatePinnedToCore( solenoidSyncTask, // task
|
||||
"solenoidSyncTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&solenoidSyncTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
// setup a task that will do the custom homing sequence
|
||||
xTaskCreatePinnedToCore( atari_home_task, // task
|
||||
"atari_home_task", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&atariHomingTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
}
|
||||
|
||||
// this task tracks the Z position and sets the solenoid
|
||||
void solenoidSyncTask(void *pvParameters)
|
||||
{
|
||||
int32_t current_position[N_AXIS]; // copy of current location
|
||||
float m_pos[N_AXIS]; // machine position in mm
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xSolenoidFrequency = SOLENOID_TASK_FREQ; // in ticks (typically ms)
|
||||
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while(true) { // don't ever return from this or the task dies
|
||||
|
||||
memcpy(current_position,sys_position,sizeof(sys_position)); // get current position in step
|
||||
system_convert_array_steps_to_mpos(m_pos,current_position); // convert to millimeters
|
||||
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
|
||||
|
||||
vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
// to do...have this return a true or false. This could be used by the normal homing feature to
|
||||
// continue with regular homing after setup
|
||||
// return true if this completes homing
|
||||
|
||||
bool user_defined_homing() {
|
||||
// create and start a task to do the special homing
|
||||
homing_phase = HOMING_PHASE_FULL_APPROACH;
|
||||
atari_homing = true;
|
||||
return true; // this does it...skip the rest of mc_homing_cycle(...)
|
||||
}
|
||||
|
||||
/*
|
||||
Do a custom homing routine.
|
||||
|
||||
A task is used because it needs to wait until until idle after each move.
|
||||
|
||||
1) Do a full travel move to the right. OK to stall if the pen started closer
|
||||
2) Check for pen 1
|
||||
3) If fail Retract
|
||||
4) move to right end
|
||||
5) Check...
|
||||
....repeat up to 12 times to try to find pen one
|
||||
|
||||
TODO can the retract, move back be 1 phase rather than 2?
|
||||
|
||||
*/
|
||||
void atari_home_task(void *pvParameters) {
|
||||
uint8_t homing_attempt = 0; // how many times have we tried to home
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xHomingTaskFrequency = 100; // in ticks (typically ms) .... need to make sure there is enough time to get out of idle
|
||||
char gcode_line[20];
|
||||
|
||||
while(true) { // this task will only last as long as it is homing
|
||||
|
||||
if (atari_homing) {
|
||||
// must be in idle or alarm state
|
||||
if (sys.state == STATE_IDLE) {
|
||||
switch(homing_phase) {
|
||||
case HOMING_PHASE_FULL_APPROACH: // a full width move to insure it hits left end
|
||||
inputBuffer.push("G90G0Z1\r"); // lift the pen
|
||||
sprintf(gcode_line, "G91G0X%3.2f\r", -ATARI_PAPER_WIDTH + ATARI_HOME_POS - 3.0); // plus a little extra
|
||||
inputBuffer.push(gcode_line);
|
||||
homing_attempt = 1;
|
||||
homing_phase = HOMING_PHASE_CHECK;
|
||||
break;
|
||||
case HOMING_PHASE_CHECK: // check the limits switch
|
||||
if (digitalRead(REED_SW_PIN) == 0) { // see if reed switch is grounded
|
||||
inputBuffer.push("G4P0.1\n"); // dramtic pause
|
||||
|
||||
sys_position[X_AXIS] = ATARI_HOME_POS * settings.steps_per_mm[X_AXIS];
|
||||
sys_position[Y_AXIS] = 0.0;
|
||||
sys_position[Z_AXIS] = 1.0 * settings.steps_per_mm[Y_AXIS];
|
||||
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
|
||||
inputBuffer.push(gcode_line);
|
||||
|
||||
current_tool = 1; // local copy for reference...until actual M6 change
|
||||
gc_state.tool = current_tool;
|
||||
atari_homing = false; // done with homing sequence
|
||||
}
|
||||
else {
|
||||
homing_phase = HOMING_PHASE_RETRACT;
|
||||
homing_attempt++;
|
||||
}
|
||||
break;
|
||||
case HOMING_PHASE_RETRACT:
|
||||
sprintf(gcode_line, "G0X%3.2f\r", -ATARI_HOME_POS);
|
||||
inputBuffer.push(gcode_line);
|
||||
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS);
|
||||
inputBuffer.push(gcode_line);
|
||||
homing_phase = HOMING_PHASE_CHECK;
|
||||
break;
|
||||
default:
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Homing phase error %d]\r\n", homing_phase);
|
||||
atari_homing = false;; // kills task
|
||||
break;
|
||||
}
|
||||
|
||||
if (homing_attempt > ATARI_HOMING_ATTEMPTS) { // try all positions plus 1
|
||||
grbl_send(CLIENT_SERIAL, "[MSG: Atari homing failed]\r\n");
|
||||
inputBuffer.push("G90\r");
|
||||
atari_homing = false;;
|
||||
}
|
||||
}
|
||||
}
|
||||
vTaskDelayUntil(&xLastWakeTime, xHomingTaskFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// calculate and set the PWM value for the servo
|
||||
void calc_solenoid(float penZ)
|
||||
{
|
||||
bool isPenUp;
|
||||
static bool previousPenState = false;
|
||||
uint32_t solenoid_pen_pulse_len; // duty cycle of solenoid
|
||||
|
||||
isPenUp = ( (penZ > 0) || (sys.state == STATE_ALARM) ); // is pen above Z0 or is there an alarm
|
||||
|
||||
// if the state has not change, we only count down to the pull time
|
||||
if (previousPenState == isPenUp) { // if state is unchanged
|
||||
if (solenoid_pull_count > 0) {
|
||||
solenoid_pull_count--;
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // stay at full power while counting down
|
||||
}
|
||||
else {
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD; // pull in delay has expired so lower duty cycle
|
||||
}
|
||||
}
|
||||
else { // pen direction has changed
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_PULL; // go to full power
|
||||
solenoid_pull_count = SOLENOID_PULL_DURATION; // set the time to count down
|
||||
}
|
||||
|
||||
previousPenState = isPenUp; // save the prev state
|
||||
|
||||
digitalWrite(SOLENOID_DIRECTION_PIN, isPenUp);
|
||||
|
||||
// skip setting value if it is unchanged
|
||||
if (ledcRead(SOLENOID_CHANNEL_NUM) == solenoid_pen_pulse_len)
|
||||
return;
|
||||
|
||||
// update the PWM value
|
||||
// ledcWrite appears to have issues with interrupts, so make this a critical section
|
||||
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL(&myMutex);
|
||||
ledcWrite(SOLENOID_CHANNEL_NUM, solenoid_pen_pulse_len);
|
||||
portEXIT_CRITICAL(&myMutex);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
A tool (pen) change is done by bumping the carriage against the right edge 3 times per
|
||||
position change. Pen 1-4 is valid range.
|
||||
*/
|
||||
void user_tool_change(uint8_t new_tool) {
|
||||
uint8_t move_count;
|
||||
char gcode_line[20];
|
||||
|
||||
protocol_buffer_synchronize(); // wait for all previous moves to complete
|
||||
|
||||
if ((new_tool < 1) || (new_tool > MAX_PEN_NUMBER)) {
|
||||
grbl_sendf(CLIENT_ALL, "[MSG: Requested Pen#%d is out of 1-4 range]\r\n", new_tool);
|
||||
return;
|
||||
}
|
||||
|
||||
if (new_tool == current_tool)
|
||||
return;
|
||||
|
||||
if (new_tool > current_tool) {
|
||||
move_count = BUMPS_PER_PEN_CHANGE * (new_tool - current_tool);
|
||||
}
|
||||
else {
|
||||
move_count = BUMPS_PER_PEN_CHANGE * ((MAX_PEN_NUMBER - current_tool) + new_tool);
|
||||
}
|
||||
sprintf(gcode_line, "G0Z%3.2f\r", ATARI_TOOL_CHANGE_Z); // go to tool change height
|
||||
inputBuffer.push(gcode_line);
|
||||
for (uint8_t i = 0; i < move_count; i++) {
|
||||
sprintf(gcode_line, "G0X%3.2f\r", ATARI_HOME_POS); //
|
||||
inputBuffer.push(gcode_line);
|
||||
inputBuffer.push("G0X0\r");
|
||||
}
|
||||
|
||||
current_tool = new_tool;
|
||||
|
||||
grbl_sendf(CLIENT_ALL, "[MSG: Change to Pen#%d]\r\n", current_tool);
|
||||
|
||||
}
|
||||
|
||||
// move from current tool to next tool....
|
||||
void atari_next_pen() {
|
||||
if (current_tool < MAX_PEN_NUMBER) {
|
||||
gc_state.tool = current_tool + 1;
|
||||
}
|
||||
else {
|
||||
gc_state.tool = 1;
|
||||
}
|
||||
user_tool_change(gc_state.tool);
|
||||
}
|
||||
|
||||
// Polar coaster has macro buttons, this handles those button pushes.
|
||||
void user_defined_macro(uint8_t index)
|
||||
{
|
||||
char gcode_line[20];
|
||||
|
||||
switch (index) {
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_0:
|
||||
grbl_send(CLIENT_SERIAL, "[MSG: Pen Switch]\r\n");
|
||||
inputBuffer.push("$H\r");
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_1:
|
||||
grbl_send(CLIENT_SERIAL, "[MSG: Color Switch]\r\n");
|
||||
atari_next_pen();
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); // alway return to right side to reduce home travel stalls
|
||||
inputBuffer.push(gcode_line);
|
||||
break;
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_2:
|
||||
// feed out some paper and reset the Y 0
|
||||
grbl_send(CLIENT_SERIAL, "[MSG: Paper Switch]\r\n");
|
||||
inputBuffer.push("G0Y-25\r");
|
||||
inputBuffer.push("G4P0.1\r"); // sync...forces wait for planner to clear
|
||||
sys_position[Y_AXIS] = 0.0; // reset the Y position
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG: Unknown Switch %d]\r\n", index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void user_m30() {
|
||||
char gcode_line[20];
|
||||
sprintf(gcode_line, "G90G0X%3.2f\r", ATARI_PAPER_WIDTH); //
|
||||
inputBuffer.push(gcode_line);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
173
Grbl_Esp32-master/Grbl_Esp32/atari_1020.h
Normal file
173
Grbl_Esp32-master/Grbl_Esp32/atari_1020.h
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
atari_1020.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
This contains all the special features required to control an
|
||||
Atari 1010 Pen Plotter
|
||||
*/
|
||||
|
||||
#define CPU_MAP_NAME "CPU_MAP_ATARI_1020"
|
||||
|
||||
// ================== CPU MAP ======================
|
||||
#define USE_UNIPOLAR
|
||||
|
||||
#define X_UNIPOLAR
|
||||
#define X_PIN_PHASE_0 GPIO_NUM_13
|
||||
#define X_PIN_PHASE_1 GPIO_NUM_21
|
||||
#define X_PIN_PHASE_2 GPIO_NUM_16
|
||||
#define X_PIN_PHASE_3 GPIO_NUM_22
|
||||
|
||||
#define Y_UNIPOLAR
|
||||
#define Y_PIN_PHASE_0 GPIO_NUM_25
|
||||
#define Y_PIN_PHASE_1 GPIO_NUM_27
|
||||
#define Y_PIN_PHASE_2 GPIO_NUM_26
|
||||
#define Y_PIN_PHASE_3 GPIO_NUM_32
|
||||
|
||||
|
||||
#define SOLENOID_DIRECTION_PIN GPIO_NUM_4
|
||||
#define SOLENOID_PEN_PIN GPIO_NUM_2
|
||||
#define SOLENOID_CHANNEL_NUM 6
|
||||
|
||||
#ifdef HOMING_CYCLE_0
|
||||
#undef HOMING_CYCLE_0
|
||||
#endif
|
||||
#define HOMING_CYCLE_0 (1<<X_AXIS) // this 'bot only homes the X axis
|
||||
#ifdef HOMING_CYCLE_1
|
||||
#undef HOMING_CYCLE_1
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_2
|
||||
#undef HOMING_CYCLE_2
|
||||
#endif
|
||||
|
||||
#define REED_SW_PIN GPIO_NUM_17
|
||||
#define LIMIT_MASK 0
|
||||
|
||||
|
||||
#ifdef IGNORE_CONTROL_PINS // maybe set in config.h
|
||||
#undef IGNORE_CONTROL_PINS
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef ENABLE_CONTROL_SW_DEBOUNCE
|
||||
#define ENABLE_CONTROL_SW_DEBOUNCE
|
||||
#endif
|
||||
|
||||
#ifdef INVERT_CONTROL_PIN_MASK
|
||||
#undef IGNORE_CONTROL_PINS
|
||||
#endif
|
||||
#define INVERT_CONTROL_PIN_MASK B01110000
|
||||
|
||||
#define MACRO_BUTTON_0_PIN GPIO_NUM_34 // Pen Switch
|
||||
#define MACRO_BUTTON_1_PIN GPIO_NUM_35 // Color Switch
|
||||
#define MACRO_BUTTON_2_PIN GPIO_NUM_36 // Paper Switch
|
||||
|
||||
#ifdef DEFAULTS_GENERIC
|
||||
#undef DEFAULTS_GENERIC // undefine generic then define each default below
|
||||
#endif
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 3
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 200 // 200ms
|
||||
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0 // uint8_t
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 0 // uint8_t
|
||||
#define DEFAULT_INVERT_ST_ENABLE 0 // boolean
|
||||
#define DEFAULT_INVERT_LIMIT_PINS 1 // boolean
|
||||
#define DEFAULT_INVERT_PROBE_PIN 0 // boolean
|
||||
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1
|
||||
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
|
||||
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
|
||||
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false
|
||||
|
||||
#define DEFAULT_HOMING_ENABLE 1
|
||||
#define DEFAULT_HOMING_DIR_MASK 0
|
||||
#define DEFAULT_HOMING_FEED_RATE 3000.0 // mm/min
|
||||
#define DEFAULT_HOMING_SEEK_RATE 3000.0 // mm/min
|
||||
#define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
|
||||
#define DEFAULT_HOMING_PULLOFF 2.0 // mm
|
||||
|
||||
#define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
|
||||
#define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
|
||||
|
||||
#define DEFAULT_LASER_MODE 0 // false
|
||||
|
||||
#define DEFAULT_X_STEPS_PER_MM 10
|
||||
#define DEFAULT_Y_STEPS_PER_MM 10
|
||||
#define DEFAULT_Z_STEPS_PER_MM 100.0 // This is percent in servo mode
|
||||
|
||||
|
||||
#define DEFAULT_X_MAX_RATE 5000.0 // mm/min
|
||||
#define DEFAULT_Y_MAX_RATE 5000.0 // mm/min
|
||||
#define DEFAULT_Z_MAX_RATE 200000.0 // mm/min
|
||||
|
||||
#define DEFAULT_X_ACCELERATION (500.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#define DEFAULT_Y_ACCELERATION (500.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#define DEFAULT_Z_ACCELERATION (500.0*60*60)
|
||||
|
||||
#define DEFAULT_X_MAX_TRAVEL 120.0 // mm NOTE: Must be a positive value.
|
||||
#define DEFAULT_Y_MAX_TRAVEL 20000.0 // mm NOTE: Must be a positive value.
|
||||
#define DEFAULT_Z_MAX_TRAVEL 10.0 // This is percent in servo mode
|
||||
|
||||
// ================== CPU MAP ======================
|
||||
|
||||
#define ATARI_1020
|
||||
|
||||
|
||||
#define SOLENOID_PWM_FREQ 5000
|
||||
#define SOLENOID_PWM_RES_BITS 8
|
||||
|
||||
#define SOLENOID_PULSE_LEN_PULL 255
|
||||
#define SOLENOID_PULL_DURATION 50 // in task counts...after this delay power will change to hold level see SOLENOID_TASK_FREQ
|
||||
#define SOLENOID_PULSE_LEN_HOLD 40 // solenoid hold level ... typically a lower value to prevent overheating
|
||||
|
||||
#define SOLENOID_TASK_FREQ 50 // this is milliseconds
|
||||
|
||||
#define MAX_PEN_NUMBER 4
|
||||
#define BUMPS_PER_PEN_CHANGE 3
|
||||
|
||||
|
||||
#define ATARI_HOME_POS -10.0f // this amound to the left of the paper 0
|
||||
#define ATARI_PAPER_WIDTH 100.0f //
|
||||
#define ATARI_HOMING_ATTEMPTS 13
|
||||
|
||||
// tells grbl we have some special functions to call
|
||||
#define USE_MACHINE_INIT
|
||||
#define USE_CUSTOM_HOMING
|
||||
#define USE_TOOL_CHANGE
|
||||
#define ATARI_TOOL_CHANGE_Z 5.0
|
||||
#define USE_M30 // use the user defined end of program
|
||||
|
||||
#ifndef atari_h
|
||||
#define atari_h
|
||||
|
||||
void machine_init();
|
||||
void solenoid_disable();
|
||||
void solenoidSyncTask(void *pvParameters);
|
||||
void calc_solenoid(float penZ);
|
||||
bool user_defined_homing();
|
||||
void atari_home_task(void *pvParameters);
|
||||
void user_tool_change(uint8_t new_tool);
|
||||
void user_defined_macro(uint8_t index);
|
||||
void user_m30();
|
||||
void atari_next_pen();
|
||||
|
||||
#endif
|
2219
Grbl_Esp32-master/Grbl_Esp32/commands.cpp
Normal file
2219
Grbl_Esp32-master/Grbl_Esp32/commands.cpp
Normal file
File diff suppressed because it is too large
Load Diff
58
Grbl_Esp32-master/Grbl_Esp32/commands.h
Normal file
58
Grbl_Esp32-master/Grbl_Esp32/commands.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
commands.h - ESP3D configuration class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef COMMANDS_h
|
||||
#define COMMANDS_h
|
||||
#include "config.h"
|
||||
|
||||
//Authentication level
|
||||
typedef enum {
|
||||
LEVEL_GUEST = 0,
|
||||
LEVEL_USER = 1,
|
||||
LEVEL_ADMIN = 2
|
||||
} level_authenticate_type;
|
||||
|
||||
// Define line flags. Includes comment type tracking and line overflow detection.
|
||||
#define LINE_FLAG_OVERFLOW bit(0)
|
||||
#define LINE_FLAG_COMMENT_PARENTHESES bit(1)
|
||||
#define LINE_FLAG_COMMENT_SEMICOLON bit(2)
|
||||
|
||||
class ESPResponseStream;
|
||||
|
||||
|
||||
class COMMANDS
|
||||
{
|
||||
public:
|
||||
static bool check_command (const char *, int * cmd, String & cmd_params);
|
||||
static String get_param (String & cmd_params, const char * id, bool withspace);
|
||||
static bool execute_internal_command (int cmd, String cmd_params, level_authenticate_type auth_level = LEVEL_GUEST , ESPResponseStream *espresponse= NULL);
|
||||
static void wait(uint32_t milliseconds);
|
||||
static void handle();
|
||||
static void restart_ESP();
|
||||
#ifdef ENABLE_AUTHENTICATION
|
||||
static bool isadmin (String & cmd_params);
|
||||
static bool isuser (String & cmd_params);
|
||||
static bool isLocalPasswordValid (const char * password);
|
||||
#endif
|
||||
private :
|
||||
static bool restart_ESP_module;
|
||||
};
|
||||
|
||||
#endif
|
722
Grbl_Esp32-master/Grbl_Esp32/config.h
Normal file
722
Grbl_Esp32-master/Grbl_Esp32/config.h
Normal file
@ -0,0 +1,722 @@
|
||||
/*
|
||||
config.h - compile time configuration
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// This file contains compile-time configurations for Grbl's internal system. For the most part,
|
||||
// users will not need to directly modify these, but they are here for specific needs, i.e.
|
||||
// performance tuning or adjusting to non-typical machines.
|
||||
|
||||
// IMPORTANT: Any changes here requires a full re-compiling of the source code to propagate them.
|
||||
|
||||
/*
|
||||
ESP 32 Notes
|
||||
|
||||
Some features should not be changed. See notes below.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef config_h
|
||||
#define config_h
|
||||
#include <Arduino.h>
|
||||
|
||||
//#define ESP_DEBUG
|
||||
#define N_AXIS 3 // Number of axes defined (valid range: 3 to 6)
|
||||
|
||||
// Define CPU pin map and default settings.
|
||||
// NOTE: OEMs can avoid the need to maintain/update the defaults.h and cpu_map.h files and use only
|
||||
// one configuration file by placing their specific defaults and pin map at the bottom of this file.
|
||||
// If doing so, simply comment out these two defines and see instructions below.
|
||||
#define CPU_MAP_TEST_DRIVE // these are defined in cpu_map.h
|
||||
#define VERBOSE_HELP // adds addition help info, but could confuse some senders
|
||||
|
||||
|
||||
// Serial baud rate
|
||||
#define BAUD_RATE 115200
|
||||
|
||||
//#define ENABLE_BLUETOOTH // enable bluetooth ... turns of if $I= something
|
||||
|
||||
//#define ENABLE_SD_CARD // enable use of SD Card to run jobs
|
||||
|
||||
//#define ENABLE_WIFI //enable wifi
|
||||
|
||||
#define ENABLE_HTTP //enable HTTP and all related services
|
||||
#define ENABLE_OTA //enable OTA
|
||||
#define ENABLE_TELNET //enable telnet
|
||||
#define ENABLE_TELNET_WELCOME_MSG //display welcome string when connect to telnet
|
||||
#define ENABLE_MDNS //enable mDNS discovery
|
||||
#define ENABLE_SSDP //enable UPNP discovery
|
||||
#define ENABLE_NOTIFICATIONS //enable notifications
|
||||
|
||||
#define ENABLE_SERIAL2SOCKET_IN
|
||||
#define ENABLE_SERIAL2SOCKET_OUT
|
||||
|
||||
#define ENABLE_CAPTIVE_PORTAL
|
||||
//#define ENABLE_AUTHENTICATION
|
||||
|
||||
#define NAMESPACE "GRBL"
|
||||
#define ESP_RADIO_MODE "RADIO_MODE"
|
||||
|
||||
#ifdef ENABLE_AUTHENTICATION
|
||||
#define DEFAULT_ADMIN_PWD "admin"
|
||||
#define DEFAULT_USER_PWD "user";
|
||||
#define DEFAULT_ADMIN_LOGIN "admin"
|
||||
#define DEFAULT_USER_LOGIN "user"
|
||||
#define ADMIN_PWD_ENTRY "ADMIN_PWD"
|
||||
#define USER_PWD_ENTRY "USER_PWD"
|
||||
#define AUTH_ENTRY_NB 20
|
||||
#define MAX_LOCAL_PASSWORD_LENGTH 16
|
||||
#define MIN_LOCAL_PASSWORD_LENGTH 1
|
||||
#endif
|
||||
|
||||
//Radio Mode
|
||||
#define ESP_RADIO_OFF 0
|
||||
#define ESP_WIFI_STA 1
|
||||
#define ESP_WIFI_AP 2
|
||||
#define ESP_BT 3
|
||||
|
||||
//Default mode
|
||||
#ifdef ENABLE_WIFI
|
||||
#define DEFAULT_RADIO_MODE ESP_WIFI_AP
|
||||
#else
|
||||
#undef ENABLE_NOTIFICATIONS
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
#define DEFAULT_RADIO_MODE ESP_BT
|
||||
#else
|
||||
#define DEFAULT_RADIO_MODE ESP_RADIO_OFF
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Define realtime command special characters. These characters are 'picked-off' directly from the
|
||||
// serial read data stream and are not passed to the grbl line execution parser. Select characters
|
||||
// that do not and must not exist in the streamed g-code program. ASCII control characters may be
|
||||
// used, if they are available per user setup. Also, extended ASCII codes (>127), which are never in
|
||||
// g-code programs, maybe selected for interface programs.
|
||||
// NOTE: If changed, manually update help message in report.c.
|
||||
|
||||
#define CMD_RESET 0x18 // ctrl-x.
|
||||
#define CMD_STATUS_REPORT '?'
|
||||
#define CMD_CYCLE_START '~'
|
||||
#define CMD_FEED_HOLD '!'
|
||||
|
||||
// NOTE: All override realtime commands must be in the extended ASCII character set, starting
|
||||
// at character value 128 (0x80) and up to 255 (0xFF). If the normal set of realtime commands,
|
||||
// such as status reports, feed hold, reset, and cycle start, are moved to the extended set
|
||||
// space, serial.c's RX ISR will need to be modified to accommodate the change.
|
||||
// #define CMD_RESET 0x80
|
||||
// #define CMD_STATUS_REPORT 0x81
|
||||
// #define CMD_CYCLE_START 0x82
|
||||
// #define CMD_FEED_HOLD 0x83
|
||||
#define CMD_SAFETY_DOOR 0x84
|
||||
#define CMD_JOG_CANCEL 0x85
|
||||
#define CMD_DEBUG_REPORT 0x86 // Only when DEBUG enabled, sends debug report in '{}' braces.
|
||||
#define CMD_FEED_OVR_RESET 0x90 // Restores feed override value to 100%.
|
||||
#define CMD_FEED_OVR_COARSE_PLUS 0x91
|
||||
#define CMD_FEED_OVR_COARSE_MINUS 0x92
|
||||
#define CMD_FEED_OVR_FINE_PLUS 0x93
|
||||
#define CMD_FEED_OVR_FINE_MINUS 0x94
|
||||
#define CMD_RAPID_OVR_RESET 0x95 // Restores rapid override value to 100%.
|
||||
#define CMD_RAPID_OVR_MEDIUM 0x96
|
||||
#define CMD_RAPID_OVR_LOW 0x97
|
||||
// #define CMD_RAPID_OVR_EXTRA_LOW 0x98 // *NOT SUPPORTED*
|
||||
#define CMD_SPINDLE_OVR_RESET 0x99 // Restores spindle override value to 100%.
|
||||
#define CMD_SPINDLE_OVR_COARSE_PLUS 0x9A
|
||||
#define CMD_SPINDLE_OVR_COARSE_MINUS 0x9B
|
||||
#define CMD_SPINDLE_OVR_FINE_PLUS 0x9C
|
||||
#define CMD_SPINDLE_OVR_FINE_MINUS 0x9D
|
||||
#define CMD_SPINDLE_OVR_STOP 0x9E
|
||||
#define CMD_COOLANT_FLOOD_OVR_TOGGLE 0xA0
|
||||
#define CMD_COOLANT_MIST_OVR_TOGGLE 0xA1
|
||||
|
||||
// If homing is enabled, homing init lock sets Grbl into an alarm state upon power up. This forces
|
||||
// the user to perform the homing cycle (or override the locks) before doing anything else. This is
|
||||
// mainly a safety feature to remind the user to home, since position is unknown to Grbl.
|
||||
#define HOMING_INIT_LOCK // Comment to disable
|
||||
|
||||
// Define the homing cycle patterns with bitmasks. The homing cycle first performs a search mode
|
||||
// to quickly engage the limit switches, followed by a slower locate mode, and finished by a short
|
||||
// pull-off motion to disengage the limit switches. The following HOMING_CYCLE_x defines are executed
|
||||
// in order starting with suffix 0 and completes the homing routine for the specified-axes only. If
|
||||
// an axis is omitted from the defines, it will not home, nor will the system update its position.
|
||||
// Meaning that this allows for users with non-standard Cartesian machines, such as a lathe (x then z,
|
||||
// with no y), to configure the homing cycle behavior to their needs.
|
||||
// NOTE: The homing cycle is designed to allow sharing of limit pins, if the axes are not in the same
|
||||
// cycle, but this requires some pin settings changes in cpu_map.h file. For example, the default homing
|
||||
// cycle can share the Z limit pin with either X or Y limit pins, since they are on different cycles.
|
||||
// By sharing a pin, this frees up a precious IO pin for other purposes. In theory, all axes limit pins
|
||||
// may be reduced to one pin, if all axes are homed with separate cycles, or vice versa, all three axes
|
||||
// on separate pin, but homed in one cycle. Also, it should be noted that the function of hard limits
|
||||
// will not be affected by pin sharing.
|
||||
|
||||
// NOTE: Defaults are set for a traditional 3-axis CNC machine. Z-axis first to clear, followed by X & Y.
|
||||
#define HOMING_CYCLE_0 (1<<Z_AXIS) // TYPICALLY REQUIRED: First move Z to clear workspace.
|
||||
#define HOMING_CYCLE_1 (1<<X_AXIS)
|
||||
#define HOMING_CYCLE_2 (1<<Y_AXIS)
|
||||
|
||||
// NOTE: The following is for for homingg X and Y at the same time
|
||||
// #define HOMING_CYCLE_0 (1<<Z_AXIS) // first home z by itself
|
||||
// #define HOMING_CYCLE_1 ((1<<X_AXIS)|(1<<Y_AXIS)) // Homes both X-Y in one cycle. NOT COMPATIBLE WITH COREXY!!!
|
||||
|
||||
// Number of homing cycles performed after when the machine initially jogs to limit switches.
|
||||
// This help in preventing overshoot and should improve repeatability. This value should be one or
|
||||
// greater.
|
||||
#define N_HOMING_LOCATE_CYCLE 1 // Integer (1-128)
|
||||
|
||||
// Enables single axis homing commands. $HX, $HY, and $HZ for X, Y, and Z-axis homing. The full homing
|
||||
// cycle is still invoked by the $H command. This is disabled by default. It's here only to address
|
||||
// users that need to switch between a two-axis and three-axis machine. This is actually very rare.
|
||||
// If you have a two-axis machine, DON'T USE THIS. Instead, just alter the homing cycle for two-axes.
|
||||
#define HOMING_SINGLE_AXIS_COMMANDS // Default disabled. Uncomment to enable.
|
||||
|
||||
// After homing, Grbl will set by default the entire machine space into negative space, as is typical
|
||||
// for professional CNC machines, regardless of where the limit switches are located. Uncomment this
|
||||
// define to force Grbl to always set the machine origin at the homed location despite switch orientation.
|
||||
// #define HOMING_FORCE_SET_ORIGIN // Uncomment to enable.
|
||||
|
||||
// Uncomment this define to force Grbl to always set the machine origin at minimum travel positions of
|
||||
// the axes. Note: The $23 setting determines the direction of travel during homing. If an axes homes towards the
|
||||
// minimum, it will set the machine position to 0. If it homes towards the maximum it will set the
|
||||
// machine position to the max travel ($13x), minus the switch pull off ($27).
|
||||
// #define HOMING_FORCE_POSITIVE_SPACE // Uncomment to enable.
|
||||
|
||||
// Number of blocks Grbl executes upon startup. These blocks are stored in EEPROM, where the size
|
||||
// and addresses are defined in settings.h. With the current settings, up to 2 startup blocks may
|
||||
// be stored and executed in order. These startup blocks would typically be used to set the g-code
|
||||
// parser state depending on user preferences.
|
||||
#define N_STARTUP_LINE 2 // Integer (1-2)
|
||||
|
||||
// Number of floating decimal points printed by Grbl for certain value types. These settings are
|
||||
// determined by realistic and commonly observed values in CNC machines. For example, position
|
||||
// values cannot be less than 0.001mm or 0.0001in, because machines can not be physically more
|
||||
// precise this. So, there is likely no need to change these, but you can if you need to here.
|
||||
// NOTE: Must be an integer value from 0 to ~4. More than 4 may exhibit round-off errors.
|
||||
// ESP32 Note: These are mostly hard coded, so these values will not change anything
|
||||
#define N_DECIMAL_COORDVALUE_INCH 4 // Coordinate or position value in inches
|
||||
#define N_DECIMAL_COORDVALUE_MM 3 // Coordinate or position value in mm
|
||||
#define N_DECIMAL_RATEVALUE_INCH 1 // Rate or velocity value in in/min
|
||||
#define N_DECIMAL_RATEVALUE_MM 0 // Rate or velocity value in mm/min
|
||||
#define N_DECIMAL_SETTINGVALUE 3 // Decimals for floating point setting values
|
||||
#define N_DECIMAL_RPMVALUE 0 // RPM value in rotations per min.
|
||||
|
||||
// If your machine has two limits switches wired in parallel to one axis, you will need to enable
|
||||
// this feature. Since the two switches are sharing a single pin, there is no way for Grbl to tell
|
||||
// which one is enabled. This option only effects homing, where if a limit is engaged, Grbl will
|
||||
// alarm out and force the user to manually disengage the limit switch. Otherwise, if you have one
|
||||
// limit switch for each axis, don't enable this option. By keeping it disabled, you can perform a
|
||||
// homing cycle while on the limit switch and not have to move the machine off of it.
|
||||
// #define LIMITS_TWO_SWITCHES_ON_AXES
|
||||
|
||||
// Allows GRBL to track and report gcode line numbers. Enabling this means that the planning buffer
|
||||
// goes from 16 to 15 to make room for the additional line number data in the plan_block_t struct
|
||||
// #define USE_LINE_NUMBERS // Disabled by default. Uncomment to enable.
|
||||
|
||||
// Upon a successful probe cycle, this option provides immediately feedback of the probe coordinates
|
||||
// through an automatically generated message. If disabled, users can still access the last probe
|
||||
// coordinates through Grbl '$#' print parameters.
|
||||
#define MESSAGE_PROBE_COORDINATES // Enabled by default. Comment to disable.
|
||||
|
||||
// Enables a second coolant control pin via the mist coolant g-code command M7 on the Arduino Uno
|
||||
// analog pin 4. Only use this option if you require a second coolant control pin.
|
||||
// NOTE: The M8 flood coolant control pin on analog pin 3 will still be functional regardless.
|
||||
// ESP32 NOTE! This is here for reference only. You enable both M7 and M8 by assigning them a GPIO Pin
|
||||
// in cpu_map.h
|
||||
//#define ENABLE_M7 // Don't uncomment...see above!
|
||||
|
||||
// This option causes the feed hold input to act as a safety door switch. A safety door, when triggered,
|
||||
// immediately forces a feed hold and then safely de-energizes the machine. Resuming is blocked until
|
||||
// the safety door is re-engaged. When it is, Grbl will re-energize the machine and then resume on the
|
||||
// previous tool path, as if nothing happened.
|
||||
#define ENABLE_SAFETY_DOOR_INPUT_PIN // ESP32 Leave this enabled for now .. code for undefined not ready
|
||||
|
||||
// After the safety door switch has been toggled and restored, this setting sets the power-up delay
|
||||
// between restoring the spindle and coolant and resuming the cycle.
|
||||
#define SAFETY_DOOR_SPINDLE_DELAY 4.0 // Float (seconds)
|
||||
#define SAFETY_DOOR_COOLANT_DELAY 1.0 // Float (seconds)
|
||||
|
||||
// Enable CoreXY kinematics. Use ONLY with CoreXY machines.
|
||||
// IMPORTANT: If homing is enabled, you must reconfigure the homing cycle #defines above to
|
||||
// #define HOMING_CYCLE_0 (1<<X_AXIS) and #define HOMING_CYCLE_1 (1<<Y_AXIS)
|
||||
// NOTE: This configuration option alters the motion of the X and Y axes to principle of operation
|
||||
// defined at (http://corexy.com/theory.html). Motors are assumed to positioned and wired exactly as
|
||||
// described, if not, motions may move in strange directions. Grbl requires the CoreXY A and B motors
|
||||
// have the same steps per mm internally.
|
||||
// #define COREXY // Default disabled. Uncomment to enable.
|
||||
|
||||
// Enable using a servo for the Z axis on a pen type machine.
|
||||
// You typically should not define a pin for the Z axis in cpu_map.h
|
||||
// You should configure your settings in servo_pen.h
|
||||
// #define USE_PEN_SERVO // this method will be deprecated soon
|
||||
// #define USE_SERVO_AXES // the new method
|
||||
// define your servo pin here or in cpu_map.h
|
||||
//#define SERVO_PEN_PIN GPIO_NUM_27
|
||||
|
||||
// Enable using a solenoid for the Z axis on a pen type machine
|
||||
// #define USE_PEN_SOLENOID
|
||||
|
||||
// Inverts pin logic of the control command pins based on a mask. This essentially means you can use
|
||||
// normally-closed switches on the specified pins, rather than the default normally-open switches.
|
||||
// The mask order is Cycle Start | Feed Hold | Reset | Safety Door
|
||||
// For example B1101 will invert the function of the Reset pin.
|
||||
#define INVERT_CONTROL_PIN_MASK B1111
|
||||
|
||||
// This allows control pins to be ignored.
|
||||
// Since these are typically used on the pins that don't have pullups, they will float and cause
|
||||
// problems if not externally pulled up. Ignoring will always return not activated when read.
|
||||
//#define IGNORE_CONTROL_PINS
|
||||
|
||||
#define ENABLE_CONTROL_SW_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
#define CONTROL_SW_DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds
|
||||
|
||||
|
||||
// Inverts select limit pin states based on the following mask. This effects all limit pin functions,
|
||||
// such as hard limits and homing. However, this is different from overall invert limits setting.
|
||||
// This build option will invert only the limit pins defined here, and then the invert limits setting
|
||||
// will be applied to all of them. This is useful when a user has a mixed set of limit pins with both
|
||||
// normally-open(NO) and normally-closed(NC) switches installed on their machine.
|
||||
// NOTE: PLEASE DO NOT USE THIS, unless you have a situation that needs it.
|
||||
// #define INVERT_LIMIT_PIN_MASK ((1<<X_LIMIT_BIT)|(1<<Y_LIMIT_BIT)) // Default disabled. Uncomment to enable.
|
||||
|
||||
// Inverts the spindle enable pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful
|
||||
// for some pre-built electronic boards.
|
||||
#define INVERT_SPINDLE_ENABLE_PIN // Default disabled. Uncomment to enable.
|
||||
|
||||
// Inverts the selected coolant pin from low-disabled/high-enabled to low-enabled/high-disabled. Useful
|
||||
// for some pre-built electronic boards.
|
||||
// #define INVERT_COOLANT_FLOOD_PIN // Default disabled. Uncomment to enable.
|
||||
// #define INVERT_COOLANT_MIST_PIN // Default disabled. Note: Enable M7 mist coolant in config.h
|
||||
|
||||
// When Grbl powers-cycles or is hard reset with the Arduino reset button, Grbl boots up with no ALARM
|
||||
// by default. This is to make it as simple as possible for new users to start using Grbl. When homing
|
||||
// is enabled and a user has installed limit switches, Grbl will boot up in an ALARM state to indicate
|
||||
// Grbl doesn't know its position and to force the user to home before proceeding. This option forces
|
||||
// Grbl to always initialize into an ALARM state regardless of homing or not. This option is more for
|
||||
// OEMs and LinuxCNC users that would like this power-cycle behavior.
|
||||
// #define FORCE_INITIALIZATION_ALARM // Default disabled. Uncomment to enable.
|
||||
|
||||
// At power-up or a reset, Grbl will check the limit switch states to ensure they are not active
|
||||
// before initialization. If it detects a problem and the hard limits setting is enabled, Grbl will
|
||||
// simply message the user to check the limits and enter an alarm state, rather than idle. Grbl will
|
||||
// not throw an alarm message.
|
||||
#define CHECK_LIMITS_AT_INIT
|
||||
|
||||
// ---------------------------------------------------------------------------------------
|
||||
// ADVANCED CONFIGURATION OPTIONS:
|
||||
|
||||
// Enables code for debugging purposes. Not for general use and always in constant flux.
|
||||
// #define DEBUG // Uncomment to enable. Default disabled.
|
||||
|
||||
// Configure rapid, feed, and spindle override settings. These values define the max and min
|
||||
// allowable override values and the coarse and fine increments per command received. Please
|
||||
// note the allowable values in the descriptions following each define.
|
||||
#define DEFAULT_FEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_FEED_RATE_OVERRIDE 200 // Percent of programmed feed rate (100-255). Usually 120% or 200%
|
||||
#define MIN_FEED_RATE_OVERRIDE 10 // Percent of programmed feed rate (1-100). Usually 50% or 1%
|
||||
#define FEED_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define FEED_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
|
||||
#define DEFAULT_RAPID_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define RAPID_OVERRIDE_MEDIUM 50 // Percent of rapid (1-99). Usually 50%.
|
||||
#define RAPID_OVERRIDE_LOW 25 // Percent of rapid (1-99). Usually 25%.
|
||||
// #define RAPID_OVERRIDE_EXTRA_LOW 5 // *NOT SUPPORTED* Percent of rapid (1-99). Usually 5%.
|
||||
|
||||
#define DEFAULT_SPINDLE_SPEED_OVERRIDE 100 // 100%. Don't change this value.
|
||||
#define MAX_SPINDLE_SPEED_OVERRIDE 200 // Percent of programmed spindle speed (100-255). Usually 200%.
|
||||
#define MIN_SPINDLE_SPEED_OVERRIDE 10 // Percent of programmed spindle speed (1-100). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_COARSE_INCREMENT 10 // (1-99). Usually 10%.
|
||||
#define SPINDLE_OVERRIDE_FINE_INCREMENT 1 // (1-99). Usually 1%.
|
||||
|
||||
// When a M2 or M30 program end command is executed, most g-code states are restored to their defaults.
|
||||
// This compile-time option includes the restoring of the feed, rapid, and spindle speed override values
|
||||
// to their default values at program end.
|
||||
#define RESTORE_OVERRIDES_AFTER_PROGRAM_END // Default enabled. Comment to disable.
|
||||
|
||||
// The status report change for Grbl v1.1 and after also removed the ability to disable/enable most data
|
||||
// fields from the report. This caused issues for GUI developers, who've had to manage several scenarios
|
||||
// and configurations. The increased efficiency of the new reporting style allows for all data fields to
|
||||
// be sent without potential performance issues.
|
||||
// NOTE: The options below are here only provide a way to disable certain data fields if a unique
|
||||
// situation demands it, but be aware GUIs may depend on this data. If disabled, it may not be compatible.
|
||||
#define REPORT_FIELD_BUFFER_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_PIN_STATE // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_CURRENT_FEED_SPEED // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_WORK_COORD_OFFSET // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_OVERRIDES // Default enabled. Comment to disable.
|
||||
#define REPORT_FIELD_LINE_NUMBERS // Default enabled. Comment to disable.
|
||||
|
||||
// Some status report data isn't necessary for realtime, only intermittently, because the values don't
|
||||
// change often. The following macros configures how many times a status report needs to be called before
|
||||
// the associated data is refreshed and included in the status report. However, if one of these value
|
||||
// changes, Grbl will automatically include this data in the next status report, regardless of what the
|
||||
// count is at the time. This helps reduce the communication overhead involved with high frequency reporting
|
||||
// and agressive streaming. There is also a busy and an idle refresh count, which sets up Grbl to send
|
||||
// refreshes more often when its not doing anything important. With a good GUI, this data doesn't need
|
||||
// to be refreshed very often, on the order of a several seconds.
|
||||
// NOTE: WCO refresh must be 2 or greater. OVR refresh must be 1 or greater.
|
||||
#define REPORT_OVR_REFRESH_BUSY_COUNT 20 // (1-255)
|
||||
#define REPORT_OVR_REFRESH_IDLE_COUNT 10 // (1-255) Must be less than or equal to the busy count
|
||||
#define REPORT_WCO_REFRESH_BUSY_COUNT 30 // (2-255)
|
||||
#define REPORT_WCO_REFRESH_IDLE_COUNT 10 // (2-255) Must be less than or equal to the busy count
|
||||
|
||||
// The temporal resolution of the acceleration management subsystem. A higher number gives smoother
|
||||
// acceleration, particularly noticeable on machines that run at very high feedrates, but may negatively
|
||||
// impact performance. The correct value for this parameter is machine dependent, so it's advised to
|
||||
// set this only as high as needed. Approximate successful values can widely range from 50 to 200 or more.
|
||||
// NOTE: Changing this value also changes the execution time of a segment in the step segment buffer.
|
||||
// When increasing this value, this stores less overall time in the segment buffer and vice versa. Make
|
||||
// certain the step segment buffer is increased/decreased to account for these changes.
|
||||
#define ACCELERATION_TICKS_PER_SECOND 100
|
||||
|
||||
// Adaptive Multi-Axis Step Smoothing (AMASS) is an advanced feature that does what its name implies,
|
||||
// smoothing the stepping of multi-axis motions. This feature smooths motion particularly at low step
|
||||
// frequencies below 10kHz, where the aliasing between axes of multi-axis motions can cause audible
|
||||
// noise and shake your machine. At even lower step frequencies, AMASS adapts and provides even better
|
||||
// step smoothing. See stepper.c for more details on the AMASS system works.
|
||||
#define ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING // Default enabled. Comment to disable.
|
||||
|
||||
// Sets the maximum step rate allowed to be written as a Grbl setting. This option enables an error
|
||||
// check in the settings module to prevent settings values that will exceed this limitation. The maximum
|
||||
// step rate is strictly limited by the CPU speed and will change if something other than an AVR running
|
||||
// at 16MHz is used.
|
||||
// NOTE: For now disabled, will enable if flash space permits.
|
||||
// #define MAX_STEP_RATE_HZ 30000 // Hz
|
||||
|
||||
// By default, Grbl sets all input pins to normal-high operation with their internal pull-up resistors
|
||||
// enabled. This simplifies the wiring for users by requiring only a switch connected to ground,
|
||||
// although its recommended that users take the extra step of wiring in low-pass filter to reduce
|
||||
// electrical noise detected by the pin. If the user inverts the pin in Grbl settings, this just flips
|
||||
// which high or low reading indicates an active signal. In normal operation, this means the user
|
||||
// needs to connect a normal-open switch, but if inverted, this means the user should connect a
|
||||
// normal-closed switch.
|
||||
// The following options disable the internal pull-up resistors, sets the pins to a normal-low
|
||||
// operation, and switches must be now connect to Vcc instead of ground. This also flips the meaning
|
||||
// of the invert pin Grbl setting, where an inverted setting now means the user should connect a
|
||||
// normal-open switch and vice versa.
|
||||
// NOTE: All pins associated with the feature are disabled, i.e. XYZ limit pins, not individual axes.
|
||||
// WARNING: When the pull-ups are disabled, this requires additional wiring with pull-down resistors!
|
||||
//#define DISABLE_LIMIT_PIN_PULL_UP
|
||||
//#define DISABLE_PROBE_PIN_PULL_UP
|
||||
//#define DISABLE_CONTROL_PIN_PULL_UP
|
||||
|
||||
// Sets which axis the tool length offset is applied. Assumes the spindle is always parallel with
|
||||
// the selected axis with the tool oriented toward the negative direction. In other words, a positive
|
||||
// tool length offset value is subtracted from the current location.
|
||||
#define TOOL_LENGTH_OFFSET_AXIS Z_AXIS // Default z-axis. Valid values are X_AXIS, Y_AXIS, or Z_AXIS.
|
||||
|
||||
// Enables variable spindle output voltage for different RPM values. On the Arduino Uno, the spindle
|
||||
// enable pin will output 5V for maximum RPM with 256 intermediate levels and 0V when disabled.
|
||||
// NOTE: IMPORTANT for Arduino Unos! When enabled, the Z-limit pin D11 and spindle enable pin D12 switch!
|
||||
// The hardware PWM output on pin D11 is required for variable spindle output voltages.
|
||||
#define VARIABLE_SPINDLE // Default enabled. Comment to disable.
|
||||
|
||||
// Alters the behavior of the spindle enable pin. By default Grbl will not disable the enable pin if
|
||||
// spindle speed is zero and M3/4 is active, but still sets the PWM output to zero. This allows the users
|
||||
// to know if the spindle is active and use it as an additional control input.
|
||||
// However, in some use cases, user may want the enable pin to disable with a zero spindle speed and
|
||||
// re-enable when spindle speed is greater than zero. This option does that.
|
||||
#define SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED // Default enabled. Comment to disable.
|
||||
|
||||
// With this enabled, Grbl sends back an echo of the line it has received, which has been pre-parsed (spaces
|
||||
// removed, capitalized letters, no comments) and is to be immediately executed by Grbl. Echoes will not be
|
||||
// sent upon a line buffer overflow, but should for all normal lines sent to Grbl. For example, if a user
|
||||
// sendss the line 'g1 x1.032 y2.45 (test comment)', Grbl will echo back in the form '[echo: G1X1.032Y2.45]'.
|
||||
// NOTE: Only use this for debugging purposes!! When echoing, this takes up valuable resources and can effect
|
||||
// performance. If absolutely needed for normal operation, the serial write buffer should be greatly increased
|
||||
// to help minimize transmission waiting within the serial write protocol.
|
||||
// #define REPORT_ECHO_LINE_RECEIVED // Default disabled. Uncomment to enable.
|
||||
|
||||
// Minimum planner junction speed. Sets the default minimum junction speed the planner plans to at
|
||||
// every buffer block junction, except for starting from rest and end of the buffer, which are always
|
||||
// zero. This value controls how fast the machine moves through junctions with no regard for acceleration
|
||||
// limits or angle between neighboring block line move directions. This is useful for machines that can't
|
||||
// tolerate the tool dwelling for a split second, i.e. 3d printers or laser cutters. If used, this value
|
||||
// should not be much greater than zero or to the minimum value necessary for the machine to work.
|
||||
#define MINIMUM_JUNCTION_SPEED 0.0 // (mm/min)
|
||||
|
||||
// Sets the minimum feed rate the planner will allow. Any value below it will be set to this minimum
|
||||
// value. This also ensures that a planned motion always completes and accounts for any floating-point
|
||||
// round-off errors. Although not recommended, a lower value than 1.0 mm/min will likely work in smaller
|
||||
// machines, perhaps to 0.1mm/min, but your success may vary based on multiple factors.
|
||||
#define MINIMUM_FEED_RATE 1.0 // (mm/min)
|
||||
|
||||
// Number of arc generation iterations by small angle approximation before exact arc trajectory
|
||||
// correction with expensive sin() and cos() calcualtions. This parameter maybe decreased if there
|
||||
// are issues with the accuracy of the arc generations, or increased if arc execution is getting
|
||||
// bogged down by too many trig calculations.
|
||||
#define N_ARC_CORRECTION 12 // Integer (1-255)
|
||||
|
||||
// The arc G2/3 g-code standard is problematic by definition. Radius-based arcs have horrible numerical
|
||||
// errors when arc at semi-circles(pi) or full-circles(2*pi). Offset-based arcs are much more accurate
|
||||
// but still have a problem when arcs are full-circles (2*pi). This define accounts for the floating
|
||||
// point issues when offset-based arcs are commanded as full circles, but get interpreted as extremely
|
||||
// small arcs with around machine epsilon (1.2e-7rad) due to numerical round-off and precision issues.
|
||||
// This define value sets the machine epsilon cutoff to determine if the arc is a full-circle or not.
|
||||
// NOTE: Be very careful when adjusting this value. It should always be greater than 1.2e-7 but not too
|
||||
// much greater than this. The default setting should capture most, if not all, full arc error situations.
|
||||
#define ARC_ANGULAR_TRAVEL_EPSILON 5E-7 // Float (radians)
|
||||
|
||||
// Time delay increments performed during a dwell. The default value is set at 50ms, which provides
|
||||
// a maximum time delay of roughly 55 minutes, more than enough for most any application. Increasing
|
||||
// this delay will increase the maximum dwell time linearly, but also reduces the responsiveness of
|
||||
// run-time command executions, like status reports, since these are performed between each dwell
|
||||
// time step. Also, keep in mind that the Arduino delay timer is not very accurate for long delays.
|
||||
#define DWELL_TIME_STEP 50 // Integer (1-255) (milliseconds)
|
||||
|
||||
|
||||
// For test use only. This uses the ESP32's RMT perifieral to generate step pulses
|
||||
// It allows the use of the STEP_PULSE_DELAY (see below) and it automatically ends the
|
||||
// pulse in one operation.
|
||||
// Dir Pin ____|--------------------
|
||||
// Step Pin _______|--|____________
|
||||
// While this is experimental, it is intended to be the future default method after testing
|
||||
//#define USE_RMT_STEPS
|
||||
|
||||
// Creates a delay between the direction pin setting and corresponding step pulse by creating
|
||||
// another interrupt (Timer2 compare) to manage it. The main Grbl interrupt (Timer1 compare)
|
||||
// sets the direction pins, and does not immediately set the stepper pins, as it would in
|
||||
// normal operation. The Timer2 compare fires next to set the stepper pins after the step
|
||||
// pulse delay time, and Timer2 overflow will complete the step pulse, except now delayed
|
||||
// by the step pulse time plus the step pulse delay. (Thanks langwadt for the idea!)
|
||||
// NOTE: Uncomment to enable. The recommended delay must be > 3us, and, when added with the
|
||||
// user-supplied step pulse time, the total time must not exceed 127us. Reported successful
|
||||
// values for certain setups have ranged from 5 to 20us.
|
||||
// must use #define USE_RMT_STEPS for this to work
|
||||
//#define STEP_PULSE_DELAY 10 // Step pulse delay in microseconds. Default disabled.
|
||||
|
||||
// The number of linear motions in the planner buffer to be planned at any give time. The vast
|
||||
// majority of RAM that Grbl uses is based on this buffer size. Only increase if there is extra
|
||||
// available RAM, like when re-compiling for a Mega2560. Or decrease if the Arduino begins to
|
||||
// crash due to the lack of available RAM or if the CPU is having trouble keeping up with planning
|
||||
// new incoming motions as they are executed.
|
||||
#define BLOCK_BUFFER_SIZE 32 // Uncomment to override default in planner.h.
|
||||
|
||||
// Governs the size of the intermediary step segment buffer between the step execution algorithm
|
||||
// and the planner blocks. Each segment is set of steps executed at a constant velocity over a
|
||||
// fixed time defined by ACCELERATION_TICKS_PER_SECOND. They are computed such that the planner
|
||||
// block velocity profile is traced exactly. The size of this buffer governs how much step
|
||||
// execution lead time there is for other Grbl processes have to compute and do their thing
|
||||
// before having to come back and refill this buffer, currently at ~50msec of step moves.
|
||||
// #define SEGMENT_BUFFER_SIZE 6 // Uncomment to override default in stepper.h.
|
||||
|
||||
// Line buffer size from the serial input stream to be executed. Also, governs the size of
|
||||
// each of the startup blocks, as they are each stored as a string of this size. Make sure
|
||||
// to account for the available EEPROM at the defined memory address in settings.h and for
|
||||
// the number of desired startup blocks.
|
||||
// NOTE: 80 characters is not a problem except for extreme cases, but the line buffer size
|
||||
// can be too small and g-code blocks can get truncated. Officially, the g-code standards
|
||||
// support up to 256 characters. In future versions, this default will be increased, when
|
||||
// we know how much extra memory space we can re-invest into this.
|
||||
// #define LINE_BUFFER_SIZE 80 // Uncomment to override default in protocol.h
|
||||
|
||||
// Serial send and receive buffer size. The receive buffer is often used as another streaming
|
||||
// buffer to store incoming blocks to be processed by Grbl when its ready. Most streaming
|
||||
// interfaces will character count and track each block send to each block response. So,
|
||||
// increase the receive buffer if a deeper receive buffer is needed for streaming and avaiable
|
||||
// memory allows. The send buffer primarily handles messages in Grbl. Only increase if large
|
||||
// messages are sent and Grbl begins to stall, waiting to send the rest of the message.
|
||||
// NOTE: Grbl generates an average status report in about 0.5msec, but the serial TX stream at
|
||||
// 115200 baud will take 5 msec to transmit a typical 55 character report. Worst case reports are
|
||||
// around 90-100 characters. As long as the serial TX buffer doesn't get continually maxed, Grbl
|
||||
// will continue operating efficiently. Size the TX buffer around the size of a worst-case report.
|
||||
#define RX_BUFFER_SIZE 254 // (1-254) Uncomment to override defaults in serial.h
|
||||
#define TX_BUFFER_SIZE 128 // (1-254)
|
||||
|
||||
// A simple software debouncing feature for hard limit switches. When enabled, the limit
|
||||
// switch interrupt unblock a waiting task which will recheck the limit switch pins after
|
||||
// a short delay. Default disabled
|
||||
#define ENABLE_SOFTWARE_DEBOUNCE // Default disabled. Uncomment to enable.
|
||||
#define DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds
|
||||
|
||||
// Configures the position after a probing cycle during Grbl's check mode. Disabled sets
|
||||
// the position to the probe target, when enabled sets the position to the start position.
|
||||
// #define SET_CHECK_MODE_PROBE_TO_START // Default disabled. Uncomment to enable.
|
||||
|
||||
// Force Grbl to check the state of the hard limit switches when the processor detects a pin
|
||||
// change inside the hard limit ISR routine. By default, Grbl will trigger the hard limits
|
||||
// alarm upon any pin change, since bouncing switches can cause a state check like this to
|
||||
// misread the pin. When hard limits are triggered, they should be 100% reliable, which is the
|
||||
// reason that this option is disabled by default. Only if your system/electronics can guarantee
|
||||
// that the switches don't bounce, we recommend enabling this option. This will help prevent
|
||||
// triggering a hard limit when the machine disengages from the switch.
|
||||
// NOTE: This option has no effect if SOFTWARE_DEBOUNCE is enabled.
|
||||
// #define HARD_LIMIT_FORCE_STATE_CHECK // Default disabled. Uncomment to enable.
|
||||
|
||||
// Adjusts homing cycle search and locate scalars. These are the multipliers used by Grbl's
|
||||
// homing cycle to ensure the limit switches are engaged and cleared through each phase of
|
||||
// the cycle. The search phase uses the axes max-travel setting times the SEARCH_SCALAR to
|
||||
// determine distance to look for the limit switch. Once found, the locate phase begins and
|
||||
// uses the homing pull-off distance setting times the LOCATE_SCALAR to pull-off and re-engage
|
||||
// the limit switch.
|
||||
// NOTE: Both of these values must be greater than 1.0 to ensure proper function.
|
||||
// #define HOMING_AXIS_SEARCH_SCALAR 1.5 // Uncomment to override defaults in limits.c.
|
||||
// #define HOMING_AXIS_LOCATE_SCALAR 10.0 // Uncomment to override defaults in limits.c.
|
||||
|
||||
// Enable the '$RST=*', '$RST=$', and '$RST=#' eeprom restore commands. There are cases where
|
||||
// these commands may be undesirable. Simply comment the desired macro to disable it.
|
||||
// NOTE: See SETTINGS_RESTORE_ALL macro for customizing the `$RST=*` command.
|
||||
#define ENABLE_RESTORE_EEPROM_WIPE_ALL // '$RST=*' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // '$RST=$' Default enabled. Comment to disable.
|
||||
#define ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // '$RST=#' Default enabled. Comment to disable.
|
||||
|
||||
// Defines the EEPROM data restored upon a settings version change and `$RST=*` command. Whenever the
|
||||
// the settings or other EEPROM data structure changes between Grbl versions, Grbl will automatically
|
||||
// wipe and restore the EEPROM. This macro controls what data is wiped and restored. This is useful
|
||||
// particularily for OEMs that need to retain certain data. For example, the BUILD_INFO string can be
|
||||
// written into the Arduino EEPROM via a seperate .INO sketch to contain product data. Altering this
|
||||
// macro to not restore the build info EEPROM will ensure this data is retained after firmware upgrades.
|
||||
// NOTE: Uncomment to override defaults in settings.h
|
||||
// #define SETTINGS_RESTORE_ALL (SETTINGS_RESTORE_DEFAULTS | SETTINGS_RESTORE_PARAMETERS | SETTINGS_RESTORE_STARTUP_LINES | SETTINGS_RESTORE_BUILD_INFO)
|
||||
|
||||
// Additional settings have been added to the original set that you see with the $$ command
|
||||
// Some senders may not be able to parse anything different from the original set
|
||||
// You can still set these like $33=5000, but you cannot read them back.
|
||||
// Default is off to limit support issues...you can enable here or in your cpu_map
|
||||
// #define SHOW_EXTENDED_SETTINGS
|
||||
|
||||
// Enable the '$I=(string)' build info write command. If disabled, any existing build info data must
|
||||
// be placed into EEPROM via external means with a valid checksum value. This macro option is useful
|
||||
// to prevent this data from being over-written by a user, when used to store OEM product data.
|
||||
// NOTE: If disabled and to ensure Grbl can never alter the build info line, you'll also need to enable
|
||||
// the SETTING_RESTORE_ALL macro above and remove SETTINGS_RESTORE_BUILD_INFO from the mask.
|
||||
// NOTE: See the included grblWrite_BuildInfo.ino example file to write this string seperately.
|
||||
#define ENABLE_BUILD_INFO_WRITE_COMMAND // '$I=' Default enabled. Comment to disable.
|
||||
|
||||
// AVR processors require all interrupts to be disabled during an EEPROM write. This includes both
|
||||
// the stepper ISRs and serial comm ISRs. In the event of a long EEPROM write, this ISR pause can
|
||||
// cause active stepping to lose position and serial receive data to be lost. This configuration
|
||||
// option forces the planner buffer to completely empty whenever the EEPROM is written to prevent
|
||||
// any chance of lost steps.
|
||||
// However, this doesn't prevent issues with lost serial RX data during an EEPROM write, especially
|
||||
// if a GUI is premptively filling up the serial RX buffer simultaneously. It's highly advised for
|
||||
// GUIs to flag these gcodes (G10,G28.1,G30.1) to always wait for an 'ok' after a block containing
|
||||
// one of these commands before sending more data to eliminate this issue.
|
||||
// NOTE: Most EEPROM write commands are implicitly blocked during a job (all '$' commands). However,
|
||||
// coordinate set g-code commands (G10,G28/30.1) are not, since they are part of an active streaming
|
||||
// job. At this time, this option only forces a planner buffer sync with these g-code commands.
|
||||
#define FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // Default enabled. Comment to disable.
|
||||
|
||||
// In Grbl v0.9 and prior, there is an old outstanding bug where the `WPos:` work position reported
|
||||
// may not correlate to what is executing, because `WPos:` is based on the g-code parser state, which
|
||||
// can be several motions behind. This option forces the planner buffer to empty, sync, and stop
|
||||
// motion whenever there is a command that alters the work coordinate offsets `G10,G43.1,G92,G54-59`.
|
||||
// This is the simplest way to ensure `WPos:` is always correct. Fortunately, it's exceedingly rare
|
||||
// that any of these commands are used need continuous motions through them.
|
||||
#define FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // Default enabled. Comment to disable.
|
||||
|
||||
// By default, Grbl disables feed rate overrides for all G38.x probe cycle commands. Although this
|
||||
// may be different than some pro-class machine control, it's arguable that it should be this way.
|
||||
// Most probe sensors produce different levels of error that is dependent on rate of speed. By
|
||||
// keeping probing cycles to their programmed feed rates, the probe sensor should be a lot more
|
||||
// repeatable. If needed, you can disable this behavior by uncommenting the define below.
|
||||
// #define ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES // Default disabled. Uncomment to enable.
|
||||
|
||||
// Enables and configures parking motion methods upon a safety door state. Primarily for OEMs
|
||||
// that desire this feature for their integrated machines. At the moment, Grbl assumes that
|
||||
// the parking motion only involves one axis, although the parking implementation was written
|
||||
// to be easily refactored for any number of motions on different axes by altering the parking
|
||||
// source code. At this time, Grbl only supports parking one axis (typically the Z-axis) that
|
||||
// moves in the positive direction upon retracting and negative direction upon restoring position.
|
||||
// The motion executes with a slow pull-out retraction motion, power-down, and a fast park.
|
||||
// Restoring to the resume position follows these set motions in reverse: fast restore to
|
||||
// pull-out position, power-up with a time-out, and plunge back to the original position at the
|
||||
// slower pull-out rate.
|
||||
// NOTE: Still a work-in-progress. Machine coordinates must be in all negative space and
|
||||
// does not work with HOMING_FORCE_SET_ORIGIN enabled. Parking motion also moves only in
|
||||
// positive direction.
|
||||
//#define PARKING_ENABLE // Default disabled. Uncomment to enable
|
||||
|
||||
// Configure options for the parking motion, if enabled.
|
||||
#define PARKING_AXIS Z_AXIS // Define which axis that performs the parking motion
|
||||
#define PARKING_TARGET -5.0 // Parking axis target. In mm, as machine coordinate [-max_travel,0].
|
||||
#define PARKING_RATE 500.0 // Parking fast rate after pull-out in mm/min.
|
||||
#define PARKING_PULLOUT_RATE 100.0 // Pull-out/plunge slow feed rate in mm/min.
|
||||
#define PARKING_PULLOUT_INCREMENT 5.0 // Spindle pull-out and plunge distance in mm. Incremental distance.
|
||||
// Must be positive value or equal to zero.
|
||||
|
||||
// Enables a special set of M-code commands that enables and disables the parking motion.
|
||||
// These are controlled by `M56`, `M56 P1`, or `M56 Px` to enable and `M56 P0` to disable.
|
||||
// The command is modal and will be set after a planner sync. Since it is g-code, it is
|
||||
// executed in sync with g-code commands. It is not a real-time command.
|
||||
// NOTE: PARKING_ENABLE is required. By default, M56 is active upon initialization. Use
|
||||
// DEACTIVATE_PARKING_UPON_INIT to set M56 P0 as the power-up default.
|
||||
// #define ENABLE_PARKING_OVERRIDE_CONTROL // Default disabled. Uncomment to enable
|
||||
// #define DEACTIVATE_PARKING_UPON_INIT // Default disabled. Uncomment to enable.
|
||||
|
||||
// This option will automatically disable the laser during a feed hold by invoking a spindle stop
|
||||
// override immediately after coming to a stop. However, this also means that the laser still may
|
||||
// be reenabled by disabling the spindle stop override, if needed. This is purely a safety feature
|
||||
// to ensure the laser doesn't inadvertently remain powered while at a stop and cause a fire.
|
||||
#define DISABLE_LASER_DURING_HOLD // Default enabled. Comment to disable.
|
||||
|
||||
// Enables a piecewise linear model of the spindle PWM/speed output. Requires a solution by the
|
||||
// 'fit_nonlinear_spindle.py' script in the /doc/script folder of the repo. See file comments
|
||||
// on how to gather spindle data and run the script to generate a solution.
|
||||
// #define ENABLE_PIECEWISE_LINEAR_SPINDLE // Default disabled. Uncomment to enable.
|
||||
|
||||
// N_PIECES, RPM_MAX, RPM_MIN, RPM_POINTxx, and RPM_LINE_XX constants are all set and given by
|
||||
// the 'fit_nonlinear_spindle.py' script solution. Used only when ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||
// is enabled. Make sure the constant values are exactly the same as the script solution.
|
||||
// NOTE: When N_PIECES < 4, unused RPM_LINE and RPM_POINT defines are not required and omitted.
|
||||
/*
|
||||
#define N_PIECES 4 // Integer (1-4). Number of piecewise lines used in script solution.
|
||||
#define RPM_MAX 11686.4 // Max RPM of model. $30 > RPM_MAX will be limited to RPM_MAX.
|
||||
#define RPM_MIN 202.5 // Min RPM of model. $31 < RPM_MIN will be limited to RPM_MIN.
|
||||
#define RPM_POINT12 6145.4 // Used N_PIECES >=2. Junction point between lines 1 and 2.
|
||||
#define RPM_POINT23 9627.8 // Used N_PIECES >=3. Junction point between lines 2 and 3.
|
||||
#define RPM_POINT34 10813.9 // Used N_PIECES = 4. Junction point between lines 3 and 4.
|
||||
#define RPM_LINE_A1 3.197101e-03 // Used N_PIECES >=1. A and B constants of line 1.
|
||||
#define RPM_LINE_B1 -3.526076e-1
|
||||
#define RPM_LINE_A2 1.722950e-2 // Used N_PIECES >=2. A and B constants of line 2.
|
||||
#define RPM_LINE_B2 8.588176e+01
|
||||
#define RPM_LINE_A3 5.901518e-02 // Used N_PIECES >=3. A and B constants of line 3.
|
||||
#define RPM_LINE_B3 4.881851e+02
|
||||
#define RPM_LINE_A4 1.203413e-01 // Used N_PIECES = 4. A and B constants of line 4.
|
||||
#define RPM_LINE_B4 1.151360e+03
|
||||
*/
|
||||
|
||||
#define N_PIECES 3
|
||||
#define RPM_MAX 23935.2
|
||||
#define RPM_MIN 2412.2
|
||||
#define RPM_POINT12 6283.9
|
||||
#define RPM_POINT23 11866.0
|
||||
#define RPM_LINE_A1 4.390865e-03
|
||||
#define RPM_LINE_B1 7.591787e+00
|
||||
#define RPM_LINE_A2 1.074874e-02
|
||||
#define RPM_LINE_B2 4.754411e+01
|
||||
#define RPM_LINE_A3 9.528342e-03
|
||||
#define RPM_LINE_B3 3.306286e+01
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------------------------
|
||||
OEM Single File Configuration Option
|
||||
|
||||
Instructions: Paste the cpu_map and default setting definitions below without an enclosing
|
||||
#ifdef. Comment out the CPU_MAP_xxx and DEFAULT_xxx defines at the top of this file, and
|
||||
the compiler will ignore the contents of defaults.h and cpu_map.h and use the definitions
|
||||
below.
|
||||
*/
|
||||
|
||||
// Paste CPU_MAP definitions here.
|
||||
|
||||
// Paste default settings definitions here.
|
||||
|
||||
|
||||
#endif
|
140
Grbl_Esp32-master/Grbl_Esp32/coolant_control.cpp
Normal file
140
Grbl_Esp32-master/Grbl_Esp32/coolant_control.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
coolant_control.c - coolant control methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
void coolant_init()
|
||||
{
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
pinMode(COOLANT_FLOOD_PIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
pinMode(COOLANT_MIST_PIN, OUTPUT);
|
||||
#endif
|
||||
coolant_stop();
|
||||
}
|
||||
|
||||
|
||||
// Returns current coolant output state. Overrides may alter it from programmed state.
|
||||
uint8_t coolant_get_state()
|
||||
{
|
||||
uint8_t cl_state = COOLANT_STATE_DISABLE;
|
||||
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
if (! digitalRead(COOLANT_FLOOD_PIN)) {
|
||||
#else
|
||||
if (digitalRead(COOLANT_FLOOD_PIN)) {
|
||||
#endif
|
||||
cl_state |= COOLANT_STATE_FLOOD;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
if (! digitalRead(COOLANT_MIST_PIN)) {
|
||||
#else
|
||||
if (digitalRead(COOLANT_MIST_PIN)) {
|
||||
#endif
|
||||
cl_state |= COOLANT_STATE_MIST;
|
||||
}
|
||||
#endif
|
||||
|
||||
return(cl_state);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Directly called by coolant_init(), coolant_set_state(), and mc_reset(), which can be at
|
||||
// an interrupt-level. No report flag set, but only called by routines that don't need it.
|
||||
void coolant_stop()
|
||||
{
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 1);
|
||||
#else
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 0);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
digitalWrite(COOLANT_MIST_PIN, 1);
|
||||
#else
|
||||
digitalWrite(COOLANT_MIST_PIN, 0);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Main program only. Immediately sets flood coolant running state and also mist coolant,
|
||||
// if enabled. Also sets a flag to report an update to a coolant state.
|
||||
// Called by coolant toggle override, parking restore, parking retract, sleep mode, g-code
|
||||
// parser program end, and g-code parser coolant_sync().
|
||||
void coolant_set_state(uint8_t mode)
|
||||
{
|
||||
if (sys.abort) { return; } // Block during abort.
|
||||
|
||||
if (mode == COOLANT_DISABLE) {
|
||||
|
||||
coolant_stop();
|
||||
|
||||
} else {
|
||||
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
if (mode & COOLANT_FLOOD_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_FLOOD_PIN
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 0);
|
||||
#else
|
||||
digitalWrite(COOLANT_FLOOD_PIN, 1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
if (mode & COOLANT_MIST_ENABLE) {
|
||||
#ifdef INVERT_COOLANT_MIST_PIN
|
||||
digitalWrite(COOLANT_MIST_PIN, 0);
|
||||
#else
|
||||
digitalWrite(COOLANT_MIST_PIN, 1);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
|
||||
// G-code parser entry-point for setting coolant state. Forces a planner buffer sync and bails
|
||||
// if an abort or check-mode is active.
|
||||
void coolant_sync(uint8_t mode)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
protocol_buffer_synchronize(); // Ensure coolant turns on when specified in program.
|
||||
coolant_set_state(mode);
|
||||
}
|
50
Grbl_Esp32-master/Grbl_Esp32/coolant_control.h
Normal file
50
Grbl_Esp32-master/Grbl_Esp32/coolant_control.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
coolant_control.h - spindle control methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef coolant_control_h
|
||||
#define coolant_control_h
|
||||
|
||||
#define COOLANT_NO_SYNC false
|
||||
#define COOLANT_FORCE_SYNC true
|
||||
|
||||
#define COOLANT_STATE_DISABLE 0 // Must be zero
|
||||
#define COOLANT_STATE_FLOOD bit(0)
|
||||
#define COOLANT_STATE_MIST bit(1)
|
||||
|
||||
|
||||
// Initializes coolant control pins.
|
||||
void coolant_init();
|
||||
|
||||
// Returns current coolant output state. Overrides may alter it from programmed state.
|
||||
uint8_t coolant_get_state();
|
||||
|
||||
// Immediately disables coolant pins.
|
||||
void coolant_stop();
|
||||
|
||||
// Sets the coolant pins according to state specified.
|
||||
void coolant_set_state(uint8_t mode);
|
||||
|
||||
// G-code parser entry-point for setting coolant states. Checks for and executes additional conditions.
|
||||
void coolant_sync(uint8_t mode);
|
||||
|
||||
#endif
|
1130
Grbl_Esp32-master/Grbl_Esp32/cpu_map.h
Normal file
1130
Grbl_Esp32-master/Grbl_Esp32/cpu_map.h
Normal file
File diff suppressed because it is too large
Load Diff
BIN
Grbl_Esp32-master/Grbl_Esp32/data/favicon.ico
Normal file
BIN
Grbl_Esp32-master/Grbl_Esp32/data/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
Grbl_Esp32-master/Grbl_Esp32/data/index.html.gz
Normal file
BIN
Grbl_Esp32-master/Grbl_Esp32/data/index.html.gz
Normal file
Binary file not shown.
320
Grbl_Esp32-master/Grbl_Esp32/defaults.h
Normal file
320
Grbl_Esp32-master/Grbl_Esp32/defaults.h
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
defaults.h - defaults settings configuration file
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* The defaults.h file serves as a central default settings selector for different machine
|
||||
types, from DIY CNC mills to CNC conversions of off-the-shelf machines. The settings
|
||||
files listed here are supplied by users, so your results may vary. However, this should
|
||||
give you a good starting point as you get to know your machine and tweak the settings for
|
||||
your nefarious needs.
|
||||
NOTE: Ensure one and only one of these DEFAULTS_XXX values is defined in config.h */
|
||||
|
||||
#ifndef defaults_h
|
||||
|
||||
/*
|
||||
All of these settings check to see if they have been defined already
|
||||
before defining them. This allows to to easily set them eslewhere.
|
||||
You only need to set ones that are important or unique to your
|
||||
machine. The rest will be pulled from here.
|
||||
*/
|
||||
|
||||
// Grbl generic default settings. Should work across different machines.
|
||||
#ifndef DEFAULT_STEP_PULSE_MICROSECONDS
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 3 // $0
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STEPPER_IDLE_LOCK_TIME
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 250 // $1 msec (0-254, 255 keeps steppers enabled)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STEPPING_INVERT_MASK
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0 // $2 uint8_t
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_DIRECTION_INVERT_MASK
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 0 // $3 uint8_
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_ST_ENABLE
|
||||
#define DEFAULT_INVERT_ST_ENABLE 0 // $4 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_LIMIT_PINS
|
||||
#define DEFAULT_INVERT_LIMIT_PINS 1 // $5 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_INVERT_PROBE_PIN
|
||||
#define DEFAULT_INVERT_PROBE_PIN 0 // $6 boolean
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_STATUS_REPORT_MASK
|
||||
#define DEFAULT_STATUS_REPORT_MASK 1 // $10
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_JUNCTION_DEVIATION
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // $11 mm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_ARC_TOLERANCE
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // $12 mm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_REPORT_INCHES
|
||||
#define DEFAULT_REPORT_INCHES 0 // $13 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SOFT_LIMIT_ENABLE
|
||||
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // $20 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HARD_LIMIT_ENABLE
|
||||
#define DEFAULT_HARD_LIMIT_ENABLE 0 // $21 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_ENABLE
|
||||
#define DEFAULT_HOMING_ENABLE 0 // $22 false
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_DIR_MASK
|
||||
#define DEFAULT_HOMING_DIR_MASK 3 // $23 move positive dir Z, negative X,Y
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_FEED_RATE
|
||||
#define DEFAULT_HOMING_FEED_RATE 200.0 // $24 mm/min
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_SEEK_RATE
|
||||
#define DEFAULT_HOMING_SEEK_RATE 2000.0 // $25 mm/min
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_DEBOUNCE_DELAY
|
||||
#define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // $26 msec (0-65k)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_HOMING_PULLOFF
|
||||
#define DEFAULT_HOMING_PULLOFF 1.0 // $27 mm
|
||||
#endif
|
||||
|
||||
// ======== sPINDLE STUFF ====================
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_FREQ
|
||||
#define DEFAULT_SPINDLE_FREQ 5000.0 // $33 Hz (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_OFF_VALUE
|
||||
#define DEFAULT_SPINDLE_OFF_VALUE 0.0 // $34 Percent (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_MIN_VALUE
|
||||
#define DEFAULT_SPINDLE_MIN_VALUE 0.0 // $35 Percent (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_MAX_VALUE
|
||||
#define DEFAULT_SPINDLE_MAX_VALUE 100.0 // $36 Percent (extended set)
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_RPM_MAX
|
||||
#define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef DEFAULT_SPINDLE_RPM_MIN
|
||||
#define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
|
||||
#endif
|
||||
|
||||
#ifndef DEFAULT_LASER_MODE
|
||||
#define DEFAULT_LASER_MODE 0 // false
|
||||
#endif
|
||||
|
||||
|
||||
// =========== AXIS RESOLUTION ======
|
||||
|
||||
#ifndef DEFAULT_X_STEPS_PER_MM
|
||||
#define DEFAULT_X_STEPS_PER_MM 800.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_STEPS_PER_MM
|
||||
#define DEFAULT_Y_STEPS_PER_MM 800.0
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_STEPS_PER_MM
|
||||
#define DEFAULT_Z_STEPS_PER_MM 800.0
|
||||
#endif
|
||||
#ifndef DEFAULT_A_STEPS_PER_MM
|
||||
#define DEFAULT_A_STEPS_PER_MM 800.0
|
||||
#endif
|
||||
#ifndef DEFAULT_B_STEPS_PER_MM
|
||||
#define DEFAULT_B_STEPS_PER_MM 800.0
|
||||
#endif
|
||||
#ifndef DEFAULT_C_STEPS_PER_MM
|
||||
#define DEFAULT_C_STEPS_PER_MM 800.0
|
||||
#endif
|
||||
|
||||
// ============ AXIS MAX SPPED =========
|
||||
|
||||
#ifndef DEFAULT_X_MAX_RATE
|
||||
#define DEFAULT_X_MAX_RATE 5000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MAX_RATE
|
||||
#define DEFAULT_Y_MAX_RATE 5000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MAX_RATE
|
||||
#define DEFAULT_Z_MAX_RATE 5000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MAX_RATE
|
||||
#define DEFAULT_A_MAX_RATE 5000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MAX_RATE
|
||||
#define DEFAULT_B_MAX_RATE 5000.0 // mm/min
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MAX_RATE
|
||||
#define DEFAULT_C_MAX_RATE 5000.0 // mm/min
|
||||
#endif
|
||||
|
||||
// ============== Axis Acceleration =========
|
||||
|
||||
#ifndef DEFAULT_X_ACCELERATION
|
||||
#define DEFAULT_X_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_ACCELERATION
|
||||
#define DEFAULT_Y_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_ACCELERATION
|
||||
#define DEFAULT_Z_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#endif
|
||||
#ifndef DEFAULT_A_ACCELERATION
|
||||
#define DEFAULT_A_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#endif
|
||||
#ifndef DEFAULT_B_ACCELERATION
|
||||
#define DEFAULT_B_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#endif
|
||||
#ifndef DEFAULT_C_ACCELERATION
|
||||
#define DEFAULT_C_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#endif
|
||||
|
||||
// ========= AXIS MAX TRAVEL ============
|
||||
|
||||
#ifndef DEFAULT_X_MAX_TRAVEL
|
||||
#define DEFAULT_X_MAX_TRAVEL 300.0 // $130 mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MAX_TRAVEL
|
||||
#define DEFAULT_Y_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MAX_TRAVEL
|
||||
#define DEFAULT_Z_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_A_TRAVEL
|
||||
#define DEFAULT_A_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MAX_TRAVEL
|
||||
#define DEFAULT_B_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MAX_TRAVEL
|
||||
#define DEFAULT_C_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#endif
|
||||
|
||||
// ========== Motor current (SPI Drivers ) =============
|
||||
#ifndef DEFAULT_X_CURRENT
|
||||
#define DEFAULT_X_CURRENT 0.25 // $140 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_CURRENT
|
||||
#define DEFAULT_Y_CURRENT 0.25 // $141 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_CURRENT
|
||||
#define DEFAULT_Z_CURRENT 0.25 // $142 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_CURRENT
|
||||
#define DEFAULT_A_CURRENT 0.25 // $143 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_CURRENT
|
||||
#define DEFAULT_B_CURRENT 0.25 // $144 current in amps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_CURRENT
|
||||
#define DEFAULT_C_CURRENT 0.25 // $145 current in amps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Motor hold current (SPI Drivers ) =============
|
||||
|
||||
#ifndef DEFAULT_X_HOLD_CURRENT
|
||||
#define DEFAULT_X_HOLD_CURRENT 50 // $150 percent of run current (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_HOLD_CURRENT
|
||||
#define DEFAULT_Y_HOLD_CURRENT 50 // $151 percent of run current (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_HOLD_CURRENT
|
||||
#define DEFAULT_Z_HOLD_CURRENT 50 // $152 percent of run current (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_HOLD_CURRENT
|
||||
#define DEFAULT_A_HOLD_CURRENT 50 // $153 percent of run current (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_HOLD_CURRENT
|
||||
#define DEFAULT_B_HOLD_CURRENT 50 // $154 percent of run current (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_HOLD_CURRENT
|
||||
#define DEFAULT_C_HOLD_CURRENT 50 // $154 percent of run current (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Microsteps (SPI Drivers ) ================
|
||||
|
||||
#ifndef DEFAULT_X_MICROSTEPS
|
||||
#define DEFAULT_X_MICROSTEPS 16 // $160 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_MICROSTEPS
|
||||
#define DEFAULT_Y_MICROSTEPS 16 // $161 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_MICROSTEPS
|
||||
#define DEFAULT_Z_MICROSTEPS 16 // $162 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_MICROSTEPS
|
||||
#define DEFAULT_A_MICROSTEPS 16 // $163 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_MICROSTEPS
|
||||
#define DEFAULT_B_MICROSTEPS 16 // $164 micro steps (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_MICROSTEPS
|
||||
#define DEFAULT_C_MICROSTEPS 16 // $165 micro steps (extended set)
|
||||
#endif
|
||||
|
||||
// ========== Stallguard (SPI Drivers ) ================
|
||||
|
||||
#ifndef DEFAULT_X_STALLGUARD
|
||||
#define DEFAULT_X_STALLGUARD 16 // $170 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Y_STALLGUARD
|
||||
#define DEFAULT_Y_STALLGUARD 16 // $171 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_Z_STALLGUARD
|
||||
#define DEFAULT_Z_STALLGUARD 16 // $172 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_A_STALLGUARD
|
||||
#define DEFAULT_A_STALLGUARD 16 // $173 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_B_STALLGUARD
|
||||
#define DEFAULT_B_STALLGUARD 16 // $174 stallguard (extended set)
|
||||
#endif
|
||||
#ifndef DEFAULT_C_STALLGUARD
|
||||
#define DEFAULT_C_STALLGUARD 16 // $175 stallguard (extended set)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
112
Grbl_Esp32-master/Grbl_Esp32/espresponse.cpp
Normal file
112
Grbl_Esp32-master/Grbl_Esp32/espresponse.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
espresponse.cpp - GRBL_ESP response class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "config.h"
|
||||
#include "espresponse.h"
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
#include "web_server.h"
|
||||
#include <WebServer.h>
|
||||
#endif
|
||||
|
||||
#include "report.h"
|
||||
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
ESPResponseStream::ESPResponseStream(WebServer * webserver){
|
||||
_header_sent=false;
|
||||
_webserver = webserver;
|
||||
_client = CLIENT_WEBUI;
|
||||
}
|
||||
#endif
|
||||
|
||||
ESPResponseStream::ESPResponseStream(){
|
||||
_client = CLIENT_INPUT;
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
_header_sent=false;
|
||||
_webserver = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
ESPResponseStream::ESPResponseStream(uint8_t client, bool byid){
|
||||
(void)byid; //fake parameter to avoid confusion with pointer one (NULL == 0)
|
||||
_client = client;
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
_header_sent=false;
|
||||
_webserver = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ESPResponseStream::println(const char *data){
|
||||
print(data);
|
||||
if (_client == CLIENT_TELNET) print("\r\n");
|
||||
else print("\n");
|
||||
}
|
||||
|
||||
//helper to format size to readable string
|
||||
String ESPResponseStream::formatBytes (uint64_t bytes)
|
||||
{
|
||||
if (bytes < 1024) {
|
||||
return String ((uint16_t)bytes) + " B";
|
||||
} else if (bytes < (1024 * 1024) ) {
|
||||
return String ((float)(bytes / 1024.0),2) + " KB";
|
||||
} else if (bytes < (1024 * 1024 * 1024) ) {
|
||||
return String ((float)(bytes / 1024.0 / 1024.0),2) + " MB";
|
||||
} else {
|
||||
return String ((float)(bytes / 1024.0 / 1024.0 / 1024.0),2) + " GB";
|
||||
}
|
||||
}
|
||||
|
||||
void ESPResponseStream::print(const char *data){
|
||||
if (_client == CLIENT_INPUT) return;
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
if (_webserver) {
|
||||
if (!_header_sent) {
|
||||
_webserver->setContentLength(CONTENT_LENGTH_UNKNOWN);
|
||||
_webserver->sendHeader("Content-Type","text/html");
|
||||
_webserver->sendHeader("Cache-Control","no-cache");
|
||||
_webserver->send(200);
|
||||
_header_sent = true;
|
||||
}
|
||||
_buffer+=data;
|
||||
if (_buffer.length() > 1200) {
|
||||
//send data
|
||||
_webserver->sendContent(_buffer);
|
||||
//reset buffer
|
||||
_buffer = "";
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (_client == CLIENT_WEBUI) return; //this is sanity check
|
||||
grbl_send(_client, data);
|
||||
}
|
||||
|
||||
void ESPResponseStream::flush(){
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
if (_webserver) {
|
||||
if(_header_sent) {
|
||||
//send data
|
||||
if(_buffer.length() > 0)_webserver->sendContent(_buffer);
|
||||
//close connection
|
||||
_webserver->sendContent("");
|
||||
}
|
||||
_header_sent = false;
|
||||
_buffer = "";
|
||||
}
|
||||
#endif
|
||||
}
|
50
Grbl_Esp32-master/Grbl_Esp32/espresponse.h
Normal file
50
Grbl_Esp32-master/Grbl_Esp32/espresponse.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
espresponse.h - GRBL_ESP response class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef ESPRESPONSE_h
|
||||
#define ESPRESPONSE_h
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
class WebServer;
|
||||
#endif
|
||||
|
||||
class ESPResponseStream{
|
||||
public:
|
||||
void print(const char *data);
|
||||
void println(const char *data);
|
||||
void flush();
|
||||
static String formatBytes (uint64_t bytes);
|
||||
uint8_t client() {return _client;}
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
ESPResponseStream(WebServer * webserver);
|
||||
#endif
|
||||
ESPResponseStream(uint8_t client, bool byid = true);
|
||||
ESPResponseStream();
|
||||
private:
|
||||
uint8_t _client;
|
||||
#if defined (ENABLE_HTTP) && defined(ENABLE_WIFI)
|
||||
bool _header_sent;
|
||||
WebServer * _webserver;
|
||||
String _buffer;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
1460
Grbl_Esp32-master/Grbl_Esp32/gcode.cpp
Normal file
1460
Grbl_Esp32-master/Grbl_Esp32/gcode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
257
Grbl_Esp32-master/Grbl_Esp32/gcode.h
Normal file
257
Grbl_Esp32-master/Grbl_Esp32/gcode.h
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
gcode.h - rs274/ngc parser.
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef gcode_h
|
||||
#define gcode_h
|
||||
|
||||
|
||||
// Define modal group internal numbers for checking multiple command violations and tracking the
|
||||
// type of command that is called in the block. A modal group is a group of g-code commands that are
|
||||
// mutually exclusive, or cannot exist on the same line, because they each toggle a state or execute
|
||||
// a unique motion. These are defined in the NIST RS274-NGC v3 g-code standard, available online,
|
||||
// and are similar/identical to other g-code interpreters by manufacturers (Haas,Fanuc,Mazak,etc).
|
||||
// NOTE: Modal group define values must be sequential and starting from zero.
|
||||
#define MODAL_GROUP_G0 0 // [G4,G10,G28,G28.1,G30,G30.1,G53,G92,G92.1] Non-modal
|
||||
#define MODAL_GROUP_G1 1 // [G0,G1,G2,G3,G38.2,G38.3,G38.4,G38.5,G80] Motion
|
||||
#define MODAL_GROUP_G2 2 // [G17,G18,G19] Plane selection
|
||||
#define MODAL_GROUP_G3 3 // [G90,G91] Distance mode
|
||||
#define MODAL_GROUP_G4 4 // [G91.1] Arc IJK distance mode
|
||||
#define MODAL_GROUP_G5 5 // [G93,G94] Feed rate mode
|
||||
#define MODAL_GROUP_G6 6 // [G20,G21] Units
|
||||
#define MODAL_GROUP_G7 7 // [G40] Cutter radius compensation mode. G41/42 NOT SUPPORTED.
|
||||
#define MODAL_GROUP_G8 8 // [G43.1,G49] Tool length offset
|
||||
#define MODAL_GROUP_G12 9 // [G54,G55,G56,G57,G58,G59] Coordinate system selection
|
||||
#define MODAL_GROUP_G13 10 // [G61] Control mode
|
||||
|
||||
#define MODAL_GROUP_M4 11 // [M0,M1,M2,M30] Stopping
|
||||
#define MODAL_GROUP_M6 14 // [M6] Tool change
|
||||
#define MODAL_GROUP_M7 12 // [M3,M4,M5] Spindle turning
|
||||
#define MODAL_GROUP_M8 13 // [M7,M8,M9] Coolant control
|
||||
#define MODAL_GROUP_M10 14 // [M62, M63] User Defined http://linuxcnc.org/docs/html/gcode/overview.html#_modal_groups
|
||||
|
||||
// #define OTHER_INPUT_F 14
|
||||
// #define OTHER_INPUT_S 15
|
||||
// #define OTHER_INPUT_T 16
|
||||
|
||||
// Define command actions for within execution-type modal groups (motion, stopping, non-modal). Used
|
||||
// internally by the parser to know which command to execute.
|
||||
// NOTE: Some macro values are assigned specific values to make g-code state reporting and parsing
|
||||
// compile a litte smaller. Necessary due to being completely out of flash on the 328p. Although not
|
||||
// ideal, just be careful with values that state 'do not alter' and check both report.c and gcode.c
|
||||
// to see how they are used, if you need to alter them.
|
||||
|
||||
// Modal Group G0: Non-modal actions
|
||||
#define NON_MODAL_NO_ACTION 0 // (Default: Must be zero)
|
||||
#define NON_MODAL_DWELL 4 // G4 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_DATA 10 // G10 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_0 28 // G28 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_0 38 // G28.1 (Do not alter value)
|
||||
#define NON_MODAL_GO_HOME_1 30 // G30 (Do not alter value)
|
||||
#define NON_MODAL_SET_HOME_1 40 // G30.1 (Do not alter value)
|
||||
#define NON_MODAL_ABSOLUTE_OVERRIDE 53 // G53 (Do not alter value)
|
||||
#define NON_MODAL_SET_COORDINATE_OFFSET 92 // G92 (Do not alter value)
|
||||
#define NON_MODAL_RESET_COORDINATE_OFFSET 102 //G92.1 (Do not alter value)
|
||||
|
||||
// Modal Group G1: Motion modes
|
||||
#define MOTION_MODE_SEEK 0 // G0 (Default: Must be zero)
|
||||
#define MOTION_MODE_LINEAR 1 // G1 (Do not alter value)
|
||||
#define MOTION_MODE_CW_ARC 2 // G2 (Do not alter value)
|
||||
#define MOTION_MODE_CCW_ARC 3 // G3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD 140 // G38.2 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_TOWARD_NO_ERROR 141 // G38.3 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY 142 // G38.4 (Do not alter value)
|
||||
#define MOTION_MODE_PROBE_AWAY_NO_ERROR 143 // G38.5 (Do not alter value)
|
||||
#define MOTION_MODE_NONE 80 // G80 (Do not alter value)
|
||||
|
||||
// Modal Group G2: Plane select
|
||||
#define PLANE_SELECT_XY 0 // G17 (Default: Must be zero)
|
||||
#define PLANE_SELECT_ZX 1 // G18 (Do not alter value)
|
||||
#define PLANE_SELECT_YZ 2 // G19 (Do not alter value)
|
||||
|
||||
// Modal Group G3: Distance mode
|
||||
#define DISTANCE_MODE_ABSOLUTE 0 // G90 (Default: Must be zero)
|
||||
#define DISTANCE_MODE_INCREMENTAL 1 // G91 (Do not alter value)
|
||||
|
||||
// Modal Group G4: Arc IJK distance mode
|
||||
#define DISTANCE_ARC_MODE_INCREMENTAL 0 // G91.1 (Default: Must be zero)
|
||||
|
||||
// Modal Group M4: Program flow
|
||||
#define PROGRAM_FLOW_RUNNING 0 // (Default: Must be zero)
|
||||
#define PROGRAM_FLOW_PAUSED 3 // M0
|
||||
#define PROGRAM_FLOW_OPTIONAL_STOP 1 // M1 NOTE: Not supported, but valid and ignored.
|
||||
#define PROGRAM_FLOW_COMPLETED_M2 2 // M2 (Do not alter value)
|
||||
#define PROGRAM_FLOW_COMPLETED_M30 30 // M30 (Do not alter value)
|
||||
|
||||
// Modal Group G5: Feed rate mode
|
||||
#define FEED_RATE_MODE_UNITS_PER_MIN 0 // G94 (Default: Must be zero)
|
||||
#define FEED_RATE_MODE_INVERSE_TIME 1 // G93 (Do not alter value)
|
||||
|
||||
// Modal Group G6: Units mode
|
||||
#define UNITS_MODE_MM 0 // G21 (Default: Must be zero)
|
||||
#define UNITS_MODE_INCHES 1 // G20 (Do not alter value)
|
||||
|
||||
// Modal Group G7: Cutter radius compensation mode
|
||||
#define CUTTER_COMP_DISABLE 0 // G40 (Default: Must be zero)
|
||||
|
||||
// Modal Group G13: Control mode
|
||||
#define CONTROL_MODE_EXACT_PATH 0 // G61 (Default: Must be zero)
|
||||
|
||||
// Modal Group M7: Spindle control
|
||||
#define SPINDLE_DISABLE 0 // M5 (Default: Must be zero)
|
||||
#define SPINDLE_ENABLE_CW PL_COND_FLAG_SPINDLE_CW // M3 (NOTE: Uses planner condition bit flag)
|
||||
#define SPINDLE_ENABLE_CCW PL_COND_FLAG_SPINDLE_CCW // M4 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// Modal Group M8: Coolant control
|
||||
#define COOLANT_DISABLE 0 // M9 (Default: Must be zero)
|
||||
#define COOLANT_FLOOD_ENABLE PL_COND_FLAG_COOLANT_FLOOD // M8 (NOTE: Uses planner condition bit flag)
|
||||
#define COOLANT_MIST_ENABLE PL_COND_FLAG_COOLANT_MIST // M7 (NOTE: Uses planner condition bit flag)
|
||||
|
||||
// modal Group M10: User I/O control
|
||||
#define NON_MODAL_IO_ENABLE 1
|
||||
#define NON_MODAL_IO_DISABLE 2
|
||||
#define MAX_USER_DIGITAL_PIN 4
|
||||
|
||||
// Modal Group G8: Tool length offset
|
||||
#define TOOL_LENGTH_OFFSET_CANCEL 0 // G49 (Default: Must be zero)
|
||||
#define TOOL_LENGTH_OFFSET_ENABLE_DYNAMIC 1 // G43.1
|
||||
|
||||
#define TOOL_CHANGE 1
|
||||
|
||||
// Modal Group G12: Active work coordinate system
|
||||
// N/A: Stores coordinate system value (54-59) to change to.
|
||||
|
||||
// Define parameter word mapping.
|
||||
#define WORD_F 0
|
||||
#define WORD_I 1
|
||||
#define WORD_J 2
|
||||
#define WORD_K 3
|
||||
#define WORD_L 4
|
||||
#define WORD_N 5
|
||||
#define WORD_P 6
|
||||
#define WORD_R 7
|
||||
#define WORD_S 8
|
||||
#define WORD_T 9
|
||||
#define WORD_X 10
|
||||
#define WORD_Y 11
|
||||
#define WORD_Z 12
|
||||
#define WORD_A 13
|
||||
#define WORD_B 14
|
||||
#define WORD_C 15
|
||||
|
||||
// Define g-code parser position updating flags
|
||||
#define GC_UPDATE_POS_TARGET 0 // Must be zero
|
||||
#define GC_UPDATE_POS_SYSTEM 1
|
||||
#define GC_UPDATE_POS_NONE 2
|
||||
|
||||
// Define probe cycle exit states and assign proper position updating.
|
||||
#define GC_PROBE_FOUND GC_UPDATE_POS_SYSTEM
|
||||
#define GC_PROBE_ABORT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_INIT GC_UPDATE_POS_NONE
|
||||
#define GC_PROBE_FAIL_END GC_UPDATE_POS_TARGET
|
||||
#ifdef SET_CHECK_MODE_PROBE_TO_START
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_NONE
|
||||
#else
|
||||
#define GC_PROBE_CHECK_MODE GC_UPDATE_POS_TARGET
|
||||
#endif
|
||||
|
||||
// Define gcode parser flags for handling special cases.
|
||||
#define GC_PARSER_NONE 0 // Must be zero.
|
||||
#define GC_PARSER_JOG_MOTION bit(0)
|
||||
#define GC_PARSER_CHECK_MANTISSA bit(1)
|
||||
#define GC_PARSER_ARC_IS_CLOCKWISE bit(2)
|
||||
#define GC_PARSER_PROBE_IS_AWAY bit(3)
|
||||
#define GC_PARSER_PROBE_IS_NO_ERROR bit(4)
|
||||
#define GC_PARSER_LASER_FORCE_SYNC bit(5)
|
||||
#define GC_PARSER_LASER_DISABLE bit(6)
|
||||
#define GC_PARSER_LASER_ISMOTION bit(7)
|
||||
|
||||
|
||||
// NOTE: When this struct is zeroed, the above defines set the defaults for the system.
|
||||
typedef struct {
|
||||
uint8_t motion; // {G0,G1,G2,G3,G38.2,G80}
|
||||
uint8_t feed_rate; // {G93,G94}
|
||||
uint8_t units; // {G20,G21}
|
||||
uint8_t distance; // {G90,G91}
|
||||
// uint8_t distance_arc; // {G91.1} NOTE: Don't track. Only default supported.
|
||||
uint8_t plane_select; // {G17,G18,G19}
|
||||
// uint8_t cutter_comp; // {G40} NOTE: Don't track. Only default supported.
|
||||
uint8_t tool_length; // {G43.1,G49}
|
||||
uint8_t coord_select; // {G54,G55,G56,G57,G58,G59}
|
||||
// uint8_t control; // {G61} NOTE: Don't track. Only default supported.
|
||||
uint8_t program_flow; // {M0,M1,M2,M30}
|
||||
uint8_t coolant; // {M7,M8,M9}
|
||||
uint8_t spindle; // {M3,M4,M5}
|
||||
uint8_t tool_change; // {M6}
|
||||
uint8_t io_control; // {M62, M63}
|
||||
} gc_modal_t;
|
||||
|
||||
typedef struct {
|
||||
float f; // Feed
|
||||
float ijk[N_AXIS]; // I,J,K Axis arc offsets
|
||||
uint8_t l; // G10 or canned cycles parameters
|
||||
int32_t n; // Line number
|
||||
float p; // G10 or dwell parameters
|
||||
// float q; // G82 peck drilling
|
||||
float r; // Arc radius
|
||||
float s; // Spindle speed
|
||||
uint8_t t; // Tool selection
|
||||
float xyz[N_AXIS]; // X,Y,Z Translational axes
|
||||
} gc_values_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
gc_modal_t modal;
|
||||
|
||||
float spindle_speed; // RPM
|
||||
float feed_rate; // Millimeters/min
|
||||
uint8_t tool; // Tracks tool number. NOT USED.
|
||||
int32_t line_number; // Last line number sent
|
||||
|
||||
float position[N_AXIS]; // Where the interpreter considers the tool to be at this point in the code
|
||||
|
||||
float coord_system[N_AXIS]; // Current work coordinate system (G54+). Stores offset from absolute machine
|
||||
// position in mm. Loaded from EEPROM when called.
|
||||
float coord_offset[N_AXIS]; // Retains the G92 coordinate offset (work coordinates) relative to
|
||||
// machine zero in mm. Non-persistent. Cleared upon reset and boot.
|
||||
float tool_length_offset; // Tracks tool length offset value when enabled.
|
||||
} parser_state_t;
|
||||
extern parser_state_t gc_state;
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t non_modal_command;
|
||||
gc_modal_t modal;
|
||||
gc_values_t values;
|
||||
} parser_block_t;
|
||||
|
||||
|
||||
// Initialize the parser
|
||||
void gc_init();
|
||||
|
||||
// Execute one block of rs275/ngc/g-code
|
||||
uint8_t gc_execute_line(char *line, uint8_t client);
|
||||
|
||||
// Set g-code parser position. Input in steps.
|
||||
void gc_sync_position();
|
||||
|
||||
#endif
|
95
Grbl_Esp32-master/Grbl_Esp32/grbl.h
Normal file
95
Grbl_Esp32-master/Grbl_Esp32/grbl.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
grbl.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Grbl versioning system
|
||||
#define GRBL_VERSION "1.1f"
|
||||
#define GRBL_VERSION_BUILD "20191208"
|
||||
|
||||
//#include <sdkconfig.h>
|
||||
#include <Arduino.h>
|
||||
#include <EEPROM.h>
|
||||
#include <driver/rmt.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include "driver/timer.h"
|
||||
|
||||
// Define the Grbl system include files. NOTE: Do not alter organization.
|
||||
#include "config.h"
|
||||
#include "nuts_bolts.h"
|
||||
#include "cpu_map.h"
|
||||
#include "tdef.h"
|
||||
|
||||
#include "defaults.h"
|
||||
#include "settings.h"
|
||||
#include "system.h"
|
||||
|
||||
#include "planner.h"
|
||||
#include "coolant_control.h"
|
||||
#include "grbl_eeprom.h"
|
||||
#include "gcode.h"
|
||||
#include "grbl_limits.h"
|
||||
#include "motion_control.h"
|
||||
#include "print.h"
|
||||
#include "probe.h"
|
||||
#include "protocol.h"
|
||||
#include "report.h"
|
||||
#include "serial.h"
|
||||
#include "spindle_control.h"
|
||||
#include "stepper.h"
|
||||
#include "jog.h"
|
||||
#include "inputbuffer.h"
|
||||
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
#include "BTconfig.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SD_CARD
|
||||
#include "grbl_sd.h"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
#include "wificonfig.h"
|
||||
#ifdef ENABLE_HTTP
|
||||
#include "serial2socket.h"
|
||||
#endif
|
||||
#ifdef ENABLE_TELNET
|
||||
#include "telnet_server.h"
|
||||
#endif
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
#include "notifications_service.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "servo_pen.h"
|
||||
#include "solenoid_pen.h"
|
||||
|
||||
#ifdef USE_SERVO_AXES
|
||||
#include "servo_axis.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_TRINAMIC
|
||||
#include "grbl_trinamic.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_UNIPOLAR
|
||||
#include "grbl_unipolar.h"
|
||||
#endif
|
||||
|
43
Grbl_Esp32-master/Grbl_Esp32/grbl_eeprom.cpp
Normal file
43
Grbl_Esp32-master/Grbl_Esp32/grbl_eeprom.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
eeprom.cpp - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size) {
|
||||
unsigned char checksum = 0;
|
||||
for(; size > 0; size--) {
|
||||
checksum = (checksum << 1) || (checksum >> 7);
|
||||
checksum += *source;
|
||||
EEPROM.write(destination++, *(source++));
|
||||
}
|
||||
EEPROM.write(destination, checksum);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size) {
|
||||
unsigned char data, checksum = 0;
|
||||
for(; size > 0; size--) {
|
||||
data = EEPROM.read(source++);
|
||||
checksum = (checksum << 1) || (checksum >> 7);
|
||||
checksum += data;
|
||||
*(destination++) = data;
|
||||
}
|
||||
return(checksum == EEPROM.read(source));
|
||||
}
|
31
Grbl_Esp32-master/Grbl_Esp32/grbl_eeprom.h
Normal file
31
Grbl_Esp32-master/Grbl_Esp32/grbl_eeprom.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
eeprom.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef eeprom_memcpy_h
|
||||
#define eeprom_memcpy_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
//unsigned char eeprom_get_char(unsigned int addr);
|
||||
//void eeprom_put_char(unsigned int addr, unsigned char new_value);
|
||||
void memcpy_to_eeprom_with_checksum(unsigned int destination, char *source, unsigned int size);
|
||||
int memcpy_from_eeprom_with_checksum(char *destination, unsigned int source, unsigned int size);
|
||||
|
||||
#endif
|
496
Grbl_Esp32-master/Grbl_Esp32/grbl_limits.cpp
Normal file
496
Grbl_Esp32-master/Grbl_Esp32/grbl_limits.cpp
Normal file
@ -0,0 +1,496 @@
|
||||
/*
|
||||
limits.c - code pertaining to limit-switches and performing the homing cycle
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
2018-12-29 - Wolfgang Lienbacher renamed file from limits.h to grbl_limits.h
|
||||
fixing ambiguation issues with limit.h in the esp32 Arduino Framework
|
||||
when compiling with VS-Code/PlatformIO.
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
xQueueHandle limit_sw_queue; // used by limit switch debouncing
|
||||
|
||||
// Homing axis search distance multiplier. Computed by this value times the cycle travel.
|
||||
#ifndef HOMING_AXIS_SEARCH_SCALAR
|
||||
#define HOMING_AXIS_SEARCH_SCALAR 1.1 // Must be > 1 to ensure limit switch will be engaged.
|
||||
#endif
|
||||
#ifndef HOMING_AXIS_LOCATE_SCALAR
|
||||
#define HOMING_AXIS_LOCATE_SCALAR 5.0 // Must be > 1 to ensure limit switch is cleared.
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR isr_limit_switches()
|
||||
{
|
||||
// Ignore limit switches if already in an alarm state or in-process of executing an alarm.
|
||||
// When in the alarm state, Grbl should have been reset or will force a reset, so any pending
|
||||
// moves in the planner and serial buffers are all cleared and newly sent blocks will be
|
||||
// locked out until a homing cycle or a kill lock command. Allows the user to disable the hard
|
||||
// limit setting if their limits are constantly triggering after a reset and move their axes.
|
||||
|
||||
if ( ( sys.state != STATE_ALARM) & (bit_isfalse(sys.state, STATE_HOMING)) ) {
|
||||
if (!(sys_rt_exec_alarm)) {
|
||||
|
||||
#ifdef ENABLE_SOFTWARE_DEBOUNCE
|
||||
// we will start a task that will recheck the switches after a small delay
|
||||
int evt;
|
||||
xQueueSendFromISR(limit_sw_queue, &evt, NULL);
|
||||
#else
|
||||
#ifdef HARD_LIMIT_FORCE_STATE_CHECK
|
||||
// Check limit pin state.
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
#else
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Homes the specified cycle axes, sets the machine position, and performs a pull-off motion after
|
||||
// completing. Homing is a special motion case, which involves rapid uncontrolled stops to locate
|
||||
// the trigger point of the limit switches. The rapid stops are handled by a system level axis lock
|
||||
// mask, which prevents the stepper algorithm from executing step pulses. Homing motions typically
|
||||
// circumvent the processes for executing motions in normal operation.
|
||||
// NOTE: Only the abort realtime command can interrupt this process.
|
||||
// TODO: Move limit pin-specific calls to a general function for portability.
|
||||
void limits_go_home(uint8_t cycle_mask)
|
||||
{
|
||||
if (sys.abort) { return; } // Block if system reset has been issued.
|
||||
|
||||
// Initialize plan data struct for homing motion. Spindle and coolant are disabled.
|
||||
plan_line_data_t plan_data;
|
||||
plan_line_data_t *pl_data = &plan_data;
|
||||
memset(pl_data,0,sizeof(plan_line_data_t));
|
||||
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
pl_data->line_number = HOMING_CYCLE_LINE_NUMBER;
|
||||
#endif
|
||||
|
||||
// Initialize variables used for homing computations.
|
||||
uint8_t n_cycle = (2*N_HOMING_LOCATE_CYCLE+1);
|
||||
uint8_t step_pin[N_AXIS];
|
||||
float target[N_AXIS];
|
||||
float max_travel = 0.0;
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// Initialize step pin masks
|
||||
step_pin[idx] = get_step_pin_mask(idx);
|
||||
#ifdef COREXY
|
||||
if ((idx==A_MOTOR)||(idx==B_MOTOR)) { step_pin[idx] = (get_step_pin_mask(X_AXIS)|get_step_pin_mask(Y_AXIS)); }
|
||||
#endif
|
||||
|
||||
if (bit_istrue(cycle_mask,bit(idx))) {
|
||||
// Set target based on max_travel setting. Ensure homing switches engaged with search scalar.
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
max_travel = MAX(max_travel,(-HOMING_AXIS_SEARCH_SCALAR)*settings.max_travel[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
// Set search mode with approach at seek rate to quickly engage the specified cycle_mask limit switches.
|
||||
bool approach = true;
|
||||
float homing_rate = settings.homing_seek_rate;
|
||||
|
||||
uint8_t limit_state, axislock, n_active_axis;
|
||||
do {
|
||||
|
||||
system_convert_array_steps_to_mpos(target,sys_position);
|
||||
|
||||
// Initialize and declare variables needed for homing routine.
|
||||
axislock = 0;
|
||||
n_active_axis = 0;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// Set target location for active axes and setup computation for homing rate.
|
||||
if (bit_istrue(cycle_mask,bit(idx))) {
|
||||
n_active_axis++;
|
||||
#ifdef COREXY
|
||||
if (idx == X_AXIS) {
|
||||
int32_t axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = axis_position;
|
||||
sys_position[B_MOTOR] = -axis_position;
|
||||
} else if (idx == Y_AXIS) {
|
||||
int32_t axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = sys_position[B_MOTOR] = axis_position;
|
||||
} else {
|
||||
sys_position[Z_AXIS] = 0;
|
||||
}
|
||||
#else
|
||||
sys_position[idx] = 0;
|
||||
#endif
|
||||
// Set target direction based on cycle mask and homing cycle approach state.
|
||||
// NOTE: This happens to compile smaller than any other implementation tried.
|
||||
if (bit_istrue(settings.homing_dir_mask,bit(idx))) {
|
||||
if (approach) { target[idx] = -max_travel; }
|
||||
else { target[idx] = max_travel; }
|
||||
} else {
|
||||
if (approach) { target[idx] = max_travel; }
|
||||
else { target[idx] = -max_travel; }
|
||||
}
|
||||
// Apply axislock to the step port pins active in this cycle.
|
||||
axislock |= step_pin[idx];
|
||||
}
|
||||
|
||||
}
|
||||
homing_rate *= sqrt(n_active_axis); // [sqrt(N_AXIS)] Adjust so individual axes all move at homing rate.
|
||||
sys.homing_axis_lock = axislock;
|
||||
|
||||
// Perform homing cycle. Planner buffer should be empty, as required to initiate the homing cycle.
|
||||
pl_data->feed_rate = homing_rate; // Set current homing rate.
|
||||
plan_buffer_line(target, pl_data); // Bypass mc_line(). Directly plan homing motion.
|
||||
|
||||
sys.step_control = STEP_CONTROL_EXECUTE_SYS_MOTION; // Set to execute homing motion and clear existing flags.
|
||||
st_prep_buffer(); // Prep and fill segment buffer from newly planned block.
|
||||
st_wake_up(); // Initiate motion
|
||||
do {
|
||||
if (approach) {
|
||||
// Check limit state. Lock out cycle axes when they change.
|
||||
limit_state = limits_get_state();
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (axislock & step_pin[idx]) {
|
||||
if (limit_state & (1 << idx)) {
|
||||
#ifdef COREXY
|
||||
if (idx==Z_AXIS) { axislock &= ~(step_pin[Z_AXIS]); }
|
||||
else { axislock &= ~(step_pin[A_MOTOR]|step_pin[B_MOTOR]); }
|
||||
#else
|
||||
axislock &= ~(step_pin[idx]);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
sys.homing_axis_lock = axislock;
|
||||
}
|
||||
|
||||
st_prep_buffer(); // Check and prep segment buffer. NOTE: Should take no longer than 200us.
|
||||
|
||||
// Exit routines: No time to run protocol_execute_realtime() in this loop.
|
||||
if (sys_rt_exec_state & (EXEC_SAFETY_DOOR | EXEC_RESET | EXEC_CYCLE_STOP)) {
|
||||
uint8_t rt_exec = sys_rt_exec_state;
|
||||
// Homing failure condition: Reset issued during cycle.
|
||||
if (rt_exec & EXEC_RESET) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
|
||||
// Homing failure condition: Safety door was opened.
|
||||
if (rt_exec & EXEC_SAFETY_DOOR) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_DOOR); }
|
||||
// Homing failure condition: Limit switch still engaged after pull-off motion
|
||||
if (!approach && (limits_get_state() & cycle_mask)) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_PULLOFF); }
|
||||
// Homing failure condition: Limit switch not found during approach.
|
||||
if (approach && (rt_exec & EXEC_CYCLE_STOP)) { system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_APPROACH); }
|
||||
if (sys_rt_exec_alarm) {
|
||||
mc_reset(); // Stop motors, if they are running.
|
||||
protocol_execute_realtime();
|
||||
return;
|
||||
} else {
|
||||
// Pull-off motion complete. Disable CYCLE_STOP from executing.
|
||||
system_clear_exec_state_flag(EXEC_CYCLE_STOP);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} while (STEP_MASK & axislock);
|
||||
|
||||
st_reset(); // Immediately force kill steppers and reset step segment buffer.
|
||||
delay_ms(settings.homing_debounce_delay); // Delay to allow transient dynamics to dissipate.
|
||||
|
||||
// Reverse direction and reset homing rate for locate cycle(s).
|
||||
approach = !approach;
|
||||
|
||||
// After first cycle, homing enters locating phase. Shorten search to pull-off distance.
|
||||
if (approach) {
|
||||
max_travel = settings.homing_pulloff*HOMING_AXIS_LOCATE_SCALAR;
|
||||
homing_rate = settings.homing_feed_rate;
|
||||
} else {
|
||||
max_travel = settings.homing_pulloff;
|
||||
homing_rate = settings.homing_seek_rate;
|
||||
}
|
||||
|
||||
} while (n_cycle-- > 0);
|
||||
|
||||
// The active cycle axes should now be homed and machine limits have been located. By
|
||||
// default, Grbl defines machine space as all negative, as do most CNCs. Since limit switches
|
||||
// can be on either side of an axes, check and set axes machine zero appropriately. Also,
|
||||
// set up pull-off maneuver from axes limit switches that have been homed. This provides
|
||||
// some initial clearance off the switches and should also help prevent them from falsely
|
||||
// triggering when hard limits are enabled or when more than one axes shares a limit pin.
|
||||
int32_t set_axis_position;
|
||||
// Set machine positions for homed limit switches. Don't update non-homed axes.
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// NOTE: settings.max_travel[] is stored as a negative value.
|
||||
if (cycle_mask & bit(idx)) {
|
||||
#ifdef HOMING_FORCE_SET_ORIGIN
|
||||
set_axis_position = 0;
|
||||
#else
|
||||
if ( bit_istrue(settings.homing_dir_mask,bit(idx)) ) {
|
||||
#ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
set_axis_position = 0; //lround(settings.homing_pulloff*settings.steps_per_mm[idx]);
|
||||
#else
|
||||
set_axis_position = lround((settings.max_travel[idx]+settings.homing_pulloff)*settings.steps_per_mm[idx]);
|
||||
#endif
|
||||
} else {
|
||||
#ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
set_axis_position = lround((-settings.max_travel[idx]-settings.homing_pulloff)*settings.steps_per_mm[idx]);
|
||||
#else
|
||||
set_axis_position = lround(-settings.homing_pulloff*settings.steps_per_mm[idx]);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef COREXY
|
||||
if (idx==X_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = set_axis_position + off_axis_position;
|
||||
sys_position[B_MOTOR] = set_axis_position - off_axis_position;
|
||||
} else if (idx==Y_AXIS) {
|
||||
int32_t off_axis_position = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
sys_position[A_MOTOR] = off_axis_position + set_axis_position;
|
||||
sys_position[B_MOTOR] = off_axis_position - set_axis_position;
|
||||
} else {
|
||||
sys_position[idx] = set_axis_position;
|
||||
}
|
||||
#else
|
||||
sys_position[idx] = set_axis_position;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP; // Return step control to normal operation.
|
||||
}
|
||||
|
||||
|
||||
void limits_init()
|
||||
{
|
||||
|
||||
#ifndef DISABLE_LIMIT_PIN_PULL_UP
|
||||
#ifdef X_LIMIT_PIN
|
||||
pinMode(X_LIMIT_PIN, INPUT_PULLUP); // input with pullup
|
||||
#endif
|
||||
#ifdef Y_LIMIT_PIN
|
||||
pinMode(Y_LIMIT_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
#ifdef Z_LIMIT_PIN
|
||||
pinMode(Z_LIMIT_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
#ifdef A_LIMIT_PIN
|
||||
pinMode(A_LIMIT_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
#ifdef B_LIMIT_PIN
|
||||
pinMode(B_LIMIT_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
#ifdef C_LIMIT_PIN
|
||||
pinMode(C_LIMIT_PIN, INPUT_PULLUP);
|
||||
#endif
|
||||
#else
|
||||
#ifdef X_LIMIT_PIN
|
||||
pinMode(X_LIMIT_PIN, INPUT); // input no pullup
|
||||
#endif
|
||||
#ifdef Y_LIMIT_PIN
|
||||
pinMode(Y_LIMIT_PIN, INPUT);
|
||||
#endif
|
||||
#ifdef Z_LIMIT_PIN
|
||||
pinMode(Z_LIMIT_PIN, INPUT);
|
||||
#endif
|
||||
#ifdef A_LIMIT_PIN
|
||||
pinMode(A_LIMIT_PIN, INPUT); // input no pullup
|
||||
#endif
|
||||
#ifdef B_LIMIT_PIN
|
||||
pinMode(B_LIMIT_PIN, INPUT);
|
||||
#endif
|
||||
#ifdef C_LIMIT_PIN
|
||||
pinMode(C_LIMIT_PIN, INPUT);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)) {
|
||||
// attach interrupt to them
|
||||
#ifdef X_LIMIT_PIN
|
||||
attachInterrupt(digitalPinToInterrupt(X_LIMIT_PIN), isr_limit_switches, CHANGE);
|
||||
#endif
|
||||
#ifdef Y_LIMIT_PIN
|
||||
attachInterrupt(digitalPinToInterrupt(Y_LIMIT_PIN), isr_limit_switches, CHANGE);
|
||||
#endif
|
||||
#ifdef Z_LIMIT_PIN
|
||||
attachInterrupt(digitalPinToInterrupt(Z_LIMIT_PIN), isr_limit_switches, CHANGE);
|
||||
#endif
|
||||
#ifdef A_LIMIT_PIN
|
||||
attachInterrupt(digitalPinToInterrupt(A_LIMIT_PIN), isr_limit_switches, CHANGE);
|
||||
#endif
|
||||
#ifdef B_LIMIT_PIN
|
||||
attachInterrupt(digitalPinToInterrupt(B_LIMIT_PIN), isr_limit_switches, CHANGE);
|
||||
#endif
|
||||
#ifdef C_LIMIT_PIN
|
||||
attachInterrupt(digitalPinToInterrupt(C_LIMIT_PIN), isr_limit_switches, CHANGE);
|
||||
#endif
|
||||
} else {
|
||||
limits_disable();
|
||||
}
|
||||
|
||||
// setup task used for debouncing
|
||||
limit_sw_queue = xQueueCreate(10, sizeof( int ));
|
||||
|
||||
xTaskCreate(limitCheckTask,
|
||||
"limitCheckTask",
|
||||
2048,
|
||||
NULL,
|
||||
5, // priority
|
||||
NULL);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Disables hard limits.
|
||||
void limits_disable()
|
||||
{
|
||||
detachInterrupt(X_LIMIT_BIT);
|
||||
detachInterrupt(Y_LIMIT_BIT);
|
||||
detachInterrupt(Z_LIMIT_BIT);
|
||||
detachInterrupt(A_LIMIT_BIT);
|
||||
detachInterrupt(B_LIMIT_BIT);
|
||||
detachInterrupt(C_LIMIT_BIT);
|
||||
}
|
||||
|
||||
|
||||
// Returns limit state as a bit-wise uint8 variable. Each bit indicates an axis limit, where
|
||||
// triggered is 1 and not triggered is 0. Invert mask is applied. Axes are defined by their
|
||||
// number in bit position, i.e. Z_AXIS is (1<<2) or bit 2, and Y_AXIS is (1<<1) or bit 1.
|
||||
uint8_t limits_get_state()
|
||||
{
|
||||
uint8_t limit_state = 0;
|
||||
uint8_t pin = 0;
|
||||
|
||||
#ifdef X_LIMIT_PIN
|
||||
pin += digitalRead(X_LIMIT_PIN);
|
||||
#endif
|
||||
|
||||
#ifdef Y_LIMIT_PIN
|
||||
pin += (digitalRead(Y_LIMIT_PIN) << Y_AXIS);
|
||||
#endif
|
||||
|
||||
#ifdef Z_LIMIT_PIN
|
||||
pin += (digitalRead(Z_LIMIT_PIN) << Z_AXIS);
|
||||
#endif
|
||||
|
||||
#ifdef A_LIMIT_PIN
|
||||
pin += (digitalRead(A_LIMIT_PIN) << A_AXIS);
|
||||
#endif
|
||||
|
||||
#ifdef B_LIMIT_PIN
|
||||
pin += (digitalRead(B_LIMIT_PIN) << B_AXIS);
|
||||
#endif
|
||||
|
||||
#ifdef C_LIMIT_PIN
|
||||
pin += (digitalRead(C_LIMIT_PIN) << C_AXIS);
|
||||
#endif
|
||||
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG: Limit pins %d]\r\n", pin);
|
||||
|
||||
#ifdef INVERT_LIMIT_PIN_MASK // not normally used..unless you have both normal and inverted switches
|
||||
pin ^= INVERT_LIMIT_PIN_MASK;
|
||||
#endif
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)) {
|
||||
pin ^= LIMIT_MASK;
|
||||
}
|
||||
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG: Limit Inverted %d]\r\n", pin);
|
||||
|
||||
if (pin) {
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (pin & get_limit_pin_mask(idx)) {
|
||||
limit_state |= (1 << idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG: Limit State %d]\r\n", limit_state);
|
||||
|
||||
return(limit_state);
|
||||
}
|
||||
|
||||
// Performs a soft limit check. Called from mc_line() only. Assumes the machine has been homed,
|
||||
// the workspace volume is in all negative space, and the system is in normal operation.
|
||||
// NOTE: Used by jogging to limit travel within soft-limit volume.
|
||||
void limits_soft_check(float *target)
|
||||
{
|
||||
if (system_check_travel_limits(target)) {
|
||||
sys.soft_limit = true;
|
||||
// Force feed hold if cycle is active. All buffered blocks are guaranteed to be within
|
||||
// workspace volume so just come to a controlled stop so position is not lost. When complete
|
||||
// enter alarm mode.
|
||||
if (sys.state == STATE_CYCLE) {
|
||||
system_set_exec_state_flag(EXEC_FEED_HOLD);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) { return; }
|
||||
} while ( sys.state != STATE_IDLE );
|
||||
}
|
||||
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_SOFT_LIMIT); // Indicate soft limit critical event
|
||||
protocol_execute_realtime(); // Execute to enter critical event loop and system abort
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// this is the task
|
||||
void limitCheckTask(void *pvParameters)
|
||||
{
|
||||
while(true) {
|
||||
int evt;
|
||||
xQueueReceive(limit_sw_queue, &evt, portMAX_DELAY); // block until receive queue
|
||||
vTaskDelay( DEBOUNCE_PERIOD / portTICK_PERIOD_MS ); // delay a while
|
||||
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Initiate system kill.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT); // Indicate hard limit critical event
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return true if the axis is defined as a squared axis
|
||||
// Squaring: is used on gantry type axes that have two motors
|
||||
// Each motor with touch off its own switch to square the axis
|
||||
bool axis_is_squared(uint8_t axis_mask)
|
||||
{
|
||||
// Note: multi-axis homing returns false because it will not match any of the following
|
||||
|
||||
if (axis_mask == (1<<X_AXIS)) {
|
||||
#ifdef X_AXIS_SQUARING
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (axis_mask == (1<<Y_AXIS)) {
|
||||
#ifdef Y_AXIS_SQUARING
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (axis_mask == (1<<Z_AXIS)) {
|
||||
#ifdef Z_AXIS_SQUARING
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
57
Grbl_Esp32-master/Grbl_Esp32/grbl_limits.h
Normal file
57
Grbl_Esp32-master/Grbl_Esp32/grbl_limits.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
limits.h - code pertaining to limit-switches and performing the homing cycle
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
2018-12-29 - Wolfgang Lienbacher renamed file from limits.h to grbl_limits.h
|
||||
fixing ambiguation issues with limit.h in the esp32 Arduino Framework
|
||||
when compiling with VS-Code/PlatformIO.
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef grbl_limits_h
|
||||
#define grbl_limits_h
|
||||
|
||||
#define SQUARING_MODE_DUAL 0 // both motors run
|
||||
#define SQUARING_MODE_A 1 // A motor runs
|
||||
#define SQUARING_MODE_B 2 // B motor runs
|
||||
|
||||
// Initialize the limits module
|
||||
void limits_init();
|
||||
|
||||
// Disables hard limits.
|
||||
void limits_disable();
|
||||
|
||||
// Returns limit state as a bit-wise uint8 variable.
|
||||
uint8_t limits_get_state();
|
||||
|
||||
// Perform one portion of the homing cycle based on the input settings.
|
||||
void limits_go_home(uint8_t cycle_mask);
|
||||
|
||||
// Check for soft limit violations
|
||||
void limits_soft_check(float *target);
|
||||
|
||||
void isr_limit_switches();
|
||||
|
||||
bool axis_is_squared(uint8_t axis_mask);
|
||||
|
||||
// A task that runs after a limit switch interrupt.
|
||||
void limitCheckTask(void *pvParameters);
|
||||
|
||||
#endif
|
233
Grbl_Esp32-master/Grbl_Esp32/grbl_sd.cpp
Normal file
233
Grbl_Esp32-master/Grbl_Esp32/grbl_sd.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
grbl_sd.cpp - Adds SD Card Features to Grbl_ESP32
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Copyright (c) 2018 Barton Dring Buildlog.net
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl_sd.h"
|
||||
|
||||
// Define line flags. Includes comment type tracking and line overflow detection.
|
||||
#define LINE_FLAG_OVERFLOW bit(0)
|
||||
#define LINE_FLAG_COMMENT_PARENTHESES bit(1)
|
||||
#define LINE_FLAG_COMMENT_SEMICOLON bit(2)
|
||||
|
||||
File myFile;
|
||||
bool SD_ready_next = false; // Grbl has processed a line and is waiting for another
|
||||
uint8_t SD_client = CLIENT_SERIAL;
|
||||
uint32_t sd_current_line_number; // stores the most recent line number read from the SD
|
||||
static char comment[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
|
||||
|
||||
// attempt to mount the SD card
|
||||
/*bool sd_mount()
|
||||
{
|
||||
if(!SD.begin()) {
|
||||
report_status_message(STATUS_SD_FAILED_MOUNT, CLIENT_SERIAL);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}*/
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels, uint8_t client)
|
||||
{
|
||||
//char temp_filename[128]; // to help filter by extension TODO: 128 needs a definition based on something
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if(!root) {
|
||||
report_status_message(STATUS_SD_FAILED_OPEN_DIR, client);
|
||||
return;
|
||||
}
|
||||
if(!root.isDirectory()) {
|
||||
report_status_message(STATUS_SD_DIR_NOT_FOUND, client);
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while(file) {
|
||||
if(file.isDirectory()) {
|
||||
if(levels) {
|
||||
listDir(fs, file.name(), levels -1, client);
|
||||
}
|
||||
} else {
|
||||
grbl_sendf(CLIENT_ALL, "[FILE:%s|SIZE:%d]\r\n", file.name(), file.size());
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
|
||||
boolean openFile(fs::FS &fs, const char * path)
|
||||
{
|
||||
myFile = fs.open(path);
|
||||
|
||||
if(!myFile) {
|
||||
//report_status_message(STATUS_SD_FAILED_READ, CLIENT_SERIAL);
|
||||
return false;
|
||||
}
|
||||
|
||||
set_sd_state(SDCARD_BUSY_PRINTING);
|
||||
SD_ready_next = false; // this will get set to true when Grbl issues "ok" message
|
||||
sd_current_line_number = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean closeFile()
|
||||
{
|
||||
if(!myFile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set_sd_state(SDCARD_IDLE);
|
||||
SD_ready_next = false;
|
||||
sd_current_line_number = 0;
|
||||
myFile.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
read a line from the SD card
|
||||
strip whitespace
|
||||
strip comments per http://linuxcnc.org/docs/ja/html/gcode/overview.html#gcode:comments
|
||||
make uppercase
|
||||
return true if a line is
|
||||
*/
|
||||
boolean readFileLine(char *line)
|
||||
{
|
||||
char c;
|
||||
uint8_t index = 0;
|
||||
uint8_t line_flags = 0;
|
||||
uint8_t comment_char_counter = 0;
|
||||
|
||||
if (!myFile) {
|
||||
report_status_message(STATUS_SD_FAILED_READ, SD_client);
|
||||
return false;
|
||||
}
|
||||
|
||||
sd_current_line_number += 1;
|
||||
|
||||
while(myFile.available()) {
|
||||
c = myFile.read();
|
||||
|
||||
if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) { // capture all characters into a comment buffer
|
||||
comment[comment_char_counter++] = c;
|
||||
}
|
||||
|
||||
if (c == '\r' || c == ' ' ) {
|
||||
// ignore these whitespace items
|
||||
} else if (c == '(') {
|
||||
line_flags |= LINE_FLAG_COMMENT_PARENTHESES;
|
||||
} else if (c == ')') {
|
||||
// End of '()' comment. Resume line allowed.
|
||||
if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) {
|
||||
line_flags &= ~(LINE_FLAG_COMMENT_PARENTHESES);
|
||||
comment[comment_char_counter] = 0; // null terminate
|
||||
report_gcode_comment(comment);
|
||||
}
|
||||
} else if (c == ';') {
|
||||
// NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
|
||||
if (!(line_flags & LINE_FLAG_COMMENT_PARENTHESES)) { // semi colon inside parentheses do not mean anything
|
||||
line_flags |= LINE_FLAG_COMMENT_SEMICOLON;
|
||||
}
|
||||
} else if (c == '%') {
|
||||
// discard this character
|
||||
} else if (c == '\n') { // found the newline, so mark the end and return true
|
||||
line[index] = '\0';
|
||||
return true;
|
||||
} else { // add characters to the line
|
||||
if (!line_flags) {
|
||||
c = toupper(c); // make upper case
|
||||
line[index] = c;
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == 255) { // name is too long so return false
|
||||
line[index] = '\0';
|
||||
report_status_message(STATUS_OVERFLOW, SD_client);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// some files end without a newline
|
||||
if (index !=0) {
|
||||
line[index] = '\0';
|
||||
return true;
|
||||
} else { // empty line after new line
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// return a percentage complete 50.5 = 50.5%
|
||||
float sd_report_perc_complete()
|
||||
{
|
||||
if (!myFile) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
return ((float)myFile.position() / (float)myFile.size() * 100.0);
|
||||
}
|
||||
|
||||
uint32_t sd_get_current_line_number()
|
||||
{
|
||||
return sd_current_line_number;
|
||||
}
|
||||
|
||||
|
||||
uint8_t sd_state = SDCARD_IDLE;
|
||||
|
||||
uint8_t get_sd_state(bool refresh)
|
||||
{
|
||||
#if defined(SDCARD_DET_PIN) && SDCARD_SD_PIN != -1
|
||||
//no need to go further if SD detect is not correct
|
||||
if (!((digitalRead (SDCARD_DET_PIN) == SDCARD_DET_VAL) ? true : false)) {
|
||||
sd_state = SDCARD_NOT_PRESENT;
|
||||
return sd_state;
|
||||
}
|
||||
#endif
|
||||
//if busy doing something return state
|
||||
if (!((sd_state == SDCARD_NOT_PRESENT) || (sd_state == SDCARD_IDLE))) {
|
||||
return sd_state;
|
||||
}
|
||||
if (!refresh) {
|
||||
return sd_state; //to avoid refresh=true + busy to reset SD and waste time
|
||||
}
|
||||
//SD is idle or not detected, let see if still the case
|
||||
|
||||
SD.end();
|
||||
sd_state = SDCARD_NOT_PRESENT;
|
||||
//using default value for speed ? should be parameter
|
||||
//refresh content if card was removed
|
||||
if (SD.begin((GRBL_SPI_SS == -1)?SS:GRBL_SPI_SS, SPI, GRBL_SPI_FREQ)) {
|
||||
if ( SD.cardSize() > 0 )sd_state = SDCARD_IDLE;
|
||||
}
|
||||
return sd_state;
|
||||
}
|
||||
|
||||
uint8_t set_sd_state(uint8_t flag)
|
||||
{
|
||||
sd_state = flag;
|
||||
return sd_state;
|
||||
}
|
||||
|
||||
void sd_get_current_filename(char* name)
|
||||
{
|
||||
|
||||
if (myFile) {
|
||||
strcpy(name, myFile.name());
|
||||
} else {
|
||||
name[0] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
53
Grbl_Esp32-master/Grbl_Esp32/grbl_sd.h
Normal file
53
Grbl_Esp32-master/Grbl_Esp32/grbl_sd.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Connect the SD card to the following pins:
|
||||
*
|
||||
* SD Card | ESP32
|
||||
* D2 -
|
||||
* D3 SS
|
||||
* CMD MOSI
|
||||
* VSS GND
|
||||
* VDD 3.3V
|
||||
* CLK SCK
|
||||
* VSS GND
|
||||
* D0 MISO
|
||||
* D1 -
|
||||
*/
|
||||
|
||||
#ifndef grbl_sd_h
|
||||
#define grbl_sd_h
|
||||
|
||||
|
||||
#include "grbl.h"
|
||||
#include "FS.h"
|
||||
#include "SD.h"
|
||||
#include "SPI.h"
|
||||
|
||||
#define FILE_TYPE_COUNT 5 // number of acceptable gcode file types in array
|
||||
|
||||
#define SDCARD_DET_PIN -1
|
||||
#define SDCARD_DET_VAL 0
|
||||
|
||||
#define SDCARD_IDLE 0
|
||||
#define SDCARD_NOT_PRESENT 1
|
||||
#define SDCARD_BUSY_PRINTING 2
|
||||
#define SDCARD_BUSY_UPLOADING 4
|
||||
#define SDCARD_BUSY_PARSING 8
|
||||
|
||||
|
||||
|
||||
extern bool SD_ready_next; // Grbl has processed a line and is waiting for another
|
||||
extern uint8_t SD_client;
|
||||
|
||||
//bool sd_mount();
|
||||
uint8_t get_sd_state(bool refresh);
|
||||
uint8_t set_sd_state(uint8_t flag);
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels, uint8_t client);
|
||||
boolean openFile(fs::FS &fs, const char * path);
|
||||
boolean closeFile();
|
||||
boolean readFileLine(char *line);
|
||||
void readFile(fs::FS &fs, const char * path);
|
||||
float sd_report_perc_complete();
|
||||
uint32_t sd_get_current_line_number();
|
||||
void sd_get_current_filename(char* name);
|
||||
|
||||
#endif
|
231
Grbl_Esp32-master/Grbl_Esp32/grbl_trinamic.cpp
Normal file
231
Grbl_Esp32-master/Grbl_Esp32/grbl_trinamic.cpp
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
grbl_trinamic.cpp - Support for Trinamic Stepper Drivers SPI Mode
|
||||
using the TMCStepper library
|
||||
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Copyright (c) 2019 Barton Dring for Buildlog.net LLC
|
||||
|
||||
Grbl_ESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef USE_TRINAMIC
|
||||
/*
|
||||
The drivers can use SPI daisy chaining to allow the use of only (1) CS_PIN.
|
||||
The PCB must be designed for this, with SDO pins being coonect to the
|
||||
next driver's SDI pin. The final SDO goes back to the controller.
|
||||
|
||||
This is setup in cpu_map.
|
||||
add #define TRINAMIC_DAISY_CHAIN to your map
|
||||
Make every axis CS_PIN definition be for the same pin like this...
|
||||
#define X_CS_PIN GPIO_NUM_17
|
||||
#define Y_CS_PIN GPIO_NUM_17
|
||||
...etc.
|
||||
|
||||
Indexes are assigned to each axis in daisy chain mode as shown below.
|
||||
This assumes your first SPI driver axis is X and there are no gaps until
|
||||
the last SPI driver.
|
||||
|
||||
*/
|
||||
#ifndef TRINAMIC_DAISY_CHAIN
|
||||
#define X_DRIVER_SPI_INDEX -1
|
||||
#define Y_DRIVER_SPI_INDEX -1
|
||||
#define Z_DRIVER_SPI_INDEX -1
|
||||
#define A_DRIVER_SPI_INDEX -1
|
||||
#define B_DRIVER_SPI_INDEX -1
|
||||
#define C_DRIVER_SPI_INDEX -1
|
||||
#else
|
||||
#define X_DRIVER_SPI_INDEX 1
|
||||
#define Y_DRIVER_SPI_INDEX 2
|
||||
#define Z_DRIVER_SPI_INDEX 3
|
||||
#define A_DRIVER_SPI_INDEX 4
|
||||
#define B_DRIVER_SPI_INDEX 5
|
||||
#define C_DRIVER_SPI_INDEX 6
|
||||
#endif
|
||||
|
||||
// TODO try to use the #define ## method to clean this up
|
||||
//#define DRIVER(driver, axis) driver##Stepper = TRINAMIC_axis## = driver##Stepper(axis##_CS_PIN, axis##_RSENSE);
|
||||
|
||||
#ifdef X_TRINAMIC
|
||||
#ifdef X_DRIVER_TMC2130
|
||||
TMC2130Stepper TRINAMIC_X = TMC2130Stepper(X_CS_PIN, X_RSENSE, X_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef X_DRIVER_TMC2209
|
||||
TMC2209Stepper TRINAMIC_X = TMC2209Stepper(X_CS_PIN, X_RSENSE, X_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef X_DRIVER_TMC5160
|
||||
TMC5160Stepper TRINAMIC_X = TMC5160Stepper(X_CS_PIN, X_RSENSE, X_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef Y_TRINAMIC
|
||||
#ifdef Y_DRIVER_TMC2130
|
||||
TMC2130Stepper TRINAMIC_Y = TMC2130Stepper(Y_CS_PIN, Y_RSENSE, Y_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef Y_DRIVER_TMC2209
|
||||
TMC2209Stepper TRINAMIC_Y = TMC2209Stepper(Y_CS_PIN, Y_RSENSE, Y_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef Y_DRIVER_TMC5160
|
||||
TMC5160Stepper TRINAMIC_Y = TMC5160Stepper(Y_CS_PIN, Y_RSENSE, Y_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef Z_TRINAMIC
|
||||
#ifdef Z_DRIVER_TMC2130
|
||||
TMC2130Stepper TRINAMIC_Z = TMC2130Stepper(Z_CS_PIN, Z_RSENSE, Z_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef Z_DRIVER_TMC2209
|
||||
TMC2209Stepper TRINAMIC_Z = TMC2209Stepper(Z_CS_PIN, Z_RSENSE, Z_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef Z_DRIVER_TMC5160
|
||||
TMC5160Stepper TRINAMIC_Z = TMC5160Stepper(Z_CS_PIN, Z_RSENSE, Z_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef A_TRINAMIC
|
||||
#ifdef A_DRIVER_TMC2130
|
||||
TMC2130Stepper TRINAMIC_A = TMC2130Stepper(A_CS_PIN, A_RSENSE, A_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef A_DRIVER_TMC2209
|
||||
TMC2209Stepper TRINAMIC_A = TMC2209Stepper(A_CS_PIN, A_RSENSE, A_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef A_DRIVER_TMC5160
|
||||
TMC5160Stepper TRINAMIC_A = TMC5160Stepper(A_CS_PIN, A_RSENSE, A_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef B_TRINAMIC
|
||||
#ifdef B_DRIVER_TMC2130
|
||||
TMC2130Stepper TRINAMIC_B = TMC2130Stepper(B_CS_PIN, B_RSENSE, B_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef B_DRIVER_TMC2209
|
||||
TMC2209Stepper TRINAMIC_B = TMC2209Stepper(B_CS_PIN, B_RSENSE, B_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef B_DRIVER_TMC5160
|
||||
TMC5160Stepper TRINAMIC_B = TMC5160Stepper(B_CS_PIN, B_RSENSE, B_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef C_TRINAMIC
|
||||
#ifdef C_DRIVER_TMC2130
|
||||
TMC2130Stepper TRINAMIC_c = TMC2130Stepper(C_CS_PIN, C_RSENSE, C_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef C_DRIVER_TMC2209
|
||||
TMC2209Stepper TRINAMIC_C = TMC2209Stepper(C_CS_PIN, C_RSENSE, C_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#ifdef C_DRIVER_TMC5160
|
||||
TMC5160Stepper TRINAMIC_C = TMC5160Stepper(C_CS_PIN, C_RSENSE, C_DRIVER_SPI_INDEX);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// TODO ABC Axes
|
||||
|
||||
void Trinamic_Init()
|
||||
{
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:TMCStepper Init using Library Ver 0x%06x]\r\n", TMCSTEPPER_VERSION);
|
||||
|
||||
SPI.begin();
|
||||
|
||||
#ifdef X_TRINAMIC
|
||||
TRINAMIC_X.begin(); // Initiate pins and registries
|
||||
TRINAMIC_X.toff(5);
|
||||
TRINAMIC_X.microsteps(settings.microsteps[X_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[X_AXIS] * 1000.0, settings.hold_current[X_AXIS]/100.0);
|
||||
TRINAMIC_X.en_pwm_mode(1); // Enable extremely quiet stepping
|
||||
TRINAMIC_X.pwm_autoscale(1);
|
||||
#endif
|
||||
|
||||
#ifdef Y_TRINAMIC
|
||||
TRINAMIC_Y.begin(); // Initiate pins and registries
|
||||
TRINAMIC_Y.toff(5);
|
||||
TRINAMIC_Y.microsteps(settings.microsteps[Y_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[Y_AXIS] * 1000.0, settings.hold_current[Y_AXIS]/100.0);
|
||||
TRINAMIC_Y.en_pwm_mode(1); // Enable extremely quiet stepping
|
||||
TRINAMIC_Y.pwm_autoscale(1);
|
||||
#endif
|
||||
|
||||
#ifdef Z_TRINAMIC
|
||||
TRINAMIC_Z.begin(); // Initiate pins and registries
|
||||
TRINAMIC_Z.toff(5);
|
||||
TRINAMIC_Z.microsteps(settings.microsteps[Z_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[Z_AXIS] * 1000.0, settings.hold_current[Z_AXIS]/100.0);
|
||||
TRINAMIC_Z.en_pwm_mode(1); // Enable extremely quiet stepping
|
||||
TRINAMIC_Z.pwm_autoscale(1);
|
||||
#endif
|
||||
|
||||
#ifdef A_TRINAMIC
|
||||
TRINAMIC_A.begin(); // Initiate pins and registries
|
||||
TRINAMIC_A.toff(5);
|
||||
TRINAMIC_A.microsteps(settings.microsteps[A_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[A_AXIS] * 1000.0, settings.hold_current[A_AXIS]/100.0);
|
||||
TRINAMIC_A.en_pwm_mode(1); // Enable extremely quiet stepping
|
||||
TRINAMIC_A.pwm_autoscale(1);
|
||||
#endif
|
||||
|
||||
#ifdef B_TRINAMIC
|
||||
TRINAMIC_B.begin(); // Initiate pins and registries
|
||||
TRINAMIC_B.toff(5);
|
||||
TRINAMIC_B.microsteps(settings.microsteps[B_AXIS]);
|
||||
TTRINAMIC_X.rms_current(settings.current[B_AXIS] * 1000.0, settings.hold_current[B_AXIS]/100.0);
|
||||
TRINAMIC_B.en_pwm_mode(1); // Enable extremely quiet stepping
|
||||
TRINAMIC_B.pwm_autoscale(1);
|
||||
#endif
|
||||
|
||||
#ifdef C_TRINAMIC
|
||||
TRINAMIC_C.begin(); // Initiate pins and registries
|
||||
TRINAMIC_C.toff(5);
|
||||
TRINAMIC_C.microsteps(settings.microsteps[C_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[C_AXIS] * 1000.0, settings.hold_current[C_AXIS]/100.0);
|
||||
TRINAMIC_C.en_pwm_mode(1); // Enable extremely quiet stepping
|
||||
TRINAMIC_C.pwm_autoscale(1);
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
void trinamic_change_settings()
|
||||
{
|
||||
#ifdef X_TRINAMIC
|
||||
TRINAMIC_X.microsteps(settings.microsteps[X_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[X_AXIS] * 1000.0, settings.hold_current[X_AXIS]/100.0);
|
||||
#endif
|
||||
|
||||
#ifdef Y_TRINAMIC
|
||||
TRINAMIC_Y.microsteps(settings.microsteps[Y_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[Y_AXIS] * 1000.0, settings.hold_current[Y_AXIS]/100.0);
|
||||
#endif
|
||||
|
||||
#ifdef Z_TRINAMIC
|
||||
TRINAMIC_Z.microsteps(settings.microsteps[Z_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[Z_AXIS] * 1000.0, settings.hold_current[Z_AXIS]/100.0);
|
||||
#endif
|
||||
|
||||
#ifdef A_TRINAMIC
|
||||
TRINAMIC_A.microsteps(settings.microsteps[A_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[A_AXIS] * 1000.0, settings.hold_current[A_AXIS]/100.0);
|
||||
#endif
|
||||
|
||||
#ifdef B_TRINAMIC
|
||||
TRINAMIC_B.microsteps(settings.microsteps[B_AXIS]);
|
||||
TTRINAMIC_X.rms_current(settings.current[B_AXIS] * 1000.0, settings.hold_current[B_AXIS]/100.0);
|
||||
#endif
|
||||
|
||||
#ifdef C_TRINAMIC
|
||||
TRINAMIC_C.microsteps(settings.microsteps[C_AXIS]);
|
||||
TRINAMIC_X.rms_current(settings.current[C_AXIS] * 1000.0, settings.hold_current[C_AXIS]/100.0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
32
Grbl_Esp32-master/Grbl_Esp32/grbl_trinamic.h
Normal file
32
Grbl_Esp32-master/Grbl_Esp32/grbl_trinamic.h
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
grbl_trinamic.h - Support for TMC2130 Stepper Drivers SPI Mode
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Copyright (c) 2019 Barton Dring for Buildlog.net LLC
|
||||
|
||||
GrblESP32 is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GRBL_TRINAMIC_h
|
||||
#define GRBL_TRINAMIC_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef USE_TRINAMIC
|
||||
#include <TMCStepper.h> // https://github.com/teemuatlut/TMCStepper
|
||||
void Trinamic_Init();
|
||||
void trinamic_change_settings();
|
||||
#endif
|
||||
|
||||
#endif
|
236
Grbl_Esp32-master/Grbl_Esp32/grbl_unipolar.cpp
Normal file
236
Grbl_Esp32-master/Grbl_Esp32/grbl_unipolar.cpp
Normal file
@ -0,0 +1,236 @@
|
||||
/*
|
||||
unipolar.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Unipolar Class
|
||||
|
||||
This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One
|
||||
is typically tied to a voltage, while the other 4 are switched to ground in a
|
||||
sequence
|
||||
|
||||
To take a step simply call the step(step, direction) function.
|
||||
|
||||
*/
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef USE_UNIPOLAR
|
||||
|
||||
// assign the I/O pins used for each coil of the motors
|
||||
#ifdef X_UNIPOLAR
|
||||
Unipolar X_Unipolar(X_PIN_PHASE_0, X_PIN_PHASE_1, X_PIN_PHASE_2, X_PIN_PHASE_3, true);
|
||||
#endif
|
||||
|
||||
#ifdef Y_UNIPOLAR
|
||||
Unipolar Y_Unipolar(Y_PIN_PHASE_0, Y_PIN_PHASE_1, Y_PIN_PHASE_2, Y_PIN_PHASE_3, true);
|
||||
#endif
|
||||
|
||||
#ifdef Z_UNIPOLAR
|
||||
Unipolar Z_Unipolar(Z_PIN_PHASE_0, Z_PIN_PHASE_1, Z_PIN_PHASE_2, Z_PIN_PHASE_3, true);
|
||||
#endif
|
||||
|
||||
void unipolar_init(){
|
||||
#ifdef X_UNIPOLAR
|
||||
X_Unipolar.init();
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:X Unipolar]\r\n");
|
||||
#endif
|
||||
#ifdef Y_UNIPOLAR
|
||||
Y_Unipolar.init();
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Y Unipolar]\r\n");
|
||||
#endif
|
||||
#ifdef Z_UNIPOLAR
|
||||
Z_Unipolar.init();
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Z Unipolar]\r\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void unipolar_step(uint8_t step_mask, uint8_t dir_mask)
|
||||
{
|
||||
#ifdef X_UNIPOLAR
|
||||
X_Unipolar.step(step_mask & (1<<X_AXIS), dir_mask & (1<<X_AXIS));
|
||||
#endif
|
||||
#ifdef Y_UNIPOLAR
|
||||
Y_Unipolar.step(step_mask & (1<<Y_AXIS), dir_mask & (1<<Y_AXIS));
|
||||
#endif
|
||||
#ifdef Z_UNIPOLAR
|
||||
Z_Unipolar.step(step_mask & (1<<Z_AXIS), dir_mask & (1<<ZX_AXIS));
|
||||
#endif
|
||||
}
|
||||
|
||||
void unipolar_disable(bool disable)
|
||||
{
|
||||
#ifdef X_UNIPOLAR
|
||||
X_Unipolar.set_enabled(!disable);
|
||||
#endif
|
||||
#ifdef Y_UNIPOLAR
|
||||
Y_Unipolar.set_enabled(!disable);
|
||||
#endif
|
||||
#ifdef Z_UNIPOLAR
|
||||
Z_Unipolar.set_enabled(!disable);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Unipolar::Unipolar(uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3, bool half_step) // constructor
|
||||
{
|
||||
_pin_phase0 = pin_phase0;
|
||||
_pin_phase1 = pin_phase1;
|
||||
_pin_phase2 = pin_phase2;
|
||||
_pin_phase3 = pin_phase3;
|
||||
_half_step = half_step;
|
||||
}
|
||||
|
||||
void Unipolar::init() {
|
||||
pinMode(_pin_phase0, OUTPUT);
|
||||
pinMode(_pin_phase1, OUTPUT);
|
||||
pinMode(_pin_phase2, OUTPUT);
|
||||
pinMode(_pin_phase3, OUTPUT);
|
||||
|
||||
_current_phase = 0;
|
||||
set_enabled(false);
|
||||
}
|
||||
|
||||
void Unipolar::set_enabled(bool enabled)
|
||||
{
|
||||
if (enabled == _enabled)
|
||||
return; // no change
|
||||
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG:Enabled...%d]\r\n", enabled);
|
||||
|
||||
_enabled = enabled;
|
||||
|
||||
if (!enabled) {
|
||||
digitalWrite(_pin_phase0, 0);
|
||||
digitalWrite(_pin_phase1, 0);
|
||||
digitalWrite(_pin_phase2, 0);
|
||||
digitalWrite(_pin_phase3, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
To take a step set step to true and set the driection
|
||||
|
||||
step is included so that st.step_outbits can be used to determine if a
|
||||
step is required on this axis
|
||||
*/
|
||||
void Unipolar::step(bool step, bool dir_forward)
|
||||
{
|
||||
uint8_t _phase[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // temporary phase values...all start as off
|
||||
uint8_t phase_max;
|
||||
|
||||
if (_half_step)
|
||||
phase_max = 7;
|
||||
else
|
||||
phase_max = 3;
|
||||
|
||||
if (!step)
|
||||
return; // a step is not required on this interrupt
|
||||
|
||||
if (!_enabled)
|
||||
return; // don't do anything, phase is not changed or lost
|
||||
|
||||
if (dir_forward) { // count up
|
||||
if (_current_phase == phase_max) {
|
||||
_current_phase = 0;
|
||||
}
|
||||
else {
|
||||
_current_phase++;
|
||||
}
|
||||
}
|
||||
else { // count down
|
||||
if (_current_phase == 0) {
|
||||
_current_phase = phase_max;
|
||||
}
|
||||
else {
|
||||
_current_phase--;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
8 Step : A – AB – B – BC – C – CD – D – DA
|
||||
4 Step : AB – BC – CD – DA (Usual application)
|
||||
|
||||
Step IN4 IN3 IN2 IN1
|
||||
A 0 0 0 1
|
||||
AB 0 0 1 1
|
||||
B 0 0 1 0
|
||||
BC 0 1 1 0
|
||||
C 0 1 0 0
|
||||
CD 1 1 0 0
|
||||
D 1 0 0 0
|
||||
DA 1 0 0 1
|
||||
*/
|
||||
if (_half_step) {
|
||||
switch (_current_phase) {
|
||||
case 0:
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
case 1:
|
||||
_phase[0] = 1;
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 2:
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 3:
|
||||
_phase[1] = 1;
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 4:
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 5:
|
||||
_phase[2] = 1;
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 6:
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 7:
|
||||
_phase[3] = 1;
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (_current_phase) {
|
||||
case 0:
|
||||
_phase[0] = 1;
|
||||
_phase[1] = 1;
|
||||
break;
|
||||
case 1:
|
||||
_phase[1] = 1;
|
||||
_phase[2] = 1;
|
||||
break;
|
||||
case 2:
|
||||
_phase[2] = 1;
|
||||
_phase[3] = 1;
|
||||
break;
|
||||
case 3:
|
||||
_phase[3] = 1;
|
||||
_phase[0] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
digitalWrite(_pin_phase0, _phase[0]);
|
||||
digitalWrite(_pin_phase1, _phase[1]);
|
||||
digitalWrite(_pin_phase2, _phase[2]);
|
||||
digitalWrite(_pin_phase3, _phase[3]);
|
||||
}
|
||||
#endif
|
54
Grbl_Esp32-master/Grbl_Esp32/grbl_unipolar.h
Normal file
54
Grbl_Esp32-master/Grbl_Esp32/grbl_unipolar.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
grbl_unipolar.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Unipolar Class
|
||||
|
||||
This class allows you to control a unipolar motor. Unipolar motors have 5 wires. One
|
||||
is typically tied to a voltage, while the other 4 are switched to ground in a
|
||||
sequence
|
||||
|
||||
To take a step simply call the step(direction) function. It will take
|
||||
|
||||
*/
|
||||
#ifndef grbl_unipolar_h
|
||||
#define grbl_unipolar_h
|
||||
|
||||
void unipolar_init();
|
||||
void unipolar_step(uint8_t step_mask, uint8_t dir_mask);
|
||||
void unipolar_disable(bool enable);
|
||||
|
||||
class Unipolar{
|
||||
public:
|
||||
Unipolar(uint8_t pin_phase0, uint8_t pin_phase1, uint8_t pin_phase2, uint8_t pin_phase3, bool half_step); // constructor
|
||||
void set_enabled(bool enabled);
|
||||
void step(bool step, bool dir_forward);
|
||||
void init();
|
||||
|
||||
private:
|
||||
uint8_t _current_phase = 0;
|
||||
bool _enabled = false;
|
||||
bool _half_step = true; // default is half step, full step
|
||||
uint8_t _pin_phase0;
|
||||
uint8_t _pin_phase1;
|
||||
uint8_t _pin_phase2;
|
||||
uint8_t _pin_phase3;
|
||||
|
||||
};
|
||||
#endif
|
108
Grbl_Esp32-master/Grbl_Esp32/inputbuffer.cpp
Normal file
108
Grbl_Esp32-master/Grbl_Esp32/inputbuffer.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
inputbuffer.cpp - inputbuffer functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
#include "config.h"
|
||||
#include "inputbuffer.h"
|
||||
|
||||
InputBuffer inputBuffer;
|
||||
|
||||
|
||||
InputBuffer::InputBuffer(){
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
InputBuffer::~InputBuffer(){
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
void InputBuffer::begin(){
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
|
||||
void InputBuffer::end(){
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
|
||||
InputBuffer::operator bool() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int InputBuffer::available(){
|
||||
return _RXbufferSize;
|
||||
}
|
||||
|
||||
size_t InputBuffer::write(uint8_t c)
|
||||
{
|
||||
//No need currently
|
||||
//keep for compatibility
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t InputBuffer::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
//No need currently
|
||||
//keep for compatibility
|
||||
return size;
|
||||
}
|
||||
|
||||
int InputBuffer::peek(void){
|
||||
if (_RXbufferSize > 0)return _RXbuffer[_RXbufferpos];
|
||||
else return -1;
|
||||
}
|
||||
|
||||
bool InputBuffer::push (const char * data){
|
||||
int data_size = strlen(data);
|
||||
if ((data_size + _RXbufferSize) <= RXBUFFERSIZE){
|
||||
int current = _RXbufferpos + _RXbufferSize;
|
||||
if (current > RXBUFFERSIZE) current = current - RXBUFFERSIZE;
|
||||
for (int i = 0; i < data_size; i++){
|
||||
if (current > (RXBUFFERSIZE-1)) current = 0;
|
||||
_RXbuffer[current] = data[i];
|
||||
current ++;
|
||||
}
|
||||
_RXbufferSize+=strlen(data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int InputBuffer::read(void){
|
||||
if (_RXbufferSize > 0) {
|
||||
int v = _RXbuffer[_RXbufferpos];
|
||||
_RXbufferpos++;
|
||||
if (_RXbufferpos > (RXBUFFERSIZE-1))_RXbufferpos = 0;
|
||||
_RXbufferSize--;
|
||||
return v;
|
||||
} else return -1;
|
||||
}
|
||||
|
||||
void InputBuffer::flush(void){
|
||||
//No need currently
|
||||
//keep for compatibility
|
||||
}
|
||||
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
71
Grbl_Esp32-master/Grbl_Esp32/inputbuffer.h
Normal file
71
Grbl_Esp32-master/Grbl_Esp32/inputbuffer.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
inputbuffer.h - inputbuffer functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _INPUT_BUFFER_H_
|
||||
#define _INPUT_BUFFER_H_
|
||||
|
||||
#include "Print.h"
|
||||
#define RXBUFFERSIZE 128
|
||||
class InputBuffer: public Print{
|
||||
public:
|
||||
InputBuffer();
|
||||
~InputBuffer();
|
||||
size_t write(uint8_t c);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
}
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
void begin();
|
||||
void end();
|
||||
int available();
|
||||
int peek(void);
|
||||
int read(void);
|
||||
bool push (const char * data);
|
||||
void flush(void);
|
||||
operator bool() const;
|
||||
private:
|
||||
uint8_t _RXbuffer[RXBUFFERSIZE];
|
||||
uint16_t _RXbufferSize;
|
||||
uint16_t _RXbufferpos;
|
||||
};
|
||||
|
||||
|
||||
extern InputBuffer inputBuffer;
|
||||
|
||||
#endif
|
53
Grbl_Esp32-master/Grbl_Esp32/jog.cpp
Normal file
53
Grbl_Esp32-master/Grbl_Esp32/jog.cpp
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
jog.h - Jogging methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block)
|
||||
{
|
||||
// Initialize planner data struct for jogging motions.
|
||||
// NOTE: Spindle and coolant are allowed to fully function with overrides during a jog.
|
||||
pl_data->feed_rate = gc_block->values.f;
|
||||
pl_data->condition |= PL_COND_FLAG_NO_FEED_OVERRIDE;
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
pl_data->line_number = gc_block->values.n;
|
||||
#endif
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)) {
|
||||
if (system_check_travel_limits(gc_block->values.xyz)) { return(STATUS_TRAVEL_EXCEEDED); }
|
||||
}
|
||||
|
||||
// Valid jog command. Plan, set state, and execute.
|
||||
mc_line(gc_block->values.xyz,pl_data);
|
||||
if (sys.state == STATE_IDLE) {
|
||||
if (plan_get_current_block() != NULL) { // Check if there is a block to execute.
|
||||
sys.state = STATE_JOG;
|
||||
st_prep_buffer();
|
||||
st_wake_up(); // NOTE: Manual start. No state machine required.
|
||||
}
|
||||
}
|
||||
|
||||
return(STATUS_OK);
|
||||
}
|
35
Grbl_Esp32-master/Grbl_Esp32/jog.h
Normal file
35
Grbl_Esp32-master/Grbl_Esp32/jog.h
Normal file
@ -0,0 +1,35 @@
|
||||
/*
|
||||
jog.h - Jogging methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef jog_h
|
||||
#define jog_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// System motion line numbers must be zero.
|
||||
#define JOG_LINE_NUMBER 0
|
||||
|
||||
// Sets up valid jog motion received from g-code parser, checks for soft-limits, and executes the jog.
|
||||
uint8_t jog_execute(plan_line_data_t *pl_data, parser_block_t *gc_block);
|
||||
|
||||
#endif
|
483
Grbl_Esp32-master/Grbl_Esp32/motion_control.cpp
Normal file
483
Grbl_Esp32-master/Grbl_Esp32/motion_control.cpp
Normal file
@ -0,0 +1,483 @@
|
||||
/*
|
||||
motion_control.c - high level interface for issuing motion commands
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
uint8_t ganged_mode = SQUARING_MODE_DUAL;
|
||||
|
||||
|
||||
// this allows kinematics to be used.
|
||||
void mc_line_kins(float *target, plan_line_data_t *pl_data, float *position)
|
||||
{
|
||||
#ifndef USE_KINEMATICS
|
||||
mc_line(target, pl_data);
|
||||
#else // else use kinematics
|
||||
inverse_kinematics(target, pl_data, position);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||
// (1 minute)/feed_rate time.
|
||||
// NOTE: This is the primary gateway to the grbl planner. All line motions, including arc line
|
||||
// segments, must pass through this routine before being passed to the planner. The seperation of
|
||||
// mc_line and plan_buffer_line is done primarily to place non-planner-type functions from being
|
||||
// in the planner and to let backlash compensation or canned cycle integration simple and direct.
|
||||
void mc_line(float *target, plan_line_data_t *pl_data)
|
||||
{
|
||||
// If enabled, check for soft limit violations. Placed here all line motions are picked up
|
||||
// from everywhere in Grbl.
|
||||
if (bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)) {
|
||||
// NOTE: Block jog state. Jogging is a special case and soft limits are handled independently.
|
||||
if (sys.state != STATE_JOG) { limits_soft_check(target); }
|
||||
}
|
||||
|
||||
// If in check gcode mode, prevent motion by blocking planner. Soft limits still work.
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
|
||||
// NOTE: Backlash compensation may be installed here. It will need direction info to track when
|
||||
// to insert a backlash line motion(s) before the intended line motion and will require its own
|
||||
// plan_check_full_buffer() and check for system abort loop. Also for position reporting
|
||||
// backlash steps will need to be also tracked, which will need to be kept at a system level.
|
||||
// There are likely some other things that will need to be tracked as well. However, we feel
|
||||
// that backlash compensation should NOT be handled by Grbl itself, because there are a myriad
|
||||
// of ways to implement it and can be effective or ineffective for different CNC machines. This
|
||||
// would be better handled by the interface as a post-processor task, where the original g-code
|
||||
// is translated and inserts backlash motions that best suits the machine.
|
||||
// NOTE: Perhaps as a middle-ground, all that needs to be sent is a flag or special command that
|
||||
// indicates to Grbl what is a backlash compensation motion, so that Grbl executes the move but
|
||||
// doesn't update the machine position values. Since the position values used by the g-code
|
||||
// parser and planner are separate from the system machine positions, this is doable.
|
||||
|
||||
// If the buffer is full: good! That means we are well ahead of the robot.
|
||||
// Remain in this loop until there is room in the buffer.
|
||||
do {
|
||||
protocol_execute_realtime(); // Check for any run-time commands
|
||||
if (sys.abort) { return; } // Bail, if system abort.
|
||||
if ( plan_check_full_buffer() ) { protocol_auto_cycle_start(); } // Auto-cycle start when buffer is full.
|
||||
else { break; }
|
||||
} while (1);
|
||||
|
||||
// Plan and queue motion into planner buffer
|
||||
// uint8_t plan_status; // Not used in normal operation.
|
||||
plan_buffer_line(target, pl_data);
|
||||
}
|
||||
|
||||
|
||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||
// offset == offset from current xyz, axis_X defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, isclockwise boolean. Used
|
||||
// for vector transformation direction.
|
||||
// The arc is approximated by generating a huge number of tiny, linear segments. The chordal tolerance
|
||||
// of each segment is configured in settings.arc_tolerance, which is defined to be the maximum normal
|
||||
// distance from segment to the circle when the end points both lie on the circle.
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
|
||||
uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc)
|
||||
{
|
||||
float center_axis0 = position[axis_0] + offset[axis_0];
|
||||
float center_axis1 = position[axis_1] + offset[axis_1];
|
||||
float r_axis0 = -offset[axis_0]; // Radius vector from center to current location
|
||||
float r_axis1 = -offset[axis_1];
|
||||
float rt_axis0 = target[axis_0] - center_axis0;
|
||||
float rt_axis1 = target[axis_1] - center_axis1;
|
||||
|
||||
#ifdef USE_KINEMATICS
|
||||
float previous_position[N_AXIS];
|
||||
uint16_t n;
|
||||
for (n = 0; n < N_AXIS; n++) {
|
||||
previous_position[n] = position[n];
|
||||
}
|
||||
#endif
|
||||
|
||||
// CCW angle between position and target from circle center. Only one atan2() trig computation required.
|
||||
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
|
||||
if (is_clockwise_arc) { // Correct atan2 output per direction
|
||||
if (angular_travel >= -ARC_ANGULAR_TRAVEL_EPSILON) { angular_travel -= 2*M_PI; }
|
||||
} else {
|
||||
if (angular_travel <= ARC_ANGULAR_TRAVEL_EPSILON) { angular_travel += 2*M_PI; }
|
||||
}
|
||||
|
||||
// NOTE: Segment end points are on the arc, which can lead to the arc diameter being smaller by up to
|
||||
// (2x) settings.arc_tolerance. For 99% of users, this is just fine. If a different arc segment fit
|
||||
// is desired, i.e. least-squares, midpoint on arc, just change the mm_per_arc_segment calculation.
|
||||
// For the intended uses of Grbl, this value shouldn't exceed 2000 for the strictest of cases.
|
||||
uint16_t segments = floor(fabs(0.5*angular_travel*radius)/
|
||||
sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
|
||||
|
||||
if (segments) {
|
||||
// Multiply inverse feed_rate to compensate for the fact that this movement is approximated
|
||||
// by a number of discrete segments. The inverse feed_rate should be correct for the sum of
|
||||
// all segments.
|
||||
if (pl_data->condition & PL_COND_FLAG_INVERSE_TIME) {
|
||||
pl_data->feed_rate *= segments;
|
||||
bit_false(pl_data->condition,PL_COND_FLAG_INVERSE_TIME); // Force as feed absolute mode over arc segments.
|
||||
}
|
||||
|
||||
float theta_per_segment = angular_travel/segments;
|
||||
float linear_per_segment = (target[axis_linear] - position[axis_linear])/segments;
|
||||
|
||||
/* Vector rotation by transformation matrix: r is the original vector, r_T is the rotated vector,
|
||||
and phi is the angle of rotation. Solution approach by Jens Geisler.
|
||||
r_T = [cos(phi) -sin(phi);
|
||||
sin(phi) cos(phi] * r ;
|
||||
|
||||
For arc generation, the center of the circle is the axis of rotation and the radius vector is
|
||||
defined from the circle center to the initial position. Each line segment is formed by successive
|
||||
vector rotations. Single precision values can accumulate error greater than tool precision in rare
|
||||
cases. So, exact arc path correction is implemented. This approach avoids the problem of too many very
|
||||
expensive trig operations [sin(),cos(),tan()] which can take 100-200 usec each to compute.
|
||||
|
||||
Small angle approximation may be used to reduce computation overhead further. A third-order approximation
|
||||
(second order sin() has too much error) holds for most, if not, all CNC applications. Note that this
|
||||
approximation will begin to accumulate a numerical drift error when theta_per_segment is greater than
|
||||
~0.25 rad(14 deg) AND the approximation is successively used without correction several dozen times. This
|
||||
scenario is extremely unlikely, since segment lengths and theta_per_segment are automatically generated
|
||||
and scaled by the arc tolerance setting. Only a very large arc tolerance setting, unrealistic for CNC
|
||||
applications, would cause this numerical drift error. However, it is best to set N_ARC_CORRECTION from a
|
||||
low of ~4 to a high of ~20 or so to avoid trig operations while keeping arc generation accurate.
|
||||
|
||||
This approximation also allows mc_arc to immediately insert a line segment into the planner
|
||||
without the initial overhead of computing cos() or sin(). By the time the arc needs to be applied
|
||||
a correction, the planner should have caught up to the lag caused by the initial mc_arc overhead.
|
||||
This is important when there are successive arc motions.
|
||||
*/
|
||||
// Computes: cos_T = 1 - theta_per_segment^2/2, sin_T = theta_per_segment - theta_per_segment^3/6) in ~52usec
|
||||
float cos_T = 2.0 - theta_per_segment*theta_per_segment;
|
||||
float sin_T = theta_per_segment*0.16666667*(cos_T + 4.0);
|
||||
cos_T *= 0.5;
|
||||
|
||||
float sin_Ti;
|
||||
float cos_Ti;
|
||||
float r_axisi;
|
||||
uint16_t i;
|
||||
uint8_t count = 0;
|
||||
|
||||
for (i = 1; i<segments; i++) { // Increment (segments-1).
|
||||
|
||||
if (count < N_ARC_CORRECTION) {
|
||||
// Apply vector rotation matrix. ~40 usec
|
||||
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
|
||||
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
|
||||
r_axis1 = r_axisi;
|
||||
count++;
|
||||
} else {
|
||||
// Arc correction to radius vector. Computed only every N_ARC_CORRECTION increments. ~375 usec
|
||||
// Compute exact location by applying transformation matrix from initial radius vector(=-offset).
|
||||
cos_Ti = cos(i*theta_per_segment);
|
||||
sin_Ti = sin(i*theta_per_segment);
|
||||
r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti;
|
||||
r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti;
|
||||
count = 0;
|
||||
}
|
||||
|
||||
// Update arc_target location
|
||||
position[axis_0] = center_axis0 + r_axis0;
|
||||
position[axis_1] = center_axis1 + r_axis1;
|
||||
position[axis_linear] += linear_per_segment;
|
||||
#ifdef USE_KINEMATICS
|
||||
mc_line_kins(position, pl_data, previous_position);
|
||||
previous_position[axis_0] = position[axis_0];
|
||||
previous_position[axis_1] = position[axis_1];
|
||||
previous_position[axis_linear] = position[axis_linear];
|
||||
#else
|
||||
mc_line(position, pl_data);
|
||||
#endif
|
||||
|
||||
// Bail mid-circle on system abort. Runtime command check already performed by mc_line.
|
||||
if (sys.abort) { return; }
|
||||
}
|
||||
}
|
||||
// Ensure last segment arrives at target location.
|
||||
#ifdef USE_KINEMATICS
|
||||
mc_line_kins(target, pl_data, previous_position);
|
||||
#else
|
||||
mc_line(target, pl_data);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Execute dwell in seconds.
|
||||
void mc_dwell(float seconds)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) { return; }
|
||||
protocol_buffer_synchronize();
|
||||
delay_sec(seconds, DELAY_MODE_DWELL);
|
||||
}
|
||||
|
||||
|
||||
// Perform homing cycle to locate and set machine zero. Only '$H' executes this command.
|
||||
// NOTE: There should be no motions in the buffer and Grbl must be in an idle state before
|
||||
// executing the homing cycle. This prevents incorrect buffered plans after homing.
|
||||
void mc_homing_cycle(uint8_t cycle_mask)
|
||||
{
|
||||
#ifdef USE_CUSTOM_HOMING
|
||||
if (user_defined_homing())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// This give kinematics a chance to do something before normal homing
|
||||
// if it returns true, the homing is canceled.
|
||||
#ifdef USE_KINEMATICS
|
||||
if (kinematics_pre_homing(cycle_mask)) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Check and abort homing cycle, if hard limits are already enabled. Helps prevent problems
|
||||
// with machines with limits wired on both ends of travel to one limit pin.
|
||||
// TODO: Move the pin-specific LIMIT_PIN call to limits.c as a function.
|
||||
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
|
||||
if (limits_get_state()) {
|
||||
mc_reset(); // Issue system reset and ensure spindle and coolant are shutdown.
|
||||
system_set_exec_alarm(EXEC_ALARM_HARD_LIMIT);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
limits_disable(); // Disable hard limits pin change register for cycle duration
|
||||
|
||||
// -------------------------------------------------------------------------------------
|
||||
// Perform homing routine. NOTE: Special motion case. Only system reset works.
|
||||
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
if (cycle_mask) { limits_go_home(cycle_mask); } // Perform homing cycle based on mask.
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Search to engage all axes limit switches at faster homing seek rate.
|
||||
if (! axis_is_squared(HOMING_CYCLE_0))
|
||||
limits_go_home(HOMING_CYCLE_0); // Homing cycle 0
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
limits_go_home(HOMING_CYCLE_0);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
limits_go_home(HOMING_CYCLE_0);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(HOMING_CYCLE_0);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
|
||||
#ifdef HOMING_CYCLE_1
|
||||
if (! axis_is_squared(HOMING_CYCLE_1))
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(HOMING_CYCLE_1);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HOMING_CYCLE_2
|
||||
if (! axis_is_squared(HOMING_CYCLE_2))
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
else {
|
||||
ganged_mode = SQUARING_MODE_DUAL;
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
ganged_mode = SQUARING_MODE_A;
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
ganged_mode = SQUARING_MODE_B;
|
||||
limits_go_home(HOMING_CYCLE_2);
|
||||
ganged_mode = SQUARING_MODE_DUAL; // always return to dual
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HOMING_CYCLE_3
|
||||
limits_go_home(HOMING_CYCLE_3); // Homing cycle 3
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_4
|
||||
limits_go_home(HOMING_CYCLE_4); // Homing cycle 4
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_5
|
||||
limits_go_home(HOMING_CYCLE_5); // Homing cycle 5
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
protocol_execute_realtime(); // Check for reset and set system abort.
|
||||
if (sys.abort) { return; } // Did not complete. Alarm state set by mc_alarm.
|
||||
|
||||
// Homing cycle complete! Setup system for normal operation.
|
||||
// -------------------------------------------------------------------------------------
|
||||
|
||||
// Sync gcode parser and planner positions to homed position.
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
|
||||
#ifdef USE_KINEMATICS
|
||||
// This give kinematics a chance to do something after normal homing
|
||||
kinematics_post_homing();
|
||||
#endif
|
||||
|
||||
// If hard limits feature enabled, re-enable hard limits pin change register after homing cycle.
|
||||
limits_init();
|
||||
}
|
||||
|
||||
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
// NOTE: Upon probe failure, the program will be stopped and placed into ALARM state.
|
||||
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags)
|
||||
{
|
||||
// TODO: Need to update this cycle so it obeys a non-auto cycle start.
|
||||
if (sys.state == STATE_CHECK_MODE) { return(GC_PROBE_CHECK_MODE); }
|
||||
|
||||
// Finish all queued commands and empty planner buffer before starting probe cycle.
|
||||
protocol_buffer_synchronize();
|
||||
if (sys.abort) { return(GC_PROBE_ABORT); } // Return if system reset has been issued.
|
||||
|
||||
// Initialize probing control variables
|
||||
uint8_t is_probe_away = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_AWAY);
|
||||
uint8_t is_no_error = bit_istrue(parser_flags,GC_PARSER_PROBE_IS_NO_ERROR);
|
||||
sys.probe_succeeded = false; // Re-initialize probe history before beginning cycle.
|
||||
probe_configure_invert_mask(is_probe_away);
|
||||
|
||||
// After syncing, check if probe is already triggered. If so, halt and issue alarm.
|
||||
// NOTE: This probe initialization error applies to all probing cycles.
|
||||
if ( probe_get_state() ) { // Check probe pin state.
|
||||
system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_INITIAL);
|
||||
protocol_execute_realtime();
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask before returning.
|
||||
return(GC_PROBE_FAIL_INIT); // Nothing else to do but bail.
|
||||
}
|
||||
|
||||
// Setup and queue probing motion. Auto cycle-start should not start the cycle.
|
||||
mc_line(target, pl_data);
|
||||
|
||||
// Activate the probing state monitor in the stepper module.
|
||||
sys_probe_state = PROBE_ACTIVE;
|
||||
|
||||
// Perform probing cycle. Wait here until probe is triggered or motion completes.
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START);
|
||||
do {
|
||||
protocol_execute_realtime();
|
||||
if (sys.abort) { return(GC_PROBE_ABORT); } // Check for system abort
|
||||
} while (sys.state != STATE_IDLE);
|
||||
|
||||
// Probing cycle complete!
|
||||
|
||||
// Set state variables and error out, if the probe failed and cycle with error is enabled.
|
||||
if (sys_probe_state == PROBE_ACTIVE) {
|
||||
if (is_no_error) { memcpy(sys_probe_position, sys_position, sizeof(sys_position)); }
|
||||
else { system_set_exec_alarm(EXEC_ALARM_PROBE_FAIL_CONTACT); }
|
||||
} else {
|
||||
sys.probe_succeeded = true; // Indicate to system the probing cycle completed successfully.
|
||||
}
|
||||
sys_probe_state = PROBE_OFF; // Ensure probe state monitor is disabled.
|
||||
probe_configure_invert_mask(false); // Re-initialize invert mask.
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
|
||||
// Reset the stepper and planner buffers to remove the remainder of the probe motion.
|
||||
st_reset(); // Reset step segment buffer.
|
||||
plan_reset(); // Reset planner buffer. Zero planner positions. Ensure probing motion is cleared.
|
||||
plan_sync_position(); // Sync planner position to current machine position.
|
||||
|
||||
#ifdef MESSAGE_PROBE_COORDINATES
|
||||
// All done! Output the probe position as message.
|
||||
report_probe_parameters(CLIENT_ALL);
|
||||
#endif
|
||||
|
||||
if (sys.probe_succeeded) { return(GC_PROBE_FOUND); } // Successful probe cycle.
|
||||
else { return(GC_PROBE_FAIL_END); } // Failed to trigger probe within travel. With or without error.
|
||||
}
|
||||
|
||||
|
||||
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
|
||||
// NOTE: Uses the always free planner ring buffer head to store motion parameters for execution.
|
||||
void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data)
|
||||
{
|
||||
if (sys.abort) { return; } // Block during abort.
|
||||
|
||||
uint8_t plan_status = plan_buffer_line(parking_target, pl_data);
|
||||
|
||||
if (plan_status) {
|
||||
bit_true(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
bit_false(sys.step_control, STEP_CONTROL_END_MOTION); // Allow parking motion to execute, if feed hold is active.
|
||||
st_parking_setup_buffer(); // Setup step segment buffer for special parking motion case
|
||||
st_prep_buffer();
|
||||
st_wake_up();
|
||||
do {
|
||||
protocol_exec_rt_system();
|
||||
if (sys.abort) { return; }
|
||||
} while (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
st_parking_restore_buffer(); // Restore step segment buffer to normal run state.
|
||||
} else {
|
||||
bit_false(sys.step_control, STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
protocol_exec_rt_system();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Method to ready the system to reset by setting the realtime reset command and killing any
|
||||
// active processes in the system. This also checks if a system reset is issued while Grbl
|
||||
// is in a motion state. If so, kills the steppers and sets the system alarm to flag position
|
||||
// lost, since there was an abrupt uncontrolled deceleration. Called at an interrupt level by
|
||||
// realtime abort command and hard limits. So, keep to a minimum.
|
||||
void mc_reset()
|
||||
{
|
||||
// Only this function can set the system reset. Helps prevent multiple kill calls.
|
||||
if (bit_isfalse(sys_rt_exec_state, EXEC_RESET)) {
|
||||
system_set_exec_state_flag(EXEC_RESET);
|
||||
|
||||
// Kill spindle and coolant.
|
||||
spindle_stop();
|
||||
coolant_stop();
|
||||
// turn off all digital I/O
|
||||
sys_io_control(0xFF, false);
|
||||
|
||||
#ifdef ENABLE_SD_CARD
|
||||
// do we need to stop a running SD job?
|
||||
if (get_sd_state(false) == SDCARD_BUSY_PRINTING) {
|
||||
//Report print stopped
|
||||
report_feedback_message(MESSAGE_SD_FILE_QUIT);
|
||||
closeFile();
|
||||
}
|
||||
#endif
|
||||
|
||||
// Kill steppers only if in any motion state, i.e. cycle, actively holding, or homing.
|
||||
// NOTE: If steppers are kept enabled via the step idle delay setting, this also keeps
|
||||
// the steppers enabled by avoiding the go_idle call altogether, unless the motion state is
|
||||
// violated, by which, all bets are off.
|
||||
if ((sys.state & (STATE_CYCLE | STATE_HOMING | STATE_JOG)) ||
|
||||
(sys.step_control & (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION))) {
|
||||
if (sys.state == STATE_HOMING) {
|
||||
if (!sys_rt_exec_alarm) {system_set_exec_alarm(EXEC_ALARM_HOMING_FAIL_RESET); }
|
||||
} else { system_set_exec_alarm(EXEC_ALARM_ABORT_CYCLE); }
|
||||
st_go_idle(); // Force kill steppers. Position has likely been lost.
|
||||
}
|
||||
|
||||
#ifdef USE_GANGED_AXES
|
||||
ganged_mode = SQUARING_MODE_DUAL; // in case an error occurred during squaring
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
74
Grbl_Esp32-master/Grbl_Esp32/motion_control.h
Normal file
74
Grbl_Esp32-master/Grbl_Esp32/motion_control.h
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
motion_control.h - high level interface for issuing motion commands
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2015 Sungeun K. Jeon
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef motion_control_h
|
||||
#define motion_control_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// System motion commands must have a line number of zero.
|
||||
#define HOMING_CYCLE_LINE_NUMBER 0
|
||||
#define PARKING_MOTION_LINE_NUMBER 0
|
||||
|
||||
#define HOMING_CYCLE_ALL 0 // Must be zero.
|
||||
#define HOMING_CYCLE_X bit(X_AXIS)
|
||||
#define HOMING_CYCLE_Y bit(Y_AXIS)
|
||||
#define HOMING_CYCLE_Z bit(Z_AXIS)
|
||||
#define HOMING_CYCLE_A bit(A_AXIS)
|
||||
#define HOMING_CYCLE_B bit(B_AXIS)
|
||||
#define HOMING_CYCLE_C bit(C_AXIS)
|
||||
|
||||
|
||||
// Execute linear motion in absolute millimeter coordinates. Feed rate given in millimeters/second
|
||||
// unless invert_feed_rate is true. Then the feed_rate means that the motion should be completed in
|
||||
// (1 minute)/feed_rate time.
|
||||
void mc_line_kins(float *target, plan_line_data_t *pl_data, float *position);
|
||||
void mc_line(float *target, plan_line_data_t *pl_data);
|
||||
|
||||
// Execute an arc in offset mode format. position == current xyz, target == target xyz,
|
||||
// offset == offset from current xyz, axis_XXX defines circle plane in tool space, axis_linear is
|
||||
// the direction of helical travel, radius == circle radius, is_clockwise_arc boolean. Used
|
||||
// for vector transformation direction.
|
||||
void mc_arc(float *target, plan_line_data_t *pl_data, float *position, float *offset, float radius,
|
||||
uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear, uint8_t is_clockwise_arc);
|
||||
|
||||
// Dwell for a specific number of seconds
|
||||
void mc_dwell(float seconds);
|
||||
|
||||
// Perform homing cycle to locate machine zero. Requires limit switches.
|
||||
void mc_homing_cycle(uint8_t cycle_mask);
|
||||
|
||||
// Perform tool length probe cycle. Requires probe switch.
|
||||
uint8_t mc_probe_cycle(float *target, plan_line_data_t *pl_data, uint8_t parser_flags);
|
||||
|
||||
// Plans and executes the single special motion case for parking. Independent of main planner buffer.
|
||||
void mc_parking_motion(float *parking_target, plan_line_data_t *pl_data);
|
||||
|
||||
// Performs system reset. If in motion state, kills all motion and sets system alarm.
|
||||
void mc_reset();
|
||||
|
||||
#endif
|
452
Grbl_Esp32-master/Grbl_Esp32/nofile.h
Normal file
452
Grbl_Esp32-master/Grbl_Esp32/nofile.h
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
nofile.h - ESP3D data file
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//data generated by https://github.com/AraHaan/bin2c
|
||||
//bin2c Conversion Tool v0.14.0 - Windows - [FINAL].
|
||||
#ifndef __nofile_h
|
||||
#define __nofile_h
|
||||
/* Generated by bin2c, do not edit manually */
|
||||
|
||||
/* Contents of file tool.html.gz */
|
||||
#define PAGE_NOFILES_SIZE 6728
|
||||
const char PAGE_NOFILES[6728] PROGMEM = {
|
||||
0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xED, 0x3C, 0x89, 0x72, 0xDB, 0xC6,
|
||||
0x92, 0xBF, 0x82, 0x20, 0x15, 0x93, 0x58, 0x02, 0x24, 0x2E, 0xDE, 0xA2, 0xBC, 0x49, 0x2C, 0x27,
|
||||
0xDA, 0xB2, 0x63, 0x97, 0x24, 0xAF, 0xF7, 0x95, 0xE3, 0x52, 0x81, 0xC4, 0x50, 0xC4, 0x1A, 0x04,
|
||||
0x28, 0x60, 0x28, 0x4A, 0x96, 0xB9, 0xDF, 0xBE, 0xDD, 0x3D, 0x83, 0x8B, 0x97, 0x8E, 0xE7, 0xB7,
|
||||
0x2F, 0x5B, 0xF5, 0xA2, 0x90, 0x00, 0xE6, 0xE8, 0xE9, 0xE9, 0xBB, 0x1B, 0x43, 0x1F, 0xCD, 0xF8,
|
||||
0x3C, 0x3C, 0x3E, 0x9A, 0x31, 0xCF, 0x3F, 0x3E, 0x4A, 0xF9, 0x5D, 0xC8, 0x8E, 0xB1, 0xE5, 0x7E,
|
||||
0x1A, 0x47, 0xDC, 0x98, 0x7A, 0xF3, 0x20, 0xBC, 0x1B, 0xA4, 0x5E, 0x94, 0x1A, 0x29, 0x4B, 0x82,
|
||||
0xE9, 0xD0, 0x98, 0xA7, 0x06, 0x67, 0xB7, 0xDC, 0x48, 0x83, 0xAF, 0xCC, 0xF0, 0xFC, 0xFF, 0x5E,
|
||||
0xA6, 0x7C, 0x60, 0x99, 0xE6, 0x4F, 0x43, 0x63, 0xC5, 0xC6, 0x5F, 0x02, 0xBE, 0xA7, 0x97, 0xC0,
|
||||
0x61, 0x2B, 0x3C, 0x2E, 0x6E, 0xD7, 0xE3, 0xD8, 0xBF, 0xAB, 0x2C, 0xA1, 0xFE, 0xCE, 0xC2, 0x1B,
|
||||
0xC6, 0x83, 0x89, 0xA7, 0xFC, 0xC1, 0x96, 0x4C, 0xD5, 0xF3, 0x67, 0xFD, 0xE7, 0x24, 0xF0, 0x42,
|
||||
0xBD, 0x84, 0x43, 0x09, 0x96, 0xBB, 0xB8, 0x1D, 0x86, 0x41, 0xC4, 0x8C, 0x19, 0x0B, 0xAE, 0x66,
|
||||
0xB0, 0x56, 0xD3, 0xB5, 0x7B, 0xED, 0xAE, 0xE5, 0x3A, 0xC3, 0x49, 0x1C, 0xC6, 0xC9, 0xE0, 0x47,
|
||||
0xC7, 0x71, 0x86, 0x63, 0x6F, 0xF2, 0xE5, 0x2A, 0x89, 0x97, 0x91, 0x6F, 0xC8, 0xD6, 0xE9, 0x74,
|
||||
0xBA, 0xE6, 0xDE, 0x38, 0x64, 0xF7, 0xE3, 0x38, 0xF1, 0x59, 0x32, 0x30, 0x87, 0xE2, 0xC6, 0x48,
|
||||
0x17, 0xDE, 0x24, 0x88, 0xAE, 0xA0, 0x61, 0xEE, 0xDD, 0x1A, 0xAB, 0xC0, 0xE7, 0x33, 0xDA, 0xC1,
|
||||
0x9A, 0xFB, 0xF7, 0xAB, 0x59, 0xC0, 0x19, 0x8D, 0x60, 0x83, 0x28, 0x5E, 0x25, 0xDE, 0x62, 0xB8,
|
||||
0xF0, 0x7C, 0x1F, 0x87, 0xDB, 0xF3, 0xF9, 0x9A, 0xCF, 0xEE, 0x69, 0xF3, 0x5E, 0x18, 0x5C, 0x45,
|
||||
0x83, 0x90, 0x4D, 0xF9, 0xBA, 0x49, 0x8B, 0x1C, 0x73, 0xDC, 0xEF, 0x31, 0x4F, 0x8E, 0xB9, 0xAF,
|
||||
0x6F, 0x35, 0xCD, 0xF2, 0x26, 0x62, 0x42, 0x75, 0x54, 0xDE, 0x34, 0xBB, 0xCF, 0x96, 0xEA, 0xED,
|
||||
0xDF, 0xF3, 0x0D, 0x4B, 0x90, 0x64, 0xA1, 0x44, 0x81, 0xC7, 0x8B, 0x6C, 0x5B, 0x70, 0x3B, 0xB0,
|
||||
0x16, 0xB7, 0x4A, 0x1A, 0x87, 0x81, 0xAF, 0xFC, 0xE8, 0xFB, 0xBE, 0xC4, 0xCD, 0x48, 0x79, 0x12,
|
||||
0x2C, 0x98, 0x9F, 0x23, 0x34, 0x88, 0xF8, 0xCC, 0x88, 0xA7, 0x06, 0xBF, 0x5B, 0xB0, 0x7A, 0xEC,
|
||||
0xFB, 0xDA, 0xFD, 0x0E, 0xF2, 0xF5, 0xF1, 0x6F, 0xED, 0xDD, 0x2F, 0xE2, 0x34, 0xE0, 0x41, 0x1C,
|
||||
0x0D, 0x12, 0x16, 0x7A, 0x3C, 0xB8, 0x61, 0x43, 0x3F, 0x48, 0x17, 0xA1, 0x77, 0x37, 0x18, 0x87,
|
||||
0xF1, 0xE4, 0x4B, 0x4E, 0x1E, 0x64, 0xBA, 0x62, 0xB5, 0x01, 0x73, 0xA2, 0x90, 0xCF, 0x26, 0x71,
|
||||
0xE2, 0xD1, 0xC4, 0x28, 0x8E, 0x58, 0xC6, 0xAB, 0xC9, 0x64, 0xB2, 0x6E, 0x7A, 0x13, 0x84, 0x73,
|
||||
0x5F, 0x30, 0x6A, 0x07, 0xFB, 0x4C, 0xD3, 0xCC, 0x06, 0x2A, 0x9E, 0xEE, 0x0D, 0xA6, 0xF1, 0x64,
|
||||
0x99, 0xC2, 0x75, 0x16, 0x03, 0x05, 0x4A, 0x53, 0xD7, 0xCD, 0x85, 0x17, 0xB1, 0xF0, 0x7E, 0xEE,
|
||||
0x25, 0x57, 0x41, 0x64, 0x8C, 0x63, 0xCE, 0xE3, 0xF9, 0xC0, 0x06, 0x64, 0x76, 0xCB, 0x84, 0xA4,
|
||||
0xD6, 0x06, 0xA5, 0x32, 0x1A, 0x26, 0x9E, 0x1F, 0x2C, 0xD3, 0x01, 0xCA, 0x5C, 0x26, 0xEC, 0xE3,
|
||||
0xF8, 0xD6, 0x48, 0x67, 0x9E, 0x1F, 0xAF, 0x06, 0xA6, 0x82, 0xB3, 0xF0, 0x93, 0x5C, 0x8D, 0xBD,
|
||||
0xBA, 0xA9, 0xE3, 0x5F, 0xD3, 0x6C, 0x6B, 0xC3, 0xC7, 0x0C, 0x92, 0x98, 0x1A, 0xA4, 0x18, 0x39,
|
||||
0xD5, 0x80, 0x60, 0x59, 0x07, 0x0A, 0x02, 0xB4, 0xDD, 0x6F, 0x53, 0xF4, 0xB0, 0xA0, 0xB7, 0xF1,
|
||||
0x2F, 0xDB, 0x81, 0x6C, 0x2C, 0xED, 0x09, 0xE4, 0xC2, 0x48, 0x50, 0x8C, 0xB2, 0xDD, 0x39, 0x48,
|
||||
0x9B, 0xA2, 0x0F, 0xA5, 0x78, 0x47, 0x97, 0xA4, 0xE4, 0xA6, 0x44, 0x4D, 0xE3, 0x64, 0x0E, 0x8B,
|
||||
0x44, 0x3C, 0x89, 0xC3, 0xFB, 0xAA, 0x24, 0x08, 0x4D, 0xF2, 0x96, 0x3C, 0x1E, 0x4A, 0xB9, 0x75,
|
||||
0x90, 0x90, 0xD9, 0x76, 0x3A, 0xB8, 0x1B, 0x1B, 0x1A, 0x9E, 0xA4, 0xDC, 0xED, 0x76, 0x7B, 0x1F,
|
||||
0x23, 0x8B, 0xD6, 0x60, 0xEE, 0x5D, 0x31, 0x21, 0x67, 0xDB, 0xEC, 0x05, 0x91, 0x7B, 0x1C, 0x7B,
|
||||
0x83, 0x28, 0x65, 0x5C, 0xD9, 0xC3, 0xBF, 0x6E, 0x95, 0xCB, 0x0F, 0x8E, 0x35, 0x62, 0x83, 0x27,
|
||||
0x60, 0xD0, 0x84, 0xEE, 0x94, 0x99, 0xA3, 0x30, 0x2F, 0x65, 0x06, 0xC8, 0x6A, 0xBC, 0xE4, 0x4A,
|
||||
0xD3, 0x6A, 0xA7, 0x7A, 0x01, 0x77, 0xAB, 0xAF, 0x4A, 0x70, 0xA1, 0x05, 0xF7, 0x55, 0x56, 0x77,
|
||||
0x3A, 0xDE, 0x94, 0xF5, 0x87, 0x30, 0x03, 0x29, 0x09, 0x56, 0xED, 0x19, 0x5B, 0xD3, 0x4D, 0xE8,
|
||||
0xEC, 0x65, 0x1D, 0x96, 0x69, 0xEB, 0x56, 0xB7, 0xAD, 0xDB, 0x8E, 0xA3, 0x37, 0x3B, 0x9A, 0xC4,
|
||||
0x01, 0x69, 0xBD, 0xD8, 0xD0, 0x33, 0x21, 0xBE, 0x63, 0x1E, 0xE5, 0xA2, 0x10, 0x44, 0xC4, 0x4F,
|
||||
0x21, 0x11, 0xD5, 0xC1, 0xA6, 0xE0, 0xFC, 0x4A, 0xB0, 0xDA, 0x35, 0xCD, 0x61, 0xC9, 0x96, 0x4E,
|
||||
0x58, 0xC4, 0x59, 0xB2, 0x69, 0xDE, 0xE6, 0x81, 0xEF, 0x87, 0x4C, 0xB8, 0xA4, 0x78, 0x39, 0x99,
|
||||
0x19, 0x68, 0x11, 0x80, 0x9E, 0x73, 0x2F, 0x0A, 0x16, 0xCB, 0x90, 0xEC, 0xCB, 0x70, 0x7F, 0xCF,
|
||||
0x64, 0x99, 0xA4, 0x40, 0xA2, 0x45, 0x1C, 0x10, 0xF0, 0x47, 0x4A, 0x0C, 0xF1, 0x6D, 0xE1, 0x25,
|
||||
0x80, 0xD1, 0xF0, 0x80, 0x3F, 0x78, 0xA2, 0x3C, 0xEF, 0x10, 0xC1, 0x79, 0xFC, 0xD5, 0x58, 0xA6,
|
||||
0xE8, 0x91, 0x58, 0xC8, 0x26, 0x5C, 0xA0, 0x83, 0x7B, 0xDD, 0x6A, 0xDC, 0x6C, 0x20, 0x9A, 0x1B,
|
||||
0x8B, 0x04, 0xB6, 0x91, 0xDC, 0x1D, 0x36, 0xA4, 0x8E, 0xD3, 0xF5, 0xC6, 0xDD, 0x0D, 0xF3, 0x60,
|
||||
0xB3, 0x8E, 0xEF, 0xB9, 0x15, 0x28, 0xD2, 0xD8, 0xEA, 0x95, 0x36, 0x61, 0x75, 0x2B, 0x4D, 0x64,
|
||||
0x80, 0x2B, 0x4D, 0x83, 0x1D, 0x33, 0x07, 0xDB, 0x33, 0xB7, 0x4C, 0xF7, 0x0E, 0x64, 0xED, 0x5E,
|
||||
0xC7, 0xEC, 0x9B, 0x1B, 0xC8, 0x5A, 0xB6, 0x3D, 0x76, 0x4D, 0x42, 0x36, 0x98, 0x5F, 0xDD, 0x4B,
|
||||
0xA6, 0xCE, 0xBC, 0x68, 0xD3, 0x6C, 0x77, 0x72, 0xEB, 0x55, 0xD6, 0x7F, 0x72, 0x12, 0x62, 0xAE,
|
||||
0x44, 0x61, 0x87, 0x3D, 0x31, 0xF1, 0x6F, 0x63, 0xDD, 0xCE, 0x04, 0xFF, 0x9E, 0xAD, 0x4E, 0x28,
|
||||
0x1F, 0x57, 0x09, 0xBB, 0x7B, 0x8A, 0xD9, 0xA8, 0x4C, 0x24, 0xAC, 0x09, 0xCD, 0xC3, 0xDB, 0x76,
|
||||
0x4C, 0xA9, 0x84, 0xD9, 0xD8, 0x87, 0xB6, 0xF9, 0xCF, 0xDC, 0x51, 0x08, 0x48, 0x81, 0x86, 0x7C,
|
||||
0xD1, 0x8B, 0xDB, 0x41, 0x35, 0x1E, 0x20, 0xCF, 0x5F, 0x74, 0x56, 0xA4, 0x06, 0xFB, 0x82, 0x68,
|
||||
0xB1, 0xE4, 0x9F, 0x30, 0x76, 0x19, 0x4D, 0x83, 0x90, 0x7D, 0x1E, 0x0C, 0xB2, 0xFD, 0xE0, 0xA3,
|
||||
0xB1, 0x5C, 0x84, 0xB1, 0xE7, 0x1B, 0xE3, 0x25, 0xD8, 0x9C, 0x7F, 0x99, 0xA5, 0xFF, 0x5B, 0xB3,
|
||||
0x34, 0x3C, 0xA8, 0xDC, 0xED, 0xF1, 0xC4, 0xF4, 0xD9, 0x86, 0x92, 0xB9, 0x9D, 0x71, 0xCF, 0xF7,
|
||||
0x9E, 0xC4, 0x54, 0xE9, 0x05, 0xFF, 0xC5, 0xDA, 0xBF, 0x0E, 0x6B, 0x1D, 0x6B, 0x6C, 0xFA, 0x9B,
|
||||
0x31, 0xA8, 0x35, 0xEE, 0xF8, 0xBD, 0xF6, 0xD3, 0x58, 0x2B, 0xB4, 0xFD, 0x5F, 0xAC, 0xFD, 0x8B,
|
||||
0xB3, 0xD6, 0xEE, 0xF4, 0xBD, 0xF1, 0x24, 0x4B, 0x5C, 0xA6, 0x71, 0x0C, 0x14, 0x39, 0x90, 0xB7,
|
||||
0x58, 0x5D, 0xB3, 0xB7, 0x0B, 0xF6, 0x23, 0x52, 0x97, 0xAD, 0x04, 0xE4, 0x9F, 0xB0, 0xE4, 0x3C,
|
||||
0xF6, 0xBD, 0x22, 0xD9, 0x21, 0x92, 0xE5, 0x59, 0xF1, 0x34, 0xB8, 0x65, 0xFE, 0xF0, 0x2B, 0xC4,
|
||||
0xEC, 0x3E, 0xBB, 0xC5, 0x32, 0x02, 0x48, 0xA2, 0xC4, 0x4A, 0xC0, 0x32, 0x31, 0x15, 0xC5, 0x1C,
|
||||
0x0B, 0x44, 0x16, 0x1B, 0xCC, 0x61, 0x51, 0x71, 0xC8, 0xF2, 0x24, 0xBA, 0x47, 0xC9, 0x9F, 0x86,
|
||||
0xE0, 0x52, 0x29, 0x83, 0xDA, 0x99, 0x11, 0x6F, 0xB7, 0x96, 0xDD, 0xAD, 0xAB, 0x49, 0x54, 0x29,
|
||||
0x5D, 0x00, 0x81, 0xBB, 0xDF, 0x93, 0xE5, 0x59, 0x66, 0x35, 0x03, 0xAC, 0x64, 0x87, 0xE5, 0x4E,
|
||||
0xA1, 0x6B, 0x7B, 0xE7, 0xCA, 0xEE, 0x7D, 0xD3, 0x07, 0x76, 0x41, 0xC7, 0x3C, 0x0A, 0x2D, 0xE5,
|
||||
0xC9, 0x98, 0x6F, 0x58, 0x28, 0xF8, 0x66, 0x25, 0x6A, 0xB0, 0xB5, 0xE1, 0x76, 0xCD, 0x41, 0x28,
|
||||
0xBF, 0x20, 0x4D, 0xC6, 0xF4, 0x1D, 0xE4, 0xF8, 0x71, 0xCA, 0xF0, 0x2F, 0xA3, 0x03, 0x66, 0xD4,
|
||||
0x25, 0x29, 0xB1, 0xE5, 0x82, 0x99, 0x90, 0x50, 0x34, 0xB4, 0x53, 0x48, 0x6C, 0xFC, 0xDB, 0x97,
|
||||
0x24, 0x3F, 0x91, 0x7C, 0x95, 0x5C, 0x74, 0x8A, 0x7F, 0x19, 0x7A, 0xD5, 0x4A, 0x80, 0x29, 0xB1,
|
||||
0xCB, 0x7A, 0x37, 0x45, 0xBC, 0x93, 0x61, 0x2F, 0x85, 0xC6, 0x6D, 0xB6, 0xD9, 0xFC, 0xE9, 0x5B,
|
||||
0xD9, 0x46, 0xE7, 0xEF, 0xE4, 0xF6, 0xBA, 0x39, 0x0B, 0x7C, 0x76, 0x19, 0xF0, 0x8A, 0x86, 0xAC,
|
||||
0xFF, 0x7D, 0xCE, 0xFC, 0xC0, 0x53, 0xEA, 0x73, 0xB0, 0xD9, 0x42, 0xE2, 0xBB, 0x1D, 0xE0, 0xB8,
|
||||
0x76, 0xBF, 0x21, 0xA3, 0xA2, 0xAF, 0xDD, 0x43, 0x48, 0xD9, 0xA4, 0x74, 0x92, 0x30, 0x16, 0x29,
|
||||
0x10, 0xEA, 0xC2, 0xFC, 0xBC, 0x46, 0xD7, 0xED, 0x74, 0xF7, 0xCE, 0xA7, 0xFA, 0xDD, 0xFA, 0xA8,
|
||||
0x25, 0xCA, 0x9B, 0x47, 0x3C, 0xE0, 0x70, 0x39, 0x39, 0x7F, 0xEF, 0xBC, 0x52, 0x78, 0x1C, 0x87,
|
||||
0xCA, 0x02, 0x2C, 0xF4, 0x51, 0x4B, 0x34, 0x1F, 0xB5, 0x44, 0x29, 0x94, 0xAA, 0x61, 0x47, 0x7E,
|
||||
0x70, 0xA3, 0x4C, 0x42, 0x2F, 0x4D, 0x47, 0x2A, 0x99, 0x16, 0x15, 0x66, 0x63, 0xD5, 0x4C, 0x21,
|
||||
0xC0, 0x23, 0x15, 0x21, 0x63, 0x5B, 0x02, 0x1F, 0x98, 0xE4, 0x65, 0x83, 0x45, 0x46, 0xA1, 0x2A,
|
||||
0xB3, 0x84, 0x4D, 0x47, 0xEA, 0x8C, 0xF3, 0x45, 0x3A, 0x68, 0xB5, 0xAE, 0x02, 0x3E, 0x5B, 0x8E,
|
||||
0x9B, 0x93, 0x78, 0xDE, 0x1A, 0xFB, 0x09, 0xF0, 0xAD, 0xF5, 0x5B, 0x32, 0x0E, 0x2F, 0x4F, 0xD2,
|
||||
0x85, 0x63, 0xAB, 0x0A, 0x07, 0x29, 0x66, 0x7C, 0xA4, 0x5E, 0x42, 0x78, 0x1B, 0x7D, 0x01, 0xA8,
|
||||
0xE9, 0xCD, 0x55, 0xBE, 0x0E, 0x9B, 0x03, 0x30, 0x62, 0xAD, 0x7C, 0xB8, 0x09, 0xD8, 0xEA, 0x97,
|
||||
0xF8, 0x76, 0xA4, 0x62, 0x08, 0x6D, 0x39, 0x26, 0x7C, 0xD9, 0xA6, 0x09, 0xB3, 0xAE, 0x84, 0x57,
|
||||
0xC1, 0xAC, 0x7C, 0xA4, 0xD2, 0x2D, 0x68, 0x09, 0xAB, 0xB7, 0x4D, 0x1D, 0x07, 0x68, 0x40, 0x3E,
|
||||
0x2F, 0x64, 0x75, 0x4B, 0x57, 0x0C, 0x4B, 0x83, 0xE1, 0x0B, 0x8F, 0xCF, 0x14, 0x7F, 0xA4, 0xBE,
|
||||
0xED, 0x20, 0x08, 0xAB, 0xEB, 0x5E, 0x3B, 0x0E, 0x40, 0xEC, 0xBA, 0x8A, 0xD1, 0x0E, 0x9D, 0x1E,
|
||||
0x8C, 0x6A, 0xDB, 0x61, 0x1B, 0x2E, 0xD7, 0x6E, 0x1F, 0xBE, 0x5D, 0xA5, 0x0F, 0x3D, 0x4E, 0x1F,
|
||||
0x9B, 0xEC, 0xD0, 0x72, 0x5C, 0xA5, 0x67, 0x5E, 0x77, 0x2C, 0xC5, 0x70, 0x7B, 0x8A, 0x65, 0x42,
|
||||
0x97, 0x65, 0xB6, 0x43, 0xA3, 0x67, 0xC2, 0x8D, 0xE3, 0x86, 0x0E, 0x00, 0xB9, 0xB6, 0x61, 0xA8,
|
||||
0xEB, 0x2A, 0x0E, 0x4C, 0xEF, 0x3B, 0x21, 0x0C, 0xED, 0x84, 0x00, 0x13, 0x80, 0xF4, 0xAE, 0xB1,
|
||||
0xC7, 0x51, 0xE0, 0xBB, 0xEB, 0x5C, 0xC3, 0x14, 0x07, 0x17, 0x85, 0x07, 0x37, 0x34, 0xE4, 0x08,
|
||||
0xB8, 0x81, 0xF1, 0xD7, 0xF0, 0x08, 0x23, 0xFB, 0xB8, 0x30, 0x01, 0x31, 0x10, 0x70, 0x28, 0x57,
|
||||
0xB9, 0xC6, 0xB5, 0x0D, 0xC4, 0xA1, 0x40, 0x80, 0x10, 0xB3, 0x42, 0x84, 0xE6, 0x5C, 0xE3, 0xEA,
|
||||
0x06, 0x62, 0x21, 0x51, 0x37, 0x08, 0x77, 0x43, 0x6C, 0xCE, 0x52, 0xAE, 0x11, 0x07, 0xB1, 0x2E,
|
||||
0xA2, 0x6B, 0xD0, 0xFE, 0xF1, 0xA1, 0x4D, 0x63, 0x60, 0x08, 0xCE, 0xB0, 0xAF, 0x11, 0x01, 0xD8,
|
||||
0x3F, 0x42, 0x11, 0x40, 0x1C, 0xB1, 0x8E, 0xD1, 0xB3, 0xAE, 0x8D, 0x8E, 0xA9, 0x20, 0x16, 0x88,
|
||||
0x01, 0x22, 0xD0, 0x43, 0x9E, 0xB8, 0x88, 0x27, 0x00, 0x84, 0xA5, 0x5D, 0x44, 0xA4, 0xA7, 0x20,
|
||||
0xEA, 0xB6, 0xD2, 0x09, 0x69, 0x5D, 0xD8, 0xBF, 0xD1, 0x51, 0x5C, 0xD8, 0x67, 0x07, 0xC8, 0x0D,
|
||||
0xFB, 0x87, 0x85, 0xE1, 0x0E, 0x48, 0x44, 0x9D, 0x21, 0x0C, 0xBC, 0xB6, 0x1C, 0x04, 0x2B, 0x66,
|
||||
0x3A, 0x8A, 0xA0, 0x2C, 0x6E, 0xD9, 0xED, 0x2A, 0xB0, 0x61, 0x58, 0x89, 0x56, 0xB3, 0x60, 0x26,
|
||||
0xF4, 0x84, 0x88, 0x25, 0xAC, 0x04, 0xEB, 0x09, 0x1C, 0xA1, 0x37, 0xA4, 0x1D, 0x40, 0x33, 0x92,
|
||||
0x19, 0xF7, 0xF4, 0x95, 0x18, 0xDD, 0x03, 0x82, 0x5E, 0x1B, 0xBD, 0x3E, 0xEE, 0x94, 0x48, 0xDD,
|
||||
0x71, 0x38, 0x7C, 0x88, 0x20, 0xCD, 0x36, 0x2F, 0xEE, 0xB2, 0x4E, 0xBC, 0xC2, 0x05, 0x3A, 0x44,
|
||||
0xBB, 0x51, 0xDC, 0x89, 0xAE, 0xAF, 0x20, 0x4B, 0x2D, 0x14, 0x26, 0xB8, 0x5C, 0xC1, 0x07, 0x84,
|
||||
0xF7, 0x58, 0x39, 0x82, 0x70, 0x26, 0xCA, 0x75, 0x22, 0xCB, 0xDA, 0xD4, 0xE3, 0xD7, 0x41, 0x32,
|
||||
0x5F, 0x41, 0xD8, 0x03, 0xC3, 0x60, 0x00, 0x8C, 0xF6, 0xE0, 0x83, 0x0A, 0xF4, 0x08, 0x25, 0x5A,
|
||||
0xAD, 0x56, 0xCD, 0x92, 0x22, 0x85, 0xCB, 0x89, 0x21, 0x1E, 0x5B, 0xA4, 0xD1, 0xC6, 0xC7, 0x93,
|
||||
0x5F, 0x3E, 0x9C, 0xB6, 0x38, 0xD8, 0x88, 0x96, 0xDD, 0xB4, 0xFE, 0x1A, 0x6A, 0x65, 0xF6, 0xDD,
|
||||
0xEB, 0x9E, 0x8D, 0x10, 0x3B, 0x66, 0x13, 0xA5, 0xCF, 0x46, 0xD2, 0xBA, 0x40, 0xFC, 0x76, 0x9F,
|
||||
0x5B, 0x56, 0x07, 0xDB, 0x7A, 0xD8, 0xD6, 0x77, 0xF1, 0xB6, 0x0F, 0x1C, 0xE8, 0xD1, 0xC5, 0xB5,
|
||||
0xF3, 0x2E, 0x14, 0xBD, 0x76, 0x97, 0x08, 0x9E, 0xDF, 0xA1, 0xE0, 0x52, 0xA7, 0xD1, 0xE9, 0xC9,
|
||||
0x89, 0x46, 0x0E, 0xC2, 0x28, 0x03, 0x36, 0xB2, 0xD5, 0x80, 0x5D, 0xFD, 0x1C, 0x05, 0xF9, 0x60,
|
||||
0xE7, 0x23, 0x68, 0x00, 0x4D, 0x13, 0xB3, 0x08, 0x58, 0x3F, 0x83, 0xDF, 0x17, 0x4B, 0x66, 0x00,
|
||||
0x15, 0x42, 0x22, 0xBB, 0x12, 0xAA, 0xD4, 0x05, 0xB8, 0xF7, 0xDB, 0x0A, 0xCF, 0xE6, 0x96, 0xE0,
|
||||
0xC9, 0x25, 0x04, 0x15, 0x70, 0xD5, 0xAF, 0x6F, 0x7B, 0xBD, 0x1E, 0xF4, 0xF5, 0x49, 0xC5, 0x51,
|
||||
0xCB, 0x2D, 0x90, 0x57, 0x9B, 0x13, 0x82, 0x64, 0x39, 0xDA, 0x5D, 0x94, 0x67, 0x40, 0xAA, 0x8F,
|
||||
0x16, 0xC2, 0xB2, 0x51, 0xDF, 0x80, 0x36, 0x36, 0x0C, 0xC2, 0x2F, 0x7C, 0x12, 0x37, 0x78, 0x85,
|
||||
0x1E, 0xB8, 0xBD, 0xC6, 0x45, 0x14, 0x1B, 0x04, 0xD4, 0x02, 0xB2, 0x2B, 0x56, 0x5F, 0x71, 0x69,
|
||||
0x39, 0xC0, 0xB9, 0x8B, 0x5B, 0x87, 0x11, 0x46, 0x17, 0x80, 0x75, 0xD0, 0xA0, 0x75, 0x10, 0x6A,
|
||||
0x0F, 0x8C, 0x88, 0x85, 0x32, 0xDF, 0x51, 0x84, 0xA9, 0x31, 0x91, 0x17, 0x70, 0x05, 0x14, 0xAF,
|
||||
0x6D, 0xB4, 0x44, 0xA0, 0xA8, 0x5D, 0x30, 0x0A, 0x16, 0xC7, 0x89, 0x3D, 0x9B, 0xF7, 0x05, 0x63,
|
||||
0x2C, 0xD8, 0x1D, 0x1A, 0x8F, 0x1E, 0x6E, 0xCE, 0x71, 0x88, 0xB0, 0xB8, 0x98, 0x7C, 0xB0, 0x5D,
|
||||
0xEA, 0xA7, 0x6E, 0x9A, 0xD1, 0x43, 0x8D, 0xE9, 0x9A, 0xE2, 0x0A, 0x10, 0xBB, 0xB0, 0xD0, 0xB5,
|
||||
0x05, 0x9A, 0x0C, 0x24, 0x53, 0xDC, 0x8C, 0xAE, 0x2E, 0xF4, 0x5E, 0x1B, 0x7D, 0xB2, 0xC7, 0x88,
|
||||
0x14, 0xEC, 0xA4, 0xD7, 0xFF, 0xFA, 0xD6, 0x05, 0x53, 0xD0, 0xB5, 0xBB, 0x60, 0x55, 0xD0, 0x9A,
|
||||
0x48, 0xAB, 0x48, 0x1F, 0xE2, 0xA8, 0x83, 0xAB, 0x10, 0xF3, 0x69, 0xBE, 0x03, 0x53, 0x91, 0x13,
|
||||
0xB8, 0x2D, 0x0B, 0x2C, 0x09, 0x6E, 0xCD, 0x51, 0x1C, 0x92, 0x13, 0xCB, 0xE2, 0x0E, 0x32, 0xC5,
|
||||
0xEA, 0x86, 0x00, 0x0B, 0xEC, 0x09, 0x2C, 0x8A, 0xF4, 0x47, 0x14, 0x11, 0x71, 0xC0, 0xA2, 0x23,
|
||||
0x6F, 0xC9, 0x7A, 0xA2, 0x01, 0x05, 0x63, 0x01, 0xE8, 0xC0, 0xA2, 0x84, 0xAD, 0x61, 0x03, 0xA9,
|
||||
0x4D, 0x6E, 0x38, 0x36, 0xD2, 0xF3, 0x49, 0xCA, 0x7F, 0x8A, 0x19, 0xD2, 0x14, 0xD2, 0x9C, 0xE7,
|
||||
0x68, 0xFF, 0x21, 0x17, 0xDA, 0x5A, 0x05, 0x5F, 0x82, 0xBF, 0x86, 0xC2, 0x5B, 0xDD, 0xEE, 0x35,
|
||||
0x32, 0xCF, 0x04, 0xB1, 0x03, 0xDA, 0xB9, 0x6D, 0x94, 0x8F, 0x9E, 0x2B, 0xA4, 0x0F, 0xAC, 0xA9,
|
||||
0xED, 0x90, 0xD4, 0x21, 0xC3, 0xDA, 0x42, 0x1B, 0x5D, 0x6E, 0x94, 0x6E, 0x4B, 0x03, 0x8C, 0xD2,
|
||||
0x3C, 0xA3, 0x80, 0x46, 0xB7, 0xE2, 0x4E, 0x0C, 0xA0, 0x7E, 0x9C, 0x27, 0xA7, 0x11, 0x34, 0x04,
|
||||
0x96, 0xDF, 0x14, 0x9D, 0xC5, 0x8C, 0x0C, 0xCA, 0xD7, 0xB7, 0x6D, 0x50, 0x9E, 0xBE, 0x0B, 0xAE,
|
||||
0xCC, 0x26, 0xAF, 0x00, 0x1A, 0x64, 0xB4, 0xA5, 0xA1, 0x37, 0x6C, 0xD4, 0x07, 0x90, 0x72, 0x29,
|
||||
0x64, 0x24, 0x60, 0xC2, 0x67, 0x48, 0x13, 0x83, 0x02, 0x88, 0xFA, 0x09, 0xAA, 0x6A, 0xD3, 0x65,
|
||||
0x66, 0x39, 0xD6, 0xB5, 0x83, 0x70, 0x14, 0x90, 0x30, 0xCB, 0xBA, 0xEE, 0x60, 0x87, 0x4D, 0x7A,
|
||||
0xDF, 0x13, 0x28, 0xF5, 0xAE, 0x6D, 0xA4, 0xB9, 0x43, 0xB0, 0x2C, 0x5C, 0xC1, 0xA2, 0x5B, 0x1B,
|
||||
0x96, 0x20, 0x58, 0xB0, 0x70, 0x17, 0x83, 0x02, 0xD8, 0x2B, 0x0A, 0x2F, 0xB8, 0x4B, 0x8B, 0xFC,
|
||||
0x15, 0xA9, 0x19, 0x12, 0x89, 0xC4, 0x9E, 0x0C, 0x21, 0x2E, 0x4A, 0x20, 0x0C, 0xD4, 0x56, 0xAB,
|
||||
0x8B, 0x44, 0x11, 0xCA, 0x88, 0x36, 0x8E, 0xB4, 0x03, 0xFA, 0x00, 0x7F, 0x17, 0xD5, 0x06, 0x10,
|
||||
0x56, 0xA8, 0x11, 0xB1, 0xE7, 0x84, 0x94, 0x01, 0xC3, 0x67, 0x16, 0x84, 0x21, 0x82, 0x67, 0x4A,
|
||||
0x8F, 0x3B, 0x84, 0xA9, 0x83, 0x16, 0xC3, 0xED, 0x71, 0x1B, 0xD7, 0xEA, 0x22, 0x0D, 0xC1, 0x9A,
|
||||
0x9B, 0x80, 0x1E, 0x9A, 0x03, 0x60, 0x70, 0xCF, 0x51, 0x38, 0x99, 0x09, 0x30, 0x82, 0x40, 0x21,
|
||||
0x1C, 0xE5, 0x10, 0xF9, 0x3B, 0xA0, 0x51, 0x3D, 0x6C, 0x41, 0xE3, 0x03, 0x4E, 0xB7, 0x0B, 0x60,
|
||||
0x4C, 0x73, 0x06, 0xD8, 0x98, 0x80, 0x81, 0x49, 0x1B, 0xE9, 0xE6, 0xF8, 0x0B, 0xBB, 0x04, 0xDF,
|
||||
0x37, 0x34, 0x80, 0x76, 0xA3, 0xE4, 0x8D, 0x3C, 0x1F, 0x39, 0xC3, 0x5E, 0x9A, 0x4D, 0x4D, 0xD8,
|
||||
0xD7, 0x25, 0x3D, 0x86, 0x99, 0x62, 0xA2, 0x65, 0xD2, 0x40, 0x6A, 0x92, 0x06, 0x0F, 0x3E, 0x4F,
|
||||
0x52, 0xD0, 0xDF, 0x59, 0xB8, 0xD8, 0xA1, 0x9B, 0x0A, 0x85, 0xCF, 0x23, 0xB5, 0x88, 0xA9, 0xD5,
|
||||
0xA2, 0x2F, 0x8E, 0x26, 0x61, 0x30, 0xF9, 0x32, 0x52, 0xCF, 0xDE, 0xD4, 0xB5, 0xA1, 0xAA, 0x04,
|
||||
0xA0, 0x0A, 0x61, 0x0C, 0x59, 0x59, 0x00, 0xA1, 0xB8, 0xBA, 0xAD, 0xD6, 0x55, 0xAD, 0x6C, 0x3A,
|
||||
0x15, 0xBD, 0x6C, 0xDA, 0xDF, 0x5D, 0x33, 0xA7, 0x41, 0x18, 0xCA, 0x4D, 0xAA, 0xA4, 0xA6, 0x7D,
|
||||
0x8C, 0x82, 0x4C, 0xF3, 0xC6, 0x26, 0x6E, 0xF6, 0xA4, 0x11, 0x87, 0x00, 0x4F, 0xC4, 0x34, 0x24,
|
||||
0xE1, 0xD8, 0x32, 0x33, 0x60, 0x65, 0x08, 0x95, 0x6C, 0xE2, 0x98, 0x6B, 0x09, 0x27, 0xDA, 0xA6,
|
||||
0x58, 0xD8, 0xBA, 0x01, 0xC1, 0x43, 0x9E, 0xE2, 0x08, 0x97, 0x84, 0xB3, 0x2B, 0xFC, 0x7B, 0x9F,
|
||||
0x44, 0x51, 0xC8, 0xA7, 0x89, 0x5C, 0xED, 0xD0, 0x32, 0x38, 0xA8, 0x68, 0xE5, 0xC5, 0xE0, 0x19,
|
||||
0xA0, 0x73, 0x4D, 0x10, 0xA8, 0x8D, 0xE6, 0x0B, 0x91, 0xC3, 0xD9, 0x62, 0x32, 0xAE, 0x9D, 0xB7,
|
||||
0x71, 0x23, 0x1F, 0x48, 0xEB, 0x83, 0x77, 0x90, 0x1B, 0x12, 0x62, 0x60, 0x5B, 0x68, 0xD0, 0x1D,
|
||||
0xD4, 0x60, 0xD4, 0x3F, 0x90, 0xC1, 0x19, 0xA0, 0xAA, 0x48, 0x95, 0x43, 0xB9, 0x22, 0x3B, 0x40,
|
||||
0x8A, 0x21, 0xA5, 0x8E, 0x76, 0xFA, 0x55, 0x6D, 0x95, 0x44, 0x64, 0x17, 0xFB, 0x4B, 0x95, 0x34,
|
||||
0xCA, 0xF6, 0x90, 0x95, 0x28, 0x47, 0xC8, 0xF1, 0xD7, 0x1F, 0xFF, 0xF3, 0xE4, 0xEC, 0xFC, 0xF4,
|
||||
0xDD, 0x1F, 0xEA, 0x0E, 0xB1, 0xCA, 0x45, 0x0A, 0xE1, 0xB5, 0x30, 0x65, 0x6A, 0x89, 0x43, 0x0E,
|
||||
0x47, 0x2D, 0x48, 0xB3, 0x76, 0xE6, 0x5A, 0xA2, 0x54, 0x77, 0x7C, 0x34, 0xB3, 0x09, 0xFC, 0xDB,
|
||||
0xF3, 0xDF, 0x10, 0xCC, 0xCC, 0x86, 0xAF, 0xAC, 0x6B, 0xF7, 0x5C, 0x45, 0x66, 0x9D, 0x42, 0x10,
|
||||
0x5F, 0x9F, 0xBE, 0x39, 0x39, 0xFF, 0xDB, 0xF9, 0xC5, 0xC9, 0x5B, 0x75, 0x7B, 0x68, 0xF6, 0x66,
|
||||
0x1D, 0xA2, 0x52, 0x68, 0x9D, 0x29, 0xAF, 0x83, 0x90, 0xA5, 0x77, 0x29, 0x67, 0xF3, 0x3D, 0xB0,
|
||||
0x29, 0x33, 0x07, 0x40, 0x54, 0xBA, 0x54, 0xA8, 0x74, 0xA9, 0x62, 0xB1, 0x52, 0xAC, 0x45, 0x65,
|
||||
0x4B, 0x51, 0x3F, 0x53, 0x95, 0xC8, 0x9B, 0x43, 0xE7, 0xFC, 0x0E, 0x1B, 0xD3, 0x4F, 0x9F, 0x55,
|
||||
0x65, 0xBE, 0x0C, 0x79, 0xB0, 0x40, 0x32, 0x66, 0x77, 0x2A, 0xE8, 0xA1, 0x80, 0x54, 0x28, 0x88,
|
||||
0x52, 0x7A, 0x31, 0xA6, 0xCA, 0x15, 0x44, 0x09, 0x54, 0xAC, 0x51, 0xA9, 0x8A, 0xAA, 0x85, 0xEE,
|
||||
0x9D, 0xB3, 0xC8, 0xC7, 0xA5, 0x48, 0x03, 0x6F, 0xBC, 0x70, 0x09, 0xF3, 0x3E, 0xD0, 0x58, 0xF5,
|
||||
0xF8, 0x45, 0x34, 0x4E, 0x17, 0x43, 0xF1, 0x7D, 0xB4, 0x48, 0xE2, 0xAB, 0x84, 0xA5, 0x69, 0xC6,
|
||||
0xD3, 0x9B, 0x20, 0x0D, 0xC6, 0x41, 0x18, 0xF0, 0xBB, 0x01, 0x10, 0xCE, 0x67, 0x51, 0x86, 0xFA,
|
||||
0x22, 0xB9, 0x12, 0x4B, 0xD2, 0x0D, 0x64, 0xDB, 0x94, 0xF2, 0x92, 0x31, 0x91, 0x20, 0x20, 0x53,
|
||||
0x4E, 0xC4, 0x67, 0x07, 0xFF, 0xF6, 0x91, 0x4E, 0xF2, 0x5D, 0xA4, 0xCD, 0x99, 0x15, 0x20, 0x7B,
|
||||
0xF2, 0x14, 0x52, 0x54, 0xF6, 0xFD, 0x6B, 0x3C, 0x9F, 0x7B, 0x91, 0x5F, 0xAF, 0x85, 0x41, 0xCA,
|
||||
0x6B, 0x7A, 0xCD, 0x0B, 0xC3, 0x5A, 0x89, 0x0C, 0x67, 0x6C, 0x0A, 0xD8, 0xCE, 0x4A, 0x16, 0xAB,
|
||||
0xBC, 0x2A, 0xE2, 0x99, 0x43, 0xFB, 0x35, 0x61, 0x60, 0x4E, 0xFC, 0x20, 0xA9, 0x6B, 0xEA, 0x21,
|
||||
0xAB, 0xE5, 0x9A, 0x85, 0xC9, 0xC2, 0xFB, 0x8A, 0xBD, 0x72, 0xF1, 0x7F, 0x18, 0x9F, 0x80, 0x1C,
|
||||
0x28, 0xD0, 0xD6, 0x56, 0x95, 0x3B, 0xA4, 0x9D, 0x9A, 0xCD, 0x76, 0x4A, 0xB3, 0x6D, 0xB8, 0x4F,
|
||||
0x60, 0x90, 0x0D, 0x97, 0x3B, 0xBA, 0x08, 0x73, 0x25, 0xCB, 0xAB, 0xA8, 0x92, 0x19, 0x1C, 0x1C,
|
||||
0x7A, 0x47, 0xE0, 0x32, 0xDB, 0xD9, 0x2E, 0x19, 0xCE, 0xF6, 0x83, 0x70, 0x50, 0x7B, 0x11, 0x8E,
|
||||
0x25, 0x10, 0xB2, 0xE1, 0x92, 0x17, 0x95, 0xA1, 0xB5, 0x27, 0x1F, 0x57, 0x12, 0x22, 0x18, 0x94,
|
||||
0x0C, 0x08, 0xD5, 0xA7, 0xD5, 0xE3, 0x06, 0x10, 0x10, 0x60, 0xE4, 0x06, 0x82, 0x54, 0x64, 0x83,
|
||||
0xA6, 0xD2, 0x37, 0x20, 0x55, 0x49, 0x76, 0xC0, 0x00, 0xE7, 0x94, 0x0C, 0xA2, 0x69, 0x9C, 0x49,
|
||||
0x63, 0x79, 0x76, 0xC5, 0x20, 0x88, 0x1A, 0x8B, 0x9C, 0x21, 0x1E, 0x2A, 0x87, 0x95, 0xD4, 0x4C,
|
||||
0x70, 0x8B, 0x8A, 0x3A, 0x4A, 0x95, 0xA8, 0xDC, 0x90, 0x54, 0xCD, 0xCA, 0xFC, 0xBD, 0x00, 0xB1,
|
||||
0x01, 0xD8, 0x33, 0x6C, 0x3F, 0xFE, 0x03, 0x04, 0x3B, 0x7F, 0x38, 0x87, 0x6D, 0x67, 0x0F, 0xC2,
|
||||
0x54, 0x9C, 0x5F, 0xF2, 0x60, 0x0E, 0xFB, 0xBC, 0x08, 0x8A, 0x61, 0x15, 0x59, 0xD9, 0x68, 0xCB,
|
||||
0xFD, 0xE0, 0x2C, 0xDF, 0x83, 0x44, 0x03, 0x65, 0x3D, 0x37, 0x09, 0x97, 0x28, 0x96, 0x34, 0x4E,
|
||||
0x14, 0x96, 0x0E, 0x9B, 0x3E, 0x59, 0xDE, 0x13, 0xAA, 0x97, 0x72, 0x8F, 0x2F, 0x53, 0x35, 0xA7,
|
||||
0xF5, 0xD6, 0xF7, 0x03, 0xC6, 0xEF, 0xE3, 0x87, 0xF7, 0xAF, 0x7E, 0xBE, 0x38, 0x39, 0x6C, 0xFA,
|
||||
0x64, 0x42, 0xAE, 0x7C, 0x58, 0xF8, 0x20, 0xFC, 0x0F, 0x58, 0xBE, 0x8A, 0xFA, 0xEE, 0x35, 0x84,
|
||||
0xAB, 0xBD, 0x66, 0xB0, 0x14, 0xEE, 0x3F, 0xD9, 0xF4, 0xC1, 0x43, 0x49, 0xF3, 0x85, 0x75, 0xDB,
|
||||
0xB6, 0x79, 0xB8, 0x89, 0xF2, 0x32, 0x4F, 0x31, 0x78, 0xD3, 0x55, 0x6E, 0xF2, 0xF0, 0x76, 0xB7,
|
||||
0xD1, 0xCB, 0x21, 0xE7, 0xBE, 0x6F, 0x9E, 0x5E, 0xA9, 0xFB, 0xC1, 0x1F, 0x9F, 0x31, 0xE0, 0x63,
|
||||
0xC2, 0x81, 0xDA, 0xBA, 0x02, 0x66, 0xDF, 0x4B, 0x99, 0xB2, 0xF2, 0x02, 0xDE, 0x84, 0xFF, 0x32,
|
||||
0xC7, 0x98, 0x83, 0x9A, 0xC4, 0x4B, 0x74, 0x6E, 0x0F, 0xBB, 0xCC, 0x82, 0x4D, 0x79, 0xBC, 0x85,
|
||||
0xB5, 0xCC, 0x5C, 0xD9, 0xA8, 0x18, 0x5A, 0x65, 0x7C, 0xA5, 0x3E, 0xBA, 0xAB, 0x4B, 0x94, 0xC5,
|
||||
0xA1, 0x67, 0xE6, 0x1C, 0x9F, 0x02, 0xEA, 0x3C, 0x98, 0x06, 0x13, 0x7A, 0xC9, 0x05, 0x9E, 0xD7,
|
||||
0xD9, 0x21, 0x73, 0x45, 0xB9, 0x5A, 0x86, 0x02, 0xC7, 0x95, 0xC0, 0x52, 0x74, 0xA3, 0xCD, 0x50,
|
||||
0x95, 0x3C, 0x58, 0x3B, 0xFE, 0x90, 0x82, 0xDA, 0xCA, 0xED, 0x6D, 0x38, 0xC0, 0xF2, 0x99, 0xA6,
|
||||
0x4C, 0x04, 0xC4, 0x74, 0xDA, 0x24, 0xF2, 0xBF, 0x12, 0x89, 0x62, 0xD9, 0xBF, 0x20, 0xD5, 0x2C,
|
||||
0x79, 0x3C, 0x12, 0xEF, 0xA1, 0x6F, 0x05, 0x16, 0xE4, 0x09, 0x88, 0x2C, 0xE4, 0x14, 0x89, 0xCC,
|
||||
0xE2, 0x30, 0x32, 0xE3, 0x5D, 0x01, 0x4A, 0xB9, 0x80, 0xBF, 0x11, 0x46, 0x64, 0x92, 0xBE, 0x4F,
|
||||
0x1F, 0x0A, 0x8F, 0xF7, 0xE6, 0x0C, 0xBD, 0x93, 0x94, 0xF7, 0xF3, 0xE5, 0x78, 0x1E, 0xF0, 0x9D,
|
||||
0x16, 0x22, 0x9D, 0x80, 0xC1, 0xE4, 0xC7, 0x37, 0x5E, 0xA2, 0xAC, 0xD2, 0xCB, 0x34, 0x5E, 0x26,
|
||||
0x13, 0xA6, 0xDF, 0xCE, 0x43, 0xCC, 0xA7, 0x45, 0x18, 0xA1, 0x4F, 0x96, 0x09, 0xBE, 0x80, 0x44,
|
||||
0x2B, 0x3D, 0x52, 0x5B, 0xAA, 0x0E, 0x5B, 0x98, 0x21, 0xDB, 0x05, 0xD3, 0x47, 0x3F, 0x58, 0xFA,
|
||||
0x8A, 0x8D, 0xD3, 0x78, 0xF2, 0x85, 0xF1, 0xCB, 0x45, 0x9C, 0xF0, 0x91, 0x59, 0x6A, 0x38, 0x7D,
|
||||
0x3F, 0x52, 0x61, 0x4A, 0x7A, 0x17, 0x4D, 0x2E, 0xA1, 0x15, 0xF2, 0xF2, 0xF9, 0x32, 0x2A, 0x4D,
|
||||
0x45, 0x71, 0xBC, 0x44, 0x52, 0xA9, 0x3A, 0x88, 0xE7, 0x65, 0x3C, 0x9D, 0x56, 0x01, 0x92, 0x52,
|
||||
0x30, 0x1F, 0x1B, 0x59, 0xBA, 0xB8, 0x64, 0x49, 0x12, 0x27, 0x97, 0x73, 0x50, 0x31, 0x98, 0x87,
|
||||
0x93, 0x8A, 0xC6, 0x49, 0xEC, 0x33, 0x58, 0x1A, 0x09, 0x25, 0x10, 0x1F, 0x99, 0xC3, 0xE9, 0x32,
|
||||
0xA2, 0x77, 0xB1, 0xA0, 0xBC, 0x37, 0x63, 0x0F, 0x1C, 0xF6, 0x3D, 0x6E, 0x14, 0x26, 0x96, 0x4C,
|
||||
0x94, 0xAA, 0xF3, 0x51, 0x69, 0x8B, 0xCD, 0x74, 0x01, 0x7A, 0x59, 0x87, 0x8D, 0x6A, 0x7A, 0x44,
|
||||
0xFB, 0x0D, 0x46, 0xD6, 0x10, 0x58, 0x5D, 0x67, 0x0D, 0x9C, 0xE7, 0x4B, 0xE2, 0xD7, 0x84, 0xCB,
|
||||
0xAF, 0x29, 0x39, 0xD1, 0xFF, 0x54, 0xCB, 0x94, 0xAA, 0xB5, 0x6A, 0x43, 0x65, 0x7F, 0xE0, 0xF1,
|
||||
0xA7, 0x7A, 0xDC, 0x22, 0xB5, 0x55, 0x87, 0xC1, 0x11, 0x6F, 0x86, 0x2C, 0xBA, 0xE2, 0x10, 0xA8,
|
||||
0x0F, 0xB5, 0x3D, 0xAB, 0xEC, 0x59, 0x44, 0x6D, 0xD4, 0xA3, 0xC6, 0x88, 0x7F, 0x0A, 0x3E, 0x37,
|
||||
0x10, 0xE3, 0x86, 0xFA, 0xD0, 0xA2, 0x6A, 0x43, 0x0C, 0xCE, 0x0D, 0x94, 0xC4, 0x42, 0x0F, 0x1A,
|
||||
0x8D, 0x61, 0xC2, 0xF8, 0x32, 0x89, 0x14, 0x42, 0xA1, 0x6C, 0x4D, 0xD4, 0x75, 0x4E, 0x48, 0x50,
|
||||
0x8E, 0x74, 0x76, 0x89, 0x49, 0x1B, 0x10, 0x53, 0x8C, 0x57, 0xB3, 0xE0, 0xA3, 0xD6, 0xB6, 0x6B,
|
||||
0x10, 0x34, 0xD4, 0x2C, 0xB8, 0x40, 0x98, 0x51, 0xEB, 0xD4, 0x30, 0xCC, 0xC0, 0x8B, 0xF0, 0x85,
|
||||
0x35, 0xBB, 0x5D, 0xCB, 0x62, 0x91, 0x5A, 0xB7, 0x26, 0x15, 0xA3, 0x86, 0xE1, 0xC3, 0x20, 0x61,
|
||||
0xFE, 0xB0, 0xA6, 0xB4, 0x00, 0x91, 0x6D, 0x70, 0xBB, 0x01, 0xD8, 0x55, 0x00, 0x14, 0x7E, 0x6C,
|
||||
0x81, 0x70, 0x4C, 0x01, 0xA2, 0xB7, 0x07, 0xA3, 0x4E, 0xB7, 0x00, 0x08, 0x36, 0xFC, 0x61, 0x9C,
|
||||
0xEC, 0x2A, 0x40, 0xCB, 0x14, 0x10, 0xF1, 0x2A, 0x41, 0xF6, 0xCA, 0x20, 0xDD, 0x47, 0x43, 0xB4,
|
||||
0xFB, 0x3B, 0x21, 0x38, 0x8F, 0xD9, 0xA5, 0x2B, 0x40, 0xB8, 0x8E, 0x40, 0xAA, 0x2B, 0x70, 0xEA,
|
||||
0xE6, 0x00, 0x4B, 0xF0, 0x3A, 0x8F, 0x02, 0xD8, 0xF9, 0xDE, 0x00, 0x7B, 0xDF, 0x03, 0xA0, 0x08,
|
||||
0x29, 0x11, 0x6C, 0x11, 0x65, 0xD7, 0x6C, 0xB7, 0x24, 0x12, 0x70, 0x9F, 0x45, 0xD9, 0x35, 0xAA,
|
||||
0x0A, 0xD8, 0x58, 0x2D, 0xEE, 0xD5, 0x8E, 0xBF, 0xA7, 0x88, 0xFE, 0xBD, 0xF2, 0xF9, 0x7D, 0x85,
|
||||
0xF3, 0x3B, 0x4B, 0xE6, 0xDF, 0x2B, 0x96, 0xDF, 0x57, 0x26, 0xBF, 0xAF, 0x40, 0xFE, 0x43, 0xA4,
|
||||
0xB1, 0x30, 0x8D, 0xF8, 0xFA, 0x7C, 0xD3, 0x32, 0x3E, 0x56, 0x50, 0x6D, 0x17, 0xFE, 0xAF, 0xE5,
|
||||
0x55, 0xE2, 0xDA, 0xDB, 0xAE, 0xEE, 0x28, 0x6F, 0x6C, 0xBD, 0xA7, 0xBC, 0xE9, 0xEA, 0x96, 0x43,
|
||||
0xDF, 0xA6, 0xF2, 0xC6, 0x92, 0x97, 0x9E, 0x6E, 0x59, 0xE2, 0xD2, 0x16, 0x8D, 0x1D, 0xB8, 0x98,
|
||||
0x74, 0xE9, 0xEB, 0x56, 0x97, 0xBE, 0xFB, 0xD4, 0x64, 0xC3, 0x70, 0x5B, 0x5E, 0x6C, 0xDD, 0xEA,
|
||||
0xD1, 0xA5, 0x47, 0x6D, 0x1D, 0x84, 0xDA, 0x51, 0xBE, 0xE2, 0x06, 0x93, 0xF8, 0x0B, 0xEC, 0x90,
|
||||
0x8A, 0x31, 0x35, 0x91, 0xCF, 0xD5, 0x68, 0xA7, 0x3B, 0x37, 0x2A, 0xC2, 0xF6, 0x4B, 0xCC, 0x80,
|
||||
0x99, 0x76, 0x5F, 0xF2, 0x47, 0x8D, 0x11, 0x43, 0x37, 0xA4, 0x97, 0x3D, 0x90, 0x4A, 0x89, 0x8D,
|
||||
0xAE, 0x82, 0x07, 0x52, 0xB5, 0x02, 0x06, 0x04, 0x02, 0x78, 0xAE, 0xE9, 0x9C, 0x63, 0x8D, 0x3E,
|
||||
0xAD, 0x33, 0x9D, 0x67, 0x44, 0xAB, 0xB3, 0x11, 0x6B, 0xF2, 0xF8, 0x4D, 0xBC, 0x62, 0xC9, 0xAF,
|
||||
0x10, 0x06, 0xD7, 0x35, 0xED, 0xA8, 0xCE, 0x47, 0x7C, 0xA3, 0xED, 0xA5, 0x61, 0x0D, 0xF8, 0x11,
|
||||
0x7B, 0x69, 0x0D, 0xCC, 0x02, 0x2A, 0x9E, 0x21, 0xF0, 0xF8, 0x64, 0x46, 0x89, 0x04, 0xA5, 0x45,
|
||||
0x88, 0x21, 0xFA, 0x7C, 0x8E, 0xC1, 0x02, 0x46, 0x1C, 0xC3, 0x60, 0x0A, 0xD0, 0xD4, 0x72, 0xB9,
|
||||
0xE3, 0x9C, 0x46, 0x0E, 0x14, 0xB5, 0xC1, 0x9A, 0x62, 0x96, 0xCE, 0x1B, 0xD5, 0x21, 0xDF, 0xCA,
|
||||
0x0F, 0x17, 0x31, 0xF7, 0x42, 0x45, 0x9C, 0xC4, 0xA2, 0x49, 0x1C, 0x1B, 0x0E, 0xCF, 0x81, 0x78,
|
||||
0xD6, 0x2F, 0x4F, 0x59, 0xC2, 0xF3, 0xE1, 0x19, 0xEF, 0x26, 0x93, 0xE5, 0x42, 0xFC, 0x06, 0x46,
|
||||
0x51, 0x69, 0xE8, 0xD1, 0x9C, 0x41, 0x48, 0xA8, 0xCC, 0x83, 0x08, 0x84, 0xA6, 0x46, 0x89, 0x87,
|
||||
0xB0, 0x0B, 0x33, 0x90, 0xAA, 0x51, 0xAD, 0x0F, 0x77, 0x22, 0xE0, 0xAB, 0xE1, 0x0A, 0x71, 0x3E,
|
||||
0x1F, 0xA2, 0x02, 0x60, 0x22, 0x4D, 0x96, 0x89, 0xF5, 0x66, 0xFF, 0x4F, 0xAA, 0xEE, 0xC7, 0x93,
|
||||
0xE5, 0x1C, 0xF8, 0xD8, 0xBC, 0x62, 0xFC, 0x24, 0x64, 0x78, 0xFB, 0xCB, 0xDD, 0x29, 0xF0, 0x4F,
|
||||
0xA6, 0x97, 0x5A, 0x33, 0x88, 0x22, 0x96, 0xFC, 0x7E, 0xF1, 0xF6, 0xCD, 0x88, 0xEB, 0x44, 0x4E,
|
||||
0x60, 0xF5, 0x0F, 0xE5, 0xD0, 0x49, 0x50, 0x3A, 0xA8, 0x44, 0x53, 0x10, 0xC5, 0xF0, 0x53, 0x3C,
|
||||
0xDD, 0xF4, 0x6E, 0x8A, 0x31, 0x95, 0x5E, 0xE9, 0x13, 0x41, 0x8F, 0xAD, 0x0D, 0x69, 0x77, 0x3C,
|
||||
0xC9, 0x34, 0xAD, 0x7C, 0x5A, 0xF9, 0x40, 0xE8, 0x53, 0x89, 0xDA, 0x60, 0x08, 0xAB, 0x9B, 0x10,
|
||||
0xC6, 0x58, 0x8F, 0x88, 0x82, 0x30, 0xC0, 0x82, 0x50, 0xA8, 0xA4, 0xB1, 0x45, 0x44, 0x04, 0xA2,
|
||||
0x19, 0x62, 0x74, 0x0E, 0xF6, 0xA1, 0x76, 0x0C, 0xF9, 0x2E, 0xE6, 0x5F, 0x59, 0x7A, 0xA5, 0xAE,
|
||||
0x59, 0x93, 0x64, 0xAB, 0x09, 0xF8, 0xF1, 0x7A, 0x26, 0x77, 0x65, 0xF1, 0xDD, 0x92, 0xEC, 0x26,
|
||||
0x26, 0x8E, 0x3A, 0xA7, 0x8B, 0xB6, 0xD6, 0x90, 0x6A, 0xA3, 0x32, 0x89, 0x5E, 0xBC, 0xA8, 0x83,
|
||||
0x5C, 0x9A, 0x1A, 0xC5, 0x98, 0x48, 0xC0, 0x10, 0x83, 0xDD, 0x18, 0xA2, 0xD7, 0xF8, 0x28, 0x5B,
|
||||
0x4D, 0x50, 0x6A, 0x18, 0x37, 0x1A, 0x9A, 0x6A, 0x58, 0x40, 0x75, 0x01, 0xBD, 0x2E, 0xFB, 0x3F,
|
||||
0xC5, 0x9F, 0x9B, 0x58, 0xA0, 0xD1, 0x00, 0x16, 0x91, 0xF2, 0xE2, 0xEC, 0x58, 0x8A, 0x0C, 0xA5,
|
||||
0xA0, 0x60, 0x84, 0xCA, 0x96, 0xA7, 0x64, 0x90, 0x76, 0x18, 0x21, 0xE5, 0x58, 0x81, 0xFF, 0x0A,
|
||||
0x4B, 0x64, 0xE9, 0x36, 0x58, 0x12, 0xDD, 0xB6, 0xD0, 0x1E, 0xD9, 0x78, 0xDF, 0x11, 0x97, 0x2E,
|
||||
0xB5, 0x59, 0x68, 0x43, 0xDE, 0x58, 0xB6, 0xFC, 0xB6, 0x14, 0x1C, 0x66, 0x3D, 0xC2, 0xAA, 0xE0,
|
||||
0xE1, 0x44, 0xE5, 0xD6, 0x12, 0xBE, 0xF8, 0x0E, 0xAF, 0x35, 0xE5, 0xD6, 0x86, 0x0B, 0x58, 0xDF,
|
||||
0x3B, 0x9B, 0xFC, 0xE0, 0x06, 0x04, 0xF1, 0x68, 0x48, 0xF4, 0xAD, 0x5A, 0x2B, 0xDB, 0xA4, 0x2C,
|
||||
0x35, 0x51, 0x1C, 0x0B, 0x0D, 0xB5, 0xA3, 0x8B, 0x57, 0x32, 0x7E, 0xFE, 0x53, 0x06, 0xD0, 0x7F,
|
||||
0x66, 0x56, 0x5C, 0xCD, 0xCF, 0x7F, 0x2D, 0x6E, 0x87, 0xF4, 0xDE, 0x41, 0xBC, 0x3F, 0xAC, 0x81,
|
||||
0x46, 0x90, 0x09, 0x2B, 0x91, 0x14, 0x39, 0xD6, 0xA8, 0xE5, 0x2F, 0x0C, 0xC5, 0xFB, 0xC2, 0x4A,
|
||||
0xAA, 0x56, 0xAA, 0x5E, 0xD7, 0x70, 0xE5, 0x8D, 0xC9, 0xBA, 0x4A, 0x07, 0xFB, 0x9A, 0xF8, 0x83,
|
||||
0xC9, 0xE6, 0xD5, 0x57, 0xE0, 0xDB, 0xC6, 0x80, 0x17, 0x2F, 0x4A, 0x23, 0xB6, 0xBB, 0xBF, 0x7D,
|
||||
0x43, 0xD1, 0xB0, 0x34, 0xB9, 0x4B, 0x91, 0xB6, 0x61, 0xC5, 0xFD, 0xE2, 0xD5, 0x31, 0xEC, 0x51,
|
||||
0xEC, 0x76, 0x43, 0x06, 0xE4, 0x58, 0xEA, 0x2D, 0x75, 0xCD, 0xBC, 0xF4, 0xDD, 0x2A, 0x7A, 0x9F,
|
||||
0xC4, 0x0B, 0x96, 0xF0, 0xBB, 0xBA, 0x4A, 0x45, 0x2C, 0xED, 0x65, 0x1D, 0x84, 0xCD, 0x14, 0x53,
|
||||
0x76, 0xC0, 0xC3, 0x41, 0x25, 0x78, 0xDA, 0x20, 0x1B, 0x28, 0xE1, 0xCB, 0xC7, 0x4C, 0xA0, 0xCC,
|
||||
0x9F, 0x6A, 0x65, 0xEA, 0xFC, 0x29, 0xAB, 0xA2, 0x7F, 0xAA, 0x25, 0x15, 0x7E, 0x05, 0xBE, 0x83,
|
||||
0xB3, 0x3A, 0x59, 0xA8, 0x2A, 0xA1, 0xD5, 0x9A, 0x86, 0xF9, 0x09, 0x02, 0x2D, 0x27, 0x19, 0x95,
|
||||
0xBD, 0xE3, 0xD2, 0x42, 0x17, 0xF1, 0x0B, 0xA5, 0xBC, 0x50, 0x9B, 0x04, 0x34, 0x26, 0xD9, 0xD4,
|
||||
0x98, 0x44, 0x6A, 0xCC, 0x68, 0x53, 0x63, 0x92, 0x6D, 0x8D, 0x79, 0x96, 0xAE, 0x94, 0xF4, 0xA4,
|
||||
0x2F, 0x9C, 0x72, 0x1F, 0xDD, 0x2B, 0xB8, 0x66, 0xF0, 0xC2, 0xF2, 0xAB, 0x8D, 0x8E, 0xD6, 0x45,
|
||||
0xBD, 0x70, 0x51, 0x93, 0xDA, 0xA4, 0x4E, 0x36, 0x0D, 0xC5, 0x0B, 0xBA, 0x67, 0x54, 0x2E, 0x87,
|
||||
0xE6, 0xB7, 0xE9, 0xDB, 0x16, 0xBA, 0x05, 0xFD, 0x8F, 0xF3, 0xCE, 0x85, 0xF0, 0x13, 0x43, 0xAA,
|
||||
0xD9, 0xA3, 0x92, 0x8B, 0x69, 0x1E, 0xCB, 0x6C, 0x1F, 0x7D, 0x2D, 0xDB, 0xD9, 0x92, 0x83, 0x2F,
|
||||
0x31, 0x2A, 0x29, 0x18, 0x35, 0xCC, 0x38, 0xB5, 0xD1, 0x57, 0x08, 0x4B, 0x2E, 0x25, 0x25, 0x71,
|
||||
0x29, 0x0D, 0xDE, 0x2D, 0x8E, 0x7A, 0x59, 0x1A, 0x9F, 0x2E, 0x55, 0xFB, 0xF1, 0x7D, 0x96, 0x60,
|
||||
0xED, 0xF5, 0x88, 0x59, 0x0D, 0xB8, 0xEC, 0x12, 0xC3, 0x97, 0xAA, 0x3A, 0x50, 0xB1, 0x28, 0x7C,
|
||||
0xC0, 0x95, 0xE2, 0xFB, 0xA9, 0xF2, 0xA4, 0xE8, 0xA5, 0x8A, 0x6F, 0x93, 0x94, 0x8A, 0x95, 0x50,
|
||||
0x82, 0x14, 0x5C, 0x7C, 0x9A, 0x96, 0x2B, 0x81, 0xA2, 0xA0, 0xA1, 0x04, 0x1C, 0xD6, 0xC8, 0x4C,
|
||||
0x56, 0xAD, 0x55, 0x93, 0x24, 0x51, 0x6A, 0x1B, 0x85, 0xA0, 0xDA, 0xF1, 0x6F, 0xB1, 0xC2, 0x63,
|
||||
0x45, 0x1C, 0x61, 0x0C, 0x8A, 0xF3, 0x14, 0xDE, 0xF1, 0x01, 0xEC, 0x8A, 0x32, 0x74, 0xD5, 0xD7,
|
||||
0xEF, 0x9D, 0x40, 0x75, 0xFB, 0xCA, 0x7E, 0x64, 0x95, 0xA5, 0x08, 0xC8, 0xA4, 0xBA, 0x63, 0x98,
|
||||
0x18, 0x47, 0xD3, 0x20, 0x99, 0xD7, 0xD5, 0x5F, 0xC5, 0x8D, 0xE2, 0x63, 0x17, 0x8E, 0x89, 0xA7,
|
||||
0x28, 0xD3, 0x22, 0x2E, 0x02, 0x7D, 0xAC, 0x04, 0x8F, 0x34, 0x08, 0x48, 0xCA, 0xB6, 0x60, 0x66,
|
||||
0xD1, 0xE7, 0x21, 0xB0, 0x30, 0x06, 0xE4, 0x38, 0x4E, 0xEE, 0x0E, 0xC0, 0x86, 0x31, 0x55, 0xF0,
|
||||
0xA5, 0xD7, 0x3B, 0xB2, 0x5A, 0xB4, 0x48, 0xC0, 0xA5, 0xF3, 0xBA, 0xFA, 0x2A, 0x03, 0x47, 0xB5,
|
||||
0x60, 0x88, 0x7F, 0x40, 0x48, 0xA2, 0x65, 0x18, 0x82, 0xDD, 0xDE, 0x00, 0x3D, 0xC9, 0x60, 0xA0,
|
||||
0xD0, 0x83, 0xE1, 0x99, 0x43, 0xC0, 0x5A, 0xAC, 0x50, 0x1E, 0x4A, 0x91, 0x03, 0x2E, 0x13, 0x8D,
|
||||
0x22, 0xB6, 0x52, 0xFE, 0xEB, 0xED, 0x9B, 0xDF, 0x39, 0x5F, 0x9C, 0xB1, 0xEB, 0x25, 0x04, 0xB0,
|
||||
0x7A, 0x30, 0x52, 0x5B, 0x24, 0xCC, 0x2F, 0xC5, 0x6F, 0x0A, 0x46, 0xB0, 0x8D, 0xFD, 0x72, 0xB9,
|
||||
0x29, 0x5E, 0x48, 0x93, 0x08, 0x30, 0x06, 0x49, 0x6A, 0x36, 0x9B, 0x58, 0xE2, 0x81, 0x70, 0x13,
|
||||
0xC1, 0x89, 0x52, 0x76, 0x83, 0x45, 0x58, 0x33, 0xFB, 0x70, 0x76, 0x5A, 0xE7, 0x9A, 0xE8, 0x14,
|
||||
0x35, 0xBE, 0x52, 0x47, 0x39, 0xBA, 0xD3, 0xA3, 0x66, 0x1C, 0xC1, 0xC6, 0xFC, 0x3B, 0x0C, 0x09,
|
||||
0xD9, 0x04, 0xC2, 0xB3, 0x2B, 0x36, 0xCA, 0x63, 0x20, 0xED, 0xDE, 0x1D, 0x8D, 0xA2, 0x26, 0x0D,
|
||||
0xC0, 0x88, 0x1A, 0x68, 0x52, 0xB7, 0x4D, 0x13, 0xDB, 0x44, 0x08, 0xF9, 0x72, 0x47, 0x74, 0xFE,
|
||||
0x1F, 0xE7, 0xEF, 0xFE, 0x00, 0xBF, 0x9B, 0x40, 0x48, 0x8F, 0x53, 0xD3, 0x45, 0x1C, 0xA5, 0xEC,
|
||||
0x82, 0xDD, 0x72, 0x4D, 0x1B, 0xB8, 0xA6, 0x55, 0x9A, 0x8C, 0xE7, 0x06, 0x06, 0x75, 0x60, 0x77,
|
||||
0x1A, 0x87, 0xAC, 0x19, 0xC6, 0x57, 0xF5, 0xAC, 0x4B, 0xD3, 0x5F, 0x7F, 0x3C, 0xC1, 0x12, 0x20,
|
||||
0x10, 0x59, 0x5B, 0x23, 0x96, 0x0B, 0x16, 0xD5, 0xD5, 0xDF, 0x4E, 0x2E, 0x60, 0xCB, 0x3A, 0x44,
|
||||
0x56, 0xD0, 0x94, 0x02, 0xC9, 0xEB, 0x1B, 0x2C, 0x10, 0x6F, 0x05, 0x24, 0x8F, 0x0F, 0x6A, 0x45,
|
||||
0xF6, 0xA2, 0x42, 0x13, 0x96, 0x05, 0x53, 0x08, 0x13, 0x9D, 0xB5, 0x70, 0x32, 0xDA, 0xFD, 0xDE,
|
||||
0xC9, 0xD5, 0x17, 0xB1, 0x5A, 0xB3, 0xF2, 0xCE, 0x35, 0x63, 0xCB, 0x7E, 0xFD, 0x4A, 0xAE, 0x60,
|
||||
0x0E, 0x59, 0xEC, 0x66, 0xF1, 0xC6, 0x40, 0xBE, 0x3D, 0x08, 0x99, 0x3A, 0x14, 0x89, 0x0D, 0xCA,
|
||||
0xCD, 0xEB, 0x38, 0x99, 0xBF, 0xF2, 0xB8, 0x37, 0xE4, 0x4D, 0x6F, 0xB1, 0xC0, 0xCD, 0x0A, 0xED,
|
||||
0x2C, 0xC7, 0xDB, 0x85, 0xAB, 0x8C, 0xC0, 0x55, 0x46, 0x47, 0x19, 0xFE, 0xC3, 0x08, 0x9C, 0xA4,
|
||||
0x0C, 0xDD, 0xD9, 0xA7, 0xE8, 0x33, 0x58, 0xE1, 0x72, 0x4E, 0x17, 0x48, 0x2B, 0x7A, 0xAE, 0x16,
|
||||
0xC0, 0x43, 0x3D, 0x10, 0xEE, 0x53, 0x2F, 0xD6, 0x2B, 0x5E, 0xDF, 0x00, 0xD5, 0xB7, 0x01, 0x68,
|
||||
0xEB, 0x7A, 0xA5, 0xAC, 0xBC, 0x43, 0xDC, 0x35, 0xC9, 0xB9, 0xF7, 0xEF, 0xCE, 0x2F, 0x30, 0xBB,
|
||||
0x20, 0x78, 0x2A, 0x71, 0xB0, 0x32, 0xB5, 0x29, 0x2F, 0xE0, 0xC3, 0x4E, 0x6E, 0x60, 0x95, 0x37,
|
||||
0x60, 0xB3, 0x18, 0x08, 0x3D, 0x52, 0x4C, 0xBC, 0x7F, 0x51, 0xF5, 0x22, 0x34, 0xD7, 0xEE, 0x81,
|
||||
0x5D, 0xD9, 0x5E, 0x41, 0xED, 0x16, 0x4B, 0x2A, 0x6A, 0x66, 0x69, 0x21, 0xCA, 0x92, 0xE7, 0x33,
|
||||
0xBF, 0x25, 0xD3, 0xB8, 0x7F, 0x83, 0x8C, 0x6A, 0xBF, 0x8A, 0x09, 0x96, 0x08, 0x36, 0x1E, 0xB0,
|
||||
0x8C, 0x0F, 0xF1, 0x5D, 0x41, 0xC6, 0x37, 0x30, 0xA5, 0x7D, 0x8D, 0xBF, 0x00, 0xA9, 0x9B, 0x1A,
|
||||
0xE6, 0x60, 0xEB, 0xB5, 0x4E, 0xC1, 0x5E, 0x51, 0xC1, 0xB6, 0x36, 0x36, 0x1E, 0x47, 0xD4, 0x5C,
|
||||
0xD2, 0x39, 0xD2, 0xB0, 0x51, 0x75, 0x94, 0xD4, 0x98, 0xFA, 0xF3, 0xD0, 0x7B, 0x86, 0x40, 0xCA,
|
||||
0x77, 0x58, 0x87, 0x5D, 0x4B, 0xA1, 0x44, 0x72, 0x39, 0x18, 0x7F, 0xD0, 0x20, 0x54, 0x37, 0x55,
|
||||
0x35, 0x0E, 0xDA, 0x40, 0x34, 0x4B, 0xBD, 0x5F, 0x6F, 0xD0, 0x89, 0xD4, 0x9D, 0x6B, 0xEB, 0x42,
|
||||
0xE1, 0x21, 0xE0, 0xF9, 0x63, 0x39, 0x1F, 0x83, 0x90, 0x90, 0xC5, 0x2D, 0x34, 0x01, 0xD9, 0x2E,
|
||||
0x63, 0x43, 0xB0, 0xE6, 0x52, 0x4C, 0x8E, 0xF8, 0x50, 0x03, 0x63, 0x6B, 0xAA, 0x8D, 0x28, 0x2B,
|
||||
0x8A, 0x47, 0x05, 0x2C, 0xD8, 0xDD, 0xFB, 0x5F, 0xD1, 0xD5, 0xE7, 0xD6, 0x03, 0x65, 0x19, 0xD4,
|
||||
0x8F, 0xE5, 0x15, 0x74, 0xA4, 0xC0, 0x6B, 0x70, 0x0D, 0x7F, 0x63, 0xE8, 0x0F, 0x1B, 0xAA, 0xA1,
|
||||
0x36, 0x4A, 0x18, 0x60, 0xEF, 0xDB, 0x38, 0xE2, 0x33, 0xE8, 0x82, 0x18, 0x6F, 0x67, 0x3F, 0x82,
|
||||
0x83, 0x20, 0x65, 0x77, 0xE7, 0xEF, 0x31, 0x64, 0xC8, 0x7B, 0x7B, 0xDF, 0x06, 0xD1, 0x92, 0xB3,
|
||||
0xFD, 0xFD, 0xE7, 0x0C, 0xCC, 0xA8, 0x2F, 0xFA, 0x8B, 0x5D, 0xFD, 0x1E, 0xF8, 0xEC, 0xE7, 0x30,
|
||||
0x44, 0x85, 0xC9, 0xDF, 0xC4, 0x98, 0xDB, 0x6F, 0x62, 0x5E, 0xBC, 0xC8, 0xDF, 0x13, 0x35, 0x27,
|
||||
0x61, 0x8C, 0xB5, 0x98, 0x82, 0xEF, 0xF4, 0x13, 0x89, 0x51, 0xF5, 0xB1, 0xA1, 0xD6, 0x81, 0xCF,
|
||||
0x13, 0xE1, 0x8A, 0x98, 0xAF, 0x3D, 0x21, 0x3E, 0x62, 0xFB, 0x87, 0x96, 0x8E, 0xEC, 0x64, 0x12,
|
||||
0x29, 0x7F, 0x40, 0x32, 0x52, 0xF1, 0x17, 0x24, 0x07, 0x56, 0xC9, 0x5F, 0x78, 0xEF, 0x9E, 0x58,
|
||||
0x50, 0x24, 0x77, 0x2B, 0xF7, 0x19, 0x6D, 0xD4, 0xD7, 0x1E, 0x88, 0xAA, 0x8F, 0xB1, 0x55, 0xF1,
|
||||
0x26, 0x0B, 0x7F, 0xEC, 0x01, 0x39, 0xC0, 0xEB, 0x8F, 0x3F, 0x94, 0x0B, 0x5C, 0xAF, 0x3F, 0xBE,
|
||||
0xFB, 0x52, 0x3F, 0xE0, 0x1A, 0xF6, 0x39, 0x6B, 0x76, 0x48, 0x01, 0x0F, 0xED, 0x9A, 0x7E, 0xE7,
|
||||
0xF8, 0xAC, 0x6D, 0x8B, 0x99, 0x05, 0xEA, 0xA7, 0x51, 0xC0, 0x3F, 0x9C, 0x4A, 0xE1, 0x8E, 0x77,
|
||||
0xC5, 0x25, 0xA0, 0xBD, 0xAD, 0x89, 0x88, 0x60, 0x5E, 0xCA, 0x2B, 0xEA, 0x65, 0x25, 0x74, 0x50,
|
||||
0x3F, 0x41, 0xF8, 0xD9, 0x33, 0xCD, 0xCF, 0x10, 0x25, 0xED, 0x79, 0xFF, 0xB7, 0xFD, 0x26, 0xB1,
|
||||
0xEC, 0xDF, 0x55, 0xC4, 0x43, 0xF9, 0x70, 0x0A, 0x79, 0x41, 0xFC, 0x40, 0xE4, 0x01, 0x16, 0x1E,
|
||||
0x82, 0x8F, 0xB8, 0x14, 0x7C, 0x64, 0x9A, 0x29, 0x0A, 0x7E, 0x64, 0x25, 0xE3, 0x2C, 0x5E, 0x90,
|
||||
0x96, 0xDF, 0xD4, 0x23, 0x9A, 0x52, 0xD8, 0x95, 0xEC, 0xDD, 0xDF, 0x8F, 0x80, 0x32, 0xCC, 0x2A,
|
||||
0x23, 0x53, 0x1D, 0x88, 0x21, 0x85, 0xB4, 0x14, 0x8E, 0x06, 0x8B, 0x98, 0x43, 0x16, 0xA6, 0x2C,
|
||||
0xB7, 0x2A, 0x01, 0xF8, 0xD7, 0xE0, 0x28, 0x1B, 0x32, 0x0C, 0x32, 0xFF, 0x1A, 0x8E, 0xA2, 0x4F,
|
||||
0xC1, 0xE7, 0x6C, 0x95, 0x01, 0xAC, 0x02, 0x5C, 0x51, 0x6E, 0x58, 0x92, 0xC2, 0x36, 0x20, 0x47,
|
||||
0x0D, 0x3F, 0x99, 0x9F, 0x65, 0xB8, 0x08, 0xC1, 0xD3, 0x01, 0x4E, 0x66, 0xA7, 0xE8, 0x2A, 0x02,
|
||||
0x74, 0xA3, 0x36, 0xC2, 0x4F, 0xD6, 0x67, 0xC8, 0x6B, 0x1A, 0x9A, 0xAE, 0x56, 0x69, 0xBB, 0x05,
|
||||
0x1C, 0x64, 0x9D, 0xDA, 0xAC, 0xAC, 0xED, 0x65, 0x7D, 0x9B, 0x1B, 0x7B, 0x31, 0x28, 0x4E, 0x6E,
|
||||
0x1E, 0x70, 0x07, 0x10, 0xAE, 0x6D, 0x82, 0x34, 0x9F, 0x0B, 0x32, 0x0B, 0x79, 0x34, 0xB9, 0xBB,
|
||||
0x4D, 0x51, 0xDA, 0xDA, 0xDF, 0xC6, 0x2B, 0xE9, 0xF0, 0x93, 0x9D, 0x75, 0x56, 0x5F, 0x4E, 0x87,
|
||||
0x9F, 0x9C, 0xBC, 0x83, 0x2C, 0xDC, 0x39, 0x75, 0xD5, 0xB3, 0x85, 0x66, 0x71, 0xCA, 0x29, 0xDA,
|
||||
0xDF, 0xCB, 0x1D, 0x61, 0xF3, 0x4A, 0x94, 0xA4, 0x99, 0x6B, 0x90, 0x47, 0xFE, 0xB2, 0xBE, 0xB7,
|
||||
0x12, 0xAE, 0x0B, 0xFB, 0xA0, 0x0D, 0x50, 0x7A, 0xD6, 0x6B, 0x14, 0x1F, 0x85, 0x02, 0xDE, 0xB8,
|
||||
0x1A, 0xF0, 0x62, 0xB7, 0x5E, 0x15, 0x44, 0x29, 0xC5, 0xDA, 0x10, 0x22, 0xEC, 0xDC, 0x44, 0x41,
|
||||
0xEC, 0x10, 0x97, 0x03, 0x5F, 0x46, 0x61, 0x53, 0xBC, 0x15, 0xF8, 0x56, 0xF6, 0x78, 0xFF, 0x28,
|
||||
0xEB, 0x5E, 0xCF, 0x9B, 0x46, 0xBB, 0xF5, 0xF8, 0x25, 0x5A, 0x88, 0x8F, 0x6C, 0x2C, 0xC1, 0xAA,
|
||||
0x2B, 0x3C, 0x88, 0xAF, 0x36, 0xCA, 0x74, 0x6E, 0x80, 0xB4, 0x37, 0xAA, 0x3C, 0x69, 0xA8, 0xAD,
|
||||
0x15, 0x04, 0x6A, 0x9F, 0x54, 0x2F, 0xF1, 0x97, 0x01, 0x88, 0xE3, 0x67, 0x6D, 0xF0, 0x2C, 0x40,
|
||||
0x15, 0x10, 0x5A, 0x73, 0x1C, 0x44, 0x90, 0x02, 0x5F, 0xD0, 0x79, 0x09, 0x2F, 0x49, 0xBC, 0xBB,
|
||||
0xF1, 0x72, 0x3A, 0x65, 0x90, 0x89, 0x15, 0x3B, 0x8B, 0x23, 0xA4, 0xD4, 0xA8, 0x1C, 0x23, 0x56,
|
||||
0x0C, 0xCF, 0xC7, 0x73, 0x55, 0xDB, 0x75, 0x06, 0xC1, 0x5C, 0x57, 0x80, 0x10, 0x81, 0x2A, 0x50,
|
||||
0x76, 0x9E, 0x5B, 0xA8, 0x80, 0xFE, 0x1F, 0x82, 0x2D, 0x1D, 0xEC, 0xB7, 0x6F, 0x29, 0xE3, 0x18,
|
||||
0x48, 0xC4, 0x4B, 0x5E, 0x2F, 0x71, 0x46, 0x77, 0x98, 0xA3, 0x55, 0xD7, 0xA2, 0x33, 0x0E, 0x07,
|
||||
0x31, 0xC6, 0x24, 0xB6, 0x32, 0x25, 0x3B, 0x25, 0xB1, 0x11, 0x0A, 0xFF, 0x00, 0x41, 0x80, 0x0F,
|
||||
0xA9, 0x82, 0x12, 0x44, 0xB0, 0x64, 0x34, 0x61, 0x90, 0x28, 0xFF, 0x8C, 0x74, 0xFA, 0x85, 0xE8,
|
||||
0xA4, 0x15, 0x81, 0x31, 0x8E, 0x2A, 0x1B, 0x2B, 0xFB, 0x68, 0x94, 0x9D, 0x54, 0x40, 0x0B, 0x22,
|
||||
0x63, 0xFC, 0xD3, 0x57, 0xA0, 0x1B, 0x1C, 0x74, 0x03, 0xDA, 0xB2, 0xD3, 0x1C, 0x1C, 0xED, 0x50,
|
||||
0xD5, 0x96, 0xBF, 0x52, 0x30, 0x0E, 0xA1, 0x6E, 0x0D, 0xCD, 0x13, 0xFD, 0xAB, 0x1D, 0xA5, 0xB9,
|
||||
0xB2, 0xEF, 0x07, 0x9A, 0xFB, 0xE2, 0x45, 0xEE, 0x71, 0x4F, 0xB9, 0x92, 0x32, 0x36, 0x4F, 0x95,
|
||||
0xBB, 0x78, 0xA9, 0xE0, 0x09, 0x34, 0x19, 0x49, 0x28, 0x53, 0xC8, 0xCA, 0x15, 0x2F, 0x8A, 0xC1,
|
||||
0xC2, 0x80, 0x65, 0x8D, 0x85, 0x28, 0xEA, 0x38, 0x2C, 0xA1, 0x71, 0x51, 0xBC, 0x52, 0xCA, 0x81,
|
||||
0x07, 0x90, 0x5D, 0x3D, 0x39, 0x3B, 0x7B, 0x77, 0x56, 0xA0, 0xBB, 0x7D, 0xA2, 0x84, 0x83, 0x9D,
|
||||
0xD8, 0x3C, 0x53, 0xB2, 0xB5, 0x19, 0x1C, 0xD4, 0x50, 0x15, 0xEC, 0x1C, 0xE0, 0x79, 0x0A, 0xEB,
|
||||
0xB3, 0xA6, 0x57, 0xC2, 0xD1, 0x8D, 0x68, 0xD4, 0x1B, 0xE3, 0xCB, 0x02, 0x4C, 0x4E, 0x4B, 0x01,
|
||||
0x69, 0x65, 0xC2, 0x3D, 0xA6, 0x93, 0x95, 0x55, 0xC1, 0x1C, 0x87, 0x0C, 0x66, 0xC9, 0xB3, 0x6A,
|
||||
0xCA, 0x94, 0x02, 0x8F, 0x3A, 0x38, 0xD8, 0xCA, 0xB0, 0x06, 0x58, 0x59, 0xA5, 0xDC, 0x28, 0x37,
|
||||
0xA2, 0x6D, 0x1D, 0x8C, 0xD1, 0x06, 0xBB, 0x00, 0x42, 0xC8, 0xA2, 0x83, 0xD1, 0x29, 0x52, 0x8E,
|
||||
0xFF, 0x07, 0x59, 0xC3, 0x5E, 0x9B, 0xAA, 0x0D, 0x32, 0x31, 0x00, 0x67, 0x8D, 0x48, 0x95, 0x0D,
|
||||
0x5F, 0xF9, 0x24, 0xE0, 0xBD, 0x70, 0xEE, 0xD5, 0xC2, 0xD1, 0xC6, 0x11, 0x47, 0xE5, 0xA5, 0xAA,
|
||||
0x3D, 0x5C, 0x1C, 0x58, 0x3D, 0xBF, 0x34, 0x80, 0x07, 0x15, 0x9F, 0x47, 0x96, 0xD2, 0xA2, 0xCF,
|
||||
0x98, 0x8E, 0xE7, 0x10, 0x0F, 0xB9, 0xD8, 0x87, 0x66, 0x96, 0x22, 0x8E, 0x67, 0x46, 0xAA, 0x0F,
|
||||
0xC4, 0xE7, 0xE2, 0x5C, 0xE5, 0xC1, 0xC2, 0x47, 0x16, 0x68, 0x55, 0x8B, 0x1F, 0xFA, 0x83, 0x75,
|
||||
0x0D, 0x15, 0xBC, 0xC9, 0xD3, 0xEA, 0x19, 0xA2, 0x9C, 0x51, 0xCC, 0xD3, 0xD6, 0xE5, 0x03, 0x66,
|
||||
0xFA, 0x93, 0x6B, 0x1A, 0x4B, 0x12, 0x2E, 0xD8, 0xDF, 0x8E, 0xB2, 0xC6, 0x3F, 0xA7, 0x9E, 0x41,
|
||||
0xB4, 0x7E, 0xB0, 0xA2, 0xB1, 0xC5, 0xFB, 0xC7, 0xD5, 0x32, 0x1E, 0x2A, 0x5F, 0x64, 0xB1, 0xF9,
|
||||
0xCE, 0x0A, 0xC6, 0xC3, 0xDA, 0xF3, 0x58, 0x13, 0xB4, 0x85, 0xFD, 0x81, 0xD3, 0xB6, 0x07, 0xC0,
|
||||
0x64, 0xE7, 0x6E, 0x9F, 0xA7, 0x3E, 0xCF, 0xD7, 0xF8, 0xCA, 0xCC, 0xEC, 0xAC, 0xF9, 0xE2, 0xF6,
|
||||
0x91, 0x36, 0xA2, 0x28, 0xB7, 0xFC, 0x83, 0x2C, 0xCA, 0xF6, 0xF4, 0x12, 0x8E, 0x43, 0x61, 0x42,
|
||||
0x1F, 0x57, 0xD7, 0x41, 0xF3, 0xA9, 0x5A, 0xF4, 0x22, 0x54, 0x88, 0xC0, 0x8B, 0x17, 0xAA, 0x5B,
|
||||
0x7D, 0x2C, 0xF7, 0x7E, 0xFB, 0x56, 0x75, 0xBB, 0xAA, 0x0D, 0xBE, 0x3D, 0xEB, 0xD4, 0xAA, 0xFE,
|
||||
0x6E, 0x82, 0xA1, 0x8E, 0xF0, 0x78, 0x94, 0xAC, 0x29, 0xB8, 0x94, 0x53, 0x1E, 0x2F, 0x14, 0x88,
|
||||
0x8C, 0xC8, 0x83, 0xFA, 0x82, 0x67, 0x2F, 0x5C, 0x53, 0xE7, 0x23, 0x08, 0xE0, 0xE8, 0xF7, 0xAA,
|
||||
0x40, 0xE4, 0x7A, 0x49, 0xAE, 0xA3, 0xC6, 0xE8, 0x40, 0xFA, 0x54, 0xD5, 0xBA, 0xE8, 0x31, 0x02,
|
||||
0x57, 0xC8, 0xAE, 0x6B, 0x19, 0x91, 0xEE, 0x9A, 0x47, 0x11, 0x04, 0x30, 0x13, 0x10, 0xDD, 0x24,
|
||||
0x5F, 0x9F, 0x63, 0x60, 0xB9, 0xE1, 0x00, 0x21, 0x26, 0xB4, 0x30, 0x98, 0xA4, 0x2D, 0x57, 0x6B,
|
||||
0x66, 0x3B, 0x9A, 0xF6, 0x95, 0xD1, 0x0A, 0x37, 0x8A, 0x59, 0xC9, 0x7E, 0xB5, 0x2C, 0x4E, 0x98,
|
||||
0x3F, 0x58, 0x64, 0xA0, 0x13, 0xCA, 0xCF, 0x82, 0x44, 0xEE, 0x63, 0xF8, 0x80, 0x67, 0x0E, 0x0B,
|
||||
0xFB, 0x90, 0xA7, 0x65, 0x07, 0x46, 0x2F, 0xB6, 0x46, 0xE3, 0xD9, 0x5F, 0x42, 0xE2, 0xE5, 0x87,
|
||||
0xF3, 0x93, 0xB3, 0x72, 0x65, 0x03, 0x6D, 0x2E, 0xA0, 0x10, 0x71, 0xB0, 0xC5, 0x0D, 0xF5, 0xC5,
|
||||
0xFB, 0x9F, 0xCF, 0xCF, 0x3F, 0xBE, 0x3B, 0x7B, 0xB5, 0x7B, 0x08, 0xC7, 0x21, 0xE7, 0x1F, 0x7E,
|
||||
0x79, 0x7B, 0x7A, 0x31, 0xBA, 0xC3, 0x6A, 0x76, 0xB0, 0xC3, 0x49, 0x0C, 0x83, 0x87, 0xDF, 0xAC,
|
||||
0x04, 0x5B, 0x6F, 0x56, 0x7E, 0x80, 0x36, 0x99, 0x2B, 0x52, 0xE6, 0x18, 0x54, 0x33, 0xC7, 0x3C,
|
||||
0x35, 0xAC, 0xC4, 0xAE, 0x41, 0x9E, 0x3E, 0x0E, 0xB2, 0x32, 0x0F, 0xB0, 0x3D, 0x28, 0xA7, 0x8E,
|
||||
0x11, 0xB9, 0xA6, 0x20, 0x4B, 0x1D, 0x57, 0x41, 0xE4, 0xC7, 0xAB, 0x1D, 0xB6, 0x3B, 0x9B, 0xBF,
|
||||
0x1E, 0x1E, 0xB5, 0xE4, 0x31, 0xF2, 0xA3, 0x96, 0xFC, 0xF5, 0x0A, 0xFD, 0xA3, 0xD1, 0xFF, 0x0B,
|
||||
0xB4, 0xEA, 0x2E, 0x52, 0x3B, 0x5A, 0x00, 0x00
|
||||
};
|
||||
#endif //__nofile_h
|
411
Grbl_Esp32-master/Grbl_Esp32/notifications_service.cpp
Normal file
411
Grbl_Esp32-master/Grbl_Esp32/notifications_service.cpp
Normal file
@ -0,0 +1,411 @@
|
||||
/*
|
||||
notifications_service.cpp - notifications service functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
//Inspired by following sources
|
||||
//* Line :
|
||||
// - https://github.com/TridentTD/TridentTD_LineNotify
|
||||
// - https://notify-bot.line.me/doc/en/
|
||||
//* Pushover:
|
||||
// - https://github.com/ArduinoHannover/Pushover
|
||||
// - https://pushover.net/api
|
||||
//* Email:
|
||||
// - https://github.com/CosmicBoris/ESP8266SMTP
|
||||
// - https://www.electronicshub.org/send-an-email-using-esp8266/
|
||||
|
||||
#include "config.h"
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
#include "grbl.h"
|
||||
#include "commands.h"
|
||||
#include "notifications_service.h"
|
||||
#include <WiFiClientSecure.h>
|
||||
#include <Preferences.h>
|
||||
#include <base64.h>
|
||||
#include "wificonfig.h"
|
||||
|
||||
#define PUSHOVERTIMEOUT 5000
|
||||
#define PUSHOVERSERVER "api.pushover.net"
|
||||
#define PUSHOVERPORT 443
|
||||
|
||||
#define LINETIMEOUT 5000
|
||||
#define LINESERVER "notify-api.line.me"
|
||||
#define LINEPORT 443
|
||||
|
||||
#define EMAILTIMEOUT 5000
|
||||
|
||||
NotificationsService notificationsservice;
|
||||
|
||||
bool Wait4Answer(WiFiClientSecure & client, const char * linetrigger, const char * expected_answer, uint32_t timeout)
|
||||
{
|
||||
if(client.connected()) {
|
||||
String answer;
|
||||
uint32_t starttimeout = millis();
|
||||
while (client.connected() && ((millis() -starttimeout) < timeout)) {
|
||||
answer = client.readStringUntil('\n');
|
||||
log_d("Answer: %s", answer.c_str());
|
||||
if ((answer.indexOf(linetrigger) != -1) || (strlen(linetrigger) == 0)) {
|
||||
break;
|
||||
}
|
||||
COMMANDS::wait(10);
|
||||
}
|
||||
if (strlen(expected_answer) == 0) {
|
||||
log_d("Answer ignored as requested");
|
||||
return true;
|
||||
}
|
||||
if(answer.indexOf(expected_answer) == -1) {
|
||||
log_d("Did not got answer!");
|
||||
return false;
|
||||
} else {
|
||||
log_d("Got expected answer");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
log_d("Failed to send message");
|
||||
return false;
|
||||
}
|
||||
|
||||
NotificationsService::NotificationsService()
|
||||
{
|
||||
_started = false;
|
||||
_notificationType = 0;
|
||||
_token1 = "";
|
||||
_token1 = "";
|
||||
_settings = "";
|
||||
}
|
||||
NotificationsService::~NotificationsService()
|
||||
{
|
||||
end();
|
||||
}
|
||||
|
||||
bool NotificationsService::started()
|
||||
{
|
||||
return _started;
|
||||
}
|
||||
|
||||
const char * NotificationsService::getTypeString()
|
||||
{
|
||||
switch(_notificationType) {
|
||||
case ESP_PUSHOVER_NOTIFICATION:
|
||||
return "Pushover";
|
||||
case ESP_EMAIL_NOTIFICATION:
|
||||
return "Email";
|
||||
case ESP_LINE_NOTIFICATION:
|
||||
return "Line";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "None";
|
||||
}
|
||||
|
||||
bool NotificationsService::sendMSG(const char * title, const char * message)
|
||||
{
|
||||
if (!_started) return false;
|
||||
if (!((strlen(title) == 0) && (strlen(message) == 0))) {
|
||||
switch(_notificationType) {
|
||||
case ESP_PUSHOVER_NOTIFICATION:
|
||||
return sendPushoverMSG(title,message);
|
||||
break;
|
||||
case ESP_EMAIL_NOTIFICATION:
|
||||
return sendEmailMSG(title,message);
|
||||
break;
|
||||
case ESP_LINE_NOTIFICATION :
|
||||
return sendLineMSG(title,message);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//Messages are currently limited to 1024 4-byte UTF-8 characters
|
||||
//but we do not do any check
|
||||
bool NotificationsService::sendPushoverMSG(const char * title, const char * message)
|
||||
{
|
||||
String data;
|
||||
String postcmd;
|
||||
bool res;
|
||||
WiFiClientSecure Notificationclient;
|
||||
if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
|
||||
log_d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
|
||||
return false;
|
||||
}
|
||||
//build data for post
|
||||
data = "user=";
|
||||
data += _token1;
|
||||
data += "&token=";
|
||||
data += _token2;;
|
||||
data +="&title=";
|
||||
data += title;
|
||||
data += "&message=";
|
||||
data += message;
|
||||
data += "&device=";
|
||||
data += wifi_config.Hostname();
|
||||
//build post query
|
||||
postcmd = "POST /1/messages.json HTTP/1.1\r\nHost: api.pushover.net\r\nConnection: close\r\nCache-Control: no-cache\r\nUser-Agent: ESP3D\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nContent-Length: ";
|
||||
postcmd += data.length();
|
||||
postcmd +="\r\n\r\n";
|
||||
postcmd +=data;
|
||||
log_d("Query: %s", postcmd.c_str());
|
||||
//send query
|
||||
Notificationclient.print(postcmd);
|
||||
res = Wait4Answer(Notificationclient, "{", "\"status\":1", PUSHOVERTIMEOUT);
|
||||
Notificationclient.stop();
|
||||
return res;
|
||||
}
|
||||
bool NotificationsService::sendEmailMSG(const char * title, const char * message)
|
||||
{
|
||||
WiFiClientSecure Notificationclient;
|
||||
log_d("Connect to server");
|
||||
if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
|
||||
log_d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
|
||||
return false;
|
||||
}
|
||||
//Check answer of connection
|
||||
if(!Wait4Answer(Notificationclient, "220", "220", EMAILTIMEOUT)) {
|
||||
log_d("Connection failed!");
|
||||
return false;
|
||||
}
|
||||
//Do HELO
|
||||
log_d("HELO");
|
||||
Notificationclient.print("HELO friend\r\n");
|
||||
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
||||
log_d("HELO failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("AUTH LOGIN");
|
||||
//Request AUthentication
|
||||
Notificationclient.print("AUTH LOGIN\r\n");
|
||||
if(!Wait4Answer(Notificationclient, "334", "334", EMAILTIMEOUT)) {
|
||||
log_d("AUTH LOGIN failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("Send LOGIN");
|
||||
//sent Login
|
||||
Notificationclient.printf("%s\r\n",_token1.c_str());
|
||||
if(!Wait4Answer(Notificationclient, "334", "334", EMAILTIMEOUT)) {
|
||||
log_d("Sent login failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("Send PASSWORD");
|
||||
//Send password
|
||||
Notificationclient.printf("%s\r\n",_token2.c_str());
|
||||
if(!Wait4Answer(Notificationclient, "235", "235", EMAILTIMEOUT)) {
|
||||
log_d("Sent password failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("MAIL FROM");
|
||||
//Send From
|
||||
Notificationclient.printf("MAIL FROM: <%s>\r\n",_settings.c_str());
|
||||
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
||||
log_d("MAIL FROM failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("RCPT TO");
|
||||
//Send To
|
||||
Notificationclient.printf("RCPT TO: <%s>\r\n",_settings.c_str());
|
||||
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
||||
log_d("RCPT TO failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("DATA");
|
||||
//Send Data
|
||||
Notificationclient.print("DATA\r\n");
|
||||
if(!Wait4Answer(Notificationclient, "354", "354", EMAILTIMEOUT)) {
|
||||
log_d("Preparing DATA failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("Send message");
|
||||
//Send message
|
||||
Notificationclient.printf("From:ESP3D<%s>\r\n",_settings.c_str());
|
||||
Notificationclient.printf("To: <%s>\r\n",_settings.c_str());
|
||||
Notificationclient.printf("Subject: %s\r\n\r\n",title);
|
||||
Notificationclient.println(message);
|
||||
|
||||
log_d("Send final dot");
|
||||
//Send Final dot
|
||||
Notificationclient.print(".\r\n");
|
||||
if(!Wait4Answer(Notificationclient, "250", "250", EMAILTIMEOUT)) {
|
||||
log_d("Sending final dot failed!");
|
||||
return false;
|
||||
}
|
||||
log_d("QUIT");
|
||||
//Quit
|
||||
Notificationclient.print("QUIT\r\n");
|
||||
if(!Wait4Answer(Notificationclient, "221", "221", EMAILTIMEOUT)) {
|
||||
log_d("QUIT failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
Notificationclient.stop();
|
||||
return true;
|
||||
}
|
||||
bool NotificationsService::sendLineMSG(const char * title, const char * message)
|
||||
{
|
||||
String data;
|
||||
String postcmd;
|
||||
bool res;
|
||||
WiFiClientSecure Notificationclient;
|
||||
(void)title;
|
||||
if (!Notificationclient.connect(_serveraddress.c_str(), _port)) {
|
||||
log_d("Error connecting server %s:%d", _serveraddress.c_str(), _port);
|
||||
return false;
|
||||
}
|
||||
//build data for post
|
||||
data = "message=";
|
||||
data += message;
|
||||
//build post query
|
||||
postcmd = "POST /api/notify HTTP/1.1\r\nHost: notify-api.line.me\r\nConnection: close\r\nCache-Control: no-cache\r\nUser-Agent: ESP3D\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nContent-Type: application/x-www-form-urlencoded\r\n";
|
||||
postcmd +="Authorization: Bearer ";
|
||||
postcmd += _token1 + "\r\n";
|
||||
postcmd += "Content-Length: ";
|
||||
postcmd += data.length();
|
||||
postcmd +="\r\n\r\n";
|
||||
postcmd +=data;
|
||||
log_d("Query: %s", postcmd.c_str());
|
||||
//send query
|
||||
Notificationclient.print(postcmd);
|
||||
res = Wait4Answer(Notificationclient, "{", "\"status\":200", LINETIMEOUT);
|
||||
Notificationclient.stop();
|
||||
return res;
|
||||
}
|
||||
//Email#serveraddress:port
|
||||
bool NotificationsService::getPortFromSettings()
|
||||
{
|
||||
Preferences prefs;
|
||||
String defV = DEFAULT_TOKEN;
|
||||
prefs.begin(NAMESPACE, true);
|
||||
String tmp = prefs.getString(NOTIFICATION_TS, defV);
|
||||
prefs.end();
|
||||
int pos = tmp.lastIndexOf(':');
|
||||
if (pos == -1) {
|
||||
return false;
|
||||
}
|
||||
_port= tmp.substring(pos+1).toInt();
|
||||
log_d("port : %d", _port);
|
||||
if (_port > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//Email#serveraddress:port
|
||||
bool NotificationsService::getServerAddressFromSettings()
|
||||
{
|
||||
Preferences prefs;
|
||||
String defV = DEFAULT_TOKEN;
|
||||
prefs.begin(NAMESPACE, true);
|
||||
String tmp = prefs.getString(NOTIFICATION_TS, defV);
|
||||
prefs.end();
|
||||
int pos1 = tmp.indexOf('#');
|
||||
int pos2 = tmp.lastIndexOf(':');
|
||||
if ((pos1 == -1) || (pos2 == -1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//TODO add a check for valid email ?
|
||||
_serveraddress = tmp.substring(pos1+1, pos2);
|
||||
log_d("server : %s", _serveraddress.c_str());
|
||||
return true;
|
||||
}
|
||||
//Email#serveraddress:port
|
||||
bool NotificationsService::getEmailFromSettings()
|
||||
{
|
||||
Preferences prefs;
|
||||
String defV = DEFAULT_TOKEN;
|
||||
prefs.begin(NAMESPACE, true);
|
||||
String tmp = prefs.getString(NOTIFICATION_TS, defV);
|
||||
prefs.end();
|
||||
int pos = tmp.indexOf('#');
|
||||
if (pos == -1) {
|
||||
return false;
|
||||
}
|
||||
_settings = tmp.substring(0, pos);
|
||||
log_d("email : %s", _settings.c_str());
|
||||
//TODO add a check for valid email ?
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool NotificationsService::begin()
|
||||
{
|
||||
bool res = true;
|
||||
end();
|
||||
Preferences prefs;
|
||||
String defV = DEFAULT_TOKEN;
|
||||
prefs.begin(NAMESPACE, true);
|
||||
_notificationType = prefs.getChar(NOTIFICATION_TYPE, DEFAULT_NOTIFICATION_TYPE);
|
||||
switch(_notificationType) {
|
||||
case 0: //no notification = no error but no start
|
||||
return true;
|
||||
case ESP_PUSHOVER_NOTIFICATION:
|
||||
_token1 = prefs.getString(NOTIFICATION_T1, defV);
|
||||
_token2 = prefs.getString(NOTIFICATION_T2, defV);
|
||||
_port = PUSHOVERPORT;
|
||||
_serveraddress = PUSHOVERSERVER;
|
||||
break;
|
||||
case ESP_LINE_NOTIFICATION:
|
||||
_token1 = prefs.getString(NOTIFICATION_T1, defV);
|
||||
_port = LINEPORT;
|
||||
_serveraddress = LINESERVER;
|
||||
break;
|
||||
case ESP_EMAIL_NOTIFICATION:
|
||||
_token1 = base64::encode(prefs.getString(NOTIFICATION_T1, defV));
|
||||
_token2 = base64::encode(prefs.getString(NOTIFICATION_T2, defV));
|
||||
//log_d("%s",Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN1));
|
||||
//log_d("%s",Settings_ESP3D::read_string(ESP_NOTIFICATION_TOKEN2));
|
||||
if(!getEmailFromSettings() || !getPortFromSettings()|| !getServerAddressFromSettings()) {
|
||||
prefs.end();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
prefs.end();
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
prefs.end();
|
||||
if(WiFi.getMode() != WIFI_STA){
|
||||
res = false;
|
||||
}
|
||||
if (!res) {
|
||||
end();
|
||||
}
|
||||
_started = res;
|
||||
return _started;
|
||||
}
|
||||
void NotificationsService::end()
|
||||
{
|
||||
if(!_started) {
|
||||
return;
|
||||
}
|
||||
_started = false;
|
||||
_notificationType = 0;
|
||||
_token1 = "";
|
||||
_token1 = "";
|
||||
_settings = "";
|
||||
_serveraddress = "";
|
||||
_port = 0;
|
||||
}
|
||||
|
||||
void NotificationsService::handle()
|
||||
{
|
||||
if (_started) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif //ENABLE_NOTIFICATIONS
|
57
Grbl_Esp32-master/Grbl_Esp32/notifications_service.h
Normal file
57
Grbl_Esp32-master/Grbl_Esp32/notifications_service.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
notifications_service.h - notifications service functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _NOTIFICATIONS_SERVICE_H
|
||||
#define _NOTIFICATIONS_SERVICE_H
|
||||
|
||||
|
||||
class NotificationsService
|
||||
{
|
||||
public:
|
||||
NotificationsService();
|
||||
~NotificationsService();
|
||||
bool begin();
|
||||
void end();
|
||||
void handle();
|
||||
bool sendMSG(const char * title, const char * message);
|
||||
const char * getTypeString();
|
||||
bool started();
|
||||
private:
|
||||
bool _started;
|
||||
uint8_t _notificationType;
|
||||
String _token1;
|
||||
String _token2;
|
||||
String _settings;
|
||||
String _serveraddress;
|
||||
uint16_t _port;
|
||||
bool sendPushoverMSG(const char * title, const char * message);
|
||||
bool sendEmailMSG(const char * title, const char * message);
|
||||
bool sendLineMSG(const char * title, const char * message);
|
||||
bool getPortFromSettings();
|
||||
bool getServerAddressFromSettings();
|
||||
bool getEmailFromSettings();
|
||||
};
|
||||
|
||||
extern NotificationsService notificationsservice;
|
||||
|
||||
#endif //_NOTIFICATIONS_SERVICE_H
|
||||
|
189
Grbl_Esp32-master/Grbl_Esp32/nuts_bolts.cpp
Normal file
189
Grbl_Esp32-master/Grbl_Esp32/nuts_bolts.cpp
Normal file
@ -0,0 +1,189 @@
|
||||
/*
|
||||
nuts_bolts.c - Shared functions
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#define MAX_INT_DIGITS 8 // Maximum number of digits in int32 (and float)
|
||||
|
||||
// Extracts a floating point value from a string. The following code is based loosely on
|
||||
// the avr-libc strtod() function by Michael Stumpf and Dmitry Xmelkov and many freely
|
||||
// available conversion method examples, but has been highly optimized for Grbl. For known
|
||||
// CNC applications, the typical decimal value is expected to be in the range of E0 to E-4.
|
||||
// Scientific notation is officially not supported by g-code, and the 'E' character may
|
||||
// be a g-code word on some CNC systems. So, 'E' notation will not be recognized.
|
||||
// NOTE: Thanks to Radu-Eosif Mihailescu for identifying the issues with using strtod().
|
||||
uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr)
|
||||
{
|
||||
char *ptr = line + *char_counter;
|
||||
unsigned char c;
|
||||
|
||||
// Grab first character and increment pointer. No spaces assumed in line.
|
||||
c = *ptr++;
|
||||
|
||||
// Capture initial positive/minus character
|
||||
bool isnegative = false;
|
||||
if (c == '-') {
|
||||
isnegative = true;
|
||||
c = *ptr++;
|
||||
} else if (c == '+') {
|
||||
c = *ptr++;
|
||||
}
|
||||
|
||||
// Extract number into fast integer. Track decimal in terms of exponent value.
|
||||
uint32_t intval = 0;
|
||||
int8_t exp = 0;
|
||||
uint8_t ndigit = 0;
|
||||
bool isdecimal = false;
|
||||
while(1) {
|
||||
c -= '0';
|
||||
if (c <= 9) {
|
||||
ndigit++;
|
||||
if (ndigit <= MAX_INT_DIGITS) {
|
||||
if (isdecimal) { exp--; }
|
||||
intval = (((intval << 2) + intval) << 1) + c; // intval*10 + c
|
||||
} else {
|
||||
if (!(isdecimal)) { exp++; } // Drop overflow digits
|
||||
}
|
||||
} else if (c == (('.'-'0') & 0xff) && !(isdecimal)) {
|
||||
isdecimal = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
c = *ptr++;
|
||||
}
|
||||
|
||||
// Return if no digits have been read.
|
||||
if (!ndigit) { return(false); };
|
||||
|
||||
// Convert integer into floating point.
|
||||
float fval;
|
||||
fval = (float)intval;
|
||||
|
||||
// Apply decimal. Should perform no more than two floating point multiplications for the
|
||||
// expected range of E0 to E-4.
|
||||
if (fval != 0) {
|
||||
while (exp <= -2) {
|
||||
fval *= 0.01;
|
||||
exp += 2;
|
||||
}
|
||||
if (exp < 0) {
|
||||
fval *= 0.1;
|
||||
} else if (exp > 0) {
|
||||
do {
|
||||
fval *= 10.0;
|
||||
} while (--exp > 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Assign floating point value with correct sign.
|
||||
if (isnegative) {
|
||||
*float_ptr = -fval;
|
||||
} else {
|
||||
*float_ptr = fval;
|
||||
}
|
||||
|
||||
*char_counter = ptr - line - 1; // Set char_counter to next statement
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
void delay_ms(uint16_t ms)
|
||||
{
|
||||
delay(ms);
|
||||
}
|
||||
|
||||
// Non-blocking delay function used for general operation and suspend features.
|
||||
void delay_sec(float seconds, uint8_t mode)
|
||||
{
|
||||
uint16_t i = ceil(1000/DWELL_TIME_STEP*seconds);
|
||||
while (i-- > 0) {
|
||||
if (sys.abort) { return; }
|
||||
if (mode == DELAY_MODE_DWELL) {
|
||||
protocol_execute_realtime();
|
||||
} else { // DELAY_MODE_SYS_SUSPEND
|
||||
// Execute rt_system() only to avoid nesting suspend loops.
|
||||
protocol_exec_rt_system();
|
||||
if (sys.suspend & SUSPEND_RESTART_RETRACT) { return; } // Bail, if safety door reopens.
|
||||
}
|
||||
delay(DWELL_TIME_STEP); // Delay DWELL_TIME_STEP increment
|
||||
}
|
||||
}
|
||||
|
||||
// Simple hypotenuse computation function.
|
||||
float hypot_f(float x, float y) { return(sqrt(x*x + y*y)); }
|
||||
|
||||
|
||||
float convert_delta_vector_to_unit_vector(float *vector)
|
||||
{
|
||||
uint8_t idx;
|
||||
float magnitude = 0.0;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (vector[idx] != 0.0) {
|
||||
magnitude += vector[idx]*vector[idx];
|
||||
}
|
||||
}
|
||||
magnitude = sqrt(magnitude);
|
||||
float inv_magnitude = 1.0/magnitude;
|
||||
for (idx=0; idx<N_AXIS; idx++) { vector[idx] *= inv_magnitude; }
|
||||
return(magnitude);
|
||||
}
|
||||
|
||||
float limit_value_by_axis_maximum(float *max_value, float *unit_vec)
|
||||
{
|
||||
uint8_t idx;
|
||||
float limit_value = SOME_LARGE_VALUE;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
if (unit_vec[idx] != 0) { // Avoid divide by zero.
|
||||
limit_value = MIN(limit_value,fabs(max_value[idx]/unit_vec[idx]));
|
||||
}
|
||||
}
|
||||
return(limit_value);
|
||||
}
|
||||
|
||||
float map_float(float x, float in_min, float in_max, float out_min, float out_max) // DrawBot_Badge
|
||||
{
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
float constrain_float(float in, float min, float max) // DrawBot_Badge
|
||||
{
|
||||
if (in < min)
|
||||
return min;
|
||||
|
||||
if (in > max)
|
||||
return max;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
float mapConstrain(float x, float in_min, float in_max, float out_min, float out_max)
|
||||
{
|
||||
x = constrain_float(x, in_min, in_max);
|
||||
return map_float(x, in_min, in_max, out_min, out_max);
|
||||
}
|
||||
|
||||
|
99
Grbl_Esp32-master/Grbl_Esp32/nuts_bolts.h
Normal file
99
Grbl_Esp32-master/Grbl_Esp32/nuts_bolts.h
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
nuts_bolts.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef nuts_bolts_h
|
||||
#define nuts_bolts_h
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define false 0
|
||||
#define true 1
|
||||
|
||||
#define SOME_LARGE_VALUE 1.0E+38
|
||||
|
||||
// Axis array index values. Must start with 0 and be continuous.
|
||||
// Note: You set the number of axes used by changing N_AXIS.
|
||||
// Be sure to define pins or servos in cpu_map.h
|
||||
#define X_AXIS 0 // Axis indexing value.
|
||||
#define Y_AXIS 1
|
||||
#define Z_AXIS 2
|
||||
#define A_AXIS 3
|
||||
#define B_AXIS 4
|
||||
#define C_AXIS 5
|
||||
|
||||
|
||||
// CoreXY motor assignments. DO NOT ALTER.
|
||||
// NOTE: If the A and B motor axis bindings are changed, this effects the CoreXY equations.
|
||||
#define A_MOTOR X_AXIS // Must be X_AXIS
|
||||
#define B_MOTOR Y_AXIS // Must be Y_AXIS
|
||||
|
||||
|
||||
|
||||
// Conversions
|
||||
#define MM_PER_INCH (25.40)
|
||||
#define INCH_PER_MM (0.0393701)
|
||||
#define TICKS_PER_MICROSECOND (F_STEPPER_TIMER/1000000) // Different from AVR version
|
||||
|
||||
#define DELAY_MODE_DWELL 0
|
||||
#define DELAY_MODE_SYS_SUSPEND 1
|
||||
|
||||
// Useful macros
|
||||
#define clear_vector(a) memset(a, 0, sizeof(a))
|
||||
#define clear_vector_float(a) memset(a, 0.0, sizeof(float)*N_AXIS)
|
||||
// #define clear_vector_long(a) memset(a, 0.0, sizeof(long)*N_AXIS)
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b)) // changed to upper case to remove conflicts with other libraries
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b)) // changed to upper case to remove conflicts with other libraries
|
||||
#define isequal_position_vector(a,b) !(memcmp(a, b, sizeof(float)*N_AXIS))
|
||||
|
||||
// Bit field and masking macros
|
||||
//Arduino.h:104:0: note: this is the location of the previous definition
|
||||
//#define bit(n) (1 << n)
|
||||
#define bit_true(x,mask) (x) |= (mask)
|
||||
#define bit_false(x,mask) (x) &= ~(mask)
|
||||
#define bit_istrue(x,mask) ((x & mask) != 0)
|
||||
#define bit_isfalse(x,mask) ((x & mask) == 0)
|
||||
|
||||
// Read a floating point value from a string. Line points to the input buffer, char_counter
|
||||
// is the indexer pointing to the current character of the line, while float_ptr is
|
||||
// a pointer to the result variable. Returns true when it succeeds
|
||||
uint8_t read_float(char *line, uint8_t *char_counter, float *float_ptr);
|
||||
|
||||
// Non-blocking delay function used for general operation and suspend features.
|
||||
void delay_sec(float seconds, uint8_t mode);
|
||||
|
||||
// Delays variable-defined milliseconds. Compiler compatibility fix for _delay_ms().
|
||||
void delay_ms(uint16_t ms);
|
||||
|
||||
// Computes hypotenuse, avoiding avr-gcc's bloated version and the extra error checking.
|
||||
float hypot_f(float x, float y);
|
||||
|
||||
float convert_delta_vector_to_unit_vector(float *vector);
|
||||
float limit_value_by_axis_maximum(float *max_value, float *unit_vec);
|
||||
|
||||
float mapConstrain(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
float map_float(float x, float in_min, float in_max, float out_min, float out_max);
|
||||
float constrain_float(float in, float min, float max);
|
||||
|
||||
template <class T> void swap ( T& a, T& b )
|
||||
{
|
||||
T c(a); a=b; b=c;
|
||||
}
|
||||
|
||||
#endif
|
511
Grbl_Esp32-master/Grbl_Esp32/planner.cpp
Normal file
511
Grbl_Esp32-master/Grbl_Esp32/planner.cpp
Normal file
@ -0,0 +1,511 @@
|
||||
/*
|
||||
planner.c - buffers movement commands and manages the acceleration profile plan
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
Copyright (c) 2011 Jens Geisler
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include <stdlib.h> // PSoc Required for labs
|
||||
|
||||
|
||||
static plan_block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instructions
|
||||
static uint8_t block_buffer_tail; // Index of the block to process now
|
||||
static uint8_t block_buffer_head; // Index of the next block to be pushed
|
||||
static uint8_t next_buffer_head; // Index of the next buffer head
|
||||
static uint8_t block_buffer_planned; // Index of the optimally planned block
|
||||
|
||||
// Define planner variables
|
||||
typedef struct {
|
||||
int32_t position[N_AXIS]; // The planner position of the tool in absolute steps. Kept separate
|
||||
// from g-code position for movements requiring multiple line motions,
|
||||
// i.e. arcs, canned cycles, and backlash compensation.
|
||||
float previous_unit_vec[N_AXIS]; // Unit vector of previous path line segment
|
||||
float previous_nominal_speed; // Nominal speed of previous path line segment
|
||||
} planner_t;
|
||||
static planner_t pl;
|
||||
|
||||
|
||||
// Returns the index of the next block in the ring buffer. Also called by stepper segment buffer.
|
||||
uint8_t plan_next_block_index(uint8_t block_index)
|
||||
{
|
||||
block_index++;
|
||||
if (block_index == BLOCK_BUFFER_SIZE) { block_index = 0; }
|
||||
return(block_index);
|
||||
}
|
||||
|
||||
|
||||
// Returns the index of the previous block in the ring buffer
|
||||
static uint8_t plan_prev_block_index(uint8_t block_index)
|
||||
{
|
||||
if (block_index == 0) { block_index = BLOCK_BUFFER_SIZE; }
|
||||
block_index--;
|
||||
return(block_index);
|
||||
}
|
||||
|
||||
|
||||
/* PLANNER SPEED DEFINITION
|
||||
+--------+ <- current->nominal_speed
|
||||
/ \
|
||||
current->entry_speed -> + \
|
||||
| + <- next->entry_speed (aka exit speed)
|
||||
+-------------+
|
||||
time -->
|
||||
|
||||
Recalculates the motion plan according to the following basic guidelines:
|
||||
|
||||
1. Go over every feasible block sequentially in reverse order and calculate the junction speeds
|
||||
(i.e. current->entry_speed) such that:
|
||||
a. No junction speed exceeds the pre-computed maximum junction speed limit or nominal speeds of
|
||||
neighboring blocks.
|
||||
b. A block entry speed cannot exceed one reverse-computed from its exit speed (next->entry_speed)
|
||||
with a maximum allowable deceleration over the block travel distance.
|
||||
c. The last (or newest appended) block is planned from a complete stop (an exit speed of zero).
|
||||
2. Go over every block in chronological (forward) order and dial down junction speed values if
|
||||
a. The exit speed exceeds the one forward-computed from its entry speed with the maximum allowable
|
||||
acceleration over the block travel distance.
|
||||
|
||||
When these stages are complete, the planner will have maximized the velocity profiles throughout the all
|
||||
of the planner blocks, where every block is operating at its maximum allowable acceleration limits. In
|
||||
other words, for all of the blocks in the planner, the plan is optimal and no further speed improvements
|
||||
are possible. If a new block is added to the buffer, the plan is recomputed according to the said
|
||||
guidelines for a new optimal plan.
|
||||
|
||||
To increase computational efficiency of these guidelines, a set of planner block pointers have been
|
||||
created to indicate stop-compute points for when the planner guidelines cannot logically make any further
|
||||
changes or improvements to the plan when in normal operation and new blocks are streamed and added to the
|
||||
planner buffer. For example, if a subset of sequential blocks in the planner have been planned and are
|
||||
bracketed by junction velocities at their maximums (or by the first planner block as well), no new block
|
||||
added to the planner buffer will alter the velocity profiles within them. So we no longer have to compute
|
||||
them. Or, if a set of sequential blocks from the first block in the planner (or a optimal stop-compute
|
||||
point) are all accelerating, they are all optimal and can not be altered by a new block added to the
|
||||
planner buffer, as this will only further increase the plan speed to chronological blocks until a maximum
|
||||
junction velocity is reached. However, if the operational conditions of the plan changes from infrequently
|
||||
used feed holds or feedrate overrides, the stop-compute pointers will be reset and the entire plan is
|
||||
recomputed as stated in the general guidelines.
|
||||
|
||||
Planner buffer index mapping:
|
||||
- block_buffer_tail: Points to the beginning of the planner buffer. First to be executed or being executed.
|
||||
- block_buffer_head: Points to the buffer block after the last block in the buffer. Used to indicate whether
|
||||
the buffer is full or empty. As described for standard ring buffers, this block is always empty.
|
||||
- next_buffer_head: Points to next planner buffer block after the buffer head block. When equal to the
|
||||
buffer tail, this indicates the buffer is full.
|
||||
- block_buffer_planned: Points to the first buffer block after the last optimally planned block for normal
|
||||
streaming operating conditions. Use for planning optimizations by avoiding recomputing parts of the
|
||||
planner buffer that don't change with the addition of a new block, as describe above. In addition,
|
||||
this block can never be less than block_buffer_tail and will always be pushed forward and maintain
|
||||
this requirement when encountered by the plan_discard_current_block() routine during a cycle.
|
||||
|
||||
NOTE: Since the planner only computes on what's in the planner buffer, some motions with lots of short
|
||||
line segments, like G2/3 arcs or complex curves, may seem to move slow. This is because there simply isn't
|
||||
enough combined distance traveled in the entire buffer to accelerate up to the nominal speed and then
|
||||
decelerate to a complete stop at the end of the buffer, as stated by the guidelines. If this happens and
|
||||
becomes an annoyance, there are a few simple solutions: (1) Maximize the machine acceleration. The planner
|
||||
will be able to compute higher velocity profiles within the same combined distance. (2) Maximize line
|
||||
motion(s) distance per block to a desired tolerance. The more combined distance the planner has to use,
|
||||
the faster it can go. (3) Maximize the planner buffer size. This also will increase the combined distance
|
||||
for the planner to compute over. It also increases the number of computations the planner has to perform
|
||||
to compute an optimal plan, so select carefully. The Arduino 328p memory is already maxed out, but future
|
||||
ARM versions should have enough memory and speed for look-ahead blocks numbering up to a hundred or more.
|
||||
|
||||
*/
|
||||
static void planner_recalculate()
|
||||
{
|
||||
// Initialize block index to the last block in the planner buffer.
|
||||
uint8_t block_index = plan_prev_block_index(block_buffer_head);
|
||||
|
||||
// Bail. Can't do anything with one only one plan-able block.
|
||||
if (block_index == block_buffer_planned) { return; }
|
||||
|
||||
// Reverse Pass: Coarsely maximize all possible deceleration curves back-planning from the last
|
||||
// block in buffer. Cease planning when the last optimal planned or tail pointer is reached.
|
||||
// NOTE: Forward pass will later refine and correct the reverse pass to create an optimal plan.
|
||||
float entry_speed_sqr;
|
||||
plan_block_t *next;
|
||||
plan_block_t *current = &block_buffer[block_index];
|
||||
|
||||
// Calculate maximum entry speed for last block in buffer, where the exit speed is always zero.
|
||||
current->entry_speed_sqr = MIN( current->max_entry_speed_sqr, 2*current->acceleration*current->millimeters);
|
||||
|
||||
block_index = plan_prev_block_index(block_index);
|
||||
if (block_index == block_buffer_planned) { // Only two plannable blocks in buffer. Reverse pass complete.
|
||||
// Check if the first block is the tail. If so, notify stepper to update its current parameters.
|
||||
if (block_index == block_buffer_tail) { st_update_plan_block_parameters(); }
|
||||
} else { // Three or more plan-able blocks
|
||||
while (block_index != block_buffer_planned) {
|
||||
next = current;
|
||||
current = &block_buffer[block_index];
|
||||
block_index = plan_prev_block_index(block_index);
|
||||
|
||||
// Check if next block is the tail block(=planned block). If so, update current stepper parameters.
|
||||
if (block_index == block_buffer_tail) { st_update_plan_block_parameters(); }
|
||||
|
||||
// Compute maximum entry speed decelerating over the current block from its exit speed.
|
||||
if (current->entry_speed_sqr != current->max_entry_speed_sqr) {
|
||||
entry_speed_sqr = next->entry_speed_sqr + 2*current->acceleration*current->millimeters;
|
||||
if (entry_speed_sqr < current->max_entry_speed_sqr) {
|
||||
current->entry_speed_sqr = entry_speed_sqr;
|
||||
} else {
|
||||
current->entry_speed_sqr = current->max_entry_speed_sqr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Forward Pass: Forward plan the acceleration curve from the planned pointer onward.
|
||||
// Also scans for optimal plan breakpoints and appropriately updates the planned pointer.
|
||||
next = &block_buffer[block_buffer_planned]; // Begin at buffer planned pointer
|
||||
block_index = plan_next_block_index(block_buffer_planned);
|
||||
while (block_index != block_buffer_head) {
|
||||
current = next;
|
||||
next = &block_buffer[block_index];
|
||||
|
||||
// Any acceleration detected in the forward pass automatically moves the optimal planned
|
||||
// pointer forward, since everything before this is all optimal. In other words, nothing
|
||||
// can improve the plan from the buffer tail to the planned pointer by logic.
|
||||
if (current->entry_speed_sqr < next->entry_speed_sqr) {
|
||||
entry_speed_sqr = current->entry_speed_sqr + 2*current->acceleration*current->millimeters;
|
||||
// If true, current block is full-acceleration and we can move the planned pointer forward.
|
||||
if (entry_speed_sqr < next->entry_speed_sqr) {
|
||||
next->entry_speed_sqr = entry_speed_sqr; // Always <= max_entry_speed_sqr. Backward pass sets this.
|
||||
block_buffer_planned = block_index; // Set optimal plan pointer.
|
||||
}
|
||||
}
|
||||
|
||||
// Any block set at its maximum entry speed also creates an optimal plan up to this
|
||||
// point in the buffer. When the plan is bracketed by either the beginning of the
|
||||
// buffer and a maximum entry speed or two maximum entry speeds, every block in between
|
||||
// cannot logically be further improved. Hence, we don't have to recompute them anymore.
|
||||
if (next->entry_speed_sqr == next->max_entry_speed_sqr) { block_buffer_planned = block_index; }
|
||||
block_index = plan_next_block_index( block_index );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void plan_reset()
|
||||
{
|
||||
memset(&pl, 0, sizeof(planner_t)); // Clear planner struct
|
||||
plan_reset_buffer();
|
||||
}
|
||||
|
||||
|
||||
void plan_reset_buffer()
|
||||
{
|
||||
block_buffer_tail = 0;
|
||||
block_buffer_head = 0; // Empty = tail
|
||||
next_buffer_head = 1; // plan_next_block_index(block_buffer_head)
|
||||
block_buffer_planned = 0; // = block_buffer_tail;
|
||||
}
|
||||
|
||||
|
||||
void plan_discard_current_block()
|
||||
{
|
||||
if (block_buffer_head != block_buffer_tail) { // Discard non-empty buffer.
|
||||
uint8_t block_index = plan_next_block_index( block_buffer_tail );
|
||||
// Push block_buffer_planned pointer, if encountered.
|
||||
if (block_buffer_tail == block_buffer_planned) { block_buffer_planned = block_index; }
|
||||
block_buffer_tail = block_index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns address of planner buffer block used by system motions. Called by segment generator.
|
||||
plan_block_t *plan_get_system_motion_block()
|
||||
{
|
||||
return(&block_buffer[block_buffer_head]);
|
||||
}
|
||||
|
||||
|
||||
// Returns address of first planner block, if available. Called by various main program functions.
|
||||
plan_block_t *plan_get_current_block()
|
||||
{
|
||||
if (block_buffer_head == block_buffer_tail) { return(NULL); } // Buffer empty
|
||||
return(&block_buffer[block_buffer_tail]);
|
||||
}
|
||||
|
||||
|
||||
float plan_get_exec_block_exit_speed_sqr()
|
||||
{
|
||||
uint8_t block_index = plan_next_block_index(block_buffer_tail);
|
||||
if (block_index == block_buffer_head) { return( 0.0 ); }
|
||||
return( block_buffer[block_index].entry_speed_sqr );
|
||||
}
|
||||
|
||||
|
||||
// Returns the availability status of the block ring buffer. True, if full.
|
||||
uint8_t plan_check_full_buffer()
|
||||
{
|
||||
if (block_buffer_tail == next_buffer_head) { return(true); }
|
||||
return(false);
|
||||
}
|
||||
|
||||
|
||||
// Computes and returns block nominal speed based on running condition and override values.
|
||||
// NOTE: All system motion commands, such as homing/parking, are not subject to overrides.
|
||||
float plan_compute_profile_nominal_speed(plan_block_t *block)
|
||||
{
|
||||
float nominal_speed = block->programmed_rate;
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { nominal_speed *= (0.01*sys.r_override); }
|
||||
else {
|
||||
if (!(block->condition & PL_COND_FLAG_NO_FEED_OVERRIDE)) { nominal_speed *= (0.01*sys.f_override); }
|
||||
if (nominal_speed > block->rapid_rate) { nominal_speed = block->rapid_rate; }
|
||||
}
|
||||
if (nominal_speed > MINIMUM_FEED_RATE) { return(nominal_speed); }
|
||||
return(MINIMUM_FEED_RATE);
|
||||
}
|
||||
|
||||
|
||||
// Computes and updates the max entry speed (sqr) of the block, based on the minimum of the junction's
|
||||
// previous and current nominal speeds and max junction speed.
|
||||
static void plan_compute_profile_parameters(plan_block_t *block, float nominal_speed, float prev_nominal_speed)
|
||||
{
|
||||
// Compute the junction maximum entry based on the minimum of the junction speed and neighboring nominal speeds.
|
||||
if (nominal_speed > prev_nominal_speed) { block->max_entry_speed_sqr = prev_nominal_speed*prev_nominal_speed; }
|
||||
else { block->max_entry_speed_sqr = nominal_speed*nominal_speed; }
|
||||
if (block->max_entry_speed_sqr > block->max_junction_speed_sqr) { block->max_entry_speed_sqr = block->max_junction_speed_sqr; }
|
||||
}
|
||||
|
||||
|
||||
// Re-calculates buffered motions profile parameters upon a motion-based override change.
|
||||
void plan_update_velocity_profile_parameters()
|
||||
{
|
||||
uint8_t block_index = block_buffer_tail;
|
||||
plan_block_t *block;
|
||||
float nominal_speed;
|
||||
float prev_nominal_speed = SOME_LARGE_VALUE; // Set high for first block nominal speed calculation.
|
||||
while (block_index != block_buffer_head) {
|
||||
block = &block_buffer[block_index];
|
||||
nominal_speed = plan_compute_profile_nominal_speed(block);
|
||||
plan_compute_profile_parameters(block, nominal_speed, prev_nominal_speed);
|
||||
prev_nominal_speed = nominal_speed;
|
||||
block_index = plan_next_block_index(block_index);
|
||||
}
|
||||
pl.previous_nominal_speed = prev_nominal_speed; // Update prev nominal speed for next incoming block.
|
||||
}
|
||||
|
||||
|
||||
uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data)
|
||||
{
|
||||
// Prepare and initialize new block. Copy relevant pl_data for block execution.
|
||||
plan_block_t *block = &block_buffer[block_buffer_head];
|
||||
memset(block,0,sizeof(plan_block_t)); // Zero all block values.
|
||||
block->condition = pl_data->condition;
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
block->spindle_speed = pl_data->spindle_speed;
|
||||
#endif
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
block->line_number = pl_data->line_number;
|
||||
#endif
|
||||
|
||||
// Compute and store initial move distance data.
|
||||
int32_t target_steps[N_AXIS], position_steps[N_AXIS];
|
||||
float unit_vec[N_AXIS], delta_mm;
|
||||
uint8_t idx;
|
||||
|
||||
// Copy position data based on type of motion being planned.
|
||||
if (block->condition & PL_COND_FLAG_SYSTEM_MOTION) {
|
||||
#ifdef COREXY
|
||||
position_steps[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
position_steps[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
position_steps[Z_AXIS] = sys_position[Z_AXIS];
|
||||
#else
|
||||
memcpy(position_steps, sys_position, sizeof(sys_position));
|
||||
#endif
|
||||
} else { memcpy(position_steps, pl.position, sizeof(pl.position)); }
|
||||
|
||||
#ifdef COREXY
|
||||
target_steps[A_MOTOR] = lround(target[A_MOTOR]*settings.steps_per_mm[A_MOTOR]);
|
||||
target_steps[B_MOTOR] = lround(target[B_MOTOR]*settings.steps_per_mm[B_MOTOR]);
|
||||
block->steps[A_MOTOR] = labs((target_steps[X_AXIS]-position_steps[X_AXIS]) + (target_steps[Y_AXIS]-position_steps[Y_AXIS]));
|
||||
block->steps[B_MOTOR] = labs((target_steps[X_AXIS]-position_steps[X_AXIS]) - (target_steps[Y_AXIS]-position_steps[Y_AXIS]));
|
||||
#endif
|
||||
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
// Calculate target position in absolute steps, number of steps for each axis, and determine max step events.
|
||||
// Also, compute individual axes distance for move and prep unit vector calculations.
|
||||
// NOTE: Computes true distance from converted step values.
|
||||
#ifdef COREXY
|
||||
if ( !(idx == A_MOTOR) && !(idx == B_MOTOR) ) {
|
||||
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
|
||||
block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
|
||||
}
|
||||
block->step_event_count = MAX(block->step_event_count, block->steps[idx]);
|
||||
if (idx == A_MOTOR) {
|
||||
delta_mm = (target_steps[X_AXIS]-position_steps[X_AXIS] + target_steps[Y_AXIS]-position_steps[Y_AXIS])/settings.steps_per_mm[idx];
|
||||
} else if (idx == B_MOTOR) {
|
||||
delta_mm = (target_steps[X_AXIS]-position_steps[X_AXIS] - target_steps[Y_AXIS]+position_steps[Y_AXIS])/settings.steps_per_mm[idx];
|
||||
} else {
|
||||
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
|
||||
}
|
||||
#else
|
||||
target_steps[idx] = lround(target[idx]*settings.steps_per_mm[idx]);
|
||||
block->steps[idx] = labs(target_steps[idx]-position_steps[idx]);
|
||||
block->step_event_count = MAX(block->step_event_count, block->steps[idx]);
|
||||
delta_mm = (target_steps[idx] - position_steps[idx])/settings.steps_per_mm[idx];
|
||||
#endif
|
||||
unit_vec[idx] = delta_mm; // Store unit vector numerator
|
||||
|
||||
// Set direction bits. Bit enabled always means direction is negative.
|
||||
if (delta_mm < 0.0 ) { block->direction_bits |= get_direction_pin_mask(idx); }
|
||||
}
|
||||
|
||||
// Bail if this is a zero-length block. Highly unlikely to occur.
|
||||
if (block->step_event_count == 0) { return(PLAN_EMPTY_BLOCK); }
|
||||
|
||||
// Calculate the unit vector of the line move and the block maximum feed rate and acceleration scaled
|
||||
// down such that no individual axes maximum values are exceeded with respect to the line direction.
|
||||
// NOTE: This calculation assumes all axes are orthogonal (Cartesian) and works with ABC-axes,
|
||||
// if they are also orthogonal/independent. Operates on the absolute value of the unit vector.
|
||||
block->millimeters = convert_delta_vector_to_unit_vector(unit_vec);
|
||||
block->acceleration = limit_value_by_axis_maximum(settings.acceleration, unit_vec);
|
||||
block->rapid_rate = limit_value_by_axis_maximum(settings.max_rate, unit_vec);
|
||||
|
||||
// Store programmed rate.
|
||||
if (block->condition & PL_COND_FLAG_RAPID_MOTION) { block->programmed_rate = block->rapid_rate; }
|
||||
else {
|
||||
block->programmed_rate = pl_data->feed_rate;
|
||||
if (block->condition & PL_COND_FLAG_INVERSE_TIME) { block->programmed_rate *= block->millimeters; }
|
||||
}
|
||||
|
||||
// TODO: Need to check this method handling zero junction speeds when starting from rest.
|
||||
if ((block_buffer_head == block_buffer_tail) || (block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
|
||||
// Initialize block entry speed as zero. Assume it will be starting from rest. Planner will correct this later.
|
||||
// If system motion, the system motion block always is assumed to start from rest and end at a complete stop.
|
||||
block->entry_speed_sqr = 0.0;
|
||||
block->max_junction_speed_sqr = 0.0; // Starting from rest. Enforce start from zero velocity.
|
||||
|
||||
} else {
|
||||
// Compute maximum allowable entry speed at junction by centripetal acceleration approximation.
|
||||
// Let a circle be tangent to both previous and current path line segments, where the junction
|
||||
// deviation is defined as the distance from the junction to the closest edge of the circle,
|
||||
// colinear with the circle center. The circular segment joining the two paths represents the
|
||||
// path of centripetal acceleration. Solve for max velocity based on max acceleration about the
|
||||
// radius of the circle, defined indirectly by junction deviation. This may be also viewed as
|
||||
// path width or max_jerk in the previous Grbl version. This approach does not actually deviate
|
||||
// from path, but used as a robust way to compute cornering speeds, as it takes into account the
|
||||
// nonlinearities of both the junction angle and junction velocity.
|
||||
//
|
||||
// NOTE: If the junction deviation value is finite, Grbl executes the motions in an exact path
|
||||
// mode (G61). If the junction deviation value is zero, Grbl will execute the motion in an exact
|
||||
// stop mode (G61.1) manner. In the future, if continuous mode (G64) is desired, the math here
|
||||
// is exactly the same. Instead of motioning all the way to junction point, the machine will
|
||||
// just follow the arc circle defined here. The Arduino doesn't have the CPU cycles to perform
|
||||
// a continuous mode path, but ARM-based microcontrollers most certainly do.
|
||||
//
|
||||
// NOTE: The max junction speed is a fixed value, since machine acceleration limits cannot be
|
||||
// changed dynamically during operation nor can the line move geometry. This must be kept in
|
||||
// memory in the event of a feedrate override changing the nominal speeds of blocks, which can
|
||||
// change the overall maximum entry speed conditions of all blocks.
|
||||
|
||||
float junction_unit_vec[N_AXIS];
|
||||
float junction_cos_theta = 0.0;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
junction_cos_theta -= pl.previous_unit_vec[idx]*unit_vec[idx];
|
||||
junction_unit_vec[idx] = unit_vec[idx]-pl.previous_unit_vec[idx];
|
||||
}
|
||||
|
||||
// NOTE: Computed without any expensive trig, sin() or acos(), by trig half angle identity of cos(theta).
|
||||
if (junction_cos_theta > 0.999999) {
|
||||
// For a 0 degree acute junction, just set minimum junction speed.
|
||||
block->max_junction_speed_sqr = MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED;
|
||||
} else {
|
||||
if (junction_cos_theta < -0.999999) {
|
||||
// Junction is a straight line or 180 degrees. Junction speed is infinite.
|
||||
block->max_junction_speed_sqr = SOME_LARGE_VALUE;
|
||||
} else {
|
||||
convert_delta_vector_to_unit_vector(junction_unit_vec);
|
||||
float junction_acceleration = limit_value_by_axis_maximum(settings.acceleration, junction_unit_vec);
|
||||
float sin_theta_d2 = sqrt(0.5*(1.0-junction_cos_theta)); // Trig half angle identity. Always positive.
|
||||
block->max_junction_speed_sqr = MAX( MINIMUM_JUNCTION_SPEED*MINIMUM_JUNCTION_SPEED,
|
||||
(junction_acceleration * settings.junction_deviation * sin_theta_d2)/(1.0-sin_theta_d2) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Block system motion from updating this data to ensure next g-code motion is computed correctly.
|
||||
if (!(block->condition & PL_COND_FLAG_SYSTEM_MOTION)) {
|
||||
float nominal_speed = plan_compute_profile_nominal_speed(block);
|
||||
plan_compute_profile_parameters(block, nominal_speed, pl.previous_nominal_speed);
|
||||
pl.previous_nominal_speed = nominal_speed;
|
||||
|
||||
// Update previous path unit_vector and planner position.
|
||||
memcpy(pl.previous_unit_vec, unit_vec, sizeof(unit_vec)); // pl.previous_unit_vec[] = unit_vec[]
|
||||
memcpy(pl.position, target_steps, sizeof(target_steps)); // pl.position[] = target_steps[]
|
||||
|
||||
// New block is all set. Update buffer head and next buffer head indices.
|
||||
block_buffer_head = next_buffer_head;
|
||||
next_buffer_head = plan_next_block_index(block_buffer_head);
|
||||
|
||||
// Finish up by recalculating the plan with the new block.
|
||||
planner_recalculate();
|
||||
}
|
||||
return(PLAN_OK);
|
||||
}
|
||||
|
||||
// Reset the planner position vectors. Called by the system abort/initialization routine.
|
||||
void plan_sync_position()
|
||||
{
|
||||
// TODO: For motor configurations not in the same coordinate frame as the machine position,
|
||||
// this function needs to be updated to accomodate the difference.
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
#ifdef COREXY
|
||||
if (idx==X_AXIS) {
|
||||
pl.position[X_AXIS] = system_convert_corexy_to_x_axis_steps(sys_position);
|
||||
} else if (idx==Y_AXIS) {
|
||||
pl.position[Y_AXIS] = system_convert_corexy_to_y_axis_steps(sys_position);
|
||||
} else {
|
||||
pl.position[idx] = sys_position[idx];
|
||||
}
|
||||
#else
|
||||
pl.position[idx] = sys_position[idx];
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of available blocks are in the planner buffer.
|
||||
uint8_t plan_get_block_buffer_available()
|
||||
{
|
||||
if (block_buffer_head >= block_buffer_tail) { return((BLOCK_BUFFER_SIZE-1)-(block_buffer_head-block_buffer_tail)); }
|
||||
return((block_buffer_tail-block_buffer_head-1));
|
||||
}
|
||||
|
||||
|
||||
// Returns the number of active blocks are in the planner buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h
|
||||
uint8_t plan_get_block_buffer_count()
|
||||
{
|
||||
if (block_buffer_head >= block_buffer_tail) { return(block_buffer_head-block_buffer_tail); }
|
||||
return(BLOCK_BUFFER_SIZE - (block_buffer_tail-block_buffer_head));
|
||||
}
|
||||
|
||||
|
||||
// Re-initialize buffer plan with a partially completed block, assumed to exist at the buffer tail.
|
||||
// Called after a steppers have come to a complete stop for a feed hold and the cycle is stopped.
|
||||
void plan_cycle_reinitialize()
|
||||
{
|
||||
// Re-plan from a complete stop. Reset planner entry speeds and buffer planned pointer.
|
||||
st_update_plan_block_parameters();
|
||||
block_buffer_planned = block_buffer_tail;
|
||||
planner_recalculate();
|
||||
}
|
152
Grbl_Esp32-master/Grbl_Esp32/planner.h
Normal file
152
Grbl_Esp32-master/Grbl_Esp32/planner.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
planner.h - buffers movement commands and manages the acceleration profile plan
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef planner_h
|
||||
#define planner_h
|
||||
|
||||
// The number of linear motions that can be in the plan at any give time
|
||||
#ifndef BLOCK_BUFFER_SIZE
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#define BLOCK_BUFFER_SIZE 15
|
||||
#else
|
||||
#define BLOCK_BUFFER_SIZE 16
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Returned status message from planner.
|
||||
#define PLAN_OK true
|
||||
#define PLAN_EMPTY_BLOCK false
|
||||
|
||||
// Define planner data condition flags. Used to denote running conditions of a block.
|
||||
#define PL_COND_FLAG_RAPID_MOTION bit(0)
|
||||
#define PL_COND_FLAG_SYSTEM_MOTION bit(1) // Single motion. Circumvents planner state. Used by home/park.
|
||||
#define PL_COND_FLAG_NO_FEED_OVERRIDE bit(2) // Motion does not honor feed override.
|
||||
#define PL_COND_FLAG_INVERSE_TIME bit(3) // Interprets feed rate value as inverse time when set.
|
||||
#define PL_COND_FLAG_SPINDLE_CW bit(4)
|
||||
#define PL_COND_FLAG_SPINDLE_CCW bit(5)
|
||||
#define PL_COND_FLAG_COOLANT_FLOOD bit(6)
|
||||
#define PL_COND_FLAG_COOLANT_MIST bit(7)
|
||||
#define PL_COND_MOTION_MASK (PL_COND_FLAG_RAPID_MOTION|PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE)
|
||||
#define PL_COND_ACCESSORY_MASK (PL_COND_FLAG_SPINDLE_CW|PL_COND_FLAG_SPINDLE_CCW|PL_COND_FLAG_COOLANT_FLOOD|PL_COND_FLAG_COOLANT_MIST)
|
||||
|
||||
|
||||
|
||||
// This struct stores a linear movement of a g-code block motion with its critical "nominal" values
|
||||
// are as specified in the source g-code.
|
||||
typedef struct {
|
||||
// Fields used by the bresenham algorithm for tracing the line
|
||||
// NOTE: Used by stepper algorithm to execute the block correctly. Do not alter these values.
|
||||
uint32_t steps[N_AXIS]; // Step count along each axis
|
||||
uint32_t step_event_count; // The maximum step axis count and number of steps required to complete this block.
|
||||
uint8_t direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
|
||||
|
||||
// Block condition data to ensure correct execution depending on states and overrides.
|
||||
uint8_t condition; // Block bitflag variable defining block run conditions. Copied from pl_line_data.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
int32_t line_number; // Block line number for real-time reporting. Copied from pl_line_data.
|
||||
#endif
|
||||
|
||||
// Fields used by the motion planner to manage acceleration. Some of these values may be updated
|
||||
// by the stepper module during execution of special motion cases for replanning purposes.
|
||||
float entry_speed_sqr; // The current planned entry speed at block junction in (mm/min)^2
|
||||
float max_entry_speed_sqr; // Maximum allowable entry speed based on the minimum of junction limit and
|
||||
// neighboring nominal speeds with overrides in (mm/min)^2
|
||||
float acceleration; // Axis-limit adjusted line acceleration in (mm/min^2). Does not change.
|
||||
float millimeters; // The remaining distance for this block to be executed in (mm).
|
||||
// NOTE: This value may be altered by stepper algorithm during execution.
|
||||
|
||||
// Stored rate limiting data used by planner when changes occur.
|
||||
float max_junction_speed_sqr; // Junction entry speed limit based on direction vectors in (mm/min)^2
|
||||
float rapid_rate; // Axis-limit adjusted maximum rate for this block direction in (mm/min)
|
||||
float programmed_rate; // Programmed rate of this block (mm/min).
|
||||
|
||||
//#ifdef VARIABLE_SPINDLE
|
||||
// Stored spindle speed data used by spindle overrides and resuming methods.
|
||||
float spindle_speed; // Block spindle speed. Copied from pl_line_data.
|
||||
//#endif
|
||||
} plan_block_t;
|
||||
|
||||
// Planner data prototype. Must be used when passing new motions to the planner.
|
||||
typedef struct {
|
||||
float feed_rate; // Desired feed rate for line motion. Value is ignored, if rapid motion.
|
||||
float spindle_speed; // Desired spindle speed through line motion.
|
||||
uint8_t condition; // Bitflag variable to indicate planner conditions. See defines above.
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
int32_t line_number; // Desired line number to report when executing.
|
||||
#endif
|
||||
} plan_line_data_t;
|
||||
|
||||
|
||||
|
||||
// Initialize and reset the motion plan subsystem
|
||||
void plan_reset(); // Reset all
|
||||
void plan_reset_buffer(); // Reset buffer only.
|
||||
|
||||
// Add a new linear movement to the buffer. target[N_AXIS] is the signed, absolute target position
|
||||
// in millimeters. Feed rate specifies the speed of the motion. If feed rate is inverted, the feed
|
||||
// rate is taken to mean "frequency" and would complete the operation in 1/feed_rate minutes.
|
||||
uint8_t plan_buffer_line(float *target, plan_line_data_t *pl_data);
|
||||
|
||||
// Called when the current block is no longer needed. Discards the block and makes the memory
|
||||
// availible for new blocks.
|
||||
void plan_discard_current_block();
|
||||
|
||||
// Gets the planner block for the special system motion cases. (Parking/Homing)
|
||||
plan_block_t *plan_get_system_motion_block();
|
||||
|
||||
// Gets the current block. Returns NULL if buffer empty
|
||||
plan_block_t *plan_get_current_block();
|
||||
|
||||
// Called periodically by step segment buffer. Mostly used internally by planner.
|
||||
uint8_t plan_next_block_index(uint8_t block_index);
|
||||
|
||||
// Called by step segment buffer when computing executing block velocity profile.
|
||||
float plan_get_exec_block_exit_speed_sqr();
|
||||
|
||||
// Called by main program during planner calculations and step segment buffer during initialization.
|
||||
float plan_compute_profile_nominal_speed(plan_block_t *block);
|
||||
|
||||
// Re-calculates buffered motions profile parameters upon a motion-based override change.
|
||||
void plan_update_velocity_profile_parameters();
|
||||
|
||||
// Reset the planner position vector (in steps)
|
||||
void plan_sync_position();
|
||||
|
||||
// Reinitialize plan with a partially completed block
|
||||
void plan_cycle_reinitialize();
|
||||
|
||||
// Returns the number of available blocks are in the planner buffer.
|
||||
uint8_t plan_get_block_buffer_available();
|
||||
|
||||
// Returns the number of active blocks are in the planner buffer.
|
||||
// NOTE: Deprecated. Not used unless classic status reports are enabled in config.h
|
||||
uint8_t plan_get_block_buffer_count();
|
||||
|
||||
// Returns the status of the block ring buffer. True, if buffer is full.
|
||||
uint8_t plan_check_full_buffer();
|
||||
|
||||
void plan_get_planner_mpos(float *target);
|
||||
|
||||
|
||||
#endif
|
299
Grbl_Esp32-master/Grbl_Esp32/polar_coaster.cpp
Normal file
299
Grbl_Esp32-master/Grbl_Esp32/polar_coaster.cpp
Normal file
@ -0,0 +1,299 @@
|
||||
/*
|
||||
kinematics_polar_coaster.cpp - Implements simple inverse kinematics for Grbl_ESP32
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Copyright (c) 2019 Barton Dring @buildlog
|
||||
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Inverse kinematics determine the joint parameters required to get to a position
|
||||
in 3D space. Grbl will still work as 3 axes of steps, but these steps could
|
||||
represent angles, etc instead of linear units.
|
||||
|
||||
Unless forward kinematics are applied to the reporting, Grbl will report raw joint
|
||||
values instead of the normal Cartesian positions
|
||||
|
||||
How it works...
|
||||
|
||||
If you tell it to go to X10 Y10 Z10 in Cartesian space, for example, the equations
|
||||
will convert those values to the required joint values. In the case of a polar machine, X represents the radius,
|
||||
Y represents the polar degrees and Z would be unchanged.
|
||||
|
||||
In most cases, a straight line in Cartesian space could cause a curve in the new system.
|
||||
To fix this, the line is broken into very small segments and each segment is converted
|
||||
to the new space. While each segment is also distorted, the amount is so small it cannot be seen.
|
||||
|
||||
This segmentation is how normal Grbl draws arcs.
|
||||
|
||||
Feed Rate
|
||||
|
||||
Feed rate is given in steps/time. Due to the new coordinate units and non linearity issues, the
|
||||
feed rate may need to be adjusted. The ratio of the step distances in the original coordinate system
|
||||
determined and applied to the feed rate.
|
||||
|
||||
TODO:
|
||||
Add y offset, for completeness
|
||||
Add ZERO_NON_HOMED_AXES option
|
||||
|
||||
|
||||
*/
|
||||
#include "grbl.h"
|
||||
#ifdef CPU_MAP_POLAR_COASTER
|
||||
#ifdef USE_KINEMATICS
|
||||
|
||||
static float last_angle = 0;
|
||||
static float last_radius = 0;
|
||||
|
||||
// this get called before homing
|
||||
// return false to complete normal home
|
||||
// return true to exit normal homing
|
||||
bool kinematics_pre_homing(uint8_t cycle_mask) {
|
||||
// cycle mask not used for polar coaster
|
||||
|
||||
// zero the axes that are not homed
|
||||
sys_position[Y_AXIS] = 0.0f;
|
||||
sys_position[Z_AXIS] = SERVO_Z_RANGE_MAX * settings.steps_per_mm[Z_AXIS]; // Move pen up.
|
||||
|
||||
return false; // finish normal homing cycle
|
||||
}
|
||||
|
||||
void kinematics_post_homing() {
|
||||
// sync the X axis (do not need sync but make it for the fail safe)
|
||||
last_radius = sys_position[X_AXIS];
|
||||
// reset the internal angle value
|
||||
last_angle = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Apply inverse kinematics for a polar system
|
||||
|
||||
float target: The desired target location in machine space
|
||||
plan_line_data_t *pl_data: Plan information like feed rate, etc
|
||||
float *position: The previous "from" location of the move
|
||||
|
||||
Note: It is assumed only the radius axis (X) is homed and only X and Z have offsets
|
||||
|
||||
|
||||
*/
|
||||
void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *position)
|
||||
{
|
||||
//static float last_angle = 0;
|
||||
//static float last_radius = 0;
|
||||
|
||||
float dx, dy, dz; // distances in each cartesian axis
|
||||
float p_dx, p_dy, p_dz; // distances in each polar axis
|
||||
|
||||
float dist, polar_dist; // the distances in both systems...used to determine feed rate
|
||||
|
||||
uint32_t segment_count; // number of segments the move will be broken in to.
|
||||
float seg_target[N_AXIS]; // The target of the current segment
|
||||
|
||||
float polar[N_AXIS]; // target location in polar coordinates
|
||||
|
||||
float x_offset = gc_state.coord_system[X_AXIS]+gc_state.coord_offset[X_AXIS]; // offset from machine coordinate system
|
||||
float z_offset = gc_state.coord_system[Z_AXIS]+gc_state.coord_offset[Z_AXIS]; // offset from machine coordinate system
|
||||
|
||||
//grbl_sendf(CLIENT_SERIAL, "Position: %4.2f %4.2f %4.2f \r\n", position[X_AXIS] - x_offset, position[Y_AXIS], position[Z_AXIS]);
|
||||
//grbl_sendf(CLIENT_SERIAL, "Target: %4.2f %4.2f %4.2f \r\n", target[X_AXIS] - x_offset, target[Y_AXIS], target[Z_AXIS]);
|
||||
|
||||
// calculate cartesian move distance for each axis
|
||||
dx = target[X_AXIS] - position[X_AXIS];
|
||||
dy = target[Y_AXIS] - position[Y_AXIS];
|
||||
dz = target[Z_AXIS] - position[Z_AXIS];
|
||||
|
||||
// calculate the total X,Y axis move distance
|
||||
// Z axis is the same in both coord systems, so it is ignored
|
||||
dist = sqrt( (dx * dx) + (dy * dy) + (dz * dz));
|
||||
|
||||
if (pl_data->condition & PL_COND_FLAG_RAPID_MOTION) {
|
||||
segment_count = 1; // rapid G0 motion is not used to draw, so skip the segmentation
|
||||
} else {
|
||||
segment_count = ceil(dist / SEGMENT_LENGTH); // determine the number of segments we need ... round up so there is at least 1
|
||||
}
|
||||
|
||||
dist /= segment_count; // segment distance
|
||||
|
||||
|
||||
for(uint32_t segment = 1; segment <= segment_count; segment++) {
|
||||
// determine this segment's target
|
||||
seg_target[X_AXIS] = position[X_AXIS] + (dx / float(segment_count) * segment) - x_offset;
|
||||
seg_target[Y_AXIS] = position[Y_AXIS] + (dy / float(segment_count) * segment);
|
||||
seg_target[Z_AXIS] = position[Z_AXIS] + (dz / float(segment_count) * segment) - z_offset;
|
||||
|
||||
calc_polar(seg_target, polar, last_angle);
|
||||
|
||||
// begin determining new feed rate
|
||||
|
||||
// calculate move distance for each axis
|
||||
p_dx = polar[RADIUS_AXIS] - last_radius;
|
||||
p_dy = polar[POLAR_AXIS] - last_angle;
|
||||
p_dz = dz;
|
||||
|
||||
polar_dist = sqrt( (p_dx * p_dx) + (p_dy * p_dy) +(p_dz * p_dz)); // calculate the total move distance
|
||||
|
||||
float polar_rate_multiply = 1.0; // fail safe rate
|
||||
if (polar_dist == 0 || dist == 0) { // prevent 0 feed rate and division by 0
|
||||
polar_rate_multiply = 1.0; // default to same feed rate
|
||||
} else {
|
||||
// calc a feed rate multiplier
|
||||
polar_rate_multiply = polar_dist / dist;
|
||||
if (polar_rate_multiply < 0.5) { // prevent much slower speed
|
||||
polar_rate_multiply = 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
pl_data->feed_rate *= polar_rate_multiply; // apply the distance ratio between coord systems
|
||||
|
||||
// end determining new feed rate
|
||||
|
||||
polar[RADIUS_AXIS] += x_offset;
|
||||
polar[Z_AXIS] += z_offset;
|
||||
|
||||
last_radius = polar[RADIUS_AXIS];
|
||||
last_angle = polar[POLAR_AXIS];
|
||||
|
||||
mc_line(polar, pl_data);
|
||||
}
|
||||
|
||||
// TO DO don't need a feedrate for rapids
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Forward kinematics converts position back to the original cartesian system. It is
|
||||
typically used for reporting
|
||||
|
||||
For example, on a polar machine, you tell it to go to a place like X10Y10. It
|
||||
converts to a radius and angle using inverse kinematics. The machine posiiton is now
|
||||
in those units X14.14 (radius) and Y45 (degrees). If you want to report those units as
|
||||
X10,Y10, you would use forward kinematics
|
||||
|
||||
position = the current machine position
|
||||
converted = position with forward kinematics applied.
|
||||
|
||||
*/
|
||||
void forward_kinematics(float *position)
|
||||
{
|
||||
float original_position[N_AXIS]; // temporary storage of original
|
||||
float print_position[N_AXIS];
|
||||
int32_t current_position[N_AXIS]; // Copy current state of the system position variable
|
||||
|
||||
memcpy(current_position,sys_position,sizeof(sys_position));
|
||||
system_convert_array_steps_to_mpos(print_position,current_position);
|
||||
|
||||
original_position[X_AXIS] = print_position[X_AXIS] - gc_state.coord_system[X_AXIS]+gc_state.coord_offset[X_AXIS];
|
||||
original_position[Y_AXIS] = print_position[Y_AXIS] - gc_state.coord_system[Y_AXIS]+gc_state.coord_offset[Y_AXIS];
|
||||
original_position[Z_AXIS] = print_position[Z_AXIS] - gc_state.coord_system[Z_AXIS]+gc_state.coord_offset[Z_AXIS];
|
||||
|
||||
position[X_AXIS] = cos(radians(original_position[Y_AXIS])) * original_position[X_AXIS] * -1;
|
||||
position[Y_AXIS] = sin(radians(original_position[Y_AXIS])) * original_position[X_AXIS];
|
||||
position[Z_AXIS] = original_position[Z_AXIS]; // unchanged
|
||||
}
|
||||
|
||||
// helper functions
|
||||
|
||||
/*******************************************
|
||||
* Calculate polar values from Cartesian values
|
||||
* float target_xyz: An array of target axis positions in Cartesian (xyz) space
|
||||
* float polar: An array to return the polar values
|
||||
* float last_angle: The polar angle of the "from" point.
|
||||
*
|
||||
* Angle calculated is 0 to 360, but you don't want a line to go from 350 to 10. This would
|
||||
* be a long line backwards. You want it to go from 350 to 370. The same is true going the other way.
|
||||
*
|
||||
* This means the angle could accumulate to very high positive or negative values over the coarse of
|
||||
* a long job.
|
||||
*
|
||||
*/
|
||||
void calc_polar(float *target_xyz, float *polar, float last_angle)
|
||||
{
|
||||
float delta_ang; // the difference from the last and next angle
|
||||
|
||||
polar[RADIUS_AXIS] = hypot_f(target_xyz[X_AXIS], target_xyz[Y_AXIS]);
|
||||
|
||||
if (polar[RADIUS_AXIS] == 0) {
|
||||
polar[POLAR_AXIS] = last_angle; // don't care about angle at center
|
||||
}
|
||||
else {
|
||||
polar[POLAR_AXIS] = atan2(target_xyz[Y_AXIS], target_xyz[X_AXIS]) * 180.0 / M_PI;
|
||||
|
||||
// no negative angles...we want the absolute angle not -90, use 270
|
||||
polar[POLAR_AXIS] = abs_angle(polar[POLAR_AXIS]);
|
||||
}
|
||||
|
||||
polar[Z_AXIS] = target_xyz[Z_AXIS]; // Z is unchanged
|
||||
|
||||
delta_ang = polar[POLAR_AXIS] - abs_angle(last_angle);
|
||||
|
||||
// if the delta is above 180 degrees it means we are crossing the 0 degree line
|
||||
if ( fabs(delta_ang) <= 180.0) {
|
||||
polar[POLAR_AXIS] = last_angle + delta_ang;
|
||||
} else {
|
||||
if (delta_ang > 0.0) { // crossing zero counter clockwise
|
||||
polar[POLAR_AXIS] = last_angle - (360.0 - delta_ang);
|
||||
} else {
|
||||
polar[POLAR_AXIS] = last_angle + delta_ang + 360.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a 0-360 angle ... fix above 360 and below zero
|
||||
float abs_angle(float ang) {
|
||||
ang = fmod(ang, 360.0); // 0-360 or 0 to -360
|
||||
|
||||
if (ang < 0.0) {
|
||||
ang = 360.0 + ang;
|
||||
}
|
||||
return ang;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Polar coaster has macro buttons, this handles those button pushes.
|
||||
void user_defined_macro(uint8_t index)
|
||||
{
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG: Macro #%d]\r\n", index);
|
||||
switch (index) {
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_0:
|
||||
inputBuffer.push("$H\r"); // home machine
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_1:
|
||||
inputBuffer.push("[ESP220]/1.nc\r"); // run SD card file 1.nc
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_2:
|
||||
inputBuffer.push("[ESP220]/2.nc\r"); // run SD card file 2.nc
|
||||
break;
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_3_PIN
|
||||
case CONTROL_PIN_INDEX_MACRO_3:
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// handle the M30 command
|
||||
void user_m30() {
|
||||
inputBuffer.push("$H\r");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
158
Grbl_Esp32-master/Grbl_Esp32/polar_coaster.h
Normal file
158
Grbl_Esp32-master/Grbl_Esp32/polar_coaster.h
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
kinematics_polar_coaster.h - Implements simple kinematics for Grbl_ESP32
|
||||
Part of Grbl_ESP32
|
||||
|
||||
Copyright (c) 2019 Barton Dring @buildlog
|
||||
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define RADIUS_AXIS 0
|
||||
#define POLAR_AXIS 1
|
||||
|
||||
#define SEGMENT_LENGTH 0.5 // segment length in mm
|
||||
#define USE_KINEMATICS
|
||||
#define FWD_KINEMATICS_REPORTING // report in cartesian
|
||||
#define USE_M30
|
||||
|
||||
// ============= Begin CPU MAP ================
|
||||
#define CPU_MAP_NAME "CPU_MAP_POLAR_COASTER"
|
||||
|
||||
#define USE_RMT_STEPS
|
||||
|
||||
#define X_STEP_PIN GPIO_NUM_15
|
||||
#define X_RMT_CHANNEL 0
|
||||
#define Y_STEP_PIN GPIO_NUM_2
|
||||
#define Y_RMT_CHANNEL 1
|
||||
#define X_DIRECTION_PIN GPIO_NUM_25
|
||||
#define Y_DIRECTION_PIN GPIO_NUM_26
|
||||
|
||||
#define STEPPERS_DISABLE_PIN GPIO_NUM_17
|
||||
|
||||
#ifndef USE_SERVO_AXES // maybe set in config.h
|
||||
#define USE_SERVO_AXES
|
||||
#endif
|
||||
|
||||
#define SERVO_Z_PIN GPIO_NUM_16
|
||||
#define SERVO_Z_CHANNEL_NUM 5
|
||||
#define SERVO_Z_RANGE_MIN 0.0
|
||||
#define SERVO_Z_RANGE_MAX 5.0
|
||||
#define SERVO_Z_HOMING_TYPE SERVO_HOMING_TARGET // during homing it will instantly move to a target value
|
||||
#define SERVO_Z_HOME_POS SERVO_Z_RANGE_MAX // move to max during homing
|
||||
#define SERVO_Z_MPOS false // will not use mpos, uses work coordinates
|
||||
|
||||
#define X_LIMIT_PIN GPIO_NUM_4
|
||||
#define LIMIT_MASK B1
|
||||
|
||||
#ifdef IGNORE_CONTROL_PINS // maybe set in config.h
|
||||
#undef IGNORE_CONTROL_PINS
|
||||
#endif
|
||||
|
||||
#ifndef ENABLE_CONTROL_SW_DEBOUNCE
|
||||
#define ENABLE_CONTROL_SW_DEBOUNCE
|
||||
#endif
|
||||
|
||||
#ifdef CONTROL_SW_DEBOUNCE_PERIOD
|
||||
#undef CONTROL_SW_DEBOUNCE_PERIOD
|
||||
#endif
|
||||
#define CONTROL_SW_DEBOUNCE_PERIOD 100 // really long debounce
|
||||
|
||||
#ifdef INVERT_CONTROL_PIN_MASK
|
||||
#undef INVERT_CONTROL_PIN_MASK
|
||||
#endif
|
||||
#define INVERT_CONTROL_PIN_MASK B11111111
|
||||
|
||||
#define MACRO_BUTTON_0_PIN GPIO_NUM_13
|
||||
#define MACRO_BUTTON_1_PIN GPIO_NUM_12
|
||||
#define MACRO_BUTTON_2_PIN GPIO_NUM_14
|
||||
|
||||
// redefine some stuff from config.h
|
||||
#ifdef HOMING_CYCLE_0
|
||||
#undef HOMING_CYCLE_0
|
||||
#endif
|
||||
#define HOMING_CYCLE_0 (1<<X_AXIS) // this 'bot only homes the X axis
|
||||
#ifdef HOMING_CYCLE_1
|
||||
#undef HOMING_CYCLE_1
|
||||
#endif
|
||||
#ifdef HOMING_CYCLE_2
|
||||
#undef HOMING_CYCLE_2
|
||||
#endif
|
||||
|
||||
// ============= End CPU MAP ==================
|
||||
|
||||
// ============= Begin Default Settings ================
|
||||
#define DEFAULT_STEP_PULSE_MICROSECONDS 3
|
||||
#define DEFAULT_STEPPER_IDLE_LOCK_TIME 255 // stay on
|
||||
|
||||
#define DEFAULT_STEPPING_INVERT_MASK 0 // uint8_t
|
||||
#define DEFAULT_DIRECTION_INVERT_MASK 2 // uint8_t
|
||||
#define DEFAULT_INVERT_ST_ENABLE 0 // boolean
|
||||
#define DEFAULT_INVERT_LIMIT_PINS 1 // boolean
|
||||
#define DEFAULT_INVERT_PROBE_PIN 0 // boolean
|
||||
|
||||
#define DEFAULT_STATUS_REPORT_MASK 2 // MPos enabled
|
||||
|
||||
#define DEFAULT_JUNCTION_DEVIATION 0.01 // mm
|
||||
#define DEFAULT_ARC_TOLERANCE 0.002 // mm
|
||||
#define DEFAULT_REPORT_INCHES 0 // false
|
||||
|
||||
#define DEFAULT_SOFT_LIMIT_ENABLE 0 // false
|
||||
#define DEFAULT_HARD_LIMIT_ENABLE 0 // false
|
||||
|
||||
#define DEFAULT_HOMING_ENABLE 1
|
||||
#define DEFAULT_HOMING_DIR_MASK 0 // move positive dir Z, negative X,Y
|
||||
#define DEFAULT_HOMING_FEED_RATE 200.0 // mm/min
|
||||
#define DEFAULT_HOMING_SEEK_RATE 1000.0 // mm/min
|
||||
#define DEFAULT_HOMING_DEBOUNCE_DELAY 250 // msec (0-65k)
|
||||
#define DEFAULT_HOMING_PULLOFF 3.0 // mm
|
||||
|
||||
#define DEFAULT_SPINDLE_RPM_MAX 1000.0 // rpm
|
||||
#define DEFAULT_SPINDLE_RPM_MIN 0.0 // rpm
|
||||
|
||||
#define DEFAULT_LASER_MODE 0 // false
|
||||
|
||||
#define DEFAULT_X_STEPS_PER_MM 200.0
|
||||
#define DEFAULT_Y_STEPS_PER_MM 71.111
|
||||
#define DEFAULT_Z_STEPS_PER_MM 100.0 // This is percent in servo mode
|
||||
|
||||
#define DEFAULT_X_MAX_RATE 5000.0 // mm/min
|
||||
#define DEFAULT_Y_MAX_RATE 15000.0 // mm/min
|
||||
#define DEFAULT_Z_MAX_RATE 3000.0 // mm/min
|
||||
|
||||
#define DEFAULT_X_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#define DEFAULT_Y_ACCELERATION (200.0*60*60) // 10*60*60 mm/min^2 = 10 mm/sec^2
|
||||
#define DEFAULT_Z_ACCELERATION (50.0*60*60)
|
||||
|
||||
#define DEFAULT_X_MAX_TRAVEL 50.0 // mm NOTE: Must be a positive value.
|
||||
#define DEFAULT_Y_MAX_TRAVEL 300.0 // mm NOTE: Must be a positive value.
|
||||
#define DEFAULT_Z_MAX_TRAVEL 100.0 // This is percent in servo mode
|
||||
// ============= End Default Settings ==================
|
||||
|
||||
#ifndef kinematics_h
|
||||
#define kinematics_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
bool kinematics_pre_homing(uint8_t cycle_mask);
|
||||
void kinematics_post_homing();
|
||||
void inverse_kinematics(float *target, plan_line_data_t *pl_data, float *position);
|
||||
void calc_polar(float *target_xyz, float *polar, float last_angle);
|
||||
float abs_angle(float ang);
|
||||
void user_defined_macro(uint8_t index);
|
||||
|
||||
void forward_kinematics(float *position);
|
||||
void user_m30();
|
||||
|
||||
#endif
|
149
Grbl_Esp32-master/Grbl_Esp32/print.cpp
Normal file
149
Grbl_Esp32-master/Grbl_Esp32/print.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
print.c - Functions for formatting output strings
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
|
||||
|
||||
// void printIntegerInBase(unsigned long n, unsigned long base)
|
||||
// {
|
||||
// unsigned char buf[8 * sizeof(long)]; // Assumes 8-bit chars.
|
||||
// unsigned long i = 0;
|
||||
//
|
||||
// if (n == 0) {
|
||||
// serial_write('0');
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// while (n > 0) {
|
||||
// buf[i++] = n % base;
|
||||
// n /= base;
|
||||
// }
|
||||
//
|
||||
// for (; i > 0; i--)
|
||||
// serial_write(buf[i - 1] < 10 ?
|
||||
// '0' + buf[i - 1] :
|
||||
// 'A' + buf[i - 1] - 10);
|
||||
// }
|
||||
|
||||
|
||||
// Prints an uint8 variable in base 10.
|
||||
void print_uint8_base10(uint8_t n)
|
||||
{
|
||||
uint8_t digit_a = 0;
|
||||
uint8_t digit_b = 0;
|
||||
if (n >= 100) { // 100-255
|
||||
digit_a = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
if (n >= 10) { // 10-99
|
||||
digit_b = '0' + n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
serial_write('0' + n);
|
||||
if (digit_b) { serial_write(digit_b); }
|
||||
if (digit_a) { serial_write(digit_a); }
|
||||
}
|
||||
|
||||
|
||||
// Prints an uint8 variable in base 2 with desired number of desired digits.
|
||||
void print_uint8_base2_ndigit(uint8_t n, uint8_t digits) {
|
||||
unsigned char buf[digits];
|
||||
uint8_t i = 0;
|
||||
|
||||
for (; i < digits; i++) {
|
||||
buf[i] = n % 2 ;
|
||||
n /= 2;
|
||||
}
|
||||
|
||||
for (; i > 0; i--)
|
||||
Serial.print('0' + buf[i - 1]);
|
||||
}
|
||||
|
||||
|
||||
void print_uint32_base10(uint32_t n)
|
||||
{
|
||||
if (n == 0) {
|
||||
Serial.print('0');
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned char buf[10];
|
||||
uint8_t i = 0;
|
||||
|
||||
while (n > 0) {
|
||||
buf[i++] = n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
for (; i > 0; i--)
|
||||
Serial.print('0' + buf[i-1]);
|
||||
}
|
||||
|
||||
|
||||
void printInteger(long n)
|
||||
{
|
||||
if (n < 0) {
|
||||
Serial.print('-');
|
||||
print_uint32_base10(-n);
|
||||
} else {
|
||||
print_uint32_base10(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Convert float to string by immediately converting to a long integer, which contains
|
||||
// more digits than a float. Number of decimal places, which are tracked by a counter,
|
||||
// may be set by the user. The integer is then efficiently converted to a string.
|
||||
// NOTE: AVR '%' and '/' integer operations are very efficient. Bitshifting speed-up
|
||||
// techniques are actually just slightly slower. Found this out the hard way.
|
||||
void printFloat(float n, uint8_t decimal_places)
|
||||
{
|
||||
Serial.print(n, decimal_places);
|
||||
}
|
||||
|
||||
|
||||
// Floating value printing handlers for special variables types used in Grbl and are defined
|
||||
// in the config.h.
|
||||
// - CoordValue: Handles all position or coordinate values in inches or mm reporting.
|
||||
// - RateValue: Handles feed rate and current velocity in inches or mm reporting.
|
||||
void printFloat_CoordValue(float n) {
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
printFloat(n*INCH_PER_MM,N_DECIMAL_COORDVALUE_INCH);
|
||||
} else {
|
||||
printFloat(n,N_DECIMAL_COORDVALUE_MM);
|
||||
}
|
||||
}
|
||||
|
||||
// Debug tool to print free memory in bytes at the called point.
|
||||
// NOTE: Keep commented unless using. Part of this function always gets compiled in.
|
||||
// void printFreeMemory()
|
||||
// {
|
||||
// extern int __heap_start, *__brkval;
|
||||
// uint16_t free; // Up to 64k values.
|
||||
// free = (int) &free - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
// printInteger((int32_t)free);
|
||||
// printString(" ");
|
||||
// }
|
54
Grbl_Esp32-master/Grbl_Esp32/print.h
Normal file
54
Grbl_Esp32-master/Grbl_Esp32/print.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
print.h - Functions for formatting output strings
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef print_h
|
||||
#define print_h
|
||||
|
||||
|
||||
void printString(const char *s);
|
||||
|
||||
void printPgmString(const char *s);
|
||||
|
||||
void printInteger(long n);
|
||||
|
||||
void print_uint32_base10(uint32_t n);
|
||||
|
||||
// Prints an uint8 variable in base 10.
|
||||
void print_uint8_base10(uint8_t n);
|
||||
|
||||
// Prints an uint8 variable in base 2 with desired number of desired digits.
|
||||
void print_uint8_base2_ndigit(uint8_t n, uint8_t digits);
|
||||
|
||||
void printFloat(float n, uint8_t decimal_places);
|
||||
|
||||
// Floating value printing handlers for special variables types used in Grbl.
|
||||
// - CoordValue: Handles all position or coordinate values in inches or mm reporting.
|
||||
// - RateValue: Handles feed rate and current velocity in inches or mm reporting.
|
||||
void printFloat_CoordValue(float n);
|
||||
void printFloat_RateValue(float n);
|
||||
|
||||
// Debug tool to print free memory in bytes at the called point. Not used otherwise.
|
||||
void printFreeMemory();
|
||||
|
||||
#endif
|
78
Grbl_Esp32-master/Grbl_Esp32/probe.cpp
Normal file
78
Grbl_Esp32-master/Grbl_Esp32/probe.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
probe.c - code pertaining to probing methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Inverts the probe pin state depending on user settings and probing cycle mode.
|
||||
uint8_t probe_invert_mask;
|
||||
|
||||
|
||||
// Probe pin initialization routine.
|
||||
void probe_init()
|
||||
{
|
||||
#ifdef PROBE_PIN
|
||||
#ifdef DISABLE_PROBE_PIN_PULL_UP
|
||||
pinMode(PROBE_PIN, INPUT);
|
||||
#else
|
||||
pinMode(PROBE_PIN, INPUT_PULLUP); // Enable internal pull-up resistors. Normal high operation.
|
||||
#endif
|
||||
|
||||
|
||||
probe_configure_invert_mask(false); // Initialize invert mask.
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Called by probe_init() and the mc_probe() routines. Sets up the probe pin invert mask to
|
||||
// appropriately set the pin logic according to setting for normal-high/normal-low operation
|
||||
// and the probing cycle modes for toward-workpiece/away-from-workpiece.
|
||||
void probe_configure_invert_mask(uint8_t is_probe_away)
|
||||
{
|
||||
probe_invert_mask = 0; // Initialize as zero.
|
||||
if (bit_isfalse(settings.flags,BITFLAG_INVERT_PROBE_PIN)) { probe_invert_mask ^= PROBE_MASK; }
|
||||
if (is_probe_away) { probe_invert_mask ^= PROBE_MASK; }
|
||||
}
|
||||
|
||||
// Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
|
||||
uint8_t probe_get_state()
|
||||
{
|
||||
#ifdef PROBE_PIN
|
||||
return((digitalRead(PROBE_PIN)) ^ probe_invert_mask);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Monitors probe pin state and records the system position when detected. Called by the
|
||||
// stepper ISR per ISR tick.
|
||||
// NOTE: This function must be extremely efficient as to not bog down the stepper ISR.
|
||||
void probe_state_monitor()
|
||||
{
|
||||
if (probe_get_state()) {
|
||||
sys_probe_state = PROBE_OFF;
|
||||
memcpy(sys_probe_position, sys_position, sizeof(sys_position));
|
||||
bit_true(sys_rt_exec_state, EXEC_MOTION_CANCEL);
|
||||
}
|
||||
}
|
46
Grbl_Esp32-master/Grbl_Esp32/probe.h
Normal file
46
Grbl_Esp32-master/Grbl_Esp32/probe.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
probe.h - code pertaining to probing methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef probe_h
|
||||
#define probe_h
|
||||
|
||||
// Values that define the probing state machine.
|
||||
#define PROBE_OFF 0 // Probing disabled or not in use. (Must be zero.)
|
||||
#define PROBE_ACTIVE 1 // Actively watching the input pin.
|
||||
|
||||
// Probe pin initialization routine.
|
||||
void probe_init();
|
||||
|
||||
// Called by probe_init() and the mc_probe() routines. Sets up the probe pin invert mask to
|
||||
// appropriately set the pin logic according to setting for normal-high/normal-low operation
|
||||
// and the probing cycle modes for toward-workpiece/away-from-workpiece.
|
||||
void probe_configure_invert_mask(uint8_t is_probe_away);
|
||||
|
||||
// Returns probe pin state. Triggered = true. Called by gcode parser and probe state monitor.
|
||||
uint8_t probe_get_state();
|
||||
|
||||
// Monitors probe pin state and records the system position when detected. Called by the
|
||||
// stepper ISR per ISR tick.
|
||||
void probe_state_monitor();
|
||||
|
||||
#endif
|
849
Grbl_Esp32-master/Grbl_Esp32/protocol.cpp
Normal file
849
Grbl_Esp32-master/Grbl_Esp32/protocol.cpp
Normal file
@ -0,0 +1,849 @@
|
||||
/*
|
||||
protocol.c - controls Grbl execution protocol and procedures
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "config.h"
|
||||
#include "commands.h"
|
||||
#include "espresponse.h"
|
||||
|
||||
// Define line flags. Includes comment type tracking and line overflow detection.
|
||||
#define LINE_FLAG_OVERFLOW bit(0)
|
||||
#define LINE_FLAG_COMMENT_PARENTHESES bit(1)
|
||||
#define LINE_FLAG_COMMENT_SEMICOLON bit(2)
|
||||
#define LINE_FLAG_BRACKET bit(3) // square bracket for WebUI commands
|
||||
|
||||
|
||||
static char line[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
|
||||
static char comment[LINE_BUFFER_SIZE]; // Line to be executed. Zero-terminated.
|
||||
|
||||
static void protocol_exec_rt_suspend();
|
||||
|
||||
|
||||
/*
|
||||
GRBL PRIMARY LOOP:
|
||||
*/
|
||||
void protocol_main_loop()
|
||||
{
|
||||
//uint8_t client = CLIENT_SERIAL; // default client
|
||||
|
||||
// Perform some machine checks to make sure everything is good to go.
|
||||
#ifdef CHECK_LIMITS_AT_INIT
|
||||
if (bit_istrue(settings.flags, BITFLAG_HARD_LIMIT_ENABLE)) {
|
||||
if (limits_get_state()) {
|
||||
sys.state = STATE_ALARM; // Ensure alarm state is active.
|
||||
report_feedback_message(MESSAGE_CHECK_LIMITS);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Check for and report alarm state after a reset, error, or an initial power up.
|
||||
// NOTE: Sleep mode disables the stepper drivers and position can't be guaranteed.
|
||||
// Re-initialize the sleep state as an ALARM mode to ensure user homes or acknowledges.
|
||||
if (sys.state & (STATE_ALARM | STATE_SLEEP)) {
|
||||
report_feedback_message(MESSAGE_ALARM_LOCK);
|
||||
sys.state = STATE_ALARM; // Ensure alarm state is set.
|
||||
} else {
|
||||
// Check if the safety door is open.
|
||||
sys.state = STATE_IDLE;
|
||||
if (system_check_safety_door_ajar()) {
|
||||
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
|
||||
protocol_execute_realtime(); // Enter safety door mode. Should return as IDLE state.
|
||||
}
|
||||
// All systems go!
|
||||
system_execute_startup(line); // Execute startup script.
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
// Primary loop! Upon a system abort, this exits back to main() to reset the system.
|
||||
// This is also where Grbl idles while waiting for something to do.
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
uint8_t line_flags = 0;
|
||||
uint8_t char_counter = 0;
|
||||
uint8_t comment_char_counter = 0;
|
||||
uint8_t c;
|
||||
|
||||
for (;;) {
|
||||
|
||||
// serialCheck(); // un comment this if you do this here rather than in a separate task
|
||||
|
||||
#ifdef ENABLE_SD_CARD
|
||||
if (SD_ready_next) {
|
||||
char fileLine[255];
|
||||
if (readFileLine(fileLine)) {
|
||||
SD_ready_next = false;
|
||||
report_status_message(gc_execute_line(fileLine, SD_client), SD_client);
|
||||
}
|
||||
else {
|
||||
char temp[50];
|
||||
sd_get_current_filename(temp);
|
||||
grbl_notifyf("SD print done", "%s print is successful", temp);
|
||||
closeFile(); // close file and clear SD ready/running flags
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Process one line of incoming serial data, as the data becomes available. Performs an
|
||||
// initial filtering by removing spaces and comments and capitalizing all letters.
|
||||
|
||||
uint8_t client = CLIENT_SERIAL;
|
||||
for (client = 0; client <= CLIENT_COUNT; client++)
|
||||
{
|
||||
while((c = serial_read(client)) != SERIAL_NO_DATA) {
|
||||
if ((c == '\n') || (c == '\r')) { // End of line reached
|
||||
|
||||
protocol_execute_realtime(); // Runtime command check point.
|
||||
if (sys.abort) { return; } // Bail to calling function upon system abort
|
||||
|
||||
line[char_counter] = 0; // Set string termination character.
|
||||
#ifdef REPORT_ECHO_LINE_RECEIVED
|
||||
report_echo_line_received(line, client);
|
||||
#endif
|
||||
|
||||
// Direct and execute one line of formatted input, and report status of execution.
|
||||
if (line_flags & LINE_FLAG_OVERFLOW) {
|
||||
// Report line overflow error.
|
||||
report_status_message(STATUS_OVERFLOW, client);
|
||||
} else if (line[0] == 0) {
|
||||
// Empty or comment line. For syncing purposes.
|
||||
report_status_message(STATUS_OK, client);
|
||||
} else if (line[0] == '$') {
|
||||
// Grbl '$' system command
|
||||
report_status_message(system_execute_line(line, client), client);
|
||||
} else if (line[0] == '[') {
|
||||
int cmd = 0;
|
||||
String cmd_params;
|
||||
if (COMMANDS::check_command (line, &cmd, cmd_params)) {
|
||||
ESPResponseStream espresponse(client, true);
|
||||
if (!COMMANDS::execute_internal_command (cmd, cmd_params, LEVEL_GUEST, &espresponse)) {
|
||||
report_status_message(STATUS_GCODE_UNSUPPORTED_COMMAND, CLIENT_ALL);
|
||||
}
|
||||
} else grbl_sendf(client, "[MSG: Unknow Command...%s]\r\n", line);
|
||||
} else if (sys.state & (STATE_ALARM | STATE_JOG)) {
|
||||
// Everything else is gcode. Block if in alarm or jog mode.
|
||||
report_status_message(STATUS_SYSTEM_GC_LOCK, client);
|
||||
} else {
|
||||
// Parse and execute g-code block.
|
||||
report_status_message(gc_execute_line(line, client), client);
|
||||
}
|
||||
|
||||
// Reset tracking data for next line.
|
||||
line_flags = 0;
|
||||
char_counter = 0;
|
||||
comment_char_counter = 0;
|
||||
} else {
|
||||
|
||||
if (line_flags) {
|
||||
if (line_flags & LINE_FLAG_BRACKET) { // in bracket mode all characters are accepted
|
||||
line[char_counter++] = c;
|
||||
}
|
||||
// Throw away all (except EOL) comment characters and overflow characters.
|
||||
if (c == ')') {
|
||||
// End of '()' comment. Resume line allowed.
|
||||
if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) {
|
||||
line_flags &= ~(LINE_FLAG_COMMENT_PARENTHESES);
|
||||
comment[comment_char_counter] = 0; // null terminate
|
||||
report_gcode_comment(comment);
|
||||
}
|
||||
}
|
||||
if (line_flags & LINE_FLAG_COMMENT_PARENTHESES) { // capture all characters into a comment buffer
|
||||
comment[comment_char_counter++] = c;
|
||||
}
|
||||
} else {
|
||||
if (c <= ' ') {
|
||||
// Throw away whitepace and control characters
|
||||
}
|
||||
/*
|
||||
else if (c == '/') {
|
||||
// Block delete NOT SUPPORTED. Ignore character.
|
||||
// NOTE: If supported, would simply need to check the system if block delete is enabled.
|
||||
}
|
||||
*/
|
||||
else if (c == '(') {
|
||||
// Enable comments flag and ignore all characters until ')' or EOL.
|
||||
// NOTE: This doesn't follow the NIST definition exactly, but is good enough for now.
|
||||
// In the future, we could simply remove the items within the comments, but retain the
|
||||
// comment control characters, so that the g-code parser can error-check it.
|
||||
line_flags |= LINE_FLAG_COMMENT_PARENTHESES;
|
||||
comment_char_counter = 0;
|
||||
} else if (c == ';') {
|
||||
// NOTE: ';' comment to EOL is a LinuxCNC definition. Not NIST.
|
||||
line_flags |= LINE_FLAG_COMMENT_SEMICOLON;
|
||||
} else if (c == '[') {
|
||||
// For ESP3D bracket commands like [ESP100]<SSID>pwd=<admin password>
|
||||
// prevents spaces being striped and converting to uppercase
|
||||
line_flags |= LINE_FLAG_BRACKET;
|
||||
line[char_counter++] = c; // capture this character
|
||||
|
||||
// TODO: Install '%' feature
|
||||
} else if (c == '%') {
|
||||
// Program start-end percent sign NOT SUPPORTED.
|
||||
// NOTE: This maybe installed to tell Grbl when a program is running vs manual input,
|
||||
// where, during a program, the system auto-cycle start will continue to execute
|
||||
// everything until the next '%' sign. This will help fix resuming issues with certain
|
||||
// functions that empty the planner buffer to execute its task on-time.
|
||||
} else if (char_counter >= (LINE_BUFFER_SIZE-1)) {
|
||||
// Detect line buffer overflow and set flag.
|
||||
line_flags |= LINE_FLAG_OVERFLOW;
|
||||
} else if (c >= 'a' && c <= 'z') { // Upcase lowercase
|
||||
line[char_counter++] = c-'a'+'A';
|
||||
} else {
|
||||
line[char_counter++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} // while serial read
|
||||
} // for clients
|
||||
|
||||
|
||||
|
||||
// If there are no more characters in the serial read buffer to be processed and executed,
|
||||
// this indicates that g-code streaming has either filled the planner buffer or has
|
||||
// completed. In either case, auto-cycle start, if enabled, any queued moves.
|
||||
protocol_auto_cycle_start();
|
||||
|
||||
protocol_execute_realtime(); // Runtime command check point.
|
||||
if (sys.abort) { return; } // Bail to main() program loop to reset system.
|
||||
|
||||
// check to see if we should disable the stepper drivers ... esp32 work around for disable in main loop.
|
||||
if (stepper_idle)
|
||||
{
|
||||
if (esp_timer_get_time() > stepper_idle_counter)
|
||||
{
|
||||
set_stepper_disable(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return; /* Never reached */
|
||||
}
|
||||
|
||||
|
||||
// Block until all buffered steps are executed or in a cycle state. Works with feed hold
|
||||
// during a synchronize call, if it should happen. Also, waits for clean cycle end.
|
||||
void protocol_buffer_synchronize()
|
||||
{
|
||||
// If system is queued, ensure cycle resumes if the auto start flag is present.
|
||||
protocol_auto_cycle_start();
|
||||
do {
|
||||
protocol_execute_realtime(); // Check and execute run-time commands
|
||||
if (sys.abort) { return; } // Check for system abort
|
||||
} while (plan_get_current_block() || (sys.state == STATE_CYCLE));
|
||||
}
|
||||
|
||||
|
||||
// Auto-cycle start triggers when there is a motion ready to execute and if the main program is not
|
||||
// actively parsing commands.
|
||||
// NOTE: This function is called from the main loop, buffer sync, and mc_line() only and executes
|
||||
// when one of these conditions exist respectively: There are no more blocks sent (i.e. streaming
|
||||
// is finished, single commands), a command that needs to wait for the motions in the buffer to
|
||||
// execute calls a buffer sync, or the planner buffer is full and ready to go.
|
||||
void protocol_auto_cycle_start()
|
||||
{
|
||||
if (plan_get_current_block() != NULL) { // Check if there are any blocks in the buffer.
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START); // If so, execute them!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// This function is the general interface to Grbl's real-time command execution system. It is called
|
||||
// from various check points in the main program, primarily where there may be a while loop waiting
|
||||
// for a buffer to clear space or any point where the execution time from the last check point may
|
||||
// be more than a fraction of a second. This is a way to execute realtime commands asynchronously
|
||||
// (aka multitasking) with grbl's g-code parsing and planning functions. This function also serves
|
||||
// as an interface for the interrupts to set the system realtime flags, where only the main program
|
||||
// handles them, removing the need to define more computationally-expensive volatile variables. This
|
||||
// also provides a controlled way to execute certain tasks without having two or more instances of
|
||||
// the same task, such as the planner recalculating the buffer upon a feedhold or overrides.
|
||||
// NOTE: The sys_rt_exec_state variable flags are set by any process, step or serial interrupts, pinouts,
|
||||
// limit switches, or the main program.
|
||||
void protocol_execute_realtime()
|
||||
{
|
||||
protocol_exec_rt_system();
|
||||
if (sys.suspend) { protocol_exec_rt_suspend(); }
|
||||
}
|
||||
|
||||
|
||||
// Executes run-time commands, when required. This function primarily operates as Grbl's state
|
||||
// machine and controls the various real-time features Grbl has to offer.
|
||||
// NOTE: Do not alter this unless you know exactly what you are doing!
|
||||
void protocol_exec_rt_system()
|
||||
{
|
||||
uint8_t rt_exec; // Temp variable to avoid calling volatile multiple times.
|
||||
rt_exec = sys_rt_exec_alarm; // Copy volatile sys_rt_exec_alarm.
|
||||
if (rt_exec) { // Enter only if any bit flag is true
|
||||
// System alarm. Everything has shutdown by something that has gone severely wrong. Report
|
||||
// the source of the error to the user. If critical, Grbl disables by entering an infinite
|
||||
// loop until system reset/abort.
|
||||
sys.state = STATE_ALARM; // Set system alarm state
|
||||
report_alarm_message(rt_exec);
|
||||
// Halt everything upon a critical event flag. Currently hard and soft limits flag this.
|
||||
if ((rt_exec == EXEC_ALARM_HARD_LIMIT) || (rt_exec == EXEC_ALARM_SOFT_LIMIT)) {
|
||||
report_feedback_message(MESSAGE_CRITICAL_EVENT);
|
||||
system_clear_exec_state_flag(EXEC_RESET); // Disable any existing reset
|
||||
do {
|
||||
// Block everything, except reset and status reports, until user issues reset or power
|
||||
// cycles. Hard limits typically occur while unattended or not paying attention. Gives
|
||||
// the user and a GUI time to do what is needed before resetting, like killing the
|
||||
// incoming stream. The same could be said about soft limits. While the position is not
|
||||
// lost, continued streaming could cause a serious crash if by chance it gets executed.
|
||||
} while (bit_isfalse(sys_rt_exec_state,EXEC_RESET));
|
||||
}
|
||||
system_clear_exec_alarm(); // Clear alarm
|
||||
}
|
||||
|
||||
rt_exec = sys_rt_exec_state; // Copy volatile sys_rt_exec_state.
|
||||
if (rt_exec) {
|
||||
|
||||
// Execute system abort.
|
||||
if (rt_exec & EXEC_RESET) {
|
||||
sys.abort = true; // Only place this is set true.
|
||||
return; // Nothing else to do but exit.
|
||||
}
|
||||
|
||||
// Execute and serial print status
|
||||
if (rt_exec & EXEC_STATUS_REPORT) {
|
||||
report_realtime_status(CLIENT_ALL);
|
||||
system_clear_exec_state_flag(EXEC_STATUS_REPORT);
|
||||
}
|
||||
|
||||
// NOTE: Once hold is initiated, the system immediately enters a suspend state to block all
|
||||
// main program processes until either reset or resumed. This ensures a hold completes safely.
|
||||
if (rt_exec & (EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP)) {
|
||||
|
||||
// State check for allowable states for hold methods.
|
||||
if (!(sys.state & (STATE_ALARM | STATE_CHECK_MODE))) {
|
||||
|
||||
// If in CYCLE or JOG states, immediately initiate a motion HOLD.
|
||||
if (sys.state & (STATE_CYCLE | STATE_JOG)) {
|
||||
if (!(sys.suspend & (SUSPEND_MOTION_CANCEL | SUSPEND_JOG_CANCEL))) { // Block, if already holding.
|
||||
st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
|
||||
sys.step_control = STEP_CONTROL_EXECUTE_HOLD; // Initiate suspend state with active flag.
|
||||
if (sys.state == STATE_JOG) { // Jog cancelled upon any hold event, except for sleeping.
|
||||
if (!(rt_exec & EXEC_SLEEP)) { sys.suspend |= SUSPEND_JOG_CANCEL; }
|
||||
}
|
||||
}
|
||||
}
|
||||
// If IDLE, Grbl is not in motion. Simply indicate suspend state and hold is complete.
|
||||
if (sys.state == STATE_IDLE) { sys.suspend = SUSPEND_HOLD_COMPLETE; }
|
||||
|
||||
// Execute and flag a motion cancel with deceleration and return to idle. Used primarily by probing cycle
|
||||
// to halt and cancel the remainder of the motion.
|
||||
if (rt_exec & EXEC_MOTION_CANCEL) {
|
||||
// MOTION_CANCEL only occurs during a CYCLE, but a HOLD and SAFETY_DOOR may been initiated beforehand
|
||||
// to hold the CYCLE. Motion cancel is valid for a single planner block motion only, while jog cancel
|
||||
// will handle and clear multiple planner block motions.
|
||||
if (!(sys.state & STATE_JOG)) { sys.suspend |= SUSPEND_MOTION_CANCEL; } // NOTE: State is STATE_CYCLE.
|
||||
}
|
||||
|
||||
// Execute a feed hold with deceleration, if required. Then, suspend system.
|
||||
if (rt_exec & EXEC_FEED_HOLD) {
|
||||
// Block SAFETY_DOOR, JOG, and SLEEP states from changing to HOLD state.
|
||||
if (!(sys.state & (STATE_SAFETY_DOOR | STATE_JOG | STATE_SLEEP))) { sys.state = STATE_HOLD; }
|
||||
}
|
||||
|
||||
// Execute a safety door stop with a feed hold and disable spindle/coolant.
|
||||
// NOTE: Safety door differs from feed holds by stopping everything no matter state, disables powered
|
||||
// devices (spindle/coolant), and blocks resuming until switch is re-engaged.
|
||||
if (rt_exec & EXEC_SAFETY_DOOR) {
|
||||
report_feedback_message(MESSAGE_SAFETY_DOOR_AJAR);
|
||||
// If jogging, block safety door methods until jog cancel is complete. Just flag that it happened.
|
||||
if (!(sys.suspend & SUSPEND_JOG_CANCEL)) {
|
||||
// Check if the safety re-opened during a restore parking motion only. Ignore if
|
||||
// already retracting, parked or in sleep state.
|
||||
if (sys.state == STATE_SAFETY_DOOR) {
|
||||
if (sys.suspend & SUSPEND_INITIATE_RESTORE) { // Actively restoring
|
||||
#ifdef PARKING_ENABLE
|
||||
// Set hold and reset appropriate control flags to restart parking sequence.
|
||||
if (sys.step_control & STEP_CONTROL_EXECUTE_SYS_MOTION) {
|
||||
st_update_plan_block_parameters(); // Notify stepper module to recompute for hold deceleration.
|
||||
sys.step_control = (STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION);
|
||||
sys.suspend &= ~(SUSPEND_HOLD_COMPLETE);
|
||||
} // else NO_MOTION is active.
|
||||
#endif
|
||||
sys.suspend &= ~(SUSPEND_RETRACT_COMPLETE | SUSPEND_INITIATE_RESTORE | SUSPEND_RESTORE_COMPLETE);
|
||||
sys.suspend |= SUSPEND_RESTART_RETRACT;
|
||||
}
|
||||
}
|
||||
if (sys.state != STATE_SLEEP) { sys.state = STATE_SAFETY_DOOR; }
|
||||
}
|
||||
// NOTE: This flag doesn't change when the door closes, unlike sys.state. Ensures any parking motions
|
||||
// are executed if the door switch closes and the state returns to HOLD.
|
||||
sys.suspend |= SUSPEND_SAFETY_DOOR_AJAR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (rt_exec & EXEC_SLEEP) {
|
||||
if (sys.state == STATE_ALARM) { sys.suspend |= (SUSPEND_RETRACT_COMPLETE|SUSPEND_HOLD_COMPLETE); }
|
||||
sys.state = STATE_SLEEP;
|
||||
}
|
||||
|
||||
system_clear_exec_state_flag((EXEC_MOTION_CANCEL | EXEC_FEED_HOLD | EXEC_SAFETY_DOOR | EXEC_SLEEP));
|
||||
}
|
||||
|
||||
// Execute a cycle start by starting the stepper interrupt to begin executing the blocks in queue.
|
||||
if (rt_exec & EXEC_CYCLE_START) {
|
||||
// Block if called at same time as the hold commands: feed hold, motion cancel, and safety door.
|
||||
// Ensures auto-cycle-start doesn't resume a hold without an explicit user-input.
|
||||
if (!(rt_exec & (EXEC_FEED_HOLD | EXEC_MOTION_CANCEL | EXEC_SAFETY_DOOR))) {
|
||||
// Resume door state when parking motion has retracted and door has been closed.
|
||||
if ((sys.state == STATE_SAFETY_DOOR) && !(sys.suspend & SUSPEND_SAFETY_DOOR_AJAR)) {
|
||||
if (sys.suspend & SUSPEND_RESTORE_COMPLETE) {
|
||||
sys.state = STATE_IDLE; // Set to IDLE to immediately resume the cycle.
|
||||
} else if (sys.suspend & SUSPEND_RETRACT_COMPLETE) {
|
||||
// Flag to re-energize powered components and restore original position, if disabled by SAFETY_DOOR.
|
||||
// NOTE: For a safety door to resume, the switch must be closed, as indicated by HOLD state, and
|
||||
// the retraction execution is complete, which implies the initial feed hold is not active. To
|
||||
// restore normal operation, the restore procedures must be initiated by the following flag. Once,
|
||||
// they are complete, it will call CYCLE_START automatically to resume and exit the suspend.
|
||||
sys.suspend |= SUSPEND_INITIATE_RESTORE;
|
||||
}
|
||||
}
|
||||
// Cycle start only when IDLE or when a hold is complete and ready to resume.
|
||||
if ((sys.state == STATE_IDLE) || ((sys.state & STATE_HOLD) && (sys.suspend & SUSPEND_HOLD_COMPLETE))) {
|
||||
if (sys.state == STATE_HOLD && sys.spindle_stop_ovr) {
|
||||
sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE_CYCLE; // Set to restore in suspend routine and cycle start after.
|
||||
} else {
|
||||
// Start cycle only if queued motions exist in planner buffer and the motion is not canceled.
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP; // Restore step control to normal operation
|
||||
if (plan_get_current_block() && bit_isfalse(sys.suspend,SUSPEND_MOTION_CANCEL)) {
|
||||
sys.suspend = SUSPEND_DISABLE; // Break suspend state.
|
||||
sys.state = STATE_CYCLE;
|
||||
st_prep_buffer(); // Initialize step segment buffer before beginning cycle.
|
||||
st_wake_up();
|
||||
} else { // Otherwise, do nothing. Set and resume IDLE state.
|
||||
sys.suspend = SUSPEND_DISABLE; // Break suspend state.
|
||||
sys.state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
system_clear_exec_state_flag(EXEC_CYCLE_START);
|
||||
}
|
||||
|
||||
if (rt_exec & EXEC_CYCLE_STOP) {
|
||||
// Reinitializes the cycle plan and stepper system after a feed hold for a resume. Called by
|
||||
// realtime command execution in the main program, ensuring that the planner re-plans safely.
|
||||
// NOTE: Bresenham algorithm variables are still maintained through both the planner and stepper
|
||||
// cycle reinitializations. The stepper path should continue exactly as if nothing has happened.
|
||||
// NOTE: EXEC_CYCLE_STOP is set by the stepper subsystem when a cycle or feed hold completes.
|
||||
if ((sys.state & (STATE_HOLD|STATE_SAFETY_DOOR|STATE_SLEEP)) && !(sys.soft_limit) && !(sys.suspend & SUSPEND_JOG_CANCEL)) {
|
||||
// Hold complete. Set to indicate ready to resume. Remain in HOLD or DOOR states until user
|
||||
// has issued a resume command or reset.
|
||||
plan_cycle_reinitialize();
|
||||
if (sys.step_control & STEP_CONTROL_EXECUTE_HOLD) { sys.suspend |= SUSPEND_HOLD_COMPLETE; }
|
||||
bit_false(sys.step_control,(STEP_CONTROL_EXECUTE_HOLD | STEP_CONTROL_EXECUTE_SYS_MOTION));
|
||||
} else {
|
||||
// Motion complete. Includes CYCLE/JOG/HOMING states and jog cancel/motion cancel/soft limit events.
|
||||
// NOTE: Motion and jog cancel both immediately return to idle after the hold completes.
|
||||
if (sys.suspend & SUSPEND_JOG_CANCEL) { // For jog cancel, flush buffers and sync positions.
|
||||
sys.step_control = STEP_CONTROL_NORMAL_OP;
|
||||
plan_reset();
|
||||
st_reset();
|
||||
gc_sync_position();
|
||||
plan_sync_position();
|
||||
}
|
||||
if (sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) { // Only occurs when safety door opens during jog.
|
||||
sys.suspend &= ~(SUSPEND_JOG_CANCEL);
|
||||
sys.suspend |= SUSPEND_HOLD_COMPLETE;
|
||||
sys.state = STATE_SAFETY_DOOR;
|
||||
} else {
|
||||
sys.suspend = SUSPEND_DISABLE;
|
||||
sys.state = STATE_IDLE;
|
||||
}
|
||||
}
|
||||
system_clear_exec_state_flag(EXEC_CYCLE_STOP);
|
||||
}
|
||||
}
|
||||
|
||||
// Execute overrides.
|
||||
rt_exec = sys_rt_exec_motion_override; // Copy volatile sys_rt_exec_motion_override
|
||||
if (rt_exec) {
|
||||
system_clear_exec_motion_overrides(); // Clear all motion override flags.
|
||||
|
||||
uint8_t new_f_override = sys.f_override;
|
||||
if (rt_exec & EXEC_FEED_OVR_RESET) { new_f_override = DEFAULT_FEED_OVERRIDE; }
|
||||
if (rt_exec & EXEC_FEED_OVR_COARSE_PLUS) { new_f_override += FEED_OVERRIDE_COARSE_INCREMENT; }
|
||||
if (rt_exec & EXEC_FEED_OVR_COARSE_MINUS) { new_f_override -= FEED_OVERRIDE_COARSE_INCREMENT; }
|
||||
if (rt_exec & EXEC_FEED_OVR_FINE_PLUS) { new_f_override += FEED_OVERRIDE_FINE_INCREMENT; }
|
||||
if (rt_exec & EXEC_FEED_OVR_FINE_MINUS) { new_f_override -= FEED_OVERRIDE_FINE_INCREMENT; }
|
||||
new_f_override = MIN(new_f_override,MAX_FEED_RATE_OVERRIDE);
|
||||
new_f_override = MAX(new_f_override,MIN_FEED_RATE_OVERRIDE);
|
||||
|
||||
uint8_t new_r_override = sys.r_override;
|
||||
if (rt_exec & EXEC_RAPID_OVR_RESET) { new_r_override = DEFAULT_RAPID_OVERRIDE; }
|
||||
if (rt_exec & EXEC_RAPID_OVR_MEDIUM) { new_r_override = RAPID_OVERRIDE_MEDIUM; }
|
||||
if (rt_exec & EXEC_RAPID_OVR_LOW) { new_r_override = RAPID_OVERRIDE_LOW; }
|
||||
|
||||
if ((new_f_override != sys.f_override) || (new_r_override != sys.r_override)) {
|
||||
sys.f_override = new_f_override;
|
||||
sys.r_override = new_r_override;
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
plan_update_velocity_profile_parameters();
|
||||
plan_cycle_reinitialize();
|
||||
}
|
||||
}
|
||||
|
||||
rt_exec = sys_rt_exec_accessory_override;
|
||||
if (rt_exec) {
|
||||
system_clear_exec_accessory_overrides(); // Clear all accessory override flags.
|
||||
|
||||
// NOTE: Unlike motion overrides, spindle overrides do not require a planner reinitialization.
|
||||
uint8_t last_s_override = sys.spindle_speed_ovr;
|
||||
if (rt_exec & EXEC_SPINDLE_OVR_RESET) { last_s_override = DEFAULT_SPINDLE_SPEED_OVERRIDE; }
|
||||
if (rt_exec & EXEC_SPINDLE_OVR_COARSE_PLUS) { last_s_override += SPINDLE_OVERRIDE_COARSE_INCREMENT; }
|
||||
if (rt_exec & EXEC_SPINDLE_OVR_COARSE_MINUS) { last_s_override -= SPINDLE_OVERRIDE_COARSE_INCREMENT; }
|
||||
if (rt_exec & EXEC_SPINDLE_OVR_FINE_PLUS) { last_s_override += SPINDLE_OVERRIDE_FINE_INCREMENT; }
|
||||
if (rt_exec & EXEC_SPINDLE_OVR_FINE_MINUS) { last_s_override -= SPINDLE_OVERRIDE_FINE_INCREMENT; }
|
||||
last_s_override = MIN(last_s_override,MAX_SPINDLE_SPEED_OVERRIDE);
|
||||
last_s_override = MAX(last_s_override,MIN_SPINDLE_SPEED_OVERRIDE);
|
||||
|
||||
if (last_s_override != sys.spindle_speed_ovr) {
|
||||
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
sys.spindle_speed_ovr = last_s_override;
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
}
|
||||
|
||||
if (rt_exec & EXEC_SPINDLE_OVR_STOP) {
|
||||
// Spindle stop override allowed only while in HOLD state.
|
||||
// NOTE: Report counters are set in spindle_set_state() when spindle stop is executed.
|
||||
if (sys.state == STATE_HOLD) {
|
||||
if (!(sys.spindle_stop_ovr)) { sys.spindle_stop_ovr = SPINDLE_STOP_OVR_INITIATE; }
|
||||
else if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_ENABLED) { sys.spindle_stop_ovr |= SPINDLE_STOP_OVR_RESTORE; }
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: Since coolant state always performs a planner sync whenever it changes, the current
|
||||
// run state can be determined by checking the parser state.
|
||||
if (rt_exec & (EXEC_COOLANT_FLOOD_OVR_TOGGLE | EXEC_COOLANT_MIST_OVR_TOGGLE)) {
|
||||
if ((sys.state == STATE_IDLE) || (sys.state & (STATE_CYCLE | STATE_HOLD))) {
|
||||
uint8_t coolant_state = gc_state.modal.coolant;
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
if (rt_exec & EXEC_COOLANT_FLOOD_OVR_TOGGLE)
|
||||
{
|
||||
if (coolant_state & COOLANT_FLOOD_ENABLE) {
|
||||
bit_false(coolant_state,COOLANT_FLOOD_ENABLE);
|
||||
}
|
||||
else {
|
||||
coolant_state |= COOLANT_FLOOD_ENABLE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
if (rt_exec & EXEC_COOLANT_MIST_OVR_TOGGLE) {
|
||||
if (coolant_state & COOLANT_MIST_ENABLE) {
|
||||
bit_false(coolant_state,COOLANT_MIST_ENABLE);
|
||||
}
|
||||
else {
|
||||
coolant_state |= COOLANT_MIST_ENABLE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
coolant_set_state(coolant_state); // Report counter set in coolant_set_state().
|
||||
gc_state.modal.coolant = coolant_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (sys_rt_exec_debug) {
|
||||
report_realtime_debug();
|
||||
sys_rt_exec_debug = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Reload step segment buffer
|
||||
if (sys.state & (STATE_CYCLE | STATE_HOLD | STATE_SAFETY_DOOR | STATE_HOMING | STATE_SLEEP| STATE_JOG)) {
|
||||
st_prep_buffer();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Handles Grbl system suspend procedures, such as feed hold, safety door, and parking motion.
|
||||
// The system will enter this loop, create local variables for suspend tasks, and return to
|
||||
// whatever function that invoked the suspend, such that Grbl resumes normal operation.
|
||||
// This function is written in a way to promote custom parking motions. Simply use this as a
|
||||
// template
|
||||
static void protocol_exec_rt_suspend()
|
||||
{
|
||||
#ifdef PARKING_ENABLE
|
||||
// Declare and initialize parking local variables
|
||||
float restore_target[N_AXIS];
|
||||
float parking_target[N_AXIS];
|
||||
float retract_waypoint = PARKING_PULLOUT_INCREMENT;
|
||||
plan_line_data_t plan_data;
|
||||
plan_line_data_t *pl_data = &plan_data;
|
||||
memset(pl_data,0,sizeof(plan_line_data_t));
|
||||
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
pl_data->line_number = PARKING_MOTION_LINE_NUMBER;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
plan_block_t *block = plan_get_current_block();
|
||||
uint8_t restore_condition;
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
float restore_spindle_speed;
|
||||
if (block == NULL) {
|
||||
restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant);
|
||||
restore_spindle_speed = gc_state.spindle_speed;
|
||||
} else {
|
||||
restore_condition = block->condition;
|
||||
restore_spindle_speed = block->spindle_speed;
|
||||
}
|
||||
#ifdef DISABLE_LASER_DURING_HOLD
|
||||
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
if (block == NULL) { restore_condition = (gc_state.modal.spindle | gc_state.modal.coolant); }
|
||||
else { restore_condition = block->condition; }
|
||||
#endif
|
||||
|
||||
while (sys.suspend) {
|
||||
|
||||
if (sys.abort) { return; }
|
||||
|
||||
// Block until initial hold is complete and the machine has stopped motion.
|
||||
if (sys.suspend & SUSPEND_HOLD_COMPLETE) {
|
||||
|
||||
// Parking manager. Handles de/re-energizing, switch state checks, and parking motions for
|
||||
// the safety door and sleep states.
|
||||
if (sys.state & (STATE_SAFETY_DOOR | STATE_SLEEP)) {
|
||||
|
||||
// Handles retraction motions and de-energizing.
|
||||
if (bit_isfalse(sys.suspend,SUSPEND_RETRACT_COMPLETE)) {
|
||||
|
||||
// Ensure any prior spindle stop override is disabled at start of safety door routine.
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED;
|
||||
|
||||
#ifndef PARKING_ENABLE
|
||||
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
coolant_set_state(COOLANT_DISABLE); // De-energize
|
||||
|
||||
#else
|
||||
|
||||
// Get current position and store restore location and spindle retract waypoint.
|
||||
system_convert_array_steps_to_mpos(parking_target,sys_position);
|
||||
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
|
||||
memcpy(restore_target,parking_target,sizeof(parking_target));
|
||||
retract_waypoint += restore_target[PARKING_AXIS];
|
||||
retract_waypoint = MIN(retract_waypoint,PARKING_TARGET);
|
||||
}
|
||||
|
||||
// Execute slow pull-out parking retract motion. Parking requires homing enabled, the
|
||||
// current location not exceeding the parking target location, and laser mode disabled.
|
||||
// NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
if ((bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) &&
|
||||
(parking_target[PARKING_AXIS] < PARKING_TARGET) &&
|
||||
bit_isfalse(settings.flags,BITFLAG_LASER_MODE) &&
|
||||
(sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
|
||||
#else
|
||||
if ((bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)) &&
|
||||
(parking_target[PARKING_AXIS] < PARKING_TARGET) &&
|
||||
bit_isfalse(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
#endif
|
||||
// Retract spindle by pullout distance. Ensure retraction motion moves away from
|
||||
// the workpiece and waypoint motion doesn't exceed the parking target location.
|
||||
if (parking_target[PARKING_AXIS] < retract_waypoint) {
|
||||
parking_target[PARKING_AXIS] = retract_waypoint;
|
||||
pl_data->feed_rate = PARKING_PULLOUT_RATE;
|
||||
pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Retain accessory state
|
||||
pl_data->spindle_speed = restore_spindle_speed;
|
||||
mc_parking_motion(parking_target, pl_data);
|
||||
}
|
||||
|
||||
// NOTE: Clear accessory state after retract and after an aborted restore motion.
|
||||
pl_data->condition = (PL_COND_FLAG_SYSTEM_MOTION|PL_COND_FLAG_NO_FEED_OVERRIDE);
|
||||
pl_data->spindle_speed = 0.0;
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
coolant_set_state(COOLANT_DISABLE); // De-energize
|
||||
|
||||
// Execute fast parking retract motion to parking target location.
|
||||
if (parking_target[PARKING_AXIS] < PARKING_TARGET) {
|
||||
parking_target[PARKING_AXIS] = PARKING_TARGET;
|
||||
pl_data->feed_rate = PARKING_RATE;
|
||||
mc_parking_motion(parking_target, pl_data);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Parking motion not possible. Just disable the spindle and coolant.
|
||||
// NOTE: Laser mode does not start a parking motion to ensure the laser stops immediately.
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
coolant_set_state(COOLANT_DISABLE); // De-energize
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
sys.suspend &= ~(SUSPEND_RESTART_RETRACT);
|
||||
sys.suspend |= SUSPEND_RETRACT_COMPLETE;
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
if (sys.state == STATE_SLEEP) {
|
||||
report_feedback_message(MESSAGE_SLEEP_MODE);
|
||||
// Spindle and coolant should already be stopped, but do it again just to be sure.
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
coolant_set_state(COOLANT_DISABLE); // De-energize
|
||||
st_go_idle(); // Disable steppers
|
||||
while (!(sys.abort)) { protocol_exec_rt_system(); } // Do nothing until reset.
|
||||
return; // Abort received. Return to re-initialize.
|
||||
}
|
||||
|
||||
// Allows resuming from parking/safety door. Actively checks if safety door is closed and ready to resume.
|
||||
if (sys.state == STATE_SAFETY_DOOR) {
|
||||
if (!(system_check_safety_door_ajar())) {
|
||||
sys.suspend &= ~(SUSPEND_SAFETY_DOOR_AJAR); // Reset door ajar flag to denote ready to resume.
|
||||
}
|
||||
}
|
||||
|
||||
// Handles parking restore and safety door resume.
|
||||
if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
|
||||
|
||||
#ifdef PARKING_ENABLE
|
||||
// Execute fast restore motion to the pull-out position. Parking requires homing enabled.
|
||||
// NOTE: State is will remain DOOR, until the de-energizing and retract is complete.
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
if (((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
|
||||
(sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
|
||||
#else
|
||||
if ((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
|
||||
#endif
|
||||
// Check to ensure the motion doesn't move below pull-out position.
|
||||
if (parking_target[PARKING_AXIS] <= PARKING_TARGET) {
|
||||
parking_target[PARKING_AXIS] = retract_waypoint;
|
||||
pl_data->feed_rate = PARKING_RATE;
|
||||
mc_parking_motion(parking_target, pl_data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Delayed Tasks: Restart spindle and coolant, delay to power-up, then resume cycle.
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
// Block if safety door re-opened during prior restore actions.
|
||||
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
|
||||
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
// When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
|
||||
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
} else {
|
||||
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
|
||||
delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DELAY_MODE_SYS_SUSPEND);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (gc_state.modal.coolant != COOLANT_DISABLE) {
|
||||
// Block if safety door re-opened during prior restore actions.
|
||||
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
|
||||
// NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin.
|
||||
coolant_set_state((restore_condition & (PL_COND_FLAG_COOLANT_FLOOD | PL_COND_FLAG_COOLANT_FLOOD)));
|
||||
delay_sec(SAFETY_DOOR_COOLANT_DELAY, DELAY_MODE_SYS_SUSPEND);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PARKING_ENABLE
|
||||
// Execute slow plunge motion from pull-out position to resume position.
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
if (((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) &&
|
||||
(sys.override_ctrl == OVERRIDE_PARKING_MOTION)) {
|
||||
#else
|
||||
if ((settings.flags & (BITFLAG_HOMING_ENABLE|BITFLAG_LASER_MODE)) == BITFLAG_HOMING_ENABLE) {
|
||||
#endif
|
||||
// Block if safety door re-opened during prior restore actions.
|
||||
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
|
||||
// Regardless if the retract parking motion was a valid/safe motion or not, the
|
||||
// restore parking motion should logically be valid, either by returning to the
|
||||
// original position through valid machine space or by not moving at all.
|
||||
pl_data->feed_rate = PARKING_PULLOUT_RATE;
|
||||
pl_data->condition |= (restore_condition & PL_COND_ACCESSORY_MASK); // Restore accessory state
|
||||
pl_data->spindle_speed = restore_spindle_speed;
|
||||
mc_parking_motion(restore_target, pl_data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (bit_isfalse(sys.suspend,SUSPEND_RESTART_RETRACT)) {
|
||||
sys.suspend |= SUSPEND_RESTORE_COMPLETE;
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
|
||||
// Feed hold manager. Controls spindle stop override states.
|
||||
// NOTE: Hold ensured as completed by condition check at the beginning of suspend routine.
|
||||
if (sys.spindle_stop_ovr) {
|
||||
// Handles beginning of spindle stop
|
||||
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_INITIATE) {
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
spindle_set_state(SPINDLE_DISABLE,0.0); // De-energize
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_ENABLED; // Set stop override state to enabled, if de-energized.
|
||||
} else {
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
|
||||
}
|
||||
// Handles restoring of spindle state
|
||||
} else if (sys.spindle_stop_ovr & (SPINDLE_STOP_OVR_RESTORE | SPINDLE_STOP_OVR_RESTORE_CYCLE)) {
|
||||
if (gc_state.modal.spindle != SPINDLE_DISABLE) {
|
||||
report_feedback_message(MESSAGE_SPINDLE_RESTORE);
|
||||
if (bit_istrue(settings.flags,BITFLAG_LASER_MODE)) {
|
||||
// When in laser mode, ignore spindle spin-up delay. Set to turn on laser when cycle starts.
|
||||
bit_true(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
} else {
|
||||
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
|
||||
}
|
||||
}
|
||||
if (sys.spindle_stop_ovr & SPINDLE_STOP_OVR_RESTORE_CYCLE) {
|
||||
system_set_exec_state_flag(EXEC_CYCLE_START); // Set to resume program.
|
||||
}
|
||||
sys.spindle_stop_ovr = SPINDLE_STOP_OVR_DISABLED; // Clear stop override state
|
||||
}
|
||||
} else {
|
||||
// Handles spindle state during hold. NOTE: Spindle speed overrides may be altered during hold state.
|
||||
// NOTE: STEP_CONTROL_UPDATE_SPINDLE_PWM is automatically reset upon resume in step generator.
|
||||
if (bit_istrue(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM)) {
|
||||
spindle_set_state((restore_condition & (PL_COND_FLAG_SPINDLE_CW | PL_COND_FLAG_SPINDLE_CCW)), restore_spindle_speed);
|
||||
bit_false(sys.step_control, STEP_CONTROL_UPDATE_SPINDLE_PWM);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
protocol_exec_rt_system();
|
||||
|
||||
}
|
||||
}
|
||||
|
56
Grbl_Esp32-master/Grbl_Esp32/protocol.h
Normal file
56
Grbl_Esp32-master/Grbl_Esp32/protocol.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
protocol.h - controls Grbl execution protocol and procedures
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef protocol_h
|
||||
#define protocol_h
|
||||
|
||||
// Line buffer size from the serial input stream to be executed.
|
||||
// NOTE: Not a problem except for extreme cases, but the line buffer size can be too small
|
||||
// and g-code blocks can get truncated. Officially, the g-code standards support up to 256
|
||||
// characters. In future versions, this will be increased, when we know how much extra
|
||||
// memory space we can invest into here or we re-write the g-code parser not to have this
|
||||
// buffer.
|
||||
#ifndef LINE_BUFFER_SIZE
|
||||
#define LINE_BUFFER_SIZE 80
|
||||
#endif
|
||||
|
||||
// Starts Grbl main loop. It handles all incoming characters from the serial port and executes
|
||||
// them as they complete. It is also responsible for finishing the initialization procedures.
|
||||
void protocol_main_loop();
|
||||
|
||||
// Checks and executes a realtime command at various stop points in main program
|
||||
void protocol_execute_realtime();
|
||||
void protocol_exec_rt_system();
|
||||
|
||||
// Executes the auto cycle feature, if enabled.
|
||||
void protocol_auto_cycle_start();
|
||||
|
||||
// Block until all buffered steps are executed
|
||||
void protocol_buffer_synchronize();
|
||||
|
||||
// Executes the auto cycle feature, if enabled.
|
||||
void protocol_auto_cycle_start();
|
||||
|
||||
#endif
|
||||
|
874
Grbl_Esp32-master/Grbl_Esp32/report.cpp
Normal file
874
Grbl_Esp32-master/Grbl_Esp32/report.cpp
Normal file
@ -0,0 +1,874 @@
|
||||
/*
|
||||
report.c - reporting and messaging methods
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2012-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file functions as the primary feedback interface for Grbl. Any outgoing data, such
|
||||
as the protocol status messages, feedback messages, and status reports, are stored here.
|
||||
For the most part, these functions primarily are called from protocol.c methods. If a
|
||||
different style feedback is desired (i.e. JSON), then a user can change these following
|
||||
methods to accommodate their needs.
|
||||
|
||||
|
||||
ESP32 Notes:
|
||||
|
||||
Major rewrite to fix issues with BlueTooth. As described here there is a
|
||||
when you try to send data a single byte at a time using SerialBT.write(...).
|
||||
https://github.com/espressif/arduino-esp32/issues/1537
|
||||
|
||||
A solution is to send messages as a string using SerialBT.print(...). Use
|
||||
a short delay after each send. Therefore this file needed to be rewritten
|
||||
to work that way. AVR Grbl was written to be super efficient to give it
|
||||
good performance. This is far less efficient, but the ESP32 can handle it.
|
||||
Do not use this version of the file with AVR Grbl.
|
||||
|
||||
ESP32 discussion here ... https://github.com/bdring/Grbl_Esp32/issues/3
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#define DEFAULTBUFFERSIZE 64
|
||||
|
||||
// this is a generic send function that everything should use, so interfaces could be added (Bluetooth, etc)
|
||||
void grbl_send(uint8_t client, const char *text)
|
||||
{
|
||||
if (client == CLIENT_INPUT) return;
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
if (SerialBT.hasClient() && ( client == CLIENT_BT || client == CLIENT_ALL ) )
|
||||
{
|
||||
|
||||
SerialBT.print(text);
|
||||
//delay(10); // possible fix for dropped characters
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_OUT)
|
||||
if ( client == CLIENT_WEBUI || client == CLIENT_ALL )
|
||||
Serial2Socket.write((const uint8_t*)text, strlen(text));
|
||||
#endif
|
||||
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_TELNET)
|
||||
if ( client == CLIENT_TELNET || client == CLIENT_ALL ){
|
||||
telnet_server.write((const uint8_t*)text, strlen(text));
|
||||
}
|
||||
#endif
|
||||
|
||||
if ( client == CLIENT_SERIAL || client == CLIENT_ALL )
|
||||
Serial.print(text);
|
||||
}
|
||||
|
||||
// This is a formating version of the grbl_send(CLIENT_ALL,...) function that work like printf
|
||||
void grbl_sendf(uint8_t client, const char *format, ...)
|
||||
{
|
||||
if (client == CLIENT_INPUT) return;
|
||||
char loc_buf[64];
|
||||
char * temp = loc_buf;
|
||||
va_list arg;
|
||||
va_list copy;
|
||||
va_start(arg, format);
|
||||
va_copy(copy, arg);
|
||||
size_t len = vsnprintf(NULL, 0, format, arg);
|
||||
va_end(copy);
|
||||
if(len >= sizeof(loc_buf)){
|
||||
temp = new char[len+1];
|
||||
if(temp == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
len = vsnprintf(temp, len+1, format, arg);
|
||||
grbl_send(client, temp);
|
||||
va_end(arg);
|
||||
if(len > 64){
|
||||
delete[] temp;
|
||||
}
|
||||
}
|
||||
|
||||
//function to notify
|
||||
void grbl_notify(const char *title, const char *msg){
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
notificationsservice.sendMSG(title, msg);
|
||||
#endif
|
||||
}
|
||||
|
||||
void grbl_notifyf(const char *title, const char *format, ...){
|
||||
char loc_buf[64];
|
||||
char * temp = loc_buf;
|
||||
va_list arg;
|
||||
va_list copy;
|
||||
va_start(arg, format);
|
||||
va_copy(copy, arg);
|
||||
size_t len = vsnprintf(NULL, 0, format, arg);
|
||||
va_end(copy);
|
||||
if(len >= sizeof(loc_buf)){
|
||||
temp = new char[len+1];
|
||||
if(temp == NULL) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
len = vsnprintf(temp, len+1, format, arg);
|
||||
grbl_notify(title, temp);
|
||||
va_end(arg);
|
||||
if(len > 64){
|
||||
delete[] temp;
|
||||
}
|
||||
}
|
||||
|
||||
// formats axis values into a string and returns that string in rpt
|
||||
static void report_util_axis_values(float *axis_value, char *rpt) {
|
||||
uint8_t idx;
|
||||
char axisVal[10];
|
||||
float unit_conv = 1.0; // unit conversion multiplier..default is mm
|
||||
|
||||
rpt[0] = '\0';
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES))
|
||||
unit_conv = 1.0 / MM_PER_INCH;
|
||||
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES))
|
||||
sprintf(axisVal, "%4.4f", axis_value[idx] * unit_conv); // Report inches to 4 decimals
|
||||
else
|
||||
sprintf(axisVal, "%4.3f", axis_value[idx] * unit_conv); // Report mm to 3 decimals
|
||||
|
||||
strcat(rpt, axisVal);
|
||||
|
||||
if (idx < (N_AXIS-1))
|
||||
{
|
||||
strcat(rpt, ",");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void get_state(char *foo)
|
||||
{
|
||||
// pad them to same length
|
||||
switch (sys.state) {
|
||||
case STATE_IDLE: strcpy(foo," Idle ");; break;
|
||||
case STATE_CYCLE: strcpy(foo," Run "); break;
|
||||
case STATE_HOLD: strcpy(foo," Hold "); break;
|
||||
case STATE_HOMING: strcpy(foo," Home "); break;
|
||||
case STATE_ALARM: strcpy(foo," Alarm"); break;
|
||||
case STATE_CHECK_MODE: strcpy(foo," Check"); break;
|
||||
case STATE_SAFETY_DOOR: strcpy(foo," Door "); break;
|
||||
default:strcpy(foo," ? "); break;
|
||||
}
|
||||
}
|
||||
|
||||
// Handles the primary confirmation protocol response for streaming interfaces and human-feedback.
|
||||
// For every incoming line, this method responds with an 'ok' for a successful command or an
|
||||
// 'error:' to indicate some error event with the line or some critical system error during
|
||||
// operation. Errors events can originate from the g-code parser, settings module, or asynchronously
|
||||
// from a critical error, such as a triggered hard limit. Interface should always monitor for these
|
||||
// responses.
|
||||
void report_status_message(uint8_t status_code, uint8_t client)
|
||||
{
|
||||
switch(status_code) {
|
||||
case STATUS_OK: // STATUS_OK
|
||||
#ifdef ENABLE_SD_CARD
|
||||
if (get_sd_state(false) == SDCARD_BUSY_PRINTING)
|
||||
SD_ready_next = true; // flag so system_execute_line() will send the next line
|
||||
else
|
||||
grbl_send(client,"ok\r\n");
|
||||
#else
|
||||
grbl_send(client,"ok\r\n");
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
#ifdef ENABLE_SD_CARD
|
||||
// do we need to stop a running SD job?
|
||||
if (get_sd_state(false) == SDCARD_BUSY_PRINTING) {
|
||||
if (status_code == STATUS_GCODE_UNSUPPORTED_COMMAND) {
|
||||
grbl_sendf(client, "error:%d\r\n", status_code); // most senders seem to tolerate this error and keep on going
|
||||
grbl_sendf(CLIENT_ALL, "error:%d in SD file at line %d\r\n", status_code, sd_get_current_line_number());
|
||||
// don't close file
|
||||
}
|
||||
else {
|
||||
grbl_notifyf("SD print error", "Error:%d during SD file at line: %d", status_code, sd_get_current_line_number());
|
||||
grbl_sendf(CLIENT_ALL, "error:%d in SD file at line %d\r\n", status_code, sd_get_current_line_number());
|
||||
closeFile();
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
grbl_sendf(client, "error:%d\r\n", status_code);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Prints alarm messages.
|
||||
void report_alarm_message(uint8_t alarm_code)
|
||||
{
|
||||
grbl_sendf(CLIENT_ALL, "ALARM:%d\r\n", alarm_code); // OK to send to all clients
|
||||
delay_ms(500); // Force delay to ensure message clears serial write buffer.
|
||||
}
|
||||
|
||||
// Prints feedback messages. This serves as a centralized method to provide additional
|
||||
// user feedback for things that are not of the status/alarm message protocol. These are
|
||||
// messages such as setup warnings, switch toggling, and how to exit alarms.
|
||||
// NOTE: For interfaces, messages are always placed within brackets. And if silent mode
|
||||
// is installed, the message number codes are less than zero.
|
||||
void report_feedback_message(uint8_t message_code) // OK to send to all clients
|
||||
{
|
||||
switch(message_code) {
|
||||
case MESSAGE_CRITICAL_EVENT:
|
||||
grbl_send(CLIENT_ALL,"[MSG:Reset to continue]\r\n"); break;
|
||||
case MESSAGE_ALARM_LOCK:
|
||||
grbl_send(CLIENT_ALL, "[MSG:'$H'|'$X' to unlock]\r\n"); break;
|
||||
case MESSAGE_ALARM_UNLOCK:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Caution: Unlocked]\r\n"); break;
|
||||
case MESSAGE_ENABLED:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Enabled]\r\n"); break;
|
||||
case MESSAGE_DISABLED:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Disabled]\r\n"); break;
|
||||
case MESSAGE_SAFETY_DOOR_AJAR:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Check Door]\r\n"); break;
|
||||
case MESSAGE_CHECK_LIMITS:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Check Limits]\r\n"); break;
|
||||
case MESSAGE_PROGRAM_END:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Pgm End]\r\n"); break;
|
||||
case MESSAGE_RESTORE_DEFAULTS:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Restoring defaults]\r\n"); break;
|
||||
case MESSAGE_SPINDLE_RESTORE:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Restoring spindle]\r\n"); break;
|
||||
case MESSAGE_SLEEP_MODE:
|
||||
grbl_send(CLIENT_ALL, "[MSG:Sleeping]\r\n"); break;
|
||||
#ifdef ENABLE_SD_CARD
|
||||
case MESSAGE_SD_FILE_QUIT:
|
||||
grbl_notifyf("SD print canceled", "Reset during SD file at line: %d", sd_get_current_line_number());
|
||||
grbl_sendf(CLIENT_ALL, "[MSG:Reset during SD file at line: %d]\r\n", sd_get_current_line_number()); break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Welcome message
|
||||
void report_init_message(uint8_t client)
|
||||
{
|
||||
#ifdef CPU_MAP_NAME
|
||||
grbl_send(client,"[MSG:Using cpu_map..." CPU_MAP_NAME "]\r\n");
|
||||
#endif
|
||||
grbl_send(client,"\r\nGrbl " GRBL_VERSION " ['$' for help]\r\n");
|
||||
}
|
||||
|
||||
// Grbl help message
|
||||
void report_grbl_help(uint8_t client) {
|
||||
grbl_send(client,"[HLP:$$ $# $G $I $N $x=val $Nx=line $J=line $SLP $C $X $H $F ~ ! ? ctrl-x]\r\n");
|
||||
}
|
||||
|
||||
|
||||
// Grbl global settings print out.
|
||||
// NOTE: The numbering scheme here must correlate to storing in settings.c
|
||||
void report_grbl_settings(uint8_t client) {
|
||||
// Print Grbl settings.
|
||||
char setting[20];
|
||||
char rpt[1000];
|
||||
|
||||
rpt[0] = '\0';
|
||||
|
||||
sprintf(setting, "$0=%d\r\n", settings.pulse_microseconds); strcat(rpt, setting);
|
||||
sprintf(setting, "$1=%d\r\n", settings.stepper_idle_lock_time); strcat(rpt, setting);
|
||||
sprintf(setting, "$2=%d\r\n", settings.step_invert_mask); strcat(rpt, setting);
|
||||
sprintf(setting, "$3=%d\r\n", settings.dir_invert_mask); strcat(rpt, setting);
|
||||
sprintf(setting, "$4=%d\r\n", bit_istrue(settings.flags,BITFLAG_INVERT_ST_ENABLE)); strcat(rpt, setting);
|
||||
sprintf(setting, "$5=%d\r\n", bit_istrue(settings.flags,BITFLAG_INVERT_LIMIT_PINS)); strcat(rpt, setting);
|
||||
sprintf(setting, "$6=%d\r\n", bit_istrue(settings.flags,BITFLAG_INVERT_PROBE_PIN)); strcat(rpt, setting);
|
||||
sprintf(setting, "$10=%d\r\n", settings.status_report_mask); strcat(rpt, setting);
|
||||
|
||||
sprintf(setting, "$11=%4.3f\r\n", settings.junction_deviation); strcat(rpt, setting);
|
||||
sprintf(setting, "$12=%4.3f\r\n", settings.arc_tolerance); strcat(rpt, setting);
|
||||
|
||||
|
||||
sprintf(setting, "$13=%d\r\n", bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)); strcat(rpt, setting);
|
||||
sprintf(setting, "$20=%d\r\n", bit_istrue(settings.flags,BITFLAG_SOFT_LIMIT_ENABLE)); strcat(rpt, setting);
|
||||
sprintf(setting, "$21=%d\r\n", bit_istrue(settings.flags,BITFLAG_HARD_LIMIT_ENABLE)); strcat(rpt, setting);
|
||||
sprintf(setting, "$22=%d\r\n", bit_istrue(settings.flags,BITFLAG_HOMING_ENABLE)); strcat(rpt, setting);
|
||||
sprintf(setting, "$23=%d\r\n", settings.homing_dir_mask); strcat(rpt, setting);
|
||||
|
||||
sprintf(setting, "$24=%4.3f\r\n", settings.homing_feed_rate); strcat(rpt, setting);
|
||||
sprintf(setting, "$25=%4.3f\r\n", settings.homing_seek_rate); strcat(rpt, setting);
|
||||
|
||||
sprintf(setting, "$26=%d\r\n", settings.homing_debounce_delay); strcat(rpt, setting);
|
||||
|
||||
sprintf(setting, "$27=%4.3f\r\n", settings.homing_pulloff); strcat(rpt, setting);
|
||||
sprintf(setting, "$30=%4.3f\r\n", settings.rpm_max); strcat(rpt, setting);
|
||||
sprintf(setting, "$31=%4.3f\r\n", settings.rpm_min); strcat(rpt, setting);
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
sprintf(setting, "$32=%d\r\n", bit_istrue(settings.flags,BITFLAG_LASER_MODE)); strcat(rpt, setting);
|
||||
#else
|
||||
strcat(rpt, "$32=0\r\n");
|
||||
#endif
|
||||
|
||||
#ifdef SHOW_EXTENDED_SETTINGS
|
||||
sprintf(setting, "$33=%5.3f\r\n", settings.spindle_pwm_freq); strcat(rpt, setting);
|
||||
sprintf(setting, "$34=%3.3f\r\n", settings.spindle_pwm_off_value); strcat(rpt, setting);
|
||||
sprintf(setting, "$35=%3.3f\r\n", settings.spindle_pwm_min_value); strcat(rpt, setting);
|
||||
sprintf(setting, "$36=%3.3f\r\n", settings.spindle_pwm_max_value); strcat(rpt, setting);
|
||||
|
||||
for (uint8_t index = 0; index<USER_SETTING_COUNT; index++) {
|
||||
sprintf(setting, "$%d=%d\r\n", 80 + index, settings.machine_int16[index]); strcat(rpt, setting);
|
||||
}
|
||||
|
||||
for (uint8_t index = 0; index<USER_SETTING_COUNT; index++) {
|
||||
sprintf(setting, "$%d=%5.3f\r\n", 90 + index, settings.machine_float[index]); strcat(rpt, setting);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Print axis settings
|
||||
uint8_t idx, set_idx;
|
||||
uint8_t val = AXIS_SETTINGS_START_VAL;
|
||||
for (set_idx=0; set_idx<AXIS_N_SETTINGS; set_idx++) {
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
switch (set_idx) {
|
||||
case 0: sprintf(setting, "$%d=%4.3f\r\n", val+idx, settings.steps_per_mm[idx]); strcat(rpt, setting); break;
|
||||
case 1: sprintf(setting, "$%d=%4.3f\r\n", val+idx, settings.max_rate[idx]); strcat(rpt, setting); break;
|
||||
case 2: sprintf(setting, "$%d=%4.3f\r\n", val+idx, settings.acceleration[idx]/(60*60)); strcat(rpt, setting); break;
|
||||
case 3: sprintf(setting, "$%d=%4.3f\r\n", val+idx, -settings.max_travel[idx]); strcat(rpt, setting); break;
|
||||
#ifdef SHOW_EXTENDED_SETTINGS
|
||||
case 4: sprintf(setting, "$%d=%4.3f\r\n", val+idx, settings.current[idx]); strcat(rpt, setting); break;
|
||||
case 5: sprintf(setting, "$%d=%4.3f\r\n", val+idx, settings.hold_current[idx]); strcat(rpt, setting); break;
|
||||
case 6: sprintf(setting, "$%d=%d\r\n", val+idx, settings.microsteps[idx]); strcat(rpt, setting); break;
|
||||
case 7: sprintf(setting, "$%d=%d\r\n", val+idx, settings.stallguard[idx]); strcat(rpt, setting); break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
val += AXIS_SETTINGS_INCREMENT;
|
||||
}
|
||||
|
||||
grbl_send(client,rpt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Prints current probe parameters. Upon a probe command, these parameters are updated upon a
|
||||
// successful probe or upon a failed probe with the G38.3 without errors command (if supported).
|
||||
// These values are retained until Grbl is power-cycled, whereby they will be re-zeroed.
|
||||
void report_probe_parameters(uint8_t client)
|
||||
{
|
||||
// Report in terms of machine position.
|
||||
float print_position[N_AXIS];
|
||||
char probe_rpt[100]; // the probe report we are building here
|
||||
char temp[60];
|
||||
|
||||
strcpy(probe_rpt, "[PRB:"); // initialize the string with the first characters
|
||||
|
||||
// get the machine position and put them into a string and append to the probe report
|
||||
system_convert_array_steps_to_mpos(print_position,sys_probe_position);
|
||||
report_util_axis_values(print_position, temp);
|
||||
strcat(probe_rpt, temp);
|
||||
|
||||
// add the success indicator and add closing characters
|
||||
sprintf(temp, ":%d]\r\n", sys.probe_succeeded);
|
||||
strcat(probe_rpt, temp);
|
||||
|
||||
grbl_send(client, probe_rpt); // send the report
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Prints Grbl NGC parameters (coordinate offsets, probing)
|
||||
void report_ngc_parameters(uint8_t client)
|
||||
{
|
||||
float coord_data[N_AXIS];
|
||||
uint8_t coord_select;
|
||||
char temp[60];
|
||||
char ngc_rpt[500];
|
||||
|
||||
ngc_rpt[0] = '\0';
|
||||
|
||||
for (coord_select = 0; coord_select <= SETTING_INDEX_NCOORD; coord_select++) {
|
||||
if (!(settings_read_coord_data(coord_select,coord_data))) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
|
||||
return;
|
||||
}
|
||||
strcat(ngc_rpt, "[G");
|
||||
switch (coord_select) {
|
||||
case 6: strcat(ngc_rpt, "28"); break;
|
||||
case 7: strcat(ngc_rpt, "30"); break;
|
||||
default:
|
||||
sprintf(temp, "%d", coord_select+54);
|
||||
strcat(ngc_rpt, temp);
|
||||
break; // G54-G59
|
||||
}
|
||||
strcat(ngc_rpt, ":");
|
||||
report_util_axis_values(coord_data, temp);
|
||||
strcat(ngc_rpt, temp);
|
||||
strcat(ngc_rpt, "]\r\n");
|
||||
}
|
||||
|
||||
strcat(ngc_rpt, "[G92:"); // Print G92,G92.1 which are not persistent in memory
|
||||
report_util_axis_values(gc_state.coord_offset, temp);
|
||||
strcat(ngc_rpt, temp);
|
||||
strcat(ngc_rpt, "]\r\n");
|
||||
strcat(ngc_rpt, "[TLO:"); // Print tool length offset value
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
sprintf(temp, "%4.3f]\r\n", gc_state.tool_length_offset * INCH_PER_MM);
|
||||
} else {
|
||||
sprintf(temp, "%4.3f]\r\n", gc_state.tool_length_offset);
|
||||
}
|
||||
strcat(ngc_rpt, temp);
|
||||
|
||||
grbl_send(client, ngc_rpt);
|
||||
|
||||
report_probe_parameters(client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Print current gcode parser mode state
|
||||
void report_gcode_modes(uint8_t client)
|
||||
{
|
||||
char temp[20];
|
||||
char modes_rpt[75];
|
||||
|
||||
|
||||
strcpy(modes_rpt, "[GC:G");
|
||||
|
||||
|
||||
if (gc_state.modal.motion >= MOTION_MODE_PROBE_TOWARD) {
|
||||
sprintf(temp, "38.%d", gc_state.modal.motion - (MOTION_MODE_PROBE_TOWARD-2));
|
||||
} else {
|
||||
sprintf(temp, "%d", gc_state.modal.motion);
|
||||
}
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
sprintf(temp, " G%d", gc_state.modal.coord_select+54);
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
sprintf(temp, " G%d", gc_state.modal.plane_select+17);
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
sprintf(temp, " G%d", 21-gc_state.modal.units);
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
sprintf(temp, " G%d", gc_state.modal.distance+90);
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
sprintf(temp, " G%d", 94-gc_state.modal.feed_rate);
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
|
||||
if (gc_state.modal.program_flow) {
|
||||
//report_util_gcode_modes_M();
|
||||
switch (gc_state.modal.program_flow) {
|
||||
case PROGRAM_FLOW_PAUSED : strcat(modes_rpt, " M0"); //serial_write('0'); break;
|
||||
// case PROGRAM_FLOW_OPTIONAL_STOP : serial_write('1'); break; // M1 is ignored and not supported.
|
||||
case PROGRAM_FLOW_COMPLETED_M2 :
|
||||
case PROGRAM_FLOW_COMPLETED_M30 :
|
||||
sprintf(temp, " M%d", gc_state.modal.program_flow);
|
||||
strcat(modes_rpt, temp);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (gc_state.modal.spindle) {
|
||||
case SPINDLE_ENABLE_CW : strcat(modes_rpt, " M3"); break;
|
||||
case SPINDLE_ENABLE_CCW : strcat(modes_rpt, " M4"); break;
|
||||
case SPINDLE_DISABLE : strcat(modes_rpt, " M5"); break;
|
||||
}
|
||||
|
||||
//report_util_gcode_modes_M(); // optional M7 and M8 should have been dealt with by here
|
||||
if (gc_state.modal.coolant) { // Note: Multiple coolant states may be active at the same time.
|
||||
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_MIST) { strcat(modes_rpt, " M7"); }
|
||||
if (gc_state.modal.coolant & PL_COND_FLAG_COOLANT_FLOOD) { strcat(modes_rpt, " M8"); }
|
||||
}
|
||||
else {
|
||||
strcat(modes_rpt, " M9");
|
||||
}
|
||||
|
||||
sprintf(temp, " T%d", gc_state.tool);
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
sprintf(temp, " F%.1f", gc_state.feed_rate);
|
||||
} else {
|
||||
sprintf(temp, " F%.0f", gc_state.feed_rate);
|
||||
}
|
||||
strcat(modes_rpt, temp);
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
sprintf(temp, " S%4.3f", gc_state.spindle_speed);
|
||||
strcat(modes_rpt, temp);
|
||||
#endif
|
||||
|
||||
strcat(modes_rpt, "]\r\n");
|
||||
|
||||
grbl_send(client, modes_rpt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Prints specified startup line
|
||||
void report_startup_line(uint8_t n, char *line, uint8_t client)
|
||||
{
|
||||
grbl_sendf(client, "$N%d=%s\r\n", n, line); // OK to send to all
|
||||
}
|
||||
|
||||
void report_execute_startup_message(char *line, uint8_t status_code, uint8_t client)
|
||||
{
|
||||
grbl_sendf(client, ">%s:", line); // OK to send to all
|
||||
report_status_message(status_code, client);
|
||||
}
|
||||
|
||||
// Prints build info line
|
||||
void report_build_info(char *line, uint8_t client)
|
||||
{
|
||||
char build_info[50];
|
||||
|
||||
strcpy(build_info, "[VER:" GRBL_VERSION "." GRBL_VERSION_BUILD ":");
|
||||
strcat(build_info, line);
|
||||
strcat(build_info, "]\r\n[OPT:");
|
||||
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
strcat(build_info,"V");
|
||||
#endif
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
strcat(build_info,"N");
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
strcat(build_info,"M"); // TODO Need to deal with M8...it could be disabled
|
||||
#endif
|
||||
#ifdef COREXY
|
||||
strcat(build_info,"C");
|
||||
#endif
|
||||
#ifdef PARKING_ENABLE
|
||||
strcat(build_info,"P");
|
||||
#endif
|
||||
#if (defined(HOMING_FORCE_SET_ORIGIN) || defined(HOMING_FORCE_POSITIVE_SPACE))
|
||||
strcat(build_info,"Z"); // homing MPOS bahavior is not the default behavior
|
||||
#endif
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
strcat(build_info,"H");
|
||||
#endif
|
||||
#ifdef LIMITS_TWO_SWITCHES_ON_AXES
|
||||
strcat(build_info,"L");
|
||||
#endif
|
||||
#ifdef ALLOW_FEED_OVERRIDE_DURING_PROBE_CYCLES
|
||||
strcat(build_info,"A");
|
||||
#endif
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
strcat(build_info,"B");
|
||||
#endif
|
||||
#ifdef ENABLE_SD_CARD
|
||||
strcat(build_info,"S");
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI)
|
||||
strcat(build_info,"W");
|
||||
#endif
|
||||
#ifndef ENABLE_RESTORE_EEPROM_WIPE_ALL // NOTE: Shown when disabled.
|
||||
strcat(build_info,"*");
|
||||
#endif
|
||||
#ifndef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS // NOTE: Shown when disabled.
|
||||
strcat(build_info,"$");
|
||||
#endif
|
||||
#ifndef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS // NOTE: Shown when disabled.
|
||||
strcat(build_info,"#");
|
||||
#endif
|
||||
#ifndef ENABLE_BUILD_INFO_WRITE_COMMAND // NOTE: Shown when disabled.
|
||||
strcat(build_info,"I");
|
||||
#endif
|
||||
#ifndef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE // NOTE: Shown when disabled.
|
||||
strcat(build_info,"E");
|
||||
#endif
|
||||
#ifndef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE // NOTE: Shown when disabled.
|
||||
strcat(build_info,"W");
|
||||
#endif
|
||||
// NOTE: Compiled values, like override increments/max/min values, may be added at some point later.
|
||||
// These will likely have a comma delimiter to separate them.
|
||||
|
||||
strcat(build_info,"]\r\n");
|
||||
grbl_send(client, build_info); // ok to send to all
|
||||
#if defined (ENABLE_WIFI)
|
||||
grbl_send(client, (char *)wifi_config.info());
|
||||
#endif
|
||||
#if defined (ENABLE_BLUETOOTH)
|
||||
grbl_send(client, (char *)bt_config.info());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Prints the character string line Grbl has received from the user, which has been pre-parsed,
|
||||
// and has been sent into protocol_execute_line() routine to be executed by Grbl.
|
||||
void report_echo_line_received(char *line, uint8_t client)
|
||||
{
|
||||
grbl_sendf(client, "[echo: %s]\r\n", line);
|
||||
}
|
||||
|
||||
// Prints real-time data. This function grabs a real-time snapshot of the stepper subprogram
|
||||
// and the actual location of the CNC machine. Users may change the following function to their
|
||||
// specific needs, but the desired real-time data report must be as short as possible. This is
|
||||
// requires as it minimizes the computational overhead and allows grbl to keep running smoothly,
|
||||
// especially during g-code programs with fast, short line segments and high frequency reports (5-20Hz).
|
||||
void report_realtime_status(uint8_t client)
|
||||
{
|
||||
uint8_t idx;
|
||||
int32_t current_position[N_AXIS]; // Copy current state of the system position variable
|
||||
memcpy(current_position,sys_position,sizeof(sys_position));
|
||||
float print_position[N_AXIS];
|
||||
|
||||
char status[200];
|
||||
char temp[80];
|
||||
|
||||
system_convert_array_steps_to_mpos(print_position,current_position);
|
||||
|
||||
// Report current machine state and sub-states
|
||||
strcpy(status, "<");
|
||||
switch (sys.state) {
|
||||
case STATE_IDLE: strcat(status, "Idle"); break;
|
||||
case STATE_CYCLE: strcat(status, "Run"); break;
|
||||
case STATE_HOLD:
|
||||
|
||||
if (!(sys.suspend & SUSPEND_JOG_CANCEL)) {
|
||||
strcat(status, "Hold:");
|
||||
if (sys.suspend & SUSPEND_HOLD_COMPLETE) { strcat(status, "0"); } // Ready to resume
|
||||
else { strcat(status, "1"); } // Actively holding
|
||||
break;
|
||||
} // Continues to print jog state during jog cancel.
|
||||
case STATE_JOG: strcat(status, "Jog"); break;
|
||||
case STATE_HOMING: strcat(status, "Home"); break;
|
||||
case STATE_ALARM: strcat(status, "Alarm"); break;
|
||||
case STATE_CHECK_MODE: strcat(status, "Check"); break;
|
||||
case STATE_SAFETY_DOOR:
|
||||
strcat(status, "Door:");
|
||||
if (sys.suspend & SUSPEND_INITIATE_RESTORE) {
|
||||
strcat(status, "3"); // Restoring
|
||||
} else {
|
||||
if (sys.suspend & SUSPEND_RETRACT_COMPLETE) {
|
||||
if (sys.suspend & SUSPEND_SAFETY_DOOR_AJAR) {
|
||||
strcat(status, "1"); // Door ajar
|
||||
} else {
|
||||
strcat(status, "0");
|
||||
} // Door closed and ready to resume
|
||||
} else {
|
||||
strcat(status, "2"); // Retracting
|
||||
}
|
||||
}
|
||||
break;
|
||||
case STATE_SLEEP: strcat(status, "Sleep"); break;
|
||||
}
|
||||
|
||||
float wco[N_AXIS];
|
||||
if (bit_isfalse(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE) ||
|
||||
(sys.report_wco_counter == 0) ) {
|
||||
for (idx=0; idx< N_AXIS; idx++) {
|
||||
// Apply work coordinate offsets and tool length offset to current position.
|
||||
wco[idx] = gc_state.coord_system[idx]+gc_state.coord_offset[idx];
|
||||
if (idx == TOOL_LENGTH_OFFSET_AXIS) { wco[idx] += gc_state.tool_length_offset; }
|
||||
if (bit_isfalse(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
|
||||
print_position[idx] -= wco[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Report machine position
|
||||
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_POSITION_TYPE)) {
|
||||
strcat(status, "|MPos:");
|
||||
} else {
|
||||
#ifdef FWD_KINEMATICS_REPORTING
|
||||
forward_kinematics(print_position);
|
||||
#endif
|
||||
strcat(status, "|WPos:");
|
||||
}
|
||||
|
||||
|
||||
report_util_axis_values(print_position, temp);
|
||||
strcat(status, temp);
|
||||
|
||||
// Returns planner and serial read buffer states.
|
||||
#ifdef REPORT_FIELD_BUFFER_STATE
|
||||
if (bit_istrue(settings.status_report_mask,BITFLAG_RT_STATUS_BUFFER_STATE)) {
|
||||
int bufsize = DEFAULTBUFFERSIZE;
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_TELNET)
|
||||
if (client == CLIENT_TELNET){
|
||||
bufsize = telnet_server.get_rx_buffer_available();
|
||||
}
|
||||
#endif //ENABLE_WIFI && ENABLE_TELNET
|
||||
#if defined(ENABLE_BLUETOOTH)
|
||||
if (client == CLIENT_BT){
|
||||
//TODO FIXME
|
||||
bufsize = 512 - SerialBT.available();
|
||||
}
|
||||
#endif //ENABLE_BLUETOOTH
|
||||
if (client == CLIENT_SERIAL){
|
||||
bufsize = serial_get_rx_buffer_available(CLIENT_SERIAL);
|
||||
}
|
||||
sprintf(temp, "|Bf:%d,%d", plan_get_block_buffer_available(), bufsize);
|
||||
strcat(status, temp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#ifdef REPORT_FIELD_LINE_NUMBERS
|
||||
// Report current line number
|
||||
plan_block_t * cur_block = plan_get_current_block();
|
||||
if (cur_block != NULL) {
|
||||
uint32_t ln = cur_block->line_number;
|
||||
if (ln > 0) {
|
||||
sprintf(temp, "|Ln:%d", ln);
|
||||
strcat(status, temp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Report realtime feed speed
|
||||
#ifdef REPORT_FIELD_CURRENT_FEED_SPEED
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
sprintf(temp, "|FS:%.1f,%.0f", st_get_realtime_rate(), sys.spindle_speed / MM_PER_INCH);
|
||||
} else {
|
||||
sprintf(temp, "|FS:%.0f,%.0f", st_get_realtime_rate(), sys.spindle_speed);
|
||||
}
|
||||
strcat(status, temp);
|
||||
#else
|
||||
if (bit_istrue(settings.flags,BITFLAG_REPORT_INCHES)) {
|
||||
sprintf(temp, "|F:%.1f", st_get_realtime_rate() / MM_PER_INCH);
|
||||
} else {
|
||||
sprintf(temp, "|F:%.0f", st_get_realtime_rate());
|
||||
}
|
||||
strcat(status, temp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef REPORT_FIELD_PIN_STATE
|
||||
uint8_t lim_pin_state = limits_get_state();
|
||||
uint8_t ctrl_pin_state = system_control_get_state();
|
||||
uint8_t prb_pin_state = probe_get_state();
|
||||
if (lim_pin_state | ctrl_pin_state | prb_pin_state) {
|
||||
strcat(status, "|Pn:");
|
||||
if (prb_pin_state) { strcat(status, "P"); }
|
||||
if (lim_pin_state) {
|
||||
if (bit_istrue(lim_pin_state,bit(X_AXIS))) { strcat(status, "X"); }
|
||||
if (bit_istrue(lim_pin_state,bit(Y_AXIS))) { strcat(status, "Y"); }
|
||||
if (bit_istrue(lim_pin_state,bit(Z_AXIS))) { strcat(status, "Z"); }
|
||||
#if (N_AXIS > A_AXIS)
|
||||
if (bit_istrue(lim_pin_state,bit(A_AXIS))) { strcat(status, "A"); }
|
||||
#endif
|
||||
#if (N_AXIS > B_AXIS)
|
||||
if (bit_istrue(lim_pin_state,bit(B_AXIS))) { strcat(status, "B"); }
|
||||
#endif
|
||||
#if (N_AXIS > C_AXIS)
|
||||
if (bit_istrue(lim_pin_state,bit(C_AXIS))) { strcat(status, "C"); }
|
||||
#endif
|
||||
}
|
||||
if (ctrl_pin_state) {
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_SAFETY_DOOR)) { strcat(status, "D"); }
|
||||
#endif
|
||||
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_RESET)) { strcat(status, "R"); }
|
||||
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_FEED_HOLD)) { strcat(status, "H"); }
|
||||
if (bit_istrue(ctrl_pin_state,CONTROL_PIN_INDEX_CYCLE_START)) { strcat(status, "S"); }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef REPORT_FIELD_WORK_COORD_OFFSET
|
||||
if (sys.report_wco_counter > 0) { sys.report_wco_counter--; }
|
||||
else {
|
||||
if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
|
||||
sys.report_wco_counter = (REPORT_WCO_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
|
||||
} else { sys.report_wco_counter = (REPORT_WCO_REFRESH_IDLE_COUNT-1); }
|
||||
if (sys.report_ovr_counter == 0) { sys.report_ovr_counter = 1; } // Set override on next report.
|
||||
strcat(status, "|WCO:");
|
||||
report_util_axis_values(wco, temp);
|
||||
strcat(status, temp);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef REPORT_FIELD_OVERRIDES
|
||||
if (sys.report_ovr_counter > 0) { sys.report_ovr_counter--; }
|
||||
else {
|
||||
if (sys.state & (STATE_HOMING | STATE_CYCLE | STATE_HOLD | STATE_JOG | STATE_SAFETY_DOOR)) {
|
||||
sys.report_ovr_counter = (REPORT_OVR_REFRESH_BUSY_COUNT-1); // Reset counter for slow refresh
|
||||
} else { sys.report_ovr_counter = (REPORT_OVR_REFRESH_IDLE_COUNT-1); }
|
||||
|
||||
sprintf(temp, "|Ov:%d,%d,%d", sys.f_override, sys.r_override, sys.spindle_speed_ovr);
|
||||
strcat(status, temp);
|
||||
|
||||
uint8_t sp_state = spindle_get_state();
|
||||
uint8_t cl_state = coolant_get_state();
|
||||
if (sp_state || cl_state) {
|
||||
strcat(status, "|A:");
|
||||
if (sp_state) { // != SPINDLE_STATE_DISABLE
|
||||
if (sp_state == SPINDLE_STATE_CW) { strcat(status, "S"); } // CW
|
||||
else { strcat(status, "C"); } // CCW
|
||||
}
|
||||
if (cl_state & COOLANT_STATE_FLOOD) { strcat(status, "F"); }
|
||||
#ifdef COOLANT_MIST_PIN // TODO Deal with M8 - Flood
|
||||
if (cl_state & COOLANT_STATE_MIST) { strcat(status, "M"); }
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_SD_CARD
|
||||
if (get_sd_state(false) == SDCARD_BUSY_PRINTING) {
|
||||
sprintf(temp, "|SD:%4.2f,", sd_report_perc_complete());
|
||||
strcat(status, temp);
|
||||
|
||||
sd_get_current_filename(temp);
|
||||
strcat(status, temp);
|
||||
}
|
||||
#endif
|
||||
|
||||
strcat(status, ">\r\n");
|
||||
|
||||
grbl_send(client, status);
|
||||
}
|
||||
|
||||
void report_realtime_steps()
|
||||
{
|
||||
uint8_t idx;
|
||||
for (idx=0; idx< N_AXIS; idx++) {
|
||||
grbl_sendf(CLIENT_ALL, "%ld\n", sys_position[idx]); // OK to send to all ... debug stuff
|
||||
}
|
||||
}
|
||||
|
||||
void report_gcode_comment(char *comment) {
|
||||
char msg[80];
|
||||
const uint8_t offset = 4; // ignore "MSG_" part of comment
|
||||
uint8_t index = offset;
|
||||
|
||||
if (strstr(comment, "MSG")) {
|
||||
while(index < strlen(comment)) {
|
||||
msg[index-offset] = comment[index];
|
||||
index++;
|
||||
}
|
||||
msg[index-offset] = 0; // null terminate
|
||||
|
||||
grbl_sendf(CLIENT_ALL, "[MSG:GCode Comment %s]\r\n",msg);
|
||||
}
|
||||
}
|
167
Grbl_Esp32-master/Grbl_Esp32/report.h
Normal file
167
Grbl_Esp32-master/Grbl_Esp32/report.h
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
report.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef report_h
|
||||
#define report_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
// Define Grbl status codes. Valid values (0-255)
|
||||
#define STATUS_OK 0
|
||||
#define STATUS_EXPECTED_COMMAND_LETTER 1
|
||||
#define STATUS_BAD_NUMBER_FORMAT 2
|
||||
#define STATUS_INVALID_STATEMENT 3
|
||||
#define STATUS_NEGATIVE_VALUE 4
|
||||
#define STATUS_SETTING_DISABLED 5
|
||||
#define STATUS_SETTING_STEP_PULSE_MIN 6
|
||||
#define STATUS_SETTING_READ_FAIL 7
|
||||
#define STATUS_IDLE_ERROR 8
|
||||
#define STATUS_SYSTEM_GC_LOCK 9
|
||||
#define STATUS_SOFT_LIMIT_ERROR 10
|
||||
#define STATUS_OVERFLOW 11
|
||||
#define STATUS_MAX_STEP_RATE_EXCEEDED 12
|
||||
#define STATUS_CHECK_DOOR 13
|
||||
#define STATUS_LINE_LENGTH_EXCEEDED 14
|
||||
#define STATUS_TRAVEL_EXCEEDED 15
|
||||
#define STATUS_INVALID_JOG_COMMAND 16
|
||||
#define STATUS_SETTING_DISABLED_LASER 17
|
||||
|
||||
#define STATUS_GCODE_UNSUPPORTED_COMMAND 20
|
||||
#define STATUS_GCODE_MODAL_GROUP_VIOLATION 21
|
||||
#define STATUS_GCODE_UNDEFINED_FEED_RATE 22
|
||||
#define STATUS_GCODE_COMMAND_VALUE_NOT_INTEGER 23
|
||||
#define STATUS_GCODE_AXIS_COMMAND_CONFLICT 24
|
||||
#define STATUS_GCODE_WORD_REPEATED 25
|
||||
#define STATUS_GCODE_NO_AXIS_WORDS 26
|
||||
#define STATUS_GCODE_INVALID_LINE_NUMBER 27
|
||||
#define STATUS_GCODE_VALUE_WORD_MISSING 28
|
||||
#define STATUS_GCODE_UNSUPPORTED_COORD_SYS 29
|
||||
#define STATUS_GCODE_G53_INVALID_MOTION_MODE 30
|
||||
#define STATUS_GCODE_AXIS_WORDS_EXIST 31
|
||||
#define STATUS_GCODE_NO_AXIS_WORDS_IN_PLANE 32
|
||||
#define STATUS_GCODE_INVALID_TARGET 33
|
||||
#define STATUS_GCODE_ARC_RADIUS_ERROR 34
|
||||
#define STATUS_GCODE_NO_OFFSETS_IN_PLANE 35
|
||||
#define STATUS_GCODE_UNUSED_WORDS 36
|
||||
#define STATUS_GCODE_G43_DYNAMIC_AXIS_ERROR 37
|
||||
#define STATUS_GCODE_MAX_VALUE_EXCEEDED 38
|
||||
#define STATUS_P_PARAM_MAX_EXCEEDED 39
|
||||
|
||||
#define STATUS_SD_FAILED_MOUNT 60 // SD Failed to mount
|
||||
#define STATUS_SD_FAILED_READ 61 // SD Failed to read file
|
||||
#define STATUS_SD_FAILED_OPEN_DIR 62 // SD card failed to open directory
|
||||
#define STATUS_SD_DIR_NOT_FOUND 63 // SD Card directory not found
|
||||
#define STATUS_SD_FILE_EMPTY 64 // SD Card directory not found
|
||||
|
||||
#define STATUS_BT_FAIL_BEGIN 70 // Bluetooth failed to start
|
||||
|
||||
|
||||
|
||||
// Define Grbl alarm codes. Valid values (1-255). 0 is reserved.
|
||||
#define ALARM_HARD_LIMIT_ERROR EXEC_ALARM_HARD_LIMIT
|
||||
#define ALARM_SOFT_LIMIT_ERROR EXEC_ALARM_SOFT_LIMIT
|
||||
#define ALARM_ABORT_CYCLE EXEC_ALARM_ABORT_CYCLE
|
||||
#define ALARM_PROBE_FAIL_INITIAL EXEC_ALARM_PROBE_FAIL_INITIAL
|
||||
#define ALARM_PROBE_FAIL_CONTACT EXEC_ALARM_PROBE_FAIL_CONTACT
|
||||
#define ALARM_HOMING_FAIL_RESET EXEC_ALARM_HOMING_FAIL_RESET
|
||||
#define ALARM_HOMING_FAIL_DOOR EXEC_ALARM_HOMING_FAIL_DOOR
|
||||
#define ALARM_HOMING_FAIL_PULLOFF EXEC_ALARM_HOMING_FAIL_PULLOFF
|
||||
#define ALARM_HOMING_FAIL_APPROACH EXEC_ALARM_HOMING_FAIL_APPROACH
|
||||
|
||||
// Define Grbl feedback message codes. Valid values (0-255).
|
||||
#define MESSAGE_CRITICAL_EVENT 1
|
||||
#define MESSAGE_ALARM_LOCK 2
|
||||
#define MESSAGE_ALARM_UNLOCK 3
|
||||
#define MESSAGE_ENABLED 4
|
||||
#define MESSAGE_DISABLED 5
|
||||
#define MESSAGE_SAFETY_DOOR_AJAR 6
|
||||
#define MESSAGE_CHECK_LIMITS 7
|
||||
#define MESSAGE_PROGRAM_END 8
|
||||
#define MESSAGE_RESTORE_DEFAULTS 9
|
||||
#define MESSAGE_SPINDLE_RESTORE 10
|
||||
#define MESSAGE_SLEEP_MODE 11
|
||||
#define MESSAGE_SD_FILE_QUIT 60 // mc_reset was called during an SD job
|
||||
|
||||
#define CLIENT_SERIAL 1
|
||||
#define CLIENT_BT 2
|
||||
#define CLIENT_WEBUI 3
|
||||
#define CLIENT_TELNET 4
|
||||
#define CLIENT_INPUT 5
|
||||
#define CLIENT_ALL 0xFF
|
||||
#define CLIENT_COUNT 5 // total number of client types regardless if they are used
|
||||
|
||||
// functions to send data to the user.
|
||||
void grbl_send(uint8_t client, const char *text);
|
||||
void grbl_sendf(uint8_t client, const char *format, ...);
|
||||
|
||||
//function to notify
|
||||
void grbl_notify(const char *title, const char *msg);
|
||||
void grbl_notifyf(const char *title, const char *format, ...);
|
||||
|
||||
// Prints system status messages.
|
||||
void report_status_message(uint8_t status_code, uint8_t client);
|
||||
void report_realtime_steps();
|
||||
|
||||
// Prints system alarm messages.
|
||||
void report_alarm_message(uint8_t alarm_code);
|
||||
|
||||
// Prints miscellaneous feedback messages.
|
||||
void report_feedback_message(uint8_t message_code);
|
||||
|
||||
// Prints welcome message
|
||||
void report_init_message(uint8_t client);
|
||||
|
||||
// Prints Grbl help and current global settings
|
||||
void report_grbl_help(uint8_t client);
|
||||
|
||||
// Prints Grbl global settings
|
||||
void report_grbl_settings(uint8_t client);
|
||||
|
||||
// Prints an echo of the pre-parsed line received right before execution.
|
||||
void report_echo_line_received(char *line, uint8_t client);
|
||||
|
||||
// Prints realtime status report
|
||||
void report_realtime_status(uint8_t client);
|
||||
|
||||
// Prints recorded probe position
|
||||
void report_probe_parameters(uint8_t client);
|
||||
|
||||
// Prints Grbl NGC parameters (coordinate offsets, probe)
|
||||
void report_ngc_parameters(uint8_t client);
|
||||
|
||||
// Prints current g-code parser mode state
|
||||
void report_gcode_modes(uint8_t client);
|
||||
|
||||
// Prints startup line when requested and executed.
|
||||
void report_startup_line(uint8_t n, char *line, uint8_t client);
|
||||
void report_execute_startup_message(char *line, uint8_t status_code, uint8_t client);
|
||||
|
||||
// Prints build info and user info
|
||||
void report_build_info(char *line, uint8_t client);
|
||||
|
||||
void report_gcode_comment(char *comment);
|
||||
|
||||
#ifdef DEBUG
|
||||
void report_realtime_debug();
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
348
Grbl_Esp32-master/Grbl_Esp32/serial.cpp
Normal file
348
Grbl_Esp32-master/Grbl_Esp32/serial.cpp
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
serial.cpp - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "commands.h"
|
||||
|
||||
#define RX_RING_BUFFER (RX_BUFFER_SIZE+1)
|
||||
#define TX_RING_BUFFER (TX_BUFFER_SIZE+1)
|
||||
|
||||
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
||||
|
||||
uint8_t serial_rx_buffer[CLIENT_COUNT][RX_RING_BUFFER];
|
||||
uint8_t serial_rx_buffer_head[CLIENT_COUNT] = {0};
|
||||
volatile uint8_t serial_rx_buffer_tail[CLIENT_COUNT] = {0};
|
||||
static TaskHandle_t serialCheckTaskHandle = 0;
|
||||
|
||||
// Returns the number of bytes available in the RX serial buffer.
|
||||
uint8_t serial_get_rx_buffer_available(uint8_t client)
|
||||
{
|
||||
uint8_t client_idx = client - 1;
|
||||
|
||||
uint8_t rtail = serial_rx_buffer_tail[client_idx]; // Copy to limit multiple calls to volatile
|
||||
if (serial_rx_buffer_head[client_idx] >= rtail) { return(RX_BUFFER_SIZE - (serial_rx_buffer_head[client_idx]-rtail)); }
|
||||
return((rtail-serial_rx_buffer_head[client_idx]-1));
|
||||
}
|
||||
|
||||
void serial_init()
|
||||
{
|
||||
Serial.begin(BAUD_RATE);
|
||||
grbl_send(CLIENT_SERIAL,"\r\n"); // create some white space after ESP32 boot info
|
||||
serialCheckTaskHandle = 0;
|
||||
// create a task to check for incoming data
|
||||
xTaskCreatePinnedToCore( serialCheckTask, // task
|
||||
"serialCheckTask", // name for task
|
||||
8192, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&serialCheckTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// this task runs and checks for data on all interfaces
|
||||
// REaltime stuff is acted upon, then characters are added to the appropriate buffer
|
||||
void serialCheckTask(void *pvParameters)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
uint8_t next_head;
|
||||
uint8_t client = CLIENT_ALL; // who send the data
|
||||
|
||||
uint8_t client_idx = 0; // index of data buffer
|
||||
|
||||
while(true) // run continuously
|
||||
{
|
||||
while (Serial.available() || inputBuffer.available()
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
|| (SerialBT.hasClient() && SerialBT.available())
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
|| Serial2Socket.available()
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_TELNET)
|
||||
|| telnet_server.available()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
client = CLIENT_SERIAL;
|
||||
data = Serial.read();
|
||||
}
|
||||
else if (inputBuffer.available()){
|
||||
client = CLIENT_INPUT;
|
||||
data = inputBuffer.read();
|
||||
}
|
||||
else
|
||||
{ //currently is wifi or BT but better to prepare both can be live
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
if(SerialBT.hasClient() && SerialBT.available()){
|
||||
client = CLIENT_BT;
|
||||
data = SerialBT.read();
|
||||
//Serial.write(data); // echo all data to serial
|
||||
} else {
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
if (Serial2Socket.available()) {
|
||||
client = CLIENT_WEBUI;
|
||||
data = Serial2Socket.read();
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_TELNET)
|
||||
if(telnet_server.available()){
|
||||
client = CLIENT_TELNET;
|
||||
data = telnet_server.read();
|
||||
}
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
client_idx = client - 1; // for zero based array
|
||||
|
||||
// Pick off realtime command characters directly from the serial stream. These characters are
|
||||
// not passed into the main buffer, but these set system state flag bits for realtime execution.
|
||||
switch (data) {
|
||||
case CMD_RESET:
|
||||
mc_reset(); // Call motion control reset routine.
|
||||
//report_init_message(client); // fool senders into thinking a reset happened.
|
||||
break;
|
||||
case CMD_STATUS_REPORT:
|
||||
report_realtime_status(client);
|
||||
break; // direct call instead of setting flag
|
||||
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
|
||||
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
|
||||
default :
|
||||
if (data > 0x7F) { // Real-time control characters are extended ACSII only.
|
||||
switch(data) {
|
||||
case CMD_SAFETY_DOOR: system_set_exec_state_flag(EXEC_SAFETY_DOOR); break; // Set as true
|
||||
case CMD_JOG_CANCEL:
|
||||
if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
|
||||
system_set_exec_state_flag(EXEC_MOTION_CANCEL);
|
||||
}
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case CMD_DEBUG_REPORT: {uint8_t sreg = SREG; cli(); bit_true(sys_rt_exec_debug,EXEC_DEBUG_REPORT); SREG = sreg;} break;
|
||||
#endif
|
||||
case CMD_FEED_OVR_RESET: system_set_exec_motion_override_flag(EXEC_FEED_OVR_RESET); break;
|
||||
case CMD_FEED_OVR_COARSE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_PLUS); break;
|
||||
case CMD_FEED_OVR_COARSE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_MINUS); break;
|
||||
case CMD_FEED_OVR_FINE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_PLUS); break;
|
||||
case CMD_FEED_OVR_FINE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_MINUS); break;
|
||||
case CMD_RAPID_OVR_RESET: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_RESET); break;
|
||||
case CMD_RAPID_OVR_MEDIUM: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_MEDIUM); break;
|
||||
case CMD_RAPID_OVR_LOW: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_LOW); break;
|
||||
case CMD_SPINDLE_OVR_RESET: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_RESET); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_MINUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS); break;
|
||||
case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break;
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
case CMD_COOLANT_FLOOD_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE); break;
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
case CMD_COOLANT_MIST_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE); break;
|
||||
#endif
|
||||
}
|
||||
// Throw away any unfound extended-ASCII character by not passing it to the serial buffer.
|
||||
} else { // Write character to buffer
|
||||
|
||||
vTaskEnterCritical(&myMutex);
|
||||
next_head = serial_rx_buffer_head[client_idx] + 1;
|
||||
if (next_head == RX_RING_BUFFER) { next_head = 0; }
|
||||
|
||||
// Write data to buffer unless it is full.
|
||||
if (next_head != serial_rx_buffer_tail[client_idx]) {
|
||||
serial_rx_buffer[client_idx][serial_rx_buffer_head[client_idx]] = data;
|
||||
serial_rx_buffer_head[client_idx] = next_head;
|
||||
}
|
||||
vTaskExitCritical(&myMutex);
|
||||
}
|
||||
} // switch data
|
||||
} // if something available
|
||||
COMMANDS::handle();
|
||||
#ifdef ENABLE_WIFI
|
||||
wifi_config.handle();
|
||||
#endif
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
bt_config.handle();
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
Serial2Socket.handle_flush();
|
||||
#endif
|
||||
vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
|
||||
} // while(true)
|
||||
}
|
||||
|
||||
// ==================== call this in main protocol loop if you want it in the main task =========
|
||||
// be sure to stop task.
|
||||
// Realtime stuff is acted upon, then characters are added to the appropriate buffer
|
||||
void serialCheck()
|
||||
{
|
||||
uint8_t data = 0;
|
||||
uint8_t next_head;
|
||||
uint8_t client = CLIENT_SERIAL; // who send the data
|
||||
|
||||
uint8_t client_idx = 0; // index of data buffer
|
||||
|
||||
|
||||
while (Serial.available() || inputBuffer.available()
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
|| (SerialBT.hasClient() && SerialBT.available())
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
|| Serial2Socket.available()
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (Serial.available())
|
||||
{
|
||||
client = CLIENT_SERIAL;
|
||||
data = Serial.read();
|
||||
}
|
||||
else if (inputBuffer.available())
|
||||
{
|
||||
client = CLIENT_INPUT;
|
||||
data = inputBuffer.read();
|
||||
}
|
||||
#if defined (ENABLE_BLUETOOTH) || (defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN))
|
||||
else
|
||||
{ //currently is wifi or BT but better to prepare both can be live
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
if(SerialBT.hasClient() && SerialBT.available()){
|
||||
client = CLIENT_BT;
|
||||
data = SerialBT.read();
|
||||
} else {
|
||||
#endif
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP) && defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
client = CLIENT_WEBUI;
|
||||
data = Serial2Socket.read();
|
||||
#endif
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
client_idx = client - 1; // for zero based array
|
||||
|
||||
// Pick off realtime command characters directly from the serial stream. These characters are
|
||||
// not passed into the main buffer, but these set system state flag bits for realtime execution.
|
||||
switch (data) {
|
||||
case CMD_RESET: mc_reset(); break; // Call motion control reset routine.
|
||||
case CMD_STATUS_REPORT:
|
||||
report_realtime_status(client);
|
||||
break; // direct call instead of setting flag
|
||||
case CMD_CYCLE_START: system_set_exec_state_flag(EXEC_CYCLE_START); break; // Set as true
|
||||
case CMD_FEED_HOLD: system_set_exec_state_flag(EXEC_FEED_HOLD); break; // Set as true
|
||||
default :
|
||||
if (data > 0x7F) { // Real-time control characters are extended ACSII only.
|
||||
switch(data) {
|
||||
case CMD_SAFETY_DOOR: system_set_exec_state_flag(EXEC_SAFETY_DOOR); break; // Set as true
|
||||
case CMD_JOG_CANCEL:
|
||||
if (sys.state & STATE_JOG) { // Block all other states from invoking motion cancel.
|
||||
system_set_exec_state_flag(EXEC_MOTION_CANCEL);
|
||||
}
|
||||
break;
|
||||
#ifdef DEBUG
|
||||
case CMD_DEBUG_REPORT: {uint8_t sreg = SREG; cli(); bit_true(sys_rt_exec_debug,EXEC_DEBUG_REPORT); SREG = sreg;} break;
|
||||
#endif
|
||||
case CMD_FEED_OVR_RESET: system_set_exec_motion_override_flag(EXEC_FEED_OVR_RESET); break;
|
||||
case CMD_FEED_OVR_COARSE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_PLUS); break;
|
||||
case CMD_FEED_OVR_COARSE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_COARSE_MINUS); break;
|
||||
case CMD_FEED_OVR_FINE_PLUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_PLUS); break;
|
||||
case CMD_FEED_OVR_FINE_MINUS: system_set_exec_motion_override_flag(EXEC_FEED_OVR_FINE_MINUS); break;
|
||||
case CMD_RAPID_OVR_RESET: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_RESET); break;
|
||||
case CMD_RAPID_OVR_MEDIUM: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_MEDIUM); break;
|
||||
case CMD_RAPID_OVR_LOW: system_set_exec_motion_override_flag(EXEC_RAPID_OVR_LOW); break;
|
||||
case CMD_SPINDLE_OVR_RESET: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_RESET); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_COARSE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_COARSE_MINUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_PLUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_PLUS); break;
|
||||
case CMD_SPINDLE_OVR_FINE_MINUS: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_FINE_MINUS); break;
|
||||
case CMD_SPINDLE_OVR_STOP: system_set_exec_accessory_override_flag(EXEC_SPINDLE_OVR_STOP); break;
|
||||
#ifdef COOLANT_FLOOD_PIN
|
||||
case CMD_COOLANT_FLOOD_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_FLOOD_OVR_TOGGLE); break;
|
||||
#endif
|
||||
#ifdef COOLANT_MIST_PIN
|
||||
case CMD_COOLANT_MIST_OVR_TOGGLE: system_set_exec_accessory_override_flag(EXEC_COOLANT_MIST_OVR_TOGGLE); break;
|
||||
#endif
|
||||
}
|
||||
// Throw away any unfound extended-ASCII character by not passing it to the serial buffer.
|
||||
} else { // Write character to buffer
|
||||
|
||||
|
||||
next_head = serial_rx_buffer_head[client_idx] + 1;
|
||||
if (next_head == RX_RING_BUFFER) { next_head = 0; }
|
||||
|
||||
// Write data to buffer unless it is full.
|
||||
if (next_head != serial_rx_buffer_tail[client_idx]) {
|
||||
serial_rx_buffer[client_idx][serial_rx_buffer_head[client_idx]] = data;
|
||||
serial_rx_buffer_head[client_idx] = next_head;
|
||||
}
|
||||
}
|
||||
} // switch data
|
||||
} // if something available
|
||||
}
|
||||
|
||||
void serial_reset_read_buffer(uint8_t client)
|
||||
{
|
||||
for (uint8_t client_num = 0; client_num <= CLIENT_COUNT; client_num++)
|
||||
{
|
||||
if (client == client_num || client == CLIENT_ALL)
|
||||
{
|
||||
serial_rx_buffer_tail[client_num-1] = serial_rx_buffer_head[client_num-1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Writes one byte to the TX serial buffer. Called by main program.
|
||||
void serial_write(uint8_t data) {
|
||||
Serial.write((char)data);
|
||||
}
|
||||
// Fetches the first byte in the serial read buffer. Called by main program.
|
||||
uint8_t serial_read(uint8_t client)
|
||||
{
|
||||
uint8_t client_idx = client - 1;
|
||||
|
||||
uint8_t tail = serial_rx_buffer_tail[client_idx]; // Temporary serial_rx_buffer_tail (to optimize for volatile)
|
||||
if (serial_rx_buffer_head[client_idx] == tail) {
|
||||
return SERIAL_NO_DATA;
|
||||
} else {
|
||||
vTaskEnterCritical(&myMutex); // make sure buffer is not modified while reading by newly read chars from the serial when we are here
|
||||
uint8_t data = serial_rx_buffer[client_idx][tail];
|
||||
|
||||
tail++;
|
||||
if (tail == RX_RING_BUFFER) { tail = 0; }
|
||||
serial_rx_buffer_tail[client_idx] = tail;
|
||||
vTaskExitCritical(&myMutex);
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
57
Grbl_Esp32-master/Grbl_Esp32/serial.h
Normal file
57
Grbl_Esp32-master/Grbl_Esp32/serial.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*
|
||||
serial.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef serial_h
|
||||
#define serial_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#ifndef RX_BUFFER_SIZE
|
||||
#define RX_BUFFER_SIZE 128
|
||||
#endif
|
||||
#ifndef TX_BUFFER_SIZE
|
||||
#ifdef USE_LINE_NUMBERS
|
||||
#define TX_BUFFER_SIZE 112
|
||||
#else
|
||||
#define TX_BUFFER_SIZE 104
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SERIAL_NO_DATA 0xff
|
||||
|
||||
// a task to read for incoming data from serial port
|
||||
void serialCheckTask(void *pvParameters);
|
||||
|
||||
void serialCheck();
|
||||
|
||||
void serial_write(uint8_t data);
|
||||
// Fetches the first byte in the serial read buffer. Called by main program.
|
||||
uint8_t serial_read(uint8_t client);
|
||||
|
||||
// See if the character is an action command like feedhold or jogging. If so, do the action and return true
|
||||
uint8_t check_action_command(uint8_t data);
|
||||
|
||||
void serial_init();
|
||||
void serial_reset_read_buffer(uint8_t client);
|
||||
|
||||
// Returns the number of bytes available in the RX serial buffer.
|
||||
uint8_t serial_get_rx_buffer_available(uint8_t client);
|
||||
|
||||
#endif
|
181
Grbl_Esp32-master/Grbl_Esp32/serial2socket.cpp
Normal file
181
Grbl_Esp32-master/Grbl_Esp32/serial2socket.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
serial2socket.cpp - serial 2 socket functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
//#include "grbl.h"
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ENABLE_WIFI) && defined(ENABLE_HTTP)
|
||||
|
||||
|
||||
#include "serial2socket.h"
|
||||
#include "web_server.h"
|
||||
#include <WebSocketsServer.h>
|
||||
#include <WiFi.h>
|
||||
Serial_2_Socket Serial2Socket;
|
||||
|
||||
|
||||
Serial_2_Socket::Serial_2_Socket(){
|
||||
_web_socket = NULL;
|
||||
_TXbufferSize = 0;
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
Serial_2_Socket::~Serial_2_Socket(){
|
||||
if (_web_socket) detachWS();
|
||||
_TXbufferSize = 0;
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
void Serial_2_Socket::begin(long speed){
|
||||
_TXbufferSize = 0;
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
|
||||
void Serial_2_Socket::end(){
|
||||
_TXbufferSize = 0;
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
|
||||
long Serial_2_Socket::baudRate(){
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Serial_2_Socket::attachWS(void * web_socket){
|
||||
if (web_socket) {
|
||||
_web_socket = web_socket;
|
||||
_TXbufferSize=0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Serial_2_Socket::detachWS(){
|
||||
_web_socket = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
Serial_2_Socket::operator bool() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
int Serial_2_Socket::available(){
|
||||
return _RXbufferSize;
|
||||
}
|
||||
|
||||
|
||||
size_t Serial_2_Socket::write(uint8_t c)
|
||||
{
|
||||
if(!_web_socket) return 0;
|
||||
write(&c,1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t Serial_2_Socket::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
if((buffer == NULL) ||(!_web_socket)) {
|
||||
if(buffer == NULL){
|
||||
log_i("[SOCKET]No buffer");
|
||||
}
|
||||
if(!_web_socket){
|
||||
log_i("[SOCKET]No socket");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#if defined(ENABLE_SERIAL2SOCKET_OUT)
|
||||
if (_TXbufferSize==0)_lastflush = millis();
|
||||
//send full line
|
||||
if (_TXbufferSize + size > TXBUFFERSIZE) flush();
|
||||
//need periodic check to force to flush in case of no end
|
||||
for (int i = 0; i < size;i++){
|
||||
_TXbuffer[_TXbufferSize] = buffer[i];
|
||||
_TXbufferSize++;
|
||||
}
|
||||
log_i("[SOCKET]buffer size %d",_TXbufferSize);
|
||||
handle_flush();
|
||||
#endif
|
||||
return size;
|
||||
}
|
||||
|
||||
int Serial_2_Socket::peek(void){
|
||||
if (_RXbufferSize > 0)return _RXbuffer[_RXbufferpos];
|
||||
else return -1;
|
||||
}
|
||||
|
||||
bool Serial_2_Socket::push (const char * data){
|
||||
#if defined(ENABLE_SERIAL2SOCKET_IN)
|
||||
int data_size = strlen(data);
|
||||
if ((data_size + _RXbufferSize) <= RXBUFFERSIZE){
|
||||
int current = _RXbufferpos + _RXbufferSize;
|
||||
if (current > RXBUFFERSIZE) current = current - RXBUFFERSIZE;
|
||||
for (int i = 0; i < data_size; i++){
|
||||
if (current > (RXBUFFERSIZE-1)) current = 0;
|
||||
_RXbuffer[current] = data[i];
|
||||
current ++;
|
||||
}
|
||||
_RXbufferSize+=strlen(data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
int Serial_2_Socket::read(void){
|
||||
if (_RXbufferSize > 0) {
|
||||
int v = _RXbuffer[_RXbufferpos];
|
||||
_RXbufferpos++;
|
||||
if (_RXbufferpos > (RXBUFFERSIZE-1))_RXbufferpos = 0;
|
||||
_RXbufferSize--;
|
||||
return v;
|
||||
} else return -1;
|
||||
}
|
||||
|
||||
void Serial_2_Socket::handle_flush() {
|
||||
if (_TXbufferSize > 0) {
|
||||
if ((_TXbufferSize>=TXBUFFERSIZE) || ((millis()- _lastflush) > FLUSHTIMEOUT)) {
|
||||
log_i("[SOCKET]need flush, buffer size %d",_TXbufferSize);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
void Serial_2_Socket::flush(void){
|
||||
if (_TXbufferSize > 0){
|
||||
//if ((((AsyncWebSocket *)_web_socket)->count() > 0) && (((AsyncWebSocket *)_web_socket)->availableForWriteAll())) {
|
||||
log_i("[SOCKET]flush data, buffer size %d",_TXbufferSize);
|
||||
((WebSocketsServer *)_web_socket)->broadcastBIN(_TXbuffer,_TXbufferSize);
|
||||
// } else {
|
||||
// log_i("[SOCKET]Cannot flush, buffer size %d",_TXbufferSize);
|
||||
// }
|
||||
//refresh timout
|
||||
_lastflush = millis();
|
||||
//reset buffer
|
||||
_TXbufferSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_WIFI
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
81
Grbl_Esp32-master/Grbl_Esp32/serial2socket.h
Normal file
81
Grbl_Esp32-master/Grbl_Esp32/serial2socket.h
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
serial2socket.h - serial 2 socket functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _SERIAL_2_SOCKET_H_
|
||||
#define _SERIAL_2_SOCKET_H_
|
||||
|
||||
#include "Print.h"
|
||||
#define TXBUFFERSIZE 1200
|
||||
#define RXBUFFERSIZE 128
|
||||
#define FLUSHTIMEOUT 500
|
||||
class Serial_2_Socket: public Print{
|
||||
public:
|
||||
Serial_2_Socket();
|
||||
~Serial_2_Socket();
|
||||
size_t write(uint8_t c);
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
|
||||
inline size_t write(const char * s)
|
||||
{
|
||||
return write((uint8_t*) s, strlen(s));
|
||||
}
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t) n);
|
||||
}
|
||||
long baudRate();
|
||||
void begin(long speed);
|
||||
void end();
|
||||
int available();
|
||||
int peek(void);
|
||||
int read(void);
|
||||
bool push (const char * data);
|
||||
void flush(void);
|
||||
void handle_flush();
|
||||
operator bool() const;
|
||||
bool attachWS(void * web_socket);
|
||||
bool detachWS();
|
||||
private:
|
||||
uint32_t _lastflush;
|
||||
void * _web_socket;
|
||||
uint8_t _TXbuffer[TXBUFFERSIZE];
|
||||
uint16_t _TXbufferSize;
|
||||
uint8_t _RXbuffer[RXBUFFERSIZE];
|
||||
uint16_t _RXbufferSize;
|
||||
uint16_t _RXbufferpos;
|
||||
};
|
||||
|
||||
|
||||
extern Serial_2_Socket Serial2Socket;
|
||||
|
||||
#endif
|
362
Grbl_Esp32-master/Grbl_Esp32/servo_axis.cpp
Normal file
362
Grbl_Esp32-master/Grbl_Esp32/servo_axis.cpp
Normal file
@ -0,0 +1,362 @@
|
||||
/*
|
||||
servo_axis.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring. This file was intended for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
See servo_axis.h for more details
|
||||
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef USE_SERVO_AXES
|
||||
|
||||
static TaskHandle_t servosSyncTaskHandle = 0;
|
||||
|
||||
#ifdef SERVO_X_PIN
|
||||
ServoAxis X_Servo_Axis(X_AXIS, SERVO_X_PIN, SERVO_X_CHANNEL_NUM);
|
||||
#endif
|
||||
#ifdef SERVO_Y_PIN
|
||||
ServoAxis Y_Servo_Axis(Y_AXIS, SERVO_Y_PIN, SERVO_Y_CHANNEL_NUM);
|
||||
#endif
|
||||
#ifdef SERVO_Z_PIN
|
||||
ServoAxis Z_Servo_Axis(Z_AXIS, SERVO_Z_PIN, SERVO_Z_CHANNEL_NUM);
|
||||
#endif
|
||||
|
||||
#ifdef SERVO_A_PIN
|
||||
ServoAxis A_Servo_Axis(A_AXIS, SERVO_A_PIN, SERVO_A_CHANNEL_NUM);
|
||||
#endif
|
||||
#ifdef SERVO_B_PIN
|
||||
ServoAxis B_Servo_Axis(B_AXIS, SERVO_B_PIN, SERVO_B_CHANNEL_NUM);
|
||||
#endif
|
||||
#ifdef SERVO_C_PIN
|
||||
ServoAxis C_Servo_Axis(C_AXIS, SERVO_C_PIN, SERVO_C_CHANNEL_NUM);
|
||||
#endif
|
||||
|
||||
void init_servos()
|
||||
{
|
||||
//grbl_send(CLIENT_SERIAL, "[MSG: Init Servos]\r\n");
|
||||
#ifdef SERVO_X_PIN
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:X Servo range %4.3f to %4.3f]\r\n", SERVO_X_RANGE_MIN, SERVO_X_RANGE_MAX);
|
||||
X_Servo_Axis.init();
|
||||
X_Servo_Axis.set_range(SERVO_X_RANGE_MIN, SERVO_X_RANGE_MAX);
|
||||
X_Servo_Axis.set_homing_type(SERVO_HOMING_OFF);
|
||||
X_Servo_Axis.set_disable_on_alarm(false);
|
||||
X_Servo_Axis.set_disable_with_steppers(false);
|
||||
#endif
|
||||
#ifdef SERVO_Y_PIN
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Y Servo range %4.3f to %4.3f]\r\n", SERVO_Y_RANGE_MIN, SERVO_Y_RANGE_MAX);
|
||||
Y_Servo_Axis.init();
|
||||
Y_Servo_Axis.set_range(SERVO_Y_RANGE_MIN, SERVO_Y_RANGE_MAX);
|
||||
#endif
|
||||
#ifdef SERVO_Z_PIN
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Z Servo range %4.3f to %4.3f]\r\n", SERVO_Z_RANGE_MIN, SERVO_Z_RANGE_MAX);
|
||||
Z_Servo_Axis.init();
|
||||
Z_Servo_Axis.set_range(SERVO_Z_RANGE_MIN, SERVO_Z_RANGE_MAX);
|
||||
#ifdef SERVO_Z_HOMING_TYPE
|
||||
Z_Servo_Axis.set_homing_type(SERVO_Z_HOMING_TYPE);
|
||||
#endif
|
||||
#ifdef SERVO_Z_HOME_POS
|
||||
Z_Servo_Axis.set_homing_position(SERVO_Z_HOME_POS);
|
||||
#endif
|
||||
#ifdef SERVO_Z_MPOS // value should be true or false
|
||||
Z_Servo_Axis.set_use_mpos(SERVO_Z_MPOS);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SERVO_A_PIN
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:A Servo range %4.3f to %4.3f]\r\n", SERVO_A_RANGE_MIN, SERVO_A_RANGE_MAX);
|
||||
A_Servo_Axis.init();
|
||||
A_Servo_Axis.set_range(SERVO_A_RANGE_MIN, SERVO_A_RANGE_MAX);
|
||||
A_Servo_Axis.set_homing_type(SERVO_HOMING_OFF);
|
||||
A_Servo_Axis.set_disable_on_alarm(false);
|
||||
A_Servo_Axis.set_disable_with_steppers(false);
|
||||
#endif
|
||||
#ifdef SERVO_B_PIN
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:B Servo range %4.3f to %4.3f]\r\n", SERVO_B_RANGE_MIN, SERVO_B_RANGE_MAX);
|
||||
B_Servo_Axis.init();
|
||||
B_Servo_Axis.set_range(SERVO_B_RANGE_MIN, SERVO_B_RANGE_MAX);
|
||||
#endif
|
||||
#ifdef SERVO_C_PIN
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:C Servo range %4.3f to %4.3f]\r\n", SERVO_C_RANGE_MIN, SERVO_C_RANGE_MAX);
|
||||
C_Servo_Axis.init();
|
||||
C_Servo_Axis.set_range(SERVO_C_RANGE_MIN, SERVO_C_RANGE_MAX);
|
||||
//C_Servo_Axis.set_homing_type(SERVO_HOMING_TARGET);
|
||||
//C_Servo_Axis.set_homing_position(SERVO_C_RANGE_MAX);
|
||||
#ifdef SERVO_C_HOMING_TYPE
|
||||
C_Servo_Axis.set_homing_type(SERVO_C_HOMING_TYPE);
|
||||
#endif
|
||||
#ifdef SERVO_C_HOME_POS
|
||||
C_Servo_Axis.set_homing_position(SERVO_C_HOME_POS);
|
||||
#endif
|
||||
#ifdef SERVO_C_MPOS // value should be true or false
|
||||
C_Servo_Axis.set_use_mpos(SERVO_C_MPOS);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// setup a task that will calculate the determine and set the servo positions
|
||||
xTaskCreatePinnedToCore( servosSyncTask, // task
|
||||
"servosSyncTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&servosSyncTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// this is the task
|
||||
void servosSyncTask(void *pvParameters)
|
||||
{
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xServoFrequency = SERVO_TIMER_INT_FREQ; // in ticks (typically ms)
|
||||
|
||||
|
||||
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while(true) { // don't ever return from this or the task dies
|
||||
#ifdef SERVO_X_PIN
|
||||
X_Servo_Axis.set_location();
|
||||
#endif
|
||||
#ifdef SERVO_Y_PIN
|
||||
Y_Servo_Axis.set_location();
|
||||
#endif
|
||||
#ifdef SERVO_Z_PIN
|
||||
Z_Servo_Axis.set_location();
|
||||
#endif
|
||||
#ifdef SERVO_A_PIN
|
||||
A_Servo_Axis.set_location();
|
||||
#endif
|
||||
#ifdef SERVO_B_PIN
|
||||
B_Servo_Axis.set_location();
|
||||
#endif
|
||||
#ifdef SERVO_C_PIN
|
||||
C_Servo_Axis.set_location();
|
||||
#endif
|
||||
|
||||
vTaskDelayUntil(&xLastWakeTime, xServoFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
// =============================== Class Stuff ================================= //
|
||||
|
||||
ServoAxis::ServoAxis(uint8_t axis, uint8_t pin_num, uint8_t channel_num) // constructor
|
||||
{
|
||||
_axis = axis;
|
||||
_pin_num = pin_num;
|
||||
_channel_num = channel_num;
|
||||
_showError = true; // this will be used to show calibration error only once
|
||||
_use_mpos = true; // default is to use the machine position rather than work position
|
||||
}
|
||||
|
||||
void ServoAxis::init()
|
||||
{
|
||||
_cal_is_valid();
|
||||
ledcSetup(_channel_num, _pwm_freq, _pwm_resolution_bits);
|
||||
ledcAttachPin(_pin_num, _channel_num);
|
||||
disable();
|
||||
}
|
||||
|
||||
void ServoAxis::set_location()
|
||||
{
|
||||
// These are the pulse lengths for the minimum and maximum positions
|
||||
// Note: Some machines will have the physical max/min inverted with pulse length max/min due to invert setting $3=...
|
||||
float servo_pulse_min, servo_pulse_max;
|
||||
float min_pulse_cal, max_pulse_cal; // calibration values in percent 110% = 1.1
|
||||
uint32_t servo_pulse_len;
|
||||
float servo_pos, mpos, offset;
|
||||
|
||||
|
||||
|
||||
// skip location if we are in alarm mode
|
||||
if (_disable_on_alarm && (sys.state == STATE_ALARM)) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
// track the disable status of the steppers if desired.
|
||||
if (_disable_with_steppers && get_stepper_disable()) {
|
||||
disable();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ( (_homing_type == SERVO_HOMING_TARGET) && (sys.state == STATE_HOMING) ) {
|
||||
servo_pos = _homing_position; // go to servos home position
|
||||
}
|
||||
else {
|
||||
mpos = system_convert_axis_steps_to_mpos(sys_position, _axis); // get the axis machine position in mm
|
||||
if (_use_mpos) {
|
||||
servo_pos = mpos;
|
||||
}
|
||||
else {
|
||||
offset = gc_state.coord_system[_axis] + gc_state.coord_offset[_axis]; // get the current axis work offset
|
||||
servo_pos = mpos - offset; // determine the current work position
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 1. Get the pulse ranges of the servos
|
||||
// 2. Invert if selected in the settings
|
||||
// 3. Get the calibration values from the settings
|
||||
// 4. Adjust the calibration offset direction of the cal based on the direction
|
||||
// 5. Apply the calibrarion
|
||||
|
||||
|
||||
servo_pulse_min = SERVO_MIN_PULSE;
|
||||
servo_pulse_max = SERVO_MAX_PULSE;
|
||||
|
||||
if (bit_istrue(settings.dir_invert_mask,bit(_axis))) { // this allows the user to change the direction via settings
|
||||
swap(servo_pulse_min, servo_pulse_max);
|
||||
}
|
||||
|
||||
// get the calibration values
|
||||
if (_cal_is_valid()) { // if calibration settings are OK then apply them
|
||||
// apply a calibration
|
||||
// the cals apply differently if the direction is reverse (i.e. longer pulse is lower position)
|
||||
if (bit_isfalse(settings.dir_invert_mask,bit(_axis))) { // normal direction
|
||||
min_pulse_cal = 2.0 - (settings.steps_per_mm[_axis] / 100.0);
|
||||
max_pulse_cal = (settings.max_travel[_axis] / -100.0);
|
||||
}
|
||||
else { // inverted direction
|
||||
min_pulse_cal = (settings.steps_per_mm[_axis] / 100.0);
|
||||
max_pulse_cal = 2.0 - (settings.max_travel[_axis] / -100.0);
|
||||
}
|
||||
}
|
||||
else { // settings are not valid so don't apply any calibration
|
||||
min_pulse_cal = 1.0;
|
||||
max_pulse_cal = 1.0;
|
||||
}
|
||||
|
||||
// apply the calibrations
|
||||
servo_pulse_min *= min_pulse_cal;
|
||||
servo_pulse_max *= max_pulse_cal;
|
||||
|
||||
// determine the pulse length
|
||||
servo_pulse_len = (uint32_t)mapConstrain(servo_pos, _position_min, _position_max, servo_pulse_min, servo_pulse_max );
|
||||
_write_pwm(servo_pulse_len);
|
||||
}
|
||||
|
||||
void ServoAxis::_write_pwm(uint32_t duty)
|
||||
{
|
||||
if (ledcRead(_channel_num) != duty) { // only write if it is changing
|
||||
ledcWrite(_channel_num, duty);
|
||||
}
|
||||
}
|
||||
|
||||
// sets the PWM to zero. This allows most servos to be manually moved
|
||||
void ServoAxis::disable()
|
||||
{
|
||||
_write_pwm(0);
|
||||
}
|
||||
|
||||
// checks to see if calibration values are in an acceptable range
|
||||
// vebose = true if you want an error sent to serial port
|
||||
bool ServoAxis::_cal_is_valid()
|
||||
{
|
||||
bool settingsOK = true;
|
||||
|
||||
if ( (settings.steps_per_mm[_axis] < SERVO_CAL_MIN) || (settings.steps_per_mm[_axis] > SERVO_CAL_MAX) ) {
|
||||
if (_showError) {
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Servo calibration ($10%d) value error. Reset to 100]\r\n", _axis);
|
||||
settings.steps_per_mm[_axis] = 100;
|
||||
write_global_settings();
|
||||
}
|
||||
settingsOK = false;
|
||||
}
|
||||
|
||||
// Note: Max travel is set positive via $$, but stored as a negative number
|
||||
if ( (settings.max_travel[_axis] < -SERVO_CAL_MAX) || (settings.max_travel[_axis] > -SERVO_CAL_MIN) ) {
|
||||
if (_showError) {
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Servo calibration ($13%d) value error. Reset to 100]\r\n", _axis);
|
||||
settings.max_travel[_axis] = -100;
|
||||
write_global_settings();
|
||||
}
|
||||
settingsOK = false;
|
||||
}
|
||||
|
||||
_showError = false; // to show error once
|
||||
|
||||
if (! settingsOK) {
|
||||
write_global_settings(); // they were changed so write them to
|
||||
}
|
||||
|
||||
return settingsOK;
|
||||
}
|
||||
|
||||
/*
|
||||
Use this to set the max and min position in mm of the servo
|
||||
This is used when mapping pulse length to the position
|
||||
*/
|
||||
void ServoAxis::set_range(float min, float max) {
|
||||
if (min < max) {
|
||||
_position_min = min;
|
||||
_position_max = max;
|
||||
}
|
||||
else {
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Error setting range. Min not smaller than max]\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Sets the mode the servo will be in during homing
|
||||
See servo_axis.h for SERVO_HOMING_xxxxx types
|
||||
*/
|
||||
void ServoAxis::set_homing_type(uint8_t homing_type)
|
||||
{
|
||||
if (homing_type <= SERVO_HOMING_TARGET)
|
||||
_homing_type = homing_type;
|
||||
}
|
||||
|
||||
/*
|
||||
Use this to set the homing position the servo will be commanded to go if
|
||||
the current homing mode is SERVO_HOMING_TARGET
|
||||
*/
|
||||
void ServoAxis::set_homing_position(float homing_position)
|
||||
{
|
||||
_homing_position = homing_position;
|
||||
}
|
||||
|
||||
/*
|
||||
Use this to set the disable on alarm feature. If true, then hobby servo PWM
|
||||
will be disable in Grbl alarm mode (like before homing). Typical hobby servo
|
||||
can be moved by hand in this mode
|
||||
*/
|
||||
void ServoAxis::set_disable_on_alarm (bool disable_on_alarm)
|
||||
{
|
||||
_disable_on_alarm = disable_on_alarm;
|
||||
}
|
||||
|
||||
void ServoAxis::set_disable_with_steppers(bool disable_with_steppers) {
|
||||
_disable_with_steppers = disable_with_steppers;
|
||||
}
|
||||
|
||||
/*
|
||||
If true, servo position will alway be calculated in machine position
|
||||
Offsets will not be applied
|
||||
*/
|
||||
void ServoAxis::set_use_mpos(bool use_mpos) {
|
||||
_use_mpos = use_mpos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
133
Grbl_Esp32-master/Grbl_Esp32/servo_axis.h
Normal file
133
Grbl_Esp32-master/Grbl_Esp32/servo_axis.h
Normal file
@ -0,0 +1,133 @@
|
||||
/*
|
||||
solenoid_pen.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2019 - Bart Dring. This file was intended for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Servo Axis Class
|
||||
|
||||
The Servo axis feature allows you to use a hobby servo on any axis.
|
||||
This is done using a repeating RTOS task. Grbl continues to calculate
|
||||
the position of the axis in real time. The task looks at the current position of
|
||||
the axis and calculates the required PWM value to go to that location. You define the travel
|
||||
of the servo in millimeters.
|
||||
|
||||
Grbl still uses the acceleration and speed values you have in the settings, so it
|
||||
will coordinate servo axes with stepper motor axes. This assumes these values are within the
|
||||
capabilities of the servo
|
||||
|
||||
Usage
|
||||
|
||||
1. In config.h un-comment #define USE_SERVO_AXES
|
||||
|
||||
2. In a cpu_map.h section, define servo pins and PWM channels like this ....
|
||||
#define SERVO_Y_PIN GPIO_NUM_14
|
||||
#define SERVO_Y_CHANNEL_NUM 6
|
||||
|
||||
undefine any step and direction pins associated with that axis
|
||||
|
||||
3. In servo_axis.cpp init_servos() function, configure servos like this ....
|
||||
X_Servo_Axis.set_range(0.0, 20.0); // millimeter
|
||||
X_Servo_Axis.set_homing_type(SERVO_HOMING_OFF);
|
||||
X_Servo_Axis.set_disable_on_alarm(true);
|
||||
|
||||
|
||||
The positions can be calibrated using the settings. $10x (resolution) settings adjust the minimum
|
||||
position and $13x (max travel) settings adjust the maximum position. If the servo is traveling
|
||||
backwards from what you want, you can use the $3 direction setting to compensate.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef servo_axis_h
|
||||
#define servo_axis_h
|
||||
|
||||
|
||||
|
||||
// this is the pulse range of a the servo. Typical servos are 0.001 to 0.002 seconds
|
||||
// some servos have a wider range. You can adjust this here or in the calibration feature
|
||||
#define SERVO_MIN_PULSE_SEC 0.001 // min pulse in seconds
|
||||
#define SERVO_MAX_PULSE_SEC 0.002 // max pulse in seconds
|
||||
|
||||
#define SERVO_POSITION_MIN_DEFAULT 0.0 // mm
|
||||
#define SERVO_POSITION_MAX_DEFAULT 20.0 // mm
|
||||
|
||||
#define SERVO_PULSE_FREQ 50 // 50Hz ...This is a standard analog servo value. Digital ones can repeat faster
|
||||
|
||||
#define SERVO_PULSE_RES_BITS 16 // bits of resolution of PWM (16 is max)
|
||||
#define SERVO_PULSE_RES_COUNT 65535 // see above TODO...do the math here 2^SERVO_PULSE_RES_BITS
|
||||
|
||||
#define SERVO_TIME_PER_BIT ((1.0 / (float)SERVO_PULSE_FREQ) / ((float)SERVO_PULSE_RES_COUNT) ) // seconds
|
||||
|
||||
#define SERVO_MIN_PULSE (uint16_t)(SERVO_MIN_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
#define SERVO_MAX_PULSE (uint16_t)(SERVO_MAX_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
|
||||
#define SERVO_PULSE_RANGE (SERVO_MAX_PULSE-SERVO_MIN_PULSE)
|
||||
|
||||
#define SERVO_CAL_MIN 20.0 // Percent: the minimum allowable calibration value
|
||||
#define SERVO_CAL_MAX 180.0 // Percent: the maximum allowable calibration value
|
||||
|
||||
#define SERVO_TIMER_INT_FREQ 20 // Hz This is the task frequency
|
||||
|
||||
#define SERVO_HOMING_OFF 0 // servo is off during homing
|
||||
#define SERVO_HOMING_TARGET 1 // servo is send to a location during homing
|
||||
|
||||
extern float my_location;
|
||||
|
||||
void init_servos();
|
||||
void servosSyncTask(void *pvParameters);
|
||||
|
||||
|
||||
class ServoAxis{
|
||||
public:
|
||||
ServoAxis(uint8_t axis, uint8_t pin_num, uint8_t channel_num); // constructor
|
||||
void init();
|
||||
void set_location();
|
||||
void disable(); // sets PWM to 0% duty cycle. Most servos can be manually moved in this state
|
||||
void set_range(float min, float max);
|
||||
void set_homing_type(uint8_t homing_type);
|
||||
void set_homing_position(float homing_position);
|
||||
void set_disable_on_alarm (bool disable_on_alarm);
|
||||
void set_disable_with_steppers(bool disable_with_steppers);
|
||||
void set_use_mpos(bool use_mpos);
|
||||
|
||||
private:
|
||||
int _axis; // these should be assign in constructor using Grbl X_AXIS type values
|
||||
int _pin_num; // The GPIO pin being used
|
||||
int _channel_num; // The PWM channel
|
||||
bool _showError;
|
||||
|
||||
uint32_t _pwm_freq = SERVO_PULSE_FREQ;
|
||||
uint32_t _pwm_resolution_bits = SERVO_PULSE_RES_BITS;
|
||||
float _pulse_min = SERVO_MIN_PULSE; // in pwm counts
|
||||
float _pulse_max = SERVO_MAX_PULSE; // in pwm counts
|
||||
float _position_min = SERVO_POSITION_MIN_DEFAULT; // position in millimeters
|
||||
float _position_max = SERVO_POSITION_MAX_DEFAULT; // position in millimeters
|
||||
|
||||
|
||||
uint8_t _homing_type = SERVO_HOMING_OFF;
|
||||
float _homing_position = SERVO_POSITION_MAX_DEFAULT;
|
||||
bool _disable_on_alarm = true;
|
||||
bool _disable_with_steppers = false;
|
||||
bool _use_mpos = true;
|
||||
|
||||
bool _validate_cal_settings();
|
||||
void _write_pwm(uint32_t duty);
|
||||
bool _cal_is_valid(); // checks to see if calibration values are in acceptable range
|
||||
|
||||
};
|
||||
|
||||
#endif
|
176
Grbl_Esp32-master/Grbl_Esp32/servo_pen.cpp
Normal file
176
Grbl_Esp32-master/Grbl_Esp32/servo_pen.cpp
Normal file
@ -0,0 +1,176 @@
|
||||
/*
|
||||
servo_pen.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef USE_PEN_SERVO
|
||||
|
||||
static TaskHandle_t servoSyncTaskHandle = 0;
|
||||
|
||||
// used to delay turn on
|
||||
bool servo_pen_enable = false;
|
||||
|
||||
void servo_init()
|
||||
{
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Servo Pen Mode]\r\n"); // startup message
|
||||
//validate_servo_settings(true); // display any calibration errors
|
||||
|
||||
// Debug stuff
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG:Servo max,min pulse times %.4f sec,%.4f sec]\r\n", SERVO_MAX_PULSE_SEC, SERVO_MIN_PULSE_SEC);
|
||||
//grbl_sendf(CLIENT_SERIAL, "[MSG:Servo max,min pulse counts %d,%d]\r\n", SERVO_MAX_PULSE, SERVO_MIN_PULSE);
|
||||
validate_servo_settings(true); // will print errors
|
||||
// debug stuff
|
||||
|
||||
servo_pen_enable = false; // start delay has not completed yet.
|
||||
|
||||
// setup PWM channel
|
||||
ledcSetup(SERVO_PEN_CHANNEL_NUM, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS);
|
||||
ledcAttachPin(SERVO_PEN_PIN, SERVO_PEN_CHANNEL_NUM);
|
||||
|
||||
servo_disable(); // start it it off
|
||||
|
||||
// setup a task that will calculate the determine and set the servo position
|
||||
xTaskCreatePinnedToCore( servoSyncTask, // task
|
||||
"servoSyncTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&servoSyncTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
}
|
||||
|
||||
// turn off the PWM (0 duty) to prevent servo jitter when not in use.
|
||||
void servo_disable()
|
||||
{
|
||||
ledcWrite(SERVO_PEN_CHANNEL_NUM, 0);
|
||||
}
|
||||
|
||||
// Grbl settings are used to calibrate the servo positions
|
||||
// They work on a percentage, so a value of 100 (100%) applies no calibration
|
||||
// Values outside a reasonable range can cause errors, so this function checks
|
||||
// that they are within a reasonable range
|
||||
bool validate_servo_settings(bool verbose) // make sure the settings are reasonable..otherwise reset the settings to default
|
||||
{
|
||||
bool settingsOK = true;
|
||||
|
||||
if ( (settings.steps_per_mm[Z_AXIS] < SERVO_CAL_MIN) || (settings.steps_per_mm[Z_AXIS] > SERVO_CAL_MAX) ) {
|
||||
if (verbose) {
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Servo cal ($102) Error: %4.4f s/b between %.2f and %.2f]\r\n", settings.steps_per_mm[Z_AXIS], SERVO_CAL_MIN, SERVO_CAL_MAX);
|
||||
}
|
||||
|
||||
settingsOK = false;
|
||||
}
|
||||
|
||||
// Note: Max travel is set positive via $$, but stored as a negative number
|
||||
if ( (settings.max_travel[Z_AXIS] < -SERVO_CAL_MAX) || (settings.max_travel[Z_AXIS] > -SERVO_CAL_MIN) ) {
|
||||
if (verbose) {
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG:Servo cal ($132) Error: %4.4f s/b between %.2f and %.2f]\r\n", -settings.max_travel[Z_AXIS], SERVO_CAL_MIN, SERVO_CAL_MAX);
|
||||
}
|
||||
|
||||
settingsOK = false;
|
||||
}
|
||||
|
||||
return settingsOK;
|
||||
}
|
||||
|
||||
// this is the task
|
||||
void servoSyncTask(void *pvParameters)
|
||||
{
|
||||
//int32_t current_position[N_AXIS]; // copy of current location
|
||||
//float m_pos[N_AXIS]; // machine position in mm
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xServoFrequency = SERVO_TIMER_INT_FREQ; // in ticks (typically ms)
|
||||
uint16_t servo_delay_counter = 0;
|
||||
|
||||
float mpos_z, wpos_z;
|
||||
float z_offset;
|
||||
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while(true) { // don't ever return from this or the task dies
|
||||
if (sys.state != STATE_ALARM) { // don't move until alarm is cleared...typically homing
|
||||
if (!servo_pen_enable ) {
|
||||
servo_delay_counter++;
|
||||
servo_pen_enable = (servo_delay_counter > SERVO_TURNON_DELAY);
|
||||
} else {
|
||||
mpos_z = system_convert_axis_steps_to_mpos(sys_position, Z_AXIS); // get the machine Z in mm
|
||||
z_offset = gc_state.coord_system[Z_AXIS]+gc_state.coord_offset[Z_AXIS]; // get the current z work offset
|
||||
wpos_z = mpos_z - z_offset; // determine the current work Z
|
||||
|
||||
calc_pen_servo(wpos_z); // calculate kinematics and move the servos
|
||||
}
|
||||
}
|
||||
vTaskDelayUntil(&xLastWakeTime, xServoFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate and set the PWM value for the servo
|
||||
void calc_pen_servo(float penZ)
|
||||
{
|
||||
uint32_t servo_pen_pulse_len;
|
||||
float servo_pen_pulse_min, servo_pen_pulse_max;
|
||||
|
||||
if (!servo_pen_enable) { // only proceed if startup delay as expired
|
||||
return;
|
||||
}
|
||||
|
||||
if (validate_servo_settings(false)) { // if calibration settings are OK then apply them
|
||||
if (bit_istrue(settings.dir_invert_mask,bit(Z_AXIS))) { // this allows the user to change the direction via settings
|
||||
// Apply a calibration to the minimum position
|
||||
servo_pen_pulse_max = SERVO_MIN_PULSE * (settings.steps_per_mm[Z_AXIS] / 100.0);
|
||||
// Apply a calibration to the maximum position
|
||||
servo_pen_pulse_min = SERVO_MAX_PULSE * (settings.max_travel[Z_AXIS] / -100.0);
|
||||
}
|
||||
else {
|
||||
// Apply a calibration to the minimum position
|
||||
servo_pen_pulse_min = SERVO_MIN_PULSE * (settings.steps_per_mm[Z_AXIS] / 100.0);
|
||||
// Apply a calibration to the maximum position
|
||||
servo_pen_pulse_max = SERVO_MAX_PULSE * (settings.max_travel[Z_AXIS] / -100.0);
|
||||
}
|
||||
|
||||
} else { // use the defaults
|
||||
if (bit_istrue(settings.dir_invert_mask,bit(Z_AXIS))) { // this allows the user to change the direction via settings
|
||||
servo_pen_pulse_min = SERVO_MAX_PULSE;
|
||||
servo_pen_pulse_max = SERVO_MIN_PULSE;
|
||||
}
|
||||
else {
|
||||
servo_pen_pulse_min = SERVO_MIN_PULSE;
|
||||
servo_pen_pulse_max = SERVO_MAX_PULSE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// determine the pulse length
|
||||
servo_pen_pulse_len = (uint32_t)mapConstrain(penZ, SERVO_PEN_RANGE_MIN_MM, SERVO_PEN_RANGE_MAX_MM, servo_pen_pulse_min, servo_pen_pulse_max );
|
||||
|
||||
// skip setting value if it is unchanged
|
||||
if (ledcRead(SERVO_PEN_CHANNEL_NUM) == servo_pen_pulse_len)
|
||||
return;
|
||||
|
||||
// update the PWM value
|
||||
// ledcWrite appears to have issues with interrupts, so make this a critical section
|
||||
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL(&myMutex);
|
||||
ledcWrite(SERVO_PEN_CHANNEL_NUM, servo_pen_pulse_len);
|
||||
portEXIT_CRITICAL(&myMutex);
|
||||
}
|
||||
|
||||
#endif
|
76
Grbl_Esp32-master/Grbl_Esp32/servo_pen.h
Normal file
76
Grbl_Esp32-master/Grbl_Esp32/servo_pen.h
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
servo.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
To use this, uncomment #define USE_PEN_SERVO in config.h
|
||||
|
||||
That should be the only change you need at the top level
|
||||
Everything occurs as a low priority task that syncs the servo with the
|
||||
current machine position.
|
||||
|
||||
*/
|
||||
|
||||
// ==== Begin: Things you are likely to change ====================
|
||||
//#define SERVO_PEN_PIN GPIO_NUM_27 // FYI...you can disable the Z stepper pins (step & dir)
|
||||
|
||||
// the pulse lengths for the min and max travel .. (Note: Servo brands vary)
|
||||
// If the servo goes backward from what you want, flip the values
|
||||
// Note: this is not necessarily the servos limits (just the travel you want)
|
||||
#define SERVO_MIN_PULSE_SEC 0.001 // min pulse in seconds
|
||||
#define SERVO_MAX_PULSE_SEC 0.002 // max pulse in seconds
|
||||
|
||||
// Pulse repeat rate (PWM Frequency)
|
||||
#define SERVO_PULSE_FREQ 50 // 50Hz ...This is a standard analog servo value. Digital ones can repeat faster
|
||||
|
||||
// the range of the servo is constrained
|
||||
// values above or below these will be limited to the min or max
|
||||
#define SERVO_PEN_RANGE_MIN_MM 0.0 // the minimum z position in mm
|
||||
#define SERVO_PEN_RANGE_MAX_MM 5.0 // the minimum z position in mm
|
||||
// ==== End: Things you are likely to change =======================
|
||||
|
||||
// Begin: Advanced settings
|
||||
|
||||
#define SERVO_TIMER_NUM 1
|
||||
#define SERVO_TIMER_INT_FREQ 20 // Hz This is the task frequency
|
||||
#define SERVO_PEN_CHANNEL_NUM 5
|
||||
|
||||
#define SERVO_PULSE_RES_BITS 16 // bits of resolution of PWM (16 is max)
|
||||
#define SERVO_PULSE_RES_COUNT 65535 // see above TODO...do the math here 2^SERVO_PULSE_RES_BITS
|
||||
|
||||
// A way to reduce the turn on current
|
||||
#define SERVO_TURNON_DELAY SERVO_TIMER_INT_FREQ*3 // Wait this many task counts to turn on servo
|
||||
|
||||
#define SERVO_TIME_PER_BIT ((1.0 / (float)SERVO_PULSE_FREQ) / ((float)SERVO_PULSE_RES_COUNT) ) // seconds
|
||||
|
||||
#define SERVO_MIN_PULSE (uint16_t)(SERVO_MIN_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
#define SERVO_MAX_PULSE (uint16_t)(SERVO_MAX_PULSE_SEC / SERVO_TIME_PER_BIT) // in timer counts
|
||||
|
||||
#define SERVO_CAL_MIN 20.0 // Percent: the minimum allowable calibration value
|
||||
#define SERVO_CAL_MAX 180.0 // Percent: the maximum allowable calibration value
|
||||
|
||||
#ifndef servo_h
|
||||
#define servo_h
|
||||
|
||||
void servo_init();
|
||||
void servo_disable();
|
||||
bool validate_servo_settings(bool verbose);
|
||||
void servoSyncTask(void *pvParameters);
|
||||
void calc_pen_servo(float penZ);
|
||||
|
||||
#endif
|
452
Grbl_Esp32-master/Grbl_Esp32/settings.cpp
Normal file
452
Grbl_Esp32-master/Grbl_Esp32/settings.cpp
Normal file
@ -0,0 +1,452 @@
|
||||
/*
|
||||
settings.c - eeprom configuration handling
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
settings_t settings;
|
||||
|
||||
// Method to store startup lines into EEPROM
|
||||
void settings_store_startup_line(uint8_t n, char *line)
|
||||
{
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE
|
||||
protocol_buffer_synchronize(); // A startup line may contain a motion and be executing.
|
||||
#endif
|
||||
uint32_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
|
||||
memcpy_to_eeprom_with_checksum(addr,(char*)line, LINE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void settings_init()
|
||||
{
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
|
||||
if(!read_global_settings()) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
|
||||
settings_restore(SETTINGS_RESTORE_ALL); // Force restore all EEPROM data.
|
||||
report_grbl_settings(CLIENT_SERIAL); // only the serial could be working at this point
|
||||
}
|
||||
}
|
||||
|
||||
// Method to restore EEPROM-saved Grbl global settings back to defaults.
|
||||
void settings_restore(uint8_t restore_flag) {
|
||||
#if defined(ENABLE_BLUETOOTH) || defined(ENABLE_WIFI)
|
||||
if (restore_flag & SETTINGS_RESTORE_WIFI_SETTINGS){
|
||||
#ifdef ENABLE_WIFI
|
||||
wifi_config.reset_settings();
|
||||
#endif
|
||||
#ifdef ENABLE_BLUETOOTH
|
||||
bt_config.reset_settings();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
if (restore_flag & SETTINGS_RESTORE_DEFAULTS) {
|
||||
settings.pulse_microseconds = DEFAULT_STEP_PULSE_MICROSECONDS;
|
||||
settings.stepper_idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME;
|
||||
settings.step_invert_mask = DEFAULT_STEPPING_INVERT_MASK;
|
||||
settings.dir_invert_mask = DEFAULT_DIRECTION_INVERT_MASK;
|
||||
settings.status_report_mask = DEFAULT_STATUS_REPORT_MASK;
|
||||
settings.junction_deviation = DEFAULT_JUNCTION_DEVIATION;
|
||||
|
||||
settings.arc_tolerance = DEFAULT_ARC_TOLERANCE;
|
||||
|
||||
settings.spindle_pwm_freq = DEFAULT_SPINDLE_FREQ; // $33 Hz (extended set)
|
||||
settings.spindle_pwm_off_value = DEFAULT_SPINDLE_OFF_VALUE; // $34 Percent (extended set)
|
||||
settings.spindle_pwm_min_value = DEFAULT_SPINDLE_MIN_VALUE; // $35 Percent (extended set)
|
||||
settings.spindle_pwm_max_value = DEFAULT_SPINDLE_MAX_VALUE; // $36 Percent (extended set)
|
||||
|
||||
settings.rpm_max = DEFAULT_SPINDLE_RPM_MAX;
|
||||
settings.rpm_min = DEFAULT_SPINDLE_RPM_MIN;
|
||||
|
||||
settings.homing_dir_mask = DEFAULT_HOMING_DIR_MASK;
|
||||
settings.homing_feed_rate = DEFAULT_HOMING_FEED_RATE;
|
||||
settings.homing_seek_rate = DEFAULT_HOMING_SEEK_RATE;
|
||||
settings.homing_debounce_delay = DEFAULT_HOMING_DEBOUNCE_DELAY;
|
||||
settings.homing_pulloff = DEFAULT_HOMING_PULLOFF;
|
||||
|
||||
settings.flags = 0;
|
||||
if (DEFAULT_REPORT_INCHES) { settings.flags |= BITFLAG_REPORT_INCHES; }
|
||||
if (DEFAULT_LASER_MODE) { settings.flags |= BITFLAG_LASER_MODE; }
|
||||
if (DEFAULT_INVERT_ST_ENABLE) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
|
||||
if (DEFAULT_HARD_LIMIT_ENABLE) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
|
||||
if (DEFAULT_HOMING_ENABLE) { settings.flags |= BITFLAG_HOMING_ENABLE; }
|
||||
if (DEFAULT_SOFT_LIMIT_ENABLE) { settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE; }
|
||||
if (DEFAULT_INVERT_LIMIT_PINS) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
|
||||
if (DEFAULT_INVERT_PROBE_PIN) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
|
||||
|
||||
settings.steps_per_mm[X_AXIS] = DEFAULT_X_STEPS_PER_MM;
|
||||
settings.steps_per_mm[Y_AXIS] = DEFAULT_Y_STEPS_PER_MM;
|
||||
settings.steps_per_mm[Z_AXIS] = DEFAULT_Z_STEPS_PER_MM;
|
||||
|
||||
settings.max_rate[X_AXIS] = DEFAULT_X_MAX_RATE;
|
||||
settings.max_rate[Y_AXIS] = DEFAULT_Y_MAX_RATE;
|
||||
settings.max_rate[Z_AXIS] = DEFAULT_Z_MAX_RATE;
|
||||
|
||||
settings.acceleration[X_AXIS] = DEFAULT_X_ACCELERATION;
|
||||
settings.acceleration[Y_AXIS] = DEFAULT_Y_ACCELERATION;
|
||||
settings.acceleration[Z_AXIS] = DEFAULT_Z_ACCELERATION;
|
||||
|
||||
settings.max_travel[X_AXIS] = (-DEFAULT_X_MAX_TRAVEL);
|
||||
settings.max_travel[Y_AXIS] = (-DEFAULT_Y_MAX_TRAVEL);
|
||||
settings.max_travel[Z_AXIS] = (-DEFAULT_Z_MAX_TRAVEL);
|
||||
|
||||
settings.current[X_AXIS] = DEFAULT_X_CURRENT;
|
||||
settings.current[Y_AXIS] = DEFAULT_Y_CURRENT;
|
||||
settings.current[Z_AXIS] = DEFAULT_Z_CURRENT;
|
||||
|
||||
settings.hold_current[X_AXIS] = DEFAULT_X_HOLD_CURRENT;
|
||||
settings.hold_current[Y_AXIS] = DEFAULT_Y_HOLD_CURRENT;
|
||||
settings.hold_current[Z_AXIS] = DEFAULT_Z_HOLD_CURRENT;
|
||||
|
||||
settings.microsteps[X_AXIS] = DEFAULT_X_MICROSTEPS;
|
||||
settings.microsteps[Y_AXIS] = DEFAULT_Y_MICROSTEPS;
|
||||
settings.microsteps[Z_AXIS] = DEFAULT_Z_MICROSTEPS;
|
||||
|
||||
settings.stallguard[X_AXIS] = DEFAULT_X_STALLGUARD;
|
||||
settings.stallguard[Y_AXIS] = DEFAULT_Y_STALLGUARD;
|
||||
settings.stallguard[Z_AXIS] = DEFAULT_Z_STALLGUARD;
|
||||
|
||||
#if (N_AXIS > A_AXIS)
|
||||
settings.steps_per_mm[A_AXIS] = DEFAULT_A_STEPS_PER_MM;
|
||||
settings.max_rate[A_AXIS] = DEFAULT_A_MAX_RATE;
|
||||
settings.acceleration[A_AXIS] = DEFAULT_A_ACCELERATION;
|
||||
settings.max_travel[A_AXIS] = (-DEFAULT_A_MAX_TRAVEL);
|
||||
settings.current[A_AXIS] = DEFAULT_A_CURRENT;
|
||||
settings.hold_current[A_AXIS] = DEFAULT_A_HOLD_CURRENT;
|
||||
settings.microsteps[A_AXIS] = DEFAULT_A_MICROSTEPS;
|
||||
settings.stallguard[A_AXIS] = DEFAULT_Z_STALLGUARD;
|
||||
#endif
|
||||
|
||||
#if (N_AXIS > B_AXIS)
|
||||
settings.steps_per_mm[B_AXIS] = DEFAULT_B_STEPS_PER_MM;
|
||||
settings.max_rate[B_AXIS] = DEFAULT_B_MAX_RATE;
|
||||
settings.acceleration[B_AXIS] = DEFAULT_B_ACCELERATION;
|
||||
settings.max_travel[B_AXIS] = (-DEFAULT_B_MAX_TRAVEL);
|
||||
settings.current[B_AXIS] = DEFAULT_B_CURRENT;
|
||||
settings.hold_current[B_AXIS] = DEFAULT_B_HOLD_CURRENT;
|
||||
settings.microsteps[B_AXIS] = DEFAULT_B_MICROSTEPS;
|
||||
settings.stallguard[B_AXIS] = DEFAULT_Z_STALLGUARD;
|
||||
#endif
|
||||
|
||||
#if (N_AXIS > C_AXIS)
|
||||
settings.steps_per_mm[C_AXIS] = DEFAULT_C_STEPS_PER_MM;
|
||||
settings.max_rate[C_AXIS] = DEFAULT_C_MAX_RATE;
|
||||
settings.acceleration[C_AXIS] = DEFAULT_C_ACCELERATION;
|
||||
settings.max_travel[C_AXIS] = (-DEFAULT_C_MAX_TRAVEL);
|
||||
settings.current[C_AXIS] = DEFAULT_C_CURRENT;
|
||||
settings.hold_current[C_AXIS] = DEFAULT_C_HOLD_CURRENT;
|
||||
settings.microsteps[C_AXIS] = DEFAULT_C_MICROSTEPS;
|
||||
settings.stallguard[C_AXIS] = DEFAULT_Z_STALLGUARD;
|
||||
#endif
|
||||
|
||||
// TODO figure out a clean way to add actual default values
|
||||
for (uint8_t index = 0; index<USER_SETTING_COUNT; index++) {
|
||||
settings.machine_int16[index] = 0;
|
||||
settings.machine_float[index] = 0.0;
|
||||
}
|
||||
|
||||
|
||||
write_global_settings();
|
||||
}
|
||||
|
||||
if (restore_flag & SETTINGS_RESTORE_PARAMETERS) {
|
||||
uint8_t idx;
|
||||
float coord_data[N_AXIS];
|
||||
memset(&coord_data, 0, sizeof(coord_data));
|
||||
for (idx=0; idx <= SETTING_INDEX_NCOORD; idx++) { settings_write_coord_data(idx, coord_data); }
|
||||
}
|
||||
|
||||
if (restore_flag & SETTINGS_RESTORE_STARTUP_LINES) {
|
||||
#if N_STARTUP_LINE > 0
|
||||
EEPROM.write(EEPROM_ADDR_STARTUP_BLOCK, 0);
|
||||
EEPROM.write(EEPROM_ADDR_STARTUP_BLOCK+1, 0); // Checksum
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
#if N_STARTUP_LINE > 1
|
||||
EEPROM.write(EEPROM_ADDR_STARTUP_BLOCK+(LINE_BUFFER_SIZE+1), 0);
|
||||
EEPROM.write(EEPROM_ADDR_STARTUP_BLOCK+(LINE_BUFFER_SIZE+2), 0); // Checksum
|
||||
EEPROM.commit();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (restore_flag & SETTINGS_RESTORE_BUILD_INFO) {
|
||||
EEPROM.write(EEPROM_ADDR_BUILD_INFO , 0);
|
||||
EEPROM.write(EEPROM_ADDR_BUILD_INFO+1 , 0); // Checksum
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Reads Grbl global settings struct from EEPROM.
|
||||
uint8_t read_global_settings() {
|
||||
// Check version-byte of eeprom
|
||||
uint8_t version = EEPROM.read(0);
|
||||
if (version == SETTINGS_VERSION) {
|
||||
// Read settings-record and check checksum
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)&settings, EEPROM_ADDR_GLOBAL, sizeof(settings_t)))) {
|
||||
return(false);
|
||||
}
|
||||
} else {
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Method to store Grbl global settings struct and version number into EEPROM
|
||||
// NOTE: This function can only be called in IDLE state.
|
||||
void write_global_settings()
|
||||
{
|
||||
EEPROM.write(0, SETTINGS_VERSION);
|
||||
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_GLOBAL, (char*)&settings, sizeof(settings_t));
|
||||
|
||||
}
|
||||
|
||||
// Read selected coordinate data from EEPROM. Updates pointed coord_data value.
|
||||
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data)
|
||||
{
|
||||
uint32_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)coord_data, addr, sizeof(float)*N_AXIS))) {
|
||||
// Reset with default zero vector
|
||||
clear_vector_float(coord_data);
|
||||
settings_write_coord_data(coord_select,coord_data);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// Method to store coord data parameters into EEPROM
|
||||
void settings_write_coord_data(uint8_t coord_select, float *coord_data)
|
||||
{
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_EEPROM_WRITE
|
||||
protocol_buffer_synchronize();
|
||||
#endif
|
||||
uint32_t addr = coord_select*(sizeof(float)*N_AXIS+1) + EEPROM_ADDR_PARAMETERS;
|
||||
memcpy_to_eeprom_with_checksum(addr,(char*)coord_data, sizeof(float)*N_AXIS);
|
||||
}
|
||||
|
||||
// Method to store build info into EEPROM
|
||||
// NOTE: This function can only be called in IDLE state.
|
||||
void settings_store_build_info(char *line)
|
||||
{
|
||||
// Build info can only be stored when state is IDLE.
|
||||
memcpy_to_eeprom_with_checksum(EEPROM_ADDR_BUILD_INFO,(char*)line, LINE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
// Reads startup line from EEPROM. Updated pointed line string data.
|
||||
uint8_t settings_read_build_info(char *line)
|
||||
{
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)line, EEPROM_ADDR_BUILD_INFO, LINE_BUFFER_SIZE))) {
|
||||
// Reset line with default value
|
||||
line[0] = 0; // Empty line
|
||||
settings_store_build_info(line);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Reads startup line from EEPROM. Updated pointed line string data.
|
||||
uint8_t settings_read_startup_line(uint8_t n, char *line)
|
||||
{
|
||||
uint32_t addr = n*(LINE_BUFFER_SIZE+1)+EEPROM_ADDR_STARTUP_BLOCK;
|
||||
if (!(memcpy_from_eeprom_with_checksum((char*)line, addr, LINE_BUFFER_SIZE))) {
|
||||
// Reset line with default value
|
||||
line[0] = 0; // Empty line
|
||||
settings_store_startup_line(n, line);
|
||||
return(false);
|
||||
}
|
||||
return(true);
|
||||
}
|
||||
|
||||
// A helper method to set settings from command line
|
||||
uint8_t settings_store_global_setting(uint8_t parameter, float value) {
|
||||
if (value < 0.0) { return(STATUS_NEGATIVE_VALUE); }
|
||||
uint8_t int_value = trunc(value); // integer version
|
||||
if (parameter >= AXIS_SETTINGS_START_VAL) {
|
||||
// Store axis configuration. Axis numbering sequence set by AXIS_SETTING defines.
|
||||
// NOTE: Ensure the setting index corresponds to the report.c settings printout.
|
||||
parameter -= AXIS_SETTINGS_START_VAL;
|
||||
uint8_t set_idx = 0;
|
||||
while (set_idx < AXIS_N_SETTINGS) {
|
||||
if (parameter < N_AXIS) {
|
||||
// Valid axis setting found.
|
||||
switch (set_idx) {
|
||||
case 0:
|
||||
#ifdef MAX_STEP_RATE_HZ
|
||||
if (value*settings.max_rate[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
|
||||
#endif
|
||||
settings.steps_per_mm[parameter] = value;
|
||||
break;
|
||||
case 1:
|
||||
#ifdef MAX_STEP_RATE_HZ
|
||||
if (value*settings.steps_per_mm[parameter] > (MAX_STEP_RATE_HZ*60.0)) { return(STATUS_MAX_STEP_RATE_EXCEEDED); }
|
||||
#endif
|
||||
settings.max_rate[parameter] = value;
|
||||
break;
|
||||
case 2: settings.acceleration[parameter] = value*60*60; break; // Convert to mm/min^2 for grbl internal use.
|
||||
case 3: settings.max_travel[parameter] = -value; break; // Store as negative for grbl internal use.
|
||||
case 4: // run current
|
||||
settings.current[parameter] = value;
|
||||
settings_spi_driver_init();
|
||||
break;
|
||||
case 5: // hold current
|
||||
settings.hold_current[parameter] = value;
|
||||
settings_spi_driver_init();
|
||||
break;
|
||||
case 6: // microstepping
|
||||
settings.microsteps[parameter] = int_value;
|
||||
settings_spi_driver_init();
|
||||
break;
|
||||
case 7: // stallguard
|
||||
settings.stallguard[parameter] = int_value;
|
||||
settings_spi_driver_init();
|
||||
break;
|
||||
}
|
||||
break; // Exit while-loop after setting has been configured and proceed to the EEPROM write call.
|
||||
} else {
|
||||
set_idx++;
|
||||
// If axis index greater than N_AXIS or setting index greater than number of axis settings, error out.
|
||||
if ((parameter < AXIS_SETTINGS_INCREMENT) || (set_idx == AXIS_N_SETTINGS)) { return(STATUS_INVALID_STATEMENT); }
|
||||
parameter -= AXIS_SETTINGS_INCREMENT;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Store non-axis Grbl settings
|
||||
|
||||
switch(parameter) {
|
||||
case 0:
|
||||
if (int_value < 3) { return(STATUS_SETTING_STEP_PULSE_MIN); }
|
||||
settings.pulse_microseconds = int_value; break;
|
||||
case 1: settings.stepper_idle_lock_time = int_value; break;
|
||||
case 2:
|
||||
settings.step_invert_mask = int_value;
|
||||
st_generate_step_dir_invert_masks(); // Regenerate step and direction port invert masks.
|
||||
break;
|
||||
case 3:
|
||||
settings.dir_invert_mask = int_value;
|
||||
st_generate_step_dir_invert_masks(); // Regenerate step and direction port invert masks.
|
||||
break;
|
||||
case 4: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_ST_ENABLE; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_ST_ENABLE; }
|
||||
break;
|
||||
case 5: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_LIMIT_PINS; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_LIMIT_PINS; }
|
||||
break;
|
||||
case 6: // Reset to ensure change. Immediate re-init may cause problems.
|
||||
if (int_value) { settings.flags |= BITFLAG_INVERT_PROBE_PIN; }
|
||||
else { settings.flags &= ~BITFLAG_INVERT_PROBE_PIN; }
|
||||
probe_configure_invert_mask(false);
|
||||
break;
|
||||
case 10: settings.status_report_mask = int_value; break;
|
||||
case 11: settings.junction_deviation = value; break;
|
||||
case 12: settings.arc_tolerance = value; break;
|
||||
case 13:
|
||||
if (int_value) { settings.flags |= BITFLAG_REPORT_INCHES; }
|
||||
else { settings.flags &= ~BITFLAG_REPORT_INCHES; }
|
||||
system_flag_wco_change(); // Make sure WCO is immediately updated.
|
||||
break;
|
||||
case 20:
|
||||
if (int_value) {
|
||||
if (bit_isfalse(settings.flags, BITFLAG_HOMING_ENABLE)) { return(STATUS_SOFT_LIMIT_ERROR); }
|
||||
settings.flags |= BITFLAG_SOFT_LIMIT_ENABLE;
|
||||
} else { settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; }
|
||||
break;
|
||||
case 21:
|
||||
if (int_value) { settings.flags |= BITFLAG_HARD_LIMIT_ENABLE; }
|
||||
else { settings.flags &= ~BITFLAG_HARD_LIMIT_ENABLE; }
|
||||
limits_init(); // Re-init to immediately change. NOTE: Nice to have but could be problematic later.
|
||||
break;
|
||||
case 22:
|
||||
if (int_value) { settings.flags |= BITFLAG_HOMING_ENABLE; }
|
||||
else {
|
||||
settings.flags &= ~BITFLAG_HOMING_ENABLE;
|
||||
settings.flags &= ~BITFLAG_SOFT_LIMIT_ENABLE; // Force disable soft-limits.
|
||||
}
|
||||
break;
|
||||
case 23: settings.homing_dir_mask = int_value; break;
|
||||
case 24: settings.homing_feed_rate = value; break;
|
||||
case 25: settings.homing_seek_rate = value; break;
|
||||
case 26: settings.homing_debounce_delay = int_value; break;
|
||||
case 27: settings.homing_pulloff = value; break;
|
||||
case 30: settings.rpm_max = value; spindle_init(); break; // Re-initialize spindle rpm calibration
|
||||
case 31: settings.rpm_min = value; spindle_init(); break; // Re-initialize spindle rpm calibration
|
||||
case 32:
|
||||
#ifdef VARIABLE_SPINDLE
|
||||
if (int_value) { settings.flags |= BITFLAG_LASER_MODE; }
|
||||
else { settings.flags &= ~BITFLAG_LASER_MODE; }
|
||||
#else
|
||||
return(STATUS_SETTING_DISABLED_LASER);
|
||||
#endif
|
||||
break;
|
||||
case 33: settings.spindle_pwm_freq = value; spindle_init(); break; // Re-initialize spindle pwm calibration
|
||||
case 34: settings.spindle_pwm_off_value = value; spindle_init(); break; // Re-initialize spindle pwm calibration
|
||||
case 35: settings.spindle_pwm_min_value = value; spindle_init(); break; // Re-initialize spindle pwm calibration
|
||||
case 36: settings.spindle_pwm_max_value = value; spindle_init(); break; // Re-initialize spindle pwm calibration
|
||||
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
settings.machine_int16[parameter - 80] = int_value;
|
||||
break;
|
||||
|
||||
case 90:
|
||||
case 91:
|
||||
case 92:
|
||||
case 93:
|
||||
case 94:
|
||||
settings.machine_float[parameter - 90] = value;
|
||||
break;
|
||||
default:
|
||||
return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
}
|
||||
write_global_settings();
|
||||
return(STATUS_OK);
|
||||
}
|
||||
|
||||
// Returns step pin mask according to Grbl internal axis indexing.
|
||||
uint8_t get_step_pin_mask(uint8_t axis_idx)
|
||||
{
|
||||
// todo clean this up further up stream
|
||||
return(1<<axis_idx);
|
||||
}
|
||||
|
||||
// Returns direction pin mask according to Grbl internal axis indexing.
|
||||
uint8_t get_direction_pin_mask(uint8_t axis_idx)
|
||||
{
|
||||
return(1<<axis_idx);
|
||||
}
|
||||
|
||||
// this allows a conditional re-init of the trinamic settings
|
||||
void settings_spi_driver_init() {
|
||||
#ifdef USE_TRINAMIC
|
||||
trinamic_change_settings();
|
||||
#else
|
||||
grbl_send(CLIENT_ALL, "[MSG: No SPI drivers setup]\r\n");
|
||||
#endif
|
||||
}
|
159
Grbl_Esp32-master/Grbl_Esp32/settings.h
Normal file
159
Grbl_Esp32-master/Grbl_Esp32/settings.h
Normal file
@ -0,0 +1,159 @@
|
||||
/*
|
||||
settings.h - eeprom configuration handling
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef settings_h
|
||||
#define settings_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
// Version of the EEPROM data. Will be used to migrate existing data from older versions of Grbl
|
||||
// when firmware is upgraded. Always stored in byte 0 of eeprom
|
||||
#define SETTINGS_VERSION 12 // NOTE: Check settings_reset() when moving to next version.
|
||||
|
||||
// Define bit flag masks for the boolean settings in settings.flag.
|
||||
#define BITFLAG_REPORT_INCHES bit(0)
|
||||
#define BITFLAG_LASER_MODE bit(1)
|
||||
#define BITFLAG_INVERT_ST_ENABLE bit(2)
|
||||
#define BITFLAG_HARD_LIMIT_ENABLE bit(3)
|
||||
#define BITFLAG_HOMING_ENABLE bit(4)
|
||||
#define BITFLAG_SOFT_LIMIT_ENABLE bit(5)
|
||||
#define BITFLAG_INVERT_LIMIT_PINS bit(6)
|
||||
#define BITFLAG_INVERT_PROBE_PIN bit(7)
|
||||
|
||||
// Define status reporting boolean enable bit flags in settings.status_report_mask
|
||||
#define BITFLAG_RT_STATUS_POSITION_TYPE bit(0)
|
||||
#define BITFLAG_RT_STATUS_BUFFER_STATE bit(1)
|
||||
|
||||
// Define settings restore bitflags.
|
||||
#define SETTINGS_RESTORE_DEFAULTS bit(0)
|
||||
#define SETTINGS_RESTORE_PARAMETERS bit(1)
|
||||
#define SETTINGS_RESTORE_STARTUP_LINES bit(2)
|
||||
#define SETTINGS_RESTORE_BUILD_INFO bit(3)
|
||||
#define SETTINGS_RESTORE_WIFI_SETTINGS bit(4)
|
||||
#ifndef SETTINGS_RESTORE_ALL
|
||||
#define SETTINGS_RESTORE_ALL 0xFF // All bitflags
|
||||
#endif
|
||||
|
||||
// Define EEPROM memory address location values for Grbl settings and parameters
|
||||
// NOTE: The Atmega328p has 1KB EEPROM. The upper half is reserved for parameters and
|
||||
// the startup script. The lower half contains the global settings and space for future
|
||||
// developments.
|
||||
#define EEPROM_SIZE 1024U
|
||||
#define EEPROM_ADDR_GLOBAL 1U
|
||||
#define EEPROM_ADDR_PARAMETERS 512U
|
||||
#define EEPROM_ADDR_STARTUP_BLOCK 768U
|
||||
#define EEPROM_ADDR_BUILD_INFO 942U
|
||||
|
||||
// Define EEPROM address indexing for coordinate parameters
|
||||
#define N_COORDINATE_SYSTEM 6 // Number of supported work coordinate systems (from index 1)
|
||||
#define SETTING_INDEX_NCOORD N_COORDINATE_SYSTEM+1 // Total number of system stored (from index 0)
|
||||
// NOTE: Work coordinate indices are (0=G54, 1=G55, ... , 6=G59)
|
||||
#define SETTING_INDEX_G28 N_COORDINATE_SYSTEM // Home position 1
|
||||
#define SETTING_INDEX_G30 N_COORDINATE_SYSTEM+1 // Home position 2
|
||||
// #define SETTING_INDEX_G92 N_COORDINATE_SYSTEM+2 // Coordinate offset (G92.2,G92.3 not supported)
|
||||
|
||||
// Define Grbl axis settings numbering scheme. Starts at START_VAL, every INCREMENT, over N_SETTINGS.
|
||||
#ifndef SHOW_EXTENDED_SETTINGS
|
||||
#define AXIS_N_SETTINGS 4
|
||||
#else
|
||||
#define AXIS_N_SETTINGS 8
|
||||
#endif
|
||||
#define AXIS_SETTINGS_START_VAL 100 // NOTE: Reserving settings values >= 100 for axis settings. Up to 255.
|
||||
#define AXIS_SETTINGS_INCREMENT 10 // Must be greater than the number of axis settings
|
||||
|
||||
#define USER_SETTING_COUNT 5 // for user to define for their machine
|
||||
|
||||
// Global persistent settings (Stored from byte EEPROM_ADDR_GLOBAL onwards)
|
||||
typedef struct {
|
||||
// Axis settings
|
||||
float steps_per_mm[N_AXIS];
|
||||
float max_rate[N_AXIS];
|
||||
float acceleration[N_AXIS];
|
||||
float max_travel[N_AXIS];
|
||||
float current[N_AXIS]; // $140... run current (extended set)
|
||||
float hold_current[N_AXIS]; // $150 percent of run current (extended set)
|
||||
uint16_t microsteps[N_AXIS]; // $160... (extended set)
|
||||
uint8_t stallguard[N_AXIS]; // $170... (extended set)
|
||||
|
||||
// Remaining Grbl settings
|
||||
uint8_t pulse_microseconds;
|
||||
uint8_t step_invert_mask;
|
||||
uint8_t dir_invert_mask;
|
||||
uint8_t stepper_idle_lock_time; // If max value 255, steppers do not disable.
|
||||
uint8_t status_report_mask; // Mask to indicate desired report data.
|
||||
float junction_deviation;
|
||||
float arc_tolerance;
|
||||
|
||||
float spindle_pwm_freq; // $33 Hz (extended set)
|
||||
float spindle_pwm_off_value; // $34 Percent (extended set)
|
||||
float spindle_pwm_min_value; // $35 Percent (extended set)
|
||||
float spindle_pwm_max_value; // $36 Percent (extended set)
|
||||
|
||||
float rpm_max;
|
||||
float rpm_min;
|
||||
|
||||
uint8_t flags; // Contains default boolean settings
|
||||
|
||||
uint8_t homing_dir_mask;
|
||||
float homing_feed_rate;
|
||||
float homing_seek_rate;
|
||||
uint16_t homing_debounce_delay;
|
||||
float homing_pulloff;
|
||||
|
||||
int16_t machine_int16[USER_SETTING_COUNT]; // settings starting at 80 to be defined by the user
|
||||
float machine_float[USER_SETTING_COUNT]; // settings starting at 80 to be defined by the user
|
||||
|
||||
} settings_t;
|
||||
extern settings_t settings;
|
||||
|
||||
// Initialize the configuration subsystem (load settings from EEPROM)
|
||||
void settings_init();
|
||||
void settings_restore(uint8_t restore_flag);
|
||||
void write_global_settings();
|
||||
uint8_t read_global_settings();
|
||||
|
||||
uint8_t settings_read_startup_line(uint8_t n, char *line);
|
||||
void settings_store_startup_line(uint8_t n, char *line);
|
||||
|
||||
uint8_t settings_read_build_info(char *line);
|
||||
void settings_store_build_info(char *line);
|
||||
|
||||
uint8_t settings_store_global_setting(uint8_t parameter, float value);
|
||||
|
||||
// Writes selected coordinate data to EEPROM
|
||||
void settings_write_coord_data(uint8_t coord_select, float *coord_data);
|
||||
|
||||
// Reads selected coordinate data from EEPROM
|
||||
uint8_t settings_read_coord_data(uint8_t coord_select, float *coord_data);
|
||||
|
||||
// Returns the step pin mask according to Grbl's internal axis numbering
|
||||
uint8_t get_step_pin_mask(uint8_t i);
|
||||
|
||||
// Returns the direction pin mask according to Grbl's internal axis numbering
|
||||
uint8_t get_direction_pin_mask(uint8_t i);
|
||||
|
||||
void settings_spi_driver_init();
|
||||
#endif
|
||||
|
123
Grbl_Esp32-master/Grbl_Esp32/solenoid_pen.cpp
Normal file
123
Grbl_Esp32-master/Grbl_Esp32/solenoid_pen.cpp
Normal file
@ -0,0 +1,123 @@
|
||||
/*
|
||||
solenoid_pen.cpp
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef USE_PEN_SOLENOID
|
||||
|
||||
static TaskHandle_t solenoidSyncTaskHandle = 0;
|
||||
|
||||
// used to delay turn on
|
||||
bool solenoid_pen_enable;
|
||||
uint16_t solenoide_hold_count;
|
||||
|
||||
void solenoid_init()
|
||||
{
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Solenoid Mode]\r\n"); // startup message
|
||||
//validate_servo_settings(true); // display any calibration errors
|
||||
|
||||
solenoid_pen_enable = false; // start delay has not completed yet.
|
||||
solenoide_hold_count = 0; // initialize
|
||||
|
||||
// setup PWM channel
|
||||
ledcSetup(SOLENOID_CHANNEL_NUM, SOLENOID_PWM_FREQ, SOLENOID_PWM_RES_BITS);
|
||||
ledcAttachPin(SOLENOID_PEN_PIN, SOLENOID_CHANNEL_NUM);
|
||||
|
||||
solenoid_disable(); // start it it off
|
||||
|
||||
// setup a task that will calculate the determine and set the servo position
|
||||
xTaskCreatePinnedToCore( solenoidSyncTask, // task
|
||||
"solenoidSyncTask", // name for task
|
||||
4096, // size of task stack
|
||||
NULL, // parameters
|
||||
1, // priority
|
||||
&solenoidSyncTaskHandle,
|
||||
0 // core
|
||||
);
|
||||
}
|
||||
|
||||
// turn off the PWM (0 duty)
|
||||
void solenoid_disable()
|
||||
{
|
||||
ledcWrite(SOLENOID_CHANNEL_NUM, 0);
|
||||
}
|
||||
|
||||
// this is the task
|
||||
void solenoidSyncTask(void *pvParameters)
|
||||
{
|
||||
int32_t current_position[N_AXIS]; // copy of current location
|
||||
float m_pos[N_AXIS]; // machine position in mm
|
||||
TickType_t xLastWakeTime;
|
||||
const TickType_t xSolenoidFrequency = SOLENOID_TIMER_INT_FREQ; // in ticks (typically ms)
|
||||
uint16_t solenoid_delay_counter = 0;
|
||||
|
||||
xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time.
|
||||
while(true) { // don't ever return from this or the task dies
|
||||
if (!solenoid_pen_enable) {
|
||||
solenoid_delay_counter++;
|
||||
solenoid_pen_enable = (solenoid_delay_counter > SOLENOID_TURNON_DELAY);
|
||||
}
|
||||
else {
|
||||
memcpy(current_position,sys_position,sizeof(sys_position)); // get current position in step
|
||||
system_convert_array_steps_to_mpos(m_pos,current_position); // convert to millimeters
|
||||
calc_solenoid(m_pos[Z_AXIS]); // calculate kinematics and move the servos
|
||||
}
|
||||
vTaskDelayUntil(&xLastWakeTime, xSolenoidFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate and set the PWM value for the servo
|
||||
void calc_solenoid(float penZ)
|
||||
{
|
||||
uint32_t solenoid_pen_pulse_len;
|
||||
|
||||
if (!solenoid_pen_enable) // only proceed if startup delay as expired
|
||||
return;
|
||||
|
||||
if (penZ < 0 && (sys.state != STATE_ALARM)) { // alarm also makes it go up
|
||||
solenoide_hold_count = 0; // reset this count
|
||||
solenoid_pen_pulse_len = 0; //
|
||||
}
|
||||
else {
|
||||
if (solenoide_hold_count < SOLENOID_PULSE_LEN_HOLD) {
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_UP;
|
||||
solenoide_hold_count++;
|
||||
}
|
||||
else {
|
||||
solenoid_pen_pulse_len = SOLENOID_PULSE_LEN_HOLD;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// skip setting value if it is unchanged
|
||||
if (ledcRead(SOLENOID_CHANNEL_NUM) == solenoid_pen_pulse_len)
|
||||
return;
|
||||
|
||||
// update the PWM value
|
||||
// ledcWrite appears to have issues with interrupts, so make this a critical section
|
||||
portMUX_TYPE myMutex = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL(&myMutex);
|
||||
ledcWrite(SOLENOID_CHANNEL_NUM, solenoid_pen_pulse_len);
|
||||
portEXIT_CRITICAL(&myMutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
53
Grbl_Esp32-master/Grbl_Esp32/solenoid_pen.h
Normal file
53
Grbl_Esp32-master/Grbl_Esp32/solenoid_pen.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
solenoid_pen.h
|
||||
Part of Grbl_ESP32
|
||||
|
||||
copyright (c) 2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Usage notes:
|
||||
This is designed to use a solenoid to lift a pen.
|
||||
When the current Z location is below zero the pen is down
|
||||
If the Z goes to zero or above the pen goes up.
|
||||
There are two power levels, the initial pull up strength, then the hold strength
|
||||
|
||||
|
||||
Note: There is a still a virtual Z axis that has a finite speed.
|
||||
If your gcode is commanding long travels in Z, there will be delays
|
||||
between solenoid states as the Z "travels" to the location that will
|
||||
change the state.
|
||||
|
||||
*/
|
||||
|
||||
#define SOLENOID_PWM_FREQ 5000
|
||||
#define SOLENOID_PWM_RES_BITS 8
|
||||
|
||||
#define SOLENOID_TURNON_DELAY (SOLENOID_TIMER_INT_FREQ/2)
|
||||
#define SOLENOID_PULSE_LEN_UP 255
|
||||
#define SOLENOID_HOLD_DELAY (SOLENOID_TIMER_INT_FREQ/2) // in task counts...after this delay power will change to hold level
|
||||
#define SOLENOID_PULSE_LEN_HOLD 80 // solenoid hold level ... typically a lower value to prevent overheating
|
||||
|
||||
#define SOLENOID_TIMER_INT_FREQ 50
|
||||
|
||||
#ifndef solenoid_h
|
||||
#define solenoid_h
|
||||
|
||||
void solenoid_init();
|
||||
void solenoid_disable();
|
||||
void solenoidSyncTask(void *pvParameters);
|
||||
void calc_solenoid(float penZ);
|
||||
|
||||
#endif
|
257
Grbl_Esp32-master/Grbl_Esp32/spindle_control.cpp
Normal file
257
Grbl_Esp32-master/Grbl_Esp32/spindle_control.cpp
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
spindle_control.cpp - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#ifdef SPINDLE_PWM_PIN
|
||||
static float pwm_gradient; // Precalulated value to speed up rpm to PWM conversions.
|
||||
float spindle_pwm_period;
|
||||
float spindle_pwm_off_value;
|
||||
float spindle_pwm_min_value;
|
||||
float spindle_pwm_max_value;
|
||||
#endif
|
||||
|
||||
void spindle_init()
|
||||
{
|
||||
|
||||
#ifdef SPINDLE_PWM_PIN
|
||||
|
||||
#ifdef INVERT_SPINDLE_PWM
|
||||
grbl_send(CLIENT_SERIAL, "[MSG: INVERT_SPINDLE_PWM]\r\n");
|
||||
#endif
|
||||
|
||||
#ifdef INVERT_SPINDLE_ENABLE_PIN
|
||||
grbl_send(CLIENT_SERIAL, "[MSG: INVERT_SPINDLE_ENABLE_PIN]\r\n");
|
||||
#endif
|
||||
|
||||
spindle_pwm_period = SPINDLE_PULSE_RES_COUNT;
|
||||
|
||||
|
||||
spindle_pwm_off_value = (spindle_pwm_period * settings.spindle_pwm_off_value / 100);
|
||||
spindle_pwm_min_value = (spindle_pwm_period * settings.spindle_pwm_min_value / 100);
|
||||
spindle_pwm_max_value = (spindle_pwm_period * settings.spindle_pwm_max_value / 100);
|
||||
|
||||
//pwm_gradient = (settings.spindle_pwm_max_value - settings.spindle_pwm_min_value)/(settings.rpm_max-settings.rpm_min);
|
||||
pwm_gradient = (spindle_pwm_max_value-spindle_pwm_min_value)/(settings.rpm_max-settings.rpm_min);
|
||||
|
||||
|
||||
if ( (F_TIMERS / (uint32_t)settings.spindle_pwm_freq) < spindle_pwm_max_value) {
|
||||
/*
|
||||
PWM Generator is based on 80,000,000 Hz counter
|
||||
Therefor the freq determines the resolution 80,000,000 / freq = max resolution
|
||||
For 5000 that is 80,000,000 / 5000 = 16000
|
||||
Round down to nearest bit count for SPINDLE_PWM_MAX_VALUE = 13bits (8192)
|
||||
*/
|
||||
grbl_sendf(CLIENT_SERIAL, "[MSG: Warning! Spindle freq %5.0f too high for requested PWM max %5.2f%% (%5.0f)]\r\n", settings.spindle_pwm_freq, settings.spindle_pwm_max_value, spindle_pwm_max_value);
|
||||
}
|
||||
|
||||
// Use DIR and Enable if pins are defined
|
||||
#ifdef SPINDLE_ENABLE_PIN
|
||||
pinMode(SPINDLE_ENABLE_PIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
#ifdef SPINDLE_DIR_PIN
|
||||
pinMode(SPINDLE_DIR_PIN, OUTPUT);
|
||||
#endif
|
||||
|
||||
// use the LED control feature to setup PWM https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/ledc.html
|
||||
ledcSetup(SPINDLE_PWM_CHANNEL, (double)settings.spindle_pwm_freq, SPINDLE_PWM_BIT_PRECISION); // setup the channel
|
||||
ledcAttachPin(SPINDLE_PWM_PIN, SPINDLE_PWM_CHANNEL); // attach the PWM to the pin
|
||||
|
||||
// Start with spindle off off
|
||||
spindle_stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
void spindle_stop()
|
||||
{
|
||||
spindle_set_enable(false);
|
||||
|
||||
#ifdef SPINDLE_PWM_PIN
|
||||
#ifndef INVERT_SPINDLE_PWM
|
||||
grbl_analogWrite(SPINDLE_PWM_CHANNEL, spindle_pwm_off_value);
|
||||
#else
|
||||
grbl_analogWrite(SPINDLE_PWM_CHANNEL, (1<<SPINDLE_PWM_BIT_PRECISION)); // TO DO...wrong for min_pwm
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8_t spindle_get_state() // returns SPINDLE_STATE_DISABLE, SPINDLE_STATE_CW or SPINDLE_STATE_CCW
|
||||
{
|
||||
// TODO Update this when direction and enable pin are added
|
||||
#ifndef SPINDLE_PWM_PIN
|
||||
return(SPINDLE_STATE_DISABLE);
|
||||
#else
|
||||
|
||||
if (ledcRead(SPINDLE_PWM_CHANNEL) == 0) // Check the PWM value
|
||||
return(SPINDLE_STATE_DISABLE);
|
||||
else
|
||||
{
|
||||
#ifdef SPINDLE_DIR_PIN
|
||||
if (digitalRead(SPINDLE_DIR_PIN))
|
||||
return (SPINDLE_STATE_CW);
|
||||
else
|
||||
return(SPINDLE_STATE_CCW);
|
||||
#else
|
||||
return(SPINDLE_STATE_CW);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void spindle_set_speed(uint32_t pwm_value)
|
||||
{
|
||||
#ifndef SPINDLE_PWM_PIN
|
||||
return;
|
||||
#else
|
||||
#ifndef SPINDLE_ENABLE_OFF_WITH_ZERO_SPEED
|
||||
spindle_set_enable(true);
|
||||
#else
|
||||
spindle_set_enable(pwm_value != 0);
|
||||
#endif
|
||||
|
||||
#ifndef INVERT_SPINDLE_PWM
|
||||
grbl_analogWrite(SPINDLE_PWM_CHANNEL, pwm_value);
|
||||
#else
|
||||
grbl_analogWrite(SPINDLE_PWM_CHANNEL, (1<<SPINDLE_PWM_BIT_PRECISION) - pwm_value);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t spindle_compute_pwm_value(float rpm){
|
||||
#ifdef SPINDLE_PWM_PIN
|
||||
uint32_t pwm_value;
|
||||
rpm *= (0.010*sys.spindle_speed_ovr); // Scale by spindle speed override value.
|
||||
// Calculate PWM register value based on rpm max/min settings and programmed rpm.
|
||||
if ((settings.rpm_min >= settings.rpm_max) || (rpm >= settings.rpm_max)) {
|
||||
// No PWM range possible. Set simple on/off spindle control pin state.
|
||||
sys.spindle_speed = settings.rpm_max;
|
||||
pwm_value = spindle_pwm_max_value;
|
||||
} else if (rpm <= settings.rpm_min) {
|
||||
if (rpm == 0.0) { // S0 disables spindle
|
||||
sys.spindle_speed = 0.0;
|
||||
pwm_value = spindle_pwm_off_value;
|
||||
} else { // Set minimum PWM output
|
||||
sys.spindle_speed = settings.rpm_min;
|
||||
pwm_value = spindle_pwm_min_value;
|
||||
}
|
||||
} else {
|
||||
// Compute intermediate PWM value with linear spindle speed model.
|
||||
// NOTE: A nonlinear model could be installed here, if required, but keep it VERY light-weight.
|
||||
sys.spindle_speed = rpm;
|
||||
#ifdef ENABLE_PIECEWISE_LINEAR_SPINDLE
|
||||
pwm_value = piecewise_linear_fit(rpm);
|
||||
#else
|
||||
pwm_value = floor((rpm - settings.rpm_min)*pwm_gradient) + settings.spindle_pwm_min_value;
|
||||
#endif
|
||||
}
|
||||
return(pwm_value);
|
||||
#else
|
||||
return(0); // no SPINDLE_PWM_PIN
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Called by spindle_set_state() and step segment generator. Keep routine small and efficient.
|
||||
void spindle_set_state(uint8_t state, float rpm)
|
||||
{
|
||||
#ifdef SPINDLE_PWM_PIN
|
||||
if (sys.abort) { return; } // Block during abort.
|
||||
if (state == SPINDLE_DISABLE) { // Halt or set spindle direction and rpm.
|
||||
sys.spindle_speed = 0.0;
|
||||
spindle_stop();
|
||||
} else {
|
||||
|
||||
// TODO ESP32 Enable and direction control
|
||||
#ifdef SPINDLE_DIR_PIN
|
||||
digitalWrite(SPINDLE_DIR_PIN, state == SPINDLE_ENABLE_CW);
|
||||
#endif
|
||||
|
||||
// NOTE: Assumes all calls to this function is when Grbl is not moving or must remain off.
|
||||
if (settings.flags & BITFLAG_LASER_MODE) {
|
||||
if (state == SPINDLE_ENABLE_CCW) { rpm = 0.0; } // TODO: May need to be rpm_min*(100/MAX_SPINDLE_SPEED_OVERRIDE);
|
||||
}
|
||||
|
||||
spindle_set_speed(spindle_compute_pwm_value(rpm));
|
||||
}
|
||||
sys.report_ovr_counter = 0; // Set to report change immediately
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void spindle_sync(uint8_t state, float rpm)
|
||||
{
|
||||
if (sys.state == STATE_CHECK_MODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
protocol_buffer_synchronize(); // Empty planner buffer to ensure spindle is set when programmed.
|
||||
spindle_set_state(state,rpm);
|
||||
}
|
||||
|
||||
|
||||
void grbl_analogWrite(uint8_t chan, uint32_t duty)
|
||||
{
|
||||
if (ledcRead(chan) != duty) // reduce unnecessary calls to ledcWrite()
|
||||
{
|
||||
// Useful for debug, but too many messages in laser mode
|
||||
// grbl_sendf(CLIENT_SERIAL, "[MSG: grbl_analogWrite %d]\r\n", duty);
|
||||
ledcWrite(chan, duty);
|
||||
}
|
||||
}
|
||||
|
||||
void spindle_set_enable(bool enable)
|
||||
{
|
||||
#ifdef SPINDLE_ENABLE_PIN
|
||||
#ifndef INVERT_SPINDLE_ENABLE_PIN
|
||||
digitalWrite(SPINDLE_ENABLE_PIN, enable); // turn off (low) with zero speed
|
||||
#else
|
||||
digitalWrite(SPINDLE_ENABLE_PIN, !enable); // turn off (high) with zero speed
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
uint32_t piecewise_linear_fit(float rpm) {
|
||||
uint32_t pwm_value;
|
||||
|
||||
#if (N_PIECES > 3)
|
||||
if (rpm > RPM_POINT34) {
|
||||
pwm_value = floor(RPM_LINE_A4*rpm - RPM_LINE_B4);
|
||||
} else
|
||||
#endif
|
||||
#if (N_PIECES > 2)
|
||||
if (rpm > RPM_POINT23) {
|
||||
pwm_value = floor(RPM_LINE_A3*rpm - RPM_LINE_B3);
|
||||
} else
|
||||
#endif
|
||||
#if (N_PIECES > 1)
|
||||
if (rpm > RPM_POINT12) {
|
||||
pwm_value = floor(RPM_LINE_A2*rpm - RPM_LINE_B2);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
pwm_value = floor(RPM_LINE_A1*rpm - RPM_LINE_B1);
|
||||
}
|
||||
return pwm_value;
|
||||
}
|
||||
|
||||
|
||||
|
47
Grbl_Esp32-master/Grbl_Esp32/spindle_control.h
Normal file
47
Grbl_Esp32-master/Grbl_Esp32/spindle_control.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
spindle.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef spindle_control_h
|
||||
#define spindle_control_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
#define SPINDLE_NO_SYNC false
|
||||
#define SPINDLE_FORCE_SYNC true
|
||||
|
||||
#define SPINDLE_STATE_DISABLE 0 // Must be zero.
|
||||
#define SPINDLE_STATE_CW bit(0)
|
||||
#define SPINDLE_STATE_CCW bit(1)
|
||||
|
||||
#define SPINDLE_PULSE_RES_COUNT ((1<<SPINDLE_PWM_BIT_PRECISION) -1) //(don't change)
|
||||
|
||||
void spindle_init();
|
||||
void spindle_stop();
|
||||
uint8_t spindle_get_state();
|
||||
void spindle_set_speed(uint32_t pwm_value);
|
||||
uint32_t spindle_compute_pwm_value(float rpm);
|
||||
void spindle_set_state(uint8_t state, float rpm);
|
||||
void spindle_sync(uint8_t state, float rpm);
|
||||
void grbl_analogWrite(uint8_t chan, uint32_t duty);
|
||||
void spindle_set_enable(bool enable);
|
||||
uint32_t piecewise_linear_fit(float rpm);
|
||||
|
||||
#endif
|
1540
Grbl_Esp32-master/Grbl_Esp32/stepper.cpp
Normal file
1540
Grbl_Esp32-master/Grbl_Esp32/stepper.cpp
Normal file
File diff suppressed because it is too large
Load Diff
131
Grbl_Esp32-master/Grbl_Esp32/stepper.h
Normal file
131
Grbl_Esp32-master/Grbl_Esp32/stepper.h
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
stepper.h - stepper motor driver: executes motion plans of planner.c using the stepper motors
|
||||
Part of Grbl
|
||||
|
||||
Copyright (c) 2011-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
Copyright (c) 2009-2011 Simen Svale Skogsrud
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef stepper_h
|
||||
#define stepper_h
|
||||
|
||||
#ifndef SEGMENT_BUFFER_SIZE
|
||||
#define SEGMENT_BUFFER_SIZE 6
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "grbl.h"
|
||||
#include "config.h"
|
||||
|
||||
// Some useful constants.
|
||||
#define DT_SEGMENT (1.0/(ACCELERATION_TICKS_PER_SECOND*60.0)) // min/segment
|
||||
#define REQ_MM_INCREMENT_SCALAR 1.25
|
||||
#define RAMP_ACCEL 0
|
||||
#define RAMP_CRUISE 1
|
||||
#define RAMP_DECEL 2
|
||||
#define RAMP_DECEL_OVERRIDE 3
|
||||
|
||||
#define PREP_FLAG_RECALCULATE bit(0)
|
||||
#define PREP_FLAG_HOLD_PARTIAL_BLOCK bit(1)
|
||||
#define PREP_FLAG_PARKING bit(2)
|
||||
#define PREP_FLAG_DECEL_OVERRIDE bit(3)
|
||||
|
||||
// Define Adaptive Multi-Axis Step-Smoothing(AMASS) levels and cutoff frequencies. The highest level
|
||||
// frequency bin starts at 0Hz and ends at its cutoff frequency. The next lower level frequency bin
|
||||
// starts at the next higher cutoff frequency, and so on. The cutoff frequencies for each level must
|
||||
// be considered carefully against how much it over-drives the stepper ISR, the accuracy of the 16-bit
|
||||
// timer, and the CPU overhead. Level 0 (no AMASS, normal operation) frequency bin starts at the
|
||||
// Level 1 cutoff frequency and up to as fast as the CPU allows (over 30kHz in limited testing).
|
||||
// NOTE: AMASS cutoff frequency multiplied by ISR overdrive factor must not exceed maximum step frequency.
|
||||
// NOTE: Current settings are set to overdrive the ISR to no more than 16kHz, balancing CPU overhead
|
||||
// and timer accuracy. Do not alter these settings unless you know what you are doing.
|
||||
///#ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
|
||||
#define MAX_AMASS_LEVEL 3
|
||||
// AMASS_LEVEL0: Normal operation. No AMASS. No upper cutoff frequency. Starts at LEVEL1 cutoff frequency.
|
||||
// Note ESP32 use F_STEPPER_TIMER rather than the AVR F_CPU
|
||||
#define AMASS_LEVEL1 (F_STEPPER_TIMER/8000) // Over-drives ISR (x2). Defined as F_CPU/(Cutoff frequency in Hz)
|
||||
#define AMASS_LEVEL2 (F_STEPPER_TIMER/4000) // Over-drives ISR (x4)
|
||||
#define AMASS_LEVEL3 (F_STEPPER_TIMER/2000) // Over-drives ISR (x8)
|
||||
|
||||
#if MAX_AMASS_LEVEL <= 0
|
||||
error "AMASS must have 1 or more levels to operate correctly."
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
#define STEP_TIMER_GROUP TIMER_GROUP_0
|
||||
#define STEP_TIMER_INDEX TIMER_0
|
||||
|
||||
// esp32 work around for diable in main loop
|
||||
extern uint64_t stepper_idle_counter;
|
||||
extern bool stepper_idle;
|
||||
|
||||
extern uint8_t ganged_mode;
|
||||
|
||||
// -- Task handles for use in the notifications
|
||||
void IRAM_ATTR onSteppertimer();
|
||||
void IRAM_ATTR onStepperOffTimer();
|
||||
|
||||
#ifdef USE_RMT_STEPS
|
||||
void initRMT();
|
||||
#endif
|
||||
|
||||
void stepper_init();
|
||||
|
||||
// Enable steppers, but cycle does not start unless called by motion control or realtime command.
|
||||
void st_wake_up();
|
||||
|
||||
// Immediately disables steppers
|
||||
void st_go_idle();
|
||||
|
||||
// Generate the step and direction port invert masks.
|
||||
void st_generate_step_dir_invert_masks();
|
||||
|
||||
// Reset the stepper subsystem variables
|
||||
void st_reset();
|
||||
|
||||
// Changes the run state of the step segment buffer to execute the special parking motion.
|
||||
void st_parking_setup_buffer();
|
||||
|
||||
// Restores the step segment buffer to the normal run state after a parking motion.
|
||||
void st_parking_restore_buffer();
|
||||
|
||||
// Reloads step segment buffer. Called continuously by realtime execution system.
|
||||
void st_prep_buffer();
|
||||
|
||||
// Called by planner_recalculate() when the executing block is updated by the new plan.
|
||||
void st_update_plan_block_parameters();
|
||||
|
||||
// Called by realtime status reporting if realtime rate reporting is enabled in config.h.
|
||||
float st_get_realtime_rate();
|
||||
|
||||
// disable (or enable) steppers via STEPPERS_DISABLE_PIN
|
||||
void set_stepper_disable(uint8_t disable);
|
||||
bool get_stepper_disable(); // returns the state of the pin
|
||||
|
||||
void set_step_pin_on(uint8_t axis, uint8_t isOn);
|
||||
void set_direction_pin_on(uint8_t axis, uint8_t isOn);
|
||||
void set_stepper_pins_on(uint8_t onMask);
|
||||
void set_direction_pins_on(uint8_t onMask);
|
||||
|
||||
void Stepper_Timer_WritePeriod(uint64_t alarm_val);
|
||||
void Stepper_Timer_Start();
|
||||
void Stepper_Timer_Stop();
|
||||
|
||||
#endif
|
614
Grbl_Esp32-master/Grbl_Esp32/system.cpp
Normal file
614
Grbl_Esp32-master/Grbl_Esp32/system.cpp
Normal file
@ -0,0 +1,614 @@
|
||||
/*
|
||||
system.cpp - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modified for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "grbl.h"
|
||||
#include "config.h"
|
||||
|
||||
xQueueHandle control_sw_queue; // used by control switch debouncing
|
||||
bool debouncing = false; // debouncing in process
|
||||
|
||||
void system_ini() // Renamed from system_init() due to conflict with esp32 files
|
||||
{
|
||||
// setup control inputs
|
||||
#ifndef IGNORE_CONTROL_PINS
|
||||
|
||||
#ifdef CONTROL_SAFETY_DOOR_PIN
|
||||
pinMode(CONTROL_SAFETY_DOOR_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(CONTROL_SAFETY_DOOR_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
#ifdef CONTROL_RESET_PIN
|
||||
pinMode(CONTROL_RESET_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(CONTROL_RESET_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
#ifdef CONTROL_FEED_HOLD_PIN
|
||||
pinMode(CONTROL_FEED_HOLD_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(CONTROL_FEED_HOLD_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
#ifdef CONTROL_CYCLE_START_PIN
|
||||
pinMode(CONTROL_CYCLE_START_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(CONTROL_CYCLE_START_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 0]\r\n");
|
||||
pinMode(MACRO_BUTTON_0_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_0_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 1]\r\n");
|
||||
pinMode(MACRO_BUTTON_1_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_1_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 2]\r\n");
|
||||
pinMode(MACRO_BUTTON_2_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_2_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_3_PIN
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Macro Pin 3]\r\n");
|
||||
pinMode(MACRO_BUTTON_3_PIN, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(MACRO_BUTTON_3_PIN), isr_control_inputs, CHANGE);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_CONTROL_SW_DEBOUNCE
|
||||
// setup task used for debouncing
|
||||
control_sw_queue = xQueueCreate(10, sizeof( int ));
|
||||
|
||||
xTaskCreate(controlCheckTask,
|
||||
"controlCheckTask",
|
||||
2048,
|
||||
NULL,
|
||||
5, // priority
|
||||
NULL);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
//customize pin definition if needed
|
||||
#if (GRBL_SPI_SS != -1) || (GRBL_SPI_MISO != -1) || (GRBL_SPI_MOSI != -1) || (GRBL_SPI_SCK != -1)
|
||||
SPI.begin(GRBL_SPI_SCK, GRBL_SPI_MISO, GRBL_SPI_MOSI, GRBL_SPI_SS);
|
||||
#endif
|
||||
|
||||
// Setup USER_DIGITAL_PINs controlled by M62 and M63
|
||||
#ifdef USER_DIGITAL_PIN_1
|
||||
pinMode(USER_DIGITAL_PIN_1, OUTPUT);
|
||||
sys_io_control(1<<1, false); // turn off
|
||||
#endif
|
||||
|
||||
#ifdef USER_DIGITAL_PIN_2
|
||||
pinMode(USER_DIGITAL_PIN_2, OUTPUT);
|
||||
sys_io_control(1<<2, false); // turn off
|
||||
#endif
|
||||
|
||||
#ifdef USER_DIGITAL_PIN_3
|
||||
pinMode(USER_DIGITAL_PIN_3, OUTPUT);
|
||||
sys_io_control(1<<3, false); // turn off
|
||||
#endif
|
||||
|
||||
#ifdef USER_DIGITAL_PIN_4
|
||||
pinMode(USER_DIGITAL_PIN_4, OUTPUT);
|
||||
sys_io_control(1<<4, false); // turn off
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_CONTROL_SW_DEBOUNCE
|
||||
// this is the debounce task
|
||||
void controlCheckTask(void *pvParameters)
|
||||
{
|
||||
while(true) {
|
||||
int evt;
|
||||
xQueueReceive(control_sw_queue, &evt, portMAX_DELAY); // block until receive queue
|
||||
vTaskDelay(CONTROL_SW_DEBOUNCE_PERIOD); // delay a while
|
||||
|
||||
uint8_t pin = system_control_get_state();
|
||||
if (pin) {
|
||||
system_exec_control_pin(pin);
|
||||
}
|
||||
debouncing = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void IRAM_ATTR isr_control_inputs()
|
||||
{
|
||||
#ifdef ENABLE_CONTROL_SW_DEBOUNCE
|
||||
// we will start a task that will recheck the switches after a small delay
|
||||
int evt;
|
||||
if (!debouncing) { // prevent resending until debounce is done
|
||||
debouncing = true;
|
||||
xQueueSendFromISR(control_sw_queue, &evt, NULL);
|
||||
}
|
||||
#else
|
||||
uint8_t pin = system_control_get_state();
|
||||
system_exec_control_pin(pin);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Executes user startup script, if stored.
|
||||
void system_execute_startup(char *line)
|
||||
{
|
||||
uint8_t n;
|
||||
for (n=0; n < N_STARTUP_LINE; n++) {
|
||||
if (!(settings_read_startup_line(n, line))) {
|
||||
line[0] = 0;
|
||||
report_execute_startup_message(line,STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
|
||||
} else {
|
||||
if (line[0] != 0) {
|
||||
uint8_t status_code = gc_execute_line(line, CLIENT_SERIAL);
|
||||
report_execute_startup_message(line,status_code, CLIENT_SERIAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Directs and executes one line of formatted input from protocol_process. While mostly
|
||||
// incoming streaming g-code blocks, this also executes Grbl internal commands, such as
|
||||
// settings, initiating the homing cycle, and toggling switch states. This differs from
|
||||
// the realtime command module by being susceptible to when Grbl is ready to execute the
|
||||
// next line during a cycle, so for switches like block delete, the switch only effects
|
||||
// the lines that are processed afterward, not necessarily real-time during a cycle,
|
||||
// since there are motions already stored in the buffer. However, this 'lag' should not
|
||||
// be an issue, since these commands are not typically used during a cycle.
|
||||
uint8_t system_execute_line(char *line, uint8_t client)
|
||||
{
|
||||
uint8_t char_counter = 1;
|
||||
uint8_t helper_var = 0; // Helper variable
|
||||
float parameter, value;
|
||||
|
||||
switch( line[char_counter] ) {
|
||||
case 0 : report_grbl_help(client); break;
|
||||
case 'J' : // Jogging
|
||||
// Execute only if in IDLE or JOG states.
|
||||
if (sys.state != STATE_IDLE && sys.state != STATE_JOG) { return(STATUS_IDLE_ERROR); }
|
||||
if(line[2] != '=') { return(STATUS_INVALID_STATEMENT); }
|
||||
return(gc_execute_line(line, client)); // NOTE: $J= is ignored inside g-code parser and used to detect jog motions.
|
||||
break;
|
||||
case '$': case 'G': case 'C': case 'X':
|
||||
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
|
||||
switch( line[1] ) {
|
||||
case '$' : // Prints Grbl settings
|
||||
if ( sys.state & (STATE_CYCLE | STATE_HOLD) ) { return(STATUS_IDLE_ERROR); } // Block during cycle. Takes too long to print.
|
||||
else { report_grbl_settings(client); }
|
||||
break;
|
||||
case 'G' : // Prints gcode parser state
|
||||
// TODO: Move this to realtime commands for GUIs to request this data during suspend-state.
|
||||
report_gcode_modes(client);
|
||||
break;
|
||||
case 'C' : // Set check g-code mode [IDLE/CHECK]
|
||||
// Perform reset when toggling off. Check g-code mode should only work if Grbl
|
||||
// is idle and ready, regardless of alarm locks. This is mainly to keep things
|
||||
// simple and consistent.
|
||||
if ( sys.state == STATE_CHECK_MODE ) {
|
||||
mc_reset();
|
||||
report_feedback_message(MESSAGE_DISABLED);
|
||||
} else {
|
||||
if (sys.state) { return(STATUS_IDLE_ERROR); } // Requires no alarm mode.
|
||||
sys.state = STATE_CHECK_MODE;
|
||||
report_feedback_message(MESSAGE_ENABLED);
|
||||
}
|
||||
break;
|
||||
case 'X' : // Disable alarm lock [ALARM]
|
||||
if (sys.state == STATE_ALARM) {
|
||||
// Block if safety door is ajar.
|
||||
if (system_check_safety_door_ajar()) { return(STATUS_CHECK_DOOR); }
|
||||
report_feedback_message(MESSAGE_ALARM_UNLOCK);
|
||||
sys.state = STATE_IDLE;
|
||||
// Don't run startup script. Prevents stored moves in startup from causing accidents.
|
||||
} // Otherwise, no effect.
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default :
|
||||
// Block any system command that requires the state as IDLE/ALARM. (i.e. EEPROM, homing)
|
||||
if ( !(sys.state == STATE_IDLE || sys.state == STATE_ALARM) ) { return(STATUS_IDLE_ERROR); }
|
||||
switch( line[1] ) {
|
||||
case '#' : // Print Grbl NGC parameters
|
||||
if ( line[2] != 0 ) { return(STATUS_INVALID_STATEMENT); }
|
||||
else { report_ngc_parameters(client); }
|
||||
break;
|
||||
case 'H' : // Perform homing cycle [IDLE/ALARM] $H
|
||||
if (bit_isfalse(settings.flags,BITFLAG_HOMING_ENABLE)) {return(STATUS_SETTING_DISABLED); }
|
||||
if (system_check_safety_door_ajar()) { return(STATUS_CHECK_DOOR); } // Block if safety door is ajar.
|
||||
sys.state = STATE_HOMING; // Set system state variable
|
||||
if (line[2] == 0) {
|
||||
mc_homing_cycle(HOMING_CYCLE_ALL);
|
||||
#ifdef HOMING_SINGLE_AXIS_COMMANDS
|
||||
} else if (line[3] == 0) {
|
||||
switch (line[2]) {
|
||||
case 'X': mc_homing_cycle(HOMING_CYCLE_X); break;
|
||||
case 'Y': mc_homing_cycle(HOMING_CYCLE_Y); break;
|
||||
case 'Z': mc_homing_cycle(HOMING_CYCLE_Z); break;
|
||||
case 'A': mc_homing_cycle(HOMING_CYCLE_A); break;
|
||||
case 'B': mc_homing_cycle(HOMING_CYCLE_B); break;
|
||||
case 'C': mc_homing_cycle(HOMING_CYCLE_C); break;
|
||||
default: return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
#endif
|
||||
} else { return(STATUS_INVALID_STATEMENT); }
|
||||
if (!sys.abort) { // Execute startup scripts after successful homing.
|
||||
sys.state = STATE_IDLE; // Set to IDLE when complete.
|
||||
st_go_idle(); // Set steppers to the settings idle state before returning.
|
||||
if (line[2] == 0) { system_execute_startup(line); }
|
||||
}
|
||||
break;
|
||||
case 'S' : // Puts Grbl to sleep [IDLE/ALARM]
|
||||
if ((line[2] != 'L') || (line[3] != 'P') || (line[4] != 0)) { return(STATUS_INVALID_STATEMENT); }
|
||||
system_set_exec_state_flag(EXEC_SLEEP); // Set to execute sleep mode immediately
|
||||
break;
|
||||
case 'I' : // Print or store build info. [IDLE/ALARM]
|
||||
if ( line[++char_counter] == 0 ) {
|
||||
settings_read_build_info(line);
|
||||
report_build_info(line, client);
|
||||
#ifdef ENABLE_BUILD_INFO_WRITE_COMMAND
|
||||
} else { // Store startup line [IDLE/ALARM]
|
||||
if(line[char_counter++] != '=') { return(STATUS_INVALID_STATEMENT); }
|
||||
helper_var = char_counter; // Set helper variable as counter to start of user info line.
|
||||
do {
|
||||
line[char_counter-helper_var] = line[char_counter];
|
||||
} while (line[char_counter++] != 0);
|
||||
settings_store_build_info(line);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case 'R' : // Restore defaults [IDLE/ALARM]
|
||||
if ((line[2] != 'S') || (line[3] != 'T') || (line[4] != '=') || (line[6] != 0)) { return(STATUS_INVALID_STATEMENT); }
|
||||
switch (line[5]) {
|
||||
#ifdef ENABLE_RESTORE_EEPROM_DEFAULT_SETTINGS
|
||||
case '$': settings_restore(SETTINGS_RESTORE_DEFAULTS); break;
|
||||
#endif
|
||||
#ifdef ENABLE_RESTORE_EEPROM_CLEAR_PARAMETERS
|
||||
case '#': settings_restore(SETTINGS_RESTORE_PARAMETERS); break;
|
||||
#endif
|
||||
#ifdef ENABLE_RESTORE_EEPROM_WIPE_ALL
|
||||
case '*': settings_restore(SETTINGS_RESTORE_ALL); break;
|
||||
#endif
|
||||
#if defined(ENABLE_BLUETOOTH) || defined(ENABLE_WIFI)
|
||||
case '@': settings_restore(SETTINGS_RESTORE_WIFI_SETTINGS); break;
|
||||
#endif
|
||||
default: return(STATUS_INVALID_STATEMENT);
|
||||
}
|
||||
report_feedback_message(MESSAGE_RESTORE_DEFAULTS);
|
||||
mc_reset(); // Force reset to ensure settings are initialized correctly.
|
||||
break;
|
||||
case 'N' : // Startup lines. [IDLE/ALARM]
|
||||
if ( line[++char_counter] == 0 ) { // Print startup lines
|
||||
for (helper_var=0; helper_var < N_STARTUP_LINE; helper_var++) {
|
||||
if (!(settings_read_startup_line(helper_var, line))) {
|
||||
report_status_message(STATUS_SETTING_READ_FAIL, CLIENT_SERIAL);
|
||||
} else {
|
||||
report_startup_line(helper_var,line, client);
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else { // Store startup line [IDLE Only] Prevents motion during ALARM.
|
||||
if (sys.state != STATE_IDLE) { return(STATUS_IDLE_ERROR); } // Store only when idle.
|
||||
helper_var = true; // Set helper_var to flag storing method.
|
||||
// No break. Continues into default: to read remaining command characters.
|
||||
}
|
||||
|
||||
default : // Storing setting methods [IDLE/ALARM]
|
||||
if(!read_float(line, &char_counter, ¶meter)) { return(STATUS_BAD_NUMBER_FORMAT); }
|
||||
if(line[char_counter++] != '=') { return(STATUS_INVALID_STATEMENT); }
|
||||
if (helper_var) { // Store startup line
|
||||
// Prepare sending gcode block to gcode parser by shifting all characters
|
||||
helper_var = char_counter; // Set helper variable as counter to start of gcode block
|
||||
do {
|
||||
line[char_counter-helper_var] = line[char_counter];
|
||||
} while (line[char_counter++] != 0);
|
||||
// Execute gcode block to ensure block is valid.
|
||||
helper_var = gc_execute_line(line, CLIENT_SERIAL); // Set helper_var to returned status code.
|
||||
if (helper_var) { return(helper_var); }
|
||||
else {
|
||||
helper_var = trunc(parameter); // Set helper_var to int value of parameter
|
||||
settings_store_startup_line(helper_var,line);
|
||||
}
|
||||
} else { // Store global setting.
|
||||
if(!read_float(line, &char_counter, &value)) { return(STATUS_BAD_NUMBER_FORMAT); }
|
||||
if((line[char_counter] != 0) || (parameter > 255)) { return(STATUS_INVALID_STATEMENT); }
|
||||
return(settings_store_global_setting((uint8_t)parameter, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
return(STATUS_OK); // If '$' command makes it to here, then everything's ok.
|
||||
}
|
||||
|
||||
|
||||
// Returns if safety door is ajar(T) or closed(F), based on pin state.
|
||||
uint8_t system_check_safety_door_ajar()
|
||||
{
|
||||
#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
return(system_control_get_state() & CONTROL_PIN_INDEX_SAFETY_DOOR);
|
||||
#else
|
||||
return(false); // Input pin not enabled, so just return that it's closed.
|
||||
#endif
|
||||
}
|
||||
|
||||
// Special handlers for setting and clearing Grbl's real-time execution flags.
|
||||
void system_set_exec_state_flag(uint8_t mask) {
|
||||
// TODO uint8_t sreg = SREG;
|
||||
// TODO cli();
|
||||
sys_rt_exec_state |= (mask);
|
||||
// TODO SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_state_flag(uint8_t mask) {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_state &= ~(mask);
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
void system_set_exec_alarm(uint8_t code) {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_alarm = code;
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_alarm() {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_alarm = 0;
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
void system_set_exec_motion_override_flag(uint8_t mask) {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_motion_override |= (mask);
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
void system_set_exec_accessory_override_flag(uint8_t mask) {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_accessory_override |= (mask);
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_motion_overrides() {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_motion_override = 0;
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
void system_clear_exec_accessory_overrides() {
|
||||
//uint8_t sreg = SREG;
|
||||
//cli();
|
||||
sys_rt_exec_accessory_override = 0;
|
||||
//SREG = sreg;
|
||||
}
|
||||
|
||||
|
||||
void system_flag_wco_change()
|
||||
{
|
||||
#ifdef FORCE_BUFFER_SYNC_DURING_WCO_CHANGE
|
||||
protocol_buffer_synchronize();
|
||||
#endif
|
||||
sys.report_wco_counter = 0;
|
||||
}
|
||||
|
||||
|
||||
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
|
||||
// NOTE: If motor steps and machine position are not in the same coordinate frame, this function
|
||||
// serves as a central place to compute the transformation.
|
||||
float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx)
|
||||
{
|
||||
float pos;
|
||||
#ifdef COREXY
|
||||
if (idx==X_AXIS) {
|
||||
pos = (float)system_convert_corexy_to_x_axis_steps(steps) / settings.steps_per_mm[idx];
|
||||
} else if (idx==Y_AXIS) {
|
||||
pos = (float)system_convert_corexy_to_y_axis_steps(steps) / settings.steps_per_mm[idx];
|
||||
} else {
|
||||
pos = steps[idx]/settings.steps_per_mm[idx];
|
||||
}
|
||||
#else
|
||||
pos = steps[idx]/settings.steps_per_mm[idx];
|
||||
#endif
|
||||
return(pos);
|
||||
}
|
||||
|
||||
void system_convert_array_steps_to_mpos(float *position, int32_t *steps)
|
||||
{
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
position[idx] = system_convert_axis_steps_to_mpos(steps, idx);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Checks and reports if target array exceeds machine travel limits.
|
||||
uint8_t system_check_travel_limits(float *target)
|
||||
{
|
||||
uint8_t idx;
|
||||
for (idx=0; idx<N_AXIS; idx++) {
|
||||
#ifdef HOMING_FORCE_SET_ORIGIN
|
||||
// When homing forced set origin is enabled, soft limits checks need to account for directionality.
|
||||
// NOTE: max_travel is stored as negative
|
||||
if (bit_istrue(settings.homing_dir_mask,bit(idx))) {
|
||||
if (target[idx] < 0 || target[idx] > -settings.max_travel[idx]) { return(true); }
|
||||
} else {
|
||||
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { return(true); }
|
||||
}
|
||||
#else
|
||||
// NOTE: max_travel is stored as negative
|
||||
#ifdef HOMING_FORCE_POSITIVE_SPACE
|
||||
if (target[idx] < 0 || target[idx] > -settings.max_travel[idx]) { return(true); }
|
||||
#else
|
||||
if (target[idx] > 0 || target[idx] < settings.max_travel[idx]) { return(true); }
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
|
||||
// Returns control pin state as a uint8 bitfield. Each bit indicates the input pin state, where
|
||||
// triggered is 1 and not triggered is 0. Invert mask is applied. Bitfield organization is
|
||||
// defined by the CONTROL_PIN_INDEX in the header file.
|
||||
uint8_t system_control_get_state()
|
||||
{
|
||||
uint8_t defined_pin_mask = 0; // a mask of defined pins
|
||||
|
||||
#ifdef IGNORE_CONTROL_PINS
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
uint8_t control_state = 0;
|
||||
#ifdef CONTROL_SAFETY_DOOR_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_SAFETY_DOOR;
|
||||
if (digitalRead(CONTROL_SAFETY_DOOR_PIN)) { control_state |= CONTROL_PIN_INDEX_SAFETY_DOOR; }
|
||||
#endif
|
||||
#ifdef CONTROL_RESET_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_RESET;
|
||||
if (digitalRead(CONTROL_RESET_PIN)) { control_state |= CONTROL_PIN_INDEX_RESET; }
|
||||
#endif
|
||||
#ifdef CONTROL_FEED_HOLD_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_FEED_HOLD;
|
||||
if (digitalRead(CONTROL_FEED_HOLD_PIN)) { control_state |= CONTROL_PIN_INDEX_FEED_HOLD; }
|
||||
#endif
|
||||
#ifdef CONTROL_CYCLE_START_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_CYCLE_START;
|
||||
if (digitalRead(CONTROL_CYCLE_START_PIN)) { control_state |= CONTROL_PIN_INDEX_CYCLE_START; }
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_MACRO_0;
|
||||
if (digitalRead(MACRO_BUTTON_0_PIN)) { control_state |= CONTROL_PIN_INDEX_MACRO_0; }
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_MACRO_1;
|
||||
if (digitalRead(MACRO_BUTTON_1_PIN)) { control_state |= CONTROL_PIN_INDEX_MACRO_1; }
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_MACRO_2;
|
||||
if (digitalRead(MACRO_BUTTON_2_PIN)) { control_state |= CONTROL_PIN_INDEX_MACRO_2; }
|
||||
#endif
|
||||
|
||||
#ifdef MACRO_BUTTON_3_PIN
|
||||
defined_pin_mask |= CONTROL_PIN_INDEX_MACRO_3;
|
||||
if (digitalRead(MACRO_BUTTON_3_PIN)) { control_state |= CONTROL_PIN_INDEX_MACRO_3; }
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef INVERT_CONTROL_PIN_MASK
|
||||
control_state ^= (INVERT_CONTROL_PIN_MASK & defined_pin_mask);
|
||||
#endif
|
||||
|
||||
return(control_state);
|
||||
}
|
||||
|
||||
// Returns limit pin mask according to Grbl internal axis indexing.
|
||||
uint8_t get_limit_pin_mask(uint8_t axis_idx)
|
||||
{
|
||||
if ( axis_idx == X_AXIS ) { return((1<<X_LIMIT_BIT)); }
|
||||
if ( axis_idx == Y_AXIS ) { return((1<<Y_LIMIT_BIT)); }
|
||||
if ( axis_idx == Z_AXIS ) { return((1<<Z_LIMIT_BIT)); }
|
||||
if ( axis_idx == A_AXIS ) { return((1<<A_LIMIT_BIT)); }
|
||||
if ( axis_idx == B_AXIS ) { return((1<<B_LIMIT_BIT)); }
|
||||
if ( axis_idx == C_AXIS ) { return((1<<C_LIMIT_BIT)); }
|
||||
return 0;
|
||||
}
|
||||
|
||||
// execute the function of the control pin
|
||||
void system_exec_control_pin(uint8_t pin) {
|
||||
|
||||
if (bit_istrue(pin,CONTROL_PIN_INDEX_RESET)) {
|
||||
grbl_send(CLIENT_SERIAL, "[MSG:Reset via control pin]\r\n"); // help debug reason for reset
|
||||
mc_reset();
|
||||
}
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_CYCLE_START)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_CYCLE_START);
|
||||
}
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_FEED_HOLD)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_FEED_HOLD);
|
||||
}
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_SAFETY_DOOR)) {
|
||||
bit_true(sys_rt_exec_state, EXEC_SAFETY_DOOR);
|
||||
}
|
||||
#ifdef MACRO_BUTTON_0_PIN
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_0)) {
|
||||
user_defined_macro(CONTROL_PIN_INDEX_MACRO_0); // function must be implemented by user
|
||||
}
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_1_PIN
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_1)) {
|
||||
user_defined_macro(CONTROL_PIN_INDEX_MACRO_1); // function must be implemented by user
|
||||
}
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_2_PIN
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_2)) {
|
||||
user_defined_macro(CONTROL_PIN_INDEX_MACRO_2); // function must be implemented by user
|
||||
}
|
||||
#endif
|
||||
#ifdef MACRO_BUTTON_3_PIN
|
||||
else if (bit_istrue(pin,CONTROL_PIN_INDEX_MACRO_3)) {
|
||||
user_defined_macro(CONTROL_PIN_INDEX_MACRO_3); // function must be implemented by user
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// CoreXY calculation only. Returns x or y-axis "steps" based on CoreXY motor steps.
|
||||
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps)
|
||||
{
|
||||
return( (steps[A_MOTOR] + steps[B_MOTOR])/2 );
|
||||
}
|
||||
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps)
|
||||
{
|
||||
return( (steps[A_MOTOR] - steps[B_MOTOR])/2 );
|
||||
}
|
||||
|
||||
// io_num is the virtual pin# and has nothing to do with the actual esp32 GPIO_NUM_xx
|
||||
// It uses a mask so all can be turned of in ms_reset
|
||||
void sys_io_control(uint8_t io_num_mask, bool turnOn) {
|
||||
protocol_buffer_synchronize();
|
||||
#ifdef USER_DIGITAL_PIN_1
|
||||
if (io_num_mask & 1<<1) {
|
||||
digitalWrite(USER_DIGITAL_PIN_1, turnOn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef USER_DIGITAL_PIN_2
|
||||
if (io_num_mask & 1<<2) {
|
||||
digitalWrite(USER_DIGITAL_PIN_2, turnOn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef USER_DIGITAL_PIN_3
|
||||
if (io_num_mask & 1<<3) {
|
||||
digitalWrite(USER_DIGITAL_PIN_3, turnOn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef USER_DIGITAL_PIN_4
|
||||
if (io_num_mask & 1<<4) {
|
||||
digitalWrite(USER_DIGITAL_PIN_4, turnOn);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
}
|
231
Grbl_Esp32-master/Grbl_Esp32/system.h
Normal file
231
Grbl_Esp32-master/Grbl_Esp32/system.h
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
system.h - Header for system level commands and real-time processes
|
||||
Part of Grbl
|
||||
Copyright (c) 2014-2016 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
2018 - Bart Dring This file was modifed for use on the ESP32
|
||||
CPU. Do not use this with Grbl for atMega328P
|
||||
|
||||
Grbl is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Grbl is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Grbl. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef system_h
|
||||
#define system_h
|
||||
#include "grbl.h"
|
||||
#include "tdef.h"
|
||||
|
||||
// Define global system variables
|
||||
typedef struct {
|
||||
uint8_t state; // Tracks the current system state of Grbl.
|
||||
uint8_t abort; // System abort flag. Forces exit back to main loop for reset.
|
||||
uint8_t suspend; // System suspend bitflag variable that manages holds, cancels, and safety door.
|
||||
uint8_t soft_limit; // Tracks soft limit errors for the state machine. (boolean)
|
||||
uint8_t step_control; // Governs the step segment generator depending on system state.
|
||||
uint8_t probe_succeeded; // Tracks if last probing cycle was successful.
|
||||
uint8_t homing_axis_lock; // Locks axes when limits engage. Used as an axis motion mask in the stepper ISR.
|
||||
uint8_t f_override; // Feed rate override value in percent
|
||||
uint8_t r_override; // Rapids override value in percent
|
||||
uint8_t spindle_speed_ovr; // Spindle speed value in percent
|
||||
uint8_t spindle_stop_ovr; // Tracks spindle stop override states
|
||||
uint8_t report_ovr_counter; // Tracks when to add override data to status reports.
|
||||
uint8_t report_wco_counter; // Tracks when to add work coordinate offset data to status reports.
|
||||
#ifdef ENABLE_PARKING_OVERRIDE_CONTROL
|
||||
uint8_t override_ctrl; // Tracks override control states.
|
||||
#endif
|
||||
|
||||
float spindle_speed;
|
||||
|
||||
} system_t;
|
||||
extern system_t sys;
|
||||
|
||||
|
||||
|
||||
|
||||
// Define system executor bit map. Used internally by realtime protocol as realtime command flags,
|
||||
// which notifies the main program to execute the specified realtime command asynchronously.
|
||||
// NOTE: The system executor uses an unsigned 8-bit volatile variable (8 flag limit.) The default
|
||||
// flags are always false, so the realtime protocol only needs to check for a non-zero value to
|
||||
// know when there is a realtime command to execute.
|
||||
#define EXEC_STATUS_REPORT bit(0) // bitmask 00000001
|
||||
#define EXEC_CYCLE_START bit(1) // bitmask 00000010
|
||||
#define EXEC_CYCLE_STOP bit(2) // bitmask 00000100
|
||||
#define EXEC_FEED_HOLD bit(3) // bitmask 00001000
|
||||
#define EXEC_RESET bit(4) // bitmask 00010000
|
||||
#define EXEC_SAFETY_DOOR bit(5) // bitmask 00100000
|
||||
#define EXEC_MOTION_CANCEL bit(6) // bitmask 01000000
|
||||
#define EXEC_SLEEP bit(7) // bitmask 10000000
|
||||
|
||||
// Alarm executor codes. Valid values (1-255). Zero is reserved.
|
||||
#define EXEC_ALARM_HARD_LIMIT 1
|
||||
#define EXEC_ALARM_SOFT_LIMIT 2
|
||||
#define EXEC_ALARM_ABORT_CYCLE 3
|
||||
#define EXEC_ALARM_PROBE_FAIL_INITIAL 4
|
||||
#define EXEC_ALARM_PROBE_FAIL_CONTACT 5
|
||||
#define EXEC_ALARM_HOMING_FAIL_RESET 6
|
||||
#define EXEC_ALARM_HOMING_FAIL_DOOR 7
|
||||
#define EXEC_ALARM_HOMING_FAIL_PULLOFF 8
|
||||
#define EXEC_ALARM_HOMING_FAIL_APPROACH 9
|
||||
|
||||
// Override bit maps. Realtime bitflags to control feed, rapid, spindle, and coolant overrides.
|
||||
// Spindle/coolant and feed/rapids are separated into two controlling flag variables.
|
||||
#define EXEC_FEED_OVR_RESET bit(0)
|
||||
#define EXEC_FEED_OVR_COARSE_PLUS bit(1)
|
||||
#define EXEC_FEED_OVR_COARSE_MINUS bit(2)
|
||||
#define EXEC_FEED_OVR_FINE_PLUS bit(3)
|
||||
#define EXEC_FEED_OVR_FINE_MINUS bit(4)
|
||||
#define EXEC_RAPID_OVR_RESET bit(5)
|
||||
#define EXEC_RAPID_OVR_MEDIUM bit(6)
|
||||
#define EXEC_RAPID_OVR_LOW bit(7)
|
||||
// #define EXEC_RAPID_OVR_EXTRA_LOW bit(*) // *NOT SUPPORTED*
|
||||
|
||||
#define EXEC_SPINDLE_OVR_RESET bit(0)
|
||||
#define EXEC_SPINDLE_OVR_COARSE_PLUS bit(1)
|
||||
#define EXEC_SPINDLE_OVR_COARSE_MINUS bit(2)
|
||||
#define EXEC_SPINDLE_OVR_FINE_PLUS bit(3)
|
||||
#define EXEC_SPINDLE_OVR_FINE_MINUS bit(4)
|
||||
#define EXEC_SPINDLE_OVR_STOP bit(5)
|
||||
#define EXEC_COOLANT_FLOOD_OVR_TOGGLE bit(6)
|
||||
#define EXEC_COOLANT_MIST_OVR_TOGGLE bit(7)
|
||||
|
||||
// Define system state bit map. The state variable primarily tracks the individual functions
|
||||
// of Grbl to manage each without overlapping. It is also used as a messaging flag for
|
||||
// critical events.
|
||||
#define STATE_IDLE 0 // Must be zero. No flags.
|
||||
#define STATE_ALARM bit(0) // In alarm state. Locks out all g-code processes. Allows settings access.
|
||||
#define STATE_CHECK_MODE bit(1) // G-code check mode. Locks out planner and motion only.
|
||||
#define STATE_HOMING bit(2) // Performing homing cycle
|
||||
#define STATE_CYCLE bit(3) // Cycle is running or motions are being executed.
|
||||
#define STATE_HOLD bit(4) // Active feed hold
|
||||
#define STATE_JOG bit(5) // Jogging mode.
|
||||
#define STATE_SAFETY_DOOR bit(6) // Safety door is ajar. Feed holds and de-energizes system.
|
||||
#define STATE_SLEEP bit(7) // Sleep state.
|
||||
|
||||
// Define system suspend flags. Used in various ways to manage suspend states and procedures.
|
||||
#define SUSPEND_DISABLE 0 // Must be zero.
|
||||
#define SUSPEND_HOLD_COMPLETE bit(0) // Indicates initial feed hold is complete.
|
||||
#define SUSPEND_RESTART_RETRACT bit(1) // Flag to indicate a retract from a restore parking motion.
|
||||
#define SUSPEND_RETRACT_COMPLETE bit(2) // (Safety door only) Indicates retraction and de-energizing is complete.
|
||||
#define SUSPEND_INITIATE_RESTORE bit(3) // (Safety door only) Flag to initiate resume procedures from a cycle start.
|
||||
#define SUSPEND_RESTORE_COMPLETE bit(4) // (Safety door only) Indicates ready to resume normal operation.
|
||||
#define SUSPEND_SAFETY_DOOR_AJAR bit(5) // Tracks safety door state for resuming.
|
||||
#define SUSPEND_MOTION_CANCEL bit(6) // Indicates a canceled resume motion. Currently used by probing routine.
|
||||
#define SUSPEND_JOG_CANCEL bit(7) // Indicates a jog cancel in process and to reset buffers when complete.
|
||||
|
||||
// Define step segment generator state flags.
|
||||
#define STEP_CONTROL_NORMAL_OP 0 // Must be zero.
|
||||
#define STEP_CONTROL_END_MOTION bit(0)
|
||||
#define STEP_CONTROL_EXECUTE_HOLD bit(1)
|
||||
#define STEP_CONTROL_EXECUTE_SYS_MOTION bit(2)
|
||||
#define STEP_CONTROL_UPDATE_SPINDLE_PWM bit(3)
|
||||
|
||||
// Define control pin index for Grbl internal use. Pin maps may change, but these values don't.
|
||||
//#ifdef ENABLE_SAFETY_DOOR_INPUT_PIN
|
||||
#define N_CONTROL_PIN 4
|
||||
#define CONTROL_PIN_INDEX_SAFETY_DOOR bit(0)
|
||||
#define CONTROL_PIN_INDEX_RESET bit(1)
|
||||
#define CONTROL_PIN_INDEX_FEED_HOLD bit(2)
|
||||
#define CONTROL_PIN_INDEX_CYCLE_START bit(3)
|
||||
#define CONTROL_PIN_INDEX_MACRO_0 bit(4)
|
||||
#define CONTROL_PIN_INDEX_MACRO_1 bit(5)
|
||||
#define CONTROL_PIN_INDEX_MACRO_2 bit(6)
|
||||
#define CONTROL_PIN_INDEX_MACRO_3 bit(7)
|
||||
//#else
|
||||
//#define N_CONTROL_PIN 3
|
||||
//#define CONTROL_PIN_INDEX_RESET bit(0)
|
||||
//#define CONTROL_PIN_INDEX_FEED_HOLD bit(1)
|
||||
//#define CONTROL_PIN_INDEX_CYCLE_START bit(2)
|
||||
//#endif
|
||||
|
||||
// Define spindle stop override control states.
|
||||
#define SPINDLE_STOP_OVR_DISABLED 0 // Must be zero.
|
||||
#define SPINDLE_STOP_OVR_ENABLED bit(0)
|
||||
#define SPINDLE_STOP_OVR_INITIATE bit(1)
|
||||
#define SPINDLE_STOP_OVR_RESTORE bit(2)
|
||||
#define SPINDLE_STOP_OVR_RESTORE_CYCLE bit(3)
|
||||
|
||||
|
||||
|
||||
|
||||
// NOTE: These position variables may need to be declared as volatiles, if problems arise.
|
||||
extern int32_t sys_position[N_AXIS]; // Real-time machine (aka home) position vector in steps.
|
||||
extern int32_t sys_probe_position[N_AXIS]; // Last probe position in machine coordinates and steps.
|
||||
|
||||
extern volatile uint8_t sys_probe_state; // Probing state value. Used to coordinate the probing cycle with stepper ISR.
|
||||
extern volatile uint8_t sys_rt_exec_state; // Global realtime executor bitflag variable for state management. See EXEC bitmasks.
|
||||
extern volatile uint8_t sys_rt_exec_alarm; // Global realtime executor bitflag variable for setting various alarms.
|
||||
extern volatile uint8_t sys_rt_exec_motion_override; // Global realtime executor bitflag variable for motion-based overrides.
|
||||
extern volatile uint8_t sys_rt_exec_accessory_override; // Global realtime executor bitflag variable for spindle/coolant overrides.
|
||||
|
||||
#ifdef DEBUG
|
||||
#define EXEC_DEBUG_REPORT bit(0)
|
||||
extern volatile uint8_t sys_rt_exec_debug;
|
||||
#endif
|
||||
|
||||
|
||||
void system_ini(); // Renamed from system_init() due to conflict with esp32 files
|
||||
|
||||
// Returns bitfield of control pin states, organized by CONTROL_PIN_INDEX. (1=triggered, 0=not triggered).
|
||||
uint8_t system_control_get_state();
|
||||
|
||||
// Returns if safety door is ajar(T) or closed(F), based on pin state.
|
||||
uint8_t system_check_safety_door_ajar();
|
||||
|
||||
void isr_control_inputs();
|
||||
|
||||
// Special handlers for setting and clearing Grbl's real-time execution flags.
|
||||
void system_set_exec_state_flag(uint8_t mask);
|
||||
void system_clear_exec_state_flag(uint8_t mask);
|
||||
void system_set_exec_alarm(uint8_t code);
|
||||
void system_clear_exec_alarm();
|
||||
void system_set_exec_motion_override_flag(uint8_t mask);
|
||||
void system_set_exec_accessory_override_flag(uint8_t mask);
|
||||
void system_clear_exec_motion_overrides();
|
||||
void system_clear_exec_accessory_overrides();
|
||||
|
||||
// Execute the startup script lines stored in EEPROM upon initialization
|
||||
void system_execute_startup(char *line);
|
||||
uint8_t system_execute_line(char *line, uint8_t client);
|
||||
|
||||
void system_flag_wco_change();
|
||||
|
||||
// Returns machine position of axis 'idx'. Must be sent a 'step' array.
|
||||
float system_convert_axis_steps_to_mpos(int32_t *steps, uint8_t idx);
|
||||
|
||||
// Updates a machine 'position' array based on the 'step' array sent.
|
||||
void system_convert_array_steps_to_mpos(float *position, int32_t *steps);
|
||||
|
||||
// Checks and reports if target array exceeds machine travel limits.
|
||||
uint8_t system_check_travel_limits(float *target);
|
||||
uint8_t get_limit_pin_mask(uint8_t axis_idx);
|
||||
|
||||
// Special handlers for setting and clearing Grbl's real-time execution flags.
|
||||
void system_set_exec_state_flag(uint8_t mask);
|
||||
void system_clear_exec_state_flag(uint8_t mask);
|
||||
void system_set_exec_alarm(uint8_t code);
|
||||
void system_clear_exec_alarm();
|
||||
void system_set_exec_motion_override_flag(uint8_t mask);
|
||||
void system_set_exec_accessory_override_flag(uint8_t mask);
|
||||
void system_clear_exec_motion_overrides();
|
||||
void system_clear_exec_accessory_overrides();
|
||||
|
||||
|
||||
int32_t system_convert_corexy_to_x_axis_steps(int32_t *steps);
|
||||
int32_t system_convert_corexy_to_y_axis_steps(int32_t *steps);
|
||||
|
||||
// A task that runs after a control switch interrupt for debouncing.
|
||||
void controlCheckTask(void *pvParameters);
|
||||
void system_exec_control_pin(uint8_t pin);
|
||||
|
||||
void sys_io_control(uint8_t io_num_mask, bool turnOn);
|
||||
|
||||
|
||||
#endif
|
7
Grbl_Esp32-master/Grbl_Esp32/tdef.h
Normal file
7
Grbl_Esp32-master/Grbl_Esp32/tdef.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef tdef_h
|
||||
#define tdef_h
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
|
||||
#endif
|
239
Grbl_Esp32-master/Grbl_Esp32/telnet_server.cpp
Normal file
239
Grbl_Esp32-master/Grbl_Esp32/telnet_server.cpp
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
telnet_server.cpp - telnet server functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if defined (ENABLE_WIFI) && defined (ENABLE_TELNET)
|
||||
|
||||
#include "wifiservices.h"
|
||||
|
||||
#include "grbl.h"
|
||||
|
||||
#include "telnet_server.h"
|
||||
#include "wificonfig.h"
|
||||
#include <WiFi.h>
|
||||
#include <Preferences.h>
|
||||
#include "report.h"
|
||||
#include "commands.h"
|
||||
|
||||
|
||||
Telnet_Server telnet_server;
|
||||
bool Telnet_Server::_setupdone = false;
|
||||
uint16_t Telnet_Server::_port = 0;
|
||||
WiFiServer * Telnet_Server::_telnetserver = NULL;
|
||||
WiFiClient Telnet_Server::_telnetClients[MAX_TLNT_CLIENTS];
|
||||
#ifdef ENABLE_TELNET_WELCOME_MSG
|
||||
IPAddress Telnet_Server::_telnetClientsIP[MAX_TLNT_CLIENTS];
|
||||
#endif
|
||||
|
||||
Telnet_Server::Telnet_Server(){
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
}
|
||||
Telnet_Server::~Telnet_Server(){
|
||||
end();
|
||||
}
|
||||
|
||||
|
||||
bool Telnet_Server::begin(){
|
||||
|
||||
bool no_error = true;
|
||||
end();
|
||||
Preferences prefs;
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;;
|
||||
prefs.begin(NAMESPACE, true);
|
||||
int8_t penabled = prefs.getChar(TELNET_ENABLE_ENTRY, DEFAULT_TELNET_STATE);
|
||||
//Get telnet port
|
||||
_port = prefs.getUShort(TELNET_PORT_ENTRY, DEFAULT_TELNETSERVER_PORT);
|
||||
prefs.end();
|
||||
|
||||
if (penabled == 0) return false;
|
||||
//create instance
|
||||
_telnetserver= new WiFiServer(_port, MAX_TLNT_CLIENTS);
|
||||
_telnetserver->setNoDelay(true);
|
||||
String s = "[MSG:TELNET Started " + String(_port) + "]\r\n";
|
||||
grbl_send(CLIENT_ALL,(char *)s.c_str());
|
||||
//start telnet server
|
||||
_telnetserver->begin();
|
||||
_setupdone = true;
|
||||
return no_error;
|
||||
}
|
||||
|
||||
void Telnet_Server::end(){
|
||||
_setupdone = false;
|
||||
_RXbufferSize = 0;
|
||||
_RXbufferpos = 0;
|
||||
if (_telnetserver) {
|
||||
delete _telnetserver;
|
||||
_telnetserver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void Telnet_Server::clearClients(){
|
||||
//check if there are any new clients
|
||||
if (_telnetserver->hasClient()){
|
||||
uint8_t i;
|
||||
for(i = 0; i < MAX_TLNT_CLIENTS; i++){
|
||||
//find free/disconnected spot
|
||||
if (!_telnetClients[i] || !_telnetClients[i].connected()){
|
||||
#ifdef ENABLE_TELNET_WELCOME_MSG
|
||||
_telnetClientsIP[i] = IPAddress(0, 0, 0, 0);
|
||||
#endif
|
||||
if(_telnetClients[i]) _telnetClients[i].stop();
|
||||
_telnetClients[i] = _telnetserver->available();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= MAX_TLNT_CLIENTS) {
|
||||
//no free/disconnected spot so reject
|
||||
_telnetserver->available().stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t Telnet_Server::write(const uint8_t *buffer, size_t size){
|
||||
|
||||
size_t wsize = 0;
|
||||
if ( !_setupdone || _telnetserver == NULL) {
|
||||
log_d("[TELNET out blocked]");
|
||||
return 0;
|
||||
}
|
||||
clearClients();
|
||||
//log_d("[TELNET out]");
|
||||
//push UART data to all connected telnet clients
|
||||
for(uint8_t i = 0; i < MAX_TLNT_CLIENTS; i++){
|
||||
if (_telnetClients[i] && _telnetClients[i].connected()){
|
||||
//log_d("[TELNET out connected]");
|
||||
wsize = _telnetClients[i].write(buffer, size);
|
||||
COMMANDS::wait(0);
|
||||
}
|
||||
}
|
||||
return wsize;
|
||||
}
|
||||
|
||||
void Telnet_Server::handle(){
|
||||
COMMANDS::wait(0);
|
||||
//check if can read
|
||||
if ( !_setupdone || _telnetserver == NULL) {
|
||||
return;
|
||||
}
|
||||
clearClients();
|
||||
//check clients for data
|
||||
//uint8_t c;
|
||||
for(uint8_t i = 0; i < MAX_TLNT_CLIENTS; i++){
|
||||
if (_telnetClients[i] && _telnetClients[i].connected()){
|
||||
#ifdef ENABLE_TELNET_WELCOME_MSG
|
||||
if (_telnetClientsIP[i] != _telnetClients[i].remoteIP()){
|
||||
report_init_message(CLIENT_TELNET);
|
||||
_telnetClientsIP[i] = _telnetClients[i].remoteIP();
|
||||
}
|
||||
#endif
|
||||
if(_telnetClients[i].available()){
|
||||
uint8_t buf[1024];
|
||||
COMMANDS::wait(0);
|
||||
int readlen = _telnetClients[i].available();
|
||||
int writelen = TELNETRXBUFFERSIZE - available();
|
||||
if (readlen > 1024) readlen = 1024;
|
||||
if (readlen > writelen) readlen = writelen;
|
||||
if (readlen > 0) {
|
||||
_telnetClients[i].read(buf, readlen);
|
||||
push(buf, readlen);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (_telnetClients[i]) {
|
||||
#ifdef ENABLE_TELNET_WELCOME_MSG
|
||||
_telnetClientsIP[i] = IPAddress(0, 0, 0, 0);
|
||||
#endif
|
||||
_telnetClients[i].stop();
|
||||
}
|
||||
}
|
||||
COMMANDS::wait(0);
|
||||
}
|
||||
}
|
||||
|
||||
int Telnet_Server::peek(void){
|
||||
if (_RXbufferSize > 0)return _RXbuffer[_RXbufferpos];
|
||||
else return -1;
|
||||
}
|
||||
|
||||
int Telnet_Server::available(){
|
||||
return _RXbufferSize;
|
||||
}
|
||||
|
||||
int Telnet_Server::get_rx_buffer_available(){
|
||||
return TELNETRXBUFFERSIZE - _RXbufferSize;
|
||||
}
|
||||
|
||||
bool Telnet_Server::push (uint8_t data){
|
||||
log_i("[TELNET]push %c",data);
|
||||
if ((1 + _RXbufferSize) <= TELNETRXBUFFERSIZE){
|
||||
int current = _RXbufferpos + _RXbufferSize;
|
||||
if (current > TELNETRXBUFFERSIZE) current = current - TELNETRXBUFFERSIZE;
|
||||
if (current > (TELNETRXBUFFERSIZE-1)) current = 0;
|
||||
_RXbuffer[current] = data;
|
||||
_RXbufferSize++;
|
||||
log_i("[TELNET]buffer size %d",_RXbufferSize);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Telnet_Server::push (const uint8_t * data, int data_size){
|
||||
if ((data_size + _RXbufferSize) <= TELNETRXBUFFERSIZE){
|
||||
int data_processed = 0;
|
||||
int current = _RXbufferpos + _RXbufferSize;
|
||||
if (current > TELNETRXBUFFERSIZE) current = current - TELNETRXBUFFERSIZE;
|
||||
for (int i = 0; i < data_size; i++){
|
||||
if (current > (TELNETRXBUFFERSIZE-1)) current = 0;
|
||||
if (char(data[i]) != '\r') {
|
||||
_RXbuffer[current] = data[i];
|
||||
current ++;
|
||||
data_processed++;
|
||||
}
|
||||
COMMANDS::wait(0);
|
||||
//vTaskDelay(1 / portTICK_RATE_MS); // Yield to other tasks
|
||||
}
|
||||
_RXbufferSize+=data_processed;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int Telnet_Server::read(void){
|
||||
|
||||
if (_RXbufferSize > 0) {
|
||||
int v = _RXbuffer[_RXbufferpos];
|
||||
//log_d("[TELNET]read %c",char(v));
|
||||
_RXbufferpos++;
|
||||
if (_RXbufferpos > (TELNETRXBUFFERSIZE-1))_RXbufferpos = 0;
|
||||
_RXbufferSize--;
|
||||
return v;
|
||||
} else return -1;
|
||||
}
|
||||
|
||||
#endif // Enable TELNET && ENABLE_WIFI
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
68
Grbl_Esp32-master/Grbl_Esp32/telnet_server.h
Normal file
68
Grbl_Esp32-master/Grbl_Esp32/telnet_server.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
telnet_server.h - telnet service functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//how many clients should be able to telnet to this ESP32
|
||||
#define MAX_TLNT_CLIENTS 1
|
||||
|
||||
#ifndef _TELNET_SERVER_H
|
||||
#define _TELNET_SERVER_H
|
||||
|
||||
|
||||
#include "config.h"
|
||||
class WiFiServer;
|
||||
class WiFiClient;
|
||||
|
||||
#define TELNETRXBUFFERSIZE 1200
|
||||
#define FLUSHTIMEOUT 500
|
||||
|
||||
class Telnet_Server {
|
||||
public:
|
||||
Telnet_Server();
|
||||
~Telnet_Server();
|
||||
bool begin();
|
||||
void end();
|
||||
void handle();
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
int read(void);
|
||||
int peek(void);
|
||||
int available();
|
||||
int get_rx_buffer_available();
|
||||
bool push (uint8_t data);
|
||||
bool push (const uint8_t * data, int datasize);
|
||||
static uint16_t port(){return _port;}
|
||||
private:
|
||||
static bool _setupdone;
|
||||
static WiFiServer * _telnetserver;
|
||||
static WiFiClient _telnetClients[MAX_TLNT_CLIENTS];
|
||||
#ifdef ENABLE_TELNET_WELCOME_MSG
|
||||
static IPAddress _telnetClientsIP[MAX_TLNT_CLIENTS];
|
||||
#endif
|
||||
static uint16_t _port;
|
||||
void clearClients();
|
||||
uint32_t _lastflush;
|
||||
uint8_t _RXbuffer[TELNETRXBUFFERSIZE];
|
||||
uint16_t _RXbufferSize;
|
||||
uint16_t _RXbufferpos;
|
||||
};
|
||||
|
||||
extern Telnet_Server telnet_server;
|
||||
|
||||
#endif
|
||||
|
6
Grbl_Esp32-master/Grbl_Esp32/tests/parsetest.nc
Normal file
6
Grbl_Esp32-master/Grbl_Esp32/tests/parsetest.nc
Normal file
@ -0,0 +1,6 @@
|
||||
G21
|
||||
G90 (A standard comment)
|
||||
G1 Z3.810 F228.6 ; a LinuxCNC style comment
|
||||
G0x0x0 (some lowercase)
|
||||
G0 X10 (internal comment) Y0
|
||||
G0X0 (internal comment; with semi colon) Y0Z3
|
1889
Grbl_Esp32-master/Grbl_Esp32/web_server.cpp
Normal file
1889
Grbl_Esp32-master/Grbl_Esp32/web_server.cpp
Normal file
File diff suppressed because it is too large
Load Diff
97
Grbl_Esp32-master/Grbl_Esp32/web_server.h
Normal file
97
Grbl_Esp32-master/Grbl_Esp32/web_server.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
web_server.h - wifi services functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _WEB_SERVER_H
|
||||
#define _WEB_SERVER_H
|
||||
|
||||
|
||||
#include "config.h"
|
||||
#include "commands.h"
|
||||
class WebSocketsServer;
|
||||
class WebServer;
|
||||
|
||||
#ifdef ENABLE_AUTHENTICATION
|
||||
struct auth_ip {
|
||||
IPAddress ip;
|
||||
level_authenticate_type level;
|
||||
char userID[17];
|
||||
char sessionID[17];
|
||||
uint32_t last_time;
|
||||
auth_ip * _next;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
class Web_Server {
|
||||
public:
|
||||
Web_Server();
|
||||
~Web_Server();
|
||||
bool begin();
|
||||
void end();
|
||||
void handle();
|
||||
static long get_client_ID();
|
||||
static uint16_t port(){return _port;}
|
||||
private:
|
||||
static bool _setupdone;
|
||||
static WebServer * _webserver;
|
||||
static long _id_connection;
|
||||
static WebSocketsServer * _socket_server;
|
||||
static uint16_t _port;
|
||||
static uint8_t _upload_status;
|
||||
static String getContentType (String filename);
|
||||
static String get_Splited_Value(String data, char separator, int index);
|
||||
static level_authenticate_type is_authenticated();
|
||||
#ifdef ENABLE_AUTHENTICATION
|
||||
static auth_ip * _head;
|
||||
static uint8_t _nb_ip;
|
||||
static bool AddAuthIP (auth_ip * item);
|
||||
static char * create_session_ID();
|
||||
static bool ClearAuthIP (IPAddress ip, const char * sessionID);
|
||||
static auth_ip * GetAuth (IPAddress ip, const char * sessionID);
|
||||
static level_authenticate_type ResetAuthIP (IPAddress ip, const char * sessionID);
|
||||
#endif
|
||||
#ifdef ENABLE_SSDP
|
||||
static void handle_SSDP ();
|
||||
#endif
|
||||
static void handle_root();
|
||||
static void handle_login();
|
||||
static void handle_not_found ();
|
||||
static void handle_web_command ();
|
||||
static void handle_web_command_silent ();
|
||||
static void handle_Websocket_Event(uint8_t num, uint8_t type, uint8_t * payload, size_t length);
|
||||
static void SPIFFSFileupload ();
|
||||
static void handleFileList ();
|
||||
static void handleUpdate ();
|
||||
static void WebUpdateUpload ();
|
||||
static bool is_realtime_cmd(char c);
|
||||
static void pushError(int code, const char * st, bool web_error = 500, uint16_t timeout = 1000);
|
||||
static void cancelUpload();
|
||||
#ifdef ENABLE_SD_CARD
|
||||
static void handle_direct_SDFileList();
|
||||
static void SDFile_direct_upload();
|
||||
static bool deleteRecursive(String path);
|
||||
#endif
|
||||
};
|
||||
|
||||
extern Web_Server web_server;
|
||||
|
||||
#endif
|
||||
|
557
Grbl_Esp32-master/Grbl_Esp32/wificonfig.cpp
Normal file
557
Grbl_Esp32-master/Grbl_Esp32/wificonfig.cpp
Normal file
@ -0,0 +1,557 @@
|
||||
/*
|
||||
wificonfig.cpp - wifi functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <ESPmDNS.h>
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <Preferences.h>
|
||||
#include "wificonfig.h"
|
||||
#include "wifiservices.h"
|
||||
#include "commands.h"
|
||||
#include "report.h"
|
||||
|
||||
WiFiConfig wifi_config;
|
||||
|
||||
String WiFiConfig::_hostname = "";
|
||||
bool WiFiConfig::_events_registered = false;
|
||||
WiFiConfig::WiFiConfig(){
|
||||
}
|
||||
|
||||
WiFiConfig::~WiFiConfig(){
|
||||
end();
|
||||
}
|
||||
|
||||
//just simple helper to convert mac address to string
|
||||
char * WiFiConfig::mac2str (uint8_t mac [8])
|
||||
{
|
||||
static char macstr [18];
|
||||
if (0 > sprintf (macstr, "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]) ) {
|
||||
strcpy (macstr, "00:00:00:00:00:00");
|
||||
}
|
||||
return macstr;
|
||||
}
|
||||
|
||||
const char *WiFiConfig::info(){
|
||||
static String result;
|
||||
String tmp;
|
||||
result = "[MSG:";
|
||||
if((WiFi.getMode() == WIFI_MODE_STA ) || (WiFi.getMode() == WIFI_MODE_APSTA )) {
|
||||
result += "Mode=STA:SSID=";
|
||||
result += WiFi.SSID();
|
||||
result += ":Status=";
|
||||
result += (WiFi.status()==WL_CONNECTED)?"Connected":"Not connected";
|
||||
result += ":IP=";
|
||||
result += WiFi.localIP().toString();
|
||||
result += ":MAC=";
|
||||
tmp = WiFi.macAddress();
|
||||
tmp.replace(":","-");
|
||||
result += tmp;
|
||||
|
||||
}
|
||||
if((WiFi.getMode() == WIFI_MODE_AP ) || (WiFi.getMode() == WIFI_MODE_APSTA )) {
|
||||
if(WiFi.getMode() == WIFI_MODE_APSTA ) {
|
||||
result+= "]\r\n[MSG:";
|
||||
}
|
||||
result+="Mode=AP:SSDI=";
|
||||
wifi_config_t conf;
|
||||
esp_wifi_get_config (ESP_IF_WIFI_AP, &conf);
|
||||
result+= (const char*)conf.ap.ssid;
|
||||
result+=":IP=";
|
||||
result+=WiFi.softAPIP().toString();
|
||||
result+=":MAC=";
|
||||
tmp = WiFi.softAPmacAddress();
|
||||
tmp.replace(":","-");
|
||||
result += tmp;
|
||||
}
|
||||
if(WiFi.getMode() == WIFI_MODE_NULL)result+="No Wifi";
|
||||
result+= "]\r\n";
|
||||
return result.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to convert IP string to int
|
||||
*/
|
||||
|
||||
uint32_t WiFiConfig::IP_int_from_string(String & s){
|
||||
uint32_t ip_int = 0;
|
||||
IPAddress ipaddr;
|
||||
if (ipaddr.fromString(s)) ip_int = ipaddr;
|
||||
return ip_int;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to convert int to IP string
|
||||
*/
|
||||
|
||||
String WiFiConfig::IP_string_from_int(uint32_t ip_int){
|
||||
IPAddress ipaddr(ip_int);
|
||||
return ipaddr.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Hostname string is valid
|
||||
*/
|
||||
|
||||
bool WiFiConfig::isHostnameValid (const char * hostname)
|
||||
{
|
||||
//limited size
|
||||
char c;
|
||||
if (strlen (hostname) > MAX_HOSTNAME_LENGTH || strlen (hostname) < MIN_HOSTNAME_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
//only letter and digit
|
||||
for (int i = 0; i < strlen (hostname); i++) {
|
||||
c = hostname[i];
|
||||
if (! (isdigit (c) || isalpha (c) || c == '-') ) {
|
||||
return false;
|
||||
}
|
||||
if (c == ' ') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if SSID string is valid
|
||||
*/
|
||||
|
||||
bool WiFiConfig::isSSIDValid (const char * ssid)
|
||||
{
|
||||
//limited size
|
||||
//char c;
|
||||
if (strlen (ssid) > MAX_SSID_LENGTH || strlen (ssid) < MIN_SSID_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
//only printable
|
||||
for (int i = 0; i < strlen (ssid); i++) {
|
||||
if (!isPrintable (ssid[i]) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if password string is valid
|
||||
*/
|
||||
|
||||
bool WiFiConfig::isPasswordValid (const char * password)
|
||||
{
|
||||
if (strlen (password) == 0) return true; //open network
|
||||
//limited size
|
||||
if ((strlen (password) > MAX_PASSWORD_LENGTH) || (strlen (password) < MIN_PASSWORD_LENGTH)) {
|
||||
return false;
|
||||
}
|
||||
//no space allowed ?
|
||||
/* for (int i = 0; i < strlen (password); i++)
|
||||
if (password[i] == ' ') {
|
||||
return false;
|
||||
}*/
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if IP string is valid
|
||||
*/
|
||||
bool WiFiConfig::isValidIP(const char * string){
|
||||
IPAddress ip;
|
||||
return ip.fromString(string);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* WiFi events
|
||||
* SYSTEM_EVENT_WIFI_READY < ESP32 WiFi ready
|
||||
* SYSTEM_EVENT_SCAN_DONE < ESP32 finish scanning AP
|
||||
* SYSTEM_EVENT_STA_START < ESP32 station start
|
||||
* SYSTEM_EVENT_STA_STOP < ESP32 station stop
|
||||
* SYSTEM_EVENT_STA_CONNECTED < ESP32 station connected to AP
|
||||
* SYSTEM_EVENT_STA_DISCONNECTED < ESP32 station disconnected from AP
|
||||
* SYSTEM_EVENT_STA_AUTHMODE_CHANGE < the auth mode of AP connected by ESP32 station changed
|
||||
* SYSTEM_EVENT_STA_GOT_IP < ESP32 station got IP from connected AP
|
||||
* SYSTEM_EVENT_STA_LOST_IP < ESP32 station lost IP and the IP is reset to 0
|
||||
* SYSTEM_EVENT_STA_WPS_ER_SUCCESS < ESP32 station wps succeeds in enrollee mode
|
||||
* SYSTEM_EVENT_STA_WPS_ER_FAILED < ESP32 station wps fails in enrollee mode
|
||||
* SYSTEM_EVENT_STA_WPS_ER_TIMEOUT < ESP32 station wps timeout in enrollee mode
|
||||
* SYSTEM_EVENT_STA_WPS_ER_PIN < ESP32 station wps pin code in enrollee mode
|
||||
* SYSTEM_EVENT_AP_START < ESP32 soft-AP start
|
||||
* SYSTEM_EVENT_AP_STOP < ESP32 soft-AP stop
|
||||
* SYSTEM_EVENT_AP_STACONNECTED < a station connected to ESP32 soft-AP
|
||||
* SYSTEM_EVENT_AP_STADISCONNECTED < a station disconnected from ESP32 soft-AP
|
||||
* SYSTEM_EVENT_AP_PROBEREQRECVED < Receive probe request packet in soft-AP interface
|
||||
* SYSTEM_EVENT_GOT_IP6 < ESP32 station or ap or ethernet interface v6IP addr is preferred
|
||||
* SYSTEM_EVENT_ETH_START < ESP32 ethernet start
|
||||
* SYSTEM_EVENT_ETH_STOP < ESP32 ethernet stop
|
||||
* SYSTEM_EVENT_ETH_CONNECTED < ESP32 ethernet phy link up
|
||||
* SYSTEM_EVENT_ETH_DISCONNECTED < ESP32 ethernet phy link down
|
||||
* SYSTEM_EVENT_ETH_GOT_IP < ESP32 ethernet got IP from connected AP
|
||||
* SYSTEM_EVENT_MAX
|
||||
*/
|
||||
|
||||
void WiFiConfig::WiFiEvent(WiFiEvent_t event)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:Connected with %s]\r\n",WiFi.localIP().toString().c_str());
|
||||
break;
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
grbl_send(CLIENT_ALL,"[MSG:Disconnected]\r\n");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get WiFi signal strength
|
||||
*/
|
||||
int32_t WiFiConfig::getSignal (int32_t RSSI)
|
||||
{
|
||||
if (RSSI <= -100) {
|
||||
return 0;
|
||||
}
|
||||
if (RSSI >= -50) {
|
||||
return 100;
|
||||
}
|
||||
return (2 * (RSSI + 100) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect client to AP
|
||||
*/
|
||||
|
||||
bool WiFiConfig::ConnectSTA2AP(){
|
||||
String msg, msg_out;
|
||||
uint8_t count = 0;
|
||||
uint8_t dot = 0;
|
||||
wl_status_t status = WiFi.status();
|
||||
while (status != WL_CONNECTED && count < 40) {
|
||||
|
||||
switch (status) {
|
||||
case WL_NO_SSID_AVAIL:
|
||||
msg="No SSID";
|
||||
break;
|
||||
case WL_CONNECT_FAILED:
|
||||
msg="Connection failed";
|
||||
break;
|
||||
case WL_CONNECTED:
|
||||
break;
|
||||
default:
|
||||
if ((dot>3) || (dot==0) ){
|
||||
dot=0;
|
||||
msg_out = "Connecting";
|
||||
}
|
||||
msg_out+=".";
|
||||
msg= msg_out;
|
||||
dot++;
|
||||
break;
|
||||
}
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:%s]\r\n",msg.c_str());
|
||||
COMMANDS::wait (500);
|
||||
count++;
|
||||
status = WiFi.status();
|
||||
}
|
||||
return (status == WL_CONNECTED);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start client mode (Station)
|
||||
*/
|
||||
|
||||
bool WiFiConfig::StartSTA(){
|
||||
String defV;
|
||||
Preferences prefs;
|
||||
//stop active service
|
||||
wifi_services.end();
|
||||
//Sanity check
|
||||
if((WiFi.getMode() == WIFI_STA) || (WiFi.getMode() == WIFI_AP_STA))WiFi.disconnect();
|
||||
if((WiFi.getMode() == WIFI_AP) || (WiFi.getMode() == WIFI_AP_STA))WiFi.softAPdisconnect();
|
||||
WiFi.enableAP (false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
//Get parameters for STA
|
||||
prefs.begin(NAMESPACE, true);
|
||||
defV = DEFAULT_HOSTNAME;
|
||||
String h = prefs.getString(HOSTNAME_ENTRY, defV);
|
||||
WiFi.setHostname(h.c_str());
|
||||
//SSID
|
||||
defV = DEFAULT_STA_SSID;
|
||||
String SSID = prefs.getString(STA_SSID_ENTRY, defV);
|
||||
if (SSID.length() == 0)SSID = DEFAULT_STA_SSID;
|
||||
//password
|
||||
defV = DEFAULT_STA_PWD;
|
||||
String password = prefs.getString(STA_PWD_ENTRY, defV);
|
||||
int8_t IP_mode = prefs.getChar(STA_IP_MODE_ENTRY, DHCP_MODE);
|
||||
//IP
|
||||
defV = DEFAULT_STA_IP;
|
||||
int32_t IP = prefs.getInt(STA_IP_ENTRY, IP_int_from_string(defV));
|
||||
//GW
|
||||
defV = DEFAULT_STA_GW;
|
||||
int32_t GW = prefs.getInt(STA_GW_ENTRY, IP_int_from_string(defV));
|
||||
//MK
|
||||
defV = DEFAULT_STA_MK;
|
||||
int32_t MK = prefs.getInt(STA_MK_ENTRY, IP_int_from_string(defV));
|
||||
prefs.end();
|
||||
//if not DHCP
|
||||
if (IP_mode != DHCP_MODE) {
|
||||
IPAddress ip(IP), mask(MK), gateway(GW);
|
||||
WiFi.config(ip, gateway,mask);
|
||||
}
|
||||
if (WiFi.begin(SSID.c_str(), (password.length() > 0)?password.c_str():NULL)){
|
||||
grbl_send(CLIENT_ALL,"\n[MSG:Client Started]\r\n");
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:Connecting %s]\r\n", SSID.c_str());
|
||||
return ConnectSTA2AP();
|
||||
} else {
|
||||
grbl_send(CLIENT_ALL,"[MSG:Starting client failed]\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup and start Access point
|
||||
*/
|
||||
|
||||
bool WiFiConfig::StartAP(){
|
||||
String defV;
|
||||
Preferences prefs;
|
||||
//stop active services
|
||||
wifi_services.end();
|
||||
//Sanity check
|
||||
if((WiFi.getMode() == WIFI_STA) || (WiFi.getMode() == WIFI_AP_STA))WiFi.disconnect();
|
||||
if((WiFi.getMode() == WIFI_AP) || (WiFi.getMode() == WIFI_AP_STA))WiFi.softAPdisconnect();
|
||||
WiFi.enableSTA (false);
|
||||
WiFi.mode(WIFI_AP);
|
||||
//Get parameters for AP
|
||||
prefs.begin(NAMESPACE, true);
|
||||
//SSID
|
||||
defV = DEFAULT_AP_SSID;
|
||||
String SSID = prefs.getString(AP_SSID_ENTRY, defV);
|
||||
if (SSID.length() == 0)SSID = DEFAULT_AP_SSID;
|
||||
//password
|
||||
defV = DEFAULT_AP_PWD;
|
||||
String password = prefs.getString(AP_PWD_ENTRY, defV);
|
||||
//channel
|
||||
int8_t channel = prefs.getChar(AP_CHANNEL_ENTRY, DEFAULT_AP_CHANNEL);
|
||||
if (channel == 0)channel = DEFAULT_AP_CHANNEL;
|
||||
//IP
|
||||
defV = DEFAULT_AP_IP;
|
||||
int32_t IP = prefs.getInt(AP_IP_ENTRY, IP_int_from_string(defV));
|
||||
if (IP==0){
|
||||
IP = IP_int_from_string(defV);
|
||||
}
|
||||
prefs.end();
|
||||
IPAddress ip(IP);
|
||||
IPAddress mask;
|
||||
mask.fromString(DEFAULT_AP_MK);
|
||||
//Set static IP
|
||||
WiFi.softAPConfig(ip, ip, mask);
|
||||
//Start AP
|
||||
if(WiFi.softAP(SSID.c_str(), (password.length() > 0)?password.c_str():NULL, channel)) {
|
||||
grbl_sendf(CLIENT_ALL,"\n[MSG:Local access point %s started, %s]\r\n", SSID.c_str(), WiFi.softAPIP().toString().c_str());
|
||||
return true;
|
||||
} else {
|
||||
grbl_send(CLIENT_ALL,"[MSG:Starting AP failed]\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop WiFi
|
||||
*/
|
||||
|
||||
void WiFiConfig::StopWiFi(){
|
||||
//Sanity check
|
||||
if((WiFi.getMode() == WIFI_STA) || (WiFi.getMode() == WIFI_AP_STA))WiFi.disconnect(true);
|
||||
if((WiFi.getMode() == WIFI_AP) || (WiFi.getMode() == WIFI_AP_STA))WiFi.softAPdisconnect(true);
|
||||
wifi_services.end();
|
||||
WiFi.enableSTA (false);
|
||||
WiFi.enableAP (false);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
grbl_send(CLIENT_ALL,"\n[MSG:WiFi Off]\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* begin WiFi setup
|
||||
*/
|
||||
void WiFiConfig::begin() {
|
||||
Preferences prefs;
|
||||
//stop active services
|
||||
wifi_services.end();
|
||||
//setup events
|
||||
if (!_events_registered) {
|
||||
//cumulative function and no remove so only do once
|
||||
WiFi.onEvent(WiFiConfig::WiFiEvent);
|
||||
_events_registered = true;
|
||||
}
|
||||
//open preferences as read-only
|
||||
prefs.begin(NAMESPACE, true);
|
||||
//Get hostname
|
||||
String defV = DEFAULT_HOSTNAME;
|
||||
_hostname = prefs.getString(HOSTNAME_ENTRY, defV);
|
||||
int8_t wifiMode = prefs.getChar(ESP_RADIO_MODE, DEFAULT_RADIO_MODE);
|
||||
|
||||
if (wifiMode == ESP_WIFI_AP) {
|
||||
StartAP();
|
||||
//start services
|
||||
wifi_services.begin();
|
||||
} else if (wifiMode == ESP_WIFI_STA){
|
||||
if(!StartSTA()){
|
||||
defV = DEFAULT_STA_SSID;
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:Cannot connect to %s]\r\n", prefs.getString(STA_SSID_ENTRY, defV).c_str());
|
||||
StartAP();
|
||||
}
|
||||
//start services
|
||||
wifi_services.begin();
|
||||
}else WiFi.mode(WIFI_OFF);
|
||||
prefs.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* End WiFi
|
||||
*/
|
||||
void WiFiConfig::end() {
|
||||
StopWiFi();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset ESP
|
||||
*/
|
||||
void WiFiConfig::reset_settings(){
|
||||
Preferences prefs;
|
||||
prefs.begin(NAMESPACE, false);
|
||||
String sval;
|
||||
int8_t bbuf;
|
||||
int16_t ibuf;
|
||||
bool error = false;
|
||||
sval = DEFAULT_HOSTNAME;
|
||||
if (prefs.putString(HOSTNAME_ENTRY, sval) == 0){
|
||||
error = true;
|
||||
}
|
||||
|
||||
bbuf = DEFAULT_NOTIFICATION_TYPE;
|
||||
if (prefs.putChar(NOTIFICATION_TYPE, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_TOKEN;
|
||||
if (prefs.putString(NOTIFICATION_T1, sval) != sval.length()){
|
||||
error = true;
|
||||
}
|
||||
if (prefs.putString(NOTIFICATION_T2, sval) != sval.length()){
|
||||
error = true;
|
||||
}
|
||||
if (prefs.putString(NOTIFICATION_TS, sval) != sval.length()){
|
||||
error = true;
|
||||
}
|
||||
|
||||
sval = DEFAULT_STA_SSID;
|
||||
if (prefs.putString(STA_SSID_ENTRY, sval) == 0){
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_STA_PWD;
|
||||
if (prefs.putString(STA_PWD_ENTRY, sval) != sval.length()){
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_AP_SSID;
|
||||
if (prefs.putString(AP_SSID_ENTRY, sval) == 0){
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_AP_PWD;
|
||||
if (prefs.putString(AP_PWD_ENTRY, sval) != sval.length()){
|
||||
error = true;
|
||||
}
|
||||
|
||||
bbuf = DEFAULT_AP_CHANNEL;
|
||||
if (prefs.putChar(AP_CHANNEL_ENTRY, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
bbuf = DEFAULT_STA_IP_MODE;
|
||||
if (prefs.putChar(STA_IP_MODE_ENTRY, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
bbuf = DEFAULT_HTTP_STATE;
|
||||
if (prefs.putChar(HTTP_ENABLE_ENTRY, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
bbuf = DEFAULT_TELNET_STATE;
|
||||
if (prefs.putChar(TELNET_ENABLE_ENTRY, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
bbuf = DEFAULT_RADIO_MODE;
|
||||
if (prefs.putChar(ESP_RADIO_MODE, bbuf) ==0 ) {
|
||||
error = true;
|
||||
}
|
||||
ibuf = DEFAULT_WEBSERVER_PORT;
|
||||
if (prefs.putUShort(HTTP_PORT_ENTRY, ibuf) == 0) {
|
||||
error = true;
|
||||
}
|
||||
ibuf = DEFAULT_TELNETSERVER_PORT;
|
||||
if (prefs.putUShort(TELNET_PORT_ENTRY, ibuf) == 0) {
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_STA_IP;
|
||||
if (prefs.putInt(STA_IP_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_STA_GW;
|
||||
if (prefs.putInt(STA_GW_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_STA_MK;
|
||||
if (prefs.putInt(STA_MK_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
|
||||
error = true;
|
||||
}
|
||||
sval = DEFAULT_AP_IP;
|
||||
if (prefs.putInt(AP_IP_ENTRY, wifi_config.IP_int_from_string(sval)) == 0) {
|
||||
error = true;
|
||||
}
|
||||
prefs.end();
|
||||
if (error) {
|
||||
grbl_send(CLIENT_ALL,"[MSG:WiFi reset error]\r\n");
|
||||
} else {
|
||||
grbl_send(CLIENT_ALL,"[MSG:WiFi reset done]\r\n");
|
||||
}
|
||||
}
|
||||
bool WiFiConfig::Is_WiFi_on(){
|
||||
return !(WiFi.getMode() == WIFI_MODE_NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle not critical actions that must be done in sync environement
|
||||
*/
|
||||
void WiFiConfig::handle() {
|
||||
//Services
|
||||
COMMANDS::wait(0);
|
||||
wifi_services.handle();
|
||||
}
|
||||
|
||||
|
||||
#endif // ENABLE_WIFI
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
129
Grbl_Esp32-master/Grbl_Esp32/wificonfig.h
Normal file
129
Grbl_Esp32-master/Grbl_Esp32/wificonfig.h
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
wificonfig.h - wifi functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
//Preferences entries
|
||||
#define HOSTNAME_ENTRY "ESP_HOSTNAME"
|
||||
#define STA_SSID_ENTRY "STA_SSID"
|
||||
#define STA_PWD_ENTRY "STA_PWD"
|
||||
#define STA_IP_ENTRY "STA_IP"
|
||||
#define STA_GW_ENTRY "STA_GW"
|
||||
#define STA_MK_ENTRY "STA_MK"
|
||||
#define AP_SSID_ENTRY "AP_SSID"
|
||||
#define AP_PWD_ENTRY "AP_PWD"
|
||||
#define AP_IP_ENTRY "AP_IP"
|
||||
#define AP_CHANNEL_ENTRY "AP_CHANNEL"
|
||||
#define HTTP_ENABLE_ENTRY "HTTP_ON"
|
||||
#define HTTP_PORT_ENTRY "HTTP_PORT"
|
||||
#define TELNET_ENABLE_ENTRY "TELNET_ON"
|
||||
#define TELNET_PORT_ENTRY "TELNET_PORT"
|
||||
#define STA_IP_MODE_ENTRY "STA_IP_MODE"
|
||||
#define NOTIFICATION_TYPE "NOTIF_TYPE"
|
||||
#define NOTIFICATION_T1 "NOTIF_T1"
|
||||
#define NOTIFICATION_T2 "NOTIF_T2"
|
||||
#define NOTIFICATION_TS "NOTIF_TS"
|
||||
|
||||
//Notifications
|
||||
#define ESP_PUSHOVER_NOTIFICATION 1
|
||||
#define ESP_EMAIL_NOTIFICATION 2
|
||||
#define ESP_LINE_NOTIFICATION 3
|
||||
|
||||
#define DHCP_MODE 0
|
||||
#define STATIC_MODE 1
|
||||
|
||||
//Switch
|
||||
#define ESP_SAVE_ONLY 0
|
||||
#define ESP_APPLY_NOW 1
|
||||
|
||||
//defaults values
|
||||
#define DEFAULT_HOSTNAME "grblesp"
|
||||
#define DEFAULT_STA_SSID "GRBL_ESP"
|
||||
#define DEFAULT_STA_PWD "12345678"
|
||||
#define DEFAULT_STA_IP "0.0.0.0"
|
||||
#define DEFAULT_STA_GW "0.0.0.0"
|
||||
#define DEFAULT_STA_MK "0.0.0.0"
|
||||
#define DEFAULT_AP_SSID "GRBL_ESP"
|
||||
#define DEFAULT_AP_PWD "12345678"
|
||||
#define DEFAULT_AP_IP "192.168.0.1"
|
||||
#define DEFAULT_AP_MK "255.255.255.0"
|
||||
#define DEFAULT_AP_CHANNEL 1
|
||||
#define DEFAULT_WEBSERVER_PORT 80
|
||||
#define DEFAULT_HTTP_STATE 1
|
||||
#define DEFAULT_TELNETSERVER_PORT 23
|
||||
#define DEFAULT_TELNET_STATE 1
|
||||
#define DEFAULT_STA_IP_MODE DHCP_MODE
|
||||
#define HIDDEN_PASSWORD "********"
|
||||
#define DEFAULT_TOKEN ""
|
||||
#define DEFAULT_NOTIFICATION_TYPE 0
|
||||
|
||||
//boundaries
|
||||
#define MAX_SSID_LENGTH 32
|
||||
#define MIN_SSID_LENGTH 1
|
||||
#define MAX_PASSWORD_LENGTH 64
|
||||
//min size of password is 0 or upper than 8 char
|
||||
//so let set min is 8
|
||||
#define MIN_PASSWORD_LENGTH 8
|
||||
#define MAX_HOSTNAME_LENGTH 32
|
||||
#define MIN_HOSTNAME_LENGTH 1
|
||||
#define MAX_HTTP_PORT 65001
|
||||
#define MIN_HTTP_PORT 1
|
||||
#define MAX_TELNET_PORT 65001
|
||||
#define MIN_TELNET_PORT 1
|
||||
#define MIN_CHANNEL 1
|
||||
#define MAX_CHANNEL 14
|
||||
#define MIN_NOTIFICATION_TOKEN_LENGTH 0
|
||||
#define MAX_NOTIFICATION_TOKEN_LENGTH 63
|
||||
#define MAX_NOTIFICATION_SETTING_LENGTH 127
|
||||
|
||||
#ifndef _WIFI_CONFIG_H
|
||||
#define _WIFI_CONFIG_H
|
||||
#include "WiFi.h"
|
||||
|
||||
class WiFiConfig {
|
||||
public:
|
||||
WiFiConfig();
|
||||
~WiFiConfig();
|
||||
static const char *info();
|
||||
static bool isValidIP(const char * string);
|
||||
static bool isPasswordValid (const char * password);
|
||||
static bool isSSIDValid (const char * ssid);
|
||||
static bool isHostnameValid (const char * hostname);
|
||||
static uint32_t IP_int_from_string(String & s);
|
||||
static String IP_string_from_int(uint32_t ip_int);
|
||||
static String Hostname(){return _hostname;}
|
||||
static char * mac2str (uint8_t mac [8]);
|
||||
static bool StartAP();
|
||||
static bool StartSTA();
|
||||
static void StopWiFi();
|
||||
static int32_t getSignal (int32_t RSSI);
|
||||
static void begin();
|
||||
static void end();
|
||||
static void handle();
|
||||
static void reset_settings();
|
||||
static bool Is_WiFi_on();
|
||||
private :
|
||||
static bool ConnectSTA2AP();
|
||||
static void WiFiEvent(WiFiEvent_t event);
|
||||
static String _hostname;
|
||||
static bool _events_registered;
|
||||
};
|
||||
|
||||
extern WiFiConfig wifi_config;
|
||||
|
||||
#endif
|
173
Grbl_Esp32-master/Grbl_Esp32/wifiservices.cpp
Normal file
173
Grbl_Esp32-master/Grbl_Esp32/wifiservices.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/*
|
||||
wifiservices.cpp - wifi services functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_ARCH_ESP32
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef ENABLE_WIFI
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <Preferences.h>
|
||||
#include "report.h"
|
||||
#include "wificonfig.h"
|
||||
#include "wifiservices.h"
|
||||
#ifdef ENABLE_MDNS
|
||||
#include <ESPmDNS.h>
|
||||
#endif
|
||||
#ifdef ENABLE_OTA
|
||||
#include <ArduinoOTA.h>
|
||||
#endif
|
||||
#ifdef ENABLE_HTTP
|
||||
#include "web_server.h"
|
||||
#endif
|
||||
#ifdef ENABLE_TELNET
|
||||
#include "telnet_server.h"
|
||||
#endif
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
#include "notifications_service.h"
|
||||
#endif
|
||||
#include "commands.h"
|
||||
|
||||
WiFiServices wifi_services;
|
||||
|
||||
WiFiServices::WiFiServices(){
|
||||
}
|
||||
WiFiServices::~WiFiServices(){
|
||||
end();
|
||||
}
|
||||
|
||||
bool WiFiServices::begin(){
|
||||
bool no_error = true;
|
||||
//Sanity check
|
||||
if(WiFi.getMode() == WIFI_OFF) return false;
|
||||
String h;
|
||||
Preferences prefs;
|
||||
//Get hostname
|
||||
String defV = DEFAULT_HOSTNAME;
|
||||
prefs.begin(NAMESPACE, true);
|
||||
h = prefs.getString(HOSTNAME_ENTRY, defV);
|
||||
prefs.end();
|
||||
//Start SPIFFS
|
||||
SPIFFS.begin(true);
|
||||
|
||||
#ifdef ENABLE_OTA
|
||||
ArduinoOTA
|
||||
.onStart([]() {
|
||||
String type;
|
||||
if (ArduinoOTA.getCommand() == U_FLASH)
|
||||
type = "sketch";
|
||||
else {// U_SPIFFS
|
||||
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
|
||||
type = "filesystem";
|
||||
SPIFFS.end();
|
||||
}
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:Start OTA updating %s]\r\n", type.c_str());
|
||||
})
|
||||
.onEnd([]() {
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:End OTA]\r\n");
|
||||
|
||||
})
|
||||
.onProgress([](unsigned int progress, unsigned int total) {
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:OTA Progress: %u%%]\r\n", (progress / (total / 100)));
|
||||
})
|
||||
.onError([](ota_error_t error) {
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:OTA Error(%u):]\r\n", error);
|
||||
if (error == OTA_AUTH_ERROR) grbl_send(CLIENT_ALL,"[MSG:Auth Failed]\r\n");
|
||||
else if (error == OTA_BEGIN_ERROR) grbl_send(CLIENT_ALL,"[MSG:Begin Failed]\r\n");
|
||||
else if (error == OTA_CONNECT_ERROR) grbl_send(CLIENT_ALL,"[MSG:Connect Failed]\r\n");
|
||||
else if (error == OTA_RECEIVE_ERROR) grbl_send(CLIENT_ALL,"[MSG:Receive Failed]\r\n");
|
||||
else if (error == OTA_END_ERROR) grbl_send(CLIENT_ALL,"[MSG:End Failed]\r\n");
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
#endif
|
||||
#ifdef ENABLE_MDNS
|
||||
//no need in AP mode
|
||||
if(WiFi.getMode() == WIFI_STA){
|
||||
//start mDns
|
||||
if (!MDNS.begin(h.c_str())) {
|
||||
grbl_send(CLIENT_ALL,"[MSG:Cannot start mDNS]\r\n");
|
||||
no_error = false;
|
||||
} else {
|
||||
grbl_sendf(CLIENT_ALL,"[MSG:Start mDNS with hostname:http://%s.local/]\r\n",h.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_HTTP
|
||||
web_server.begin();
|
||||
#endif
|
||||
#ifdef ENABLE_TELNET
|
||||
telnet_server.begin();
|
||||
#endif
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
notificationsservice.begin();
|
||||
#endif
|
||||
//be sure we are not is mixed mode in setup
|
||||
WiFi.scanNetworks (true);
|
||||
return no_error;
|
||||
}
|
||||
void WiFiServices::end(){
|
||||
#ifdef ENABLE_NOTIFICATIONS
|
||||
notificationsservice.end();
|
||||
#endif
|
||||
#ifdef ENABLE_TELNET
|
||||
telnet_server.end();
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_HTTP
|
||||
web_server.end();
|
||||
#endif
|
||||
//stop OTA
|
||||
#ifdef ENABLE_OTA
|
||||
ArduinoOTA.end();
|
||||
#endif
|
||||
//Stop SPIFFS
|
||||
SPIFFS.end();
|
||||
|
||||
#ifdef ENABLE_MDNS
|
||||
//Stop mDNS
|
||||
MDNS.end();
|
||||
#endif
|
||||
}
|
||||
|
||||
void WiFiServices::handle(){
|
||||
COMMANDS::wait(0);
|
||||
//to avoid mixed mode due to scan network
|
||||
if (WiFi.getMode() == WIFI_AP_STA) {
|
||||
if (WiFi.scanComplete() != WIFI_SCAN_RUNNING) {
|
||||
WiFi.enableSTA (false);
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_OTA
|
||||
ArduinoOTA.handle();
|
||||
#endif
|
||||
#ifdef ENABLE_HTTP
|
||||
web_server.handle();
|
||||
#endif
|
||||
#ifdef ENABLE_TELNET
|
||||
telnet_server.handle();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // ENABLE_WIFI
|
||||
|
||||
#endif // ARDUINO_ARCH_ESP32
|
39
Grbl_Esp32-master/Grbl_Esp32/wifiservices.h
Normal file
39
Grbl_Esp32-master/Grbl_Esp32/wifiservices.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
wifiservices.h - wifi services functions class
|
||||
|
||||
Copyright (c) 2014 Luc Lebosse. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef _WIFI_SERVICES_H
|
||||
#define _WIFI_SERVICES_H
|
||||
|
||||
|
||||
class WiFiServices {
|
||||
public:
|
||||
WiFiServices();
|
||||
~WiFiServices();
|
||||
static bool begin();
|
||||
static void end();
|
||||
static void handle();
|
||||
};
|
||||
|
||||
extern WiFiServices wifi_services;
|
||||
|
||||
#endif
|
||||
|
674
Grbl_Esp32-master/LICENSE
Normal file
674
Grbl_Esp32-master/LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
56
Grbl_Esp32-master/README.md
Normal file
56
Grbl_Esp32-master/README.md
Normal file
@ -0,0 +1,56 @@
|
||||
|
||||
|
||||
# Grbl (CNC Controller) For ESP32
|
||||
|
||||

|
||||
|
||||
### Project Overview
|
||||
|
||||
[](https://travis-ci.com/odaki/Grbl_Esp32)
|
||||
|
||||
This is a port of [Grbl](https://github.com/gnea/grbl) for the ESP32. The ESP32 is potentially a great target for Grbl for the following reasons
|
||||
|
||||
- **Faster** - At least 4x the step rates over Grbl
|
||||
- **Lower Cost** -
|
||||
- **Small footprint** -
|
||||
- **More Flash and RAM** - A larger planner buffer could be used and more features could be added.
|
||||
- **I/O** - It has just about the same number of pins as an Arduino UNO, the original target for Grbl
|
||||
- **Peripherals** - It has more timers and advanced features than an UNO. These can also be mapped to pins more flexibly.
|
||||
- **Connectivity** - Bluetooth and WiFi built in.
|
||||
- **Fast Boot** - Boots almost instantly and does not need to be formally shutdown (unlike Raspberry Pi or Beagle Bone)
|
||||
- **RTOS (Real Time operating System)** - Custom features can be added without affecting the performance of the motion control system.
|
||||
|
||||
|
||||
### Using It
|
||||
|
||||
The code should be compiled using the latest Arduino IDE. [Follow instructions here](https://github.com/espressif/arduino-esp32) on how to setup ESP32 in the IDE. The choice was made to use the Arduino IDE over the ESP-IDF to make the code a little more accessible to novices trying to compile the code.
|
||||
|
||||
I use the ESP32 Dev Module version of the ESP32. I suggest starting with that if you don't have hardware yet.
|
||||
|
||||
For basic instructions on using Grbl use the [gnea/grbl wiki](https://github.com/gnea/grbl/wiki). That is the Arduino version of Grbl, so keep that in mind regarding hardware setup. If you have questions ask via the GitHub issue system for this project.
|
||||
|
||||
### Roadmap
|
||||
|
||||
The roadmap is now [on the wiki](https://github.com/bdring/Grbl_Esp32/wiki/Development-Roadmap).
|
||||
|
||||
### Credits
|
||||
|
||||
The original [Grbl](https://github.com/gnea/grbl) is an awesome project by Sungeon (Sonny) Jeon. I have known him for many years and he is always very helpful. I have used Grbl on many projects. I only ported because of the limitation of the processors it was designed for. The core engine design is virtually unchanged.
|
||||
|
||||
The Wifi and WebUI is based on [this project.](https://github.com/luc-github/ESP3D-WEBUI)
|
||||
|
||||
### Contribute
|
||||
|
||||
 There is a slack channel for the development this project. Ask for an Invite
|
||||
|
||||
### FAQ
|
||||
|
||||
Start asking questions...I'll put the frequent ones here.
|
||||
|
||||
|
||||
|
||||
### <a name="donation"></a>Donation
|
||||
|
||||
This project requires a lot of work and often expensive items for testing. Please consider a safe, secure and highly appreciated donation via the PayPal link below.
|
||||
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=TKNJ9Z775VXB2)
|
19
Grbl_Esp32-master/command.sh
Normal file
19
Grbl_Esp32-master/command.sh
Normal file
@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
function build_sketch()
|
||||
{
|
||||
local sketch=$1
|
||||
|
||||
# buld sketch with arudino ide
|
||||
echo -e "\n Build $sketch \n"
|
||||
arduino --verbose --verify $sketch
|
||||
|
||||
# get build result from arduino
|
||||
local re=$?
|
||||
|
||||
# check result
|
||||
if [ $re -ne 0 ]; then
|
||||
echo "Failed to build $sketch"
|
||||
return $re
|
||||
fi
|
||||
}
|
153
Grbl_Esp32-master/doc/Commands.txt
Normal file
153
Grbl_Esp32-master/doc/Commands.txt
Normal file
@ -0,0 +1,153 @@
|
||||
This file defines the [ESP...] style commands. They can be used via serial, Bluetooth or Wifi
|
||||
These are used for basic wireless settings as well as SD card commands
|
||||
|
||||
Some commands need to be authenticated with a password. Authentication
|
||||
is optional via #define ENABLE_AUTHENTICATION in the config.h file.
|
||||
The default password is "admin"
|
||||
|
||||
============== Examples (assumes "admin" password): ===============
|
||||
|
||||
Command: [ESP800]pwd=admin
|
||||
Reply: FW version:1.1f # FW target:grbl-embedded # FW HW:Direct SD # primary sd:/sd # secondary sd:none # authentication:yes # webcommunication: Sync: 81# hostname:grblesp
|
||||
|
||||
Command: [ESP111]
|
||||
Reply: 192.168.1.11
|
||||
|
||||
Command: [ESP121]pwd=admin
|
||||
Reply: 80
|
||||
|
||||
Command: [ESP121]pwd=admin
|
||||
Reply: 80
|
||||
|
||||
Command: [ESP121]81 pwd=admin
|
||||
Reply: ok
|
||||
|
||||
Command: [ESP121]pwd=admin
|
||||
Reply: 81
|
||||
|
||||
=============== Command Reference ========================
|
||||
|
||||
|
||||
* Set/Get STA SSID
|
||||
[ESP100]<SSID>pwd=<admin password>
|
||||
|
||||
* Set STA Password
|
||||
[ESP101]<Password>pwd=<admin password>
|
||||
|
||||
* Set/Get STA IP mode (DHCP/STATIC)
|
||||
[ESP102]<mode>pwd=<admin password>
|
||||
|
||||
* Set/Get STA IP/Mask/GW
|
||||
[ESP103]IP=<IP> MSK=<IP> GW=<IP> pwd=<admin password>
|
||||
|
||||
* Set/Get AP SSID
|
||||
[ESP105]<SSID>pwd=<admin password>
|
||||
|
||||
* Change AP Password
|
||||
[ESP106]<Password>pwd=<admin password>
|
||||
|
||||
* Set/Get AP IP
|
||||
[ESP107]<IP>pwd=<admin password>
|
||||
|
||||
* Set/Get AP channel
|
||||
[ESP108]<channel>pwd=<admin password>
|
||||
|
||||
* Set/Get radio state which can be STA, AP, BT, OFF
|
||||
[ESP110]<state>pwd=<admin password>
|
||||
|
||||
* Get current IP
|
||||
[ESP111]<header answer>
|
||||
|
||||
* Get/Set hostname
|
||||
[ESP112]<Hostname> pwd=<admin password>
|
||||
|
||||
* Get/Set immediate Radio (WiFi/BT) state which can be ON, OFF
|
||||
[ESP115]<state>pwd=<admin password>
|
||||
|
||||
* Get/Set HTTP state which can be ON, OFF
|
||||
[ESP120]<state>pwd=<admin password>
|
||||
|
||||
* Get/Set HTTP port
|
||||
[ESP121]<port>pwd=<admin password>
|
||||
|
||||
* Get/Set Telnet state which can be ON, OFF
|
||||
[ESP130]<state>pwd=<admin password>
|
||||
|
||||
* Get/Set Telnet port
|
||||
[ESP131]<port>pwd=<admin password>
|
||||
|
||||
* Get/Set btname
|
||||
[ESP140]< Bluetooth name> pwd=<admin password>
|
||||
|
||||
* Get SD Card Status
|
||||
[ESP200] pwd=<user/admin password>
|
||||
|
||||
* Get SD Card Content
|
||||
[ESP210] pwd=<user/admin password>
|
||||
|
||||
* Delete SD Card file / directory
|
||||
[ESP215]<file/dir name>pwd=<user/admin password>
|
||||
|
||||
* Print SD file
|
||||
[ESP220] <Filename> pwd=<user/admin password>
|
||||
|
||||
*Get full EEPROM settings content
|
||||
but do not give any passwords
|
||||
[ESP400] pwd=<user/admin password>
|
||||
|
||||
*Set EEPROM setting
|
||||
position in EEPROM, type: B(byte), I(integer/long), S(string), A(IP address / mask)
|
||||
[ESP401]P=<position> T=<type> V=<value> pwd=<user/admin password>
|
||||
Positions:
|
||||
HOSTNAME_ENTRY "ESP_HOSTNAME" String
|
||||
STA_SSID_ENTRY "STA_SSID" String
|
||||
STA_PWD_ENTRY "STA_PWD" String
|
||||
STA_IP_ENTRY "STA_IP" IP
|
||||
STA_GW_ENTRY "STA_GW" IP
|
||||
STA_MK_ENTRY "STA_MK" IP
|
||||
ESP_WIFI_MODE "WIFI_MODE" Byte (0=OFF, STA=1, AP=2)
|
||||
AP_SSID_ENTRY "AP_SSID" String
|
||||
AP_PWD_ENTRY "AP_PWD" String
|
||||
AP_IP_ENTRY "AP_IP" IP
|
||||
AP_CHANNEL_ENTRY "AP_CHANNEL" Byte
|
||||
HTTP_ENABLE_ENTRY "HTTP_ON" Byte (0=Disabled, 1=Enabled)
|
||||
HTTP_PORT_ENTRY "HTTP_PORT" Integer
|
||||
TELNET_ENABLE_ENTRY "TELNET_ON" Byte (0=Disabled, 1=Enabled)
|
||||
TELNET_PORT_ENTRY "TELNET_PORT" Integer
|
||||
STA_IP_MODE_ENTRY "STA_IP_MODE" Byte (0=DHCP, 1=STATIC)
|
||||
|
||||
*Get available AP list (limited to 30)
|
||||
output is JSON or plain text according parameter
|
||||
[ESP410] pwd=<user/admin password>
|
||||
|
||||
*Get current settings of ESP3D
|
||||
output is JSON or plain text according parameter
|
||||
[ESP420]pwd=<user/admin password>
|
||||
|
||||
* Restart ESP
|
||||
[ESP444]RESTART pwd=<admin password>
|
||||
|
||||
* Change / Reset user password
|
||||
[ESP555]<password>pwd=<admin password>
|
||||
if no password set it use default one
|
||||
|
||||
* Send Notification
|
||||
[ESP600]msg [pwd=<admin password>]
|
||||
|
||||
* Set/Get Notification settings
|
||||
[ESP610]type=<NONE/PUSHOVER/EMAIL/LINE> T1=<token1> T2=<token2> TS=<Settings> [pwd=<admin password>]
|
||||
Get will give type and settings only, not the protected T1/T2
|
||||
|
||||
* Read SPIFFS file and send each line to serial
|
||||
[ESP700]<filename> pwd=<user/admin password>
|
||||
|
||||
* Format SPIFFS
|
||||
[ESP710]FORMAT pwd=<admin password>
|
||||
|
||||
* SPIFFS total size and used size
|
||||
[ESP720]<header answer> pwd=<user/admin password>
|
||||
|
||||
* Get fw version and basic information
|
||||
[ESP800]<header answer>
|
||||
|
||||
|
10
Grbl_Esp32-master/doc/csv/alarm_codes_en_US.csv
Normal file
10
Grbl_Esp32-master/doc/csv/alarm_codes_en_US.csv
Normal file
@ -0,0 +1,10 @@
|
||||
"Alarm Code in v1.1+"," Alarm Message in v1.0-"," Alarm Description"
|
||||
"1","Hard limit","Hard limit has been triggered. Machine position is likely lost due to sudden halt. Re-homing is highly recommended."
|
||||
"2","Soft limit","Soft limit alarm. G-code motion target exceeds machine travel. Machine position retained. Alarm may be safely unlocked."
|
||||
"3","Abort during cycle","Reset while in motion. Machine position is likely lost due to sudden halt. Re-homing is highly recommended."
|
||||
"4","Probe fail","Probe fail. Probe is not in the expected initial state before starting probe cycle when G38.2 and G38.3 is not triggered and G38.4 and G38.5 is triggered."
|
||||
"5","Probe fail","Probe fail. Probe did not contact the workpiece within the programmed travel for G38.2 and G38.4."
|
||||
"6","Homing fail","Homing fail. The active homing cycle was reset."
|
||||
"7","Homing fail","Homing fail. Safety door was opened during homing cycle."
|
||||
"8","Homing fail","Homing fail. Pull off travel failed to clear limit switch. Try increasing pull-off setting or check wiring."
|
||||
"9","Homing fail","Homing fail. Could not find limit switch within search distances. Try increasing max travel, decreasing pull-off distance, or check wiring."
|
|
22
Grbl_Esp32-master/doc/csv/build_option_codes_en_US.csv
Normal file
22
Grbl_Esp32-master/doc/csv/build_option_codes_en_US.csv
Normal file
@ -0,0 +1,22 @@
|
||||
OPT: Code, Build-Option Description,State
|
||||
V,Variable spindle,Enabled
|
||||
N,Line numbers,Enabled
|
||||
M,Mist coolant M7,Enabled
|
||||
C,CoreXY,Enabled
|
||||
P,Parking motion,Enabled
|
||||
Z,Homing force origin,Enabled
|
||||
H,Homing single axis commands,Enabled
|
||||
T,Two limit switches on axis,Enabled
|
||||
A,Allow feed rate overrides in probe cycles,Enabled
|
||||
D,Use spindle direction as enable pin,Enabled
|
||||
0,Spindle enable off when speed is zero,Enabled
|
||||
S,Software limit pin debouncing,Enabled
|
||||
R,Parking override control,Enabled
|
||||
+,Safety door input pin,Enabled
|
||||
*,Restore all EEPROM command,Disabled
|
||||
$,Restore EEPROM `$` settings command,Disabled
|
||||
#,Restore EEPROM parameter data command,Disabled
|
||||
I,Build info write user string command,Disabled
|
||||
E,Force sync upon EEPROM write,Disabled
|
||||
W,Force sync upon work coordinate offset change,Disabled
|
||||
L,Homing initialization auto-lock,Disabled
|
|
44
Grbl_Esp32-master/doc/csv/error_codes_en_US.csv
Normal file
44
Grbl_Esp32-master/doc/csv/error_codes_en_US.csv
Normal file
@ -0,0 +1,44 @@
|
||||
"Error Code in v1.1+","Error Message in v1.0-","Error Description"
|
||||
"1","Expected command letter","G-code words consist of a letter and a value. Letter was not found."
|
||||
"2","Bad number format","Missing the expected G-code word value or numeric value format is not valid."
|
||||
"3","Invalid statement","Grbl '$' system command was not recognized or supported."
|
||||
"4","Value < 0","Negative value received for an expected positive value."
|
||||
"5","Setting disabled","Homing cycle failure. Homing is not enabled via settings."
|
||||
"6","Value < 3 usec","Minimum step pulse time must be greater than 3usec."
|
||||
"7","EEPROM read fail. Using defaults","An EEPROM read failed. Auto-restoring affected EEPROM to default values."
|
||||
"8","Not idle","Grbl '$' command cannot be used unless Grbl is IDLE. Ensures smooth operation during a job."
|
||||
"9","G-code lock","G-code commands are locked out during alarm or jog state."
|
||||
"10","Homing not enabled","Soft limits cannot be enabled without homing also enabled."
|
||||
"11","Line overflow","Max characters per line exceeded. Received command line was not executed."
|
||||
"12","Step rate > 30kHz","Grbl '$' setting value cause the step rate to exceed the maximum supported."
|
||||
"13","Check Door","Safety door detected as opened and door state initiated."
|
||||
"14","Line length exceeded","Build info or startup line exceeded EEPROM line length limit. Line not stored."
|
||||
"15","Travel exceeded","Jog target exceeds machine travel. Jog command has been ignored."
|
||||
"16","Invalid jog command","Jog command has no '=' or contains prohibited g-code."
|
||||
"17","Setting disabled","Laser mode requires PWM output."
|
||||
"20","Unsupported command","Unsupported or invalid g-code command found in block."
|
||||
"21","Modal group violation","More than one g-code command from same modal group found in block."
|
||||
"22","Undefined feed rate","Feed rate has not yet been set or is undefined."
|
||||
"23","Invalid gcode ID:23","G-code command in block requires an integer value."
|
||||
"24","Invalid gcode ID:24","More than one g-code command that requires axis words found in block."
|
||||
"25","Invalid gcode ID:25","Repeated g-code word found in block."
|
||||
"26","Invalid gcode ID:26","No axis words found in block for g-code command or current modal state which requires them."
|
||||
"27","Invalid gcode ID:27","Line number value is invalid."
|
||||
"28","Invalid gcode ID:28","G-code command is missing a required value word."
|
||||
"29","Invalid gcode ID:29","G59.x work coordinate systems are not supported."
|
||||
"30","Invalid gcode ID:30","G53 only allowed with G0 and G1 motion modes."
|
||||
"31","Invalid gcode ID:31","Axis words found in block when no command or current modal state uses them."
|
||||
"32","Invalid gcode ID:32","G2 and G3 arcs require at least one in-plane axis word."
|
||||
"33","Invalid gcode ID:33","Motion command target is invalid."
|
||||
"34","Invalid gcode ID:34","Arc radius value is invalid."
|
||||
"35","Invalid gcode ID:35","G2 and G3 arcs require at least one in-plane offset word."
|
||||
"36","Invalid gcode ID:36","Unused value words found in block."
|
||||
"37","Invalid gcode ID:37","G43.1 dynamic tool length offset is not assigned to configured tool length axis."
|
||||
"38","Invalid gcode ID:38","Tool number greater than max supported value."
|
||||
"39","Parameter P exceeded max ID:39","Parameter P exceeded max"
|
||||
"60","SD failed to mount"
|
||||
"61","SD card failed to open file for reading"
|
||||
"62","SD card failed to open directory"
|
||||
"63","SD Card directory not found"
|
||||
"64","SD Card file empty"
|
||||
"70","Bluetooth failed to start"
|
Can't render this file because it has a wrong number of fields in line 39.
|
46
Grbl_Esp32-master/doc/csv/setting_codes_en_US.csv
Normal file
46
Grbl_Esp32-master/doc/csv/setting_codes_en_US.csv
Normal file
@ -0,0 +1,46 @@
|
||||
"$-Code"," Setting"," Units"," Setting Description"
|
||||
"0","Step pulse time","microseconds","Sets time length per step. Minimum 3usec."
|
||||
"1","Step idle delay","milliseconds","Sets a short hold delay when stopping to let dynamics settle before disabling steppers. Value 255 keeps motors enabled with no delay."
|
||||
"2","Step pulse invert","mask","Inverts the step signal. Set axis bit to invert (00000ZYX)."
|
||||
"3","Step direction invert","mask","Inverts the direction signal. Set axis bit to invert (00000ZYX)."
|
||||
"4","Invert step enable pin","boolean","Inverts the stepper driver enable pin signal."
|
||||
"5","Invert limit pins","boolean","Inverts the all of the limit input pins."
|
||||
"6","Invert probe pin","boolean","Inverts the probe input pin signal."
|
||||
"10","Status report options","mask","Alters data included in status reports."
|
||||
"11","Junction deviation","millimeters","Sets how fast Grbl travels through consecutive motions. Lower value slows it down."
|
||||
"12","Arc tolerance","millimeters","Sets the G2 and G3 arc tracing accuracy based on radial error. Beware: A very small value may effect performance."
|
||||
"13","Report in inches","boolean","Enables inch units when returning any position and rate value that is not a settings value."
|
||||
"20","Soft limits enable","boolean","Enables soft limits checks within machine travel and sets alarm when exceeded. Requires homing."
|
||||
"21","Hard limits enable","boolean","Enables hard limits. Immediately halts motion and throws an alarm when switch is triggered."
|
||||
"22","Homing cycle enable","boolean","Enables homing cycle. Requires limit switches on all axes."
|
||||
"23","Homing direction invert","mask","Homing searches for a switch in the positive direction. Set axis bit (00000ZYX) to search in negative direction."
|
||||
"24","Homing locate feed rate","mm/min","Feed rate to slowly engage limit switch to determine its location accurately."
|
||||
"25","Homing search seek rate","mm/min","Seek rate to quickly find the limit switch before the slower locating phase."
|
||||
"26","Homing switch debounce delay","milliseconds","Sets a short delay between phases of homing cycle to let a switch debounce."
|
||||
"27","Homing switch pull-off distance","millimeters","Retract distance after triggering switch to disengage it. Homing will fail if switch isn't cleared."
|
||||
"30","Maximum spindle speed","RPM","Maximum spindle speed. Sets PWM to 100% duty cycle."
|
||||
"31","Minimum spindle speed","RPM","Minimum spindle speed. Sets PWM to 0.4% or lowest duty cycle."
|
||||
"32","Laser-mode enable","boolean","Enables laser mode. Consecutive G1/2/3 commands will not halt when spindle speed is changed."
|
||||
"33","Spindle PWM Freq","16-bit","Spindle PWM Freq"
|
||||
"34","Spindle PWM Off Value","16-bit","Spindle PWM Off Value"
|
||||
"35","Spindle PWM Min Value","16-bit","Spindle PWM Min Value"
|
||||
"36","Spindle PWM Max Value","16-bit","Spindle PWM Max Value"
|
||||
"80-84","User integer Values","unsigned 16-bit","Reserved for custom machine use"
|
||||
"90-94","User Floating point value","float","Reserved for custom machine use"
|
||||
"100","X-axis travel resolution","step/mm","X-axis travel resolution in steps per millimeter."
|
||||
"101","Y-axis travel resolution","step/mm","Y-axis travel resolution in steps per millimeter."
|
||||
"102","Z-axis travel resolution","step/mm","Z-axis travel resolution in steps per millimeter."
|
||||
"110","X-axis maximum rate","mm/min","X-axis maximum rate. Used as G0 rapid rate."
|
||||
"111","Y-axis maximum rate","mm/min","Y-axis maximum rate. Used as G0 rapid rate."
|
||||
"112","Z-axis maximum rate","mm/min","Z-axis maximum rate. Used as G0 rapid rate."
|
||||
"120","X-axis acceleration","mm/sec^2","X-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
|
||||
"121","Y-axis acceleration","mm/sec^2","Y-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
|
||||
"122","Z-axis acceleration","mm/sec^2","Z-axis acceleration. Used for motion planning to not exceed motor torque and lose steps."
|
||||
"130","X-axis maximum travel","millimeters","Maximum X-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
|
||||
"131","Y-axis maximum travel","millimeters","Maximum Y-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
|
||||
"132","Z-axis maximum travel","millimeters","Maximum Z-axis travel distance from homing switch. Determines valid machine space for soft-limits and homing search distances."
|
||||
"140-145","Motor run current","Amps","Motor run current for SPI (Trinamic) type motors"
|
||||
"150-155","Motor hold current","Percent","Hold current in percent of run current for SPI (Trinamic) type motors"
|
||||
"160-165","Motor microstepping","micros/step","Number of microsteps per step for SPI (Trinamic) type motors"
|
||||
"170-175","Motor Stallguard Value","0-255","Value of Stallguard setting for SPI (Trinamic) type motors"
|
||||
|
|
373
Grbl_Esp32-master/doc/script/fit_nonlinear_spindle.py
Normal file
373
Grbl_Esp32-master/doc/script/fit_nonlinear_spindle.py
Normal file
@ -0,0 +1,373 @@
|
||||
"""
|
||||
---------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017-2018 Sungeun K. Jeon for Gnea Research LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
---------------------
|
||||
"""
|
||||
|
||||
|
||||
"""
|
||||
This Python script produces a continuous piece-wise line fit of actual spindle speed over
|
||||
programmed speed/PWM, which must be measured and provided by the user. A plot of the data
|
||||
and line fit will be auto-generated and saved in the working directory as 'line_fit.png'.
|
||||
|
||||
REQUIREMENTS:
|
||||
- Python 2.7 or 3.x with SciPy, NumPy, and Matplotlib Python Libraries
|
||||
|
||||
- For the most people, the easiest way to run this script is on the free cloud service
|
||||
https://repl.it/site/languages/python3. No account necessary. Unlimited runs.
|
||||
|
||||
- Last checked on 4/5/2018. This site has been regularly evolving and becoming more
|
||||
powerful. Things may not work exactly as shown. Please report any issues.
|
||||
|
||||
- To use, go to the website and start the Python REPL. Copy and paste this script into
|
||||
the main.py file in the browser editor. Click 'Run' and a solution should appear in
|
||||
the text output in the REPL console window. You can edit the script directly in the
|
||||
browser and re-run the script as many times as you need. A free account is only
|
||||
necessary if you want to save files on their servers.
|
||||
|
||||
- This script will also automatically generate a png image with the plot of the data
|
||||
with the piece-wise linear fit over it, but this will not show up by default on this
|
||||
website. To enable this, just click the 'Add File' icon and create a dummy file.
|
||||
Name it anything, like dummy.py. Leave this file blank. Doing this places the REPL
|
||||
in multiple file mode and will enable viewing the plot. Click the 'Run' icon. The
|
||||
solution will be presented again in the console, and the data plot will appear in
|
||||
the file list called 'line_fit.png'. Click the file to view the plot.
|
||||
|
||||
- For offline Python installs, most Mac and Linux computers have Python pre-installed
|
||||
with the required libraries. If not, a quick google search will show you how to
|
||||
install them. For Windows, Python installations are bit more difficult. Anaconda and
|
||||
Pyzo seem to work well.
|
||||
|
||||
USAGE:
|
||||
- First, make sure you are using the stock build of Grbl for the 328p processor. Most
|
||||
importantly, the SPINDLE_PWM_MAX_VALUE and SPINDLE_PWM_MIN_VALUE should be unaltered
|
||||
from defaults, otherwise change them back to 255.0 and 1.0 respectively for this test.
|
||||
|
||||
- Next, program the max and min rpm Grbl settings to '$30=255' and '$31=1'. This sets
|
||||
the internal PWM values equal to 'S' spindle speed for the standard Grbl build.
|
||||
|
||||
- Check if your spindle does not turn on at very low voltages by setting 'S' spindle
|
||||
speed to 'S1'. If it does not turn on or turns at a non-useful rpm, increase 'S' by
|
||||
one until it does. Write down this 'S' value for later. You'll start the rpm data
|
||||
collection from this point onward and will need to update the SPINDLE_PWM_MIN_VALUE
|
||||
in cpu_map.h afterwards.
|
||||
|
||||
- Collect actual spindle speed with a tachometer or similar means over a range of 'S'
|
||||
and PWM values. Start by setting the spindle 'S' speed to the minimum useful 'S' from
|
||||
the last step and measure and record actual spindle rpm. Next, increase 'S' spindle
|
||||
speed over equally sized intervals and repeat the measurement. Increments of 20 rpm
|
||||
should be more than enough, but decrease increment size, if highly nonlinear. Complete
|
||||
the data collection the 'S' spindle speed equal to '$30' max rpm, or at the max useful
|
||||
rpm, and record the actual rpm output. Make sure to collect rpm data all the way
|
||||
throughout useful output rpm. The actual operating range within this model may be set
|
||||
later within Grbl with the '$30' and '$31' settings.
|
||||
|
||||
- In some cases, spindle PWM output can have discontinuities or not have a useful rpm
|
||||
in certain ranges. For example, a known controller board has the spindle rpm drop
|
||||
completely at voltages above ~4.5V. If you have discontinuities like this at the low
|
||||
or high range of rpm, simply trim them from the data set. Don't include them. For
|
||||
Grbl to compensate, you'll need to alter the SPINDLE_PWM_MIN_VALUE and/or
|
||||
SPINDLE_PWM_MAX_VALUE in cpu_map.h to where your data set ends. This script will
|
||||
indicate if you need to do that in the solution output.
|
||||
|
||||
- Keep in mind that spindles without control electronics can slow down drastically when
|
||||
cutting and under load. How much it slows down is dependent on a lot of factors, such
|
||||
as feed rate, chip load, cutter diameter, flutes, cutter type, lubricant/coolant,
|
||||
material being cut, etc. Even spindles with controllers can still slow down if the
|
||||
load is higher than the max current the controller can provide. It's recommended to
|
||||
frequently re-check and measure actual spindle speed during a job. You can always use
|
||||
spindle speed overrides to tweak it temporarily to the desired speed.
|
||||
|
||||
- Edit this script and enter the measured rpm values and their corresponding 'S' spindle
|
||||
speed values in the data arrays below. Set the number of piecewise lines you would
|
||||
like to use, from one to four lines. For most cases, four lines is perfectly fine.
|
||||
In certain scenarios (laser engraving), this may significantly degrade performance and
|
||||
should be reduced if possible.
|
||||
|
||||
- Run the Python script. Visually assess the line fit from the plot. It will not likely
|
||||
to what you want on the first go. Dial things in by altering the line fit junction
|
||||
points 'PWM_pointX' in this script to move where the piecewise line junctions are
|
||||
located along the plot x-axis. It may be desired to tweak the junction points so the
|
||||
model solution is more accurate in the region that the spindle typically running.
|
||||
Re-run the script and tweak the junction points until you are satified with the model.
|
||||
|
||||
- Record the solution and enter the RPM_POINT and RPM_LINE values into config.h. Set the
|
||||
number of piecewise lines used in this model in config.h. Also set the '$30' and '$31'
|
||||
max and min rpm values to the solution values or in a range between them in Grbl '$'
|
||||
settings. And finally, alter the SPINDLE_PWM_MIN_VALUE in cpu_map.h, if your spindle
|
||||
needs to be above a certain voltage to produce a useful low rpm.
|
||||
|
||||
- Once the solution is entered. Recompile and flash Grbl. This solution model is only
|
||||
valid for this particular set of data. If the machine is altered, you will need to
|
||||
perform this experiment again and regenerate a new model here.
|
||||
|
||||
OUTPUT:
|
||||
The solver produces a set of values that define the piecewise fit and can be used by
|
||||
Grbl to quickly and efficiently compute spindle PWM output voltage for a desired RPM.
|
||||
|
||||
The first two are the RPM_MAX ($30) and RPM_MIN ($31) Grbl settings. These must be
|
||||
programmed into Grbl manually or setup in defaults.h for new systems. Altering these
|
||||
values within Grbl after a piece-wise linear model is installed will not change alter
|
||||
model. It will only alter the range of spindle speed rpm values Grbl output.
|
||||
|
||||
For example, if the solver produces an RPM_MAX of 9000 and Grbl is programmed with
|
||||
$30=8000, S9000 may be programmed, but Grbl will only produce the output voltage to run
|
||||
at 8000 rpm. In other words, Grbl will only output voltages the range between
|
||||
max(RPM_MIN,$31) and min(RPM_MAX,$30).
|
||||
|
||||
The remaining values define the slopes and offsets of the line segments and the junction
|
||||
points between line segments, like so for n_pieces=3:
|
||||
|
||||
PWM_output = RPM_LINE_A1 * rpm - RPM_LINE_B1 [ RPM_MIN < rpm < RPM_POINT12 ]
|
||||
PWM_output = RPM_LINE_A2 * rpm - RPM_LINE_B2 [ RPM_POINT12 < rpm < RPM_POINT23 ]
|
||||
PWM_output = RPM_LINE_A3 * rpm - RPM_LINE_B3 [ RPM_POINT23 < rpm < RPM_MAX ]
|
||||
|
||||
NOTE: The script solves in terms of PWM but the final equations and values are expressed
|
||||
in terms of rpm in the form 'PWM = a*rpm - b'.
|
||||
|
||||
"""
|
||||
|
||||
from scipy import optimize
|
||||
import numpy as np
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
# Configure spindle PWM line fit solver
|
||||
|
||||
n_pieces = 4 # Number of line segments used for data fit. Only 1 to 4 line segments supported.
|
||||
|
||||
# Programmed 'S' spindle speed values. Must start with minimum useful PWM or 'S' programmed
|
||||
# value and end with the maximum useful PWM or 'S' programmed value. Order of the array must
|
||||
# be synced with the RPM_measured array below.
|
||||
# NOTE: ** DO NOT USE DATA FROM AN EXISTING PIECEWISE LINE FIT. USE DEFAULT GRBL MODEL ONLY. **
|
||||
PWM_set = np.array([2,18,36,55,73,91,109,127,146,164,182,200,218,237,254], dtype=float)
|
||||
|
||||
# Actual RPM measured at the spindle. Must be in the ascending value and equal in length
|
||||
# as the PWM_set array. Must include the min and max measured rpm output in the first and
|
||||
# last array entries, respectively.
|
||||
RPM_measured = np.array([213.,5420,7145,8282,9165,9765,10100,10500,10700,10900,11100,11250,11400,11550,11650], dtype=float)
|
||||
|
||||
# Configure line fit points by 'S' programmed rpm or PWM value. Values must be between
|
||||
# PWM_max and PWM_min. Typically, alter these values to space the points evenly between
|
||||
# max and min PWM range. However, they may be tweaked to maximize accuracy in the places
|
||||
# you normally operate for highly nonlinear curves. Plot to visually assess how well the
|
||||
# solution fits the data.
|
||||
PWM_point1 = 20.0 # (S) Point between segments 0 and 1. Used when n_pieces >= 2.
|
||||
PWM_point2 = 80.0 # (S) Point between segments 1 and 2. Used when n_pieces >= 3.
|
||||
PWM_point3 = 150.0 # (S) Point between segments 2 and 3. Used when n_pieces = 4.
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
|
||||
# Advanced settings
|
||||
|
||||
# The optimizer requires an initial guess of the solution. Change value if solution fails.
|
||||
slope_i = 100.0; # > 0.0
|
||||
|
||||
PWM_max = max(PWM_set) # Maximum PWM set in measured range
|
||||
PWM_min = min(PWM_set) # Minimum PWM set in measured range
|
||||
plot_figure = True # Set to False, if matplotlib is not available.
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
# DO NOT ALTER ANYTHING BELOW.
|
||||
|
||||
def piecewise_linear_1(x,b,k1):
|
||||
return np.piecewise(x, [(x>=PWM_min)&(x<=PWM_max)], [lambda x:k1*(x-PWM_min)+b])
|
||||
|
||||
def piecewise_linear_2(x,b,k1,k2):
|
||||
c = [b,
|
||||
b+k1*(PWM_point1-PWM_min)]
|
||||
funcs = [lambda x:k1*(x-PWM_min)+c[0],
|
||||
lambda x:k2*(x-PWM_point1)+c[1]]
|
||||
conds = [(x<PWM_point1)&(x>=PWM_min),
|
||||
(x<=PWM_max)&(x>=PWM_point1)]
|
||||
return np.piecewise(x, conds, funcs)
|
||||
|
||||
def piecewise_linear_3(x,b,k1,k2,k3):
|
||||
c = [b,
|
||||
b+k1*(PWM_point1-PWM_min),
|
||||
b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1)]
|
||||
funcs = [lambda x:k1*(x-PWM_min)+c[0],
|
||||
lambda x:k2*(x-PWM_point1)+c[1],
|
||||
lambda x:k3*(x-PWM_point2)+c[2]]
|
||||
conds = [(x<PWM_point1)&(x>=PWM_min),
|
||||
(x<PWM_point2)&(x>=PWM_point1),
|
||||
(x<=PWM_max)&(x>=PWM_point2)]
|
||||
return np.piecewise(x, conds, funcs)
|
||||
|
||||
def piecewise_linear_4(x,b,k1,k2,k3,k4):
|
||||
c = [b,
|
||||
b+k1*(PWM_point1-PWM_min),
|
||||
b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1),
|
||||
b+k1*(PWM_point1-PWM_min)+k2*(PWM_point2-PWM_point1)+k3*(PWM_point3-PWM_point2)]
|
||||
funcs = [lambda x:k1*(x-PWM_min)+c[0],
|
||||
lambda x:k2*(x-PWM_point1)+c[1],
|
||||
lambda x:k3*(x-PWM_point2)+c[2],
|
||||
lambda x:k4*(x-PWM_point3)+c[3]]
|
||||
conds = [(x<PWM_point1)&(x>=PWM_min),
|
||||
(x<PWM_point2)&(x>=PWM_point1),
|
||||
(x<PWM_point3)&(x>=PWM_point2),
|
||||
(x<=PWM_max)&(x>=PWM_point3)]
|
||||
return np.piecewise(x, conds, funcs)
|
||||
|
||||
# ----------------------------------------------------------------------------------------
|
||||
|
||||
print("\nCONFIG:")
|
||||
print(" N_pieces: %i" % n_pieces)
|
||||
print(" PWM_min: %.1f" % PWM_min)
|
||||
print(" PWM_max: %.1f" % PWM_max)
|
||||
if n_pieces > 1:
|
||||
print(" PWM_point1: %.1f" % PWM_point1)
|
||||
if n_pieces > 2:
|
||||
print(" PWM_point2: %.1f" % PWM_point2)
|
||||
if n_pieces > 3:
|
||||
print(" PWM_point3: %.1f" % PWM_point3)
|
||||
print(" N_data: %i" % len(RPM_measured))
|
||||
print(" PWM_set: ", PWM_set)
|
||||
print(" RPM_measured: ", RPM_measured)
|
||||
|
||||
if n_pieces == 1:
|
||||
piece_func = piecewise_linear_1
|
||||
p_initial = [RPM_measured[0],slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1]]
|
||||
b = [ p[0]-p[1]*PWM_min]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)]
|
||||
|
||||
elif n_pieces == 2:
|
||||
piece_func = piecewise_linear_2
|
||||
p_initial = [RPM_measured[0],slope_i,slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1],p[2]]
|
||||
b = [ p[0]-p[1]*PWM_min,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_max-PWM_point1)]
|
||||
|
||||
elif n_pieces == 3:
|
||||
piece_func = piecewise_linear_3
|
||||
p_initial = [RPM_measured[0],slope_i,slope_i,slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1],p[2],p[3]]
|
||||
b = [ p[0]-p[1]*PWM_min,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)-p[3]*PWM_point2]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_max-PWM_point2) ]
|
||||
|
||||
elif n_pieces == 4:
|
||||
piece_func = piecewise_linear_4
|
||||
p_initial = [RPM_measured[0],slope_i,slope_i,slope_i,slope_i]
|
||||
|
||||
p , e = optimize.curve_fit(piece_func, PWM_set, RPM_measured, p0=p_initial)
|
||||
a = [p[1],p[2],p[3],p[4]]
|
||||
b = [ p[0]-p[1]*PWM_min,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)-p[2]*PWM_point1,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)-p[3]*PWM_point2,
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2)-p[4]*PWM_point3 ]
|
||||
rpm = [ p[0],
|
||||
p[0]+p[1]*(PWM_point1-PWM_min),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2),
|
||||
p[0]+p[1]*(PWM_point1-PWM_min)+p[2]*(PWM_point2-PWM_point1)+p[3]*(PWM_point3-PWM_point2)+p[4]*(PWM_max-PWM_point3) ]
|
||||
|
||||
else :
|
||||
print("ERROR: Unsupported number of pieces. Check and alter n_pieces")
|
||||
quit()
|
||||
|
||||
print("\nSOLUTION:\n\n[Update these #define values and uncomment]\n[ENABLE_PIECEWISE_LINEAR_SPINDLE in config.h.]")
|
||||
print("#define N_PIECES %.0f" % n_pieces)
|
||||
print("#define RPM_MAX %.1f" % rpm[-1])
|
||||
print("#define RPM_MIN %.1f" % rpm[0])
|
||||
|
||||
if n_pieces > 1:
|
||||
print("#define RPM_POINT12 %.1f" % rpm[1])
|
||||
if n_pieces > 2:
|
||||
print("#define RPM_POINT23 %.1f" %rpm[2])
|
||||
if n_pieces > 3:
|
||||
print("#define RPM_POINT34 %.1f" %rpm[3])
|
||||
|
||||
print("#define RPM_LINE_A1 %.6e" % (1./a[0]))
|
||||
print("#define RPM_LINE_B1 %.6e" % (b[0]/a[0]))
|
||||
if n_pieces > 1:
|
||||
print("#define RPM_LINE_A2 %.6e" % (1./a[1]))
|
||||
print("#define RPM_LINE_B2 %.6e" % (b[1]/a[1]))
|
||||
if n_pieces > 2:
|
||||
print("#define RPM_LINE_A3 %.6e" % (1./a[2]))
|
||||
print("#define RPM_LINE_B3 %.6e" % (b[2]/a[2]))
|
||||
if n_pieces > 3:
|
||||
print("#define RPM_LINE_A4 %.6e" % (1./a[3]))
|
||||
print("#define RPM_LINE_B4 %.6e" % (b[3]/a[3]))
|
||||
|
||||
print("\n[To operate over full model range, manually write these]")
|
||||
print("['$' settings or alter values in defaults.h. Grbl will]")
|
||||
print("[operate between min($30,RPM_MAX) and max($31,RPM_MIN)]")
|
||||
print("$30=%.1f (rpm max)" % rpm[-1])
|
||||
print("$31=%.1f (rpm min)" % rpm[0])
|
||||
|
||||
if (PWM_min > 1)|(PWM_max<255):
|
||||
print("\n[Update the following #define values in cpu_map.h]")
|
||||
if (PWM_min >1) :
|
||||
print("#define SPINDLE_PWM_MIN_VALUE %.0f" % PWM_min)
|
||||
if PWM_max <255:
|
||||
print("#define SPINDLE_PWM_MAX_VALUE %.0f" % PWM_max)
|
||||
else:
|
||||
print("\n[No cpu_map.h changes required.]")
|
||||
print("\n")
|
||||
|
||||
test_val = (1./a[0])*rpm[0] - (b[0]/a[0])
|
||||
if test_val < 0.0 :
|
||||
print("ERROR: Solution is negative at RPM_MIN. Adjust junction points or increase n_pieces.\n")
|
||||
|
||||
if plot_figure:
|
||||
import matplotlib
|
||||
matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig = plt.figure()
|
||||
ax = fig.add_subplot(111)
|
||||
xd = np.linspace(PWM_min, PWM_max, 10000)
|
||||
ax.plot(PWM_set, RPM_measured, "o")
|
||||
ax.plot(xd, piece_func(xd, *p),'g')
|
||||
plt.xlabel("Programmed PWM")
|
||||
plt.ylabel("Measured RPM")
|
||||
|
||||
# Check solution by plotting in terms of rpm.
|
||||
# x = np.linspace(rpm[0], rpm[1], 10000)
|
||||
# ax.plot((1./a[0])*x-(b[0]/a[0]),x,'r:')
|
||||
# if n_pieces > 1:
|
||||
# x = np.linspace(rpm[1], rpm[2], 10000)
|
||||
# ax.plot((1./a[1])*x-(b[1]/a[1]),x,'r:')
|
||||
# if n_pieces > 2:
|
||||
# x = np.linspace(rpm[2], rpm[3], 10000)
|
||||
# ax.plot((1./a[2])*x-(b[2]/a[2]),x,'r:')
|
||||
# if n_pieces > 3:
|
||||
# x = np.linspace(rpm[3], rpm[-1], 10000)
|
||||
# ax.plot((1./a[3])*x-(b[3]/a[3]),x,'r:')
|
||||
|
||||
fig.savefig("line_fit.png")
|
BIN
Grbl_Esp32-master/doc/script/piecewise_example.png
Normal file
BIN
Grbl_Esp32-master/doc/script/piecewise_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
66
Grbl_Esp32-master/doc/script/simple_stream.py
Normal file
66
Grbl_Esp32-master/doc/script/simple_stream.py
Normal file
@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
Simple g-code streaming script for grbl
|
||||
|
||||
Provided as an illustration of the basic communication interface
|
||||
for grbl. When grbl has finished parsing the g-code block, it will
|
||||
return an 'ok' or 'error' response. When the planner buffer is full,
|
||||
grbl will not send a response until the planner buffer clears space.
|
||||
|
||||
G02/03 arcs are special exceptions, where they inject short line
|
||||
segments directly into the planner. So there may not be a response
|
||||
from grbl for the duration of the arc.
|
||||
|
||||
---------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012 Sungeun K. Jeon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
---------------------
|
||||
"""
|
||||
|
||||
import serial
|
||||
import time
|
||||
|
||||
# Open grbl serial port
|
||||
s = serial.Serial('/dev/tty.usbmodem1811',115200)
|
||||
|
||||
# Open g-code file
|
||||
f = open('grbl.gcode','r');
|
||||
|
||||
# Wake up grbl
|
||||
s.write("\r\n\r\n")
|
||||
time.sleep(2) # Wait for grbl to initialize
|
||||
s.flushInput() # Flush startup text in serial input
|
||||
|
||||
# Stream g-code to grbl
|
||||
for line in f:
|
||||
l = line.strip() # Strip all EOL characters for consistency
|
||||
print 'Sending: ' + l,
|
||||
s.write(l + '\n') # Send g-code block to grbl
|
||||
grbl_out = s.readline() # Wait for grbl response with carriage return
|
||||
print ' : ' + grbl_out.strip()
|
||||
|
||||
# Wait here until grbl is finished to close serial port and file.
|
||||
raw_input(" Press <Enter> to exit and disable grbl.")
|
||||
|
||||
# Close file and serial port
|
||||
f.close()
|
||||
s.close()
|
202
Grbl_Esp32-master/doc/script/stream.py
Normal file
202
Grbl_Esp32-master/doc/script/stream.py
Normal file
@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env python
|
||||
"""\
|
||||
|
||||
Stream g-code to grbl controller
|
||||
|
||||
This script differs from the simple_stream.py script by
|
||||
tracking the number of characters in grbl's serial read
|
||||
buffer. This allows grbl to fetch the next line directly
|
||||
from the serial buffer and does not have to wait for a
|
||||
response from the computer. This effectively adds another
|
||||
buffer layer to prevent buffer starvation.
|
||||
|
||||
CHANGELOG:
|
||||
- 20170531: Status report feedback at 1.0 second intervals.
|
||||
Configurable baudrate and report intervals. Bug fixes.
|
||||
- 20161212: Added push message feedback for simple streaming
|
||||
- 20140714: Updated baud rate to 115200. Added a settings
|
||||
write mode via simple streaming method. MIT-licensed.
|
||||
|
||||
TODO:
|
||||
- Add realtime control commands during streaming.
|
||||
|
||||
---------------------
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2012-2017 Sungeun K. Jeon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
---------------------
|
||||
"""
|
||||
|
||||
import serial
|
||||
import re
|
||||
import time
|
||||
import sys
|
||||
import argparse
|
||||
import threading
|
||||
|
||||
RX_BUFFER_SIZE = 128
|
||||
BAUD_RATE = 115200
|
||||
ENABLE_STATUS_REPORTS = True
|
||||
REPORT_INTERVAL = 1.0 # seconds
|
||||
|
||||
is_run = True # Controls query timer
|
||||
|
||||
# Define command line argument interface
|
||||
parser = argparse.ArgumentParser(description='Stream g-code file to grbl. (pySerial and argparse libraries required)')
|
||||
parser.add_argument('gcode_file', type=argparse.FileType('r'),
|
||||
help='g-code filename to be streamed')
|
||||
parser.add_argument('device_file',
|
||||
help='serial device path')
|
||||
parser.add_argument('-q','--quiet',action='store_true', default=False,
|
||||
help='suppress output text')
|
||||
parser.add_argument('-s','--settings',action='store_true', default=False,
|
||||
help='settings write mode')
|
||||
parser.add_argument('-c','--check',action='store_true', default=False,
|
||||
help='stream in check mode')
|
||||
args = parser.parse_args()
|
||||
|
||||
# Periodic timer to query for status reports
|
||||
# TODO: Need to track down why this doesn't restart consistently before a release.
|
||||
def send_status_query():
|
||||
s.write('?')
|
||||
|
||||
def periodic_timer() :
|
||||
while is_run:
|
||||
send_status_query()
|
||||
time.sleep(REPORT_INTERVAL)
|
||||
|
||||
|
||||
# Initialize
|
||||
s = serial.Serial(args.device_file,BAUD_RATE)
|
||||
f = args.gcode_file
|
||||
verbose = True
|
||||
if args.quiet : verbose = False
|
||||
settings_mode = False
|
||||
if args.settings : settings_mode = True
|
||||
check_mode = False
|
||||
if args.check : check_mode = True
|
||||
|
||||
# Wake up grbl
|
||||
print "Initializing Grbl..."
|
||||
s.write("\r\n\r\n")
|
||||
|
||||
# Wait for grbl to initialize and flush startup text in serial input
|
||||
time.sleep(2)
|
||||
s.flushInput()
|
||||
|
||||
if check_mode :
|
||||
print "Enabling Grbl Check-Mode: SND: [$C]",
|
||||
s.write("$C\n")
|
||||
while 1:
|
||||
grbl_out = s.readline().strip() # Wait for grbl response with carriage return
|
||||
if grbl_out.find('error') >= 0 :
|
||||
print "REC:",grbl_out
|
||||
print " Failed to set Grbl check-mode. Aborting..."
|
||||
quit()
|
||||
elif grbl_out.find('ok') >= 0 :
|
||||
if verbose: print 'REC:',grbl_out
|
||||
break
|
||||
|
||||
start_time = time.time();
|
||||
|
||||
# Start status report periodic timer
|
||||
if ENABLE_STATUS_REPORTS :
|
||||
timerThread = threading.Thread(target=periodic_timer)
|
||||
timerThread.daemon = True
|
||||
timerThread.start()
|
||||
|
||||
# Stream g-code to grbl
|
||||
l_count = 0
|
||||
error_count = 0
|
||||
if settings_mode:
|
||||
# Send settings file via simple call-response streaming method. Settings must be streamed
|
||||
# in this manner since the EEPROM accessing cycles shut-off the serial interrupt.
|
||||
print "SETTINGS MODE: Streaming", args.gcode_file.name, " to ", args.device_file
|
||||
for line in f:
|
||||
l_count += 1 # Iterate line counter
|
||||
# l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
|
||||
l_block = line.strip() # Strip all EOL characters for consistency
|
||||
if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
|
||||
s.write(l_block + '\n') # Send g-code block to grbl
|
||||
while 1:
|
||||
grbl_out = s.readline().strip() # Wait for grbl response with carriage return
|
||||
if grbl_out.find('ok') >= 0 :
|
||||
if verbose: print " REC<"+str(l_count)+": \""+grbl_out+"\""
|
||||
break
|
||||
elif grbl_out.find('error') >= 0 :
|
||||
if verbose: print " REC<"+str(l_count)+": \""+grbl_out+"\""
|
||||
error_count += 1
|
||||
break
|
||||
else:
|
||||
print " MSG: \""+grbl_out+"\""
|
||||
else:
|
||||
# Send g-code program via a more agressive streaming protocol that forces characters into
|
||||
# Grbl's serial read buffer to ensure Grbl has immediate access to the next g-code command
|
||||
# rather than wait for the call-response serial protocol to finish. This is done by careful
|
||||
# counting of the number of characters sent by the streamer to Grbl and tracking Grbl's
|
||||
# responses, such that we never overflow Grbl's serial read buffer.
|
||||
g_count = 0
|
||||
c_line = []
|
||||
for line in f:
|
||||
l_count += 1 # Iterate line counter
|
||||
l_block = re.sub('\s|\(.*?\)','',line).upper() # Strip comments/spaces/new line and capitalize
|
||||
# l_block = line.strip()
|
||||
c_line.append(len(l_block)+1) # Track number of characters in grbl serial read buffer
|
||||
grbl_out = ''
|
||||
while sum(c_line) >= RX_BUFFER_SIZE-1 | s.inWaiting() :
|
||||
out_temp = s.readline().strip() # Wait for grbl response
|
||||
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
|
||||
print " MSG: \""+out_temp+"\"" # Debug response
|
||||
else :
|
||||
if out_temp.find('error') >= 0 : error_count += 1
|
||||
g_count += 1 # Iterate g-code counter
|
||||
if verbose: print " REC<"+str(g_count)+": \""+out_temp+"\""
|
||||
del c_line[0] # Delete the block character count corresponding to the last 'ok'
|
||||
s.write(l_block + '\n') # Send g-code block to grbl
|
||||
if verbose: print "SND>"+str(l_count)+": \"" + l_block + "\""
|
||||
# Wait until all responses have been received.
|
||||
while l_count > g_count :
|
||||
out_temp = s.readline().strip() # Wait for grbl response
|
||||
if out_temp.find('ok') < 0 and out_temp.find('error') < 0 :
|
||||
print " MSG: \""+out_temp+"\"" # Debug response
|
||||
else :
|
||||
if out_temp.find('error') >= 0 : error_count += 1
|
||||
g_count += 1 # Iterate g-code counter
|
||||
del c_line[0] # Delete the block character count corresponding to the last 'ok'
|
||||
if verbose: print " REC<"+str(g_count)+": \""+out_temp + "\""
|
||||
|
||||
# Wait for user input after streaming is completed
|
||||
print "\nG-code streaming finished!"
|
||||
end_time = time.time();
|
||||
is_run = False;
|
||||
print " Time elapsed: ",end_time-start_time,"\n"
|
||||
if check_mode :
|
||||
if error_count > 0 :
|
||||
print "CHECK FAILED:",error_count,"errors found! See output for details.\n"
|
||||
else :
|
||||
print "CHECK PASSED: No errors found in g-code program.\n"
|
||||
else :
|
||||
print "WARNING: Wait until Grbl completes buffered g-code blocks before exiting."
|
||||
raw_input(" Press <Enter> to exit and disable Grbl.")
|
||||
|
||||
# Close file and serial port
|
||||
f.close()
|
||||
s.close()
|
16
Grbl_Esp32-master/embedded/build.bat
Normal file
16
Grbl_Esp32-master/embedded/build.bat
Normal file
@ -0,0 +1,16 @@
|
||||
cd %~dp0
|
||||
cmd.exe /c npm install
|
||||
cmd.exe /c npm audit fix
|
||||
cmd.exe /c npm audit
|
||||
cmd.exe /c gulp package
|
||||
cmd.exe /c bin2c -o embedded.h -m tool.html.gz
|
||||
cat header.txt > out.h
|
||||
cat embedded.h >> out.h
|
||||
cat footer.txt >> out.h
|
||||
sed -i "s/tool_html_gz_size/PAGE_NOFILES_SIZE/g" ./out.h
|
||||
sed -i "s/const unsigned char tool_html_gz/const char PAGE_NOFILES/g" ./out.h
|
||||
sed -i "s/] = {/] PROGMEM = {/g" ./out.h
|
||||
cat out.h > ../Grbl_Esp32/nofile.h
|
||||
rm -f out.h
|
||||
pause
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user