diff --git a/README.md b/README.md index cc87e2f..fe8f755 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,11 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20211117, see the [changelog](changelog.md) for details. -__NOTE:__ Drivers built with more than three axes configured \(`N_AXIS` > `3`\) will force a settings reset when upgraded. Backup and restore of settings is recommended for these. +Latest build date is 20211121, see the [changelog](changelog.md) for details. +__NOTE:__ A settings reset will be performed on an update for versions earlier than 20211121. Backup and restore of settings is recommended. +__IMPORTANT!__ A new setting has been introduced for ganged axes motors in version 20211121. +I have only bench tested this for a couple of drivers, correct function should be verified after updating by those who have more than three motors configured. +More details in the [changelog](changelog.md). --- @@ -80,4 +83,4 @@ List of Supported G-Codes: Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes. --- -2021-11-17 +2021-11-21 diff --git a/changelog.md b/changelog.md index 0ebfc52..0e3b614 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,34 @@ ## grblHAL changelog +Build 20211121: + +Core: + +* Added some data fields to the settings structures and modified a HAL API call signature. +Due to this settings and HAL version numbers has been increased to 21 and 9 respectively. +__NOTE:__ due to this settings will be reset to default values after an update. Backup and restore! +* Added `$8` setting for inverting direction signals for the second motor for ganged axes. +__NOTE:__ This setting is applied _after_ inversion is performed according to the `$3` setting. +__NOTE:__ I have only bench tested this for a couple of drivers, correct function should be verified after updating! +* Changed default value for `$4` stepper enable setting to invert all axes \(active low\). +* Added reason code \(flags\) to "Incompatible driver" message, delayed halt so other POS \(Power On Self-test\) messages is not lost. +* Some bug fixes in new ioports code. + +Plugins: + +* Updated _Bluetooth_, _Fans_, _Laser coolant_ and _Plasma_ plugins with settings for selecting aux port\(s\) to use. +__NOTE:__ Port settings are added under the _Aux ports_ setting group even when the plugin has its own setting group. +* Updated SD card plugin to support manual tool change on `M6` \(only available if the driver supports it\). + +Drivers: + +* Updated many for additional features in enhanced ioports API. +* Updated drivers supporting ganged axes for the new `$8` setting. +* iMRXT1062 \(Teensy 4\): Added full ioports support for MCP3221 I2C ADC. +* Some bug/regression fixes. + +--- + Build 20211117: Core: @@ -19,7 +48,7 @@ Drivers: * Updated many for define symbol changes (harmonization) and enhanced ioports API. * iMRXT1062 \(Teensy 4\): Fixed bugs, one was a typo and one slowed down max USB streaming rate. -* RP2040 \(Pi Pico\): Added support for SD card and ioports API for aux output pins on Pico CNC board. +* RP2040 \(Pi Pico\): Added support for SD card and ioports API for aux output pins on Pico CNC board. * STM32F3xx: Fixed typo and some compiler warnings. --- diff --git a/defaults.h b/defaults.h index 8b54fd4..5843f91 100644 --- a/defaults.h +++ b/defaults.h @@ -206,6 +206,9 @@ #ifndef DEFAULT_DIRECTION_INVERT_MASK #define DEFAULT_DIRECTION_INVERT_MASK 0 #endif +#ifndef DEFAULT_GANGED_DIRECTION_INVERT_MASK +#define DEFAULT_GANGED_DIRECTION_INVERT_MASK 0 +#endif #ifndef DEFAULT_STEPPER_IDLE_LOCK_TIME #define DEFAULT_STEPPER_IDLE_LOCK_TIME 25 #endif @@ -570,7 +573,7 @@ #endif #ifndef INVERT_ST_ENABLE_MASK -#define INVERT_ST_ENABLE_MASK 0 +#define INVERT_ST_ENABLE_MASK AXES_BITMASK #endif #ifndef INVERT_LIMIT_BIT_MASK diff --git a/gcode.c b/gcode.c index e5bb161..d41d780 100644 --- a/gcode.c +++ b/gcode.c @@ -2569,7 +2569,7 @@ status_code_t gc_execute_block(char *block) break; case 66: - sys.var5399 = hal.port.wait_on_input(gc_block.output_command.is_digital, gc_block.output_command.port, (wait_mode_t)gc_block.values.l, gc_block.values.q); + sys.var5399 = hal.port.wait_on_input((io_port_type_t)gc_block.output_command.is_digital, gc_block.output_command.port, (wait_mode_t)gc_block.values.l, gc_block.values.q); sys.report.m66result = On; break; diff --git a/grbl.h b/grbl.h index b3b7fd6..ac4d081 100644 --- a/grbl.h +++ b/grbl.h @@ -34,7 +34,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20211117 +#define GRBL_BUILD 20211121 // The following symbols are set here if not already set by the compiler or in config.h // Do NOT change here! diff --git a/grbllib.c b/grbllib.c index 82cb1d2..8a99fe3 100644 --- a/grbllib.c +++ b/grbllib.c @@ -50,9 +50,25 @@ #include "wall_plotter.h" #endif + +typedef union { + uint8_t ok; + struct { + uint8_t init :1, + setup :1, + spindle :1, + door :1, + amass :1, + pulse_delay :1, + linearization :1, + unused :1; + }; +} driver_startup_t; + struct system sys = {0}; //!< System global variable structure. grbl_t grbl; grbl_hal_t hal; +static driver_startup_t driver = { .ok = 0xFF }; #ifdef KINEMATICS_API @@ -90,6 +106,18 @@ static bool dummy_irq_claim (irq_type_t irq, uint_fast8_t id, irq_callback_ptr c return false; } +static void report_driver_error (sys_state_t state) +{ + char msg[40]; + + driver.ok = ~driver.ok; + strcpy(msg, "Fatal: Incompatible driver ("); + strcat(msg, uitoa(driver.ok)); + strcat(msg, ")"); + + report_message(msg, Message_Plain); +} + // main entry point int grbl_enter (void) @@ -97,7 +125,7 @@ int grbl_enter (void) assert(NVS_ADDR_PARAMETERS + N_CoordinateSystems * (sizeof(coord_data_t) + NVS_CRC_BYTES) < NVS_ADDR_STARTUP_BLOCK); assert(NVS_ADDR_STARTUP_BLOCK + N_STARTUP_LINE * (sizeof(stored_line_t) + NVS_CRC_BYTES) < NVS_ADDR_BUILD_INFO); - bool looping = true, driver_ok; + bool looping = true; // Clear all and set some core function pointers memset(&grbl, 0, sizeof(grbl_t)); @@ -138,7 +166,7 @@ int grbl_enter (void) #ifdef DEBUGOUT hal.debug_out = debug_out; // must be overridden by driver to have any effect #endif - driver_ok = driver_init(); + driver.init = driver_init(); #if COMPATIBILITY_LEVEL > 0 hal.stream.suspend_read = NULL; @@ -147,27 +175,27 @@ int grbl_enter (void) #ifndef ENABLE_SAFETY_DOOR_INPUT_PIN hal.signals_cap.safety_door_ajar = Off; #else - driver_ok &= hal.signals_cap.safety_door_ajar; + driver.door = hal.signals_cap.safety_door_ajar; #endif #ifdef BUFFER_NVSDATA nvs_buffer_init(); #endif - settings_init(); // Load Grbl settings from non-volatile storage + settings_init(); // Load settings from non-volatile storage memset(sys.position, 0, sizeof(sys.position)); // Clear machine position. // check and configure driver #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING - driver_ok = driver_ok && hal.driver_cap.amass_level >= MAX_AMASS_LEVEL; + driver.amass = hal.driver_cap.amass_level >= MAX_AMASS_LEVEL; hal.driver_cap.amass_level = MAX_AMASS_LEVEL; #else hal.driver_cap.amass_level = 0; #endif #ifdef DEFAULT_STEP_PULSE_DELAY - driver_ok = driver_ok & hal.driver_cap.step_pulse_delay; + driver.pulse_delay = hal.driver_cap.step_pulse_delay; #endif /* #if AXIS_N_SETTINGS > 4 @@ -176,19 +204,20 @@ int grbl_enter (void) */ sys.mpg_mode = false; - driver_ok = driver_ok && hal.driver_setup(&settings); + if(driver.ok == 0xFF) + driver.setup = hal.driver_setup(&settings); #ifdef ENABLE_SPINDLE_LINEARIZATION - driver_ok = driver_ok && hal.driver_cap.spindle_pwm_linearization; + driver.linearization = hal.driver_cap.spindle_pwm_linearization; #endif #ifdef SPINDLE_PWM_DIRECT - driver_ok = driver_ok && (!hal.driver_cap.variable_spindle || (hal.spindle.get_pwm != NULL && hal.spindle.update_pwm != NULL)); + driver.spindle = (!hal.driver_cap.variable_spindle || (hal.spindle.get_pwm != NULL && hal.spindle.update_pwm != NULL)); #endif - if(!driver_ok) { - hal.stream.write("grblHAL: incompatible driver" ASCII_EOL); - while(true); + if(driver.ok != 0xFF) { + sys.alarm = Alarm_SelftestFailed; + protocol_enqueue_rt_command(report_driver_error); } if(hal.get_position) @@ -202,7 +231,7 @@ int grbl_enter (void) wall_plotter_init(); #endif - sys.driver_started = true; + sys.driver_started = sys.alarm != Alarm_SelftestFailed; // "Wire" homing switches to limit switches if not provided by the driver. if(hal.homing.get_state == NULL) diff --git a/hal.h b/hal.h index 11eb520..71001b1 100644 --- a/hal.h +++ b/hal.h @@ -38,7 +38,7 @@ #include "ioports.h" #include "plugins.h" -#define HAL_VERSION 8 +#define HAL_VERSION 9 /// Bitmap flags for driver capabilities, to be set by driver in driver_init(), flags may be cleared after to switch off option. typedef union { @@ -369,9 +369,9 @@ typedef void (*stepper_output_step_ptr)(axes_signals_t step_outbits, axes_signal /*! \brief Pointer to function for getting which axes are configured for auto squaring. -\returns which axes are configured for auto squaring in an \a axes_signals_t union. +\returns which axes are configured for ganging or auto squaring in an \a axes_signals_t union. */ -typedef axes_signals_t (*stepper_get_auto_squared_ptr)(void); +typedef axes_signals_t (*stepper_get_ganged_ptr)(bool auto_squared); /*! \brief Pointer to callback function for outputting the next direction and step pulse signals. _Set by the core on startup._ @@ -388,7 +388,7 @@ typedef struct { stepper_cycles_per_tick_ptr cycles_per_tick; //!< Handler for setting the step pulse rate for the next motion segment. stepper_pulse_start_ptr pulse_start; //!< Handler for starting outputting direction signals and a step pulse. stepper_interrupt_callback_ptr interrupt_callback; //!< Callback for informing about the next step pulse to output. _Set by the core at startup._ - stepper_get_auto_squared_ptr get_auto_squared; //!< Optional handler getting which axes are configured for auto squaring. + stepper_get_ganged_ptr get_ganged; //!< Optional handler getting which axes are configured for ganging or auto squaring. stepper_output_step_ptr output_step; //!< Optional handler for outputting a single step pulse. _Experimental._ motor_iterator_ptr motor_iterator; //!< Optional handler iteration over motor vs. axis mappings. Required for the motors plugin (Trinamic drivers). } stepper_ptrs_t; @@ -437,7 +437,6 @@ typedef struct { probe_connected_toggle_ptr connected_toggle; //!< Optional handler for toggling probe connected status. } probe_ptrs_t; - /******************************* * Tool selection and change * *******************************/ diff --git a/ioports.c b/ioports.c index 03db6ce..3ffca84 100644 --- a/ioports.c +++ b/ioports.c @@ -38,7 +38,7 @@ static uint8_t ioports_count (io_port_type_t type, io_port_direction_t dir) // determine how many ports, including claimed ports, that are available do { - if((port = hal.port.get_pin_info(type, type, n_ports))) + if((port = hal.port.get_pin_info(type, dir, n_ports))) n_ports++; } while(port != NULL); @@ -88,16 +88,19 @@ bool ioport_claim (io_port_type_t type, io_port_direction_t dir, uint8_t *port, { bool ok = false; uint8_t n_ports = ioports_available(type, dir); + uint8_t base = type == Port_Digital + ? (dir == Port_Input ? Input_Aux0 : Output_Aux0) + : (dir == Port_Input ? Input_Aux0 : Output_Aux0); // TODO add analog ports? - if(hal.port.claim != 0) { + if(hal.port.claim != NULL) { - xbar_t *portinfo = NULL; + xbar_t *portinfo; if(n_ports > 0) do { n_ports--; portinfo = hal.port.get_pin_info(type, dir, n_ports); - if((ok = portinfo && !portinfo->mode.claimed && (portinfo->function - Output_Aux0) == *port)) { - hal.port.claim(type, dir, port, description); + if((ok = portinfo && !portinfo->mode.claimed && (portinfo->function - base) == *port)) { + ok = hal.port.claim(type, dir, port, description); break; } } while(n_ports && !ok); diff --git a/limits.c b/limits.c index c30a05a..6674a8e 100644 --- a/limits.c +++ b/limits.c @@ -470,8 +470,8 @@ bool limits_go_home (axes_signals_t cycle) axes_signals_t auto_square = {0}, auto_squared = {0}; - if(hal.stepper.get_auto_squared) - auto_squared = hal.stepper.get_auto_squared(); + if(hal.stepper.get_ganged) + auto_squared = hal.stepper.get_ganged(true); auto_squared.mask &= cycle.mask; diff --git a/motor_pins.h b/motor_pins.h index d2b089e..75f7684 100644 --- a/motor_pins.h +++ b/motor_pins.h @@ -33,6 +33,10 @@ #define SQUARING_ENABLED #endif +#if N_GANGED +#define GANGING_ENABLED +#endif + #if Z_GANGED #define Z_DOUBLED N_ABC_MOTORS #elif Y_GANGED diff --git a/plugins.h b/plugins.h index 41eb9c2..79afe72 100644 --- a/plugins.h +++ b/plugins.h @@ -76,6 +76,7 @@ typedef struct { uint16_t telnet_port; uint16_t websocket_port; uint16_t http_port; + uint16_t ftp_port; ip_mode_t ip_mode; network_services_t services; } network_settings_t; diff --git a/protocol.c b/protocol.c index 2a6cd39..dc3c9b1 100644 --- a/protocol.c +++ b/protocol.c @@ -86,6 +86,7 @@ bool protocol_enqueue_gcode (char *gcode) bool protocol_main_loop (void) { if(sys.alarm == Alarm_SelftestFailed) { + sys.alarm = Alarm_None; system_raise_alarm(Alarm_SelftestFailed); } else if (hal.control.get_state().e_stop) { // Check for e-stop active. Blocks everything until cleared. @@ -127,7 +128,7 @@ bool protocol_main_loop (void) state_set(STATE_IDLE); #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN // Check if the safety door is open. - if (!settings.flags.safety_door_ignore_when_idle && hal.control.get_state().safety_door_ajar) { + if (!settings.safety_door.flags.ignore_when_idle && hal.control.get_state().safety_door_ajar) { system_set_exec_state_flag(EXEC_SAFETY_DOOR); protocol_execute_realtime(); // Enter safety door mode. Should return as IDLE state. } @@ -887,6 +888,9 @@ static void protocol_execute_rt_commands (void) } realtime_queue.tail = (bptr + 1) & (RT_QUEUE_SIZE - 1); } + + if(!sys.driver_started) + while(true); } void protocol_execute_noop (sys_state_t state) diff --git a/report.c b/report.c index a3bbc23..9f8f5b1 100644 --- a/report.c +++ b/report.c @@ -921,7 +921,7 @@ void report_build_info (char *line, bool extended) if(!settings.status_report.sync_on_wco_change) // NOTE: Shown when disabled. *append++ = 'W'; - if(hal.stepper.get_auto_squared) + if(hal.stepper.get_ganged) *append++ = '2'; *append++ = ','; diff --git a/settings.c b/settings.c index fedd7af..b6d7a00 100644 --- a/settings.c +++ b/settings.c @@ -103,6 +103,7 @@ PROGMEM const settings_t defaults = { .steppers.idle_lock_time = DEFAULT_STEPPER_IDLE_LOCK_TIME, .steppers.step_invert.mask = DEFAULT_STEPPING_INVERT_MASK, .steppers.dir_invert.mask = DEFAULT_DIRECTION_INVERT_MASK, + .steppers.ganged_dir_invert.mask = DEFAULT_GANGED_DIRECTION_INVERT_MASK, .steppers.enable_invert.mask = INVERT_ST_ENABLE_MASK, .steppers.deenergize.mask = ST_DEENERGIZE_MASK, #if N_AXIS > 3 @@ -284,7 +285,10 @@ PROGMEM const settings_t defaults = { .parking.target = DEFAULT_PARKING_TARGET, .parking.rate = DEFAULT_PARKING_RATE, .parking.pullout_rate = DEFAULT_PARKING_PULLOUT_RATE, - .parking.pullout_increment = DEFAULT_PARKING_PULLOUT_INCREMENT + .parking.pullout_increment = DEFAULT_PARKING_PULLOUT_INCREMENT, + + .safety_door.spindle_on_delay = SAFETY_DOOR_SPINDLE_DELAY, + .safety_door.coolant_on_delay = SAFETY_DOOR_COOLANT_DELAY }; PROGMEM static const setting_group_detail_t setting_group_detail [] = { @@ -344,10 +348,10 @@ static status_code_t set_force_initialization_alarm (setting_id_t id, uint_fast1 static status_code_t set_probe_allow_feed_override (setting_id_t id, uint_fast16_t int_value); static status_code_t set_tool_change_mode (setting_id_t id, uint_fast16_t int_value); static status_code_t set_tool_change_probing_distance (setting_id_t id, float value); +static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value); #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN static status_code_t set_parking_enable (setting_id_t id, uint_fast16_t int_value); static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_value); -static status_code_t set_door_options (setting_id_t id, uint_fast16_t int_value); #endif #ifdef ENABLE_SPINDLE_LINEARIZATION static status_code_t set_linear_piece (setting_id_t id, char *svalue); @@ -367,17 +371,17 @@ static float get_float (setting_id_t setting); static uint32_t get_int (setting_id_t id); static bool is_setting_available (const setting_detail_t *setting); - static char control_signals[] = "Reset,Feed hold,Cycle start,Safety door,Block delete,Optional stop,EStop,Probe connected,Motor fault"; static char spindle_signals[] = "Spindle enable,Spindle direction,PWM"; static char coolant_signals[] = "Flood,Mist"; +static char ganged_axes[] = "X-Axis,Y-Axis,Z-Axis"; PROGMEM static const setting_detail_t setting_detail[] = { { Setting_PulseMicroseconds, Group_Stepper, "Step pulse time", "microseconds", Format_Decimal, "#0.0", "2.0", NULL, Setting_IsLegacy, &settings.steppers.pulse_microseconds, NULL, NULL }, { Setting_StepperIdleLockTime, Group_Stepper, "Step idle delay", "milliseconds", Format_Int16, "####0", NULL, "65535", Setting_IsLegacy, &settings.steppers.idle_lock_time, NULL, NULL }, { Setting_StepInvertMask, Group_Stepper, "Step pulse invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.step_invert.mask, NULL, NULL }, { Setting_DirInvertMask, Group_Stepper, "Step direction invert", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.dir_invert.mask, NULL, NULL }, - { Setting_InvertStepperEnable, Group_Stepper, "Invert step enable pin(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.enable_invert.mask, NULL, NULL }, + { Setting_InvertStepperEnable, Group_Stepper, "Invert stepper enable pin(s)", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.steppers.enable_invert.mask, NULL, NULL }, #if COMPATIBILITY_LEVEL <= 1 { Setting_LimitPinsInvertMask, Group_Limits, "Invert limit pins", NULL, Format_AxisMask, NULL, NULL, NULL, Setting_IsLegacy, &settings.limits.invert.mask, NULL, NULL }, #else @@ -386,6 +390,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_InvertProbePin, Group_Probing, "Invert probe pin", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsLegacyFn, set_probe_invert, get_int, NULL }, { Setting_SpindlePWMBehaviour, Group_Spindle, "Disable spindle with zero speed", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtended, &settings.spindle.flags.mask, NULL, is_setting_available }, // { Setting_SpindlePWMBehaviour, Group_Spindle, "Spindle enable vs. speed behaviour", NULL, Format_RadioButtons, "No action,Disable spindle with zero speed,Enable spindle with all speeds", NULL, NULL, Setting_IsExtended, &settings.spindle.flags.mask, NULL, NULL }, + { Setting_GangedDirInvertMask, Group_Stepper, "Ganged axes direction invert", NULL, Format_Bitfield, ganged_axes, NULL, NULL, Setting_IsExtendedFn, set_ganged_dir_invert, get_int, NULL }, #if COMPATIBILITY_LEVEL <= 1 { Setting_StatusReportMask, Group_General, "Status report options", NULL, Format_Bitfield, "Position in machine coordinate,Buffer state,Line numbers,Feed & speed,Pin state,Work coordinate offset,Overrides,Probe coordinates,Buffer sync on WCO change,Parser state,Alarm substatus,Run substatus", NULL, NULL, Setting_IsExtendedFn, set_report_mask, get_int, NULL }, #else @@ -452,7 +457,7 @@ PROGMEM static const setting_detail_t setting_detail[] = { { Setting_ParkingTarget, Group_SafetyDoor, "Parking target", "mm", Format_Decimal, "-###0.0", "-100000", NULL, Setting_IsExtended, &settings.parking.target, NULL, NULL }, { Setting_ParkingFastRate, Group_SafetyDoor, "Parking fast rate", "mm/min", Format_Decimal, "###0.0", NULL, NULL, Setting_IsExtended, &settings.parking.rate, NULL, NULL }, { Setting_RestoreOverrides, Group_General, "Restore overrides", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_restore_overrides, get_int, NULL }, - { Setting_DoorOptions, Group_SafetyDoor, "Safety door options", NULL, Format_Bitfield, "Ignore when idle,Keep coolant state on open", NULL, NULL, Setting_IsExtendedFn, set_door_options, get_int, NULL }, + { Setting_DoorOptions, Group_SafetyDoor, "Safety door options", NULL, Format_Bitfield, "Ignore when idle,Keep coolant state on open", NULL, NULL, Setting_IsExtended, &settings.safety_door.flags.value, NULL, NULL }, #endif { Setting_SleepEnable, Group_General, "Sleep enable", NULL, Format_Bool, NULL, NULL, NULL, Setting_IsExtendedFn, set_sleep_enable, get_int, NULL }, { Setting_HoldActions, Group_General, "Feed hold actions", NULL, Format_Bitfield, "Disable laser during hold,Restore spindle and coolant state on resume", NULL, NULL, Setting_IsExtendedFn, set_hold_actions, get_int, NULL }, @@ -511,10 +516,13 @@ PROGMEM static const setting_descr_t setting_descr[] = { { Setting_StepperIdleLockTime, "Sets a short hold delay when stopping to let dynamics settle before disabling steppers. Value 255 keeps motors enabled." }, { Setting_StepInvertMask, "Inverts the step signals (active low)." }, { Setting_DirInvertMask, "Inverts the direction signals (active low)." }, - { Setting_InvertStepperEnable, "Inverts the stepper driver enable signals (active low). If the stepper drivers shares the same enable signal only X is used." }, + { Setting_InvertStepperEnable, "Inverts the stepper driver enable signals. Most drivers uses active low enable requiring inversion.\\n" + "NOTE: If the stepper drivers shares the same enable signal only X is used." + }, { Setting_LimitPinsInvertMask, "Inverts the axis limit input signals." }, { Setting_InvertProbePin, "Inverts the probe input pin signal." }, { Setting_SpindlePWMBehaviour, "" }, + { Setting_GangedDirInvertMask, "Inverts the direction signals for ganged axes." }, { Setting_StatusReportMask, "Specifies optional data included in status reports.\\n" "If Run substatus is enabled it may be used for simple probe protection.\\n\\n" "Note that Parser state will be sent separately after the status report and only on changes." @@ -723,6 +731,16 @@ static status_code_t set_probe_invert (setting_id_t id, uint_fast16_t int_value) return Status_OK; } +static status_code_t set_ganged_dir_invert (setting_id_t id, uint_fast16_t int_value) +{ + if(!hal.stepper.get_ganged) + return Status_SettingDisabled; + + settings.steppers.ganged_dir_invert.mask = int_value & hal.stepper.get_ganged(false).mask; + + return Status_OK; +} + static status_code_t set_report_mask (setting_id_t id, uint_fast16_t int_value) { #if COMPATIBILITY_LEVEL <= 1 @@ -892,14 +910,6 @@ static status_code_t set_restore_overrides (setting_id_t id, uint_fast16_t int_v return Status_OK; } -static status_code_t set_door_options (setting_id_t id, uint_fast16_t int_value) -{ - settings.flags.safety_door_ignore_when_idle = bit_istrue(int_value, bit(0)); - settings.flags.keep_coolant_state_on_door_open = bit_istrue(int_value, bit(1)); - - return Status_OK; -} - #endif static status_code_t set_sleep_enable (setting_id_t id, uint_fast16_t int_value) @@ -1078,7 +1088,7 @@ static status_code_t set_axis_setting (setting_id_t setting, float value) break; case Setting_AxisAutoSquareOffset: - if(hal.stepper.get_auto_squared && bit_istrue(hal.stepper.get_auto_squared().mask, bit(idx))) + if(hal.stepper.get_ganged && bit_istrue(hal.stepper.get_ganged(true).mask, bit(idx))) settings.axis[idx].dual_axis_offset = value; else status = Status_SettingDisabled; @@ -1164,6 +1174,10 @@ static uint32_t get_int (setting_id_t id) value = settings.probe.invert_probe_pin; break; + case Setting_GangedDirInvertMask: + value = settings.steppers.ganged_dir_invert.mask; + break; + case Setting_StatusReportMask: #if COMPATIBILITY_LEVEL <= 1 value = settings.status_report.mask; @@ -1233,10 +1247,6 @@ static uint32_t get_int (setting_id_t id) value = settings.flags.restore_overrides; break; - case Setting_DoorOptions: - value = settings.flags.safety_door_ignore_when_idle | (settings.flags.keep_coolant_state_on_door_open << 1) ; - break; - case Setting_SleepEnable: value = settings.flags.sleep_enable; break; @@ -1358,6 +1368,10 @@ static bool is_setting_available (const setting_detail_t *setting) if(setting) switch(normalize_id(setting->id)) { + case Setting_GangedDirInvertMask: + available = hal.stepper.get_ganged && hal.stepper.get_ganged(false).mask != 0; + break; + case Setting_SpindlePWMBehaviour: available = hal.driver_cap.variable_spindle; break; @@ -1380,7 +1394,8 @@ static bool is_setting_available (const setting_detail_t *setting) break; case Setting_AxisAutoSquareOffset: - available = hal.stepper.get_auto_squared != NULL; + available = hal.stepper.get_ganged && hal.stepper.get_ganged(true).mask != 0; +// available = hal.stepper.get_ganged && bit_istrue(hal.stepper.get_ganged(true).mask, setting->id - Setting_AxisAutoSquareOffset); break; default: @@ -1614,7 +1629,7 @@ bool settings_is_group_available (setting_group_t group) break; case Group_Limits_DualAxis: - available = hal.stepper.get_auto_squared != NULL; + available = hal.stepper.get_ganged && hal.stepper.get_ganged(true).mask != 0; break; case Group_General: @@ -2124,6 +2139,9 @@ void settings_init (void) setting_remove_elements(Setting_SpindleInvertMask, spindle_cap.mask); setting_remove_elements(Setting_ControlInvertMask, hal.signals_cap.mask); + if(hal.stepper.get_ganged) + setting_remove_elements(Setting_GangedDirInvertMask, hal.stepper.get_ganged(false).mask); + if(!hal.driver_cap.mist_control) setting_remove_element(Setting_CoolantInvertMask, 1); diff --git a/settings.h b/settings.h index f4e56e8..c297ac1 100644 --- a/settings.h +++ b/settings.h @@ -30,14 +30,7 @@ // Version of the persistent storage data. Will be used to migrate existing data from older versions of Grbl // when firmware is upgraded. Always stored in byte 0 of non-volatile storage - -// TODO: add ftp port to network settings, enable safety_door settings - -#if N_AXIS > 3 // TODO: remove on next version update -#define SETTINGS_VERSION 20 // NOTE: Check settings_reset() when moving to next version. -#else -#define SETTINGS_VERSION 19 // NOTE: Check settings_reset() when moving to next version. -#endif +#define SETTINGS_VERSION 21 // NOTE: Check settings_reset() when moving to next version. // Define axis settings numbering scheme. Starts at Setting_AxisSettingsBase, every INCREMENT, over N_SETTINGS. #define AXIS_SETTINGS_INCREMENT 10 // Must be greater than the number of axis settings. @@ -47,6 +40,8 @@ #define ENCODER_N_SETTINGS_MAX 5 // NOTE: This is the maximum number of encoders allowed. #define ENCODER_SETTINGS_INCREMENT 10 +#define SETTINGS_HARD_RESET_REQUIRED "\\n\\nNOTE: A hard reset of the controller is required after changing this setting." + typedef enum { Setting_PulseMicroseconds = 0, Setting_StepperIdleLockTime = 1, @@ -56,6 +51,7 @@ typedef enum { Setting_LimitPinsInvertMask = 5, Setting_InvertProbePin = 6, Setting_SpindlePWMBehaviour = 7, + Setting_GangedDirInvertMask = 8, Setting_StatusReportMask = 10, Setting_JunctionDeviation = 11, Setting_ArcTolerance = 12, @@ -226,6 +222,10 @@ typedef enum { Setting_Arc_HeightPerVolt = 363, Setting_Arc_OkHighVoltage = 364, Setting_Arc_OkLowVoltage = 365, + Setting_Arc_VoltagePort = 366, + Setting_Arc_OkPort = 367, + Setting_THC_CutterDownPort = 368, + Setting_THC_CutterUpPort = 369, Settings_IoPort_InvertIn = 370, Settings_IoPort_Pullup_Disable = 371, @@ -242,6 +242,13 @@ typedef enum { Setting_CoolantOffset = 382, Setting_CoolantGain = 383, Setting_DisableG92Persistence = 384, + Setting_BlueToothStateInput = 385, + Setting_FanPort0 = 386, + Setting_FanPort1 = 387, + Setting_FanPort2 = 388, + Setting_FanPort3 = 389, + Setting_CoolantTempPort = 390, + Setting_CoolantOkPort = 391, Setting_EncoderSettingsBase = 400, // NOTE: Reserving settings values >= 400 for encoder settings. Up to 449. Setting_EncoderSettingsMax = 449, @@ -471,6 +478,7 @@ typedef struct { typedef struct { axes_signals_t step_invert; axes_signals_t dir_invert; + axes_signals_t ganged_dir_invert; // applied after inversion for the master motor axes_signals_t enable_invert; axes_signals_t deenergize; #if N_AXIS > 3 @@ -575,7 +583,7 @@ typedef struct { homing_settings_t homing; limit_settings_t limits; parking_settings_t parking; -// safety_door_settings_t safety_door; + safety_door_settings_t safety_door; position_pid_t position; // Used for synchronized motion ioport_signals_t ioport; } settings_t; diff --git a/spindle_control.c b/spindle_control.c index 42a4bc2..e492829 100644 --- a/spindle_control.c +++ b/spindle_control.c @@ -90,7 +90,7 @@ bool spindle_sync (spindle_state_t state, float rpm) delay += 0.1f; if(ABORTED) break; - if(delay >= SAFETY_DOOR_SPINDLE_DELAY) { + if(delay >= settings.safety_door.spindle_on_delay) { system_raise_alarm(Alarm_Spindle); break; } @@ -114,7 +114,7 @@ bool spindle_restore (spindle_state_t state, float rpm) spindle_set_state(state, rpm); if(state.on) { if((ok = !hal.driver_cap.spindle_at_speed)) - delay_sec(SAFETY_DOOR_SPINDLE_DELAY, DelayMode_SysSuspend); + delay_sec(settings.safety_door.spindle_on_delay, DelayMode_SysSuspend); else if((ok == (settings.spindle.at_speed_tolerance <= 0.0f))) { float delay = 0.0f; while(!(ok = hal.spindle.get_state().at_speed)) { @@ -122,7 +122,7 @@ bool spindle_restore (spindle_state_t state, float rpm) delay += 0.1f; if(ABORTED) break; - if(delay >= SAFETY_DOOR_SPINDLE_DELAY) { + if(delay >= settings.safety_door.spindle_on_delay) { system_raise_alarm(Alarm_Spindle); break; } diff --git a/state_machine.c b/state_machine.c index eac4fc0..5c270f4 100644 --- a/state_machine.c +++ b/state_machine.c @@ -81,7 +81,7 @@ static void state_restore_conditions (planner_cond_t *condition, float rpm) if (gc_state.modal.coolant.value != hal.coolant.get_state().value) { // NOTE: Laser mode will honor this delay. An exhaust system is often controlled by this pin. coolant_set_state(condition->coolant); - delay_sec(SAFETY_DOOR_COOLANT_DELAY, DelayMode_SysSuspend); + delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend); } park.flags.restoring = Off; @@ -554,7 +554,7 @@ static void state_await_resume (uint_fast16_t rt_exec) if (restore_condition.coolant.value != hal.coolant.get_state().value) { // NOTE: Laser mode will honor this delay. An exhaust system is often controlled by coolant signals. coolant_set_state(restore_condition.coolant); - delay_sec(SAFETY_DOOR_COOLANT_DELAY, DelayMode_SysSuspend); + delay_sec(settings.safety_door.coolant_on_delay, DelayMode_SysSuspend); } sys.override.spindle_stop.value = 0; // Clear spindle stop override states diff --git a/system.c b/system.c index 6a2b379..d09325f 100644 --- a/system.c +++ b/system.c @@ -107,7 +107,7 @@ ISR_CODE void control_interrupt_handler (control_signals_t signals) else { #ifdef ENABLE_SAFETY_DOOR_INPUT_PIN if (signals.safety_door_ajar) { - if(settings.flags.safety_door_ignore_when_idle) { + if(settings.safety_door.flags.ignore_when_idle) { // Only stop the spindle (laser off) when idle or jogging, // this to allow positioning the controlled point (spindle) when door is open. // NOTE: at least for lasers there should be an external interlock blocking laser power. @@ -613,7 +613,7 @@ static status_code_t go_home (sys_state_t state, axes_signals_t axes) else if (!(settings.homing.flags.enabled && (sys.homing.mask || settings.homing.flags.single_axis_commands || settings.homing.flags.manual))) retval = Status_HomingDisabled; // Block if safety door is ajar. - else if (control_signals.safety_door_ajar && !settings.flags.safety_door_ignore_when_idle) + else if (control_signals.safety_door_ajar && !settings.safety_door.flags.ignore_when_idle) retval = Status_CheckDoor; // Block if safety reset is active. else if(control_signals.reset) @@ -983,7 +983,7 @@ void system_raise_alarm (alarm_code_t alarm) if(sys.alarm != alarm) { sys.alarm = alarm; state_set(alarm == Alarm_EStop ? STATE_ESTOP : STATE_ALARM); - if(sys.driver_started) + if(sys.driver_started || sys.alarm == Alarm_SelftestFailed) report_alarm_message(alarm); } }