From 1444c08997827a5653eea821f4739fdc8a689a78 Mon Sep 17 00:00:00 2001 From: Terje Io Date: Sun, 10 Nov 2024 11:39:21 +0100 Subject: [PATCH] Added generic passthru support for programming external MCU via USB > UART bridge. Requires driver support if to be used. Adds $PTRGH system command when available. --- CMakeLists.txt | 1 + changelog.md | 12 +++ crossbar.h | 4 + grbl.h | 2 +- pin_bits_masks.h | 18 ++-- stream_passthru.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++ stream_passthru.h | 22 +++++ 7 files changed, 258 insertions(+), 7 deletions(-) create mode 100644 stream_passthru.c create mode 100644 stream_passthru.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e619202..cc2763d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,6 +22,7 @@ target_sources(grbl INTERFACE ${CMAKE_CURRENT_LIST_DIR}/state_machine.c ${CMAKE_CURRENT_LIST_DIR}/stream.c ${CMAKE_CURRENT_LIST_DIR}/stream_file.c + ${CMAKE_CURRENT_LIST_DIR}/stream_passthru.c ${CMAKE_CURRENT_LIST_DIR}/stepper.c ${CMAKE_CURRENT_LIST_DIR}/stepper2.c ${CMAKE_CURRENT_LIST_DIR}/system.c diff --git a/changelog.md b/changelog.md index 47ef8a2..51869f5 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,17 @@ ## grblHAL changelog +Build 20241110 + +Core: + +* Added generic passthru support for programming external MCU via USB > UART bridge. Requires driver support if to be used. Adds `$PTRGH` system command when available. + +Plugins: + +* Misc, ESP-AT: general improvements. + +--- + Build 20241107 Core: diff --git a/crossbar.h b/crossbar.h index d210860..e5b476f 100644 --- a/crossbar.h +++ b/crossbar.h @@ -181,6 +181,8 @@ typedef enum { Output_LED_Adressable, Output_LED0_Adressable = Output_LED_Adressable, Output_LED1_Adressable, + Output_CoProc_Reset, + Output_CoProc_Boot0, // Multipin peripherals Input_MISO, Multipin = Input_MISO, @@ -382,6 +384,8 @@ PROGMEM static const pin_name_t pin_names[] = { { .function = Output_LED_W, .name = "LED W" }, { .function = Output_LED_Adressable, .name = "LED adressable" }, { .function = Output_LED1_Adressable, .name = "LED adressable 1" }, + { .function = Output_CoProc_Reset, .name = "CoProc Reset" }, + { .function = Output_CoProc_Boot0, .name = "CoProc Boot0" }, { .function = Input_MISO, .name = "MISO" }, { .function = Output_MOSI, .name = "MOSI" }, { .function = Output_SPICLK, .name = "SPI CLK" }, diff --git a/grbl.h b/grbl.h index 76ddaca..051c780 100644 --- a/grbl.h +++ b/grbl.h @@ -42,7 +42,7 @@ #else #define GRBL_VERSION "1.1f" #endif -#define GRBL_BUILD 20241107 +#define GRBL_BUILD 20241110 #define GRBL_URL "https://github.com/grblHAL" diff --git a/pin_bits_masks.h b/pin_bits_masks.h index 459028d..6be6918 100644 --- a/pin_bits_masks.h +++ b/pin_bits_masks.h @@ -397,23 +397,29 @@ static inline control_signals_t aux_ctrl_scan_status (control_signals_t signals) // The following pins are bound explicitly to aux output pins static aux_ctrl_out_t aux_ctrl_out[] = { #if DRIVER_SPINDLE_ENABLE - { .function = Output_SpindleOn, .aux_port = 0xFF, .pin = SPINDLE_ENABLE_PIN, .port = SPINDLE_ENABLE_PORT }, + { .function = Output_SpindleOn, .aux_port = 0xFF, .pin = SPINDLE_ENABLE_PIN, .port = SPINDLE_ENABLE_PORT }, #if DRIVER_SPINDLE_PWM_ENABLE - { .function = Output_SpindlePWM, .aux_port = 0xFF, .pin = SPINDLE_PWM_PIN, .port = SPINDLE_PWM_PORT }, + { .function = Output_SpindlePWM, .aux_port = 0xFF, .pin = SPINDLE_PWM_PIN, .port = SPINDLE_PWM_PORT }, #endif #if DRIVER_SPINDLE_DIR_ENABLE - { .function = Output_SpindleDir, .aux_port = 0xFF, .pin = SPINDLE_DIRECTION_PIN, .port = SPINDLE_DIRECTION_PORT }, + { .function = Output_SpindleDir, .aux_port = 0xFF, .pin = SPINDLE_DIRECTION_PIN, .port = SPINDLE_DIRECTION_PORT }, #endif #endif // DRIVER_SPINDLE_ENABLE #if DRIVER_SPINDLE1_ENABLE - { .function = Output_Spindle1On, .aux_port = 0xFF, .pin = SPINDLE1_ENABLE_PIN, .port = SPINDLE1_ENABLE_PORT }, + { .function = Output_Spindle1On, .aux_port = 0xFF, .pin = SPINDLE1_ENABLE_PIN, .port = SPINDLE1_ENABLE_PORT }, #if DRIVER_SPINDLE1_PWM_ENABLE - { .function = Output_Spindle1PWM, .aux_port = 0xFF, .pin = SPINDLE1_PWM_PIN, .port = SPINDLE1_PWM_PORT }, + { .function = Output_Spindle1PWM, .aux_port = 0xFF, .pin = SPINDLE1_PWM_PIN, .port = SPINDLE1_PWM_PORT }, #endif #if DRIVER_SPINDLE1_DIR_ENABLE - { .function = Output_Spindle1Dir, .aux_port = 0xFF, .pin = SPINDLE1_DIRECTION_PIN, .port = SPINDLE1_DIRECTION_PORT }, + { .function = Output_Spindle1Dir, .aux_port = 0xFF, .pin = SPINDLE1_DIRECTION_PIN, .port = SPINDLE1_DIRECTION_PORT }, #endif #endif // DRIVER_SPINDLE1_DIR_ENABLE +#ifdef COPROC_RESET_PIN + { .function = Output_CoProc_Reset, .aux_port = 0xFF, .pin = COPROC_RESET_PIN, .port = COPROC_RESET_PORT }, +#endif +#ifdef COPROC_BOOT0_PIN + { .function = Output_CoProc_Boot0, .aux_port = 0xFF, .pin = COPROC_BOOT0_PIN, .port = COPROC_BOOT0_PORT }, +#endif /* #ifdef COOLANT_FLOOD_PIN { .function = Output_CoolantFlood, .aux_port = 0xFF, .pin = COOLANT_FLOOD_PIN, .port = COOLANT_FLOOD_PORT }, diff --git a/stream_passthru.c b/stream_passthru.c new file mode 100644 index 0000000..f8bbe55 --- /dev/null +++ b/stream_passthru.c @@ -0,0 +1,206 @@ +/* + stream_passthru.c - stream redirector for programming coprocessor + + Part of grblHAL + + Copyright (c) 2024 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 "hal.h" +#include "task.h" +#include "protocol.h" + +//static xbar_t *dtr, *rts; +static uint8_t boot0_port = 0xFF, reset_port = 0xFF; +static io_stream_t dest; +static bool conn_ok = false; +static on_linestate_changed_ptr on_linestate_changed; +//static on_execute_realtime_ptr on_execute_realtime = NULL; + +// Weak implementation of low level function to be provided by the driver + +__attribute__((weak)) void stream_passthru_enter (void) +{ + // The driver implementation calls stream_passthru_init() with start parameter set true after setting up for execution. +} + +// **** + + +/* +static void onExecuteRealtime (uint_fast16_t state) +{ + static bool lock = false; + + int16_t c; + + if(!lock) { + lock = true; + if((c = hal.stream.read()) != SERIAL_NO_DATA) + dest.write_char(c); + lock = false; + } + + on_execute_realtime(state); +} +*/ + +ISR_CODE static bool ISR_FUNC(forward_usb_rx)(char c) +{ + dest.write_char(c); + + return true; +} + +ISR_CODE static bool ISR_FUNC(sink_uart_rx)(char c) +{ + return true; +} + +static void forward_uart_rx (void *data) +{ + static char buf[64]; + static uint_fast8_t idx = 0; + + int16_t c; + + while((c = dest.read()) != SERIAL_NO_DATA) { + + idx = 1; + *buf = c; + + while(idx < sizeof(buf) && (c = dest.read()) != SERIAL_NO_DATA) + buf[idx++] = c; + + hal.stream.write_n(buf, idx); + } + + task_add_delayed(forward_uart_rx, NULL, 8); +} + +static void onLinestateChanged (serial_linestate_t state) +{ + /* + Auto program + DTR RTS-->EN IO0 + 1 1 1 1 + 0 0 1 1 + 1 0 0 1 + 0 1 1 0 + */ + if(conn_ok) { + + if(state.dtr == state.rts) { + hal.port.digital_out(boot0_port, 0); + hal.port.digital_out(reset_port, 1); + } else if(state.dtr) { + hal.port.digital_out(reset_port, 0); + hal.port.digital_out(boot0_port, 0); + } else { + hal.port.digital_out(boot0_port, 0); + hal.port.digital_out(reset_port, 1); + } + } +} + +static void passthru_start2 (void *data) +{ + conn_ok = true; + hal.port.digital_out(reset_port, 1); + + task_add_delayed(forward_uart_rx, NULL, 8); + +// on_execute_realtime = grbl.on_execute_realtime; +// grbl.on_execute_realtime = onExecuteRealtime; + + dest.set_enqueue_rt_handler(stream_buffer_all); + dest.cancel_read_buffer(); +} + +static void passthru_start1 (void *data) +{ + hal.port.digital_out(boot0_port, 0); + hal.port.digital_out(reset_port, 0); + + on_linestate_changed = hal.stream.on_linestate_changed; + hal.stream.on_linestate_changed = onLinestateChanged; + + task_add_delayed(passthru_start2, NULL, 1250); // delay a bit to allow the USB stack to start +} + +static bool get_ports (xbar_t *properties, uint8_t port, void *data) +{ + switch(properties->function) { + + case Output_CoProc_Reset: + reset_port = port; + break; + + case Output_CoProc_Boot0: + boot0_port = port; + break; + + default: + break; + } + + return boot0_port != 0xFF && reset_port != 0xFF; +} + +static status_code_t passthru_enter (sys_state_t state, char *args) +{ + report_message("Entering passthru mode", Message_Warning); + hal.delay_ms(100, NULL); + + stream_passthru_enter(); + + return Status_OK; +} + +void stream_passthru_init (uint8_t instance, uint32_t baud_rate, bool start) +{ + static const sys_command_t passthru_command_list[] = { + {"PTRGH", passthru_enter, { .noargs = On }, { .str = "enter passthru mode" } } + }; + + static sys_commands_t passthru_commands = { + .n_commands = sizeof(passthru_command_list) / sizeof(sys_command_t), + .commands = passthru_command_list + }; + + if(hal.stream.type == StreamType_Serial && + hal.stream.state.is_usb && + hal.stream.state.linestate_event && + ioports_enumerate(Port_Digital, Port_Output, (pin_cap_t){ .output = On }, get_ports, NULL)) { + + if(start) { + + io_stream_t const *stream = stream_open_instance(instance, baud_rate, NULL, "Passthru"); + + if(stream != NULL) { + + protocol_enqueue_foreground_task(passthru_start1, NULL); // enter passthrouh mode after finished booting grblHAL + + memcpy(&dest, stream, sizeof(io_stream_t)); + dest.set_enqueue_rt_handler(sink_uart_rx); + hal.stream.set_enqueue_rt_handler(forward_usb_rx); + } else + report_message("Entering passthru mode failed!", Message_Warning); + + } else + system_register_commands(&passthru_commands); + } +} diff --git a/stream_passthru.h b/stream_passthru.h new file mode 100644 index 0000000..e9caadd --- /dev/null +++ b/stream_passthru.h @@ -0,0 +1,22 @@ +/* + stream_passthru.h - stream redirector for programming coprocessor + + Part of grblHAL + + Copyright (c) 2024 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 . +*/ + +void stream_passthru_init (uint8_t instance, uint32_t baud_rate, bool start);