From c950e2a16d4c7c6ad9a3fe050cb2c9a6454abfa3 Mon Sep 17 00:00:00 2001 From: bdring Date: Wed, 3 Feb 2021 14:55:01 -0600 Subject: [PATCH 1/4] Devt (#732) * Fixed various small bugs (#605) * Fixed various small bugs * Fixed potential cast bug * Fixed double reporting of errors Co-authored-by: Stefan de Bruijn * Stallguard tuning (#607) * Devt (#571) * Handles Tranimic drivers errors better - If an unsupported driver is specified, it will give a message and not crash. * Cleaned up unused files Got rid of old unipolar files Got rid of servo axis feature - it is a motor class now Got rid of solenoid pen feature - never really used and it should be a motor class if it is. * Fix ENABLE_AUTHENTICATION (#569) * Fixed authentication code. * Removed another const cast Co-authored-by: Stefan de Bruijn * Fix step leakage with inverted steps (#570) * Fix step leakage with inverted steps * Update build date for merge Co-authored-by: Bart Dring Co-authored-by: Stefan de Bruijn Co-authored-by: Stefan de Bruijn Co-authored-by: Mitch Bradley Co-authored-by: Bart Dring * Update platformio.ini Per PR 583 * Created an enum for mode * Removing some unused machine defs * Added test machine definition * Clean up for PR * Remove test machine def. Co-authored-by: Stefan de Bruijn Co-authored-by: Stefan de Bruijn Co-authored-by: Mitch Bradley Co-authored-by: Bart Dring * Basic testing Complete * Made state variable volatile. * Homing cycle settings (#613) * Initial Tests Complete * Update Grbl.h * Update variables Co-authored-by: Mitch Bradley * fixed dual switches when inverted (#614) * fixed dual switches when inverted * Removed debug message * Cleaning up the machine defs Removed unused #defines. * Store coordinate offsets in NVS (#611) * Store coordinate offsets in NVS * Handle both old Eeprom formats * Implementing fixes (#616) - Stop creating additional tasks when limit_init() gets called again from homing and resets - Explicitly delete an object that was causing a memory loss. * Update Grbl.h * Tweak memory fix and add $H check for $Homing/Cycles * Fix G28.1 and G30.1 * Update Grbl.h * Homing cycle defaults (#624) * Changed to add homing cycle defaults There needs to be a way to set the homing cycle defaults in a machine definition. There will likely be a better way to do this in the future. * Update 10vSpindle.cpp Had wrong error message * Fixed typos and removed obsolete #defines * Probe cleanup (#625) * Cleanup probing code * Update Grbl.h * Update after review * Update error_codes_en_US.csv * More sd_close() to free memory (#622) * Changed buffer sizes to 256 throughout various parts of the program. (#626) This is a patch necessary for F360 personal users, because they decided to add a very lengthy comment... Co-authored-by: Stefan de Bruijn * $sd/show and handle settings in SD files (#629) * $sd/show and handle settings in SD files * Added $LocalFs/Show and fixed $LocalFs/Run output * Infer / at beginning of SD path name The LocalFS path processing code already inserts a / at the beginning of the path is one isn't present. This patch does the same for SD files. * Show $ command responses in WebUI console * Added $Settings/ListChanged AKA $SC This is useful for saving settings in a compact form that leaves defaults unchanged. * $sd/show works in idle or alarm state * Apply idle/alarm checks to SPIFFS files too * Changed sd_close to SD.end() sd_close was a temporary function to check for memory usage * Big BUILD_INFO fix (#632) -- Changes that affect behavior Fixed the bugs with report_build_info() Build info is no longer stored in the fixed "EEPROM" section; instead it is a proper Setting named $Firmware/Build . You can change it in the usual way with $Firmware/Build= $I without the = still works. -- Changes that affect configurability for developers Converted a couple more #defines into enums - SETTINGS_RESTORE_* and BITFLAG_RT_STATUS_* . A side effect of this is that it is no longer possible to configure the behavior of $RST=* by defining SETTINGS_RESTORE_ALL to include only a subset. I think it is a bad idea from a customer support perspective to have the meaning of this command be different for different builds. Changed some of the #define ENABLE_ names to eliminate "EEPROM" -- Changes that are purely cosmetic Clarified descriptions in Config.h, to eliminate spurious/incorrect mentions of "EEPROM" Eliminated all mentions of the name "EEPROM" except the ones that truly mean the EEPROM section, as opposed to generalized non-volatile storage. The contents of SettingsStorage.h and SettingsStorage.cpp, which were really related to coordinate storage in Eeprom, not proper settings, were moved to Eeprom.h and Eeprom.cpp. The SettingsStorage files are gone. Got rid of get_step_pin_mask() and get_direction_pin_mask() because they were just aliases for bit(). That eliminated some junk from the SettingsStorage/Eeprom files. Those files now tightly contain only the residual stuff related to the storage of coordinate data in EEPROM. * Most #defines are gone (#595) * Many more #defines bite the dust * Fixed botch in rt accessory logic * Update Probe.cpp * Update System.cpp * Typo * Fixed WebUI crash (#633) While eliminating a redundant definition of is_realtime_command(), I inadvertently introduced a recursion due to the similarity of the names "is_realtime_command()" and "is_realtime_cmd()". The solution is to eliminate the latter entirely. * Fix i2s probing hang (#608) * Fix I2S stepper hung just after the completion of motor moving * Fix recompile issue Fixed a problem with the recompile not being recompiled even if the files under the Custom folder are changed. * More comment for macOS in debug.ini * Fix the timing of calling I2S out's exclusion function and reset sequence The reset sequence did not seem to be correct, so I changed it. According to the ESP-IDF PR, the correct sequence is as follows: 1)TX module 2)DMA 3)FIFO https://github.com/espressif/esp-idf/commit/c7f33524b469e75937f003d4c06336bf4694a043#diff-27688c6b3c29373d2a2b142b8471981c * Changed the message level for I2S swtiching from warning to debug * Add some comments * Implement stepping through Motors class (#636) * Implement stepping through Motors class WIP for discussion and review - not ready to merge yet * Document Motor methods and variables .. and remove some unused ones and move some that are subclass-specific * Move position_min/max to Limits.cpp ... and coalesced other uses thereof into a unified scheme. * Call motor ->init() explicitly instead of implicitly This makes it possible to inherit constructors without spurious config messages. * Fixed problems with I2S * Changes in class method override syntax per atlaste * Fixed oops * More Motors simplification a) Eliminated can_home() in favor of a return value from set_homing_mode() b) Eliminated axis_name() in favor of reportAxisNameMsg() * Fixes to RcServo and Trinamic - RC Servo was not handling disable ... probably old issue - Display test after config * More tweaks * Define that variable! * Move functions from Motors.cpp to subclasses Created a Servo base class from which RcServo and Dynamixel2 are derived. This gets the servo update task out of Motors. It also eliminates the need for type_id. Now all of the functions that are specific to particular kinds of motors are within their subclasses * Adding Dynamixel to ABC axes. * Removed second #ifndef SPINDLE_TYPE * Fixed potential leak in Report.cpp as reported by @atlaste * Some servo cleanup. Has errors! * min should be max * Removed test rcservo machine definition. * Removed obsolete #defines in machine defs for RcServo cal Co-authored-by: bdring * Cleaned up AMASS code (#635) * Cleaned up AMASS code More #defines gone 74 lines shorter Tested by comparing the result of original AMASS computation code to the new code with values surrounding all of the cutoff frequencies. * I2SOut tick calculation * Sorted out units for stepper pulse periods I tried to make it clear what the units are at different places in the code, and to use argument datatypes that clearly show the value range at different points, instead of relying on implicit type promotion. Hopefully this will make it easier to understand when, where, and why unit conversions occur. * Update Stepper.h * Deleted AMASS Config.h option ... as it is no longer optional * Use less memory (#644) a) closeFile() now does SD.end() to release memory after running a file from SD. b) Several task stacks are smaller c) All tasks now check their free space if DEBUG_REPORT_STACK_FREE is defined. platformio.ini has a commented-out line that can be uncommented to turn that on. d) Similarly, platformio.ini can turn on DEBUG_REPORT_HEAP_SIZE e) Fixed a small leak that occurred when listing local files. With these changes, the heap size tends to hover around 53K, dropping to about 37K when running a file from SD. * Add coolant pin messages to startup (#647) * Add coolant pin messages to startup Help with user support. * Removing incorrect STEPPER_RESET definition * Fix laser mode startup message * cleanup - coolant_init() will behave as before - update build date - return default machine to test_drive * Move CoreXY out of main Grbl (#653) * Created branch * WIP * Update parallel_delta.cpp * Wip * WIP * Wip * Still working on kinematics - Added an interface into the jogging section * WIP * WIP * wip * WIP * WIP * Wip * WIP * WIP * Wip * Update machine defs * Created branch * WIP * Update parallel_delta.cpp * Wip * WIP * Wip * Still working on kinematics - Added an interface into the jogging section * WIP * WIP * wip * WIP * WIP * Wip * WIP * WIP * Wip * Update machine defs * Machine def change. Moved switches to module 1 * WIP * Cleanup before P.R. - Fixed ranges for delta geometry - Added post homing delay option for servos - renamed and removed old machine defs. * Fixing initialization problem when not in USE_KINEMATICS mode * Fixing Git Mess * Publishing Branch - Not ready yet. Issues with Z axis - Need to add midTbot option * WIP - Seems to be fully functional now. - Need to add midTbot option. * Update CoreXY.cpp * I think it is ready for PR - fixed $RST=# - added midTbot geometry factor * Fine tune midtbot definition * Removed more unneeded corexy code. * Fixed doubled #define in machine def file. * Update after review comments * Added $A AKA Alarms/List command (#654) * Added $A AKA Alarms/List command Similar to $E AKA Errors/List $E used to be AKA ErrorCodes/List Also added $Errors/Verbose setting to display full error text instead of the error number. It defaults to true because it works with every sender I have tried so far - cncjs, UGS, and Chrome GCode Sender. If you have problems with some sender you can set it to false. * Added static_assert per atlaste's comment * Added a default and fixed Authentication issue Co-authored-by: bdring * TMC2130 plotter machine servo config update (#657) * TMC2130 plotter machine servo config update based on Slack conversation https://buildlog.slack.com/archives/CBZKZ8LHL/p1604243530253000 * Update Grbl.h * Trinamic reporting (#656) * Enhanced reporting of errors * Change "motor" to "driver" for clarity. * Added better way to show changed Setting values from Mitch * Update build date * Machine Definition Cleanup (#658) - Removed machine definitions to speed up testing. - Moved 6 pack CS/MS3 pins with other axis pins to help them stay in sync with the aixs letters * Spindle delay and Telnet Fix (#676) * Removed early saving of old state Was causing later tests to be wrong * Update Grbl.h * Update TelnetServer.cpp Remove filtering of '\r' character. * ABC Bresenham counter init fix * Rst responses (#679) * Added verification of changes from $RST command When sending $RST=$ you only get these responses. [MSG:WiFi reset done] [MSG:BT reset done] Added the other things that change. [MSG:WiFi reset done] [MSG:BT reset done] [MSG:Settings reset done] [MSG:Postion offsets reset done] * Update ProcessSettings.cpp * Update Grbl.h * Update ProcessSettings.cpp * Fix Spindle State broken in earlier PR * Update Grbl.h * Spindle and laser (#683) * WIP * Updates * Updates - Added Laser/FullPower - Move some stuff from PWM to Laser * WIP * Used the stop function before resetiing pins. * Updates from discussion - Reset_pins is now deinit() - VFD task is now deleted when ... deinit() - Added a Motor/Disable command * Added Mitch's gambit * Cleanup - Finished VFD - Fixed Settings (Thanks Brian!) - changed task cores. * Update VFDSpindle.cpp * Update Laser.cpp * Fixing reset - gpio_reset_pin sets a pullup, which could turn on a device * Changed Spindle messages to CLIENT_ALL * Update Grbl.h * Updates after review * P.R. Cleanup * Most spindle settings cause a new init() * Laser mode (#692) * Update Machine.h * spindles now say if in laser mode * name fix * Updates * Getting rid of crosstalk * Update PWMSpindle.cpp * Reset some values at spindle init() * Update SettingsDefinitions.cpp * Update Grbl.h * Return to test_drive.h * User macro button (#685) * Test Macro Button Idea * Updates * Formating * Changed macro pin reporting to be a single character * Sd Web UI issues (#698) * Updates * returned reportTaskStackSize(uxHighWaterMark); In a #ifdef DEBUG_TASK_STACK guard * Disallow web commands unless idle or alarm state * merging stuff after review * Handle SD busy state in webserver handler (#697) * Handle SD busy state in webserver handler * Update index.html.gz * Fixed reporting * Add case for SD not enabled. * Prevent Web commands except in idle or alarm * Return authentication to the default Co-authored-by: Mitch Bradley Co-authored-by: Luc <8822552+luc-github@users.noreply.github.com> * Update axis squaring checking (#699) * Reverting some spindle changes... CLIENT_ALL caused queue issues * Rate Adjusting Fix * Fix SD card hanging on bad gcode * Fix hang on error 20 from SD/Run (#701) * Fixed strange WCO values on first load (#702) When loading Grbl_Esp32 into a fresh ESP32, the WCOs would often have strange, very large, values. The problem was the code that tries to propagate data from the old "Eeprom" storage format into the new NVS scheme. The old format had a broken checksum computation that made the checksum so weak that if succeeds about half the time on random data. The solution is to get rid of all that old code. The downside is that migration from a build that uses the old format will lose the WCO values. The user will have to reestablish them. Subsequent updates between different versions that both use the new NVS format will propagate WCO values correctly. * Fixes to homing (#706) * Fixes to homing * Update Grbl.h * Clean up after code review. * Trinamic uart (#700) * WIP * WIP * Updates * Update Grbl.h * Removing some test machine definitions * TMC5160 Drivers were not in tests * Fix a few issues with VFDSpindle critical error handling (#705) If a command is critical and fails to receive a response, it should trigger an Alarm. However, because the critical check was only evaluated if the spindle was not already unresponsive, it meant that a critical command failure would be silently ignored if a non-critical command failed before it (putting the VFDSpindle in unresponsive state). Therefore, I've moved the critical check to occur regardless of whether the spindle was already unresponsive. Second, I believe that setting `sys_rt_exec_alarm` is not sufficient to stop the machine and put it into alarm state. Other alarm conditions (such as hard limits) also run an `mc_reset()` to stop motion first. It appears that without this, motion will not be stopped, and in fact, the alarm appears to get cleared if it occurs during motion! * Update per P.R. #704 on main * Update Motors.cpp * Fix undefined probe reporting if inverted. * Settings filtering via regular expressions (#717) * Settings filtering via regular expressions Implements only the most basic - and the most useful - special characters - ^$.* If the search string does not contain a special character, it is interpreted as before. Otherwise the match is either more strict if anchored by ^ or $, or less strict if it contains a . wildcard or a * repetition. * Commentary * Eliminated . metacharacter * Fix SD/List repetition error (#727) * Fix SD/List repetition error The one line change that actually fixes it is Serial.cpp line 162, where the SD state is compared to "not busy" instead of "is idle", thus also handling the "not present" case. In the process, I converted the "const int SDCARD_ ..." to an SDState enum class, thus proving type safety and eliminating yet another untyped uint8_t . * Updates after testing Co-authored-by: bdring * Fixed RcServo Cals * PWM fix and simplification (#722) * PWM fix and simplification This is an alternative solution to the PWM/ISR/float problem. 1. The set_level() argument is the exact value that is passed to the LEDC Write function. It can be interpreted as the numerator of a rational fraction whose denominator is the max PWM value, i.e. the precision, == 1 << _resolution_bits 2. There is a new denominator() method that returns the precision. 3. The sys_pwm_control(mask, duty, synchronize) function is replaced by two functions sys_analog_all_off() and sys_set_analog(io_num, duty). This closely matches the actual usage. The old routine was called from two places, one where the mask was alway 0xFF, the duty was always 0, and synchronize was always false. That is the one that was troublesome from ISR context. The other call always affected a single pin, so the mask formulation with its loop was useless extra baggage. By splitting into two functions, each one becomes much simpler, thus faster and easier to understand. The "synchronize" argument and associated logic moved out to the caller (GCode.cpp), which more closely reflects the behavioral logic. 4. For symmetry, sys_io_control() was similarly split. 5. sys_calc_pwm_precision() was moved into UserOutput.cpp since is it driver specific, not a general system routine. * Update Grbl.h * Delete template.h Co-authored-by: bdring * TMC2209 Stallguard (#748) * TMC2209 Stallguard - Added StallGuard homing support to TMC2209 (UART) - Killed off TMC2208 for now. Too many conflicts with TMC2209. Will return with Diamond motor class hierarchy - Increase StallGuard setting range for TMC2209. Constrianed in each class to actual limits - Added a machine def to test TMC2209 * Update build date * Web cmd modes (#754) * Update System.cpp * WebCommand with configurable modes * Added a few more ESP commands to work in anu state * Update Grbl.h Co-authored-by: Mitch Bradley * Updates from PWM_ISR_Fix branch (#755) - $Message/Level - ISR safe ledcWrite Co-authored-by: Stefan de Bruijn Co-authored-by: Stefan de Bruijn Co-authored-by: Mitch Bradley Co-authored-by: Bart Dring Co-authored-by: odaki Co-authored-by: Pete Wildsmith Co-authored-by: Luc <8822552+luc-github@users.noreply.github.com> Co-authored-by: Scott Bezek --- Grbl_Esp32/src/Config.h | 4 +- Grbl_Esp32/src/GCode.cpp | 15 +- Grbl_Esp32/src/Grbl.h | 2 +- Grbl_Esp32/src/Machines/TMC2209_4x.h | 89 +++++++ Grbl_Esp32/src/Machines/template.h | 233 ------------------ Grbl_Esp32/src/MotionControl.cpp | 6 +- Grbl_Esp32/src/Motors/RcServo.cpp | 3 + Grbl_Esp32/src/Motors/TrinamicDriver.cpp | 4 +- Grbl_Esp32/src/Motors/TrinamicUartDriver.h | 2 +- .../src/Motors/TrinamicUartDriverClass.cpp | 89 ++++--- Grbl_Esp32/src/Probe.cpp | 2 +- Grbl_Esp32/src/ProcessSettings.cpp | 22 +- Grbl_Esp32/src/Regex.cpp | 60 +++++ Grbl_Esp32/src/Regex.h | 5 + Grbl_Esp32/src/Report.cpp | 14 +- Grbl_Esp32/src/Report.h | 6 +- Grbl_Esp32/src/SDCard.cpp | 20 +- Grbl_Esp32/src/SDCard.h | 17 +- Grbl_Esp32/src/Serial.cpp | 2 +- Grbl_Esp32/src/Settings.cpp | 13 + Grbl_Esp32/src/Settings.h | 23 +- Grbl_Esp32/src/SettingsDefinitions.cpp | 27 +- Grbl_Esp32/src/SettingsDefinitions.h | 2 + Grbl_Esp32/src/Spindles/PWMSpindle.cpp | 11 +- Grbl_Esp32/src/System.cpp | 43 ++-- Grbl_Esp32/src/System.h | 9 +- Grbl_Esp32/src/UserOutput.cpp | 28 ++- Grbl_Esp32/src/UserOutput.h | 17 +- Grbl_Esp32/src/WebUI/WebServer.cpp | 23 +- Grbl_Esp32/src/WebUI/WebSettings.cpp | 34 +-- 30 files changed, 411 insertions(+), 414 deletions(-) create mode 100644 Grbl_Esp32/src/Machines/TMC2209_4x.h delete mode 100644 Grbl_Esp32/src/Machines/template.h create mode 100644 Grbl_Esp32/src/Regex.cpp create mode 100644 Grbl_Esp32/src/Regex.h diff --git a/Grbl_Esp32/src/Config.h b/Grbl_Esp32/src/Config.h index f22e88aa..2feece69 100644 --- a/Grbl_Esp32/src/Config.h +++ b/Grbl_Esp32/src/Config.h @@ -47,7 +47,7 @@ Some features should not be changed. See notes below. // that the machine file might choose to undefine. // Note: HOMING_CYCLES are now settings -#define SUPPORT_TASK_CORE 1 // Reference: CONFIG_ARDUINO_RUNNING_CORE = 1 +#define SUPPORT_TASK_CORE 1 // Reference: CONFIG_ARDUINO_RUNNING_CORE = 1 // 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. @@ -87,8 +87,6 @@ const int MAX_N_AXIS = 6; # define LIMIT_MASK B0 #endif -#define GRBL_MSG_LEVEL MsgLevel::Info // what level of [MSG:....] do you want to see 0=all off - // Serial baud rate // OK to change, but the ESP32 boot text is 115200, so you will not see that is your // serial monitor, sender, etc uses a different value than 115200 diff --git a/Grbl_Esp32/src/GCode.cpp b/Grbl_Esp32/src/GCode.cpp index b1a7a079..94ea3237 100644 --- a/Grbl_Esp32/src/GCode.cpp +++ b/Grbl_Esp32/src/GCode.cpp @@ -1401,10 +1401,11 @@ Error gc_execute_line(char* line, uint8_t client) { if ((gc_block.modal.io_control == IoControl::DigitalOnSync) || (gc_block.modal.io_control == IoControl::DigitalOffSync) || (gc_block.modal.io_control == IoControl::DigitalOnImmediate) || (gc_block.modal.io_control == IoControl::DigitalOffImmediate)) { if (gc_block.values.p < MaxUserDigitalPin) { - if (!sys_io_control( - bit((int)gc_block.values.p), - (gc_block.modal.io_control == IoControl::DigitalOnSync) || (gc_block.modal.io_control == IoControl::DigitalOnImmediate), - (gc_block.modal.io_control == IoControl::DigitalOnSync) || (gc_block.modal.io_control == IoControl::DigitalOffSync))) { + if ((gc_block.modal.io_control == IoControl::DigitalOnSync) || (gc_block.modal.io_control == IoControl::DigitalOffSync)) { + protocol_buffer_synchronize(); + } + bool turnOn = gc_block.modal.io_control == IoControl::DigitalOnSync || gc_block.modal.io_control == IoControl::DigitalOnImmediate; + if (!sys_set_digital((int)gc_block.values.p, turnOn)) { FAIL(Error::PParamMaxExceeded); } } else { @@ -1414,8 +1415,12 @@ Error gc_execute_line(char* line, uint8_t client) { if ((gc_block.modal.io_control == IoControl::SetAnalogSync) || (gc_block.modal.io_control == IoControl::SetAnalogImmediate)) { if (gc_block.values.e < MaxUserDigitalPin) { gc_block.values.q = constrain(gc_block.values.q, 0.0, 100.0); // force into valid range - if (!sys_pwm_control(bit((int)gc_block.values.e), gc_block.values.q, (gc_block.modal.io_control == IoControl::SetAnalogSync))) + if (gc_block.modal.io_control == IoControl::SetAnalogSync) { + protocol_buffer_synchronize(); + } + if (!sys_set_analog((int)gc_block.values.e, gc_block.values.q)) { FAIL(Error::PParamMaxExceeded); + } } else { FAIL(Error::PParamMaxExceeded); } diff --git a/Grbl_Esp32/src/Grbl.h b/Grbl_Esp32/src/Grbl.h index 93c3f1e6..f42b4b85 100644 --- a/Grbl_Esp32/src/Grbl.h +++ b/Grbl_Esp32/src/Grbl.h @@ -23,7 +23,7 @@ // Grbl versioning system const char* const GRBL_VERSION = "1.3a"; -const char* const GRBL_VERSION_BUILD = "20201212"; +const char* const GRBL_VERSION_BUILD = "20210203"; //#include #include diff --git a/Grbl_Esp32/src/Machines/TMC2209_4x.h b/Grbl_Esp32/src/Machines/TMC2209_4x.h new file mode 100644 index 00000000..004b351b --- /dev/null +++ b/Grbl_Esp32/src/Machines/TMC2209_4x.h @@ -0,0 +1,89 @@ +#pragma once +// clang-format off + +/* + TMC2209_4x.h + https://github.com/FYSETC/FYSETC-E4 + + 2020-12-29 B. Dring + + This is a machine definition file to use the FYSTEC E4 3D Printer controller + This is a 4 motor controller. This is setup for XYZA, but XYYZ, could also be used. + There are 5 inputs + The controller has outputs for a Fan, Hotbed and Extruder. There are mapped to + spindle, mist and flood coolant to drive an external relay. + + 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_ESP32. If not, see . +*/ + +#define MACHINE_NAME "TMC2209 4x Controller" + +#define N_AXIS 4 + +#define TRINAMIC_UART_RUN_MODE TrinamicUartMode :: StealthChop +#define TRINAMIC_UART_HOMING_MODE TrinamicUartMode :: StallGuard + +#define TMC_UART UART_NUM_1 +#define TMC_UART_RX GPIO_NUM_21 +#define TMC_UART_TX GPIO_NUM_22 + +#define X_TRINAMIC_DRIVER 2209 +#define X_STEP_PIN GPIO_NUM_26 +#define X_DIRECTION_PIN GPIO_NUM_27 +#define X_RSENSE TMC2209_RSENSE_DEFAULT +#define X_DRIVER_ADDRESS 0 +#define DEFAULT_X_MICROSTEPS 16 + +#define Y_TRINAMIC_DRIVER 2209 +#define Y_STEP_PIN GPIO_NUM_33 +#define Y_DIRECTION_PIN GPIO_NUM_32 +#define Y_RSENSE TMC2209_RSENSE_DEFAULT +#define Y_DRIVER_ADDRESS 1 +#define DEFAULT_Y_MICROSTEPS 16 + +#define Z_TRINAMIC_DRIVER 2209 +#define Z_STEP_PIN GPIO_NUM_2 +#define Z_DIRECTION_PIN GPIO_NUM_4 +#define Z_RSENSE TMC2209_RSENSE_DEFAULT +#define Z_DRIVER_ADDRESS 2 +#define DEFAULT_Z_MICROSTEPS 16 + +#define A_TRINAMIC_DRIVER 2209 +#define A_STEP_PIN GPIO_NUM_16 +#define A_DIRECTION_PIN GPIO_NUM_17 +#define A_RSENSE TMC2209_RSENSE_DEFAULT +#define A_DRIVER_ADDRESS 3 +#define DEFAULT_A_MICROSTEPS 16 + +#define X_LIMIT_PIN GPIO_NUM_36 +#define Y_LIMIT_PIN GPIO_NUM_39 +#define Z_LIMIT_PIN GPIO_NUM_34 +#define PROBE_PIN GPIO_NUM_35 + +// OK to comment out to use pin for other features +#define STEPPERS_DISABLE_PIN GPIO_NUM_25 + + +// https://github.com/bdring/6-Pack_CNC_Controller/wiki/4x-5V-Buffered-Output-Module +// https://github.com/bdring/6-Pack_CNC_Controller/wiki/Quad-MOSFET-Module +#define USER_DIGITAL_PIN_0 GPIO_NUM_14 // M62 M63 +#define USER_DIGITAL_PIN_1 GPIO_NUM_13 // M62 M63 +#define USER_DIGITAL_PIN_2 GPIO_NUM_15 // M62 M63 +#define USER_DIGITAL_PIN_3 GPIO_NUM_12 // M62 M63 + + +// ===================== defaults ====================== +// https://github.com/bdring/Grbl_Esp32/wiki/Setting-Defaults + +#define DEFAULT_INVERT_PROBE_PIN 1 diff --git a/Grbl_Esp32/src/Machines/template.h b/Grbl_Esp32/src/Machines/template.h deleted file mode 100644 index 7672d31f..00000000 --- a/Grbl_Esp32/src/Machines/template.h +++ /dev/null @@ -1,233 +0,0 @@ -#pragma once -// clang-format off - -/* - template.h - Part of Grbl_ESP32 - - Template for a machine configuration file. - - 2020 - Mitch Bradley - - 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_ESP32. If not, see . -*/ - -// This contains a long list of things that might possibly be -// configured. Most machines - especially simple cartesian machines -// that use stepper motors - will only need to define a few of the -// options herein, often just the pin assignments. - -// Pin assignments depend on how the ESP32 is connected to -// the external machine. Typically the ESP32 module plugs into -// an adapter board that wires specific ESP32 GPIO pins to -// other connectors on the board, such as Pololu sockets for -// stepper drivers or connectors for external drivers, limit -// pins, spindle control, etc. This file describes how those -// GPIO pins are wired to those other connectors. - -// Some machines might choose to use an adapter board in a -// non-standard way, for example a 3-axis board might have axes -// labeled XYZ, but the machine might have only 2 axes one of which is -// driven by two ganged motors. In that case, you would need -// a custom version of this file that assigns the pins differently -// from the adapter board labels. - -// In addition to pin assignments, many other aspects of Grbl -// can be configured, such as spindle speeds, special motor -// types like servos and unipolars, homing order, default values -// for $$ settings, etc. A detailed list of such options is -// given below. - -// Furthermore, it is possible to implement special complex -// behavior in custom C++ code, for non-Cartesian machines, -// unusual homing cycles, etc. See the Special Features section -// below for additional instructions. - -// === Machine Name -// Change TEMPLATE to some name of your own choosing. That name -// will be shown in a Grbl startup message to identify your -// configuration. - -#define MACHINE_NAME "TEMPLATE" - -// If your machine requires custom code as described below in -// Special Features, you must copy Custom/custom_code_template.cpp -// to a new name like Custom/my_custom_code.cpp, implement the -// functions therein, and enable its use by defining: -// #define CUSTOM_CODE_FILENAME "Custom/my_custom_code.cpp" - -// === Number of axes - -// You can set the number of axes that the machine supports -// by defining N_AXIS. If you do not define it, 3 will be -// used. The value must be at least 3, even if your machine -// has fewer axes. -// #define N_AXIS 4 - - -// == Pin Assignments - -// Step and direction pins; these must be output-capable pins, -// specifically ESP32 GPIO numbers 0..31 -// #define X_STEP_PIN GPIO_NUM_12 -// #define X_DIRECTION_PIN GPIO_NUM_14 -// #define Y_STEP_PIN GPIO_NUM_26 -// #define Y_DIRECTION_PIN GPIO_NUM_15 -// #define Z_STEP_PIN GPIO_NUM_27 -// #define Z_DIRECTION_PIN GPIO_NUM_33 - -// #define X_LIMIT_PIN GPIO_NUM_17 -// #define Y_LIMIT_PIN GPIO_NUM_4 -// #define Z_LIMIT_PIN GPIO_NUM_16 - -// Common enable for all steppers. If it is okay to leave -// your drivers enabled at all times, you can leave -// STEPPERS_DISABLE_PIN undefined and use the pin for something else. -// #define STEPPERS_DISABLE_PIN GPIO_NUM_13 - -// Pins for controlling various aspects of the machine. If your -// machine does not support one of these features, you can leave -// the corresponding pin undefined. - -// #define SPINDLE_OUTPUT_PIN GPIO_NUM_2 // labeled SpinPWM -// #define SPINDLE_ENABLE_PIN GPIO_NUM_22 // labeled SpinEnbl -// #define COOLANT_MIST_PIN GPIO_NUM_21 // labeled Mist -// #define COOLANT_FLOOD_PIN GPIO_NUM_25 // labeled Flood -// #define PROBE_PIN GPIO_NUM_32 // labeled Probe - -// Input pins for various functions. If the corresponding pin is not defined, -// the function will not be available. - -// CONTROL_SAFETY_DOOR_PIN shuts off the machine when a door is opened -// or some other unsafe condition exists. -// #define CONTROL_SAFETY_DOOR_PIN GPIO_NUM_35 // labeled Door, needs external pullup - -// RESET, FEED_HOLD, and CYCLE_START can control GCode execution at -// the push of a button. - -// #define CONTROL_RESET_PIN GPIO_NUM_34 // labeled Reset, needs external pullup -// #define CONTROL_FEED_HOLD_PIN GPIO_NUM_36 // labeled Hold, needs external pullup -// #define CONTROL_CYCLE_START_PIN GPIO_NUM_39 // labeled Start, needs external pullup - -// === Ganging -// If you need to use two motors on one axis, you can "gang" the motors by -// defining a second pin to control the other motor on the axis. For example: - -// #define Y2_STEP_PIN GPIO_NUM_27 /* labeled Z */ -// #define Y2_DIRECTION_PIN GPIO_NUM_33 /* labeled Z */ - -// === Servos -// To use a servo motor on an axis, do not define step and direction -// pins for that axis, but instead include a block like this: - -// #define SERVO_Z_PIN GPIO_NUM_22 - -// === Homing cycles -// Set them using $Homing/Cycle0= optionally up to $Homing/Cycle5= - -// === Default settings -// Grbl has many run-time settings that the user can changed by -// commands like $110=2000 . Their values are stored in non-volatile -// storage so they persist after the controller has been powered down. -// Those settings have default values that are used if the user -// has not altered them, or if the settings are explicitly reset -// to the default values wth $RST=$. -// -// The default values are established in defaults.h, but you -// can override any one of them by definining it here, for example: - -//#define DEFAULT_INVERT_LIMIT_PINS 1 -//#define DEFAULT_REPORT_INCHES 1 - -// === Control Pins - -// If some of the control pin switches are normally closed -// (the default is normally open), you can invert some of them -// with INVERT_CONTROL_PIN_MASK. The bits in the mask are -// Cycle Start, Feed Hold, Reset, Safety Door. To use a -// normally open switch on Reset, you would say -// #define INVERT_CONTROL_PIN_MASK B1101 - -// If your control pins do not have adequate hardware signal -// conditioning, you can define these to use software to -// reduce false triggering. -// #define ENABLE_CONTROL_SW_DEBOUNCE // Default disabled. Uncomment to enable. -// #define CONTROL_SW_DEBOUNCE_PERIOD 32 // in milliseconds default 32 microseconds - - -// Grbl_ESP32 use the ESP32's special RMT (IR remote control) hardware -// engine to achieve more precise high step rates than can be done -// in software. That feature is enabled by default, but there are -// some machines that might not want to use it, such as machines that -// do not use ordinary stepper motors. To turn it off, do this: -// #undef USE_RMT_STEPS - -// === Special Features -// Grbl_ESP32 can support non-Cartesian machines and some other -// scenarios that cannot be handled by choosing from a set of -// predefined selections. Instead they require machine-specific -// C++ code functions. There are callouts in the core code for -// such code, guarded by ifdefs that enable calling the individual -// functions. custom_code_template.cpp describes the functions -// that you can implement. The ifdef guards are described below: -// -// USE_CUSTOM_HOMING enables the user_defined_homing(uint8_t cycle_mask) function -// that can implement an arbitrary homing sequence. -// #define USE_CUSTOM_HOMING - -// USE_KINEMATICS enables the functions inverse_kinematics(), -// kinematics_pre_homing(), and kinematics_post_homing(), -// so non-Cartesian machines can be implemented. -// #define USE_KINEMATICS - -// USE_FWD_KINEMATICS enables the forward_kinematics() function -// that converts motor positions in non-Cartesian coordinate -// systems back to Cartesian form, for status reports. -//#define USE_FWD_KINEMATICS - -// USE_TOOL_CHANGE enables the user_tool_change() function -// that implements custom tool change procedures. -// #define USE_TOOL_CHANGE - -// Any one of MACRO_BUTTON_0_PIN, MACRO_BUTTON_1_PIN, and MACRO_BUTTON_2_PIN -// enables the user_defined_macro(number) function which -// implements custom behavior at the press of a button -// #define MACRO_BUTTON_0_PIN - -// USE_M30 enables the user_m30() function which implements -// custom behavior when a GCode programs stops at the end -// #define USE_M30 - -// USE_TRIAMINIC enables a suite of functions that are defined -// in grbl_triaminic.cpp, allowing the use of Triaminic stepper -// drivers that require software configuration at startup. -// There are several options that control the details of such -// drivers; inspect the code in grbl_triaminic.cpp to see them. -// #define USE_TRIAMINIC -// #define X_TRIAMINIC -// #define X_DRIVER_TMC2209 -// #define TRIAMINIC_DAISY_CHAIN - -// USE_MACHINE_TRINAMIC_INIT enables the machine_triaminic_setup() -// function that replaces the normal setup of Triaminic drivers. -// It could, for, example, setup StallGuard or other special modes. -// #define USE_MACHINE_TRINAMIC_INIT - - -// === Grbl behavior options -// There are quite a few options that control aspects of Grbl that -// are not specific to particular machines. They are listed and -// described in config.h after it includes the file machine.h. -// Normally you would not need to change them, but if you do, -// it will be necessary to make the change in config.h diff --git a/Grbl_Esp32/src/MotionControl.cpp b/Grbl_Esp32/src/MotionControl.cpp index 74b53d26..954009a1 100644 --- a/Grbl_Esp32/src/MotionControl.cpp +++ b/Grbl_Esp32/src/MotionControl.cpp @@ -505,11 +505,11 @@ void mc_reset() { coolant_stop(); // turn off all User I/O immediately - sys_io_control(0xFF, LOW, false); - sys_pwm_control(0xFF, 0, false); + sys_digital_all_off(); + sys_analog_all_off(); #ifdef ENABLE_SD_CARD // do we need to stop a running SD job? - if (get_sd_state(false) == SDCARD_BUSY_PRINTING) { + if (get_sd_state(false) == SDState::BusyPrinting) { //Report print stopped report_feedback_message(Message::SdFileQuit); closeFile(); diff --git a/Grbl_Esp32/src/Motors/RcServo.cpp b/Grbl_Esp32/src/Motors/RcServo.cpp index 4d9a6dd7..2eefbfc2 100644 --- a/Grbl_Esp32/src/Motors/RcServo.cpp +++ b/Grbl_Esp32/src/Motors/RcServo.cpp @@ -42,6 +42,9 @@ namespace Motors { sprintf(setting_cal_max, "%c/RcServo/Cal/Max", report_get_axis_letter(_axis_index)); // rc_servo_cal_max = new FloatSetting(EXTENDED, WG, NULL, setting_cal_max, 1.0, 0.5, 2.0); + rc_servo_cal_min->load(); + rc_servo_cal_max->load(); + read_settings(); _channel_num = sys_get_next_PWM_chan_num(); ledcSetup(_channel_num, SERVO_PULSE_FREQ, SERVO_PULSE_RES_BITS); diff --git a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp index 26229dd2..16e658b8 100644 --- a/Grbl_Esp32/src/Motors/TrinamicDriver.cpp +++ b/Grbl_Esp32/src/Motors/TrinamicDriver.cpp @@ -258,7 +258,7 @@ namespace Motors { tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0)); tmcstepper->sfilt(1); tmcstepper->diag1_stall(true); // stallguard i/o is on diag1 - tmcstepper->sgt(axis_settings[_axis_index]->stallguard->get()); + tmcstepper->sgt(constrain(axis_settings[_axis_index]->stallguard->get(), -64, 63)); break; default: grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "TRINAMIC_MODE_UNDEFINED"); @@ -286,7 +286,7 @@ namespace Motors { tmcstepper->stallguard(), tmcstepper->sg_result(), feedrate, - axis_settings[_axis_index]->stallguard->get()); + constrain(axis_settings[_axis_index]->stallguard->get(), -64, 63)); TMC2130_n ::DRV_STATUS_t status { 0 }; // a useful struct to access the bits. status.sr = tmcstepper->DRV_STATUS(); diff --git a/Grbl_Esp32/src/Motors/TrinamicUartDriver.h b/Grbl_Esp32/src/Motors/TrinamicUartDriver.h index 3fb6e7cd..ef489ae1 100644 --- a/Grbl_Esp32/src/Motors/TrinamicUartDriver.h +++ b/Grbl_Esp32/src/Motors/TrinamicUartDriver.h @@ -98,7 +98,7 @@ namespace Motors { private: uint32_t calc_tstep(float speed, float percent); //TODO: see if this is useful/used. - TMC2208Stepper* tmcstepper; // all other driver types are subclasses of this one + TMC2209Stepper* tmcstepper; // all other driver types are subclasses of this one TrinamicUartMode _homing_mode; uint16_t _driver_part_number; // example: use 2209 for TMC2209 float _r_sense; diff --git a/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp b/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp index e930a848..f2498505 100644 --- a/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp +++ b/Grbl_Esp32/src/Motors/TrinamicUartDriverClass.cpp @@ -7,6 +7,9 @@ 2020 - The Ant Team 2020 - Bart Dring + TMC2209 Datasheet + https://www.trinamic.com/fileadmin/assets/Products/ICs_Documents/TMC2209_Datasheet_V103.pdf + 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 @@ -27,6 +30,8 @@ HardwareSerial tmc_serial(TMC_UART); namespace Motors { + TrinamicUartDriver* TrinamicUartDriver::List = NULL; // a static ist of all drivers for stallguard reporting + /* HW Serial Constructor. */ TrinamicUartDriver::TrinamicUartDriver( uint8_t axis_index, uint8_t step_pin, uint8_t dir_pin, uint8_t disable_pin, uint16_t driver_part_number, float r_sense, uint8_t addr) : @@ -40,13 +45,13 @@ namespace Motors { tmc_serial.begin(115200, SERIAL_8N1, TMC_UART_RX, TMC_UART_TX); tmc_serial.setRxBufferSize(128); hw_serial_init(); + + link = List; + List = this; } void TrinamicUartDriver::hw_serial_init() { - if (_driver_part_number == 2208) - // TMC 2208 does not use address, this field is 0 - tmcstepper = new TMC2208Stepper(&tmc_serial, _r_sense); - else if (_driver_part_number == 2209) + if (_driver_part_number == 2209) tmcstepper = new TMC2209Stepper(&tmc_serial, _r_sense, addr); else { grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unsupported Trinamic motor p/n:%d", _driver_part_number); @@ -73,6 +78,20 @@ namespace Motors { read_settings(); set_mode(false); } + + // After initializing all of the TMC drivers, create a task to + // display StallGuard data. List == this for the final instance. + if (List == this) { + xTaskCreatePinnedToCore(readSgTask, // task + "readSgTask", // name for task + 4096, // size of task stack + NULL, // parameters + 1, // priority + NULL, + SUPPORT_TASK_CORE // must run the task on same core + // core + ); + } } /* @@ -192,38 +211,27 @@ namespace Motors { if (newMode == _mode) { return; } + _mode = newMode; switch (_mode) { case TrinamicUartMode ::StealthChop: - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "StealthChop"); - // tmcstepper->en_pwm_mode(true); //TODO: check if this is present in TMC2208/09 + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "StealthChop"); tmcstepper->en_spreadCycle(false); tmcstepper->pwm_autoscale(true); - // if (_driver_part_number == 2209) { - // tmcstepper->diag1_stall(false); //TODO: check the equivalent in TMC2209 - // } break; case TrinamicUartMode ::CoolStep: - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Coolstep"); + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Coolstep"); // tmcstepper->en_pwm_mode(false); //TODO: check if this is present in TMC2208/09 tmcstepper->en_spreadCycle(true); tmcstepper->pwm_autoscale(false); - if (_driver_part_number == 2209) { - // tmcstepper->TCOOLTHRS(NORMAL_TCOOLTHRS); // when to turn on coolstep //TODO: add this solving compilation issue. - // tmcstepper->THIGH(NORMAL_THIGH); //TODO: this does not exist in TMC2208/09. verify and eventually remove. - } break; case TrinamicUartMode ::StallGuard: //TODO: check all configurations for stallguard - //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Stallguard"); - // tmcstepper->en_pwm_mode(false); //TODO: check if this is present in TMC2208/09 + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Stallguard"); tmcstepper->en_spreadCycle(false); tmcstepper->pwm_autoscale(false); - // tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0)); - // tmcstepper->THIGH(calc_tstep(homing_feed_rate->get(), 60.0)); - // tmcstepper->sfilt(1); - // tmcstepper->diag1_stall(true); // stallguard i/o is on diag1 - // tmcstepper->sgt(axis_settings[_axis_index]->stallguard->get()); + tmcstepper->TCOOLTHRS(calc_tstep(homing_feed_rate->get(), 150.0)); + tmcstepper->SGTHRS(constrain(axis_settings[_axis_index]->stallguard->get(),0,255)); break; default: grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Unknown Trinamic mode:d", _mode); @@ -246,10 +254,9 @@ namespace Motors { grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, - "%s Stallguard %d SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d", + "%s SG_Val: %04d Rate: %05.0f mm/min SG_Setting:%d", reportAxisNameMsg(_axis_index, _dual_axis_index), - 0, // tmcstepper->stallguard(), // TODO: add this again solving the compilation issues - 0, // tmcstepper->sg_result(), + tmcstepper->SG_RESULT(), // tmcstepper->sg_result(), feedrate, axis_settings[_axis_index]->stallguard->get()); @@ -261,13 +268,6 @@ namespace Motors { report_short_to_ground(status); report_over_temp(status); report_short_to_ps(status); - - // grbl_msg_sendf(CLIENT_SERIAL, - // MsgLevel::Info, - // "%s Status Register %08x GSTAT %02x", - // reportAxisNameMsg(_axis_index, _dual_axis_index), - // status.sr, - // tmcstepper->GSTAT()); } // calculate a tstep from a rate @@ -367,4 +367,31 @@ namespace Motors { return false; // no error } + // Prints StallGuard data that is useful for tuning. + void TrinamicUartDriver::readSgTask(void* pvParameters) { + TickType_t xLastWakeTime; + const TickType_t xreadSg = 200; // in ticks (typically ms) + auto n_axis = number_axis->get(); + + xLastWakeTime = xTaskGetTickCount(); // Initialise the xLastWakeTime variable with the current time. + while (true) { // don't ever return from this or the task dies + if (stallguard_debug_mask->get() != 0) { + if (sys.state == State::Cycle || sys.state == State::Homing || sys.state == State::Jog) { + for (TrinamicUartDriver* p = List; p; p = p->link) { + if (bitnum_istrue(stallguard_debug_mask->get(), p->_axis_index)) { + //grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "SG:%d", stallguard_debug_mask->get()); + p->debug_message(); + } + } + } // sys.state + } // if mask + + vTaskDelayUntil(&xLastWakeTime, xreadSg); + + static UBaseType_t uxHighWaterMark = 0; +#ifdef DEBUG_TASK_STACK + reportTaskStackSize(uxHighWaterMark); +#endif + } + } } \ No newline at end of file diff --git a/Grbl_Esp32/src/Probe.cpp b/Grbl_Esp32/src/Probe.cpp index 661c2d84..dcb57e64 100644 --- a/Grbl_Esp32/src/Probe.cpp +++ b/Grbl_Esp32/src/Probe.cpp @@ -50,7 +50,7 @@ void set_probe_direction(bool is_away) { // Returns the probe pin state. Triggered = true. Called by gcode parser and probe state monitor. bool probe_get_state() { - return digitalRead(PROBE_PIN) ^ probe_invert->get(); + return (PROBE_PIN == UNDEFINED_PIN) ? false : digitalRead(PROBE_PIN) ^ probe_invert->get(); } // Monitors probe pin state and records the system position when detected. Called by the diff --git a/Grbl_Esp32/src/ProcessSettings.cpp b/Grbl_Esp32/src/ProcessSettings.cpp index a6831713..05b765ec 100644 --- a/Grbl_Esp32/src/ProcessSettings.cpp +++ b/Grbl_Esp32/src/ProcessSettings.cpp @@ -1,5 +1,6 @@ #include "Grbl.h" #include +#include "Regex.h" // WG Readable and writable as guest // WU Readable and writable as user and admin @@ -420,19 +421,6 @@ Error motor_disable(const char* value, WebUI::AuthenticationLevel auth_level, We return Error::Ok; } -static bool anyState() { - return false; -} -static bool idleOrJog() { - return sys.state != State::Idle && sys.state != State::Jog; -} -bool idleOrAlarm() { - return sys.state != State::Idle && sys.state != State::Alarm; -} -static bool notCycleOrHold() { - return sys.state == State::Cycle && sys.state == State::Hold; -} - // Commands use the same syntax as Settings, but instead of setting or // displaying a persistent value, a command causes some action to occur. // That action could be anything, from displaying a run-time parameter @@ -565,19 +553,13 @@ Error do_command_or_setting(const char* key, char* value, WebUI::AuthenticationL Error retval = Error::InvalidStatement; if (!value) { auto lcKey = String(key); - // We allow the key string to begin with *, which we remove. - // This lets us look at X axis settings with $*x. - // $x by itself is the disable alarm lock command - if (lcKey.startsWith("*")) { - lcKey.remove(0, 1); - } lcKey.toLowerCase(); bool found = false; for (Setting* s = Setting::List; s; s = s->next()) { auto lcTest = String(s->getName()); lcTest.toLowerCase(); - if (lcTest.indexOf(lcKey) >= 0) { + if (regexMatch(lcKey.c_str(), lcTest.c_str())) { const char* displayValue = auth_failed(s, value, auth_level) ? "" : s->getStringValue(); show_setting(s->getName(), displayValue, NULL, out); found = true; diff --git a/Grbl_Esp32/src/Regex.cpp b/Grbl_Esp32/src/Regex.cpp new file mode 100644 index 00000000..7f942ccc --- /dev/null +++ b/Grbl_Esp32/src/Regex.cpp @@ -0,0 +1,60 @@ +// Simple regular expression matcher from Rob Pike per +// https://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html + +// c matches any literal character c +// ^ matches the beginning of the input string +// $ matches the end of the input string +// * matches zero or more occurrences of any character + +// The code therein has been reformatted into the style used in this +// project while replacing ints used as flags by bools. The regex +// syntax was changed by omitting '.' and making '*' equivalent to +// ".*". This regular expression matcher is for matching setting +// names, where arbitrary repetion of literal characters is +// unlikely. Literal character repetition is most useful for +// skipping whitespace, which does not occur in setting names. The +// "bare * wildcard" is similar to filename wildcarding in many shells +// and CLIs. + +static bool matchHere(const char* regexp, const char* text); + +// matchStar - search for *regexp at beginning of text +static bool matchStar(const char* regexp, const char* text) { + do { + if (matchHere(regexp, text)) { + return true; + } + } while (*text++ != '\0'); + return false; +} + +// matchHere - search for regex at beginning of text +static bool matchHere(const char* regexp, const char* text) { + if (regexp[0] == '\0') { + return true; + } + if (regexp[0] == '*') { + return matchStar(regexp + 1, text); + } + if (regexp[0] == '$' && regexp[1] == '\0') { + return *text == '\0'; + } + if (*text != '\0' && (regexp[0] == *text)) { + return matchHere(++regexp, ++text); + } + return false; +} + +// match - search for regular expression anywhere in text +// Returns true if text contains the regular expression regexp +bool regexMatch(const char* regexp, const char* text) { + if (regexp[0] == '^') { + return matchHere(++regexp, text); + } + do { + if (matchHere(regexp, text)) { + return true; + } + } while (*text++ != '\0'); + return false; +} diff --git a/Grbl_Esp32/src/Regex.h b/Grbl_Esp32/src/Regex.h new file mode 100644 index 00000000..9c0c5d13 --- /dev/null +++ b/Grbl_Esp32/src/Regex.h @@ -0,0 +1,5 @@ +// Simple regular expression matcher. +// See Regex.cpp for attribution, description and discussion + +// Returns true if text contains the regular expression regexp +bool regexMatch(const char* regexp, const char* text); diff --git a/Grbl_Esp32/src/Report.cpp b/Grbl_Esp32/src/Report.cpp index 33c53c11..da8b5316 100644 --- a/Grbl_Esp32/src/Report.cpp +++ b/Grbl_Esp32/src/Report.cpp @@ -111,9 +111,13 @@ void grbl_msg_sendf(uint8_t client, MsgLevel level, const char* format, ...) { if (client == CLIENT_INPUT) { return; } - if (level > GRBL_MSG_LEVEL) { - return; + + if (message_level != NULL) { // might be null before messages are setup + if (level > static_cast(message_level->get())) { + return; + } } + char loc_buf[100]; char* temp = loc_buf; va_list arg; @@ -222,7 +226,7 @@ void report_status_message(Error status_code, uint8_t client) { switch (status_code) { case Error::Ok: // Error::Ok #ifdef ENABLE_SD_CARD - if (get_sd_state(false) == SDCARD_BUSY_PRINTING) { + if (get_sd_state(false) == SDState::BusyPrinting) { SD_ready_next = true; // flag so system_execute_line() will send the next line } else { grbl_send(client, "ok\r\n"); @@ -234,7 +238,7 @@ void report_status_message(Error status_code, uint8_t client) { default: #ifdef ENABLE_SD_CARD // do we need to stop a running SD job? - if (get_sd_state(false) == SDCARD_BUSY_PRINTING) { + if (get_sd_state(false) == SDState::BusyPrinting) { if (status_code == Error::GcodeUnsupportedCommand) { 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()); @@ -837,7 +841,7 @@ void report_realtime_status(uint8_t client) { } #endif #ifdef ENABLE_SD_CARD - if (get_sd_state(false) == SDCARD_BUSY_PRINTING) { + if (get_sd_state(false) == SDState::BusyPrinting) { sprintf(temp, "|SD:%4.2f,", sd_report_perc_complete()); strcat(status, temp); sd_get_current_filename(temp); diff --git a/Grbl_Esp32/src/Report.h b/Grbl_Esp32/src/Report.h index 5b128b5d..2ffcecee 100644 --- a/Grbl_Esp32/src/Report.h +++ b/Grbl_Esp32/src/Report.h @@ -52,8 +52,8 @@ enum class Message : uint8_t { #define CLIENT_ALL 0xFF #define CLIENT_COUNT 5 // total number of client types regardless if they are used -enum class MsgLevel : uint8_t { - None = 0, // set GRBL_MSG_LEVEL in config.h to the level you want to see +enum class MsgLevel : int8_t { // Use $Message/Level + None = 0, Error = 1, Warning = 2, Info = 3, @@ -128,4 +128,4 @@ char* reportAxisLimitsMsg(uint8_t axis); char* reportAxisNameMsg(uint8_t axis); char* reportAxisNameMsg(uint8_t axis, uint8_t dual_axis); -void reportTaskStackSize(UBaseType_t& saved); +void reportTaskStackSize(UBaseType_t& saved); diff --git a/Grbl_Esp32/src/SDCard.cpp b/Grbl_Esp32/src/SDCard.cpp index 2a6fab21..32dd95ef 100644 --- a/Grbl_Esp32/src/SDCard.cpp +++ b/Grbl_Esp32/src/SDCard.cpp @@ -67,7 +67,7 @@ boolean openFile(fs::FS& fs, const char* path) { //report_status_message(Error::SdFailedRead, CLIENT_SERIAL); return false; } - set_sd_state(SDCARD_BUSY_PRINTING); + set_sd_state(SDState::BusyPrinting); SD_ready_next = false; // this will get set to true when Grbl issues "ok" message sd_current_line_number = 0; return true; @@ -77,7 +77,7 @@ boolean closeFile() { if (!myFile) { return false; } - set_sd_state(SDCARD_IDLE); + set_sd_state(SDState::Idle); SD_ready_next = false; sd_current_line_number = 0; myFile.close(); @@ -125,19 +125,19 @@ uint32_t sd_get_current_line_number() { return sd_current_line_number; } -uint8_t sd_state = SDCARD_IDLE; +SDState sd_state = SDState::Idle; -uint8_t get_sd_state(bool refresh) { +SDState get_sd_state(bool refresh) { if (SDCARD_DET_PIN != UNDEFINED_PIN) { if (digitalRead(SDCARD_DET_PIN) != SDCARD_DET_VAL) { - sd_state = SDCARD_NOT_PRESENT; + sd_state = SDState::NotPresent; return sd_state; //no need to go further if SD detect is not correct } } //if busy doing something return state - if (!((sd_state == SDCARD_NOT_PRESENT) || (sd_state == SDCARD_IDLE))) { + if (!((sd_state == SDState::NotPresent) || (sd_state == SDState::Idle))) { return sd_state; } if (!refresh) { @@ -146,19 +146,19 @@ uint8_t get_sd_state(bool refresh) { //SD is idle or not detected, let see if still the case SD.end(); - sd_state = SDCARD_NOT_PRESENT; + sd_state = SDState::NotPresent; //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, "/sd", 2)) { if (SD.cardSize() > 0) { - sd_state = SDCARD_IDLE; + sd_state = SDState::Idle; } } return sd_state; } -uint8_t set_sd_state(uint8_t flag) { - sd_state = flag; +SDState set_sd_state(SDState state) { + sd_state = state; return sd_state; } diff --git a/Grbl_Esp32/src/SDCard.h b/Grbl_Esp32/src/SDCard.h index 298fbdec..a680e0a4 100644 --- a/Grbl_Esp32/src/SDCard.h +++ b/Grbl_Esp32/src/SDCard.h @@ -23,19 +23,22 @@ //#define SDCARD_DET_PIN -1 const int SDCARD_DET_VAL = 0; // for now, CD is close to ground -const int SDCARD_IDLE = 0; -const int SDCARD_NOT_PRESENT = 1; -const int SDCARD_BUSY_PRINTING = 2; -const int SDCARD_BUSY_UPLOADING = 4; -const int SDCARD_BUSY_PARSING = 8; +enum class SDState : uint8_t { + Idle = 0, + NotPresent = 1, + Busy = 2, + BusyPrinting = 2, + BusyUploading = 3, + BusyParsing = 4, +}; extern bool SD_ready_next; // Grbl has processed a line and is waiting for another extern uint8_t SD_client; extern WebUI::AuthenticationLevel SD_auth_level; //bool sd_mount(); -uint8_t get_sd_state(bool refresh); -uint8_t set_sd_state(uint8_t flag); +SDState get_sd_state(bool refresh); +SDState set_sd_state(SDState state); void listDir(fs::FS& fs, const char* dirname, uint8_t levels, uint8_t client); boolean openFile(fs::FS& fs, const char* path); boolean closeFile(); diff --git a/Grbl_Esp32/src/Serial.cpp b/Grbl_Esp32/src/Serial.cpp index 5e5e2549..9a4b9e4e 100644 --- a/Grbl_Esp32/src/Serial.cpp +++ b/Grbl_Esp32/src/Serial.cpp @@ -159,7 +159,7 @@ void serialCheckTask(void* pvParameters) { if (is_realtime_command(data)) { execute_realtime_command(static_cast(data), client); } else { - if (get_sd_state(false) == SDCARD_IDLE) { + if (get_sd_state(false) < SDState::Busy) { vTaskEnterCritical(&myMutex); client_buffer[client].write(data); vTaskExitCritical(&myMutex); diff --git a/Grbl_Esp32/src/Settings.cpp b/Grbl_Esp32/src/Settings.cpp index 678a43c0..686b409d 100644 --- a/Grbl_Esp32/src/Settings.cpp +++ b/Grbl_Esp32/src/Settings.cpp @@ -3,6 +3,19 @@ #include #include +bool anyState() { + return false; +} +bool idleOrJog() { + return sys.state != State::Idle && sys.state != State::Jog; +} +bool idleOrAlarm() { + return sys.state != State::Idle && sys.state != State::Alarm; +} +bool notCycleOrHold() { + return sys.state == State::Cycle && sys.state == State::Hold; +} + Word::Word(type_t type, permissions_t permissions, const char* description, const char* grblName, const char* fullName) : _description(description), _grblName(grblName), _fullName(fullName), _type(type), _permissions(permissions) {} diff --git a/Grbl_Esp32/src/Settings.h b/Grbl_Esp32/src/Settings.h index e206b307..26d99ad1 100644 --- a/Grbl_Esp32/src/Settings.h +++ b/Grbl_Esp32/src/Settings.h @@ -76,12 +76,13 @@ class Command : public Word { protected: Command* link; // linked list of setting objects bool (*_cmdChecker)(); + public: static Command* List; Command* next() { return link; } ~Command() {} - Command(const char* description, type_t type, permissions_t permissions, const char* grblName, const char* fullName, bool (*cmcChecker)()); + Command(const char* description, type_t type, permissions_t permissions, const char* grblName, const char* fullName, bool (*cmdChecker)()); // The default implementation of addWebui() does nothing. // Derived classes may override it to do something. @@ -444,7 +445,10 @@ public: AxisSettings(const char* axisName); }; +extern bool idleOrJog(); extern bool idleOrAlarm(); +extern bool anyState(); +extern bool notCycleOrHold(); class WebCommand : public Command { private: @@ -457,12 +461,19 @@ public: permissions_t permissions, const char* grblName, const char* name, - Error (*action)(char*, WebUI::AuthenticationLevel)) : - // At some point we might want to be more subtle, but for now we block - // all web commands in Cycle and Hold states, to avoid crashing a - // running job. - Command(description, type, permissions, grblName, name, idleOrAlarm), + Error (*action)(char*, WebUI::AuthenticationLevel), + bool (*cmdChecker)()) : + Command(description, type, permissions, grblName, name, cmdChecker), _action(action) {} + + WebCommand(const char* description, + type_t type, + permissions_t permissions, + const char* grblName, + const char* name, + Error (*action)(char*, WebUI::AuthenticationLevel)) : + WebCommand(description, type, permissions, grblName, name, action, idleOrAlarm) {} + Error action(char* value, WebUI::AuthenticationLevel auth_level, WebUI::ESPResponseStream* response); }; diff --git a/Grbl_Esp32/src/SettingsDefinitions.cpp b/Grbl_Esp32/src/SettingsDefinitions.cpp index 02115c00..bde5e97f 100644 --- a/Grbl_Esp32/src/SettingsDefinitions.cpp +++ b/Grbl_Esp32/src/SettingsDefinitions.cpp @@ -57,6 +57,8 @@ IntSetting* spindle_pwm_bit_precision; EnumSetting* spindle_type; +EnumSetting* message_level; + enum_opt_t spindleTypes = { // clang-format off { "NONE", int8_t(SpindleType::NONE) }, @@ -71,6 +73,17 @@ enum_opt_t spindleTypes = { // clang-format on }; +enum_opt_t messageLevels = { + // clang-format off + { "None", int8_t(MsgLevel::None) }, + { "Error", int8_t(MsgLevel::Error) }, + { "Warning", int8_t(MsgLevel::Warning) }, + { "Info", int8_t(MsgLevel::Info) }, + { "Debug", int8_t(MsgLevel::Debug) }, + { "Verbose", int8_t(MsgLevel::Verbose) }, + // clang-format on +}; + AxisSettings* x_axis_settings; AxisSettings* y_axis_settings; AxisSettings* z_axis_settings; @@ -256,16 +269,16 @@ void make_settings() { b_axis_settings = axis_settings[B_AXIS]; c_axis_settings = axis_settings[C_AXIS]; for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) { - def = &axis_defaults[axis]; - auto setting = - new IntSetting(EXTENDED, WG, makeGrblName(axis, 170), makename(def->name, "StallGuard"), def->stallguard, -64, 63, postMotorSetting); + def = &axis_defaults[axis]; + auto setting = new IntSetting( + EXTENDED, WG, makeGrblName(axis, 170), makename(def->name, "StallGuard"), def->stallguard, -64, 255, postMotorSetting); setting->setAxis(axis); axis_settings[axis]->stallguard = setting; } for (axis = MAX_N_AXIS - 1; axis >= 0; axis--) { - def = &axis_defaults[axis]; - auto setting = - new IntSetting(EXTENDED, WG, makeGrblName(axis, 160), makename(def->name, "Microsteps"), def->microsteps, 0, 256, postMotorSetting); + def = &axis_defaults[axis]; + auto setting = new IntSetting( + EXTENDED, WG, makeGrblName(axis, 160), makename(def->name, "Microsteps"), def->microsteps, 0, 256, postMotorSetting); setting->setAxis(axis); axis_settings[axis]->microsteps = setting; } @@ -395,4 +408,6 @@ void make_settings() { user_macro2 = new StringSetting(EXTENDED, WG, NULL, "User/Macro2", DEFAULT_USER_MACRO2); user_macro1 = new StringSetting(EXTENDED, WG, NULL, "User/Macro1", DEFAULT_USER_MACRO1); user_macro0 = new StringSetting(EXTENDED, WG, NULL, "User/Macro0", DEFAULT_USER_MACRO0); + + message_level = +new EnumSetting(NULL, EXTENDED, WG, NULL, "Message/Level", static_cast(MsgLevel::Info), &messageLevels, NULL); } diff --git a/Grbl_Esp32/src/SettingsDefinitions.h b/Grbl_Esp32/src/SettingsDefinitions.h index 7315637a..95c229e9 100644 --- a/Grbl_Esp32/src/SettingsDefinitions.h +++ b/Grbl_Esp32/src/SettingsDefinitions.h @@ -65,3 +65,5 @@ extern StringSetting* user_macro0; extern StringSetting* user_macro1; extern StringSetting* user_macro2; extern StringSetting* user_macro3; + +extern EnumSetting* message_level; diff --git a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp index 23477494..ba364768 100644 --- a/Grbl_Esp32/src/Spindles/PWMSpindle.cpp +++ b/Grbl_Esp32/src/Spindles/PWMSpindle.cpp @@ -20,6 +20,7 @@ */ #include "PWMSpindle.h" +#include "soc/ledc_struct.h" // ======================= PWM ============================== /* @@ -222,7 +223,15 @@ namespace Spindles { duty = (1 << _pwm_precision) - duty; } - ledcWrite(_pwm_chan_num, duty); + //ledcWrite(_pwm_chan_num, duty); + + // This was ledcWrite, but this is called from an ISR + // and ledcWrite uses RTOS features not compatible with ISRs + LEDC.channel_group[0].channel[0].duty.duty = duty << 4; + bool on = !!duty; + LEDC.channel_group[0].channel[0].conf0.sig_out_en = on; + LEDC.channel_group[0].channel[0].conf1.duty_start = on; + LEDC.channel_group[0].channel[0].conf0.clk_en = on; } void PWM::set_enable_pin(bool enable) { diff --git a/Grbl_Esp32/src/System.cpp b/Grbl_Esp32/src/System.cpp index 6b21702c..60a399b2 100644 --- a/Grbl_Esp32/src/System.cpp +++ b/Grbl_Esp32/src/System.cpp @@ -47,18 +47,22 @@ void system_ini() { // Renamed from system_init() due to conflict with esp32 fi // setup control inputs #ifdef CONTROL_SAFETY_DOOR_PIN + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Door switch on pin %s", pinName(CONTROL_SAFETY_DOOR_PIN).c_str()); pinMode(CONTROL_SAFETY_DOOR_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(CONTROL_SAFETY_DOOR_PIN), isr_control_inputs, CHANGE); #endif #ifdef CONTROL_RESET_PIN + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Reset switch on pin %s", pinName(CONTROL_RESET_PIN).c_str()); pinMode(CONTROL_RESET_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(CONTROL_RESET_PIN), isr_control_inputs, CHANGE); #endif #ifdef CONTROL_FEED_HOLD_PIN + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Hold switch on pin %s", pinName(CONTROL_FEED_HOLD_PIN).c_str()); pinMode(CONTROL_FEED_HOLD_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(CONTROL_FEED_HOLD_PIN), isr_control_inputs, CHANGE); #endif #ifdef CONTROL_CYCLE_START_PIN + grbl_msg_sendf(CLIENT_SERIAL, MsgLevel::Info, "Start switch on pin %s", pinName(CONTROL_CYCLE_START_PIN).c_str()); pinMode(CONTROL_CYCLE_START_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(CONTROL_CYCLE_START_PIN), isr_control_inputs, CHANGE); #endif @@ -267,36 +271,29 @@ void system_exec_control_pin(ControlPins pins) { } } -// 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 -bool sys_io_control(uint8_t io_num_mask, bool turnOn, bool synchronized) { - bool cmd_ok = true; - if (synchronized) - protocol_buffer_synchronize(); - +void sys_digital_all_off() { for (uint8_t io_num = 0; io_num < MaxUserDigitalPin; io_num++) { - if (io_num_mask & bit(io_num)) { - if (!myDigitalOutputs[io_num]->set_level(turnOn)) - cmd_ok = false; - } + myDigitalOutputs[io_num]->set_level(LOW); } - return cmd_ok; } -// 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 -bool sys_pwm_control(uint8_t io_num_mask, float duty, bool synchronized) { - bool cmd_ok = true; - if (synchronized) - protocol_buffer_synchronize(); +// io_num is the virtual digital pin# +bool sys_set_digital(uint8_t io_num, bool turnOn) { + return myDigitalOutputs[io_num]->set_level(turnOn); +} +// Turn off all analog outputs +void sys_analog_all_off() { for (uint8_t io_num = 0; io_num < MaxUserDigitalPin; io_num++) { - if (io_num_mask & bit(io_num)) { - if (!myAnalogOutputs[io_num]->set_level(duty)) - cmd_ok = false; - } + myAnalogOutputs[io_num]->set_level(0); } - return cmd_ok; +} + +// io_num is the virtual analog pin# +bool sys_set_analog(uint8_t io_num, float percent) { + auto analog = myAnalogOutputs[io_num]; + uint32_t numerator = percent / 100.0 * analog->denominator(); + return analog->set_level(numerator); } /* diff --git a/Grbl_Esp32/src/System.h b/Grbl_Esp32/src/System.h index 6803f7e2..d955f01e 100644 --- a/Grbl_Esp32/src/System.h +++ b/Grbl_Esp32/src/System.h @@ -170,8 +170,9 @@ void system_convert_array_steps_to_mpos(float* position, int32_t* steps); void controlCheckTask(void* pvParameters); void system_exec_control_pin(ControlPins pins); -bool sys_io_control(uint8_t io_num_mask, bool turnOn, bool synchronized); -bool sys_pwm_control(uint8_t io_num_mask, float duty, bool synchronized); +bool sys_set_digital(uint8_t io_num, bool turnOn); +void sys_digital_all_off(); +bool sys_set_analog(uint8_t io_num, float percent); +void sys_analog_all_off(); -int8_t sys_get_next_PWM_chan_num(); -uint8_t sys_calc_pwm_precision(uint32_t freq); +int8_t sys_get_next_PWM_chan_num(); diff --git a/Grbl_Esp32/src/UserOutput.cpp b/Grbl_Esp32/src/UserOutput.cpp index 6a1f9ce0..05b856dd 100644 --- a/Grbl_Esp32/src/UserOutput.cpp +++ b/Grbl_Esp32/src/UserOutput.cpp @@ -64,8 +64,17 @@ namespace UserOutput { if (pin == UNDEFINED_PIN) return; - // determine the highest bit precision allowed by frequency - _resolution_bits = sys_calc_pwm_precision(_pwm_frequency); + // determine the highest resolution (number of precision bits) allowed by frequency + + uint32_t apb_frequency = getApbFrequency(); + + // increase the precision (bits) until it exceeds allow by frequency the max or is 16 + _resolution_bits = 0; + while ((1 << _resolution_bits) < (apb_frequency / _pwm_frequency) && _resolution_bits <= 16) { + ++_resolution_bits; + } + // _resolution_bits is now just barely too high, so drop it down one + --_resolution_bits; init(); } @@ -89,9 +98,7 @@ namespace UserOutput { } // returns true if able to set value - bool AnalogOutput::set_level(float percent) { - float duty; - + bool AnalogOutput::set_level(uint32_t numerator) { // look for errors, but ignore if turning off to prevent mask turn off from generating errors if (_pin == UNDEFINED_PIN) { return false; @@ -102,15 +109,14 @@ namespace UserOutput { return false; } - if (_current_value == percent) + if (_current_value == numerator) { return true; + } - _current_value = percent; + _current_value = numerator; - duty = (percent / 100.0) * (1 << _resolution_bits); - - ledcWrite(_pwm_channel, duty); + ledcWrite(_pwm_channel, numerator); return true; } -} \ No newline at end of file +} diff --git a/Grbl_Esp32/src/UserOutput.h b/Grbl_Esp32/src/UserOutput.h index 10a7ea30..ca0d6e2c 100644 --- a/Grbl_Esp32/src/UserOutput.h +++ b/Grbl_Esp32/src/UserOutput.h @@ -41,17 +41,18 @@ namespace UserOutput { public: AnalogOutput(); AnalogOutput(uint8_t number, uint8_t pin, float pwm_frequency); - bool set_level(float percent); + bool set_level(uint32_t numerator); + uint32_t denominator() { return 1UL << _resolution_bits; }; protected: void init(); void config_message(); - uint8_t _number = UNDEFINED_PIN; - uint8_t _pin = UNDEFINED_PIN; - uint8_t _pwm_channel = -1; // -1 means invalid or not setup - float _pwm_frequency; - uint8_t _resolution_bits; - float _current_value; + uint8_t _number = UNDEFINED_PIN; + uint8_t _pin = UNDEFINED_PIN; + uint8_t _pwm_channel = -1; // -1 means invalid or not setup + float _pwm_frequency; + uint8_t _resolution_bits; + uint32_t _current_value; }; -} \ No newline at end of file +} diff --git a/Grbl_Esp32/src/WebUI/WebServer.cpp b/Grbl_Esp32/src/WebUI/WebServer.cpp index d58a8b7c..97b2ca34 100644 --- a/Grbl_Esp32/src/WebUI/WebServer.cpp +++ b/Grbl_Esp32/src/WebUI/WebServer.cpp @@ -1221,16 +1221,15 @@ namespace WebUI { bool list_files = true; uint64_t totalspace = 0; uint64_t usedspace = 0; - int8_t state = get_sd_state(true); - if (state != SDCARD_IDLE) { + SDState state = get_sd_state(true); + if (state != SDState::Idle) { String status = "{\"status\":\""; - if(state == SDCARD_NOT_PRESENT)status+="No SD Card\"}"; - else status+="Busy\"}"; + status += state == SDState::NotPresent ? "No SD Card\"}" : "Busy\"}"; _webserver->sendHeader("Cache-Control", "no-cache"); _webserver->send(200, "application/json", status); return; } - set_sd_state(SDCARD_BUSY_PARSING); + set_sd_state(SDState::BusyParsing); //get current path if (_webserver->hasArg("path")) { @@ -1400,7 +1399,7 @@ namespace WebUI { _webserver->sendHeader("Cache-Control", "no-cache"); _webserver->send(200, "application/json", jsonfile); _upload_status = UploadStatusType::NONE; - set_sd_state(SDCARD_IDLE); + set_sd_state(SDState::Idle); SD.end(); } @@ -1427,13 +1426,13 @@ namespace WebUI { filename = "/" + upload.filename; } //check if SD Card is available - if (get_sd_state(true) != SDCARD_IDLE) { + if (get_sd_state(true) != SDState::Idle) { _upload_status = UploadStatusType::FAILED; grbl_send(CLIENT_ALL, "[MSG:Upload cancelled]\r\n"); pushError(ESP_ERROR_UPLOAD_CANCELLED, "Upload cancelled"); } else { - set_sd_state(SDCARD_BUSY_UPLOADING); + set_sd_state(SDState::BusyUploading); //delete file on SD Card if already present if (SD.exists(filename)) { SD.remove(filename); @@ -1468,7 +1467,7 @@ namespace WebUI { //************** } else if (upload.status == UPLOAD_FILE_WRITE) { vTaskDelay(1 / portTICK_RATE_MS); - if (sdUploadFile && (_upload_status == UploadStatusType::ONGOING) && (get_sd_state(false) == SDCARD_BUSY_UPLOADING)) { + if (sdUploadFile && (_upload_status == UploadStatusType::ONGOING) && (get_sd_state(false) == SDState::BusyUploading)) { //no error write post data if (upload.currentSize != sdUploadFile.write(upload.buf, upload.currentSize)) { _upload_status = UploadStatusType::FAILED; @@ -1506,7 +1505,7 @@ namespace WebUI { } if (_upload_status == UploadStatusType::ONGOING) { _upload_status = UploadStatusType::SUCCESSFUL; - set_sd_state(SDCARD_IDLE); + set_sd_state(SDState::Idle); } else { _upload_status = UploadStatusType::FAILED; pushError(ESP_ERROR_UPLOAD, "Upload error"); @@ -1514,7 +1513,7 @@ namespace WebUI { } else { //Upload cancelled _upload_status = UploadStatusType::FAILED; - set_sd_state(SDCARD_IDLE); + set_sd_state(SDState::Idle); grbl_send(CLIENT_ALL, "[MSG:Upload failed]\r\n"); if (sdUploadFile) { sdUploadFile.close(); @@ -1532,7 +1531,7 @@ namespace WebUI { if (SD.exists(filename)) { SD.remove(filename); } - set_sd_state(SDCARD_IDLE); + set_sd_state(SDState::Idle); } COMMANDS::wait(0); } diff --git a/Grbl_Esp32/src/WebUI/WebSettings.cpp b/Grbl_Esp32/src/WebUI/WebSettings.cpp index cec830b9..2a47176d 100644 --- a/Grbl_Esp32/src/WebUI/WebSettings.cpp +++ b/Grbl_Esp32/src/WebUI/WebSettings.cpp @@ -682,9 +682,9 @@ namespace WebUI { if (path[0] != '/') { path = "/" + path; } - int8_t state = get_sd_state(true); - if (state != SDCARD_IDLE) { - if (state == SDCARD_NOT_PRESENT) { + SDState state = get_sd_state(true); + if (state != SDState::Idle) { + if (state == SDState::NotPresent) { webPrintln("No SD Card"); return Error::SdFailedMount; } else { @@ -752,9 +752,9 @@ namespace WebUI { webPrintln("Missing file name!"); return Error::InvalidValue; } - int8_t state = get_sd_state(true); - if (state != SDCARD_IDLE) { - webPrintln((state == SDCARD_NOT_PRESENT) ? "No SD card" : "Busy"); + SDState state = get_sd_state(true); + if (state != SDState::Idle) { + webPrintln((state == SDState::NotPresent) ? "No SD card" : "Busy"); return Error::Ok; } String path = parameter; @@ -784,9 +784,9 @@ namespace WebUI { } static Error listSDFiles(char* parameter, AuthenticationLevel auth_level) { // ESP210 - int8_t state = get_sd_state(true); - if (state != SDCARD_IDLE) { - if (state == SDCARD_NOT_PRESENT) { + SDState state = get_sd_state(true); + if (state != SDState::Idle) { + if (state == SDState::NotPresent) { webPrintln("No SD Card"); return Error::SdFailedMount; } else { @@ -857,10 +857,10 @@ namespace WebUI { const char* resp = "No SD card"; #ifdef ENABLE_SD_CARD switch (get_sd_state(true)) { - case SDCARD_IDLE: + case SDState::Idle: resp = "SD card detected"; break; - case SDCARD_NOT_PRESENT: + case SDState::NotPresent: resp = "No SD card"; break; default: @@ -868,7 +868,7 @@ namespace WebUI { } #else resp = "SD card not enabled"; -#endif +#endif webPrintln(resp); return Error::Ok; } @@ -1025,7 +1025,7 @@ namespace WebUI { // WU - need user or admin password to set // WA - need admin password to set #ifdef WEB_COMMON - new WebCommand(NULL, WEBCMD, WG, "ESP800", "Firmware/Info", showFwInfo); + new WebCommand(NULL, WEBCMD, WG, "ESP800", "Firmware/Info", showFwInfo, anyState); new WebCommand(NULL, WEBCMD, WU, "ESP720", "LocalFS/Size", SPIFFSSize); new WebCommand("FORMAT", WEBCMD, WA, "ESP710", "LocalFS/Format", formatSpiffs); new WebCommand("path", WEBCMD, WU, "ESP701", "LocalFS/Show", showLocalFile); @@ -1043,14 +1043,14 @@ namespace WebUI { #endif #ifdef WEB_COMMON new WebCommand("RESTART", WEBCMD, WA, "ESP444", "System/Control", setSystemMode); - new WebCommand(NULL, WEBCMD, WU, "ESP420", "System/Stats", showSysStats); + new WebCommand(NULL, WEBCMD, WU, "ESP420", "System/Stats", showSysStats, anyState); #endif #ifdef ENABLE_WIFI new WebCommand(NULL, WEBCMD, WU, "ESP410", "WiFi/ListAPs", listAPs); #endif #ifdef WEB_COMMON new WebCommand("P=position T=type V=value", WEBCMD, WA, "ESP401", "WebUI/Set", setWebSetting); - new WebCommand(NULL, WEBCMD, WU, "ESP400", "WebUI/List", listSettings); + new WebCommand(NULL, WEBCMD, WU, "ESP400", "WebUI/List", listSettings, anyState); #endif #ifdef ENABLE_SD_CARD new WebCommand("path", WEBCMD, WU, "ESP221", "SD/Show", showSDFile); @@ -1067,8 +1067,8 @@ namespace WebUI { new WebCommand("IP=ipaddress MSK=netmask GW=gateway", WEBCMD, WA, "ESP103", "Sta/Setup", showSetStaParams); #endif #ifdef WEB_COMMON - new WebCommand(NULL, WEBCMD, WG, "ESP0", "WebUI/Help", showWebHelp); - new WebCommand(NULL, WEBCMD, WG, "ESP", "WebUI/Help", showWebHelp); + new WebCommand(NULL, WEBCMD, WG, "ESP0", "WebUI/Help", showWebHelp, anyState); + new WebCommand(NULL, WEBCMD, WG, "ESP", "WebUI/Help", showWebHelp, anyState); #endif // WebUI Settings // Standard WEBUI authentication is user+ to get, admin to set unless otherwise specified From 4cc14d1673a3eaaf9a9b5a4c4bfad661b5f2746f Mon Sep 17 00:00:00 2001 From: Jens Hauser <44340656+JensHauser@users.noreply.github.com> Date: Mon, 15 Feb 2021 21:12:40 +0100 Subject: [PATCH 2/4] Update README.md Slack -> Discord --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bf7b16b4..05c51250 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ The Wifi and WebUI is based on [this project.](https://github.com/luc-github/ESP ### Contribute -![](http://www.buildlog.net/blog/wp-content/uploads/2018/07/slack_hash_128.png) There is a slack channel for the development this project. Ask for an Invite +![](http://www.buildlog.net/blog/wp-content/uploads/2018/07/slack_hash_128.png) There is a Discord channel for the development this project. Ask for an invite ### FAQ From 0d2f7509a0b05500db0e457fbf54f5ce6cf420b7 Mon Sep 17 00:00:00 2001 From: Jens Hauser <44340656+JensHauser@users.noreply.github.com> Date: Mon, 15 Feb 2021 21:26:31 +0100 Subject: [PATCH 3/4] Updated with Discord logo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 05c51250..e6272c70 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ The Wifi and WebUI is based on [this project.](https://github.com/luc-github/ESP ### Contribute -![](http://www.buildlog.net/blog/wp-content/uploads/2018/07/slack_hash_128.png) There is a Discord channel for the development this project. Ask for an invite + There is a Discord channel for the development this project. Ask for an invite ### FAQ From 40fcdf45bce69b1e8e59a95415aa0237d492ea6f Mon Sep 17 00:00:00 2001 From: Jens Hauser <44340656+JensHauser@users.noreply.github.com> Date: Mon, 15 Feb 2021 21:28:49 +0100 Subject: [PATCH 4/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e6272c70..743a5d9f 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ The Wifi and WebUI is based on [this project.](https://github.com/luc-github/ESP ### Contribute - There is a Discord channel for the development this project. Ask for an invite + There is a Discord server for the development this project. Ask for an invite ### FAQ