diff --git a/CMakeLists.txt b/CMakeLists.txt index 26dc6f8..445316f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ target_sources(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}/ngc_params.c ${CMAKE_CURRENT_LIST_DIR}/ngc_expr.c ${CMAKE_CURRENT_LIST_DIR}/regex.c + ${CMAKE_CURRENT_LIST_DIR}/ioports.c ) target_include_directories(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}) diff --git a/README.md b/README.md index b52e61f..cc87e2f 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It has been written to complement grblHAL and has features such as proper keyboa --- -Latest build date is 20211109, see the [changelog](changelog.md) for details. +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. --- @@ -80,4 +80,4 @@ List of Supported G-Codes: Some [plugins](https://github.com/grblHAL/plugins) implements additional M-codes. --- -2021-10-24 +2021-11-17 diff --git a/changelog.md b/changelog.md index 08aa0dc..0ebfc52 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,29 @@ ## grblHAL changelog +Build 20211117: + +Core: + +* Enhanced [ioports API](http://svn.io-engineering.com/grblHAL/html/ioports_8h.html) with new calls for claiming ports and swapping pin to port mappings. +* Fixed bug #87 where executing G28/G30 with explicit motion when a motion mode was not active \(following a G80\) raised error 31. +* Replaced string symbol `GRBL_VERSION_BUILD` with numeric symbol `GRBL_BUILD`. +The new symbol can be used by plugin code to check for functionality. + +Plugins: + +* Updated Bluetooth plugin for enhanced ioports API, bug fix. +* Updated Spindle plugin for dual spindle support, merged PR#4. +* Updated some to use the new `GRBL_BUILD` symbol. + +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. +* STM32F3xx: Fixed typo and some compiler warnings. + +--- + Build 20211108: Core: @@ -15,7 +39,7 @@ Plugins: * Made Modbus plugin configuration symbols settable from compiler command line, added pin description to claimed UART pins. Drivers: -* Updated most to provide peripheral pin info to `$pins` report. +* Updated to provide peripheral pin info to `$pins` report. * Some bug fixes. --- diff --git a/crossbar.h b/crossbar.h index 7ce2ed1..a6282ef 100644 --- a/crossbar.h +++ b/crossbar.h @@ -281,6 +281,7 @@ typedef enum { IRQ_Mode_Rising = 0b00001, //!< 0b00001 (0x01) IRQ_Mode_Falling = 0b00010, //!< 0b00010 (0x02) IRQ_Mode_Change = 0b00100, //!< 0b00100 (0x04) + IRQ_Mode_Edges = 0b00111, //!< 0b00111 (0x07) - only used to report port capability. IRQ_Mode_High = 0b01000, //!< 0b01000 (0x08) IRQ_Mode_Low = 0b10000, //!< 0b10000 (0x10) IRQ_Mode_All = 0b11111 //!< 0b11111 (0x1F) - only used to report port capability. @@ -298,10 +299,12 @@ typedef struct driver_irq_handler { struct driver_irq_handler *next; } driver_irq_handler_t; +//! Pin pullup and pulldown modes, may be or'ed when reporting pin capability. typedef enum { - PullMode_None = 0b00, - PullMode_Up = 0b01, - PullMode_Down = 0b10 + PullMode_None = 0b00, //!< 0b00 (0x00) + PullMode_Up = 0b01, //!< 0b01 (0x01) + PullMode_Down = 0b10, //!< 0b10 (0x02) + PullMode_UpDown = 0b11 //!< 0b11 (0x03) - only used to report port capability. } pull_mode_t; #define PINMODE_NONE (0) @@ -324,7 +327,8 @@ typedef union { pwm :1, analog :1, peripheral :1, - reserved :2, + claimed :1, + remapped :1, can_remap :1; }; } pin_mode_t; diff --git a/driver_opts.h b/driver_opts.h index ce3e1b7..28dc829 100644 --- a/driver_opts.h +++ b/driver_opts.h @@ -125,16 +125,27 @@ #ifndef PPI_ENABLE #define PPI_ENABLE 0 #endif -#ifndef SPINDLE_HUANYANG -#define SPINDLE_HUANYANG 0 + +#ifndef HUANYANG_ENABLE +#define HUANYANG_ENABLE 0 +#else +#ifndef VFD_SPINDLE +#define VFD_SPINDLE 1 #endif +#endif + +#ifndef VFD_SPINDLE +#define VFD_SPINDLE 0 +#endif + #ifndef MODBUS_ENABLE -#if SPINDLE_HUANYANG +#if HUANYANG_ENABLE #define MODBUS_ENABLE 1 #else #define MODBUS_ENABLE 0 #endif #endif + #ifndef QEI_ENABLE #define QEI_ENABLE 0 #endif diff --git a/gcode.c b/gcode.c index 01e2355..e5bb161 100644 --- a/gcode.c +++ b/gcode.c @@ -1771,7 +1771,7 @@ status_code_t gc_execute_block(char *block) FAIL(Status_GcodeUnsupportedCoordSys); // [Greater than N sys] // Determine coordinate system to change and try to load from non-volatile storage. gc_block.values.coord_data.id = p_value == 0 - ? gc_block.modal.coord_system.id // Index P0 as the active coordinate system + ? gc_block.modal.coord_system.id // Index P0 as the active coordinate system : (coord_system_id_t)(p_value - 1); // else adjust index to NVS coordinate data indexing. if (!settings_read_coord_data(gc_block.values.coord_data.id, &gc_block.values.coord_data.xyz)) @@ -1924,7 +1924,7 @@ status_code_t gc_execute_block(char *block) // [G80 Errors]: Axis word are programmed while G80 is active. // NOTE: Even non-modal commands or TLO that use axis words will throw this strict error. - if (axis_words.mask) // [No axis words allowed] + if (axis_words.mask && axis_command != AxisCommand_NonModal) // [No axis words allowed] FAIL(Status_GcodeAxisWordsExist); gc_block.modal.retract_mode = CCRetractMode_Previous; diff --git a/grbl.h b/grbl.h index 27b9798..b3b7fd6 100644 --- a/grbl.h +++ b/grbl.h @@ -34,7 +34,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_VERSION_BUILD "20211107" +#define GRBL_BUILD 20211117 // The following symbols are set here if not already set by the compiler or in config.h // Do NOT change here! diff --git a/hal.h b/hal.h index 215082b..11eb520 100644 --- a/hal.h +++ b/hal.h @@ -35,6 +35,7 @@ #include "stepper.h" #include "nvs.h" #include "probe.h" +#include "ioports.h" #include "plugins.h" #define HAL_VERSION 8 @@ -86,90 +87,6 @@ __NOTE:__ required if the networking plugin is to be supported. */ typedef bool (*stream_select_ptr)(const io_stream_t *stream); - -/************* - * Aux I/O * - *************/ - -typedef enum { - Port_Analog = 0, - Port_Digital = 1 -} io_port_type_t; - -typedef enum { - Port_Input = 0, - Port_Output = 1 -} io_port_direction_t; - -/*! \brief Pointer to function for setting a digital output. -\param port port number -\param on true to set ouput high, false to set it low -*/ -typedef void (*digital_out_ptr)(uint8_t port, bool on); - -/*! \brief Pointer to function for setting an analog output. -\param port port number. -\param value -\returns true if successful, false otherwise. -*/ -typedef bool (*analog_out_ptr)(uint8_t port, float value); - -/*! \brief Pointer to function for reading a digital or analog input. - -__NOTE:__ The latest value read is stored in \ref #sys \ref #sys#var5399. - -\param digital true if port is digital, false if analog. -\param port port number. -\param wait_mode a #wait_mode_t enum value. -\param timeout in seconds, ignored if wait_mode is #WaitMode_Immediate (0). -\returns read value if successful, -1 otherwise. -*/ -typedef int32_t (*wait_on_input_ptr)(bool digital, uint8_t port, wait_mode_t wait_mode, float timeout); - -/*! \brief Pointer to function for setting pin description for a digital or analog port. -\param digital true if port is digital, false if analog. -\param output true if port is an output, false if an input. -\param port port number. -\param s pointer to null terminated description string. -*/ -typedef void (*set_pin_description_ptr)(bool digital, bool output, uint8_t port, const char *s); - -/*! \brief Pointer to function for getting information about a digital or analog port. -\param digital true if port is digital, false if analog. -\param output true if port is an output, false if an input. -\param port port number. -\returns pointer to port information in a xbar_t struct if successful, NULL if not. -*/ -typedef xbar_t *(*get_pin_info_ptr)(bool digital, bool output, uint8_t port); - -/*! \brief Pointer to callback function for input port interrupt events. -\param port port number. -\param state true if port level is high, false if it is low. -*/ -typedef void (*ioport_interrupt_callback_ptr)(uint8_t port, bool state); - -/*! \brief Pointer to function for registering or deregistering an interrupt handler for a digital input port. -\param port port number. -\param irq_mode a \a #pin_irq_mode_t enum value. -\param interrupt_callback pointer to the callback function to register or NULL to deregister the current callback. -\returns true if successful, false otherwise. -*/ -typedef bool (*ioport_register_interrupt_handler_ptr)(uint8_t port, pin_irq_mode_t irq_mode, ioport_interrupt_callback_ptr interrupt_callback); - -//! Properties and handlers for auxillary digital and analog I/O. -typedef struct { - uint8_t num_digital_in; //!< Number of digital inputs available. - uint8_t num_digital_out; //!< Number of digital outputs available. - uint8_t num_analog_in; //!< Number of analog inputs available. - uint8_t num_analog_out; //!< Number of analog outputs available. - digital_out_ptr digital_out; //!< Optional handler for setting a digital output. - analog_out_ptr analog_out; //!< Optional handler for setting an analog output. - wait_on_input_ptr wait_on_input; //!< Optional handler for reading a digital or analog input. - set_pin_description_ptr set_pin_description; //!< Optional handler for setting a description of an auxillary pin. - get_pin_info_ptr get_pin_info; //!< Optional handler for getting information about an auxillary pin. - ioport_register_interrupt_handler_ptr register_interrupt_handler; -} io_port_t; - /*! \brief Pointer to function for registering information about a peripheral pin. \param pin as periph_pin_t struct containing pin information. */ diff --git a/ioports.c b/ioports.c new file mode 100644 index 0000000..03db6ce --- /dev/null +++ b/ioports.c @@ -0,0 +1,121 @@ +/* + ioports.c - some wrapper functions for the ioports HAL API + + Part of grblHAL + + Copyright (c) 2021 Terje Io + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +/** + * @file + * + * Some wrapper functions for the #io_port_t API. + * They perform the neccesary checks for both availablity of ports + * and advanced functionality simplifying plugin code that uses them. + */ + +#include "hal.h" + +static int16_t digital_in = -1, digital_out = -1, analog_in = -1, analog_out = -1; + +static uint8_t ioports_count (io_port_type_t type, io_port_direction_t dir) +{ + xbar_t *port; + uint8_t n_ports = 0; + + // determine how many ports, including claimed ports, that are available + do { + if((port = hal.port.get_pin_info(type, type, n_ports))) + n_ports++; + } while(port != NULL); + + return n_ports; +} + +/*! \brief Get number of digital or analog ports available. +\param type as an \a #io_port_type_t enum value. +\param dir as an \a #io_port_direction_t enum value. +\returns number of ports available including claimed ports if the API implementation supports that. +*/ +uint8_t ioports_available (io_port_type_t type, io_port_direction_t dir) +{ + uint8_t ports = 0; + + if(hal.port.get_pin_info) { + + if(type == Port_Digital) { + if(dir == Port_Input) + ports = digital_in == -1 ? (digital_in = ioports_count(type, dir)) : (uint8_t)digital_in; + else + ports = digital_out == -1 ? (digital_out = ioports_count(type, dir)) : (uint8_t)digital_out; + } else { + if(dir == Port_Input) + ports = analog_in == -1 ? (analog_in = ioports_count(type, dir)) : (uint8_t)analog_in; + else + ports = analog_out == -1 ? (analog_out = ioports_count(type, dir)) : (uint8_t)analog_out; + } + } else { + if(type == Port_Digital) + ports = dir == Port_Input ? hal.port.num_digital_in : hal.port.num_digital_out; + else + ports = dir == Port_Input ? hal.port.num_analog_in : hal.port.num_analog_out; + } + + return ports; +} + +/*! \brief Claim a digital or analog port for exclusive use. +\param type as an \a #io_port_type_t enum value. +\param dir as an \a #io_port_direction_t enum value. +\param port pointer to a \a uint8_t holding the ports aux number, returns the actual port number to use if successful. +\param description pointer to a \a char constant for the pin description. +\returns true if successful, false if not. +*/ +bool ioport_claim (io_port_type_t type, io_port_direction_t dir, uint8_t *port, const char *description) +{ + bool ok = false; + uint8_t n_ports = ioports_available(type, dir); + + if(hal.port.claim != 0) { + + xbar_t *portinfo = NULL; + + 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); + break; + } + } while(n_ports && !ok); + + } else if((ok = n_ports > 0)) { + if(type == Port_Digital) + *port = dir == Port_Input ? --hal.port.num_digital_in : --hal.port.num_digital_out; + else + *port = dir == Port_Input ? --hal.port.num_analog_in : --hal.port.num_analog_out; + } + + return ok; +} + +/*! \brief Check if ports can be claimed by aux number or not. +\returns true if ports can be claimed by aux number, false if claimed ports are allocated by the API. +*/ +bool ioport_can_claim_explicit (void) +{ + return !(hal.port.claim == NULL || hal.port.get_pin_info == NULL); +} diff --git a/ioports.h b/ioports.h new file mode 100644 index 0000000..35eced8 --- /dev/null +++ b/ioports.h @@ -0,0 +1,126 @@ +/* + ioports.h - typedefs, API structure and functions for auxillary I/O + + Part of grblHAL + + Copyright (c) 2021 Terje Io + + Grbl is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Grbl is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Grbl. If not, see . +*/ + +#pragma once + +typedef enum { + Port_Analog = 0, //!< 0 + Port_Digital = 1 //!< 1 +} io_port_type_t; + +typedef enum { + Port_Input = 0, //!< 0 + Port_Output = 1 //!< 1 +} io_port_direction_t; + +/*! \brief Pointer to function for setting a digital output. +\param port port number +\param on true to set ouput high, false to set it low +*/ +typedef void (*digital_out_ptr)(uint8_t port, bool on); + +/*! \brief Pointer to function for setting an analog output. +\param port port number. +\param value +\returns true if successful, false otherwise. +*/ +typedef bool (*analog_out_ptr)(uint8_t port, float value); + +/*! \brief Pointer to function for reading a digital or analog input. + +__NOTE:__ The latest value read is stored in \ref #sys \ref #sys#var5399. + +\param type as an \a #io_port_type_t enum value. +\param port port number. +\param wait_mode a #wait_mode_t enum value. +\param timeout in seconds, ignored if wait_mode is #WaitMode_Immediate (0). +\returns read value if successful, -1 otherwise. +*/ +typedef int32_t (*wait_on_input_ptr)(io_port_type_t type, uint8_t port, wait_mode_t wait_mode, float timeout); + +/*! \brief Pointer to function for setting pin description for a digital or analog port. +\param type as an \a #io_port_type_t enum value. +\param dir as an \a #io_port_direction_t enum value. +\param port port number. +\param s pointer to null terminated description string. +*/ +typedef void (*set_pin_description_ptr)(io_port_type_t type, io_port_direction_t dir, uint8_t port, const char *s); + +/*! \brief Pointer to function for getting information about a digital or analog port. +\param type as an \a #io_port_type_t enum value. +\param dir as an \a #io_port_direction_t enum value. +\param port port number. +\returns pointer to port information in a xbar_t struct if successful, NULL if not. +*/ +typedef xbar_t *(*get_pin_info_ptr)(io_port_type_t type, io_port_direction_t dir, uint8_t port); + +/*! \brief Pointer to function for claiming a digital or analog port for exclusive use. +\param type as an \a #io_port_type_t enum value. +\param dir as an \a #io_port_direction_t enum value. +\param port port number. +\returns true if successful, false if not. +*/ +typedef bool (*claim_port_ptr)(io_port_type_t type, io_port_direction_t dir, uint8_t *port, const char *description); + +/*! \brief Pointer to function for swapping two digital or analog ports. +\param type as an \a #io_port_type_t enum value. +\param dir as an \a #io_port_direction_t enum value. +\param port_from port number. +\param port_to port number. +\returns true if successful, false if not. +*/ +typedef bool (*swap_pins_ptr)(io_port_type_t type, io_port_direction_t dir, uint8_t port_from, uint8_t port_to); + +/*! \brief Pointer to callback function for input port interrupt events. +\param port port number. +\param state true if port level is high, false if it is low. +*/ +typedef void (*ioport_interrupt_callback_ptr)(uint8_t port, bool state); + +/*! \brief Pointer to function for registering or deregistering an interrupt handler for a digital input port. +\param port port number. +\param irq_mode a \a #pin_irq_mode_t enum value. +\param interrupt_callback pointer to the callback function to register or NULL to deregister the current callback. +\returns true if successful, false otherwise. +*/ +typedef bool (*ioport_register_interrupt_handler_ptr)(uint8_t port, pin_irq_mode_t irq_mode, ioport_interrupt_callback_ptr interrupt_callback); + +//! Properties and handlers for auxillary digital and analog I/O. +typedef struct { + uint8_t num_digital_in; //!< Number of digital inputs available. + uint8_t num_digital_out; //!< Number of digital outputs available. + uint8_t num_analog_in; //!< Number of analog inputs available. + uint8_t num_analog_out; //!< Number of analog outputs available. + digital_out_ptr digital_out; //!< Optional handler for setting a digital output. + analog_out_ptr analog_out; //!< Optional handler for setting an analog output. + wait_on_input_ptr wait_on_input; //!< Optional handler for reading a digital or analog input. + set_pin_description_ptr set_pin_description; //!< Optional handler for setting a description of an auxillary pin. + get_pin_info_ptr get_pin_info; //!< Optional handler for getting information about an auxillary pin. + claim_port_ptr claim; //!< Optional handler for claiming an auxillary pin for exclusive use. + swap_pins_ptr swap_pins; //!< Optional handler for swapping pins. + ioport_register_interrupt_handler_ptr register_interrupt_handler; +} io_port_t; + +uint8_t ioports_available (io_port_type_t type, io_port_direction_t dir); +bool ioport_claim (io_port_type_t type, io_port_direction_t dir, uint8_t *port, const char *description); +bool ioport_can_claim_explicit (void); + +/*EOF*/ diff --git a/nuts_bolts.h b/nuts_bolts.h index ef41c55..0836195 100644 --- a/nuts_bolts.h +++ b/nuts_bolts.h @@ -51,7 +51,7 @@ #define CAPS(c) ((c >= 'a' && c <= 'z') ? (c & 0x5F) : c) #define LCAPS(c) ((c >= 'A' && c <= 'Z') ? (c | 0x20) : c) -#ifndef STM32F103xB +#if !(defined(STM32F103xB) || defined(STM32F303xC)) #ifndef UNUSED #define UNUSED(x) (void)(x) #endif diff --git a/pin_bits_masks.h b/pin_bits_masks.h index 8de4a16..4a61b3d 100644 --- a/pin_bits_masks.h +++ b/pin_bits_masks.h @@ -98,9 +98,49 @@ #define I2C_STROBE_BIT (1<