diff --git a/FluidNC/data/config.yaml b/FluidNC/data/config.yaml new file mode 100644 index 000000000..27008cf42 --- /dev/null +++ b/FluidNC/data/config.yaml @@ -0,0 +1,156 @@ +board: None +name: Default (Test Drive no I/O) +meta: +stepping: + engine: RMT + idle_ms: 255 + pulse_us: 4 + dir_delay_us: 0 + disable_delay_us: 0 + segments: 12 + +spi: + miso_pin: NO_PIN + mosi_pin: NO_PIN + sck_pin: NO_PIN + +sdcard: + cs_pin: NO_PIN + card_detect_pin: NO_PIN + frequency_hz: 8000000 + +kinematics: + Cartesian: + +axes: + shared_stepper_disable_pin: NO_PIN + shared_stepper_reset_pin: NO_PIN + homing_runs: 2 + x: + steps_per_mm: 80.000000 + max_rate_mm_per_min: 1000.000000 + acceleration_mm_per_sec2: 25.000000 + max_travel_mm: 1000.000000 + soft_limits: false + motor0: + limit_neg_pin: NO_PIN + limit_pos_pin: NO_PIN + limit_all_pin: NO_PIN + hard_limits: false + pulloff_mm: 1.000000 + null_motor: + + y: + steps_per_mm: 80.000000 + max_rate_mm_per_min: 1000.000000 + acceleration_mm_per_sec2: 25.000000 + max_travel_mm: 1000.000000 + soft_limits: false + motor0: + limit_neg_pin: NO_PIN + limit_pos_pin: NO_PIN + limit_all_pin: NO_PIN + hard_limits: false + pulloff_mm: 1.000000 + null_motor: + + z: + steps_per_mm: 80.000000 + max_rate_mm_per_min: 1000.000000 + acceleration_mm_per_sec2: 25.000000 + max_travel_mm: 1000.000000 + soft_limits: false + motor0: + limit_neg_pin: NO_PIN + limit_pos_pin: NO_PIN + limit_all_pin: NO_PIN + hard_limits: false + pulloff_mm: 1.000000 + null_motor: + +control: + safety_door_pin: NO_PIN + reset_pin: NO_PIN + feed_hold_pin: NO_PIN + cycle_start_pin: NO_PIN + macro0_pin: NO_PIN + macro1_pin: NO_PIN + macro2_pin: NO_PIN + macro3_pin: NO_PIN + fault_pin: NO_PIN + estop_pin: NO_PIN + +coolant: + flood_pin: NO_PIN + mist_pin: NO_PIN + delay_ms: 0 + +probe: + pin: NO_PIN + toolsetter_pin: NO_PIN + check_mode_start: true + hard_stop: false + +macros: + startup_line0: + startup_line1: + Macro0: + Macro1: + Macro2: + Macro3: + after_homing: + after_reset: + after_unlock: + +start: + must_home: false + deactivate_parking: false + check_limits: true + +parking: + enable: false + axis: Z + target_mpos_mm: -5.000000 + rate_mm_per_min: 800.000000 + pullout_distance_mm: 5.000000 + pullout_rate_mm_per_min: 250.000000 + +user_outputs: + analog0_pin: NO_PIN + analog1_pin: NO_PIN + analog2_pin: NO_PIN + analog3_pin: NO_PIN + analog0_hz: 5000 + analog1_hz: 5000 + analog2_hz: 5000 + analog3_hz: 5000 + digital0_pin: NO_PIN + digital1_pin: NO_PIN + digital2_pin: NO_PIN + digital3_pin: NO_PIN + digital4_pin: NO_PIN + digital5_pin: NO_PIN + digital6_pin: NO_PIN + digital7_pin: NO_PIN + +user_inputs: + analog0_pin: NO_PIN + analog1_pin: NO_PIN + analog2_pin: NO_PIN + analog3_pin: NO_PIN + digital0_pin: NO_PIN + digital1_pin: NO_PIN + digital2_pin: NO_PIN + digital3_pin: NO_PIN + digital4_pin: NO_PIN + digital5_pin: NO_PIN + digital6_pin: NO_PIN + digital7_pin: NO_PIN + +arc_tolerance_mm: 0.002000 +junction_deviation_mm: 0.010000 +verbose_errors: true +report_inches: false +enable_parking_override_control: false +use_line_numbers: false +planner_blocks: 16 diff --git a/FluidNC/esp32/i2s_engine.c b/FluidNC/esp32/i2s_engine.c index 828cebe7e..6c27c316d 100644 --- a/FluidNC/esp32/i2s_engine.c +++ b/FluidNC/esp32/i2s_engine.c @@ -154,11 +154,10 @@ static int i2s_out_start() { static bool timer_running = false; +// i2s_out_delay() is used by synchronous_write(), to ensure that that +// the newly-written data has arrived at the shift register output void i2s_out_delay() { - // Depending on the timing, it may not be reflected immediately, - // so wait twice as long just in case. - uint32_t wait_counts = timer_running ? FIFO_THRESHOLD + FIFO_RELOAD : 2; - delay_us(i2s_frame_us * wait_counts); + delay_us((FIFO_LENGTH + FIFO_RELOAD) * (I2S_OUT_USEC_PER_PULSE / 2)); } void IRAM_ATTR i2s_out_write(pinnum_t pin, uint8_t val) { diff --git a/FluidNC/src/Channel.cpp b/FluidNC/src/Channel.cpp index 1d626beda..80cd8fd96 100644 --- a/FluidNC/src/Channel.cpp +++ b/FluidNC/src/Channel.cpp @@ -9,6 +9,7 @@ #include "Logging.h" #include "Job.h" #include +#include void Channel::flushRx() { _linelen = 0; @@ -328,7 +329,7 @@ void Channel::sendLine(MsgLevel level, const std::string& line) { } } -bool Channel::is_visible(const std::string& stem, const std::string& extension, bool isdir) { +bool Channel::is_visible(const std::string& stem, std::string extension, bool isdir) { if (stem.length() && stem[0] == '.') { // Exclude hidden files and directories return false; @@ -341,6 +342,9 @@ bool Channel::is_visible(const std::string& stem, const std::string& extension, return true; } + // Convert extension to canonical lower case format + std::transform(extension.begin(), extension.end(), extension.begin(), [](unsigned char c) { return std::tolower(c); }); + // common gcode extensions std::string_view extensions(".g .gc .gco .gcode .nc .ngc .ncc .txt .cnc .tap"); int pos = 0; diff --git a/FluidNC/src/Channel.h b/FluidNC/src/Channel.h index 2eae69485..0a3a6c703 100644 --- a/FluidNC/src/Channel.h +++ b/FluidNC/src/Channel.h @@ -137,7 +137,7 @@ class Channel : public Stream { return readBytes(buffer, length); } - virtual bool is_visible(const std::string& stem, const std::string& extension, bool isdir); + virtual bool is_visible(const std::string& stem, std::string extension, bool isdir); size_t timedReadBytes(uint8_t* buffer, size_t length, TickType_t timeout) { return timedReadBytes(reinterpret_cast(buffer), length, timeout); diff --git a/FluidNC/src/Control.cpp b/FluidNC/src/Control.cpp index e71cd8ab0..008fc46f2 100644 --- a/FluidNC/src/Control.cpp +++ b/FluidNC/src/Control.cpp @@ -42,6 +42,16 @@ std::string Control::report_status() { return ret; } +bool Control::pins_block_unlock() { + std::string blockers("FE"); // Fault, E-Stop block unlock and homing + for (auto pin : _pins) { + if (pin->get() && blockers.find(pin->letter()) != std::string::npos) { + return true; + } + } + return false; +} + bool Control::stuck() { for (auto pin : _pins) { if (pin->get()) { diff --git a/FluidNC/src/Control.h b/FluidNC/src/Control.h index 78cc386a0..470a732ec 100644 --- a/FluidNC/src/Control.h +++ b/FluidNC/src/Control.h @@ -22,6 +22,7 @@ class Control : public Configuration::Configurable { bool stuck(); bool safety_door_ajar(); + bool pins_block_unlock(); std::string report_status(); diff --git a/FluidNC/src/GCode.cpp b/FluidNC/src/GCode.cpp index 17e6e3bc0..0c1436ea8 100644 --- a/FluidNC/src/GCode.cpp +++ b/FluidNC/src/GCode.cpp @@ -64,7 +64,9 @@ gc_modal_t modal_defaults = { void gc_init() { // Reset parser state: + auto save_tlo = gc_state.tool_length_offset; // we want TLO to persist until reboot. memset(&gc_state, 0, sizeof(parser_state_t)); + gc_state.tool_length_offset = save_tlo; // Load default G54 coordinate system. gc_state.modal = modal_defaults; @@ -1603,7 +1605,7 @@ Error gc_execute_line(char* line) { // NOTE: Pass zero spindle speed for all restricted laser motions. if (!disableLaser) { pl_data->spindle_speed = gc_state.spindle_speed; // Record data for planner use. - } // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already. + } // else { pl_data->spindle_speed = 0.0; } // Initialized as zero already. // [5. Select tool ]: NOT SUPPORTED. Only tracks tool value. // [M6. Change tool ]: if (gc_block.modal.tool_change == ToolChange::Enable) { @@ -1627,9 +1629,9 @@ Error gc_execute_line(char* line) { } if (gc_block.modal.set_tool_number == SetToolNumber::Enable) { gc_state.selected_tool = gc_block.values.q; - bool stopped_spindle = false; // was spindle stopped via the change - bool new_spindle = false; // was the spindle changed - protocol_buffer_synchronize(); // wait for motion in buffer to finish + bool stopped_spindle = false; // was spindle stopped via the change + bool new_spindle = false; // was the spindle changed + protocol_buffer_synchronize(); // wait for motion in buffer to finish Spindles::Spindle::switchSpindle(gc_state.selected_tool, Spindles::SpindleFactory::objects(), spindle, stopped_spindle, new_spindle); if (stopped_spindle) { gc_block.modal.spindle = SpindleState::Disable; @@ -1786,10 +1788,10 @@ Error gc_execute_line(char* line) { switch (gc_block.non_modal_command) { case NonModal::SetCoordinateData: coords[coord_select]->set(coord_data); + gc_wco_changed(); // Update system coordinate system if currently active. if (gc_state.modal.coord_select == coord_select) { copyAxes(gc_state.coord_system, coord_data); - gc_wco_changed(); } break; case NonModal::GoHome0: diff --git a/FluidNC/src/ProcessSettings.cpp b/FluidNC/src/ProcessSettings.cpp index f080ac512..78a99edaf 100644 --- a/FluidNC/src/ProcessSettings.cpp +++ b/FluidNC/src/ProcessSettings.cpp @@ -34,8 +34,12 @@ // WU Readable and writable as user and admin // WA Readable as user and admin, writable as admin +static Error switchInchMM(const char* value, AuthenticationLevel auth_level, Channel& out); + static Error fakeMaxSpindleSpeed(const char* value, AuthenticationLevel auth_level, Channel& out); +static Error report_init_message_cmd(const char* value, AuthenticationLevel auth_level, Channel& out); + // If authentication is disabled, auth_level will be LEVEL_ADMIN static bool auth_failed(Word* w, const char* value, AuthenticationLevel auth_level) { permissions_t permissions = w->getPermissions(); @@ -193,9 +197,13 @@ static void show_settings(Channel& out, type_t type) { show_setting(s->getGrblName(), s->getCompatibleValue(), NULL, out); } } + // Print Report/Inches + switchInchMM(NULL, AuthenticationLevel::LEVEL_ADMIN, out); + // need this per issue #1036 fakeMaxSpindleSpeed(NULL, AuthenticationLevel::LEVEL_ADMIN, out); } + static Error report_normal_settings(const char* value, AuthenticationLevel auth_level, Channel& out) { show_settings(out, GRBL); // GRBL non-axis settings return Error::Ok; @@ -377,6 +385,10 @@ static Error cmd_log_verbose(const char* value, AuthenticationLevel auth_level, return Error::Ok; } static Error home(AxisMask axisMask, Channel& out) { + // see if blocking control switches are active + if (config->_control->pins_block_unlock()) { + return Error::CheckControlPins; + } if (axisMask != Machine::Homing::AllCycles) { // if not AllCycles we need to make sure the cycle is not prohibited // if there is a cycle it is the axis from $H auto n_axis = Axes::_numberAxis; @@ -705,6 +717,22 @@ static Error dump_config(const char* value, AuthenticationLevel auth_level, Chan return Error::Ok; } +static Error report_init_message_cmd(const char* value, AuthenticationLevel auth_level, Channel& out) { + report_init_message(out); + + return Error::Ok; +} + +static Error switchInchMM(const char* value, AuthenticationLevel auth_level, Channel& out) { + if (!value) { + log_stream(out, "$13=" << (config->_reportInches ? "1" : "0")); + } else { + config->_reportInches = ((value[0]=='1') ? true : false); + } + + return Error::Ok; +} + static Error fakeMaxSpindleSpeed(const char* value, AuthenticationLevel auth_level, Channel& out) { if (!value) { log_stream(out, "$30=" << spindle->maxSpeed()); @@ -837,9 +865,12 @@ void make_user_commands() { new UserCommand("RI", "Report/Interval", setReportInterval, anyState); + new UserCommand("13", "Report/Inches", switchInchMM, notIdleOrAlarm); new UserCommand("30", "FakeMaxSpindleSpeed", fakeMaxSpindleSpeed, notIdleOrAlarm); new UserCommand("32", "FakeLaserMode", fakeLaserMode, notIdleOrAlarm); + new UserCommand("GS", "GRBL/Show", report_init_message_cmd, notIdleOrAlarm); + new AsyncUserCommand("J", "Jog", doJog, notIdleOrJog); new AsyncUserCommand("G", "GCode/Modes", report_gcode, anyState); }; diff --git a/FluidNC/src/Protocol.cpp b/FluidNC/src/Protocol.cpp index 2f9325a8c..98548f5d5 100644 --- a/FluidNC/src/Protocol.cpp +++ b/FluidNC/src/Protocol.cpp @@ -484,16 +484,17 @@ static void protocol_do_alarm(void* alarmVoid) { static void protocol_start_holding() { if (!(sys.suspend.bit.motionCancel || sys.suspend.bit.jogCancel)) { // Block, if already holding. sys.step_control = {}; - if (!Stepper::update_plan_block_parameters()) { // Notify stepper module to recompute for hold deceleration. - sys.step_control.endMotion = true; - } + Stepper::update_plan_block_parameters(); sys.step_control.executeHold = true; // Initiate suspend state with active flag. } } static void protocol_cancel_jogging() { - if (!sys.suspend.bit.motionCancel) { - sys.suspend.bit.jogCancel = true; + if (!(sys.suspend.bit.motionCancel || sys.suspend.bit.jogCancel)) { // Block, if already holding. + sys.step_control = {}; + Stepper::update_plan_block_parameters(); + sys.step_control.executeHold = true; // Initiate suspend state with active flag. + sys.suspend.bit.jogCancel = true; } } @@ -525,7 +526,6 @@ void protocol_do_motion_cancel() { break; case State::Jog: - protocol_start_holding(); protocol_cancel_jogging(); // When jogging, we do not set motionCancel, hence return not break return; @@ -571,7 +571,6 @@ static void protocol_do_feedhold() { break; case State::Jog: - protocol_start_holding(); protocol_cancel_jogging(); return; // Do not change the state to Hold } @@ -623,7 +622,6 @@ static void protocol_do_safety_door() { protocol_start_holding(); break; case State::Jog: - protocol_start_holding(); protocol_cancel_jogging(); break; } diff --git a/FluidNC/src/SettingsDefinitions.cpp b/FluidNC/src/SettingsDefinitions.cpp index f17b0450a..e5b331820 100644 --- a/FluidNC/src/SettingsDefinitions.cpp +++ b/FluidNC/src/SettingsDefinitions.cpp @@ -116,4 +116,5 @@ void make_settings() { INT_PROXY("21", "Grbl/HardLimitsEnable", config._axes->hasHardLimits()) INT_PROXY("22", "Grbl/HomingCycleEnable", (bool)Axes::homingMask) INT_PROXY("23", "Grbl/HomingInvertMask", Homing::direction_mask) + INT_PROXY("32", "Grbl/LaserMode", spindle->isRateAdjusted()) } diff --git a/FluidNC/src/WebUI/WifiConfig.cpp b/FluidNC/src/WebUI/WifiConfig.cpp index f424e86c7..d1d1701a3 100644 --- a/FluidNC/src/WebUI/WifiConfig.cpp +++ b/FluidNC/src/WebUI/WifiConfig.cpp @@ -255,16 +255,16 @@ namespace WebUI { modeName = "???"; } - j.id_value_object("Phy Mode: ", modeName); - j.id_value_object("Channel: ", WiFi.channel()); + j.id_value_object("Phy Mode", modeName); + j.id_value_object("Channel", WiFi.channel()); tcpip_adapter_dhcp_status_t dhcp_status; tcpip_adapter_dhcpc_get_status(TCPIP_ADAPTER_IF_STA, &dhcp_status); - j.id_value_object("IP Mode: ", (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED ? "DHCP" : "Static")); - j.id_value_object("IP: ", IP_string(WiFi.localIP())); - j.id_value_object("Gateway: ", IP_string(WiFi.gatewayIP())); - j.id_value_object("Mask: ", IP_string(WiFi.subnetMask())); - j.id_value_object("DNS: ", IP_string(WiFi.dnsIP())); + j.id_value_object("IP Mode", (dhcp_status == TCPIP_ADAPTER_DHCP_STARTED ? "DHCP" : "Static")); + j.id_value_object("IP", IP_string(WiFi.localIP())); + j.id_value_object("Gateway", IP_string(WiFi.gatewayIP())); + j.id_value_object("Mask", IP_string(WiFi.subnetMask())); + j.id_value_object("DNS", IP_string(WiFi.dnsIP())); } //this is web command so connection => no command j.id_value_object("Disabled Mode", std::string("AP (") + WiFi.softAPmacAddress().c_str() + ")"); @@ -275,9 +275,9 @@ namespace WebUI { wifi_country_t country; esp_wifi_get_config(WIFI_IF_AP, &conf); esp_wifi_get_country(&country); - j.id_value_object("SSID: ", (const char*)conf.ap.ssid); - j.id_value_object("Visible: ", (conf.ap.ssid_hidden == 0 ? "Yes" : "No")); - j.id_value_object("Radio country set: ", + j.id_value_object("SSID", (const char*)conf.ap.ssid); + j.id_value_object("Visible", (conf.ap.ssid_hidden == 0 ? "Yes" : "No")); + j.id_value_object("Radio country set", std::string("") + country.cc[0] + country.cc[1] + " (channels " + std::to_string(country.schan) + "-" + std::to_string((country.schan + country.nchan - 1)) + ", max power " + std::to_string(country.max_tx_power) + "dBm)");