/* pin_bits_masks.h - for adding bit definitions and masks NOTE: This file is not used by the core, it may be used by drivers Part of grblHAL Copyright (c) 2021-2025 Terje Io grblHAL 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. grblHAL 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 grblHAL. If not, see . */ #include "platform.h" // Sanity checks #if PROBE_ENABLE && !defined(PROBE_PIN) #error "Probe input is not supported in this configuration!" #endif #if SAFETY_DOOR_ENABLE && !defined(SAFETY_DOOR_PIN) #error "Safety door input is not supported in this configuration!" #endif #if MOTOR_FAULT_ENABLE && !defined(MOTOR_FAULT_PIN) #error "Motor fault input is not supported in this configuration!" #endif #if MOTOR_WARNING_ENABLE && !defined(MOTOR_WARNING_PIN) #error "Motor warning input is not supported in this configuration!" #endif #if I2C_STROBE_ENABLE && !defined(I2C_STROBE_PIN) #error "I2C keypad/strobe is not supported in this configuration!" #endif #if MPG_ENABLE == 1 && !defined(MPG_MODE_PIN) #error "MPG mode input is not supported in this configuration!" #endif #if QEI_SELECT_ENABLE && !defined(QEI_SELECT_PIN) #error "Encoder select input is not supported in this configuration!" #endif #define EXPANDER_PORT 1 // Control input signals // Define the CONTROL_PORT symbol as a shorthand in the *_map.h file if all control inputs share the same port. #ifdef CONTROL_PORT #ifndef RESET_PORT #define RESET_PORT CONTROL_PORT #endif #ifndef FEED_HOLD_PORT #define FEED_HOLD_PORT CONTROL_PORT #endif #ifndef CYCLE_START_PORT #define CYCLE_START_PORT CONTROL_PORT #endif #ifndef ESTOP_PORT #define ESTOP_PORT CONTROL_PORT #endif #ifndef PROBE_DISCONNECT_PORT #define PROBE_DISCONNECT_PORT CONTROL_PORT #endif #ifndef STOP_DISABLE_PORT #define STOP_DISABLE_PORT CONTROL_PORT #endif #ifndef BLOCK_DELETE_PORT #define BLOCK_DELETE_PORT CONTROL_PORT #endif #ifndef SINGLE_BLOCK_PORT #define SINGLE_BLOCK_PORT CONTROL_PORT #endif #ifndef MOTOR_FAULT_PORT #define MOTOR_FAULT_PORT CONTROL_PORT #endif #ifndef MOTOR_WARNING_PORT #define MOTOR_WARNING_PORT CONTROL_PORT #endif #ifndef LIMITS_OVERRIDE_PORT #define LIMITS_OVERRIDE_PORT CONTROL_PORT #endif #if SAFETY_DOOR_ENABLE && !defined(SAFETY_DOOR_PORT) #define SAFETY_DOOR_PORT CONTROL_PORT #endif #endif // CONTROL_PORT #ifndef SD_DETECT_BIT #ifdef SD_DETECT_PIN #define SD_DETECT_BIT (1<aux_port = aux_port; ctrl_pin->input = input; break; } } } return ctrl_pin; } static inline aux_ctrl_t *aux_ctrl_get_pin (uint8_t aux_port) { aux_ctrl_t *ctrl_pin = NULL; uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t); if(idx) do { if(aux_ctrl[--idx].aux_port == aux_port) ctrl_pin = &aux_ctrl[idx]; } while(idx && ctrl_pin == NULL); return ctrl_pin; } static inline void aux_ctrl_irq_enable (settings_t *settings, ioport_interrupt_callback_ptr aux_irq_handler) { uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t); if(idx) do { if(aux_ctrl[--idx].aux_port != 0xFF && aux_ctrl[idx].irq_mode != IRQ_Mode_None) { if(!aux_ctrl_is_probe(aux_ctrl[idx].function)) { pin_irq_mode_t irq_mode; if((irq_mode = aux_ctrl[idx].irq_mode) & IRQ_Mode_RisingFalling) irq_mode = (settings->control_invert.mask & aux_ctrl[idx].cap.mask) ? IRQ_Mode_Falling : IRQ_Mode_Rising; hal.port.register_interrupt_handler(aux_ctrl[idx].aux_port, irq_mode, aux_irq_handler); } } } while(idx); } typedef bool (*aux_claim_explicit_ptr)(aux_ctrl_t *aux_ctrl); static bool aux_ctrl_claim_port (xbar_t *properties, uint8_t port, void *data) { if(ioport_claim(Port_Digital, Port_Input, &port, xbar_fn_to_pinname(((aux_ctrl_t *)data)->function))) ((aux_ctrl_t *)data)->aux_port = port; return ((aux_ctrl_t *)data)->aux_port != IOPORT_UNASSIGNED; } static bool aux_ctrl_find_port (xbar_t *properties, uint8_t port, void *data) { ((aux_ctrl_t *)data)->aux_port = port; return true; } static inline void aux_ctrl_claim_ports (aux_claim_explicit_ptr aux_claim_explicit, ioports_enumerate_callback_ptr aux_claim) { uint_fast8_t idx; if(aux_claim == NULL) aux_claim = aux_ctrl_claim_port; for(idx = 0; idx < sizeof(aux_ctrl) / sizeof(aux_ctrl_t); idx++) { pin_cap_t cap = { .irq_mode = aux_ctrl[idx].irq_mode, .claimable = On }; if(aux_ctrl[idx].pin == 0xFE) // Toolsetter and Probe2 ioports_enumerate(Port_Digital, Port_Input, cap, aux_ctrl_find_port, (void *)&aux_ctrl[idx]); #ifdef STM32_PLATFORM if(aux_ctrl[idx].irq_mode == IRQ_Mode_None && !(aux_ctrl[idx].function == Input_Probe || aux_ctrl[idx].function == Input_LimitsOverride)) continue; #endif if(aux_ctrl[idx].pin == 0xFF) { if(ioports_enumerate(Port_Digital, Port_Input, cap, aux_claim, (void *)&aux_ctrl[idx])) hal.signals_cap.mask |= aux_ctrl[idx].cap.mask; } else if(aux_ctrl[idx].aux_port != IOPORT_UNASSIGNED) aux_claim_explicit(&aux_ctrl[idx]); } } static inline control_signals_t aux_ctrl_scan_status (control_signals_t signals) { #if PROBE_DISCONNECT_ENABLE || STOP_DISABLE_ENABLE || BLOCK_DELETE_ENABLE || SINGLE_BLOCK_ENABLE || LIMITS_OVERRIDE_ENABLE uint_fast8_t idx = sizeof(aux_ctrl) / sizeof(aux_ctrl_t); if(idx) do { if(aux_ctrl[--idx].pin != 0xFF) break; if(aux_ctrl[idx].aux_port != IOPORT_UNASSIGNED) { signals.mask &= ~aux_ctrl[idx].cap.mask; #ifdef GRBL_ESP32 // Snowflake guru workaround if(hal.port.wait_on_input(Port_Digital, aux_ctrl[idx].aux_port, WaitMode_Immediate, FZERO) == 1) signals.mask |= aux_ctrl[idx].cap.mask; #else if(hal.port.wait_on_input(Port_Digital, aux_ctrl[idx].aux_port, WaitMode_Immediate, 0.0f) == 1) signals.mask |= aux_ctrl[idx].cap.mask; #endif } } while(idx); #endif return signals; } // The following pins are bound explicitly to aux output pins static aux_ctrl_out_t aux_ctrl_out[] = { #if defined(ESP_PLATFORM) || defined(RP2040) // for now #if defined(STEPPERS_ENABLE_PIN) && STEPPERS_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnable, .aux_port = IOPORT_UNASSIGNED, .pin = STEPPERS_ENABLE_PIN, .port = (void *)STEPPERS_ENABLE_PORT }, #endif #if defined(X_ENABLE_PIN) && X_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableX, .aux_port = IOPORT_UNASSIGNED, .pin = X_ENABLE_PIN, .port = (void *)X_ENABLE_PORT }, #endif #if defined(X2_ENABLE_PIN) && X2_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableX2, .aux_port = IOPORT_UNASSIGNED, .pin = X2_ENABLE_PIN, .port = (void *)X2_ENABLE_PORT }, #endif #if defined(Y_ENABLE_PIN) && Y_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableY, .aux_port = IOPORT_UNASSIGNED, .pin = Y_ENABLE_PIN, .port = (void *)Y_ENABLE_PORT }, #endif #if defined(Y2_ENABLE_PIN) && Y2_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableY2, .aux_port = IOPORT_UNASSIGNED, .pin = Y2_ENABLE_PIN, .port = (void *)Y2_ENABLE_PORT }, #endif #if defined(XY_ENABLE_PIN) && XY_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableXY, .aux_port = IOPORT_UNASSIGNED, .pin = XY_ENABLE_PIN, .port = (void *)XY_ENABLE_PORT }, #endif #if defined(Z_ENABLE_PIN) && Z_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableZ, .aux_port = IOPORT_UNASSIGNED, .pin = Z_ENABLE_PIN, .port = (void *)Z_ENABLE_PORT }, #endif #if defined(Z2_ENABLE_PIN) && Z2_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableZ2, .aux_port = IOPORT_UNASSIGNED, .pin = Z2_ENABLE_PIN, .port = (void *)Z2_ENABLE_PORT }, #endif #if defined(A_ENABLE_PIN) && A_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableA, .aux_port = IOPORT_UNASSIGNED, .pin = A_ENABLE_PIN, .port = (void *)A_ENABLE_PORT }, #endif #if defined(B_ENABLE_PIN) && B_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableB, .aux_port = IOPORT_UNASSIGNED, .pin = B_ENABLE_PIN, .port = (void *)B_ENABLE_PORT }, #endif #if defined(C_ENABLE_PIN) && C_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableC, .aux_port = IOPORT_UNASSIGNED, .pin = C_ENABLE_PIN, .port = (void *)C_ENABLE_PORT }, #endif #if defined(U_ENABLE_PIN) && U_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableU, .aux_port = IOPORT_UNASSIGNED, .pin = U_ENABLE_PIN, .port = (void *)U_ENABLE_PORT }, #endif #if defined(V_ENABLE_PIN) && AV_ENABLE_PORT == EXPANDER_PORT { .function = Output_StepperEnableV, .aux_port = IOPORT_UNASSIGNED, .pin = V_ENABLE_PIN, .port = (void *)V_ENABLE_PORT }, #endif #endif // #ifdef SPINDLE_ENABLE_PIN #ifndef SPINDLE_ENABLE_PORT #define SPINDLE_ENABLE_PORT 0 #endif { .function = Output_SpindleOn, .aux_port = IOPORT_UNASSIGNED, .pin = SPINDLE_ENABLE_PIN, .port = (void *)SPINDLE_ENABLE_PORT }, #endif #ifdef SPINDLE_PWM_PIN #ifndef SPINDLE_PWM_PORT #define SPINDLE_PWM_PORT 0 #endif { .function = Output_SpindlePWM, .aux_port = IOPORT_UNASSIGNED, .pin = SPINDLE_PWM_PIN, .port = (void *)SPINDLE_PWM_PORT }, #endif #ifdef SPINDLE_DIRECTION_PIN #ifndef SPINDLE_DIRECTION_PORT #define SPINDLE_DIRECTION_PORT 0 #endif { .function = Output_SpindleDir, .aux_port = IOPORT_UNASSIGNED, .pin = SPINDLE_DIRECTION_PIN, .port = (void *)SPINDLE_DIRECTION_PORT }, #endif #ifdef SPINDLE1_ENABLE_PIN #ifndef SPINDLE1_ENABLE_PORT #define SPINDLE1_ENABLE_PORT 0 #endif { .function = Output_Spindle1On, .aux_port = IOPORT_UNASSIGNED, .pin = SPINDLE1_ENABLE_PIN, .port = (void *)SPINDLE1_ENABLE_PORT }, #endif #ifdef SPINDLE1_PWM_PIN #ifndef SPINDLE1_PWM_PORT #define SPINDLE1_PWM_PORT 0 #endif { .function = Output_Spindle1PWM, .aux_port = IOPORT_UNASSIGNED, .pin = SPINDLE1_PWM_PIN, .port = (void *)SPINDLE1_PWM_PORT }, #endif #ifdef SPINDLE1_DIRECTION_PIN #ifndef SPINDLE1_DIRECTION_PORT #define SPINDLE1_DIRECTION_PORT 0 #endif { .function = Output_Spindle1Dir, .aux_port = IOPORT_UNASSIGNED, .pin = SPINDLE1_DIRECTION_PIN, .port = (void *)SPINDLE1_DIRECTION_PORT }, #endif #ifdef COOLANT_FLOOD_PIN #ifndef COOLANT_FLOOD_PORT #define COOLANT_FLOOD_PORT 0 #endif { .function = Output_CoolantFlood, .aux_port = IOPORT_UNASSIGNED, .pin = COOLANT_FLOOD_PIN, .port = (void *)COOLANT_FLOOD_PORT }, #endif #ifdef COOLANT_MIST_PIN #ifndef COOLANT_MIST_PORT #define COOLANT_MIST_PORT 0 #endif { .function = Output_CoolantMist, .aux_port = IOPORT_UNASSIGNED, .pin = COOLANT_MIST_PIN, .port = (void *)COOLANT_MIST_PORT }, #endif #ifdef COPROC_RESET_PIN #ifndef COPROC_RESET_PORT #define COPROC_RESET_PORT 0 #endif { .function = Output_CoProc_Reset, .aux_port = IOPORT_UNASSIGNED, .pin = COPROC_RESET_PIN, .port = (void *)COPROC_RESET_PORT }, #endif #ifdef COPROC_BOOT0_PIN #ifndef COPROC_BOOT0_PORT #define COPROC_BOOT0_PORT 0 #endif { .function = Output_CoProc_Boot0, .aux_port = IOPORT_UNASSIGNED, .pin = COPROC_BOOT0_PIN, .port = (void *)COPROC_BOOT0_PORT }, #endif #if defined(SPI_RST_PIN) && defined(RP2040) #if SPI_RST_PORT == EXPANDER_PORT { .function = Output_SPIRST, .aux_port = IOPORT_UNASSIGNED, .pin = SPI_RST_PIN, .port = (void *)SPI_RST_PORT }, #endif #endif }; static inline aux_ctrl_out_t *aux_out_remap_explicit (void *port, uint8_t pin, uint8_t aux_port, void *output) { aux_ctrl_out_t *ctrl_pin = NULL; uint_fast8_t idx = sizeof(aux_ctrl_out) / sizeof(aux_ctrl_out_t); if(idx) do { idx--; if(aux_ctrl_out[idx].port == port && aux_ctrl_out[idx].pin == pin) { ctrl_pin = &aux_ctrl_out[idx]; ctrl_pin->aux_port = aux_port; ctrl_pin->output = output; } } while(idx && ctrl_pin == NULL); return ctrl_pin; } typedef bool (*aux_claim_explicit_out_ptr)(aux_ctrl_out_t *aux_ctrl); static bool aux_ctrl_claim_out_port (xbar_t *properties, uint8_t port, void *data) { if(((aux_ctrl_out_t *)data)->port == (void *)EXPANDER_PORT) { if(((aux_ctrl_out_t *)data)->pin == properties->pin && properties->set_value) ((aux_ctrl_out_t *)data)->aux_port = port; } else if(ioport_claim(Port_Digital, Port_Output, &port, xbar_fn_to_pinname(((aux_ctrl_out_t *)data)->function))) ((aux_ctrl_out_t *)data)->aux_port = port; return ((aux_ctrl_out_t *)data)->aux_port != 0xFF; } static inline void aux_ctrl_claim_out_ports (aux_claim_explicit_out_ptr aux_claim_explicit, ioports_enumerate_callback_ptr aux_claim) { uint_fast8_t idx; if(aux_claim == NULL) aux_claim = aux_ctrl_claim_out_port; for(idx = 0; idx < sizeof(aux_ctrl_out) / sizeof(aux_ctrl_out_t); idx++) { if(aux_ctrl_out[idx].port == (void *)EXPANDER_PORT) { if(ioports_enumerate(Port_Digital, Port_Output, (pin_cap_t){ .external = On, .claimable = On }, aux_claim, &aux_ctrl_out[idx])) { if((aux_ctrl_out[idx].output = ioport_claim(Port_Digital, Port_Output, &aux_ctrl_out[idx].aux_port, NULL /*xbar_fn_to_pinname(aux_ctrl_out[idx].function)*/))) { ioport_set_function((xbar_t *)aux_ctrl_out[idx].output, aux_ctrl_out[idx].function, NULL); // TODO: else set description? aux_claim_explicit(&aux_ctrl_out[idx]); } } } else if(aux_ctrl_out[idx].pin == 0xFF) { if(ioports_enumerate(Port_Digital, Port_Output, (pin_cap_t){ .claimable = On }, aux_claim, &aux_ctrl_out[idx])) aux_claim_explicit(&aux_ctrl_out[idx]); } else if(aux_ctrl_out[idx].aux_port != 0xFF) aux_claim_explicit(&aux_ctrl_out[idx]); } } // Output Signals #if defined(SPINDLE_ENABLE_PIN) && !defined(SPINDLE_ENABLE_BIT) #define SPINDLE_ENABLE_BIT (1<