diff --git a/.gitignore b/.gitignore index b54877c5..0a6475fe 100755 --- a/.gitignore +++ b/.gitignore @@ -53,3 +53,5 @@ Tools/gcc-arm-none-eabi-*.tar.bz2 */TinyG2.componentinfo.xml g2core/g2core.componentinfo.xml .tags + +g2core/compile_commands.json diff --git a/Motate b/Motate index 1540f1af..18c93112 160000 --- a/Motate +++ b/Motate @@ -1 +1 @@ -Subproject commit 1540f1af7fd2213a704fc8585513effae041f9f1 +Subproject commit 18c93112f1e1e13eb0fa740e185c4b973e4419fc diff --git a/README.md b/README.md index 9d70f08d..6592e57f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +g2core + [![Build Status](https://travis-ci.org/synthetos/g2.svg?branch=edge)](https://travis-ci.org/synthetos/g2) [![Issues in Ready](https://badge.waffle.io/synthetos/g2.svg?label=ready&title=Ready)](http://waffle.io/synthetos/g2) [![Issues in Progress](https://badge.waffle.io/synthetos/g2.svg?label=in%20progress&title=In%20Progress)](http://waffle.io/synthetos/g2) # g2core - Edge Branch diff --git a/Resources/debug/mb_analyze.py b/Resources/debug/mb_analyze.py index 13ab4deb..3e3368cb 100644 --- a/Resources/debug/mb_analyze.py +++ b/Resources/debug/mb_analyze.py @@ -25,13 +25,13 @@ def load_pool(filename): if buf: current_buffer = int(buf.groups()[0], 16) pool[TUMBLER[tumbler_pos]] = current_buffer - # print "TUMBLER[tumbler_pos]: %s=%i" % (TUMBLER[tumbler_pos], current_buffer) + print "TUMBLER[tumbler_pos]: %s=%i" % (TUMBLER[tumbler_pos], current_buffer) tumbler_pos += 1 else: buf = re.search('\(mpBuf_t\s\*\)\s(0x[0-9a-fA-F]+)', line) if buf: current_buffer = int(buf.groups()[0], 16) - # print "setup current_buffer: %s" % current_buffer + print "setup current_buffer: %s" % current_buffer pool[current_buffer] = {'move_time': 0} if current_buffer == pool['r']: pool[current_buffer]['is_r'] = True @@ -49,9 +49,11 @@ def load_pool(filename): if key == 'pv': pv = int(val, 16) pool[current_buffer]['pv'] = pv + print "pv: %s" % pv elif key == 'nx': - nv = int(val, 16) - pool[current_buffer]['nx'] = nv + nx = int(val, 16) + pool[current_buffer]['nx'] = nx + print "nx: %s" % nx elif key == 'buffer_state': pool[current_buffer]['buffer_state'] = val elif key == 'jerk': @@ -60,6 +62,7 @@ def load_pool(filename): pool[current_buffer]['linenum'] = val elif key == 'buffer_number': pool[current_buffer]['buffer_number'] = val + print "#: %s" % val elif key == 'junction_vmax': pool[current_buffer]['junction_vmax'] = float(val) elif key == 'cruise_velocity': diff --git a/g2core.atsln b/g2core.atsln old mode 100755 new mode 100644 index ca5ee57b..93cd6ae1 --- a/g2core.atsln +++ b/g2core.atsln @@ -3,9 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "g2core", "g2core\g2core.cppproj", "{44EA8FEC-55D7-4149-8A78-A574FC26BF51}" - ProjectSection(ProjectDependencies) = postProject - {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0} = {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0} - EndProjectSection EndProject Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "Motate", "Motate\Motate.cppproj", "{D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}" EndProject @@ -22,6 +19,7 @@ Global Shapeoko2|ARM = Shapeoko2|ARM shopbotShield|ARM = shopbotShield|ARM Stub|ARM = Stub|ARM + TestQuadratic|ARM = TestQuadratic|ARM TestQuintic|ARM = TestQuintic|ARM TestV9|ARM = TestV9|ARM Ultimakerv9k|ARM = Ultimakerv9k|ARM @@ -49,6 +47,8 @@ Global {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.shopbotShield|ARM.ActiveCfg = shopbotShield|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.shopbotShield|ARM.Build.0 = shopbotShield|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.Stub|ARM.ActiveCfg = Shapeoko2|ARM + {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.TestQuadratic|ARM.ActiveCfg = TestQuadratic|ARM + {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.TestQuadratic|ARM.Build.0 = TestQuadratic|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.TestQuintic|ARM.ActiveCfg = TestQuintic|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.TestQuintic|ARM.Build.0 = TestQuintic|ARM {44EA8FEC-55D7-4149-8A78-A574FC26BF51}.TestV9|ARM.ActiveCfg = TestV9|ARM @@ -68,6 +68,7 @@ Global {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.Shapeoko2|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.shopbotShield|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.Stub|ARM.ActiveCfg = Stub|ARM + {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.TestQuadratic|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.TestQuintic|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.TestV9|ARM.ActiveCfg = Stub|ARM {D7779B24-5CD6-4A1B-893C-2CAE8CF7A3A0}.Ultimakerv9k|ARM.ActiveCfg = Stub|ARM diff --git a/g2core/board/Archim/board_xio.cpp b/g2core/board/Archim/board_xio.cpp old mode 100755 new mode 100644 index 11599fb7..87ab4dd3 --- a/g2core/board/Archim/board_xio.cpp +++ b/g2core/board/Archim/board_xio.cpp @@ -42,20 +42,23 @@ const Motate::USBSettings_t Motate::USBSettings = { }; /*gProductVersion = */ //0.1, -//Motate::USBDevice< Motate::USBCDC > usb; -Motate::USBDevice< Motate::USBCDC, Motate::USBCDC > usb; +XIOUSBDevice_t usb; + +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif + decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; -// 115200 is the default, as well. -//UART Serial {115200, UARTMode::RTSCTSFlowControl}; - -MOTATE_SET_USB_VENDOR_STRING({'S', 'y', 'n', 't', 'h', 'e', 't', 'o', 's'}) -MOTATE_SET_USB_PRODUCT_STRING({'T', 'i', 'n', 'y', 'G', ' ', 'v', '2'}) +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() #endif // XIO_HAS_USB + //******** SPI ******** #if XIO_HAS_SPI Motate::SPI spi; diff --git a/g2core/board/Archim/board_xio.h b/g2core/board/Archim/board_xio.h index 102698d3..09f20fef 100755 --- a/g2core/board/Archim/board_xio.h +++ b/g2core/board/Archim/board_xio.h @@ -29,15 +29,25 @@ #ifndef board_xio_h #define board_xio_h +#include "settings.h" + //******** USB ******** #if XIO_HAS_USB #include "MotateUSB.h" #include "MotateUSBCDC.h" -// extern Motate::USBDevice< Motate::USBCDC > usb; -extern Motate::USBDevice usb; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif + +extern XIOUSBDevice_t usb; extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif #endif // XIO_HAS_USB diff --git a/g2core/board/Archim/hardware.h b/g2core/board/Archim/hardware.h old mode 100755 new mode 100644 index d66cae7d..6da17870 --- a/g2core/board/Archim/hardware.h +++ b/g2core/board/Archim/hardware.h @@ -126,9 +126,8 @@ using Motate::OutputPin; // Timer definitions. See stepper.h and other headers for setup typedef TimerChannel<3,0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<4,0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp -typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp +typedef TimerChannel<4,0> load_timer_type; // request load timer in stepper.cpp +typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp // Pin assignments diff --git a/g2core/board/ArduinoDue/board_xio.cpp b/g2core/board/ArduinoDue/board_xio.cpp index 04d9a326..7f2a0774 100755 --- a/g2core/board/ArduinoDue/board_xio.cpp +++ b/g2core/board/ArduinoDue/board_xio.cpp @@ -32,27 +32,31 @@ #include "board_xio.h" //******** USB ******** +#if XIO_HAS_USB const Motate::USBSettings_t Motate::USBSettings = { /*gVendorID = */ 0x1d50, /*gProductID = */ 0x606d, /*gProductVersion = */ G2CORE_FIRMWARE_VERSION, /*gAttributes = */ kUSBConfigAttributeSelfPowered, - /*gPowerConsumption = */ 500}; -/*gProductVersion = */ // 0.1, + /*gPowerConsumption = */ 500 +}; +/*gProductVersion = */ //0.1, -// Motate::USBDevice< Motate::USBCDC > usb; -Motate::USBDevice usb; +XIOUSBDevice_t usb; -decltype(usb.mixin<0>::Serial)& SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial)& SerialUSB1 = usb.mixin<1>::Serial; - -// 115200 is the default, as well. -// UART Serial {115200, UARTMode::RTSCTSFlowControl}; +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif -MOTATE_SET_USB_VENDOR_STRING({'S', 'y', 'n', 't', 'h', 'e', 't', 'o', 's'}) -MOTATE_SET_USB_PRODUCT_STRING({'T', 'i', 'n', 'y', 'G', ' ', 'v', '2'}) +decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; + +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() +#endif // XIO_HAS_USB diff --git a/g2core/board/ArduinoDue/board_xio.h b/g2core/board/ArduinoDue/board_xio.h index a7bf7959..31afd8c8 100755 --- a/g2core/board/ArduinoDue/board_xio.h +++ b/g2core/board/ArduinoDue/board_xio.h @@ -29,15 +29,26 @@ #ifndef board_xio_h #define board_xio_h +#include "settings.h" + //******** USB ******** +#if XIO_HAS_USB #include "MotateUSB.h" #include "MotateUSBCDC.h" -// extern Motate::USBDevice< Motate::USBCDC > usb; -extern Motate::USBDevice usb; -extern decltype(usb.mixin<0>::Serial)& SerialUSB; -extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif +extern XIOUSBDevice_t usb; +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif +#endif // XIO_HAS_USB //******** SPI ******** diff --git a/g2core/board/ArduinoDue/hardware.h b/g2core/board/ArduinoDue/hardware.h old mode 100755 new mode 100644 index 1b5bbe6b..e01e70d4 --- a/g2core/board/ArduinoDue/hardware.h +++ b/g2core/board/ArduinoDue/hardware.h @@ -128,9 +128,8 @@ using Motate::OutputPin; // Timer definitions. See stepper.h and other headers for setup typedef TimerChannel<3,0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<4,0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp -typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp +typedef TimerChannel<4,0> load_timer_type; // request load timer in stepper.cpp +typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp // Pin assignments diff --git a/g2core/board/G2v9/board_xio.cpp b/g2core/board/G2v9/board_xio.cpp index 04d9a326..09ccaf80 100755 --- a/g2core/board/G2v9/board_xio.cpp +++ b/g2core/board/G2v9/board_xio.cpp @@ -32,28 +32,31 @@ #include "board_xio.h" //******** USB ******** +#if XIO_HAS_USB const Motate::USBSettings_t Motate::USBSettings = { /*gVendorID = */ 0x1d50, /*gProductID = */ 0x606d, /*gProductVersion = */ G2CORE_FIRMWARE_VERSION, /*gAttributes = */ kUSBConfigAttributeSelfPowered, - /*gPowerConsumption = */ 500}; -/*gProductVersion = */ // 0.1, + /*gPowerConsumption = */ 500 +}; +/*gProductVersion = */ //0.1, -// Motate::USBDevice< Motate::USBCDC > usb; -Motate::USBDevice usb; +XIOUSBDevice_t usb; -decltype(usb.mixin<0>::Serial)& SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial)& SerialUSB1 = usb.mixin<1>::Serial; - -// 115200 is the default, as well. -// UART Serial {115200, UARTMode::RTSCTSFlowControl}; +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif -MOTATE_SET_USB_VENDOR_STRING({'S', 'y', 'n', 't', 'h', 'e', 't', 'o', 's'}) -MOTATE_SET_USB_PRODUCT_STRING({'T', 'i', 'n', 'y', 'G', ' ', 'v', '2'}) +decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; + +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() - +#endif // XIO_HAS_USB //******** SPI ******** diff --git a/g2core/board/G2v9/board_xio.h b/g2core/board/G2v9/board_xio.h index a7bf7959..09f20fef 100755 --- a/g2core/board/G2v9/board_xio.h +++ b/g2core/board/G2v9/board_xio.h @@ -29,15 +29,26 @@ #ifndef board_xio_h #define board_xio_h +#include "settings.h" + //******** USB ******** +#if XIO_HAS_USB #include "MotateUSB.h" #include "MotateUSBCDC.h" -// extern Motate::USBDevice< Motate::USBCDC > usb; -extern Motate::USBDevice usb; -extern decltype(usb.mixin<0>::Serial)& SerialUSB; -extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif +extern XIOUSBDevice_t usb; +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif +#endif // XIO_HAS_USB //******** SPI ******** @@ -52,9 +63,8 @@ extern Motate::SPI spi; extern Motate::UART Serial; #endif - - //******* Generic Functions ******* -void board_xio_init(void); +void board_hardware_init(void); // called 1st +void board_xio_init(void); // called later #endif // board_xio_h diff --git a/g2core/board/G2v9/hardware.cpp b/g2core/board/G2v9/hardware.cpp index 580ed646..45d63c37 100755 --- a/g2core/board/G2v9/hardware.cpp +++ b/g2core/board/G2v9/hardware.cpp @@ -43,6 +43,7 @@ void hardware_init() { + board_hardware_init(); return; } diff --git a/g2core/board/G2v9/hardware.h b/g2core/board/G2v9/hardware.h index 17ac7bf3..b8f19f4a 100644 --- a/g2core/board/G2v9/hardware.h +++ b/g2core/board/G2v9/hardware.h @@ -129,9 +129,8 @@ using Motate::OutputPin; // Timer definitions. See stepper.h and other headers for setup typedef TimerChannel<3,0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<4,0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp -typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp +typedef TimerChannel<4,0> load_timer_type; // request load timer in stepper.cpp +typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp // Pin assignments diff --git a/g2core/board/gquadratic.mk b/g2core/board/gquadratic.mk index 14bae333..9527cdc1 100755 --- a/g2core/board/gquadratic.mk +++ b/g2core/board/gquadratic.mk @@ -12,15 +12,15 @@ ########## # BOARDs for use directly from the make command line (with default settings) or by CONFIGs. -ifeq ("$(BOARD)","gquadratic-a") +ifeq ("$(BOARD)","gquadratic-b") BASE_BOARD=gquadratic - DEVICE_DEFINES += MOTATE_BOARD="gquadratic-a" + DEVICE_DEFINES += MOTATE_BOARD="gquadratic-b" DEVICE_DEFINES += SETTINGS_FILE=${SETTINGS_FILE} endif ########## -# The general pboard-a BASE_BOARD. +# The general gquadratic BASE_BOARD. ifeq ("$(BASE_BOARD)","gquadratic") _BOARD_FOUND = 1 @@ -34,7 +34,7 @@ ifeq ("$(BASE_BOARD)","gquadratic") CHIP_LOWERCASE = sams70n19 BOARD_PATH = ./board/gquadratic - SOURCE_DIRS += ${BOARD_PATH} device/step_dir_driver + SOURCE_DIRS += ${BOARD_PATH} device/step_dir_driver device/step_dir_hobbyservo device/neopixel PLATFORM_BASE = ${MOTATE_PATH}/platform/atmel_sam include $(PLATFORM_BASE).mk diff --git a/g2core/board/gquadratic/board_stepper.cpp b/g2core/board/gquadratic/board_stepper.cpp index 183d946c..bc927558 100755 --- a/g2core/board/gquadratic/board_stepper.cpp +++ b/g2core/board/gquadratic/board_stepper.cpp @@ -47,15 +47,8 @@ StepDirStepper motor_2{}; -// StepDirStepper< -// Motate::kSocket3_StepPinNumber, -// Motate::kSocket3_DirPinNumber, -// Motate::kSocket3_EnablePinNumber, -// Motate::kSocket3_Microstep_0PinNumber, -// Motate::kSocket3_Microstep_1PinNumber, -// Motate::kSocket3_Microstep_2PinNumber, -// Motate::kSocket3_VrefPinNumber> motor_3 {}; -// +StepDirHobbyServo motor_3; + // StepDirStepper< // Motate::kSocket4_StepPinNumber, // Motate::kSocket4_DirPinNumber, @@ -83,7 +76,7 @@ StepDirStepper motor_6 {}; -Stepper* Motors[MOTORS] = {&motor_1, &motor_2}; +Stepper* Motors[MOTORS] = {&motor_1, &motor_2, &motor_3}; void board_stepper_init() { for (uint8_t motor = 0; motor < MOTORS; motor++) { Motors[motor]->init(); } diff --git a/g2core/board/gquadratic/board_stepper.h b/g2core/board/gquadratic/board_stepper.h index 1282ff0e..6e044efa 100755 --- a/g2core/board/gquadratic/board_stepper.h +++ b/g2core/board/gquadratic/board_stepper.h @@ -30,6 +30,7 @@ #include "hardware.h" // for MOTORS #include "step_dir_driver.h" +#include "step_dir_hobbyservo.h" extern StepDirStepper motor_2; -// extern StepDirStepper< -// Motate::kSocket3_StepPinNumber, -// Motate::kSocket3_DirPinNumber, -// Motate::kSocket3_EnablePinNumber, -// Motate::kSocket3_Microstep_0PinNumber, -// Motate::kSocket3_Microstep_1PinNumber, -// Motate::kSocket3_Microstep_2PinNumber, -// Motate::kSocket3_VrefPinNumber> motor_3; -// -// extern StepDirStepper< -// Motate::kSocket4_StepPinNumber, -// Motate::kSocket4_DirPinNumber, -// Motate::kSocket4_EnablePinNumber, -// Motate::kSocket4_Microstep_0PinNumber, -// Motate::kSocket4_Microstep_1PinNumber, -// Motate::kSocket4_Microstep_2PinNumber, -// Motate::kSocket4_VrefPinNumber> motor_4; -// + extern StepDirHobbyServo motor_3; + // extern StepDirStepper< // Motate::kSocket5_StepPinNumber, // Motate::kSocket5_DirPinNumber, @@ -89,4 +74,4 @@ extern Stepper* Motors[MOTORS]; void board_stepper_init(); -#endif // BOARD_STEPPER_H_ONCE \ No newline at end of file +#endif // BOARD_STEPPER_H_ONCE diff --git a/g2core/board/gquadratic/board_xio.cpp b/g2core/board/gquadratic/board_xio.cpp index 028c60a5..8b4835b2 100755 --- a/g2core/board/gquadratic/board_xio.cpp +++ b/g2core/board/gquadratic/board_xio.cpp @@ -42,20 +42,23 @@ const Motate::USBSettings_t Motate::USBSettings = { }; /*gProductVersion = */ //0.1, -//Motate::USBDevice< Motate::USBCDC > usb; -Motate::USBDevice< Motate::USBCDC, Motate::USBCDC > usb; +XIOUSBDevice_t usb; + +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif + decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; -// 115200 is the default, as well. -//UART Serial {115200, UARTMode::RTSCTSFlowControl}; - -MOTATE_SET_USB_VENDOR_STRING( u"Synthetos (http://synthetos.com)" ) -MOTATE_SET_USB_PRODUCT_STRING( u"g2core gQuadratic" ) +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() #endif // XIO_HAS_USB + //******** SPI ******** #if XIO_HAS_SPI Motate::SPI spi; @@ -64,14 +67,14 @@ Motate::SPI spi; //******** UART ******** #if XIO_HAS_UART -Motate::UART Serial {115200, Motate::UARTMode::RTSCTSFlowControl}; +Motate::UART Serial {115200, Motate::UARTMode::RTSCTSFlowControl}; #endif void board_hardware_init(void) // called 1st { #if XIO_HAS_USB // Init USB - usb.attach(); // USB setup. Runs in "background" as the rest of this executes + usb.attach(); #endif // XIO_HAS_USB } diff --git a/g2core/board/gquadratic/board_xio.h b/g2core/board/gquadratic/board_xio.h index dc57cd3c..09f20fef 100755 --- a/g2core/board/gquadratic/board_xio.h +++ b/g2core/board/gquadratic/board_xio.h @@ -29,15 +29,25 @@ #ifndef board_xio_h #define board_xio_h +#include "settings.h" + //******** USB ******** #if XIO_HAS_USB #include "MotateUSB.h" #include "MotateUSBCDC.h" -// extern Motate::USBDevice< Motate::USBCDC > usb; -extern Motate::USBDevice usb; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif + +extern XIOUSBDevice_t usb; extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif #endif // XIO_HAS_USB @@ -50,7 +60,7 @@ extern Motate::SPI spi; //******** UART ******** #if XIO_HAS_UART #include "MotateUART.h" -extern Motate::UART Serial; +extern Motate::UART Serial; #endif //******* Generic Functions ******* diff --git a/g2core/board/gquadratic/gquadratic-a-pinout.h b/g2core/board/gquadratic/gquadratic-a-pinout.h deleted file mode 100755 index 600accfe..00000000 --- a/g2core/board/gquadratic/gquadratic-a-pinout.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * gquadratic-a-pinout.h - board pinout specification - * This file is part of the g2core project - * - * Copyright (c) 2016 Robert Giseburt - * Copyright (c) 2016 Alden S. Hart Jr. - * - * This file is part of the Motate Library. - * - * This file ("the software") is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2 as published by the - * Free Software Foundation. You should have received a copy of the GNU General Public - * License, version 2 along with the software. If not, see . - * - * As a special exception, you may use this file as part of a software library without - * restriction. Specifically, if other files instantiate templates or use macros or - * inline functions from this file, or you compile this file and link it with other - * files to produce an executable, this file does not by itself cause the resulting - * executable to be covered by the GNU General Public License. This exception does not - * however invalidate any other reasons why the executable file might be covered by the - * GNU General Public License. - * - * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY - * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES - * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF - * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - */ - -#ifndef GQUADRATIC_A_PINOUT_H -#define GQUADRATIC_A_PINOUT_H - -/* - * USAGE NOTES - * - * Read this first: - * https://github.com/synthetos/g2/wiki/Adding-a-new-G2-board-(or-revision)-to-G2#making-a-new-pin-assignment - * - * USAGE: - * - * This file is lays out all the pin capabilities of the SAM3X8C organized by pin number. - * Each pin has its associated functions listed at the bottom of the file, and is essentially - * immutable for each processor. - * - * To use, assign Motate pin numbers to the first value in the _MAKE_MOTATE_PIN() macro. - * ALL PINS MUST BE ASSIGNED A NUMBER, even if they are not used. There will NOT be a - * code-size or speed penalty for unused pins, but the WILL be a compiler-failure for - * unassigned pins. This new restriction allows for simplification of linkages deep in - * Motate. - */ -/* See motate_pin_assignments.h for pin names to be used int he rest of the G2 code. - * EXAMPLES: - * - * *** Vanilla pin example *** - * - * _MAKE_MOTATE_PIN(4, A, 'A', 27); // SPI0_SCKPinNumber - * - * This assigns Motate pin 4 to Port A, pin 27 (A27) - * Look in motate_pin_assignments.h to see that this is kSPI_SCKPinNumber - * - * ** Other pin functions *** - * - * Please look in /platform/atmel_sam/motate_chip_pin_functions.h - */ - - -#include - -// We don't have all of the inputs, so we have to indicate as much: -#define INPUT1_AVAILABLE 1 -#define INPUT2_AVAILABLE 1 -#define INPUT3_AVAILABLE 1 -#define INPUT4_AVAILABLE 1 -#define INPUT5_AVAILABLE 0 -#define INPUT6_AVAILABLE 0 -#define INPUT7_AVAILABLE 0 -#define INPUT8_AVAILABLE 0 -#define INPUT9_AVAILABLE 0 -#define INPUT10_AVAILABLE 0 -#define INPUT11_AVAILABLE 0 -#define INPUT12_AVAILABLE 0 -#define INPUT13_AVAILABLE 0 - - -#define ADC0_AVAILABLE 0 -#define ADC1_AVAILABLE 0 -#define ADC2_AVAILABLE 0 -#define ADC3_AVAILABLE 0 - -#define XIO_HAS_USB 1 -#define XIO_HAS_UART 1 -#define XIO_HAS_SPI 0 -#define XIO_HAS_I2C 0 - -#define TEMPERATURE_OUTPUT_ON 0 // NO ADC yet - -// Some pins, if the PWM capability is turned on, it will cause timer conflicts. -// So we have to explicitly enable them as PWM pins. -// Generated with: -// perl -e 'for($i=1;$i<14;$i++) { print "#define OUTPUT${i}_PWM 0\n";}' -#define OUTPUT1_PWM 1 // Timer0ch0 -#define OUTPUT2_PWM 1 // PWM0.0 -#define OUTPUT3_PWM 1 // Timer0ch1 -#define OUTPUT4_PWM 1 // PWM1.3 -#define OUTPUT5_PWM 0 // unused -#define OUTPUT6_PWM 0 // unused -#define OUTPUT7_PWM 0 // unused -#define OUTPUT8_PWM 0 // unused -#define OUTPUT9_PWM 0 // unused -#define OUTPUT10_PWM 0 // unused -#define OUTPUT11_PWM 0 // unused -#define OUTPUT12_PWM 0 // Unused -#define OUTPUT13_PWM 0 // Unused - -namespace Motate { - -// Arduino pin name & function -_MAKE_MOTATE_PIN(kOutput1_PinNumber, 'A', 0); // -_MAKE_MOTATE_PIN(kOutput3_PinNumber, 'A', 1); // -_MAKE_MOTATE_PIN(kSocket2_VrefPinNumber, 'A', 2); // -_MAKE_MOTATE_PIN(kI2C1_SDAPinNumber, 'A', 3); // -_MAKE_MOTATE_PIN(kI2C1_SCLPinNumber, 'A', 4); // -_MAKE_MOTATE_PIN(kOutput4_PinNumber, 'A', 5); // -_MAKE_MOTATE_PIN(kUnassigned1, 'A', 6); // Missing in 100-pin package -_MAKE_MOTATE_PIN(kUnassigned2, 'A', 7); // -_MAKE_MOTATE_PIN(kUnassigned3, 'A', 8); // -_MAKE_MOTATE_PIN(kSerial_RX, 'A', 9); // -_MAKE_MOTATE_PIN(kSerial_TX, 'A', 10); // -_MAKE_MOTATE_PIN(kSocket1_Microstep_1PinNumber, 'A', 11); // -_MAKE_MOTATE_PIN(kSocket1_EnablePinNumber, 'A', 12); // -_MAKE_MOTATE_PIN(kUnassigned4, 'A', 13); // -_MAKE_MOTATE_PIN(kUnassigned6, 'A', 14); // -_MAKE_MOTATE_PIN(kUnassigned5, 'A', 15); // -_MAKE_MOTATE_PIN(kUnassigned7, 'A', 16); // -_MAKE_MOTATE_PIN(kUnassigned8, 'A', 17); // -_MAKE_MOTATE_PIN(kUnassigned9, 'A', 18); // -_MAKE_MOTATE_PIN(kUnassigned10, 'A', 19); // -_MAKE_MOTATE_PIN(kUnassigned11, 'A', 20); // -_MAKE_MOTATE_PIN(kUnassigned13, 'A', 21); // -_MAKE_MOTATE_PIN(kUnassigned12, 'A', 22); // -_MAKE_MOTATE_PIN(kUnassigned14, 'A', 23); // -_MAKE_MOTATE_PIN(kUnassigned15, 'A', 24); // -_MAKE_MOTATE_PIN(kUnassigned16, 'A', 25); // -_MAKE_MOTATE_PIN(kUnassigned17, 'A', 26); // -_MAKE_MOTATE_PIN(kSocket1_VrefPinNumber, 'A', 27); // -_MAKE_MOTATE_PIN(kSerial_CTS, 'A', 28); // -_MAKE_MOTATE_PIN(kUnassigned18, 'A', 29); // Missing in 100-pin package -_MAKE_MOTATE_PIN(kSerial_RTS, 'A', 30); // -_MAKE_MOTATE_PIN(kOutputSAFE_PinNumber, 'A', 31); // - -_MAKE_MOTATE_PIN(kUnassigned20, 'B', 0); // -_MAKE_MOTATE_PIN(kUnassigned22, 'B', 1); // -_MAKE_MOTATE_PIN(kUnassigned21, 'B', 2); // -_MAKE_MOTATE_PIN(kUnassigned23, 'B', 3); // -//_MAKE_MOTATE_PIN( , 'B', 4); // TDI -//_MAKE_MOTATE_PIN( , 'B', 5); // TRACESDO -//_MAKE_MOTATE_PIN( , 'B', 6); // SWDIO -//_MAKE_MOTATE_PIN( , 'B', 7); // SWDCLK -//_MAKE_MOTATE_PIN( , 'B', 8); // XOUT -//_MAKE_MOTATE_PIN( , 'B', 9); // XIN -//_MAKE_MOTATE_PIN( , 'B', 10); // USB_D- -//_MAKE_MOTATE_PIN( , 'B', 11); // USB_D+ -//_MAKE_MOTATE_PIN( , 'B', 12); // ERASE -_MAKE_MOTATE_PIN(kUnassigned38, 'B', 13); // LED_1 (Heartbeat) - PWM2 - -//_MAKE_MOTATE_PIN( , 'D', 0); // USB_VBUS -_MAKE_MOTATE_PIN(kInput1_PinNumber, 'D', 1); // -_MAKE_MOTATE_PIN(kInput2_PinNumber, 'D', 2); // -_MAKE_MOTATE_PIN(kUnassigned24, 'D', 3); // -_MAKE_MOTATE_PIN(kUnassigned25, 'D', 4); // -_MAKE_MOTATE_PIN(kUnassigned26, 'D', 5); // -_MAKE_MOTATE_PIN(kInput3_PinNumber, 'D', 6); // -_MAKE_MOTATE_PIN(kInput4_PinNumber, 'D', 7); // -_MAKE_MOTATE_PIN(kUnassigned19, 'D', 8); // INTERRUPT_OUT -_MAKE_MOTATE_PIN(kUnassigned27, 'D', 9); // -_MAKE_MOTATE_PIN(kOutput2_PinNumber, 'D', 10); // -_MAKE_MOTATE_PIN(kUnassigned28, 'D', 11); // -_MAKE_MOTATE_PIN(kSocket2_DirPinNumber, 'D', 12); // -_MAKE_MOTATE_PIN(kSocket2_EnablePinNumber, 'D', 13); // -_MAKE_MOTATE_PIN(kSocket2_StepPinNumber, 'D', 14); // -_MAKE_MOTATE_PIN(kUnassigned29, 'D', 15); // -_MAKE_MOTATE_PIN(kSocket2_Microstep_0PinNumber, 'D', 16); // -_MAKE_MOTATE_PIN(kSocket2_Microstep_1PinNumber, 'D', 17); // -_MAKE_MOTATE_PIN(kSocket1_DirPinNumber, 'D', 18); // -_MAKE_MOTATE_PIN(kSocket1_StepPinNumber, 'D', 19); // -_MAKE_MOTATE_PIN(kSocket1_Microstep_0PinNumber, 'D', 20); // -_MAKE_MOTATE_PIN(kSocket1_Microstep_2PinNumber, 'D', 21); // -_MAKE_MOTATE_PIN(kUnassigned30, 'D', 22); // -_MAKE_MOTATE_PIN(kUnassigned31, 'D', 23); // Missing in 100-pin package -_MAKE_MOTATE_PIN(kUnassigned32, 'D', 24); // -_MAKE_MOTATE_PIN(kUnassigned33, 'D', 25); // -_MAKE_MOTATE_PIN(kUnassigned34, 'D', 26); // -_MAKE_MOTATE_PIN(kUnassigned35, 'D', 27); // -_MAKE_MOTATE_PIN(kSocket2_Microstep_2PinNumber, 'D', 28); // -_MAKE_MOTATE_PIN(kUnassigned36, 'D', 29); // Missing in 100-pin package -_MAKE_MOTATE_PIN(kLEDPWM_PinNumber, 'D', 30); // -_MAKE_MOTATE_PIN(kUnassigned37, 'D', 31); // - -} // namespace Motate - -// We then allow each chip-type to have it's onw function definitions -// that will refer to these pin assignments. -#include "motate_chip_pin_functions.h" - -#endif - -// GQUADRATIC_A_PINOUT_H diff --git a/g2core/board/gquadratic/gquadratic-b-pinout.h b/g2core/board/gquadratic/gquadratic-b-pinout.h new file mode 100755 index 00000000..0eaa3c5d --- /dev/null +++ b/g2core/board/gquadratic/gquadratic-b-pinout.h @@ -0,0 +1,209 @@ +/* + * gquadratic-b-pinout.h - board pinout specification + * This file is part of the g2core project + * + * Copyright (c) 2016 Robert Giseburt + * Copyright (c) 2016 Alden S. Hart Jr. + * + * This file is part of the Motate Library. + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * As a special exception, you may use this file as part of a software library without + * restriction. Specifically, if other files instantiate templates or use macros or + * inline functions from this file, or you compile this file and link it with other + * files to produce an executable, this file does not by itself cause the resulting + * executable to be covered by the GNU General Public License. This exception does not + * however invalidate any other reasons why the executable file might be covered by the + * GNU General Public License. + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + */ + +#ifndef GQUADRATIC_B_PINOUT_H +#define GQUADRATIC_B_PINOUT_H + +/* + * USAGE NOTES + * + * Read this first: + * https://github.com/synthetos/g2/wiki/Adding-a-new-G2-board-(or-revision)-to-G2#making-a-new-pin-assignment + * + * USAGE: + * + * This file is lays out all the pin capabilities of the SAM3X8C organized by pin number. + * Each pin has its associated functions listed at the bottom of the file, and is essentially + * immutable for each processor. + * + * To use, assign Motate pin numbers to the first value in the _MAKE_MOTATE_PIN() macro. + * ALL PINS MUST BE ASSIGNED A NUMBER, even if they are not used. There will NOT be a + * code-size or speed penalty for unused pins, but the WILL be a compiler-failure for + * unassigned pins. This new restriction allows for simplification of linkages deep in + * Motate. + */ +/* See motate_pin_assignments.h for pin names to be used int he rest of the G2 code. + * EXAMPLES: + * + * *** Vanilla pin example *** + * + * _MAKE_MOTATE_PIN(4, A, 'A', 27); // SPI0_SCKPinNumber + * + * This assigns Motate pin 4 to Port A, pin 27 (A27) + * Look in motate_pin_assignments.h to see that this is kSPI_SCKPinNumber + * + * ** Other pin functions *** + * + * Please look in /platform/atmel_sam/motate_chip_pin_functions.h + */ + + +#include + +// We don't have all of the inputs, so we have to indicate as much: +#define INPUT1_AVAILABLE 1 +#define INPUT2_AVAILABLE 1 +#define INPUT3_AVAILABLE 1 +#define INPUT4_AVAILABLE 1 +#define INPUT5_AVAILABLE 0 +#define INPUT6_AVAILABLE 0 +#define INPUT7_AVAILABLE 0 +#define INPUT8_AVAILABLE 0 +#define INPUT9_AVAILABLE 0 +#define INPUT10_AVAILABLE 0 +#define INPUT11_AVAILABLE 0 +#define INPUT12_AVAILABLE 0 +#define INPUT13_AVAILABLE 0 + + +#define ADC0_AVAILABLE 0 +#define ADC1_AVAILABLE 0 +#define ADC2_AVAILABLE 0 +#define ADC3_AVAILABLE 0 + +#define XIO_HAS_USB 1 +#define XIO_HAS_UART 1 +#define XIO_HAS_SPI 0 +#define XIO_HAS_I2C 0 + +#define TEMPERATURE_OUTPUT_ON 0 // NO ADC yet + +// Some pins, if the PWM capability is turned on, it will cause timer conflicts. +// So we have to explicitly enable them as PWM pins. +// Generated with: +// perl -e 'for($i=1;$i<14;$i++) { print "#define OUTPUT${i}_PWM 0\n";}' +#define OUTPUT1_PWM 1 // TC0.0 +#define OUTPUT2_PWM 1 // PWM0.0 +#define OUTPUT3_PWM 1 // TC0.1 +#define OUTPUT4_PWM 1 // PWM1.3 +#define OUTPUT5_PWM 0 // unused +#define OUTPUT6_PWM 0 // unused +#define OUTPUT7_PWM 0 // unused +#define OUTPUT8_PWM 0 // unused +#define OUTPUT9_PWM 0 // unused +#define OUTPUT10_PWM 0 // unused +#define OUTPUT11_PWM 0 // unused +#define OUTPUT12_PWM 0 // Unused +#define OUTPUT13_PWM 0 // Unused + +namespace Motate { + +// Arduino pin name & function +_MAKE_MOTATE_PIN(kOutput2_PinNumber, 'A', 0); // TC0.0 or PWM0 +_MAKE_MOTATE_PIN(kOutput3_PinNumber, 'A', 1); // TC0.1 or PWM1 +_MAKE_MOTATE_PIN(kSocket2_VrefPinNumber, 'A', 2); // PWM1 +_MAKE_MOTATE_PIN(kI2C1_SDAPinNumber, 'A', 3); // +_MAKE_MOTATE_PIN(kI2C1_SCLPinNumber, 'A', 4); // +_MAKE_MOTATE_PIN(kUnassigned1, 'A', 5); // +_MAKE_MOTATE_PIN(kUnassigned2, 'A', 6); // Missing in 100-pin package +_MAKE_MOTATE_PIN(kUnassigned3, 'A', 7); // +_MAKE_MOTATE_PIN(kUnassigned4, 'A', 8); // +_MAKE_MOTATE_PIN(kSerial_RXPinNumber, 'A', 9); // +_MAKE_MOTATE_PIN(kSerial_TXPinNumber, 'A', 10); // +_MAKE_MOTATE_PIN(kSocket1_Microstep_1PinNumber, 'A', 11); // +_MAKE_MOTATE_PIN(kSocket1_EnablePinNumber, 'A', 12); // +_MAKE_MOTATE_PIN(kUnassigned5, 'A', 13); // +_MAKE_MOTATE_PIN(kUnassigned6, 'A', 14); // +_MAKE_MOTATE_PIN(kUnassigned7, 'A', 15); // +_MAKE_MOTATE_PIN(kUnassigned8, 'A', 16); // +_MAKE_MOTATE_PIN(kUnassigned9, 'A', 17); // +_MAKE_MOTATE_PIN(kUnassigned10, 'A', 18); // +_MAKE_MOTATE_PIN(kUnassigned11, 'A', 19); // +_MAKE_MOTATE_PIN(kUnassigned12, 'A', 20); // +_MAKE_MOTATE_PIN(kUnassigned13, 'A', 21); // +_MAKE_MOTATE_PIN(kUnassigned14, 'A', 22); // +_MAKE_MOTATE_PIN(kUnassigned15, 'A', 23); // +_MAKE_MOTATE_PIN(kUnassigned16, 'A', 24); // +_MAKE_MOTATE_PIN(kUnassigned17, 'A', 25); // +_MAKE_MOTATE_PIN(kUnassigned18, 'A', 26); // +_MAKE_MOTATE_PIN(kSocket1_VrefPinNumber, 'A', 27); // TC2.1 +_MAKE_MOTATE_PIN(kSerial_CTSPinNumber, 'A', 28); // +_MAKE_MOTATE_PIN(kUnassigned19, 'A', 29); // Missing in 100-pin package +_MAKE_MOTATE_PIN(kServo1_PinNumber, 'A', 30); // PWM2 +_MAKE_MOTATE_PIN(kInput4_PinNumber, 'A', 31); // + +_MAKE_MOTATE_PIN(kUnassigned20, 'B', 0); // +_MAKE_MOTATE_PIN(kUnassigned21, 'B', 1); // +_MAKE_MOTATE_PIN(kUnassigned22, 'B', 2); // +_MAKE_MOTATE_PIN(kUnassigned23, 'B', 3); // +//_MAKE_MOTATE_PIN( , 'B', 4); // TDI +//_MAKE_MOTATE_PIN( , 'B', 5); // TRACESDO +//_MAKE_MOTATE_PIN( , 'B', 6); // SWDIO +//_MAKE_MOTATE_PIN( , 'B', 7); // SWDCLK +//_MAKE_MOTATE_PIN( , 'B', 8); // XOUT +//_MAKE_MOTATE_PIN( , 'B', 9); // XIN +//_MAKE_MOTATE_PIN( , 'B', 10); // USB_D- +//_MAKE_MOTATE_PIN( , 'B', 11); // USB_D+ +//_MAKE_MOTATE_PIN( , 'B', 12); // ERASE +_MAKE_MOTATE_PIN(kUnassigned24, 'B', 13); // LED_1 (Heartbeat) - PWM2 + +//_MAKE_MOTATE_PIN( , 'D', 0); // USB_VBUS +_MAKE_MOTATE_PIN(kInput1_PinNumber, 'D', 1); // +_MAKE_MOTATE_PIN(kInput2_PinNumber, 'D', 2); // +_MAKE_MOTATE_PIN(kUnassigned25, 'D', 3); // +_MAKE_MOTATE_PIN(kUnassigned26, 'D', 4); // +_MAKE_MOTATE_PIN(kUnassigned27, 'D', 5); // +_MAKE_MOTATE_PIN(kInput3_PinNumber, 'D', 6); // +_MAKE_MOTATE_PIN(kSerial_RTSPinNumber, 'D', 7); // +_MAKE_MOTATE_PIN(kUnassigned28, 'D', 8); // INTERRUPT_OUT +_MAKE_MOTATE_PIN(kUnassigned29, 'D', 9); // +_MAKE_MOTATE_PIN(kUnassigned30, 'D', 10); // +_MAKE_MOTATE_PIN(kLED_RGBWPixelPinNumber, 'D', 11); // PWM0 +_MAKE_MOTATE_PIN(kSocket2_DirPinNumber, 'D', 12); // +_MAKE_MOTATE_PIN(kSocket2_EnablePinNumber, 'D', 13); // +_MAKE_MOTATE_PIN(kSocket2_StepPinNumber, 'D', 14); // +_MAKE_MOTATE_PIN(kOutputSAFE_PinNumber, 'D', 15); // +_MAKE_MOTATE_PIN(kSocket2_Microstep_0PinNumber, 'D', 16); // +_MAKE_MOTATE_PIN(kSocket2_Microstep_1PinNumber, 'D', 17); // +_MAKE_MOTATE_PIN(kSocket1_DirPinNumber, 'D', 18); // +_MAKE_MOTATE_PIN(kSocket1_StepPinNumber, 'D', 19); // +_MAKE_MOTATE_PIN(kSocket1_Microstep_0PinNumber, 'D', 20); // +_MAKE_MOTATE_PIN(kSocket1_Microstep_2PinNumber, 'D', 21); // +_MAKE_MOTATE_PIN(kUnassigned31, 'D', 22); // +_MAKE_MOTATE_PIN(kUnassigned32, 'D', 23); // Missing in 100-pin package +_MAKE_MOTATE_PIN(kUnassigned33, 'D', 24); // +_MAKE_MOTATE_PIN(kUnassigned34, 'D', 25); // +_MAKE_MOTATE_PIN(kUnassigned35, 'D', 26); // +_MAKE_MOTATE_PIN(kUnassigned36, 'D', 27); // +_MAKE_MOTATE_PIN(kSocket2_Microstep_2PinNumber, 'D', 28); // +_MAKE_MOTATE_PIN(kUnassigned37, 'D', 29); // Missing in 100-pin package +_MAKE_MOTATE_PIN(kLEDPWM_PinNumber, 'D', 30); // +_MAKE_MOTATE_PIN(kUnassigned38, 'D', 31); // + +} // namespace Motate + +// We then allow each chip-type to have it's onw function definitions +// that will refer to these pin assignments. +#include "motate_chip_pin_functions.h" + +#endif + +// GQUADRATIC_B_PINOUT_H diff --git a/g2core/board/gquadratic/hardware.cpp b/g2core/board/gquadratic/hardware.cpp index e11d595c..f40a7928 100755 --- a/g2core/board/gquadratic/hardware.cpp +++ b/g2core/board/gquadratic/hardware.cpp @@ -37,7 +37,37 @@ #include "MotatePower.h" //Motate::ClockOutputPin external_clk_pin {16000000}; // 16MHz optimally -Motate::OutputPin external_clk_pin {Motate::kStartLow}; +//Motate::OutputPin external_clk_pin {Motate::kStartLow}; + +#include "neopixel.h" +#include "canonical_machine.h" + +namespace LEDs { + NeoPixel rgbw_leds {NeoPixelOrder::GRB}; + + RGB_Color_t display_color[15] { + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + {0, 0, 0, 5}, + }; + + bool alarm_red = false; // if we are in alarm, the tells us if we're going to red (pulsing) + bool shutdown_white = false; // if we are in shutdown, the tells us if we're going to red (pulsing) + cmMachineState last_see_machine_state; + float old_x_pos = 0.0; +} /* * hardware_init() - lowest level hardware init @@ -46,7 +76,13 @@ Motate::OutputPin external_clk_pin {Motate::k void hardware_init() { board_hardware_init(); - external_clk_pin = 0; // Force external clock to 0 for now. +// external_clk_pin = 0; // Force external clock to 0 for now. + + for (uint8_t pixel = 0; pixel < LEDs::rgbw_leds.count; pixel++) { + LEDs::display_color[pixel].startTransition(100, 0, 0, 0); + LEDs::rgbw_leds.setPixel(pixel, LEDs::display_color[pixel]); + } + LEDs::rgbw_leds.update(); } /* @@ -55,6 +91,36 @@ void hardware_init() stat_t hardware_periodic() { + float x_pos = cm_get_work_position(ACTIVE_MODEL, AXIS_X); + if (fabs(LEDs::old_x_pos - x_pos) > 0.01) { + LEDs::old_x_pos = x_pos; + + float led_pos = x_pos * ((float)(LEDs::rgbw_leds.count-1) / 40); + + for (uint8_t pixel = 0; pixel < LEDs::rgbw_leds.count; pixel++) { + float value = fabs(led_pos - (float)pixel); + if (value < 1.001) { + value = 1.0 - value; + if (LEDs::display_color[pixel].red < value) { + LEDs::display_color[pixel].startTransition(10, value, value, value); + } else { + LEDs::display_color[pixel].startTransition(500, 0, 0, 0); + } + } else { +// LEDs::display_color[pixel].startTransition(500, 0, 0, 0); + } +// LEDs::display_color[pixel].startTransition(100, std::max(0.0f, std::min(40.0f, (float)(x_pos/40.0) )), 0, 0); + } + } + + for (uint8_t pixel = 0; pixel < LEDs::rgbw_leds.count; pixel++) { + if (LEDs::display_color[pixel].update()) { + LEDs::rgbw_leds.setPixel(pixel, LEDs::display_color[pixel]); + } + } + + LEDs::rgbw_leds.update(); + return STAT_OK; } diff --git a/g2core/board/gquadratic/hardware.h b/g2core/board/gquadratic/hardware.h old mode 100755 new mode 100644 index 9784b4d6..a28bf858 --- a/g2core/board/gquadratic/hardware.h +++ b/g2core/board/gquadratic/hardware.h @@ -58,7 +58,7 @@ enum hwPlatform { #define AXES 6 // number of axes supported in this version #define HOMING_AXES 4 // number of axes that can be homed (assumes Zxyabc sequence) -#define MOTORS 2 // number of motors on the board +#define MOTORS 3 // number of motors on the board #define COORDS 6 // number of supported coordinate systems (1-6) #define PWMS 2 // number of supported PWM channels @@ -110,8 +110,8 @@ using Motate::OutputPin; * * The following interrupts are defined w/indicated priorities * - * 0 DDA_TIMER (3) for step pulse generation - * 1 DWELL_TIMER (4) for dwell timing + * 0 DDA_TIMER (9) for step pulse generation + * 1 DWELL_TIMER (10) for dwell timing * 2 LOADER software generated interrupt (STIR / SGI) * 3 Serial read character interrupt * 4 EXEC software generated interrupt (STIR / SGI) @@ -128,11 +128,10 @@ using Motate::OutputPin; /**** Motate Definitions ****/ // Timer definitions. See stepper.h and other headers for setup -typedef TimerChannel<0, 0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<1, 0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp -typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp -typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp +typedef TimerChannel<9, 0> dda_timer_type; // stepper pulse generation in stepper.cpp +typedef TimerChannel<10, 0> load_timer_type; // request load timer in stepper.cpp +typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp +typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp // Pin assignments diff --git a/g2core/board/gquadratic/motate_pin_assignments.h b/g2core/board/gquadratic/motate_pin_assignments.h index 77609574..9cc268e7 100755 --- a/g2core/board/gquadratic/motate_pin_assignments.h +++ b/g2core/board/gquadratic/motate_pin_assignments.h @@ -30,8 +30,6 @@ #ifndef motate_pin_assignments_h #define motate_pin_assignments_h -#include - // Board pinout is pulled in after naming, so we can use the naming there. namespace Motate { @@ -40,15 +38,15 @@ namespace Motate { // Undefined pins will be equivalent to Motate::NullPin, and return 1 for Pin<>::isNull(); -pin_number kSerial_RX = 0; -pin_number kSerial_TX = 1; -pin_number kSerial_RTS = 2; // added later -pin_number kSerial_CTS = 3; // added later +pin_number kSerial_RXPinNumber = 0; +pin_number kSerial_TXPinNumber = 1; +pin_number kSerial_RTSPinNumber = 2; // added later +pin_number kSerial_CTSPinNumber = 3; // added later -pin_number kSerial0_RX = 0; -pin_number kSerial0_TX = 1; -pin_number kSerial0_RTS = 2; // added later -pin_number kSerial0_CTS = 3; // added later +pin_number kSerial0_RXPinNumber = 0; +pin_number kSerial0_TXPinNumber = 1; +pin_number kSerial0_RTSPinNumber = 2; // added later +pin_number kSerial0_CTSPinNumber = 3; // added later pin_number kI2C_SDAPinNumber = 5; pin_number kI2C_SCLPinNumber = 6; @@ -159,13 +157,15 @@ pin_number kDebug3_PinNumber = -1; // 116; //e Not the out-of-order numbering & pin_number kDebug4_PinNumber = -1; // 114; // END DEBUG PINS -pin_number kLED_USBRXPinNumber = 117; -pin_number kLED_USBTXPinNumber = 118; -pin_number kSD_CardDetectPinNumber = 119; -pin_number kSD_ChipSelectPinNumber = 120; -pin_number kInterlock_InPinNumber = 121; -pin_number kOutputSAFE_PinNumber = 122; // SAFE signal -pin_number kLEDPWM_PinNumber = 123; +pin_number kLED_USBRXPinNumber = 117; +pin_number kLED_USBTXPinNumber = 118; +pin_number kSD_CardDetectPinNumber = 119; +pin_number kSD_ChipSelectPinNumber = 120; +pin_number kInterlock_InPinNumber = 121; +pin_number kOutputSAFE_PinNumber = 122; // SAFE signal +pin_number kLEDPWM_PinNumber = 123; +pin_number kOutputInterrupt_PinNumber = 124; // to-host interrupt signal +pin_number kLED_RGBWPixelPinNumber = 125; // 117; // GRBL / gShield compatibility pins -- Due board ONLY @@ -213,8 +213,12 @@ pin_number kADC14_PinNumber = 164; // Not physically pinned out pin_number kExternalClock1_PinNumber = 170; // External pins for exporting a clock signal (for Trinamics) +pin_number kServo1_PinNumber = 171; // +pin_number kServo2_PinNumber = 172; // +pin_number kServo3_PinNumber = 173; // -// start next sequence at 171 + +// start next sequence at 174 // blank spots for unassigned pins - all unassigned pins need a unique number (do not re-use numbers) diff --git a/g2core/board/gquintic.gdb b/g2core/board/gquintic.gdb index 3a78d77d..864a9f89 100644 --- a/g2core/board/gquintic.gdb +++ b/g2core/board/gquintic.gdb @@ -4,7 +4,7 @@ target remote | /usr/local/bin/openocd -c "set CHIPNAME ${CHIP}" -f ${MOTATE_PAT source ./board/g2_default.gdb define boot_from_flash - monitor at91sam4 gpnvm set 1 + monitor atsamv gpnvm set 1 end source -s arm.gdb diff --git a/g2core/board/gquintic.mk b/g2core/board/gquintic.mk index 4f512476..ab60f6cb 100755 --- a/g2core/board/gquintic.mk +++ b/g2core/board/gquintic.mk @@ -6,32 +6,33 @@ # make BOARD=gquintic-a # You can also choose a CONFIG from boards.mk: -# make CONFIG=PrintrbotPlus BOARD=gquintic-a +# make CONFIG=PrintrbotPlus BOARD=gquintic-b ########## # BOARDs for use directly from the make command line (with default settings) or by CONFIGs. -ifeq ("$(BOARD)","gquintic-a") +ifeq ("$(BOARD)","gquintic-b") BASE_BOARD=gquintic - DEVICE_DEFINES += MOTATE_BOARD="gquintic-a" + DEVICE_DEFINES += MOTATE_BOARD="gquintic-b" DEVICE_DEFINES += SETTINGS_FILE=${SETTINGS_FILE} endif ########## -# The general pboard-a BASE_BOARD. +# The general gquintic BASE_BOARD. +# NOTE: rev a is no longer supported! ifeq ("$(BASE_BOARD)","gquintic") _BOARD_FOUND = 1 DEVICE_DEFINES += MOTATE_CONFIG_HAS_USBSERIAL=1 - FIRST_LINK_SOURCES += $(sort $(wildcard ${MOTATE_PATH}/Atmel_sam_common/*.cpp)) $(sort $(wildcard ${MOTATE_PATH}/Atmel_sam4e/*.cpp)) + FIRST_LINK_SOURCES += $(sort $(wildcard ${MOTATE_PATH}/Atmel_sam_common/*.cpp)) $(sort $(wildcard ${MOTATE_PATH}/Atmel_sams70/*.cpp)) - CHIP = SAM4E8C + CHIP = SAMS70N19 export CHIP - CHIP_LOWERCASE = sam4e8c + CHIP_LOWERCASE = sams70n19 BOARD_PATH = ./board/gquintic SOURCE_DIRS += ${BOARD_PATH} device/trinamic diff --git a/g2core/board/gquintic/board_stepper.h b/g2core/board/gquintic/board_stepper.h index f1b90dd3..23b8c4db 100755 --- a/g2core/board/gquintic/board_stepper.h +++ b/g2core/board/gquintic/board_stepper.h @@ -31,7 +31,7 @@ #include "hardware.h" // for MOTORS #include "tmc2130.h" -typedef Motate::SPIBus SPIBus_used_t; +typedef Motate::SPIBus SPIBus_used_t; // These are identical to board_stepper.h, except for the word "extern" and the initialization extern Trinamic2130 usb; -Motate::USBDevice< Motate::USBCDC, Motate::USBCDC > usb; +XIOUSBDevice_t usb; + +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif + decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; -// 115200 is the default, as well. -//UART Serial {115200, UARTMode::RTSCTSFlowControl}; - -MOTATE_SET_USB_VENDOR_STRING( {'S' ,'y', 'n', 't', 'h', 'e', 't', 'o', 's'} ) -MOTATE_SET_USB_PRODUCT_STRING( {'T', 'i', 'n', 'y', 'G', ' ', 'v', '2'} ) +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() #endif // XIO_HAS_USB + //******** SPI ******** #if XIO_HAS_SPI Motate::SPI spi; @@ -64,14 +67,14 @@ Motate::SPI spi; //******** UART ******** #if XIO_HAS_UART -Motate::UART Serial {115200, Motate::UARTMode::RTSCTSFlowControl}; +Motate::UART Serial {115200, Motate::UARTMode::RTSCTSFlowControl}; #endif void board_hardware_init(void) // called 1st { #if XIO_HAS_USB // Init USB - usb.attach(); // USB setup. Runs in "background" as the rest of this executes + usb.attach(); #endif // XIO_HAS_USB } diff --git a/g2core/board/gquintic/board_xio.h b/g2core/board/gquintic/board_xio.h index dc57cd3c..09f20fef 100755 --- a/g2core/board/gquintic/board_xio.h +++ b/g2core/board/gquintic/board_xio.h @@ -29,15 +29,25 @@ #ifndef board_xio_h #define board_xio_h +#include "settings.h" + //******** USB ******** #if XIO_HAS_USB #include "MotateUSB.h" #include "MotateUSBCDC.h" -// extern Motate::USBDevice< Motate::USBCDC > usb; -extern Motate::USBDevice usb; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif + +extern XIOUSBDevice_t usb; extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif #endif // XIO_HAS_USB @@ -50,7 +60,7 @@ extern Motate::SPI spi; //******** UART ******** #if XIO_HAS_UART #include "MotateUART.h" -extern Motate::UART Serial; +extern Motate::UART Serial; #endif //******* Generic Functions ******* diff --git a/g2core/board/gquintic/gquintic-a-pinout.h b/g2core/board/gquintic/gquintic-b-pinout.h similarity index 62% rename from g2core/board/gquintic/gquintic-a-pinout.h rename to g2core/board/gquintic/gquintic-b-pinout.h index 67e9ecd3..75d7c52e 100755 --- a/g2core/board/gquintic/gquintic-a-pinout.h +++ b/g2core/board/gquintic/gquintic-b-pinout.h @@ -89,7 +89,7 @@ #define ADC2_AVAILABLE 0 #define ADC3_AVAILABLE 0 -#define XIO_HAS_USB 0 +#define XIO_HAS_USB 1 #define XIO_HAS_UART 1 #define XIO_HAS_SPI 0 #define XIO_HAS_I2C 0 @@ -100,60 +100,66 @@ // So we have to explicitly enable them as PWM pins. // Generated with: // perl -e 'for($i=1;$i<14;$i++) { print "#define OUTPUT${i}_PWM 0\n";}' -#define OUTPUT1_PWM 1 // PWM1 - Fet 1 -#define OUTPUT2_PWM 1 // PWM2 - Fet 2 -#define OUTPUT3_PWM 1 // PWM3 - Fan 1 -#define OUTPUT4_PWM 0 // PWM2 - Fan 2 -#define OUTPUT5_PWM 1 // Timer2ch0 - Fan 3 -#define OUTPUT6_PWM 1 // Timer2ch1 -#define OUTPUT7_PWM 0 // PWM2 -#define OUTPUT8_PWM 1 // PWM0 -#define OUTPUT9_PWM 0 // PWM3 or Timer1ch0 -#define OUTPUT10_PWM 0 // PWM1 -#define OUTPUT11_PWM 0 // Can't PWM - Fet 3 +#define OUTPUT1_PWM 1 // TC0,1 - Fet 1 +#define OUTPUT2_PWM 1 // PWM1 - Fet 2 +#define OUTPUT3_PWM 1 // TC1,0 - Fan 1 +#define OUTPUT4_PWM 1 // TC1,1 - Fan 2 +#define OUTPUT5_PWM 1 // TC2,0 - Fan 3 +#define OUTPUT6_PWM 1 // PWM8+0 +#define OUTPUT7_PWM 1 // PWM3 +#define OUTPUT8_PWM 1 // PWM2 +#define OUTPUT9_PWM 0 // PWM2 +#define OUTPUT10_PWM 1 // PWM8+2 +#define OUTPUT11_PWM 1 // PWM8+3 - Fet 3 #define OUTPUT12_PWM 0 // Unused #define OUTPUT13_PWM 0 // Unused namespace Motate { -// Arduino pin name & function -_MAKE_MOTATE_PIN(kOutput2_PinNumber, 'A', 0); // +// Unused: +// +// +// +// +// + +_MAKE_MOTATE_PIN(kLED_RGBWPixelPinNumber, 'A', 0); // _MAKE_MOTATE_PIN(kOutput1_PinNumber, 'A', 1); // -_MAKE_MOTATE_PIN(kSocket5_EnablePinNumber, 'A', 2); // +_MAKE_MOTATE_PIN(kOutput2_PinNumber, 'A', 2); // _MAKE_MOTATE_PIN(kI2C1_SDAPinNumber, 'A', 3); // _MAKE_MOTATE_PIN(kI2C1_SCLPinNumber, 'A', 4); // -_MAKE_MOTATE_PIN(kUnassigned1, 'A', 5); // +_MAKE_MOTATE_PIN(kOutput11_PinNumber, 'A', 5); // _MAKE_MOTATE_PIN(kExternalClock1_PinNumber, 'A', 6); // CPU_CLK -_MAKE_MOTATE_PIN(kSerial_CTS, 'A', 7); // -_MAKE_MOTATE_PIN(kUnassigned2, 'A', 8); // -_MAKE_MOTATE_PIN(kSerial_RX, 'A', 9); // -_MAKE_MOTATE_PIN(kSerial_TX, 'A', 10); // -_MAKE_MOTATE_PIN(kSocket1_SPISlaveSelectPinNumber, 'A', 11); // -_MAKE_MOTATE_PIN(kSPI0_MISOPinNumber, 'A', 12); // -_MAKE_MOTATE_PIN(kSPI0_MOSIPinNumber, 'A', 13); // -_MAKE_MOTATE_PIN(kSPI0_SCKPinNumber, 'A', 14); // -_MAKE_MOTATE_PIN(kOutput9_PinNumber, 'A', 15); // -_MAKE_MOTATE_PIN(kOutput7_PinNumber, 'A', 16); // +_MAKE_MOTATE_PIN(kOutput7_PinNumber, 'A', 7); // +_MAKE_MOTATE_PIN(kSerial_RTSPinNumber, 'A', 8); // +_MAKE_MOTATE_PIN(kSerial_RXPinNumber, 'A', 9); // +_MAKE_MOTATE_PIN(kSerial_TXPinNumber, 'A', 10); // +_MAKE_MOTATE_PIN(kSocket2_EnablePinNumber, 'A', 11); // +_MAKE_MOTATE_PIN(kOutput6_PinNumber, 'A', 12); // +_MAKE_MOTATE_PIN(kOutput8_PinNumber, 'A', 13); // +_MAKE_MOTATE_PIN(kSocket1_StepPinNumber, 'A', 14); // +_MAKE_MOTATE_PIN(kOutput3_PinNumber, 'A', 15); // +_MAKE_MOTATE_PIN(kOutput4_PinNumber, 'A', 16); // _MAKE_MOTATE_PIN(kADC3_PinNumber, 'A', 17); // _MAKE_MOTATE_PIN(kADC2_PinNumber, 'A', 18); // _MAKE_MOTATE_PIN(kADC1_PinNumber, 'A', 19); // _MAKE_MOTATE_PIN(kADC0_PinNumber, 'A', 20); // -_MAKE_MOTATE_PIN(kUnassigned3, 'A', 21); // -_MAKE_MOTATE_PIN(kSocket2_SPISlaveSelectPinNumber, 'A', 22); // -_MAKE_MOTATE_PIN(kOutput8_PinNumber, 'A', 23); // -_MAKE_MOTATE_PIN(kOutput10_PinNumber, 'A', 24); // -_MAKE_MOTATE_PIN(kOutput4_PinNumber, 'A', 25); // +_MAKE_MOTATE_PIN(kSerial_CTSPinNumber, 'A', 21); // +_MAKE_MOTATE_PIN(kSocket1_EnablePinNumber, 'A', 22); // +_MAKE_MOTATE_PIN(kOutput10_PinNumber, 'A', 23); // +_MAKE_MOTATE_PIN(kSocket3_EnablePinNumber, 'A', 24); // +_MAKE_MOTATE_PIN(kSocket2_DirPinNumber, 'A', 25); // _MAKE_MOTATE_PIN(kOutput5_PinNumber, 'A', 26); // On Timer 2! -_MAKE_MOTATE_PIN(kOutput6_PinNumber, 'A', 27); // On Timer 2! -_MAKE_MOTATE_PIN(kUnassigned13, 'A', 28); // DIAG0 -_MAKE_MOTATE_PIN(kInput8_PinNumber, 'A', 29); // +_MAKE_MOTATE_PIN(kSocket3_StepPinNumber, 'A', 27); // On Timer 2! +_MAKE_MOTATE_PIN(kUnassigned1, 'A', 28); // DIAG1 +_MAKE_MOTATE_PIN(kUnassigned2, 'A', 29); // _MAKE_MOTATE_PIN(kInput1_PinNumber, 'A', 30); // -_MAKE_MOTATE_PIN(kInput2_PinNumber, 'A', 31); // +_MAKE_MOTATE_PIN(kInput4_PinNumber, 'A', 31); // _MAKE_MOTATE_PIN(kInput12_PinNumber, 'B', 0); // _MAKE_MOTATE_PIN(kInput11_PinNumber, 'B', 1); // -_MAKE_MOTATE_PIN(kSocket3_SPISlaveSelectPinNumber, 'B', 2); // -_MAKE_MOTATE_PIN(kSerial_RTS, 'B', 3); // +_MAKE_MOTATE_PIN(kSocket1_SPISlaveSelectPinNumber, 'B', 2); // +_MAKE_MOTATE_PIN(kOutputSAFE_PinNumber, 'B', 3); // //_MAKE_MOTATE_PIN( , 'B', 4); // TDI //_MAKE_MOTATE_PIN( , 'B', 5); // TRACESDO //_MAKE_MOTATE_PIN( , 'B', 6); // SWDIO @@ -168,35 +174,35 @@ _MAKE_MOTATE_PIN(kSocket4_SPISlaveSelectPinNumber, 'B', 14); // NOT CONNECTED //_MAKE_MOTATE_PIN( , 'D', 0); // USB_VBUS -_MAKE_MOTATE_PIN(kInput10_PinNumber, 'D', 1); // -_MAKE_MOTATE_PIN(kInput9_PinNumber, 'D', 2); // -_MAKE_MOTATE_PIN(kInput7_PinNumber, 'D', 3); // -_MAKE_MOTATE_PIN(kInput6_PinNumber, 'D', 4); // -_MAKE_MOTATE_PIN(kInput5_PinNumber, 'D', 5); // -_MAKE_MOTATE_PIN(kInput4_PinNumber, 'D', 6); // +_MAKE_MOTATE_PIN(kInput9_PinNumber, 'D', 1); // +_MAKE_MOTATE_PIN(kInput10_PinNumber, 'D', 2); // +_MAKE_MOTATE_PIN(kInput8_PinNumber, 'D', 3); // +_MAKE_MOTATE_PIN(kInput7_PinNumber, 'D', 4); // +_MAKE_MOTATE_PIN(kInput6_PinNumber, 'D', 5); // +_MAKE_MOTATE_PIN(kInput5_PinNumber, 'D', 6); // _MAKE_MOTATE_PIN(kInput3_PinNumber, 'D', 7); // -_MAKE_MOTATE_PIN(kUnassigned11, 'D', 8); // DIAG1 -_MAKE_MOTATE_PIN(kOutputSAFE_PinNumber, 'D', 9); // -_MAKE_MOTATE_PIN(kSocket5_StepPinNumber, 'D', 10); // -_MAKE_MOTATE_PIN(kSocket5_DirPinNumber, 'D', 11); // -_MAKE_MOTATE_PIN(kSocket4_StepPinNumber, 'D', 12); // -_MAKE_MOTATE_PIN(kUnassigned5, 'D', 13); // -_MAKE_MOTATE_PIN(kSocket4_DirPinNumber, 'D', 14); // -_MAKE_MOTATE_PIN(kUnassigned6, 'D', 15); // -_MAKE_MOTATE_PIN(kSocket4_EnablePinNumber, 'D', 16); // -_MAKE_MOTATE_PIN(kSocket3_DirPinNumber, 'D', 17); // -_MAKE_MOTATE_PIN(kUnassigned7, 'D', 18); // -_MAKE_MOTATE_PIN(kSocket3_EnablePinNumber, 'D', 19); // -_MAKE_MOTATE_PIN(kSocket2_StepPinNumber, 'D', 20); // -_MAKE_MOTATE_PIN(kSocket2_DirPinNumber, 'D', 21); // -_MAKE_MOTATE_PIN(kUnassigned8, 'D', 22); // -_MAKE_MOTATE_PIN(kOutput3_PinNumber, 'D', 23); // -_MAKE_MOTATE_PIN(kSocket2_EnablePinNumber, 'D', 24); // -_MAKE_MOTATE_PIN(kSocket1_DirPinNumber, 'D', 25); // -_MAKE_MOTATE_PIN(kSocket1_StepPinNumber, 'D', 26); // -_MAKE_MOTATE_PIN(kSocket1_EnablePinNumber, 'D', 27); // -_MAKE_MOTATE_PIN(kSocket3_StepPinNumber, 'D', 28); // -_MAKE_MOTATE_PIN(kOutput11_PinNumber, 'D', 29); // +_MAKE_MOTATE_PIN(kInput2_PinNumber, 'D', 8); // ] +_MAKE_MOTATE_PIN(kUnassigned3, 'D', 9); // DIAG0 +_MAKE_MOTATE_PIN(kUnassigned4, 'D', 10); // +_MAKE_MOTATE_PIN(kSocket5_StepPinNumber, 'D', 11); // +_MAKE_MOTATE_PIN(kSocket3_SPISlaveSelectPinNumber, 'D', 12); // +_MAKE_MOTATE_PIN(kSocket5_DirPinNumber, 'D', 13); // +_MAKE_MOTATE_PIN(kSocket5_EnablePinNumber, 'D', 14); // +_MAKE_MOTATE_PIN(kUnassigned5, 'D', 15); // +_MAKE_MOTATE_PIN(kSocket4_StepPinNumber, 'D', 16); // +_MAKE_MOTATE_PIN(kSocket4_DirPinNumber, 'D', 17); // +_MAKE_MOTATE_PIN(kSocket3_DirPinNumber, 'D', 18); // +_MAKE_MOTATE_PIN(kUnassigned6, 'D', 19); // +_MAKE_MOTATE_PIN(kSPI0_MISOPinNumber, 'D', 20); // +_MAKE_MOTATE_PIN(kSPI0_MOSIPinNumber, 'D', 21); // +_MAKE_MOTATE_PIN(kSPI0_SCKPinNumber, 'D', 22); // +_MAKE_MOTATE_PIN(kUnassigned7, 'D', 23); // +_MAKE_MOTATE_PIN(kSocket2_StepPinNumber, 'D', 24); // +_MAKE_MOTATE_PIN(kSocket2_SPISlaveSelectPinNumber, 'D', 25); // +_MAKE_MOTATE_PIN(kOutput9_PinNumber, 'D', 26); // +_MAKE_MOTATE_PIN(kSocket1_DirPinNumber, 'D', 27); // +_MAKE_MOTATE_PIN(kSocket4_EnablePinNumber, 'D', 28); // +_MAKE_MOTATE_PIN(kUnassigned8, 'D', 29); // _MAKE_MOTATE_PIN(kUnassigned9, 'D', 30); // INTERRUPT_OUT _MAKE_MOTATE_PIN(kUnassigned10, 'D', 31); // diff --git a/g2core/board/gquintic/hardware.h b/g2core/board/gquintic/hardware.h index 2f3fc969..e7fb56ba 100755 --- a/g2core/board/gquintic/hardware.h +++ b/g2core/board/gquintic/hardware.h @@ -119,18 +119,19 @@ using Motate::OutputPin; /**** Stepper DDA and dwell timer settings ****/ //#define FREQUENCY_DDA 200000UL // Hz step frequency. Interrupts actually fire at 2x (400 KHz) -#define FREQUENCY_DDA 150000UL // Hz step frequency. Interrupts actually fire at 2x (300 KHz) +#define FREQUENCY_DDA 300000UL // Hz step frequency. Interrupts actually fire at 2x (300 KHz) #define FREQUENCY_DWELL 1000UL #define FREQUENCY_SGI 200000UL // 200,000 Hz means software interrupts will fire 5 uSec after being called /**** Motate Definitions ****/ // Timer definitions. See stepper.h and other headers for setup -typedef TimerChannel<0,0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<1,0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp -typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp -typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp +typedef TimerChannel<9, 0> dda_timer_type; // stepper pulse generation in stepper.cpp +typedef TimerChannel<10, 0> load_timer_type; // request load timer in stepper.cpp +typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp +typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp + +Motate::service_call_number kSPI_ServiceCallNumber = 3; // Pin assignments diff --git a/g2core/board/gquintic/motate_pin_assignments.h b/g2core/board/gquintic/motate_pin_assignments.h index 12ec29bf..af029d31 100755 --- a/g2core/board/gquintic/motate_pin_assignments.h +++ b/g2core/board/gquintic/motate_pin_assignments.h @@ -40,15 +40,15 @@ namespace Motate { // Undefined pins will be equivalent to Motate::NullPin, and return 1 for Pin<>::isNull(); -pin_number kSerial_RX = 0; -pin_number kSerial_TX = 1; -pin_number kSerial_RTS = 2; // added later -pin_number kSerial_CTS = 3; // added later +pin_number kSerial_RXPinNumber = 0; +pin_number kSerial_TXPinNumber = 1; +pin_number kSerial_RTSPinNumber = 2; // added later +pin_number kSerial_CTSPinNumber = 3; // added later -pin_number kSerial0_RX = 0; -pin_number kSerial0_TX = 1; -pin_number kSerial0_RTS = 2; // added later -pin_number kSerial0_CTS = 3; // added later +pin_number kSerial0_RXPinNumber = 0; +pin_number kSerial0_TXPinNumber = 1; +pin_number kSerial0_RTSPinNumber = 2; // added later +pin_number kSerial0_CTSPinNumber = 3; // added later pin_number kI2C_SDAPinNumber = 5; pin_number kI2C_SCLPinNumber = 6; @@ -166,6 +166,8 @@ pin_number kSD_ChipSelectPinNumber = 120; pin_number kInterlock_InPinNumber = 121; pin_number kOutputSAFE_PinNumber = 122; // SAFE signal pin_number kLEDPWM_PinNumber = 123; +pin_number kOutputInterrupt_PinNumber = 124; // to-host interrupt signal +pin_number kLED_RGBWPixelPinNumber = 125; // 117; // GRBL / gShield compatibility pins -- Due board ONLY @@ -238,12 +240,6 @@ pin_number kUnassigned4 = 251; pin_number kUnassigned3 = 252; pin_number kUnassigned2 = 253; pin_number kUnassigned1 = 254; // 254 is the max.. Do not exceed this number - -/** NOTE: When adding pin definitions here, they must be - * added to ALL board pin assignment files, even if - * they are defined as -1. - **/ - } // namespace Motate // For the SAM3X8C boards, we actually use the same NUMBERING, but have different number to pin linkages diff --git a/g2core/board/printrboardg2/board_xio.cpp b/g2core/board/printrboardg2/board_xio.cpp index 709b0e57..8b4835b2 100755 --- a/g2core/board/printrboardg2/board_xio.cpp +++ b/g2core/board/printrboardg2/board_xio.cpp @@ -32,6 +32,7 @@ #include "board_xio.h" //******** USB ******** +#if XIO_HAS_USB const Motate::USBSettings_t Motate::USBSettings = { /*gVendorID = */ 0x1d50, /*gProductID = */ 0x606d, @@ -41,18 +42,21 @@ const Motate::USBSettings_t Motate::USBSettings = { }; /*gProductVersion = */ //0.1, -//Motate::USBDevice< Motate::USBCDC > usb; -Motate::USBDevice< Motate::USBCDC, Motate::USBCDC > usb; +XIOUSBDevice_t usb; + +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif + decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; -// 115200 is the default, as well. -//UART Serial {115200, UARTMode::RTSCTSFlowControl}; - -MOTATE_SET_USB_VENDOR_STRING( {'S' ,'y', 'n', 't', 'h', 'e', 't', 'o', 's'} ) -MOTATE_SET_USB_PRODUCT_STRING( {'T', 'i', 'n', 'y', 'G', ' ', 'v', '2'} ) +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() +#endif // XIO_HAS_USB //******** SPI ******** @@ -68,8 +72,10 @@ Motate::UART usb; -extern Motate::USBDevice usb; -extern decltype(usb.mixin<0>::Serial)& SerialUSB; -extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif +extern XIOUSBDevice_t usb; +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif +#endif // XIO_HAS_USB //******** SPI ******** #if XIO_HAS_SPI diff --git a/g2core/board/printrboardg2/hardware.h b/g2core/board/printrboardg2/hardware.h index 6046c789..244a2681 100755 --- a/g2core/board/printrboardg2/hardware.h +++ b/g2core/board/printrboardg2/hardware.h @@ -126,8 +126,7 @@ using Motate::OutputPin; // Timer definitions. See stepper.h and other headers for setup typedef TimerChannel<3,0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<4,0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp +typedef TimerChannel<4,0> load_timer_type; // request load timer in stepper.cpp typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp diff --git a/g2core/board/sbv300/board_xio.cpp b/g2core/board/sbv300/board_xio.cpp index 712a89e9..8b4835b2 100755 --- a/g2core/board/sbv300/board_xio.cpp +++ b/g2core/board/sbv300/board_xio.cpp @@ -32,6 +32,7 @@ #include "board_xio.h" //******** USB ******** +#if XIO_HAS_USB const Motate::USBSettings_t Motate::USBSettings = { /*gVendorID = */ 0x1d50, /*gProductID = */ 0x606d, @@ -41,20 +42,21 @@ const Motate::USBSettings_t Motate::USBSettings = { }; /*gProductVersion = */ //0.1, -//Motate::USBDevice< Motate::USBCDC > usb; -Motate::USBDevice< Motate::USBCDC, Motate::USBCDC > usb; +XIOUSBDevice_t usb; + +extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 +extern decltype(usb.mixin<1>::Serial)& SerialUSB1; +#endif + decltype(usb.mixin<0>::Serial) &SerialUSB = usb.mixin<0>::Serial; -decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; +//decltype(usb.mixin<1>::Serial) &SerialUSB1 = usb.mixin<1>::Serial; -// 115200 is the default, as well. -//UART Serial {115200, UARTMode::RTSCTSFlowControl}; - - -MOTATE_SET_USB_VENDOR_STRING( {'S' ,'y', 'n', 't', 'h', 'e', 't', 'o', 's'} ) -MOTATE_SET_USB_PRODUCT_STRING( {'T', 'i', 'n', 'y', 'G', ' ', 'v', '2'} ) +MOTATE_SET_USB_VENDOR_STRING( u"Synthetos" ) +MOTATE_SET_USB_PRODUCT_STRING( u"TinyG v2" ) MOTATE_SET_USB_SERIAL_NUMBER_STRING_FROM_CHIPID() - +#endif // XIO_HAS_USB //******** SPI ******** @@ -65,25 +67,26 @@ Motate::SPI spi; //******** UART ******** #if XIO_HAS_UART -Motate::UART Serial{ - 115200, Motate::UARTMode::RTSCTSFlowControl}; +Motate::UART Serial {115200, Motate::UARTMode::RTSCTSFlowControl}; #endif -void board_hardware_init(void) // called 1st +void board_hardware_init(void) // called 1st { +#if XIO_HAS_USB // Init USB - usb.attach(); // USB setup. Runs in "background" as the rest of this executes + usb.attach(); +#endif // XIO_HAS_USB } -void board_xio_init(void) // called later than board_hardware_init (there are thing in between) +void board_xio_init(void) // called later than board_hardware_init (there are thing in between) { -// Init SPI + // Init SPI #if XIO_HAS_SPI -// handled internally for now + // handled internally for now #endif -// Init UART + // Init UART #if XIO_HAS_UART Serial.init(); #endif diff --git a/g2core/board/sbv300/board_xio.h b/g2core/board/sbv300/board_xio.h index 40b42a09..6bc4421f 100755 --- a/g2core/board/sbv300/board_xio.h +++ b/g2core/board/sbv300/board_xio.h @@ -29,28 +29,38 @@ #ifndef board_xio_h #define board_xio_h +#include "settings.h" + //******** USB ******** +#if XIO_HAS_USB #include "MotateUSB.h" #include "MotateUSBCDC.h" -// extern Motate::USBDevice< Motate::USBCDC > usb; -extern Motate::USBDevice usb; +#if USB_SERIAL_PORTS_EXPOSED == 1 +typedef Motate::USBDevice< Motate::USBCDC > XIOUSBDevice_t; +#endif +#if USB_SERIAL_PORTS_EXPOSED == 2 +typedef Motate::USBDevice XIOUSBDevice_t; +#endif + +extern XIOUSBDevice_t usb; extern decltype(usb.mixin<0>::Serial)& SerialUSB; +#if USB_SERIAL_PORTS_EXPOSED == 2 extern decltype(usb.mixin<1>::Serial)& SerialUSB1; - - +#endif +#endif // XIO_HAS_USB //******** SPI ******** -//#include "MotateSPI.h" -// extern Motate::SPI spi; - - +#if XIO_HAS_SPI +#include "MotateSPI.h" +extern Motate::SPI spi; +#endif //******** UART ******** -//#include "MotateUART.h" -// extern Motate::UART Serial; - - +#if XIO_HAS_UART +#include "MotateUART.h" +extern Motate::UART Serial; +#endif //******* Generic Functions ******* void board_hardware_init(void); // called 1st diff --git a/g2core/board/sbv300/hardware.h b/g2core/board/sbv300/hardware.h index 0e576ab4..5ded07eb 100755 --- a/g2core/board/sbv300/hardware.h +++ b/g2core/board/sbv300/hardware.h @@ -126,8 +126,7 @@ using Motate::OutputPin; // Timer definitions. See stepper.h and other headers for setup typedef TimerChannel<3,0> dda_timer_type; // stepper pulse generation in stepper.cpp -typedef TimerChannel<4,0> dwell_timer_type; // dwell timing in stepper.cpp -typedef ServiceCall<0> load_timer_type; // request load timer in stepper.cpp +typedef TimerChannel<4,0> load_timer_type; // request load timer in stepper.cpp typedef ServiceCall<1> exec_timer_type; // request exec timer in stepper.cpp typedef ServiceCall<2> fwd_plan_timer_type; // request exec timer in stepper.cpp diff --git a/g2core/boards.mk b/g2core/boards.mk index 81443f81..2643578d 100644 --- a/g2core/boards.mk +++ b/g2core/boards.mk @@ -72,7 +72,7 @@ endif ifeq ("$(CONFIG)","TestQuintic") ifeq ("$(BOARD)","NONE") - BOARD=gquintic-a + BOARD=gquintic-b endif SETTINGS_FILE="settings_test.h" endif @@ -80,12 +80,11 @@ endif ifeq ("$(CONFIG)","TestQuadratic") ifeq ("$(BOARD)","NONE") - BOARD=gquadratic-a + BOARD=gquadratic-b endif SETTINGS_FILE="settings_test.h" endif - ########## # Shopbot configs: @@ -138,5 +137,23 @@ ifeq ("$(CONFIG)","Ultimakerv9k") SETTINGS_FILE="settings_ultimaker.h" endif +########## +# EMSL configs: + +ifeq ("$(CONFIG)","WaterColorBotv2") + ifeq ("$(BOARD)","NONE") + BOARD=gquadratic-b + endif + SETTINGS_FILE="settings_watercolorbot_v2.h" +endif + +ifeq ("$(CONFIG)","EggBot") + ifeq ("$(BOARD)","NONE") + BOARD=gquadratic-b + endif + SETTINGS_FILE="settings_eggbot.h" +endif + + include $(wildcard ./board/$(STAR).mk) diff --git a/g2core/canonical_machine.cpp b/g2core/canonical_machine.cpp index 01152b35..3899ed89 100644 --- a/g2core/canonical_machine.cpp +++ b/g2core/canonical_machine.cpp @@ -225,7 +225,7 @@ cmCombinedState cm_get_combined_state() * ACTIVE_MODEL cm.am // active model pointer is maintained by state management */ uint32_t cm_get_linenum(const GCodeState_t *gcode_state) { return gcode_state->linenum;} -uint8_t cm_get_motion_mode(const GCodeState_t *gcode_state) { return gcode_state->motion_mode;} +cmMotionMode cm_get_motion_mode(const GCodeState_t *gcode_state) { return gcode_state->motion_mode;} uint8_t cm_get_coord_system(const GCodeState_t *gcode_state) { return gcode_state->coord_system;} uint8_t cm_get_units_mode(const GCodeState_t *gcode_state) { return gcode_state->units_mode;} uint8_t cm_get_select_plane(const GCodeState_t *gcode_state) { return gcode_state->select_plane;} @@ -1683,8 +1683,9 @@ void cm_request_queue_flush() { if ((cm.hold_state != FEEDHOLD_OFF) && // don't honor request unless you are in a feedhold (cm.queue_flush_state == FLUSH_OFF)) { // ...and only once - xio_flush_read(); // flush the input buffers - you can do that now cm.queue_flush_state = FLUSH_REQUESTED; // request planner flush once motion has stopped + + // NOTE: we used to flush the input buffers, but this is handled in xio *prior* to queue flush now } } @@ -2311,7 +2312,7 @@ void _cm_recalc_max_junction_accel(const uint8_t axis) { void cm_set_axis_jerk(const uint8_t axis, const float jerk) { cm.a[axis].jerk_max = jerk; - cm.a[axis].recip_jerk = 1/(jerk * JERK_MULTIPLIER); + //cm.a[axis].recip_jerk = 1/(jerk * JERK_MULTIPLIER); // Must recalculate the max_junction_accel now that the jerk has changed. _cm_recalc_max_junction_accel(axis); diff --git a/g2core/canonical_machine.h b/g2core/canonical_machine.h index 85d3db45..509df9d4 100755 --- a/g2core/canonical_machine.h +++ b/g2core/canonical_machine.h @@ -320,7 +320,7 @@ typedef enum { // axis modes (ordered: see _cm_get_feed_time()) */ typedef struct GCodeState { // Gcode model state - used by model, planning and runtime uint32_t linenum; // Gcode block line number - uint8_t motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81, + cmMotionMode motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81, // G82, G83 G84, G85, G86, G87, G88, G89 float target[AXES]; // XYZABC where the move should go @@ -340,6 +340,31 @@ typedef struct GCodeState { // Gcode model state - used by model, pl cmCoordSystem coord_system; // G54-G59 - select coordinate system 1-9 uint8_t tool; // G // M6 tool change - moves "tool_select" to "tool" uint8_t tool_select; // G // T value - T sets this value + + void reset() { + linenum = 0; + motion_mode = MOTION_MODE_STRAIGHT_TRAVERSE; + + for (uint8_t i = 0; i< AXES; i++) { + target[i] = 0.0; + work_offset[i] = 0.0; + } + + feed_rate = 0.0; + parameter = 0.0; + + feed_rate_mode = INVERSE_TIME_MODE; + select_plane = CANON_PLANE_XY; + units_mode = INCHES; + path_control = PATH_EXACT_PATH; + distance_mode = ABSOLUTE_MODE; + arc_distance_mode = ABSOLUTE_MODE; + absolute_override = ABSOLUTE_OVERRIDE_OFF; + coord_system = ABSOLUTE_COORDS; + tool = 0; + tool_select = 0; + + }; } GCodeState_t; typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used by model and arcs @@ -372,7 +397,7 @@ typedef struct GCodeStateExtended { // Gcode dynamic state extensions - used typedef struct GCodeInput { // Gcode model inputs - meaning depends on context uint8_t next_action; // handles G modal group 1 moves & non-modals - uint8_t motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81, G82 + cmMotionMode motion_mode; // Group1: G0, G1, G2, G3, G38.2, G80, G81, G82 // G83, G84, G85, G86, G87, G88, G89 uint8_t program_flow; // used only by the gcode_parser @@ -472,7 +497,7 @@ typedef struct cmAxis { float travel_min; // min work envelope for soft limits float jerk_max; // max jerk (Jm) in mm/min^3 divided by 1 million float jerk_high; // high speed deceleration jerk (Jh) in mm/min^3 divided by 1 million - float recip_jerk; // stored reciprocal of current jerk value - has the million in it + //float recip_jerk; // stored reciprocal of current jerk value - has the million in it float max_junction_accel; // high speed deceleration jerk (Jh) in mm/min^3 divided by 1 million float junction_dev; // aka cornering delta -- DEPRICATED! float radius; // radius in mm for rotary axis modes @@ -581,7 +606,7 @@ float cm_get_axis_jerk(const uint8_t axis); void cm_set_axis_jerk(const uint8_t axis, const float jerk); uint32_t cm_get_linenum(const GCodeState_t *gcode_state); -uint8_t cm_get_motion_mode(const GCodeState_t *gcode_state); +cmMotionMode cm_get_motion_mode(const GCodeState_t *gcode_state); uint8_t cm_get_coord_system(const GCodeState_t *gcode_state); uint8_t cm_get_units_mode(const GCodeState_t *gcode_state); uint8_t cm_get_select_plane(const GCodeState_t *gcode_state); @@ -676,7 +701,7 @@ stat_t cm_arc_feed(const float target[], const bool target_f[], // G const float radius, const bool radius_f, // radius if radius mode const float P_word, const bool P_word_f, // parameter const bool modal_g1_f, // modal group flag for motion group - const uint8_t motion_mode); // defined motion mode + const cmMotionMode motion_mode); // defined motion mode // Spindle Functions (4.3.7) // see spindle.h for spindle functions - which would go right here diff --git a/g2core/config.cpp b/g2core/config.cpp old mode 100755 new mode 100644 index 279eff86..5b0b048c --- a/g2core/config.cpp +++ b/g2core/config.cpp @@ -584,7 +584,9 @@ nvObj_t *nv_add_object(const char *token) // add an object to the body usi nvObj_t *nv = nv_body; for (uint8_t i=0; ivaluetype != TYPE_EMPTY) { - if ((nv = nv->nx) == NULL) return(NULL); // not supposed to find a NULL; here for safety + if ((nv = nv->nx) == NULL) { // not supposed to find a NULL; here for safety + return(NULL); + } continue; } // load the index from the token or die trying @@ -600,7 +602,9 @@ nvObj_t *nv_add_integer(const char *token, const uint32_t value)// add an intege nvObj_t *nv = nv_body; for (uint8_t i=0; ivaluetype != TYPE_EMPTY) { - if ((nv = nv->nx) == NULL) return(NULL); // not supposed to find a NULL; here for safety + if ((nv = nv->nx) == NULL) { // not supposed to find a NULL; here for safety + return(NULL); + } continue; } strncpy(nv->token, token, TOKEN_LEN); @@ -616,7 +620,9 @@ nvObj_t *nv_add_data(const char *token, const uint32_t value)// add an integer o nvObj_t *nv = nv_body; for (uint8_t i=0; ivaluetype != TYPE_EMPTY) { - if ((nv = nv->nx) == NULL) return(NULL); // not supposed to find a NULL; here for safety + if ((nv = nv->nx) == NULL) { // not supposed to find a NULL; here for safety + return(NULL); + } continue; } strcpy(nv->token, token); @@ -633,7 +639,9 @@ nvObj_t *nv_add_float(const char *token, const float value) // add a float ob nvObj_t *nv = nv_body; for (uint8_t i=0; ivaluetype != TYPE_EMPTY) { - if ((nv = nv->nx) == NULL) return(NULL); // not supposed to find a NULL; here for safety + if ((nv = nv->nx) == NULL) { // not supposed to find a NULL; here for safety + return(NULL); + } continue; } strncpy(nv->token, token, TOKEN_LEN); @@ -649,7 +657,9 @@ nvObj_t *nv_add_string(const char *token, const char *string) // add a string ob nvObj_t *nv = nv_body; for (uint8_t i=0; ivaluetype != TYPE_EMPTY) { - if ((nv = nv->nx) == NULL) return(NULL); // not supposed to find a NULL; here for safety + if ((nv = nv->nx) == NULL) { // not supposed to find a NULL; here for safety + return(NULL); + } continue; } strncpy(nv->token, token, TOKEN_LEN); diff --git a/g2core/device/neopixel/neopixel.h b/g2core/device/neopixel/neopixel.h index b57f5135..4c69f8dc 100755 --- a/g2core/device/neopixel/neopixel.h +++ b/g2core/device/neopixel/neopixel.h @@ -215,6 +215,12 @@ struct RGB_Color_t : NeopixelColorTag { float green; float blue; + enum ColorFilter { + Set = 0, + Lighten, + Darken + }; + const uint32_t _update_timeout_ms; Motate::Timeout _update_timeout; @@ -233,7 +239,18 @@ struct RGB_Color_t : NeopixelColorTag { _update_timeout.set(0); }; - void startTransition(uint32_t milliseconds, float to_red, float to_green, float to_blue) { + void startTransition(uint32_t milliseconds, float to_red, float to_green, float to_blue, ColorFilter cf = Set) { + if (cf == Lighten) { + to_red = std::max(to_red, red); + to_green = std::max(to_green, green); + to_blue = std::max(to_blue, blue); + } + else if (cf == Darken) { + to_red = std::min(to_red, red); + to_green = std::min(to_green, green); + to_blue = std::min(to_blue, blue); + } + _transition_steps_left = 0.5 + (milliseconds / _update_timeout_ms); float h = 1.0 / _transition_steps_left; float h_2 = h * h; @@ -418,6 +435,10 @@ struct NeoPixel { }; void setPixel(uint8_t pixel, uint8_t red, uint8_t green, uint8_t blue, int16_t white = -1) { + uint8_t data_width = 32; + if (!_has_white) { + data_width = 24; + } if (_has_white && (white == -1)) { // Adjust all of the RGB to accomodate white white = std::min(red, std::min(green, blue)); @@ -425,32 +446,32 @@ struct NeoPixel { // green -= white; // blue -= white; } - _period_buffer[0 + 1 + _red_offset + (pixel * 32)] = (red & 0b10000000) ? led_ON : led_OFF; - _period_buffer[1 + 1 + _red_offset + (pixel * 32)] = (red & 0b01000000) ? led_ON : led_OFF; - _period_buffer[2 + 1 + _red_offset + (pixel * 32)] = (red & 0b00100000) ? led_ON : led_OFF; - _period_buffer[3 + 1 + _red_offset + (pixel * 32)] = (red & 0b00010000) ? led_ON : led_OFF; - _period_buffer[4 + 1 + _red_offset + (pixel * 32)] = (red & 0b00001000) ? led_ON : led_OFF; - _period_buffer[5 + 1 + _red_offset + (pixel * 32)] = (red & 0b00000100) ? led_ON : led_OFF; - _period_buffer[6 + 1 + _red_offset + (pixel * 32)] = (red & 0b00000010) ? led_ON : led_OFF; - _period_buffer[7 + 1 + _red_offset + (pixel * 32)] = (red & 0b00000001) ? led_ON : led_OFF; + _period_buffer[0 + 1 + _red_offset + (pixel * data_width)] = (red & 0b10000000) ? led_ON : led_OFF; + _period_buffer[1 + 1 + _red_offset + (pixel * data_width)] = (red & 0b01000000) ? led_ON : led_OFF; + _period_buffer[2 + 1 + _red_offset + (pixel * data_width)] = (red & 0b00100000) ? led_ON : led_OFF; + _period_buffer[3 + 1 + _red_offset + (pixel * data_width)] = (red & 0b00010000) ? led_ON : led_OFF; + _period_buffer[4 + 1 + _red_offset + (pixel * data_width)] = (red & 0b00001000) ? led_ON : led_OFF; + _period_buffer[5 + 1 + _red_offset + (pixel * data_width)] = (red & 0b00000100) ? led_ON : led_OFF; + _period_buffer[6 + 1 + _red_offset + (pixel * data_width)] = (red & 0b00000010) ? led_ON : led_OFF; + _period_buffer[7 + 1 + _red_offset + (pixel * data_width)] = (red & 0b00000001) ? led_ON : led_OFF; - _period_buffer[0 + 1 + _green_offset + (pixel * 32)] = (green & 0b10000000) ? led_ON : led_OFF; - _period_buffer[1 + 1 + _green_offset + (pixel * 32)] = (green & 0b01000000) ? led_ON : led_OFF; - _period_buffer[2 + 1 + _green_offset + (pixel * 32)] = (green & 0b00100000) ? led_ON : led_OFF; - _period_buffer[3 + 1 + _green_offset + (pixel * 32)] = (green & 0b00010000) ? led_ON : led_OFF; - _period_buffer[4 + 1 + _green_offset + (pixel * 32)] = (green & 0b00001000) ? led_ON : led_OFF; - _period_buffer[5 + 1 + _green_offset + (pixel * 32)] = (green & 0b00000100) ? led_ON : led_OFF; - _period_buffer[6 + 1 + _green_offset + (pixel * 32)] = (green & 0b00000010) ? led_ON : led_OFF; - _period_buffer[7 + 1 + _green_offset + (pixel * 32)] = (green & 0b00000001) ? led_ON : led_OFF; + _period_buffer[0 + 1 + _green_offset + (pixel * data_width)] = (green & 0b10000000) ? led_ON : led_OFF; + _period_buffer[1 + 1 + _green_offset + (pixel * data_width)] = (green & 0b01000000) ? led_ON : led_OFF; + _period_buffer[2 + 1 + _green_offset + (pixel * data_width)] = (green & 0b00100000) ? led_ON : led_OFF; + _period_buffer[3 + 1 + _green_offset + (pixel * data_width)] = (green & 0b00010000) ? led_ON : led_OFF; + _period_buffer[4 + 1 + _green_offset + (pixel * data_width)] = (green & 0b00001000) ? led_ON : led_OFF; + _period_buffer[5 + 1 + _green_offset + (pixel * data_width)] = (green & 0b00000100) ? led_ON : led_OFF; + _period_buffer[6 + 1 + _green_offset + (pixel * data_width)] = (green & 0b00000010) ? led_ON : led_OFF; + _period_buffer[7 + 1 + _green_offset + (pixel * data_width)] = (green & 0b00000001) ? led_ON : led_OFF; - _period_buffer[0 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b10000000) ? led_ON : led_OFF; - _period_buffer[1 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b01000000) ? led_ON : led_OFF; - _period_buffer[2 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b00100000) ? led_ON : led_OFF; - _period_buffer[3 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b00010000) ? led_ON : led_OFF; - _period_buffer[4 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b00001000) ? led_ON : led_OFF; - _period_buffer[5 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b00000100) ? led_ON : led_OFF; - _period_buffer[6 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b00000010) ? led_ON : led_OFF; - _period_buffer[7 + 1 + _blue_offset + (pixel * 32)] = (blue & 0b00000001) ? led_ON : led_OFF; + _period_buffer[0 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b10000000) ? led_ON : led_OFF; + _period_buffer[1 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b01000000) ? led_ON : led_OFF; + _period_buffer[2 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b00100000) ? led_ON : led_OFF; + _period_buffer[3 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b00010000) ? led_ON : led_OFF; + _period_buffer[4 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b00001000) ? led_ON : led_OFF; + _period_buffer[5 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b00000100) ? led_ON : led_OFF; + _period_buffer[6 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b00000010) ? led_ON : led_OFF; + _period_buffer[7 + 1 + _blue_offset + (pixel * data_width)] = (blue & 0b00000001) ? led_ON : led_OFF; if (_has_white) { _period_buffer[0 + 1 + _white_offset + (pixel * 32)] = (white & 0b10000000) ? led_ON : led_OFF; diff --git a/g2core/device/step_dir_driver/step_dir_driver.h b/g2core/device/step_dir_driver/step_dir_driver.h index 390cdb65..da3cfc1e 100644 --- a/g2core/device/step_dir_driver/step_dir_driver.h +++ b/g2core/device/step_dir_driver/step_dir_driver.h @@ -49,7 +49,7 @@ template -struct StepDirStepper : Stepper { +struct StepDirStepper final : Stepper { /* stepper pin assignments */ OutputPin _step; diff --git a/g2core/device/step_dir_hobbyservo/step_dir_hobbyservo.h b/g2core/device/step_dir_hobbyservo/step_dir_hobbyservo.h new file mode 100644 index 00000000..d631b558 --- /dev/null +++ b/g2core/device/step_dir_hobbyservo/step_dir_hobbyservo.h @@ -0,0 +1,153 @@ +/* + * step_dir_hobbyservo.cpp - control over a hobby servo (PWM-driven) using steper Step/Direction/Enable from software + * This file is part of G2 project + * + * Copyright (c) 2016 Alden S. Hart, Jr. + * Copyright (c) 2016 Robert Giseburt + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * As a special exception, you may use this file as part of a software library without + * restriction. Specifically, if other files instantiate templates or use macros or + * inline functions from this file, or you compile this file and link it with other + * files to produce an executable, this file does not by itself cause the resulting + * executable to be covered by the GNU General Public License. This exception does not + * however invalidate any other reasons why the executable file might be covered by the + * GNU General Public License. + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef STEPP_DIR_HOBBYSERVO_H_ONCE +#define STEPP_DIR_HOBBYSERVO_H_ONCE + +#include "MotatePins.h" +#include "MotateTimers.h" + +#include "stepper.h" + +using Motate::pin_number; +using Motate::OutputPin; +using Motate::PWMOutputPin; +using Motate::kStartHigh; +using Motate::kNormal; +using Motate::Timeout; + + +// Motor structures +template // Setup a stepper template to hold our pins +struct StepDirHobbyServo final : Stepper { + /* stepper pin assignments */ + + int16_t _microsteps_per_step = 1; + bool _step_is_forward = false; + int32_t _position = 0; // in steps from 0 - 6400 for a full "rotation" + int32_t _position_computed = 0; // in steps from 0 - 6400 for a full "rotation" + float _min_value; + float _max_value; + float _value_range; + bool _enabled = false; + PWMOutputPin _pwm_pin; + Motate::Timeout check_timer; + + // sets default pwm freq for all motor vrefs (commented line below also sets HiZ) + StepDirHobbyServo(const uint32_t frequency = 50) : Stepper{}, _pwm_pin{kNormal, frequency} { + _pwm_pin.setFrequency(frequency); // redundant due to a bug + uint16_t _top_value = _pwm_pin.getTopValue(); + float frequency_inv = 1.0/(float)frequency; + _min_value = (float)_top_value / ((frequency_inv)/(750.0/1000000.0)); + _max_value = (float)_top_value / ((frequency_inv)/(2000.0/1000000.0)); + _value_range = _max_value - _min_value; + _position_computed = _min_value; + check_timer.set(1); + }; + + /* Optional override of init */ + + /* Functions that must be implemented in subclasses */ + + bool canStep() override { return true; }; + + void setMicrosteps(const uint8_t microsteps) override { + switch (microsteps) { + case (1): { + _microsteps_per_step = 32; + break; + } + case (2): { + _microsteps_per_step = 16; + break; + } + case (4): { + _microsteps_per_step = 8; + break; + } + case (8): { + _microsteps_per_step = 4; + break; + } + case (16): { + _microsteps_per_step = 2; + break; + } + case (32): { + _microsteps_per_step = 1; + break; + } + } + }; + + void _enableImpl() override { + _enabled = true; + _pwm_pin.setExactDutyCycle(_position_computed, true); + }; + + void _disableImpl() override { + _enabled = false; + _pwm_pin.setExactDutyCycle(0, true); + }; + + void stepStart() override { + if (!_enabled) return; + + if (_step_is_forward) { + _position += _microsteps_per_step; + } else { + _position -= _microsteps_per_step; + } + + if (!check_timer.isPast()) { return; } + check_timer.set(10); + + float used_position = _position; + if (used_position > 6400.0) { + used_position = 6400.0; + } + if (used_position < 0.0) { + used_position = 0.0; + } + + _position_computed = _min_value + ((used_position/6400.0) * _value_range); + _pwm_pin.setExactDutyCycle(_position_computed, true); // apply the change + }; + + void stepEnd() override { + }; + + void setDirection(uint8_t new_direction) override { + _step_is_forward = new_direction; + }; + + void setPowerLevel(float new_pl) override { + ; // ignore this + }; +}; + +#endif // STEPP_DIR_HOBBYSERVO_H_ONCE diff --git a/g2core/device/trinamic/tmc2130.h b/g2core/device/trinamic/tmc2130.h index aa6580bd..9c541851 100644 --- a/g2core/device/trinamic/tmc2130.h +++ b/g2core/device/trinamic/tmc2130.h @@ -46,7 +46,7 @@ template -struct Trinamic2130 : Stepper { +struct Trinamic2130 final : Stepper { // Pins that are directly managed OutputPin _step; OutputPin _dir; @@ -501,7 +501,8 @@ struct Trinamic2130 : Stepper { } out_buffer.addr = (uint8_t) next_reg; - _device.queueMessage(_message.setup((uint8_t *)&out_buffer, (uint8_t *)&in_buffer, 5, SPIMessage::DeassertAfter, SPIMessage::KeepTransaction)); + _message.setup((uint8_t *)&out_buffer, (uint8_t *)&in_buffer, 5, SPIMessage::DeassertAfter, SPIMessage::KeepTransaction); + _device.queueMessage(&_message); }; void _doneReadingCallback() @@ -538,7 +539,7 @@ struct Trinamic2130 : Stepper { _reading_only = false; _transmitting = false; - _startNextReadWrite(); + //_startNextReadWrite(); }; void init() override diff --git a/g2core/error.h b/g2core/error.h old mode 100755 new mode 100644 diff --git a/g2core/g2core.cppproj b/g2core/g2core.cppproj index 2b1f1c3d..4669f074 100644 --- a/g2core/g2core.cppproj +++ b/g2core/g2core.cppproj @@ -1454,6 +1454,72 @@ Makefile bin\PrintrbotSimple1608-printrboardG2v3\ + + + + True + True + True + True + True + + + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\CMSIS\Include + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL\sam3xa\include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\CMSIS\Include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL\sam3xa\include + + + Optimize (-O1) + True + Maximum (-g3) + True + + + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\CMSIS\Include + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL + C:\Program Files\Atmel\Atmel Studio 6.0\extensions\Atmel\ARMGCC\3.3.1.128\ARMSupportFiles\Device\ATMEL\sam3xa\include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\CMSIS\Include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL\sam3xa\include + + + Optimize (-O1) + True + Maximum (-g3) + True + + + libm + + + True + -Tsam3x8c_flash.ld + Default (-g) + + + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\CMSIS\Include + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL + C:\Program Files\Atmel\Atmel Toolchain\ARM GCC\Native\4.7.2.87\arm-gnu-toolchain\bin\..\..\CMSIS_Atmel\Device\ATMEL\sam3xa\include + + + Default (-Wa,-g) + + + True + + CONFIG=TestQuadratic COLOR=0 VERBOSE=1 DEBUG=1 + clean CONFIG=TestQuintic + Makefile + bin\TestQuadratic\ + compile @@ -1542,7 +1608,7 @@ compile - + compile @@ -1566,7 +1632,7 @@ compile - + compile diff --git a/g2core/g2core.xcodeproj/project.pbxproj b/g2core/g2core.xcodeproj/project.pbxproj index d6ac4fe3..e4d1864c 100644 --- a/g2core/g2core.xcodeproj/project.pbxproj +++ b/g2core/g2core.xcodeproj/project.pbxproj @@ -58,6 +58,8 @@ D44E72C21D663B0F00ECD5DD /* coolant.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = coolant.h; sourceTree = ""; }; D4522DC91C45F41D0086AAE6 /* g2core_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = g2core_info.h; sourceTree = ""; }; D457117B17053EFA00EA19A8 /* Makefile */ = {isa = PBXFileReference; explicitFileType = sourcecode.make; fileEncoding = 4; path = Makefile; sourceTree = ""; usesTabs = 1; xcLanguageSpecificationIdentifier = xcode.lang.sh; }; + D4782AB21D9B5F9400B32136 /* settings_watercolorbot_v2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = settings_watercolorbot_v2.h; sourceTree = ""; }; + D4782AB41D9E2FF300B32136 /* settings_eggbot.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = settings_eggbot.h; sourceTree = ""; }; D47B744C1D4925B4004FAB53 /* device */ = {isa = PBXFileReference; lastKnownFileType = folder; path = device; sourceTree = ""; }; D48F5A40172CB1F900D0E055 /* canonical_machine.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = canonical_machine.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; D48F5A41172CB1F900D0E055 /* config_app.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; lineEnding = 0; path = config_app.cpp; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.cpp; }; @@ -146,6 +148,8 @@ isa = PBXGroup; children = ( D4AC39081C77C1F20098D685 /* settings_default.h */, + D4782AB41D9E2FF300B32136 /* settings_eggbot.h */, + D4782AB21D9B5F9400B32136 /* settings_watercolorbot_v2.h */, D4AC39091C77C1F20098D685 /* settings_makeblock.h */, D4AC390A1C77C1F20098D685 /* settings_othermill_test.h */, D4AC390B1C77C1F20098D685 /* settings_othermill.h */, @@ -291,6 +295,34 @@ passBuildSettingsInEnvironment = 1; productName = g3_due; }; + D4782AAE1D9B16BE00B32136 /* G2 Probotix */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION) VERBOSE=1 COLOR=0 CONFIG=ProbotixV90 DEBUG=1"; + buildConfigurationList = D4782AAF1D9B16BE00B32136 /* Build configuration list for PBXLegacyTarget "G2 Probotix" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = .; + dependencies = ( + ); + name = "G2 Probotix"; + passBuildSettingsInEnvironment = 1; + productName = g3_due; + }; + D4782AB61D9E39EC00B32136 /* G2 EggBot */ = { + isa = PBXLegacyTarget; + buildArgumentsString = "$(ACTION) VERBOSE=1 COLOR=0 CONFIG=EggBot DEBUG=1"; + buildConfigurationList = D4782AB71D9E39EC00B32136 /* Build configuration list for PBXLegacyTarget "G2 EggBot" */; + buildPhases = ( + ); + buildToolPath = /usr/bin/make; + buildWorkingDirectory = .; + dependencies = ( + ); + name = "G2 EggBot"; + passBuildSettingsInEnvironment = 1; + productName = g3_due; + }; D4AC391A1C7BAB8E0098D685 /* G2 sbv300 */ = { isa = PBXLegacyTarget; buildArgumentsString = "$(ACTION) VERBOSE=1 COLOR=0 CONFIG=sbv300 DEBUG=2"; @@ -349,7 +381,7 @@ }; D4F226F31D088A48008ED57C /* G2 gQuintic PrintrbotPlus */ = { isa = PBXLegacyTarget; - buildArgumentsString = "$(ACTION) VERBOSE=1 COLOR=0 CONFIG=PrintrbotPlus BOARD=gquintic-a DEBUG=2"; + buildArgumentsString = "$(ACTION) VERBOSE=1 COLOR=0 CONFIG=PrintrbotPlus BOARD=gquintic-b DEBUG=2"; buildConfigurationList = D4F226F41D088A48008ED57C /* Build configuration list for PBXLegacyTarget "G2 gQuintic PrintrbotPlus" */; buildPhases = ( ); @@ -411,7 +443,9 @@ D4AC391A1C7BAB8E0098D685 /* G2 sbv300 */, D4F226F31D088A48008ED57C /* G2 gQuintic PrintrbotPlus */, D43FF7141D537A5C00FB5B53 /* G2 gQuadratic Test */, + D4782AAE1D9B16BE00B32136 /* G2 Probotix */, D457112317053BFB00EA19A8 /* index */, + D4782AB61D9E39EC00B32136 /* G2 EggBot */, ); }; /* End PBXProject section */ @@ -653,6 +687,38 @@ }; name = Release; }; + D4782AB01D9B16BE00B32136 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PATH = "$PATH:/usr/local/gcc-arm-none-eabi/bin"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + D4782AB11D9B16BE00B32136 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PATH = "$PATH:/usr/local/gcc-arm-none-eabi/bin"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + D4782AB81D9E39EC00B32136 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + PATH = "$PATH:/usr/local/gcc-arm-none-eabi/bin"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + D4782AB91D9E39EC00B32136 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + PATH = "$PATH:/usr/local/gcc-arm-none-eabi/bin"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; D4AC391C1C7BAB8E0098D685 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -790,6 +856,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + D4782AAF1D9B16BE00B32136 /* Build configuration list for PBXLegacyTarget "G2 Probotix" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D4782AB01D9B16BE00B32136 /* Debug */, + D4782AB11D9B16BE00B32136 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D4782AB71D9E39EC00B32136 /* Build configuration list for PBXLegacyTarget "G2 EggBot" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D4782AB81D9E39EC00B32136 /* Debug */, + D4782AB91D9E39EC00B32136 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; D4AC391B1C7BAB8E0098D685 /* Build configuration list for PBXLegacyTarget "G2 sbv300" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/g2core/g2core_info.h b/g2core/g2core_info.h index d81a3420..f9a5344a 100644 --- a/g2core/g2core_info.h +++ b/g2core/g2core_info.h @@ -21,7 +21,7 @@ #ifndef G2CORE_INFO_H_ONCE #define G2CORE_INFO_H_ONCE -#define G2CORE_FIRMWARE_BUILD 100.12 // Fix UART flow control +#define G2CORE_FIRMWARE_BUILD 100.12 // Changes to USB serial for SAMS70 and SAM8X targets #ifdef GIT_VERSION #define G2CORE_FIRMWARE_BUILD_STRING GIT_VERSION #else diff --git a/g2core/gcode_parser.cpp b/g2core/gcode_parser.cpp old mode 100755 new mode 100644 index c8095d18..cd591cda --- a/g2core/gcode_parser.cpp +++ b/g2core/gcode_parser.cpp @@ -697,6 +697,7 @@ static stat_t _execute_gcode_block(char *active_comment) cm.gn.motion_mode); break; } + default: break; } cm_set_absolute_override(MODEL, ABSOLUTE_OVERRIDE_OFF); // un-set absolute override once the move is planned } diff --git a/g2core/plan_arc.cpp b/g2core/plan_arc.cpp index 8698c231..d9dc6bc8 100644 --- a/g2core/plan_arc.cpp +++ b/g2core/plan_arc.cpp @@ -108,7 +108,7 @@ stat_t cm_arc_feed(const float target[], const bool target_f[], // target en const float radius, const bool radius_f, // radius if radius mode const float P_word, const bool P_word_f, // parameter const bool modal_g1_f, // modal group flag for motion group - const uint8_t motion_mode) // defined motion mode + const cmMotionMode motion_mode) // defined motion mode { // Start setting up the arc and trapping arc specification errors diff --git a/g2core/plan_exec.cpp b/g2core/plan_exec.cpp index 8ea3fef7..8727e4e4 100644 --- a/g2core/plan_exec.cpp +++ b/g2core/plan_exec.cpp @@ -46,96 +46,197 @@ static stat_t _exec_aline_segment(void); static void _init_forward_diffs(float v_0, float v_1); -/************************************************************************* - * mp_plan_move() - call ramping function to plan moves ahead of the exec +/******************************************************************************* + * mp_forward_plan() - plan commands and moves ahead of exec; call ramping for moves * - * This should NOT normally be called directly! Instead call st_request_plan_move(). + **** WARNING **** + * This function should NOT be called directly! + * Instead call st_request_forward_plan(), which mediates access. * + * mp_forward_plan() performs just-in-time forward planning immediately before + * lines and commands are queued to the move execution runtime (exec). + * Unlike backward planning, buffers are only forward planned once. + * + * mp_forward_plan() is called aggressively via st_request_forward_plan(). + * It has a relatively low interrupt level to call its own. + * See also: Planner Overview notes in planner.h + * + * It examines the currently running buffer and its adjacent buffers to: + * + * - Stop the system from re-planning or planning something that's not prepped + * - Plan the next available ALINE (movement) block past the COMMAND blocks + * - Skip past/ or pre-plan COMMAND blocks while labeling them as PLANNED + * + * Returns: + * - STAT_OK if exec should be called to kickstart (or continue) movement + * - STAT_NOOP to exit with no action taken (do not call exec) + */ +/* + * --- Forward Planning Processing and Cases --- + * + * These cases describe all possible sequences of buffers in the planner queue starting + * with the currently executing (or about to execute) Run buffer, looking forward + * to more recently arrived buffers. In most cases only one or two buffers need to + * be examined, but contiguous groups of commands may need to be processed. + * + * 'Running' cases are where the run buffer state is RUNNING. Bootstrap handles all other cases. + * 'Bootstrap' occurs during the startup phase where moves are collected before starting movement. + * Conditions that are impossible based on this definition are not listed in the tables below. + * + * See planner.h / bufferState enum for shorthand used in the descriptions. + * All cases assume a mix of moves and commands, as noted in the shorthand. + * All cases assume 2 'blocks' - Run block & Plan block. Cases will need to be + * revisited and generalized if more blocks are used in the future (deeper + * forward planning). + * + * 'NOT_PREPPED' refers to any preliminary state below PREPPED, i.e. < PREPPED. + * ' NOT_PREPPED' can be either a move or command, we don't care so it's not specified. + * + * 'COMMAND' or 'COMMAND(s)' refers to one command or a contiguous group of command buffers + * that may be in PREPPED or PLANNED states. Processing is always the same. Plan all + * PREPPED commands and skip past all PLANNED commands. + * + * Note 1: For MOVEs use the exit velocity of the Run block (mr.r->exit_velocity) as the + * entry velocity of the next adjacent move. + * + * Note 1a: In this special COMMAND case we trust mr.r->exit_velocity because the + * backplanner has already handled this case for us. + * + * Note 2: For COMMANDs use the entry velocity of the current runtime (mr.entry_velocity) + * as the entry velocity for the next adjacent move. mr.entry_velocity is almost always 0, + * but could be non-0 in a race condition. + * FYI: mr.entry_velocity is set at the end of the last running block in mp_exec_aline(). + * + * + * CASE: + * 0. Nothing to do + * + * run_buffer + * ---------- + * a. Run buffer has not yet been initialized (prep null buffer and return NOOP) + * b. NOT_PREPPED No moves or commands in run buffer. Exit with no action + * + * 1. Bootstrap cases (buffer state < RUNNING) + * + * run_buffer next N bufs terminal buf Actions + * ---------- ----------- ------------ ---------------------------------- + * a. PREPPED-MOVE plan move, exit OK + * b. PLANNED-MOVE NOT_PREPPED exit NOOP + * c. PLANNED-MOVE PREPPED-MOVE exit NOOP (don't plan past a PLANNED buffer) + * d. PLANNED-MOVE PLANNED-MOVE trap illegal condition, exit NOOP + * e. PLANNED-MOVE COMMAND(s) exit NOOP + * f. PREPPED-COMMAND NOT_PREPPED plan command, exit OK + * g. PREPPED-COMMAND PREPPED-MOVE plan command, plan move (Note 2), exit OK + * h. PREPPED-COMMAND PLANNED-MOVE trap illegal condition, exit NOOP + * i. PLANNED-COMMAND NOT_PREPPED skip command, exit OK + * j. PLANNED-COMMAND PREPPED-MOVE skip command, plan move (Note 2), exit OK + * k. PLANNED-COMMAND PLANNED-MOVE exit NOOP + * + * 2. Running cases (buffer state == RUNNING) + * + * run_buffer next N bufs terminal buf Actions + * ---------- ----------- ------------ ---------------------------------- + * a. RUNNING-MOVE PREPPED-MOVE plan move, exit OK + * b. RUNNING-MOVE PLANNED-MOVE exit NOOP + * c. RUNNING-MOVE COMMAND(s) NOT_PREPPED skip/plan command(s), exit OK + * d. RUNNING-MOVE COMMAND(s) PREPPED-MOVE skip/plan command(s), plan move, exit OK + * e. RUNNING-MOVE COMMAND(s) PLANNED-MOVE exit NOOP + * f. RUNNING-COMMAND PREPPED-MOVE plan move, exit OK + * g. RUNNING-COMMAND PLANNED-MOVE exit NOOP + * h. RUNNING-COMMAND COMMAND(s) NOT_PREPPED skip/plan command(s), exit OK + * i. RUNNING-COMMAND COMMAND(s) PREPPED-MOVE skip/plan command(s), plan move (Note 1a), exit OK + * j. RUNNING-COMMAND COMMAND(s) PLANNED-MOVE skip command(s), exit NOOP + * (Note: all COMMAND(s) in j. should be in PLANNED state) */ -stat_t mp_plan_move() +static mpBuf_t *_plan_commands(mpBuf_t *bf) // plan or skip commands; return bf past last command { - mpBuf_t *bf; + // must test for buffer state first as the buffer is only "safe" once it's >= PREPPED + while ((bf->buffer_state >= MP_BUFFER_PREPPED) && (bf->block_type >= BLOCK_TYPE_COMMAND)) { + if (bf->buffer_state != MP_BUFFER_PLANNED) { // skip already planned buffers + bf->buffer_state = MP_BUFFER_PLANNED; // "planning" is just setting the state (for now) + } + bf = bf->nx; + } + return (bf); +} - // NULL means nothing's running - this is OK - if ((bf = mp_get_run_buffer()) == NULL) { +static stat_t _plan_move(mpBuf_t *bf, float entry_velocity) +{ + // Calculate ramps for the current planning block and the next PREPPED buffer + // The PREPPED buffer will be set to PLANNED later... + // + // Pass in the bf buffer that will "link" with the planned block + // The block and the buffer are implicitly linked for exec_aline() + // + // Note that that can only be one PLANNED move at a time. + // This is to help sync mr.p to point to the next planned mr.bf + // mr.p is only advanced in mp_exec_aline(), after mp.r = mr.p. + // This code aligns the buffers and the blocks for exec_aline(). + + mpBlockRuntimeBuf_t* block = mr.p; // set a local planning block so it doesn't change on you + mp_calculate_ramps(block, bf, entry_velocity); // (which it will if you don't do this) + + // diagnostic traps + if (block->exit_velocity > block->cruise_velocity) { + __asm__("BKPT"); // exit > cruise after calculate_block + } + if (block->head_length < 0.00001 && block->body_length < 0.00001 && block->tail_length < 0.00001) { + __asm__("BKPT"); // zero or negative length block + } + bf->buffer_state = MP_BUFFER_PLANNED; //...here + bf->plannable = false; + return (STAT_OK); // report that we planned something... +} + +stat_t mp_forward_plan() +{ + mpBuf_t *bf = mp_get_run_buffer(); + float entry_velocity; + + // Case 0: Examine current running buffer for early exit conditions + if (bf == NULL) { // case 0a: NULL means nothing is running - this is OK st_prep_null(); return (STAT_NOOP); } - - if (bf->buffer_state < MP_BUFFER_PREPPED) { - // Get outta here. - // We did nothing + if (bf->buffer_state < MP_BUFFER_PREPPED) { // case 0b: nothing to do. get outta here. return (STAT_NOOP); } - if (bf->block_type != BLOCK_TYPE_ALINE) { - // Nothing to see here... - - bf->buffer_state = MP_BUFFER_PLANNED; - - // report that we "planned" something... - return (STAT_OK); - } - - // We default to the planning block - mpBlockRuntimeBuf_t* block = mr.p; - - // Default to the planning buffer - float entry_velocity = mr.entry_velocity; - - // At this point, bf == bf.r + // Case 2: Running cases - move bf past run buffer so it acts like case 1 if (bf->buffer_state == MP_BUFFER_RUNNING) { - // Update bf to bf->nx, set entry_* to mr.r->exit_*. bf = bf->nx; - entry_velocity = mr.r->exit_velocity; + entry_velocity = mr.r->exit_velocity; // set Note 1 entry_velocity (move cases) + } else { + entry_velocity = mr.entry_velocity; // set Note 2 entry velocity (command cases) + } - if (bf->buffer_state < MP_BUFFER_PREPPED) { - // Get outta here. - // We did nothing - return (STAT_NOOP); - } + // bf points to command; start cases 1f, 1g, 1h, 1i, 1j, 1k, 2c, 2d, 2e, 2h, 2i, 2j + if (bf->block_type != BLOCK_TYPE_ALINE) { // meaning it's a COMMAND + bf = _plan_commands(bf); // plan commands or skip past already planned commands + // bf now points to the first non-command buffer past the command(s) + if ((bf->block_type == BLOCK_TYPE_ALINE) && (bf->buffer_state > MP_BUFFER_PREPPED )) { // case 1i + entry_velocity = mr.r->exit_velocity; // set entry_velocity for Note 1a + } + } + // bf will always be on a non-command at this point - either a move or empty buffer - if (bf->block_type != BLOCK_TYPE_ALINE) { - // Nothing to see here... - - bf->buffer_state = MP_BUFFER_PLANNED; - // report that we "planned" something... - return (STAT_OK); + // process move + if (bf->block_type == BLOCK_TYPE_ALINE) { // do cases 1a - 1e; finish cases 1f - 1k + if (bf->buffer_state == MP_BUFFER_PREPPED) {// do 1a; finish 1f, 1j, 2d, 2i + return (_plan_move(bf, entry_velocity)); + } else { + return (STAT_NOOP); // do 1b, 1c, 1d, 1e; finish 1g, 1h, 1j, 1k, 2e, 2j } } - - if (bf->buffer_state == MP_BUFFER_PLANNED) { - // Get outta here. - // We did nothing - return (STAT_NOOP); - } - - // Note that that can only be one PLANNED move at a time. - // This is to help sync mr.p to point to the next planned mr.bf - // mr.p is only advanced in mp_exec_aline, after mp.r = mr.p. - - mp_calculate_ramps(block, bf, entry_velocity); - - if (block->exit_velocity > block->cruise_velocity) { - __asm__("BKPT"); // exit > cruise after calculate_block - } - if (block->head_length < 0.00001 && block->body_length < 0.00001 && block->tail_length < 0.00001) { - __asm__("BKPT"); // zero or negative length block - } - - bf->buffer_state = MP_BUFFER_PLANNED; - bf->plannable = false; - - // report that we planned something... - return (STAT_OK); + return (STAT_OK); // report that we planned something... } /************************************************************************* * mp_exec_move() - execute runtime functions to prep move for steppers * - * Dequeues the buffer queue and executes the move continuations. - * Manages run buffers and other details + * Dequeues the buffer queue and executes the move continuations. + * Manages run buffers and other details */ stat_t mp_exec_move() @@ -149,12 +250,12 @@ stat_t mp_exec_move() } if (bf->block_type == BLOCK_TYPE_ALINE) { // cycle auto-start for lines only + // first-time operations if (bf->buffer_state != MP_BUFFER_RUNNING) { if ((bf->buffer_state < MP_BUFFER_PREPPED) && (cm.motion_state == MOTION_RUN)) { - __asm__("BKPT"); - // rpt_exception(42, "mp_exec_move() buffer is not prepped"); - // ^^^ CAUSES A CRASH. We can't rpt_exception from here! + __asm__("BKPT"); // mp_exec_move() buffer is not prepped + // IMPORTANT: We can't rpt_exception from here! st_prep_null(); return (STAT_NOOP); } @@ -166,11 +267,11 @@ stat_t mp_exec_move() if (bf->buffer_state == MP_BUFFER_PREPPED) { if (cm.motion_state == MOTION_RUN) { -// __asm__("BKPT"); // we are running but don't have a block planned + __asm__("BKPT"); // we are running but don't have a block planned } // We need to have it planned. We don't want to do this here, as it // might already be happening in a lower interrupt. - st_request_plan_move(); + st_request_forward_plan(); return (STAT_NOOP); } @@ -182,12 +283,12 @@ stat_t mp_exec_move() mp_planner_time_accounting(); } - if (bf->nx->buffer_state == MP_BUFFER_PREPPED) { + if (bf->nx->buffer_state >= MP_BUFFER_PREPPED) { // We go ahead and *ask* for a forward planning of the next move. // This won't call mp_plan_move until we leave this function // (and have called mp_exec_aline via bf->bf_func). // This also allows mp_exec_aline to advance mr.p first. - st_request_plan_move(); + st_request_forward_plan(); } // Manage motion state transitions @@ -215,24 +316,23 @@ stat_t mp_exec_move() * Returns: * STAT_OK move is done * STAT_EAGAIN move is not finished - has more segments to run - * STAT_NOOP cause no operation from the steppers - do not load the move - * STAT_xxxxx fatal error. Ends the move and frees the bf buffer + * STAT_NOOP cause no operation from the steppers - do not load the move + * STAT_xxxxx fatal error. Ends the move and frees the bf buffer * - * This routine is called from the (LO) interrupt level. The interrupt - * sequencing relies on the behaviors of the routines being exactly correct. - * Each call to _exec_aline() must execute and prep *one and only one* - * segment. If the segment is the not the last segment in the bf buffer the - * _aline() must return STAT_EAGAIN. If it's the last segment it must return - * STAT_OK. If it encounters a fatal error that would terminate the move it - * should return a valid error code. Failure to obey this will introduce - * subtle and very difficult to diagnose bugs (trust me on this). + * This routine is called from the (LO) interrupt level. The interrupt sequencing + * relies on the behaviors of the routines being exactly correct. Each call to + * _exec_aline() must execute and prep *one and only one* segment. If the segment + * is the not the last segment in the bf buffer the _aline() must return STAT_EAGAIN. + * If it's the last segment it must return STAT_OK. If it encounters a fatal error + * that would terminate the move it should return a valid error code. Failure to + * obey this will introduce subtle and very difficult to diagnose bugs (trust us on this). * - * Note 1 Returning STAT_OK ends the move and frees the bf buffer. + * Note 1: Returning STAT_OK ends the move and frees the bf buffer. * Returning STAT_OK at this point does NOT advance position meaning any * position error will be compensated by the next move. * - * Note 2 Solves a potential race condition where the current move ends but the - * new move has not started because the previous move is still being run + * Note 2: Solves a potential race condition where the current move ends but the + * new move has not started because the previous move is still being run * by the steppers. Planning can overwrite the new move. */ /* --- State transitions - hierarchical state machine --- @@ -247,12 +347,35 @@ stat_t mp_exec_move() * _NEW - trigger initialization * _RUN1 - run the first part * _RUN2 - run the second part + * + * Important distinction to note: + * - mp_plan move() is called for every type of move + * - mp_exec_move() is called for every type of move + * - mp_exec_aline() is only called for alines */ -/* Note: - * For a version of these routines that execute using the original equation-of-motion - * math (as opposed to the forward difference math) please refer to build 357.xx or earlier. - * Builds 358 onward have only forward difference code. ALso, the Kahan corrections for the - * forward differencing were also been removed shortly after as they were not needed. +/* Synchronization of run BUFFER and run BLOCK + * + * Note first: mp_exec_aline() makes a huge assumption: When it comes time to get a + * new run block (mr.r) it assumes the planner block (mr.p) has been fully planned + * via the JIT forward planning and is ready for use as the new run block. + * + * The runtime uses 2 structures for the current move or commend, the run BUFFER + * from the planner queue (mb.r, aka bf), and the run BLOCK from the runtime + * singleton (mr.r). These structures are synchronized implicitly, but not + * explicitly referenced, as pointers can lead to race conditions. + * See plan_zoid.cpp / mp_calculate_ramps() for more details + * + * When mp_exec_aline() needs to grab a new planner buffer for a new move or command + * (i.e. block state is inactive) it swaps (rolls) the run and planner BLOCKS so that + * mr.p (planner block) is now the mr.r (run block), and the old mr.r block becomes + * available for planning; it becomes mr.p block. + * + * At the same time, it's when finished with its current run buffer (mb.r), it has already + * advanced to the next buffer. mp_exec_move() does this at the end of previous move. + * Or in the bootstrap case, there never was a previous mb.r, so the current one is OK. + * + * As if by magic, the new mb.r aligns with the run block that was just moved in from + * the planning block. */ /**** NOTICE ** NOTICE ** NOTICE **** @@ -285,13 +408,15 @@ stat_t mp_exec_aline(mpBuf_t *bf) // Start a new move by setting up the runtime singleton (mr) memcpy(&mr.gm, &(bf->gm), sizeof(GCodeState_t)); // copy in the gcode model state - bf->block_state = BLOCK_ACTIVE; // note that this buffer is running -- note the planner doesn't look at block_state + bf->block_state = BLOCK_ACTIVE; // note that this buffer is running + // note the planner doesn't look at block_state mr.block_state = BLOCK_INITIAL_ACTION; mr.section = SECTION_HEAD; mr.section_state = SECTION_NEW; - mr.r = mr.p; - mr.p = mr.p->nx; + // This is the only place in the system where mr.r and mr.p are allowed to be changed + mr.r = mr.p; // we are now going to run the planning block + mr.p = mr.p->nx; // re-use the old running block as the new planning block // Assumptions that are required for this to work: // entry velocity <= cruise velocity && cruise velocity >= exit velocity @@ -508,11 +633,11 @@ stat_t mp_exec_aline(mpBuf_t *bf) } // There are 4 things that can happen here depending on return conditions: - // status bf->block_state Description - // ----------- -------------- ---------------------------------------- - // STAT_EAGAIN mr buffer has more segments to run - // STAT_OK BLOCK_ACTIVE mr and bf buffers are done - // STAT_OK BLOCK_INITIAL_ACTION mr done; bf must be run again (it's been reused) + // status bf->block_state Description + // ----------- -------------- ---------------------------------------- + // STAT_EAGAIN mr buffer has more segments to run + // STAT_OK BLOCK_ACTIVE mr and bf buffers are done + // STAT_OK BLOCK_INITIAL_ACTION mr done; bf must be run again (it's been reused) // There is no fourth thing. Nobody expects the Spanish Inquisition if (status == STAT_EAGAIN) { @@ -531,7 +656,7 @@ stat_t mp_exec_aline(mpBuf_t *bf) cm_cycle_end(); // free buffer & end cycle if planner is empty } } else { - st_request_plan_move(); + st_request_forward_plan(); } } } @@ -821,6 +946,9 @@ static stat_t _exec_aline_body(mpBuf_t *bf) mr.section_state = SECTION_RUNNING; // uses PERIOD_2 so last segment detection works } if (_exec_aline_segment() == STAT_OK) { // OK means this section is done + if (fp_ZERO(mr.r->tail_length)) { + return(STAT_OK); // ends the move + } mr.section = SECTION_TAIL; mr.section_state = SECTION_NEW; } diff --git a/g2core/plan_line.cpp b/g2core/plan_line.cpp index 27637acd..1132345b 100644 --- a/g2core/plan_line.cpp +++ b/g2core/plan_line.cpp @@ -35,6 +35,7 @@ #include "report.h" #include "util.h" #include "spindle.h" +#include "settings.h" #include "xio.h" @@ -102,7 +103,7 @@ float mp_get_runtime_work_position(uint8_t axis) { /* * mp_get_runtime_busy() - returns TRUE if motion control busy (i.e. robot is moving) - * mp_runtime_is_idle() - returns TRUE is steppers are not actively moving + * mp_runtime_is_idle() - returns TRUE is steppers are not actively moving * * Use mp_get_runtime_busy() to sync to the queue. If you wait until it returns * FALSE you know the queue is empty and the motors have stopped. @@ -148,31 +149,36 @@ stat_t mp_aline(GCodeState_t* gm_in) float length; // A few notes about the rotated coordinate space: - // These are position PRE-rotation: + // These are positions PRE-rotation: // gm_in.* (anything in gm_in) // // These are positions POST-rotation: - // target_rotated (after the rotiton here, of course) + // target_rotated (after the rotation here, of course) // mp.* (anything in mp, including mp.gm.*) - - // a being target[0], - // b being target[1], - // c being target[2], - // x_1 being cm.rotation_matrix[1][0] - + // // Shorthand: - // target_rotated[0] = a x_0 + b y_0 + c z_0 - // target_rotated[1] = a x_1 + b y_1 + c z_1 - // target_rotated[2] = a x_2 + b y_2 + c z_2 + z_offset + // target_rotated[0] = a x_0 + b y_0 + c z_0 + // target_rotated[1] = a x_1 + b y_1 + c z_1 + // target_rotated[2] = a x_2 + b y_2 + c z_2 + z_offset + // + // With: + // a being target[0], + // b being target[1], + // c being target[2], + // x_1 being cm.rotation_matrix[1][0] - target_rotated[0] = gm_in->target[0] * cm.rotation_matrix[0][0] + gm_in->target[1] * cm.rotation_matrix[0][1] + + target_rotated[0] = gm_in->target[0] * cm.rotation_matrix[0][0] + + gm_in->target[1] * cm.rotation_matrix[0][1] + gm_in->target[2] * cm.rotation_matrix[0][2]; - target_rotated[1] = gm_in->target[0] * cm.rotation_matrix[1][0] + gm_in->target[1] * cm.rotation_matrix[1][1] + + target_rotated[1] = gm_in->target[0] * cm.rotation_matrix[1][0] + + gm_in->target[1] * cm.rotation_matrix[1][1] + gm_in->target[2] * cm.rotation_matrix[1][2]; - target_rotated[2] = gm_in->target[0] * cm.rotation_matrix[2][0] + gm_in->target[1] * cm.rotation_matrix[2][1] + - gm_in->target[2] * cm.rotation_matrix[2][2] + cm.rotation_z_offset; + target_rotated[2] = gm_in->target[0] * cm.rotation_matrix[2][0] + + gm_in->target[1] * cm.rotation_matrix[2][1] + + gm_in->target[2] * cm.rotation_matrix[2][2] + + cm.rotation_z_offset; // copy rotation axes ABC target_rotated[3] = gm_in->target[3]; @@ -194,6 +200,7 @@ stat_t mp_aline(GCodeState_t* gm_in) if (fp_ZERO(length)) { sr_request_status_report(SR_REQUEST_TIMED_FULL); // Was SR_REQUEST_IMMEDIATE_FULL return (STAT_MINIMUM_LENGTH_MOVE); +// return (STAT_OK); //+++++ test this } // get a cleared buffer and copy in the Gcode model state @@ -261,7 +268,7 @@ void mp_plan_block_list() } if (mp.planner_state > PLANNER_STARTUP) { if (planned_something && (cm.hold_state != FEEDHOLD_HOLD)) { - st_request_plan_move(); // start motion if runtime is not already busy + st_request_forward_plan(); // start motion if runtime is not already busy } } mp.p = bf; // update planner pointer @@ -287,13 +294,13 @@ static mpBuf_t* _plan_block(mpBuf_t* bf) } } _calculate_override(bf); // adjust cruise_vmax for feed/traverse override - // bf->plannable_time = bf->pv->plannable_time; // set plannable time - excluding current move + // bf->plannable_time = bf->pv->plannable_time; // set plannable time - excluding current move bf->buffer_state = MP_BUFFER_IN_PROCESS; // +++++ Why do we have to do this here? // bf->pv_group = bf->pv; - bf->hint = NO_HINT; // ensure we've cleared the hints + bf->hint = NO_HINT; // ensure we've cleared the hints // Time: 12us-41us if (bf->nx->plannable) { // read in new buffers until EMPTY return (bf->nx); @@ -321,15 +328,15 @@ static mpBuf_t* _plan_block(mpBuf_t* bf) bf->iterations++; bf->plannable = bf->plannable && !optimal; // Don't accidentally enable plannable! - // Let's be mindful that for ward planning may change exit_vmax, and our exit velocity may be lowered + // Let's be mindful that forward planning may change exit_vmax, and our exit velocity may be lowered braking_velocity = min(braking_velocity, bf->exit_vmax); // We *must* set cruise before exit, and keep it at least as high as exit. bf->cruise_velocity = max(braking_velocity, bf->cruise_velocity); bf->exit_velocity = braking_velocity; - // We have two places where it could be a mixed decel or an asymetric bump, - // dpending on if the pv->exit_vmax is the same as bf.cruise_vmax + // We have two places where it could be a mixed decel or an asymmetric bump, + // depending on if the pv->exit_vmax is the same as bf.cruise_vmax bool test_decel_or_bump = false; // command blocks @@ -505,7 +512,22 @@ static void _calculate_jerk(mpBuf_t* bf) for (uint8_t axis = 0; axis < AXES; axis++) { if (fabs(bf->unit[axis]) > 0) { // if this axis is participating in the move - jerk = cm.a[axis].jerk_max / fabs(bf->unit[axis]); + float axis_jerk = 0; +#ifdef TRAVERSE_AT_HIGH_JERK +#warning using experimental feature TRAVERSE_AT_HIGH_JERK! + switch (bf->gm.motion_mode) { + case MOTION_MODE_STRAIGHT_TRAVERSE: + //case MOTION_MODE_STRAIGHT_PROBE: // <-- not sure on this one + axis_jerk = cm.a[axis].jerk_high; + break; + default: + axis_jerk = cm.a[axis].jerk_max; + } +#else + axis_jerk = cm.a[axis].jerk_max; +#endif + + jerk = axis_jerk / fabs(bf->unit[axis]); if (jerk < bf->jerk) { bf->jerk = jerk; // bf->jerk_axis = axis; // +++ diagnostic diff --git a/g2core/plan_zoid.cpp b/g2core/plan_zoid.cpp old mode 100755 new mode 100644 index 8e9c3025..28a54ee4 --- a/g2core/plan_zoid.cpp +++ b/g2core/plan_zoid.cpp @@ -80,7 +80,7 @@ static float _get_meet_velocity(const float v_0, * * Note we use three data structures: mr, bf, and block. * - * bf holds the data from aline and back-planning. For the most part it is immuatable. + * bf holds the data from aline and back-planning. For the most part it is immutable. * * block is the data for forward-planning. There are only two block structures, and they * are for the current block and the next block. @@ -94,8 +94,8 @@ static float _get_meet_velocity(const float v_0, * * All values of block are expected to be setup by mp_calculate_ramps. * - * Quick cheat-sheet on which is in bf and whcih is in block: - * bf: + * Quick cheat-sheet on which is in buffer (bf) and which is in block: + * buffer (bf): * block_type * hint * {cruise,exit}_vmax @@ -290,9 +290,9 @@ void mp_calculate_ramps(mpBlockRuntimeBuf_t* block, mpBuf_t* bf, const float ent // PERFECT_DECELERATION // MIXED_DECELERATION - // All that remians is ASYMMETRIC_BUMP and SYMMETRIC_BUMP. + // All that remains is ASYMMETRIC_BUMP and SYMMETRIC_BUMP. // We don't really care if it's symmetric, since the first test that _get_meet_velocity - // does is for a symmetic move. It's cheaper to just let it do that then to try and prevent it. + // does is for a symmetric move. It's cheaper to just let it do that then to try and prevent it. // *** Requested-Fit cases (2) *** diff --git a/g2core/planner.cpp b/g2core/planner.cpp index 04714315..0f17ef13 100644 --- a/g2core/planner.cpp +++ b/g2core/planner.cpp @@ -44,7 +44,7 @@ * functions. Data from the Gcode model is transferred to the motion planner by the mp_xxxx() * functions called by the canonical machine. * - * The planner should only use data in the planner model. When a move (block) is ready for + * The planner should only use data in the planner model. When a move (buffer) is ready for * execution the relevant data from the planner is transferred to the runtime model, * which should also be isolated. * @@ -177,6 +177,14 @@ stat_t planner_test_assertions() ) { return(cm_panic(STAT_PLANNER_ASSERTION_FAILURE, "planner_test_assertions()")); } +// for (uint8_t i=0; i < PLANNER_BUFFER_POOL_SIZE; i++) { +// if (mb.bf[i].nx == nullptr) { +// _debug_trap("buffer has nullptr for nx"); +// } +// if (mb.bf[i].pv == nullptr) { +// _debug_trap("buffer has nullptr for pv"); +// } +// } return (STAT_OK); } @@ -470,8 +478,8 @@ bool mp_is_phat_city_time() * mp_planner_callback()'s job is to invoke backward planning intelligently. * The flow of control and division of responsibilities for planning is: * - * - mp_aline() receives new Gcode blocks and initializes the local variables - * for the new block. + * - mp_aline() receives new Gcode moves and initializes the local variables + * for the new buffer. * * - mp_planner_callback() is called regularly from the main loop. * It's job is to determine whether or not to call mp_plan_block_list(), @@ -480,9 +488,9 @@ bool mp_is_phat_city_time() * mp_planner_callback() also manages planner state - whether the planner * is IDLE, in STARTUP or in one of the running states. * - * - _plan_block_list() / _planblock() is the backward planning function. + * - _plan_block() is the backward planning function for a single buffer. * - * - Forward planning is just-in-time by the execution runtime + * - Just-in-time forward planning is performed by mp_plan_move() in the plan_exec.cpp runtime executive * * Some Items to note: * @@ -702,7 +710,7 @@ static inline void _clear_buffer(mpBuf_t *bf) // the pointers and buffer number during interrupts // We'll have to figure something else out for C, sorry. - bf->clear(); + bf->reset(); } void _init_planner_queue(uint8_t q, mpBuf_t *pool, uint8_t size) @@ -730,6 +738,29 @@ void _init_planner_queue(uint8_t q, mpBuf_t *pool, uint8_t size) b->bf[i].nx = nx; // setup circular list pointers b->bf[i].pv = pv; pv = &b->bf[i]; + +/*======= + + //memset(&mb, 0, sizeof(mb)); // clear all values, pointers and status + mb.magic_start = MAGICNUM; + mb.magic_end = MAGICNUM; + + mb.w = &mb.bf[0]; // init all buffer pointers + mb.r = &mb.bf[0]; + pv = &mb.bf[PLANNER_BUFFER_POOL_SIZE-1]; + for (uint8_t i=0; i < PLANNER_BUFFER_POOL_SIZE; i++) { + _clear_buffer(&mb.bf[i]); + uint8_t nx_i = ((i<(PLANNER_BUFFER_POOL_SIZE-1))?(i+1):0); // buffer incr & wrap + + mb.bf[i].buffer_number = i; //+++++ number it for diagnostics only (otherwise not used) + + nx = &mb.bf[nx_i]; + mb.bf[i].nx = nx; // setup ring pointers + mb.bf[i].pv = pv; + + pv = &mb.bf[i]; +>>refs/heads/dev-168-gquadratic +*/ } } @@ -799,7 +830,8 @@ void mp_commit_write_buffer(const blockType block_type) if ((mp.planner_state > PLANNER_STARTUP) && (cm.hold_state == FEEDHOLD_OFF)) { // NB: BEWARE! the exec may result in the planner buffer being // processed IMMEDIATELY and then freed - invalidating the contents - st_request_plan_move(); // request an exec if the runtime is not busy +// st_request_plan_move(); // ++++ request an exec if the runtime is not busy + st_request_forward_plan(); // request an exec if the runtime is not busy } } q->w->plannable = true; // enable block for planning diff --git a/g2core/planner.h b/g2core/planner.h index 471e4940..2766af71 100644 --- a/g2core/planner.h +++ b/g2core/planner.h @@ -25,6 +25,126 @@ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*x + * --- Planner Background --- + * + * The planner is a complicated beast that takes a lot of things into account. + * Planner documentation is scattered about and co-located with the functions + * that perform the actions. Key files are: + * + * - planner.h - This file has defines, structures and prototypes. What you would expect + * - planner.cpp - Core and common functions, queue handling, JSON and command handlers + * - plan_line.cpp - Move planning and queuing, backward planning functions + * - plan_zoid.cpp - Move forward planning, velocity contour calculations and crazy math + * - plan_exec.cpp - Runtime execution functions, calls zoid's forward planning functions + * - stepper.cpp/h - Real-time step generation, segment loading, pulls from plan_exec + * - plan_arc.cpp/h- Arc calculation and runtime functions - layer above the rest of this + * + * --- Planner Overview --- + * + * At high level the planner's job is to reconstruct smooth motion from a set of linear + * approximations while observing and operating within the physical constraints of the + * machine and the physics of motion. Gcode - which consists of a series of into linear + * motion segments - is interpreted, queued to the planner, and joined together to produce + * continuous, synchronized motion. Non-motion commands such as pauses (dwells) and + * peripheral controls such as spindles can also be synchronized in the queue. Arcs are + * just a special case consisting of many linear moves. Arcs are not interpreted directly. + * + * The planner sits in the middle of three system layers: + * - The Gcode interpreter and canonical machine (the 'model'), which feeds... + * - The planner - taking generic commands from the model and queuing them for... + * - The runtime layer - pulling from the planner and driving stepper motors or other devices + * + * The planner queue is the heart of the planner. It's a circular list of ~48 complex structures + * that carry the state of the system needs to execute a linear motion, run a pre-planned command, + * like turning on a spindle, or executing an arbitrary JSON command such as an active comment. + * + * The queue can be viewed as a list of instructions that will execute in exact sequence. + * Some instructions control motion and need to be joined to their forward and backwards + * neighbors so that position, velocity, acceleration, and jerk constraints are not + * violated when moving from one motion to the next. + * + * Others are "commands" that are actually just function callbacks that happen to execute + * at a particular point in time (synchronized with motion commands). Commands can control + * anything you can reasonably program, such as digital IO, serial communications, or + * interpreted commands encoded in JSON. + * + * The buffers in the planner queue are treated as a 'closure' - with all state needed for + * proper execution carried in the planner structure. This is important as it keeps + * model state coherent in a heavily pipelined system. The local copy of the Gcode + * model is carried in the gm structure that is part of each planner buffer. + * See header notes in planner.cpp for more details. + * + * The planner is entered by calling one of: + * - mp_aline() - plan and queue a move with acceleration management + * - mp_dwell() - plan and queue a pause (dwell) to the planner queue + * - mp_queue_command() - queue a canned command + * - mp_json_command() - queue a JSON command for run-time interpretation and execution (M100) + * - mp_json_wait() - queue a JSON wait for run-time interpretation and execution (M101) + * - + * In addition, cm_arc_feed() valaidates and sets up a arc paramewters and calls mp_aline() + * repeatedly to spool out the arc segments into the planner queue. + * + * All the above queueing commands other than mp_aline() are relatively trivial; they just + * post callbacks into the next available planner buffer. Command functions are in 2 parts: + * the part that posts to the queue, and the callback that is executed when the command is + * finally reached in the queue - the _exec(). + * + * All mp_aline() does is some preliminary math and then posts an initialized buffer to + * the planner queue. The rest of the move planning operations takes place in background; + * via mp_planner_callback() called from the main loop, and as 'pulls' from the runtime + * stepper operations. + * + * Motion planning is separated into backward planning and forward planning stages. + * Backward planning is initiated by mp_planner_callback() which is called repeatedly + * from the main loop. Backwards planning is performed by mp_plan_block_list() and + * _plan_block(). It starts at the most recently arrived Gcode block. Backward + * planning can occur multiple times for a given buffer, as new moves arriving + * can make the motion profile more optimal. + * + * Backward planning uses velocity and jerk constraints to set maximum entry, + * travel (cruise) and exit velocities for the moves in the queue. In addition, + * it observes the maximum cornering velocities that adjoining moves can sustain + * in a corner or a 'kink' to ensure that the jerk limit of any axis participating + * in the move is not violated. See mp_planner_callback() header comments for more detail. + * + * Forward planning is performed just-in-time and only once, right before the + * planner runtime needs the next buffer. Forward planning provides the final + * contouring of the move. It is invoked by mp_forward_plan() and executed by + * mp_calculate_ramps() in plan_zoid.cpp. + * + * Planner timing operates at a few different levels: + * + * - New lines of ASCII containing commands and moves arriving from the USB are + * parsed and executed as the lowest priority background task from the main loop. + * + * - Backward planning is invoked by a main loop callback, so it also executes as + * a background task, albeit a higher priority one. + * + * - Forward planning and the ultimate preparation of the move for the runtime runs + * as an interrupt as a 'pull' from the planner queue that uses a series of + * interrupts at progressively lower priorities to ensure that the next planner + * buffer is ready before the runtime runs out of forward-planned moves and starves. + * + * Some other functions performed by the planner include: + * + * - Velocity throttling to ensure that very short moves do not execute faster + * than the serial interface can deliver them + * + * - Feed hold and cycle start (resume) operations + * + * - Feed rate override functions and replanning + * + * Some terms that are useful that we try to use consistently: + * + * - buffer - in this context a planner buffer holding a move or a command: mb._ or bf + * - block - a data structure for planning or runtime control. See mp_calculate_ramps() comments + * - move - a linear Gcode move, typically from a G0 or G1 code + * - command - a non-move executable in the planner + * - group - a collection of moves or commands that are treated as a unit + * - line - a line of ASCII gcode or arbitrary text + * - bootstrap - the startup period where the planner collects moves but does not yet execute them + */ #ifndef PLANNER_H_ONCE #define PLANNER_H_ONCE @@ -60,12 +180,12 @@ typedef enum { // bf->buffer_state values in incresing orde } bufferState; typedef enum { // bf->block_type values - BLOCK_TYPE_NULL = 0, // null move - does a no-op - BLOCK_TYPE_ALINE, // acceleration planned line - BLOCK_TYPE_DWELL, // delay with no movement - BLOCK_TYPE_COMMAND, // general command - BLOCK_TYPE_JSON_WAIT, // general command - BLOCK_TYPE_TOOL, // T command + BLOCK_TYPE_NULL = 0, // MUST=0 null move - does a no-op + BLOCK_TYPE_ALINE = 1, // MUST=1 acceleration planned line + BLOCK_TYPE_COMMAND = 2, // MUST=2 general command + BLOCK_TYPE_DWELL, // Gcode dwell + BLOCK_TYPE_JSON_WAIT, // JSON wait command + BLOCK_TYPE_TOOL, // T command (T, not M6 tool change) BLOCK_TYPE_SPINDLE_SPEED, // S command BLOCK_TYPE_STOP, // program stop BLOCK_TYPE_END // program end @@ -179,7 +299,12 @@ typedef enum { #define UPDATE_MP_DIAGNOSTICS { mp.plannable_time_ms = mp.plannable_time*60000; } /* - * Planner structures + * Planner structures + * + * You should be aware of the distinction between 'buffers' and 'blocks' + * Please refer to header comments in for important details on buffers and blocks + * - plan_zoid.cpp / mp_calculate_ramps() + * - plan_exec.cpp / mp_exec_aline() */ struct mpBuffer_to_clear { @@ -236,8 +361,46 @@ struct mpBuffer_to_clear { GCodeState_t gm; // Gcode model state - passed from model, used by planner and runtime - void clear() { - memset((void *)(this), 0, sizeof(mpBuffer_to_clear)); + void reset() { + //memset((void *)(this), 0, sizeof(mpBuffer_to_clear)); + + bf_func = nullptr; + cm_func = nullptr; + + linenum = 0; + iterations = 0; + block_time_ms = 0; + plannable_time_ms = 0; + plannable_length = 0; + meet_iterations = 0; + + buffer_state = MP_BUFFER_EMPTY; + block_type = BLOCK_TYPE_NULL; + block_state = BLOCK_INACTIVE; + hint = NO_HINT; + + for (uint8_t i = 0; i< AXES; i++) { + unit[i] = 0; + axis_flags[i] = 0; + } + + plannable = false; + length = 0.0; + block_time = 0.0; + override_factor = 0.0; + cruise_velocity = 0.0; + exit_velocity = 0.0; + cruise_vset = 0.0; + cruise_vmax = 0.0; + exit_vmax = 0.0; + absolute_vmax = 0.0; + junction_vmax = 0.0; + jerk = 0.0; + jerk_sq = 0.0; + recip_jerk = 0.0; + sqrt_j = 0.0; + q_recip_2_sqrt_j = 0.0; + gm.reset(); } }; @@ -336,9 +499,9 @@ typedef struct mpMotionRuntimeSingleton { // persistent runtime variables float encoder_steps[MOTORS]; // encoder position in steps - ideally the same as commanded_steps float following_error[MOTORS]; // difference between encoder_steps and commanded steps - mpBlockRuntimeBuf_t *r; // what's running - mpBlockRuntimeBuf_t *p; // what's being planned, p might == r - mpBlockRuntimeBuf_t bf[2]; // the buffer + mpBlockRuntimeBuf_t *r; // block that is running + mpBlockRuntimeBuf_t *p; // block that is being planned, p might == r + mpBlockRuntimeBuf_t bf[2]; // buffer holding the two blocks float entry_velocity; // entry values for the currently running block @@ -435,7 +598,7 @@ void mp_plan_block_forward(mpBuf_t *bf); void mp_calculate_ramps(mpBlockRuntimeBuf_t *block, mpBuf_t *bf, const float entry_velocity); float mp_get_target_length(const float v_0, const float v_1, const mpBuf_t *bf); float mp_get_target_velocity(const float v_0, const float L, const mpBuf_t *bf); // acceleration ONLY -float mp_get_decel_velocity(const float v_0, const float L, const mpBuf_t *bf); // decelleration ONLY +float mp_get_decel_velocity(const float v_0, const float L, const mpBuf_t *bf); // deceleration ONLY float mp_find_t(const float v_0, const float v_1, const float L, const float totalL, const float initial_t, const float T); float mp_calc_v(const float t, const float v_0, const float v_1); // compute the velocity along the curve accelerating from v_0 to v_1, at position t=[0,1] @@ -444,8 +607,8 @@ float mp_calc_j(const float t, const float v_0, const float v_1, const float T); //float mp_calc_l(const float t, const float v_0, const float v_1, const float T); // compute length over curve accelerating from v_0 to v_1, at position t=[0,1], total time T // plan_exec.c functions +stat_t mp_forward_plan(void); stat_t mp_exec_move(void); -stat_t mp_plan_move(void); stat_t mp_exec_aline(mpBuf_t *bf); void mp_exit_hold_state(void); diff --git a/g2core/settings/settings_Printrbot_Simple_1608.h b/g2core/settings/settings_Printrbot_Simple_1608.h index 7b24e154..d9c71c28 100755 --- a/g2core/settings/settings_Printrbot_Simple_1608.h +++ b/g2core/settings/settings_Printrbot_Simple_1608.h @@ -39,7 +39,7 @@ //**** GLOBAL / GENERAL SETTINGS ****************************************************** -#define JUNCTION_INTEGRATION_TIME 1.05 // cornering - between 0.10 and 2.00 (higher is faster) +#define JUNCTION_INTEGRATION_TIME 1.15 // cornering - between 0.10 and 2.00 (higher is faster) #define CHORDAL_TOLERANCE 0.01 // chordal accuracy for arc drawing (in mm) #define SOFT_LIMIT_ENABLE 0 // 0=off, 1=on @@ -94,11 +94,11 @@ // 80 steps/mm at 1/16 microstepping = 40 mm/rev #define M1_MOTOR_MAP AXIS_X // 1ma #define M1_STEP_ANGLE 1.8 // 1sa -#define M1_TRAVEL_PER_REV 40.132 // 1tr +#define M1_TRAVEL_PER_REV 40.011604 // 1tr #define M1_MICROSTEPS 32 // 1mi 1,2,4,8,16,32 #define M1_POLARITY 0 // 1po 0=normal, 1=reversed #define M1_POWER_MODE MOTOR_POWER_MODE // 1pm standard -#define M1_POWER_LEVEL 0.5 // 1mp +#define M1_POWER_LEVEL 0.35 // 1mp // 80 steps/mm at 1/16 microstepping = 40 mm/rev #define M3_MOTOR_MAP AXIS_Y @@ -107,7 +107,7 @@ #define M3_MICROSTEPS 32 #define M3_POLARITY 0 #define M3_POWER_MODE MOTOR_POWER_MODE -#define M3_POWER_LEVEL 0.5 +#define M3_POWER_LEVEL 0.35 // 2020 steps/mm at 1/16 microstepping = 1.58416 mm/rev #define M2_MOTOR_MAP AXIS_Z @@ -116,7 +116,7 @@ #define M2_MICROSTEPS 32 #define M2_POLARITY 1 #define M2_POWER_MODE MOTOR_POWER_MODE -#define M2_POWER_LEVEL 0.4 +#define M2_POWER_LEVEL 0.3 // 96 steps/mm at 1/16 microstepping = 33.3333 mm/rev #define M4_MOTOR_MAP AXIS_A @@ -125,7 +125,7 @@ #define M4_MICROSTEPS 32 #define M4_POLARITY 1 #define M4_POWER_MODE MOTOR_POWER_MODE -#define M4_POWER_LEVEL 0.4 +#define M4_POWER_LEVEL 0.3 // 96 steps/mm at 1/16 microstepping = 33.3333 mm/rev #define M5_MOTOR_MAP AXIS_B @@ -139,12 +139,12 @@ // *** axis settings ********************************************************************************** #define X_AXIS_MODE AXIS_STANDARD // xam see canonical_machine.h cmAxisMode for valid values -#define X_VELOCITY_MAX 10000 // xvm G0 max velocity in mm/min +#define X_VELOCITY_MAX 15000 // xvm G0 max velocity in mm/min #define X_FEEDRATE_MAX X_VELOCITY_MAX // xfr G1 max feed rate in mm/min #define X_TRAVEL_MIN 0 // xtn minimum travel - used by soft limits and homing #define X_TRAVEL_MAX 215 // xtm travel between switches or crashes -#define X_JERK_MAX 3000 // xjm yes, that's "100 billion" mm/(min^3) -#define X_JERK_HIGH_SPEED 3000 // xjh +#define X_JERK_MAX 6000 // xjm yes, that's "100 billion" mm/(min^3) +#define X_JERK_HIGH_SPEED 6000 // xjh #define X_HOMING_INPUT 4 // xhi input used for homing or 0 to disable #define X_HOMING_DIRECTION 0 // xhd 0=search moves negative, 1= search moves positive #define X_SEARCH_VELOCITY 2500 // xsv move in negative direction @@ -153,12 +153,12 @@ #define X_ZERO_BACKOFF 0.5 // xzb mm #define Y_AXIS_MODE AXIS_STANDARD -#define Y_VELOCITY_MAX 10000 +#define Y_VELOCITY_MAX 15000 #define Y_FEEDRATE_MAX Y_VELOCITY_MAX #define Y_TRAVEL_MIN 0 #define Y_TRAVEL_MAX 152.4 -#define Y_JERK_MAX 3000 -#define Y_JERK_HIGH_SPEED 3000 +#define Y_JERK_MAX 6000 +#define Y_JERK_HIGH_SPEED 6000 #define Y_HOMING_INPUT 1 #define Y_HOMING_DIRECTION 1 #define Y_SEARCH_VELOCITY 3000 @@ -185,7 +185,7 @@ * To calculate the speeds here, in Wolfram Alpha-speak: * * c=2*pi*r, r=0.609, d=c/360, s=((S*60)/d), S=40 for s - * c=2*pi*r, r=5.30516476972984, d=c/360, s=((S*60)/d), S=40 for s + * c=2*pi*r, r=4.28394, d=c/360, s=((S*60)/d), S=40 for s * * Change r to A_RADIUS, and S to the desired speed, in mm/s or mm/s/s/s. * @@ -204,12 +204,12 @@ //#define A_VELOCITY_MAX 25920.0 // ~40 mm/s, 2,400 mm/min //#define A_FEEDRATE_MAX 25920.0/2.0 // ~20 mm/s, 1,200 mm/min #define A_VELOCITY_MAX 77760.0 // G0 rate ~120 mm/s, 2,400 mm/min -#define A_FEEDRATE_MAX 6480 // ~10 mm/s +#define A_FEEDRATE_MAX 16050 // ~10 mm/s //#define A_FEEDRATE_MAX 9720.0 // 9720.0 = G1 rate ~15 mm/s, 900 mm/min #define A_TRAVEL_MIN 0 #define A_TRAVEL_MAX 10 -#define A_JERK_MAX 81000 // 250 million mm/min^3 = 324000 -//#define A_JERK_MAX 162000 // 250 million mm/min^3 = 324000 +//#define A_JERK_MAX 81000 // 250 million mm/min^3 = 324000 +#define A_JERK_MAX 162000 // 250 million mm/min^3 = 324000 //#define A_JERK_MAX 324000 // 500 million mm/min^3 = 324000 //#define A_JERK_MAX 648000 // 1,000 million mm/min^3 = 648000 // * a million IF it's over a million diff --git a/g2core/settings/settings_default.h b/g2core/settings/settings_default.h index 233346c3..e0566ae7 100755 --- a/g2core/settings/settings_default.h +++ b/g2core/settings/settings_default.h @@ -58,6 +58,11 @@ // *** Machine configuration settings *** // +#ifndef USB_SERIAL_PORTS_EXPOSED +#define USB_SERIAL_PORTS_EXPOSED 1 // Valid options are 1 or 2, only! +#endif + + #ifndef JUNCTION_INTEGRATION_TIME #define JUNCTION_INTEGRATION_TIME 0.75 // {jt: cornering - between 0.05 and 2.00 (max) #endif diff --git a/g2core/settings/settings_eggbot.h b/g2core/settings/settings_eggbot.h new file mode 100755 index 00000000..4527a339 --- /dev/null +++ b/g2core/settings/settings_eggbot.h @@ -0,0 +1,401 @@ +/* + * settings_eggbot.h - settings for the EggBot + * This file is part of the g2core project + * + * Copyright (c) 2016 Alden S. Hart Jr. + * Copyright (c) 2016 Robert Giseburt + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * As a special exception, you may use this file as part of a software library without + * restriction. Specifically, if other files instantiate templates or use macros or + * inline functions from this file, or you compile this file and link it with other + * files to produce an executable, this file does not by itself cause the resulting + * executable to be covered by the GNU General Public License. This exception does not + * however invalidate any other reasons why the executable file might be covered by the + * GNU General Public License. + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/***********************************************************************/ +/**** TestV9 profile - naked board *************************************/ +/***********************************************************************/ + +// ***> NOTE: The init message must be a single line with no CRs or LFs +#define INIT_MESSAGE "Initializing configs to WaterColorBot v2 settings" + +#define JUNCTION_INTEGRATION_TIME 1.50 // cornering - usually between 0.5 and 2.0 (higher is faster) +#define CHORDAL_TOLERANCE 0.01 // chordal accuracy for arc drawing (in mm) + +#define SOFT_LIMIT_ENABLE 0 // 0=off, 1=on +#define HARD_LIMIT_ENABLE 1 // 0=off, 1=on +#define SAFETY_INTERLOCK_ENABLE 1 // 0=off, 1=on + +#define SPINDLE_ENABLE_POLARITY 1 // 0=active low, 1=active high +#define SPINDLE_DIR_POLARITY 0 // 0=clockwise is low, 1=clockwise is high +#define SPINDLE_PAUSE_ON_HOLD true +#define SPINDLE_DWELL_TIME 1.0 + +#define COOLANT_MIST_POLARITY 1 // 0=active low, 1=active high +#define COOLANT_FLOOD_POLARITY 1 // 0=active low, 1=active high +#define COOLANT_PAUSE_ON_HOLD false + +// Communications and reporting settings + +#define COMM_MODE JSON_MODE // one of: TEXT_MODE, JSON_MODE +#define XIO_ENABLE_FLOW_CONTROL FLOW_CONTROL_RTS // FLOW_CONTROL_OFF, FLOW_CONTROL_RTS + +#define TEXT_VERBOSITY TV_VERBOSE // one of: TV_SILENT, TV_VERBOSE +#define JSON_VERBOSITY JV_MESSAGES // one of: JV_SILENT, JV_FOOTER, JV_CONFIGS, JV_MESSAGES, JV_LINENUM, JV_VERBOSE +#define QUEUE_REPORT_VERBOSITY QR_OFF // one of: QR_OFF, QR_SINGLE, QR_TRIPLE + +#define STATUS_REPORT_VERBOSITY SR_FILTERED // one of: SR_OFF, SR_FILTERED, SR_VERBOSE +#define STATUS_REPORT_MIN_MS 100 // milliseconds - enforces a viable minimum +#define STATUS_REPORT_INTERVAL_MS 250 // milliseconds - set $SV=0 to disable + +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","posa","bcr","feed","vel","unit","coor","dist","admo","frmo","momo","stat" +#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","feed","vel","momo","stat" + +// Alternate SRs +//#define STATUS_REPORT_DEFAULTS "line","vel","mpox","mpoy","mpoz","mpoa","coor","ofsa","ofsx","ofsy","ofsz","dist","unit","stat","homz","homy","homx","momo" +//#define STATUS_REPORT_DEFAULTS "_ts1","_cs1","_es1","_xs1","_fe1","line","posx","posy","posz","vel","stat" +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","vel","_cs1","_es1","_xs1","_fe1","_cs2","_es2","_xs2","_fe2" +//#define STATUS_REPORT_DEFAULTS "mpox","mpoy","mpoz","mpoa","ofsx","ofsy","ofsz","ofsa","unit","stat","coor","momo","dist","home","hold","macs","cycs","mots","plan","feed" +//#define STATUS_REPORT_DEFAULTS "line","mpox","mpoy","mpoz","mpoa","ofsx","ofsy","ofsz","ofsa","stat","_cs1","_es1","_fe0","_fe1","_fe2","_fe3" +//#define STATUS_REPORT_DEFAULTS "line","mpox","mpoy","mpoz","stat","_ts2","_ps2","_cs2","_es2","_fe2" +//#define STATUS_REPORT_DEFAULTS "line","mpox","mpoy","mpoz","_cs3","_es3","_fe3","_xs3","_cs2","_es2","_fe2","_xs2","stat" +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","posa","feed","vel","unit","coor","dist","frmo","momo","stat","_cs1","_es1","_xs1","_fe1" + +// Gcode startup defaults +#define GCODE_DEFAULT_UNITS MILLIMETERS // MILLIMETERS or INCHES +#define GCODE_DEFAULT_PLANE CANON_PLANE_XY // CANON_PLANE_XY, CANON_PLANE_XZ, or CANON_PLANE_YZ +#define GCODE_DEFAULT_COORD_SYSTEM G54 // G54, G55, G56, G57, G58 or G59 +#define GCODE_DEFAULT_PATH_CONTROL PATH_CONTINUOUS +#define GCODE_DEFAULT_DISTANCE_MODE ABSOLUTE_MODE + +// *** motor settings ************************************************************************************ + +#define MOTOR_POWER_MODE MOTOR_POWERED_IN_CYCLE // default motor power mode (see cmMotorPowerMode in stepper.h) +#define MOTOR_POWER_TIMEOUT 2.00 // motor power timeout in seconds + +#define MOTOR_POWER_MODE MOTOR_POWERED_IN_CYCLE // default motor power mode (see cmMotorPowerMode in stepper.h) +#define MOTOR_POWER_TIMEOUT 2.00 // motor power timeout in seconds + +#define M1_MOTOR_MAP AXIS_Y // 1ma +#define M1_STEP_ANGLE 1.8 // 1sa +#define M1_TRAVEL_PER_REV 125.66370614 // 1tr +#define M1_MICROSTEPS 32 // 1mi 1,2,4,8 +#define M1_POLARITY 1 // 1po 0=normal, 1=reversed +#define M1_POWER_MODE MOTOR_POWER_MODE // 1pm standard +#define M1_POWER_LEVEL 0.4 + +#define M2_MOTOR_MAP AXIS_X +#define M2_STEP_ANGLE 1.8 +#define M2_TRAVEL_PER_REV 125.66370614 +#define M2_MICROSTEPS 32 +#define M2_POLARITY 1 +#define M2_POWER_MODE MOTOR_POWER_MODE +#define M2_POWER_LEVEL 0.4 + +#define M3_MOTOR_MAP AXIS_Z + // This "stepper" is a hobby servo. Note that all hobby + // servo settings are per full servo range, instead of + // per revolution. +#define M3_STEP_ANGLE 1.8 // hobby servos are simulated with 200 "full steps" +#define M3_TRAVEL_PER_REV 26 // this is actually the full travel of the servo, not + // necessarily covering a revolution +#define M3_MICROSTEPS 32 // the max step resolution for a hobby servo is 1/32 +#define M3_POLARITY 1 +#define M3_POWER_MODE MOTOR_ALWAYS_POWERED +#define M3_POWER_LEVEL 0.50 // this is ignored + +#define M4_MOTOR_MAP AXIS_A +#define M4_STEP_ANGLE 1.8 +#define M4_TRAVEL_PER_REV 360 // degrees moved per motor rev +#define M4_MICROSTEPS 32 +#define M4_POLARITY 0 +#define M4_POWER_MODE MOTOR_POWER_MODE +#define M4_POWER_LEVEL 0.6 + +// *** axis settings ********************************************************************************** + +#define JERK_MAX 20000 + +#define X_AXIS_MODE AXIS_STANDARD // xam see canonical_machine.h cmAxisMode for valid values +#define X_VELOCITY_MAX 50000 // xvm G0 max velocity in mm/min +#define X_FEEDRATE_MAX X_VELOCITY_MAX // xfr G1 max feed rate in mm/min +#define X_TRAVEL_MIN 0 // xtn minimum travel - used by soft limits and homing +#define X_TRAVEL_MAX 400 // xtm maximum travel - used by soft limits and homing +#define X_JERK_MAX JERK_MAX // xjm +#define X_JERK_HIGH_SPEED X_JERK_MAX // xjh +#define X_HOMING_INPUT 1 // xhi input used for homing or 0 to disable +#define X_HOMING_DIRECTION 0 // xhd 0=search moves negative, 1= search moves positive +#define X_SEARCH_VELOCITY 1000 // xsv move in negative direction +#define X_LATCH_VELOCITY 100 // xlv mm/min +#define X_LATCH_BACKOFF 10 // xlb mm +#define X_ZERO_BACKOFF 2 // xzb mm + +#define Y_AXIS_MODE AXIS_STANDARD +#define Y_VELOCITY_MAX 50000 +#define Y_FEEDRATE_MAX Y_VELOCITY_MAX +#define Y_TRAVEL_MIN 0 +#define Y_TRAVEL_MAX 175 +#define Y_JERK_MAX JERK_MAX +#define Y_JERK_HIGH_SPEED Y_JERK_MAX +#define Y_HOMING_INPUT 3 +#define Y_HOMING_DIRECTION 0 +#define Y_SEARCH_VELOCITY 1000 +#define Y_LATCH_VELOCITY 100 +#define Y_LATCH_BACKOFF 10 +#define Y_ZERO_BACKOFF 2 + +#define Z_AXIS_MODE AXIS_STANDARD +#define Z_VELOCITY_MAX 15000 +#define Z_FEEDRATE_MAX Z_VELOCITY_MAX +#define Z_TRAVEL_MIN 0 +#define Z_TRAVEL_MAX 75 +#define Z_JERK_MAX 5000 +#define Z_JERK_HIGH_SPEED Z_JERK_MAX +#define Z_HOMING_INPUT 6 +#define Z_HOMING_DIRECTION 1 +#define Z_SEARCH_VELOCITY 600 +#define Z_LATCH_VELOCITY 100 +#define Z_LATCH_BACKOFF 10 +#define Z_ZERO_BACKOFF 2 + +// Rotary values are chosen to make the motor react the same as X for testing +/*************************************************************************************** + * To calculate the speeds here, in Wolfram Alpha-speak: + * + * c=2*pi*r, r=0.609, d=c/360, s=((S*60)/d), S=40 for s + * c=2*pi*r, r=5.30516476972984, d=c/360, s=((S*60)/d), S=40 for s + * + * Change r to A_RADIUS, and S to the desired speed, in mm/s or mm/s/s/s. + * + * It will return s= as the value you want to enter. + * + * If the value is over 1 million, the code will divide it by 1 million, + * so you have to pre-multiply it by 1000000.0. (The value is in millions, btw.) + * + * Note that you need these to be floating point values, so always have a .0 at the end! + * + ***************************************************************************************/ + +#define A_AXIS_MODE AXIS_RADIUS +#define A_RADIUS 5.30516476972984 +//#define A_VELOCITY_MAX 25920.0 // ~40 mm/s, 2,400 mm/min +//#define A_FEEDRATE_MAX 25920.0/2.0 // ~20 mm/s, 1,200 mm/min +#define A_VELOCITY_MAX 77760.0 // G0 rate ~120 mm/s, 2,400 mm/min +#define A_FEEDRATE_MAX 9720.0 // 9720.0 = G1 rate ~15 mm/s, 900 mm/min +#define A_TRAVEL_MIN 0 +#define A_TRAVEL_MAX 10 +#define A_JERK_MAX 648000 // 1,000 million mm/min^3 = 648000 + // * a million IF it's over a million + // c=2*pi*r, r=5.30516476972984, d=c/360, s=((1000*60)/d) +#define A_HOMING_INPUT 0 +#define A_HOMING_DIRECTION 0 +#define A_SEARCH_VELOCITY 2000 +#define A_LATCH_VELOCITY 2000 +#define A_LATCH_BACKOFF 5 +#define A_ZERO_BACKOFF 2 +#define A_JERK_HIGH_SPEED A_JERK_MAX + +#define B_AXIS_MODE AXIS_DISABLED +#define B_RADIUS 1 +#define B_VELOCITY_MAX 3600 +#define B_FEEDRATE_MAX B_VELOCITY_MAX +#define B_TRAVEL_MIN 0 +#define B_TRAVEL_MAX -1 +//#define B_JERK_MAX 20000000 +#define B_JERK_MAX 20 +#define B_HOMING_INPUT 0 +#define B_HOMING_DIRECTION 0 +#define B_SEARCH_VELOCITY 600 +#define B_LATCH_VELOCITY 100 +#define B_LATCH_BACKOFF 10 +#define B_ZERO_BACKOFF 2 +#define B_JERK_HIGH_SPEED A_JERK_MAX + + +//*** Input / output settings *** +/* + IO_MODE_DISABLED + IO_ACTIVE_LOW aka NORMALLY_OPEN + IO_ACTIVE_HIGH aka NORMALLY_CLOSED + + INPUT_ACTION_NONE + INPUT_ACTION_STOP + INPUT_ACTION_FAST_STOP + INPUT_ACTION_HALT + INPUT_ACTION_RESET + + INPUT_FUNCTION_NONE + INPUT_FUNCTION_LIMIT + INPUT_FUNCTION_INTERLOCK + INPUT_FUNCTION_SHUTDOWN + INPUT_FUNCTION_PANIC +*/ +// Inputs are defined for the g2ref(a) board +// Xmn (board label) +#define DI1_MODE IO_ACTIVE_HIGH +#define DI1_ACTION INPUT_ACTION_NONE +#define DI1_FUNCTION INPUT_FUNCTION_NONE + +// Xmax +#define DI2_MODE IO_MODE_DISABLED +#define DI2_ACTION INPUT_ACTION_NONE +#define DI2_FUNCTION INPUT_FUNCTION_NONE + +// Ymin +#define DI3_MODE IO_MODE_DISABLED +#define DI3_ACTION INPUT_ACTION_NONE +#define DI3_FUNCTION INPUT_FUNCTION_NONE + +// Ymax +#define DI4_MODE IO_ACTIVE_HIGH +#define DI4_ACTION INPUT_ACTION_NONE +#define DI4_FUNCTION INPUT_FUNCTION_NONE + +// Zmin +#define DI5_MODE IO_ACTIVE_LOW // Z probe +#define DI5_ACTION INPUT_ACTION_NONE +#define DI5_FUNCTION INPUT_FUNCTION_NONE + +// Zmax +#define DI6_MODE IO_MODE_DISABLED +#define DI6_ACTION INPUT_ACTION_STOP +#define DI6_FUNCTION INPUT_FUNCTION_NONE + +// Shutdown (Amin on v9 board) +#define DI7_MODE IO_MODE_DISABLED +#define DI7_ACTION INPUT_ACTION_NONE +#define DI7_FUNCTION INPUT_FUNCTION_NONE + +// High Voltage Z Probe In (Amax on v9 board) +#define DI8_MODE IO_ACTIVE_LOW +#define DI8_ACTION INPUT_ACTION_NONE +#define DI8_FUNCTION INPUT_FUNCTION_NONE + +// Hardware interlock input +#define DI9_MODE IO_MODE_DISABLED +#define DI9_ACTION INPUT_ACTION_NONE +#define DI9_FUNCTION INPUT_FUNCTION_NONE + +//Extruder1_PWM +#define DO1_MODE IO_ACTIVE_HIGH + +//Extruder2_PWM +#define DO2_MODE IO_ACTIVE_HIGH + +//Fan1A_PWM +#define DO3_MODE IO_ACTIVE_HIGH + +//Fan1B_PWM +#define DO4_MODE IO_ACTIVE_HIGH + +#define DO5_MODE IO_ACTIVE_HIGH +#define DO6_MODE IO_ACTIVE_HIGH +#define DO7_MODE IO_ACTIVE_HIGH +#define DO8_MODE IO_ACTIVE_HIGH + +//SAFEin (Output) signal +#define DO9_MODE IO_ACTIVE_HIGH + +#define DO10_MODE IO_ACTIVE_HIGH + +//Header Bed FET +#define DO11_MODE IO_ACTIVE_HIGH + +//Indicator_LED +#define DO12_MODE IO_ACTIVE_HIGH + +#define DO13_MODE IO_ACTIVE_HIGH + + +/*** Extruders / Heaters ***/ +/* +#define MIN_FAN_TEMP 40.0 +#define MAX_FAN_TEMP 150.0 + +#define H1_DEFAULT_ENABLE true +#define H1_DEFAULT_P 9.0 +#define H1_DEFAULT_I 0.12 +#define H1_DEFAULT_D 400.0 + +#define H2_DEFAULT_ENABLE false +#define H2_DEFAULT_P 9.0 +#define H2_DEFAULT_I 0.12 +#define H2_DEFAULT_D 400.0 + +#define H3_DEFAULT_ENABLE false +#define H3_DEFAULT_P 9.0 +#define H3_DEFAULT_I 0.12 +#define H3_DEFAULT_D 400.0 +*/ + + +// *** PWM SPINDLE CONTROL *** + +#define P1_PWM_FREQUENCY 100 // in Hz +#define P1_CW_SPEED_LO 1000 // in RPM (arbitrary units) +#define P1_CW_SPEED_HI 2000 +#define P1_CW_PHASE_LO 0.125 // phase [0..1] +#define P1_CW_PHASE_HI 0.2 +#define P1_CCW_SPEED_LO 1000 +#define P1_CCW_SPEED_HI 2000 +#define P1_CCW_PHASE_LO 0.125 +#define P1_CCW_PHASE_HI 0.2 +#define P1_PWM_PHASE_OFF 0.1 + +// *** DEFAULT COORDINATE SYSTEM OFFSETS *** + +#define G54_X_OFFSET 0 // G54 is traditionally set to all zeros +#define G54_Y_OFFSET 0 +#define G54_Z_OFFSET 0 +#define G54_A_OFFSET 0 +#define G54_B_OFFSET 0 +#define G54_C_OFFSET 0 + +#define G55_X_OFFSET (X_TRAVEL_MAX/2) // set to middle of table +#define G55_Y_OFFSET (Y_TRAVEL_MAX/2) +#define G55_Z_OFFSET 0 +#define G55_A_OFFSET 0 +#define G55_B_OFFSET 0 +#define G55_C_OFFSET 0 + +#define G56_X_OFFSET 0 +#define G56_Y_OFFSET 0 +#define G56_Z_OFFSET 0 +#define G56_A_OFFSET 0 +#define G56_B_OFFSET 0 +#define G56_C_OFFSET 0 + +#define G57_X_OFFSET 0 +#define G57_Y_OFFSET 0 +#define G57_Z_OFFSET 0 +#define G57_A_OFFSET 0 +#define G57_B_OFFSET 0 +#define G57_C_OFFSET 0 + +#define G58_X_OFFSET 0 +#define G58_Y_OFFSET 0 +#define G58_Z_OFFSET 0 +#define G58_A_OFFSET 0 +#define G58_B_OFFSET 0 +#define G58_C_OFFSET 0 + +#define G59_X_OFFSET 0 +#define G59_Y_OFFSET 0 +#define G59_Z_OFFSET 0 +#define G59_A_OFFSET 0 +#define G59_B_OFFSET 0 +#define G59_C_OFFSET 0 diff --git a/g2core/settings/settings_shapeoko375_Dual.h b/g2core/settings/settings_shapeoko375_Dual.h new file mode 100644 index 00000000..b787d58c --- /dev/null +++ b/g2core/settings/settings_shapeoko375_Dual.h @@ -0,0 +1,256 @@ +/* + * settings_shapeoko375.h - Shapeoko 375mm table + * This file is part of the TinyG project + * + * Copyright (c) 2010 - 2014 Alden S. Hart, Jr. + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * As a special exception, you may use this file as part of a software library without + * restriction. Specifically, if other files instantiate templates or use macros or + * inline functions from this file, or you compile this file and link it with other + * files to produce an executable, this file does not by itself cause the resulting + * executable to be covered by the GNU General Public License. This exception does not + * however invalidate any other reasons why the executable file might be covered by the + * GNU General Public License. + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +/* Note: The values in this file are the default settings that are loaded + * into a virgin EEPROM, and can be changed using the config commands. + * After initial load the EEPROM values (or changed values) are used. + * + * System and hardware settings that you shouldn't need to change + * are in system.h Application settings that also shouldn't need + * to be changed are in tinyg.h + */ + +/***********************************************************************/ +/**** Shapeoko 375mm profile *******************************************/ +/***********************************************************************/ + +// ***> NOTE: The init message must be a single line with no CRs or LFs +#define INIT_MESSAGE "Initializing configs to Shapeoko 375mm Dual-Y profile" + +//**** GLOBAL / GENERAL SETTINGS ****************************************************** + +// Machine configuration settings + +#define JUNCTION_INTEGRATION_TIME 0.75 // cornering - between 0.10 and 2.00 (higher is faster) +#define CHORDAL_TOLERANCE 0.01 // chordal tolerance for arcs (in mm) + +#define SOFT_LIMIT_ENABLE 0 // 0=off, 1=on +#define HARD_LIMIT_ENABLE 0 // 0=off, 1=on +#define SAFETY_INTERLOCK_ENABLE 1 // 0=off, 1=on + +#define SPINDLE_ENABLE_POLARITY 1 // 0=active low, 1=active high +#define SPINDLE_DIR_POLARITY 0 // 0=clockwise is low, 1=clockwise is high +#define SPINDLE_PAUSE_ON_HOLD true +#define SPINDLE_DWELL_TIME 1.0 + +#define COOLANT_MIST_POLARITY 1 // 0=active low, 1=active high +#define COOLANT_FLOOD_POLARITY 1 // 0=active low, 1=active high +#define COOLANT_PAUSE_ON_HOLD false + +// Communications and reporting settings + +#define COMM_MODE JSON_MODE // one of: TEXT_MODE, JSON_MODE +#define XIO_ENABLE_FLOW_CONTROL FLOW_CONTROL_RTS // FLOW_CONTROL_OFF, FLOW_CONTROL_RTS + +#define TEXT_VERBOSITY TV_VERBOSE // one of: TV_SILENT, TV_VERBOSE +#define JSON_VERBOSITY JV_MESSAGES // one of: JV_SILENT, JV_FOOTER, JV_CONFIGS, JV_MESSAGES, JV_LINENUM, JV_VERBOSE +#define QUEUE_REPORT_VERBOSITY QR_OFF // one of: QR_OFF, QR_SINGLE, QR_TRIPLE + +#define STATUS_REPORT_VERBOSITY SR_FILTERED // one of: SR_OFF, SR_FILTERED, SR_VERBOSE + +#define STATUS_REPORT_MIN_MS 100 // milliseconds - enforces a viable minimum +#define STATUS_REPORT_INTERVAL_MS 250 // milliseconds - set $SV=0 to disable + +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","posa","bcr","feed","vel","unit","coor","dist","admo","frmo","momo","stat" +#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","bcr","feed","vel","momo","stat" + +// Alternate SRs that report in drawable units +//#define STATUS_REPORT_DEFAULTS "line","vel","mpox","mpoy","mpoz","mpoa","coor","ofsa","ofsx","ofsy","ofsz","dist","unit","stat","homz","homy","homx","momo" +//#define STATUS_REPORT_DEFAULTS "_ts1","_cs1","_es1","_xs1","_fe1","line","posx","posy","posz","vel","stat" + +// Gcode startup defaults +#define GCODE_DEFAULT_UNITS MILLIMETERS // MILLIMETERS or INCHES +#define GCODE_DEFAULT_PLANE CANON_PLANE_XY // CANON_PLANE_XY, CANON_PLANE_XZ, or CANON_PLANE_YZ +#define GCODE_DEFAULT_COORD_SYSTEM G54 // G54, G55, G56, G57, G58 or G59 +#define GCODE_DEFAULT_PATH_CONTROL PATH_CONTINUOUS +#define GCODE_DEFAULT_DISTANCE_MODE ABSOLUTE_MODE + + +// *** motor settings ************************************************************************************ + +#define MOTOR_POWER_MODE MOTOR_POWERED_IN_CYCLE // default motor power mode (see cmMotorPowerMode in stepper.h) +#define MOTOR_POWER_TIMEOUT 20.00 // motor power timeout in seconds + +// *** motor settings *** + +/* Mapping for dual gantry setup */ +#define M1_MOTOR_MAP AXIS_X // 1ma +#define M1_STEP_ANGLE 1.8 // 1sa +#define M1_TRAVEL_PER_REV 36.54 // 1tr +#define M1_MICROSTEPS 32 // 1mi 1,2,4,8 +#define M1_POLARITY 0 // 1po 0=normal, 1=reversed +#define M1_POWER_MODE MOTOR_POWER_MODE // 1pm TRUE=low power idle enabled +#define M1_POWER_LEVEL 0.6 + +#define M2_MOTOR_MAP AXIS_Y +#define M2_STEP_ANGLE 1.8 +#define M2_TRAVEL_PER_REV 36.54 +#define M2_MICROSTEPS 32 +#define M2_POLARITY 1 +#define M2_POWER_MODE MOTOR_POWER_MODE +#define M2_POWER_LEVEL 0.6 + +#define M3_MOTOR_MAP AXIS_Y +#define M3_STEP_ANGLE 1.8 +#define M3_TRAVEL_PER_REV 36.54 +#define M3_MICROSTEPS 32 +#define M3_POLARITY 0 +#define M3_POWER_MODE MOTOR_POWER_MODE +#define M3_POWER_LEVEL 0.6 + +#define M4_MOTOR_MAP AXIS_Z +#define M4_STEP_ANGLE 1.8 +#define M4_TRAVEL_PER_REV 1.25 +#define M4_MICROSTEPS 32 +#define M4_POLARITY 0 +#define M4_POWER_MODE MOTOR_POWER_MODE +#define M4_POWER_LEVEL 0.5 + +// *** axis settings ********************************************************************************** + + +#define X_AXIS_MODE AXIS_STANDARD // xam see canonical_machine.h cmAxisMode for valid values +#define X_VELOCITY_MAX 16000 // xvm G0 max velocity in mm/min +#define X_FEEDRATE_MAX X_VELOCITY_MAX // xfr G1 max feed rate in mm/min +#define X_TRAVEL_MIN 0 // xtn minimum travel - used by soft limits and homing +#define X_TRAVEL_MAX 220 // xtm maximum travel - used by soft limits and homing +#define X_JERK_MAX 5000 // xjm yes, that's "5 billion" mm/(min^3) +#define X_JERK_HIGH_SPEED X_JERK_MAX // xjh +#define X_HOMING_INPUT 1 // xhi input used for homing or 0 to disable +#define X_HOMING_DIR 0 // xhd 0 to search to minimum, 1 to search to maximum +#define X_SEARCH_VELOCITY 3000 // xsv minus means move to minimum switch +#define X_LATCH_VELOCITY 100 // xlv mm/min +#define X_LATCH_BACKOFF 4 // xlb mm +#define X_ZERO_BACKOFF 0.5 // xzb mm + +#define Y_AXIS_MODE AXIS_STANDARD +#define Y_VELOCITY_MAX 16000 +#define Y_FEEDRATE_MAX Y_VELOCITY_MAX +#define Y_TRAVEL_MIN 0 +#define Y_TRAVEL_MAX 220 +#define Y_JERK_MAX 5000 +#define Y_JERK_HIGH_SPEED Y_JERK_MAX +#define Y_HOMING_INPUT 3 +#define Y_HOMING_DIR 0 +#define Y_SEARCH_VELOCITY 3000 +#define Y_LATCH_VELOCITY 100 +#define Y_LATCH_BACKOFF 4 +#define Y_ZERO_BACKOFF 0.5 + +#define Z_AXIS_MODE AXIS_STANDARD +#define Z_VELOCITY_MAX 300 +#define Z_FEEDRATE_MAX Z_VELOCITY_MAX +#define Z_TRAVEL_MIN 0 +#define Z_TRAVEL_MAX 100 +#define Z_JERK_MAX 25 // 50,000,000 +#define Z_JERK_HIGH_SPEED Z_JERK_MAX +#define Z_HOMING_INPUT 5 +#define Z_HOMING_DIR 0 +#define Z_SEARCH_VELOCITY Z_VELOCITY_MAX +#define Z_LATCH_VELOCITY 100 +#define Z_LATCH_BACKOFF 4 +#define Z_ZERO_BACKOFF 0.5 + +//*** Input / output settings *** +/* + IO_MODE_DISABLED + IO_ACTIVE_LOW aka NORMALLY_OPEN + IO_ACTIVE_HIGH aka NORMALLY_CLOSED + + INPUT_ACTION_NONE + INPUT_ACTION_STOP + INPUT_ACTION_FAST_STOP + INPUT_ACTION_HALT + INPUT_ACTION_RESET + + INPUT_FUNCTION_NONE + INPUT_FUNCTION_LIMIT + INPUT_FUNCTION_INTERLOCK + INPUT_FUNCTION_SHUTDOWN + INPUT_FUNCTION_PANIC + */ +// Xmin on v9 board +#define DI1_MODE NORMALLY_CLOSED +//#define DI1_ACTION INPUT_ACTION_STOP +#define DI1_ACTION INPUT_ACTION_NONE +#define DI1_FUNCTION INPUT_FUNCTION_LIMIT + +// Xmax +#define DI2_MODE NORMALLY_CLOSED +//#define DI2_ACTION INPUT_ACTION_STOP +#define DI2_ACTION INPUT_ACTION_NONE +#define DI2_FUNCTION INPUT_FUNCTION_LIMIT + +// Ymin +#define DI3_MODE NORMALLY_CLOSED +//#define DI3_ACTION INPUT_ACTION_STOP +#define DI3_ACTION INPUT_ACTION_NONE +#define DI3_FUNCTION INPUT_FUNCTION_LIMIT + +// Ymax +#define DI4_MODE NORMALLY_CLOSED +//#define DI4_ACTION INPUT_ACTION_STOP +#define DI4_ACTION INPUT_ACTION_NONE +#define DI4_FUNCTION INPUT_FUNCTION_LIMIT + +// Zmin +#define DI5_MODE IO_ACTIVE_HIGH // Z probe +#define DI5_ACTION INPUT_ACTION_NONE +#define DI5_FUNCTION INPUT_FUNCTION_NONE + +// Zmax +#define DI6_MODE NORMALLY_CLOSED +//#define DI6_ACTION INPUT_ACTION_STOP +#define DI6_ACTION INPUT_ACTION_NONE +#define DI6_FUNCTION INPUT_FUNCTION_LIMIT + +// Amin +#define DI7_MODE IO_MODE_DISABLED +#define DI7_ACTION INPUT_ACTION_NONE +#define DI7_FUNCTION INPUT_FUNCTION_NONE + +// Amax +#define DI8_MODE IO_MODE_DISABLED +#define DI8_ACTION INPUT_ACTION_NONE +#define DI8_FUNCTION INPUT_FUNCTION_NONE + +// Hardware interlock input +#define DI9_MODE IO_MODE_DISABLED +#define DI9_ACTION INPUT_ACTION_NONE +#define DI9_FUNCTION INPUT_FUNCTION_NONE + +// *** PWM SPINDLE CONTROL *** + +#define P1_PWM_FREQUENCY 5000 // in Hz +#define P1_CW_SPEED_LO 3000 // in RPM (arbitrary units) +#define P1_CW_SPEED_HI 12000 +#define P1_CW_PHASE_LO 0.15 // phase [0..1] +#define P1_CW_PHASE_HI 0.81 +#define P1_CCW_SPEED_LO 0 +#define P1_CCW_SPEED_HI 0 +#define P1_CCW_PHASE_LO 0.1 +#define P1_CCW_PHASE_HI 0.1 +#define P1_PWM_PHASE_OFF 0.0 diff --git a/g2core/settings/settings_watercolorbot_v2.h b/g2core/settings/settings_watercolorbot_v2.h new file mode 100755 index 00000000..2eb170a9 --- /dev/null +++ b/g2core/settings/settings_watercolorbot_v2.h @@ -0,0 +1,401 @@ +/* + * settings_watercolorbot_v2.h - settings for the WaterColorBot v2 (http://watercolorbot.com/) + * This file is part of the g2core project + * + * Copyright (c) 2016 Alden S. Hart Jr. + * Copyright (c) 2016 Robert Giseburt + * + * This file ("the software") is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2 as published by the + * Free Software Foundation. You should have received a copy of the GNU General Public + * License, version 2 along with the software. If not, see . + * + * As a special exception, you may use this file as part of a software library without + * restriction. Specifically, if other files instantiate templates or use macros or + * inline functions from this file, or you compile this file and link it with other + * files to produce an executable, this file does not by itself cause the resulting + * executable to be covered by the GNU General Public License. This exception does not + * however invalidate any other reasons why the executable file might be covered by the + * GNU General Public License. + * + * THE SOFTWARE IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL, BUT WITHOUT ANY + * WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT + * SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF + * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/***********************************************************************/ +/**** TestV9 profile - naked board *************************************/ +/***********************************************************************/ + +// ***> NOTE: The init message must be a single line with no CRs or LFs +#define INIT_MESSAGE "Initializing configs to WaterColorBot v2 settings" + +#define JUNCTION_INTEGRATION_TIME 1.50 // cornering - usually between 0.5 and 2.0 (higher is faster) +#define CHORDAL_TOLERANCE 0.01 // chordal accuracy for arc drawing (in mm) + +#define SOFT_LIMIT_ENABLE 0 // 0=off, 1=on +#define HARD_LIMIT_ENABLE 1 // 0=off, 1=on +#define SAFETY_INTERLOCK_ENABLE 1 // 0=off, 1=on + +#define SPINDLE_ENABLE_POLARITY 1 // 0=active low, 1=active high +#define SPINDLE_DIR_POLARITY 0 // 0=clockwise is low, 1=clockwise is high +#define SPINDLE_PAUSE_ON_HOLD true +#define SPINDLE_DWELL_TIME 1.0 + +#define COOLANT_MIST_POLARITY 1 // 0=active low, 1=active high +#define COOLANT_FLOOD_POLARITY 1 // 0=active low, 1=active high +#define COOLANT_PAUSE_ON_HOLD false + +// Communications and reporting settings + +#define COMM_MODE JSON_MODE // one of: TEXT_MODE, JSON_MODE +#define XIO_ENABLE_FLOW_CONTROL FLOW_CONTROL_RTS // FLOW_CONTROL_OFF, FLOW_CONTROL_RTS + +#define TEXT_VERBOSITY TV_VERBOSE // one of: TV_SILENT, TV_VERBOSE +#define JSON_VERBOSITY JV_MESSAGES // one of: JV_SILENT, JV_FOOTER, JV_CONFIGS, JV_MESSAGES, JV_LINENUM, JV_VERBOSE +#define QUEUE_REPORT_VERBOSITY QR_OFF // one of: QR_OFF, QR_SINGLE, QR_TRIPLE + +#define STATUS_REPORT_VERBOSITY SR_FILTERED // one of: SR_OFF, SR_FILTERED, SR_VERBOSE +#define STATUS_REPORT_MIN_MS 100 // milliseconds - enforces a viable minimum +#define STATUS_REPORT_INTERVAL_MS 250 // milliseconds - set $SV=0 to disable + +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","posa","bcr","feed","vel","unit","coor","dist","admo","frmo","momo","stat" +#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","feed","vel","momo","stat" + +// Alternate SRs +//#define STATUS_REPORT_DEFAULTS "line","vel","mpox","mpoy","mpoz","mpoa","coor","ofsa","ofsx","ofsy","ofsz","dist","unit","stat","homz","homy","homx","momo" +//#define STATUS_REPORT_DEFAULTS "_ts1","_cs1","_es1","_xs1","_fe1","line","posx","posy","posz","vel","stat" +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","vel","_cs1","_es1","_xs1","_fe1","_cs2","_es2","_xs2","_fe2" +//#define STATUS_REPORT_DEFAULTS "mpox","mpoy","mpoz","mpoa","ofsx","ofsy","ofsz","ofsa","unit","stat","coor","momo","dist","home","hold","macs","cycs","mots","plan","feed" +//#define STATUS_REPORT_DEFAULTS "line","mpox","mpoy","mpoz","mpoa","ofsx","ofsy","ofsz","ofsa","stat","_cs1","_es1","_fe0","_fe1","_fe2","_fe3" +//#define STATUS_REPORT_DEFAULTS "line","mpox","mpoy","mpoz","stat","_ts2","_ps2","_cs2","_es2","_fe2" +//#define STATUS_REPORT_DEFAULTS "line","mpox","mpoy","mpoz","_cs3","_es3","_fe3","_xs3","_cs2","_es2","_fe2","_xs2","stat" +//#define STATUS_REPORT_DEFAULTS "line","posx","posy","posz","posa","feed","vel","unit","coor","dist","frmo","momo","stat","_cs1","_es1","_xs1","_fe1" + +// Gcode startup defaults +#define GCODE_DEFAULT_UNITS MILLIMETERS // MILLIMETERS or INCHES +#define GCODE_DEFAULT_PLANE CANON_PLANE_XY // CANON_PLANE_XY, CANON_PLANE_XZ, or CANON_PLANE_YZ +#define GCODE_DEFAULT_COORD_SYSTEM G54 // G54, G55, G56, G57, G58 or G59 +#define GCODE_DEFAULT_PATH_CONTROL PATH_CONTINUOUS +#define GCODE_DEFAULT_DISTANCE_MODE ABSOLUTE_MODE + +// *** motor settings ************************************************************************************ + +#define MOTOR_POWER_MODE MOTOR_POWERED_IN_CYCLE // default motor power mode (see cmMotorPowerMode in stepper.h) +#define MOTOR_POWER_TIMEOUT 2.00 // motor power timeout in seconds + +#define MOTOR_POWER_MODE MOTOR_POWERED_IN_CYCLE // default motor power mode (see cmMotorPowerMode in stepper.h) +#define MOTOR_POWER_TIMEOUT 2.00 // motor power timeout in seconds + +#define M1_MOTOR_MAP AXIS_Y // 1ma +#define M1_STEP_ANGLE 1.8 // 1sa +#define M1_TRAVEL_PER_REV 91.5 // 1tr +#define M1_MICROSTEPS 32 // 1mi 1,2,4,8 +#define M1_POLARITY 1 // 1po 0=normal, 1=reversed +#define M1_POWER_MODE MOTOR_POWER_MODE // 1pm standard +#define M1_POWER_LEVEL 0.4 + +#define M2_MOTOR_MAP AXIS_X +#define M2_STEP_ANGLE 1.8 +#define M2_TRAVEL_PER_REV 91.5 +#define M2_MICROSTEPS 32 +#define M2_POLARITY 0 +#define M2_POWER_MODE MOTOR_POWER_MODE +#define M2_POWER_LEVEL 0.4 + +#define M3_MOTOR_MAP AXIS_Z + // This "stepper" is a hobby servo. Note that all hobby + // servo settings are per full servo range, instead of + // per revolution. +#define M3_STEP_ANGLE 1.8 // hobby servos are simulated with 200 "full steps" +#define M3_TRAVEL_PER_REV 26 // this is actually the full travel of the servo, not + // necessarily covering a revolution +#define M3_MICROSTEPS 32 // the max step resolution for a hobby servo is 1/32 +#define M3_POLARITY 1 +#define M3_POWER_MODE MOTOR_ALWAYS_POWERED +#define M3_POWER_LEVEL 0.50 // this is ignored + +#define M4_MOTOR_MAP AXIS_A +#define M4_STEP_ANGLE 1.8 +#define M4_TRAVEL_PER_REV 360 // degrees moved per motor rev +#define M4_MICROSTEPS 32 +#define M4_POLARITY 0 +#define M4_POWER_MODE MOTOR_POWER_MODE +#define M4_POWER_LEVEL 0.6 + +// *** axis settings ********************************************************************************** + +#define JERK_MAX 20000 + +#define X_AXIS_MODE AXIS_STANDARD // xam see canonical_machine.h cmAxisMode for valid values +#define X_VELOCITY_MAX 50000 // xvm G0 max velocity in mm/min +#define X_FEEDRATE_MAX X_VELOCITY_MAX // xfr G1 max feed rate in mm/min +#define X_TRAVEL_MIN 0 // xtn minimum travel - used by soft limits and homing +#define X_TRAVEL_MAX 400 // xtm maximum travel - used by soft limits and homing +#define X_JERK_MAX JERK_MAX // xjm +#define X_JERK_HIGH_SPEED X_JERK_MAX // xjh +#define X_HOMING_INPUT 1 // xhi input used for homing or 0 to disable +#define X_HOMING_DIRECTION 0 // xhd 0=search moves negative, 1= search moves positive +#define X_SEARCH_VELOCITY 1000 // xsv move in negative direction +#define X_LATCH_VELOCITY 100 // xlv mm/min +#define X_LATCH_BACKOFF 10 // xlb mm +#define X_ZERO_BACKOFF 2 // xzb mm + +#define Y_AXIS_MODE AXIS_STANDARD +#define Y_VELOCITY_MAX 50000 +#define Y_FEEDRATE_MAX Y_VELOCITY_MAX +#define Y_TRAVEL_MIN 0 +#define Y_TRAVEL_MAX 175 +#define Y_JERK_MAX JERK_MAX +#define Y_JERK_HIGH_SPEED Y_JERK_MAX +#define Y_HOMING_INPUT 3 +#define Y_HOMING_DIRECTION 0 +#define Y_SEARCH_VELOCITY 1000 +#define Y_LATCH_VELOCITY 100 +#define Y_LATCH_BACKOFF 10 +#define Y_ZERO_BACKOFF 2 + +#define Z_AXIS_MODE AXIS_STANDARD +#define Z_VELOCITY_MAX 15000 +#define Z_FEEDRATE_MAX Z_VELOCITY_MAX +#define Z_TRAVEL_MIN 0 +#define Z_TRAVEL_MAX 75 +#define Z_JERK_MAX 5000 +#define Z_JERK_HIGH_SPEED Z_JERK_MAX +#define Z_HOMING_INPUT 6 +#define Z_HOMING_DIRECTION 1 +#define Z_SEARCH_VELOCITY 600 +#define Z_LATCH_VELOCITY 100 +#define Z_LATCH_BACKOFF 10 +#define Z_ZERO_BACKOFF 2 + +// Rotary values are chosen to make the motor react the same as X for testing +/*************************************************************************************** + * To calculate the speeds here, in Wolfram Alpha-speak: + * + * c=2*pi*r, r=0.609, d=c/360, s=((S*60)/d), S=40 for s + * c=2*pi*r, r=5.30516476972984, d=c/360, s=((S*60)/d), S=40 for s + * + * Change r to A_RADIUS, and S to the desired speed, in mm/s or mm/s/s/s. + * + * It will return s= as the value you want to enter. + * + * If the value is over 1 million, the code will divide it by 1 million, + * so you have to pre-multiply it by 1000000.0. (The value is in millions, btw.) + * + * Note that you need these to be floating point values, so always have a .0 at the end! + * + ***************************************************************************************/ + +#define A_AXIS_MODE AXIS_RADIUS +#define A_RADIUS 5.30516476972984 +//#define A_VELOCITY_MAX 25920.0 // ~40 mm/s, 2,400 mm/min +//#define A_FEEDRATE_MAX 25920.0/2.0 // ~20 mm/s, 1,200 mm/min +#define A_VELOCITY_MAX 77760.0 // G0 rate ~120 mm/s, 2,400 mm/min +#define A_FEEDRATE_MAX 9720.0 // 9720.0 = G1 rate ~15 mm/s, 900 mm/min +#define A_TRAVEL_MIN 0 +#define A_TRAVEL_MAX 10 +#define A_JERK_MAX 648000 // 1,000 million mm/min^3 = 648000 + // * a million IF it's over a million + // c=2*pi*r, r=5.30516476972984, d=c/360, s=((1000*60)/d) +#define A_HOMING_INPUT 0 +#define A_HOMING_DIRECTION 0 +#define A_SEARCH_VELOCITY 2000 +#define A_LATCH_VELOCITY 2000 +#define A_LATCH_BACKOFF 5 +#define A_ZERO_BACKOFF 2 +#define A_JERK_HIGH_SPEED A_JERK_MAX + +#define B_AXIS_MODE AXIS_DISABLED +#define B_RADIUS 1 +#define B_VELOCITY_MAX 3600 +#define B_FEEDRATE_MAX B_VELOCITY_MAX +#define B_TRAVEL_MIN 0 +#define B_TRAVEL_MAX -1 +//#define B_JERK_MAX 20000000 +#define B_JERK_MAX 20 +#define B_HOMING_INPUT 0 +#define B_HOMING_DIRECTION 0 +#define B_SEARCH_VELOCITY 600 +#define B_LATCH_VELOCITY 100 +#define B_LATCH_BACKOFF 10 +#define B_ZERO_BACKOFF 2 +#define B_JERK_HIGH_SPEED A_JERK_MAX + + +//*** Input / output settings *** +/* + IO_MODE_DISABLED + IO_ACTIVE_LOW aka NORMALLY_OPEN + IO_ACTIVE_HIGH aka NORMALLY_CLOSED + + INPUT_ACTION_NONE + INPUT_ACTION_STOP + INPUT_ACTION_FAST_STOP + INPUT_ACTION_HALT + INPUT_ACTION_RESET + + INPUT_FUNCTION_NONE + INPUT_FUNCTION_LIMIT + INPUT_FUNCTION_INTERLOCK + INPUT_FUNCTION_SHUTDOWN + INPUT_FUNCTION_PANIC +*/ +// Inputs are defined for the g2ref(a) board +// Xmn (board label) +#define DI1_MODE IO_ACTIVE_HIGH +#define DI1_ACTION INPUT_ACTION_NONE +#define DI1_FUNCTION INPUT_FUNCTION_NONE + +// Xmax +#define DI2_MODE IO_MODE_DISABLED +#define DI2_ACTION INPUT_ACTION_NONE +#define DI2_FUNCTION INPUT_FUNCTION_NONE + +// Ymin +#define DI3_MODE IO_MODE_DISABLED +#define DI3_ACTION INPUT_ACTION_NONE +#define DI3_FUNCTION INPUT_FUNCTION_NONE + +// Ymax +#define DI4_MODE IO_ACTIVE_HIGH +#define DI4_ACTION INPUT_ACTION_NONE +#define DI4_FUNCTION INPUT_FUNCTION_NONE + +// Zmin +#define DI5_MODE IO_ACTIVE_LOW // Z probe +#define DI5_ACTION INPUT_ACTION_NONE +#define DI5_FUNCTION INPUT_FUNCTION_NONE + +// Zmax +#define DI6_MODE IO_MODE_DISABLED +#define DI6_ACTION INPUT_ACTION_STOP +#define DI6_FUNCTION INPUT_FUNCTION_NONE + +// Shutdown (Amin on v9 board) +#define DI7_MODE IO_MODE_DISABLED +#define DI7_ACTION INPUT_ACTION_NONE +#define DI7_FUNCTION INPUT_FUNCTION_NONE + +// High Voltage Z Probe In (Amax on v9 board) +#define DI8_MODE IO_ACTIVE_LOW +#define DI8_ACTION INPUT_ACTION_NONE +#define DI8_FUNCTION INPUT_FUNCTION_NONE + +// Hardware interlock input +#define DI9_MODE IO_MODE_DISABLED +#define DI9_ACTION INPUT_ACTION_NONE +#define DI9_FUNCTION INPUT_FUNCTION_NONE + +//Extruder1_PWM +#define DO1_MODE IO_ACTIVE_HIGH + +//Extruder2_PWM +#define DO2_MODE IO_ACTIVE_HIGH + +//Fan1A_PWM +#define DO3_MODE IO_ACTIVE_HIGH + +//Fan1B_PWM +#define DO4_MODE IO_ACTIVE_HIGH + +#define DO5_MODE IO_ACTIVE_HIGH +#define DO6_MODE IO_ACTIVE_HIGH +#define DO7_MODE IO_ACTIVE_HIGH +#define DO8_MODE IO_ACTIVE_HIGH + +//SAFEin (Output) signal +#define DO9_MODE IO_ACTIVE_HIGH + +#define DO10_MODE IO_ACTIVE_HIGH + +//Header Bed FET +#define DO11_MODE IO_ACTIVE_HIGH + +//Indicator_LED +#define DO12_MODE IO_ACTIVE_HIGH + +#define DO13_MODE IO_ACTIVE_HIGH + + +/*** Extruders / Heaters ***/ +/* +#define MIN_FAN_TEMP 40.0 +#define MAX_FAN_TEMP 150.0 + +#define H1_DEFAULT_ENABLE true +#define H1_DEFAULT_P 9.0 +#define H1_DEFAULT_I 0.12 +#define H1_DEFAULT_D 400.0 + +#define H2_DEFAULT_ENABLE false +#define H2_DEFAULT_P 9.0 +#define H2_DEFAULT_I 0.12 +#define H2_DEFAULT_D 400.0 + +#define H3_DEFAULT_ENABLE false +#define H3_DEFAULT_P 9.0 +#define H3_DEFAULT_I 0.12 +#define H3_DEFAULT_D 400.0 +*/ + + +// *** PWM SPINDLE CONTROL *** + +#define P1_PWM_FREQUENCY 100 // in Hz +#define P1_CW_SPEED_LO 1000 // in RPM (arbitrary units) +#define P1_CW_SPEED_HI 2000 +#define P1_CW_PHASE_LO 0.125 // phase [0..1] +#define P1_CW_PHASE_HI 0.2 +#define P1_CCW_SPEED_LO 1000 +#define P1_CCW_SPEED_HI 2000 +#define P1_CCW_PHASE_LO 0.125 +#define P1_CCW_PHASE_HI 0.2 +#define P1_PWM_PHASE_OFF 0.1 + +// *** DEFAULT COORDINATE SYSTEM OFFSETS *** + +#define G54_X_OFFSET 0 // G54 is traditionally set to all zeros +#define G54_Y_OFFSET 0 +#define G54_Z_OFFSET 0 +#define G54_A_OFFSET 0 +#define G54_B_OFFSET 0 +#define G54_C_OFFSET 0 + +#define G55_X_OFFSET (X_TRAVEL_MAX/2) // set to middle of table +#define G55_Y_OFFSET (Y_TRAVEL_MAX/2) +#define G55_Z_OFFSET 0 +#define G55_A_OFFSET 0 +#define G55_B_OFFSET 0 +#define G55_C_OFFSET 0 + +#define G56_X_OFFSET 0 +#define G56_Y_OFFSET 0 +#define G56_Z_OFFSET 0 +#define G56_A_OFFSET 0 +#define G56_B_OFFSET 0 +#define G56_C_OFFSET 0 + +#define G57_X_OFFSET 0 +#define G57_Y_OFFSET 0 +#define G57_Z_OFFSET 0 +#define G57_A_OFFSET 0 +#define G57_B_OFFSET 0 +#define G57_C_OFFSET 0 + +#define G58_X_OFFSET 0 +#define G58_Y_OFFSET 0 +#define G58_Z_OFFSET 0 +#define G58_A_OFFSET 0 +#define G58_B_OFFSET 0 +#define G58_C_OFFSET 0 + +#define G59_X_OFFSET 0 +#define G59_Y_OFFSET 0 +#define G59_Z_OFFSET 0 +#define G59_A_OFFSET 0 +#define G59_B_OFFSET 0 +#define G59_C_OFFSET 0 diff --git a/g2core/stepper.cpp b/g2core/stepper.cpp index 0652b099..f013059a 100644 --- a/g2core/stepper.cpp +++ b/g2core/stepper.cpp @@ -40,6 +40,20 @@ #include "controller.h" #include "xio.h" +/**** Debugging output with semihosting ****/ + +#include "MotateDebug.h" + +// Unless debugging, this should always read "#if 0 && ..." +// DON'T COMMIT with anything else! +#if 0 && (IN_DEBUGGER == 1) +template +void stepper_debug(const char (&str)[len]) { Motate::debug.write(str); }; +#else +template +void stepper_debug(const char (&str)[len]) { ; }; +#endif + /**** Allocate structures ****/ stConfig_t st_cfg; @@ -62,11 +76,19 @@ extern OutputPin debug_pin3; //extern OutputPin debug_pin4; dda_timer_type dda_timer {kTimerUpToMatch, FREQUENCY_DDA}; // stepper pulse generation -dwell_timer_type dwell_timer {kTimerUpToMatch, FREQUENCY_DWELL}; // dwell timer load_timer_type load_timer; // triggers load of next stepper segment exec_timer_type exec_timer; // triggers calculation of next+1 stepper segment fwd_plan_timer_type fwd_plan_timer; // triggers planning of next block +// SystickEvent for handling dweels (must be registered before it is active) +Motate::SysTickEvent dwell_systick_event {[&] { + if (--st_run.dwell_ticks_downcount == 0) { + SysTickTimer.unregisterEvent(&dwell_systick_event); + _load_move(); // load the next move at the current interrupt level + } +}, nullptr}; + + /************************************************************************************ **** CODE ************************************************************************** ************************************************************************************/ @@ -103,18 +125,15 @@ void stepper_init() // If you need more pulse width you need to drop the DDA clock rate dda_timer.setInterrupts(kInterruptOnOverflow | kInterruptPriorityHighest); - // setup DWELL timer - dwell_timer.setInterrupts(kInterruptOnOverflow | kInterruptPriorityHighest); - // setup software interrupt load timer - load_timer.setInterrupts(kInterruptOnSoftwareTrigger | kInterruptPriorityMedium); + load_timer.setInterrupts(kInterruptOnSoftwareTrigger | kInterruptPriorityHigh); // setup software interrupt exec timer & initial condition - exec_timer.setInterrupts(kInterruptOnSoftwareTrigger | kInterruptPriorityLow); + exec_timer.setInterrupts(kInterruptOnSoftwareTrigger | kInterruptPriorityMedium); st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC; // setup software interrupt forward plan timer & initial condition - fwd_plan_timer.setInterrupts(kInterruptOnSoftwareTrigger | kInterruptPriorityLowest); + fwd_plan_timer.setInterrupts(kInterruptOnSoftwareTrigger | kInterruptPriorityLow); // setup motor power levels and apply power level to stepper drivers for (uint8_t motor=0; motor void dda_timer_type::interrupt() { - dda_timer.getInterruptCause(); // clear interrupt condition + dda_timer.getInterruptCause(); // clear interrupt condition // clear all steps from the previous interrupt // for (uint8_t motor=0; motor 0) { // Motors[motor]->stepStart(); // turn step bit on @@ -279,67 +298,52 @@ void dda_timer_type::interrupt() // process DDAs for each motor if ((st_run.mot[MOTOR_1].substep_accumulator += st_run.mot[MOTOR_1].substep_increment) > 0) { - motor_1.stepStart(); // turn step bit on + motor_1.stepStart(); // turn step bit on st_run.mot[MOTOR_1].substep_accumulator -= st_run.dda_ticks_X_substeps; INCREMENT_ENCODER(MOTOR_1); } if ((st_run.mot[MOTOR_2].substep_accumulator += st_run.mot[MOTOR_2].substep_increment) > 0) { - motor_2.stepStart(); // turn step bit on + motor_2.stepStart(); // turn step bit on st_run.mot[MOTOR_2].substep_accumulator -= st_run.dda_ticks_X_substeps; INCREMENT_ENCODER(MOTOR_2); } #if MOTORS > 2 if ((st_run.mot[MOTOR_3].substep_accumulator += st_run.mot[MOTOR_3].substep_increment) > 0) { - motor_3.stepStart(); // turn step bit on + motor_3.stepStart(); // turn step bit on st_run.mot[MOTOR_3].substep_accumulator -= st_run.dda_ticks_X_substeps; INCREMENT_ENCODER(MOTOR_3); } #endif #if MOTORS > 3 if ((st_run.mot[MOTOR_4].substep_accumulator += st_run.mot[MOTOR_4].substep_increment) > 0) { - motor_4.stepStart(); // turn step bit on + motor_4.stepStart(); // turn step bit on st_run.mot[MOTOR_4].substep_accumulator -= st_run.dda_ticks_X_substeps; INCREMENT_ENCODER(MOTOR_4); } #endif #if MOTORS > 4 if ((st_run.mot[MOTOR_5].substep_accumulator += st_run.mot[MOTOR_5].substep_increment) > 0) { - motor_5.stepStart(); // turn step bit on + motor_5.stepStart(); // turn step bit on st_run.mot[MOTOR_5].substep_accumulator -= st_run.dda_ticks_X_substeps; INCREMENT_ENCODER(MOTOR_5); } #endif #if MOTORS > 5 if ((st_run.mot[MOTOR_6].substep_accumulator += st_run.mot[MOTOR_6].substep_increment) > 0) { - motor_6.stepStart(); // turn step bit on + motor_6.stepStart(); // turn step bit on st_run.mot[MOTOR_6].substep_accumulator -= st_run.dda_ticks_X_substeps; INCREMENT_ENCODER(MOTOR_6); } #endif - // process end of segment + // Process end of segment. + // One more interrupt will occur to turn of any pulses set in this pass. if (--st_run.dda_ticks_downcount == 0) { - _load_move(); // load the next move at the current interrupt level + _load_move(); // load the next move at the current interrupt level } } // MOTATE_TIMER_INTERRUPT } // namespace Motate -/***** Dwell Interrupt Service Routine ************************************************** - * ISR - DDA timer interrupt routine - service ticks from DDA timer - */ - -namespace Motate { // Must define timer interrupts inside the Motate namespace - template<> - void dwell_timer_type::interrupt() -{ - dwell_timer.getInterruptCause(); // read SR to clear interrupt condition - if (--st_run.dda_ticks_downcount == 0) { - dwell_timer.stop(); - _load_move(); - } -} -} // namespace Motate - /**************************************************************************************** * Exec sequencing code - computes and prepares next load segment * st_request_exec_move() - SW interrupt to request to execute a move @@ -348,9 +352,12 @@ namespace Motate { // Must define timer interrupts inside the Motate void st_request_exec_move() { + stepper_debug("e"); if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_EXEC) { // bother interrupting exec_timer.setInterruptPending(); + return; } + stepper_debug("!\n"); } namespace Motate { // Define timer inside Motate namespace @@ -359,16 +366,21 @@ namespace Motate { // Define timer inside Motate namespace { exec_timer.getInterruptCause(); // clears the interrupt condition if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_EXEC) { + stepper_debug("E>"); if (mp_exec_move() != STAT_NOOP) { + stepper_debug("E+\n"); st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // flip it back st_request_load_move(); + return; } + stepper_debug("E-\n"); } } } // namespace Motate -void st_request_plan_move() +void st_request_forward_plan() { + stepper_debug("p"); fwd_plan_timer.setInterruptPending(); } @@ -376,10 +388,14 @@ namespace Motate { // Define timer inside Motate namespace template<> void fwd_plan_timer_type::interrupt() { - fwd_plan_timer.getInterruptCause(); // clears the interrupt condition - if (mp_plan_move() != STAT_NOOP) { // We now have a move to exec. + fwd_plan_timer.getInterruptCause(); // clears the interrupt condition + stepper_debug("P>"); + if (mp_forward_plan() != STAT_NOOP) { // We now have a move to exec. + stepper_debug("P+\n"); st_request_exec_move(); + return; } + stepper_debug("P-\n"); } } // namespace Motate @@ -398,7 +414,9 @@ void st_request_load_move() if (st_runtime_isbusy()) { // don't request a load if the runtime is busy return; } + stepper_debug("l"); if (st_pre.buffer_state == PREP_BUFFER_OWNED_BY_LOADER) { // bother interrupting + stepper_debug("_"); load_timer.setInterruptPending(); } } @@ -408,7 +426,9 @@ namespace Motate { // Define timer inside Motate namespace void load_timer_type::interrupt() { load_timer.getInterruptCause(); // read SR to clear interrupt condition + stepper_debug("L>"); _load_move(); + stepper_debug("L+\n"); } } // namespace Motate @@ -454,8 +474,11 @@ static void _load_move() #if (MOTORS > 5) motor_6.motionStopped(); #endif + stepper_debug("•"); return; - } + } // if (st_pre.buffer_state != PREP_BUFFER_OWNED_BY_LOADER) + + stepper_debug("^"); // handle aline loads first (most common case) NB: there are no more lines, only alines if (st_pre.block_type == BLOCK_TYPE_ALINE) { @@ -500,7 +523,7 @@ static void _load_move() } else { // Motor has 0 steps; might need to energize motor for power mode processing motor_1.motionStopped(); - } + } // accumulate counted steps to the step position and zero out counted steps for the segment currently being loaded ACCUMULATE_ENCODER(MOTOR_1); @@ -597,26 +620,25 @@ static void _load_move() //**** do this last **** - dda_timer.start(); // start the DDA timer if not already running + dda_timer.start(); // start the DDA timer if not already running - // handle dwells + // handle dwells and commands } else if (st_pre.block_type == BLOCK_TYPE_DWELL) { - st_run.dda_ticks_downcount = st_pre.dda_ticks; - dwell_timer.start(); + st_run.dwell_ticks_downcount = st_pre.dwell_ticks; - // handle synchronous commands + // We now use SysTick events to handle dwells + SysTickTimer.registerEvent(&dwell_systick_event); + + // handle synchronous commands } else if (st_pre.block_type == BLOCK_TYPE_COMMAND) { mp_runtime_command(st_pre.bf); - - } // else null - WARNING - We cannot printf from here!! Causes crashes. - else { - _debug_trap("_load_move called when it's not needed?"); - } + + } // else null - which is okay in many cases // all other cases drop to here (e.g. Null moves after Mcodes skip to here) st_pre.block_type = BLOCK_TYPE_NULL; st_pre.buffer_state = PREP_BUFFER_OWNED_BY_EXEC; // we are done with the prep buffer - flip the flag back - st_request_exec_move(); // exec and prep next move + st_request_exec_move(); // exec and prep next move } /*********************************************************************************** @@ -645,6 +667,7 @@ static void _load_move() stat_t st_prep_line(float travel_steps[], float following_error[], float segment_time) { + stepper_debug("😶"); // trap assertion failures and other conditions that would prevent queuing the line if (st_pre.buffer_state != PREP_BUFFER_OWNED_BY_EXEC) { // never supposed to happen return (cm_panic(STAT_INTERNAL_ERROR, "st_prep_line() prep sync error")); @@ -723,6 +746,7 @@ stat_t st_prep_line(float travel_steps[], float following_error[], float segment } st_pre.block_type = BLOCK_TYPE_ALINE; st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready + stepper_debug("👍🏻"); return (STAT_OK); } @@ -754,8 +778,8 @@ void st_prep_command(void *bf) void st_prep_dwell(float microseconds) { st_pre.block_type = BLOCK_TYPE_DWELL; - //st_pre.dda_period = _f_to_period(FREQUENCY_DWELL); - st_pre.dda_ticks = (uint32_t)((microseconds/1000000) * FREQUENCY_DWELL); + // we need dwell_ticks to be at least 1 + st_pre.dwell_ticks = std::max((uint32_t)((microseconds/1000000) * FREQUENCY_DWELL), 1UL); st_pre.buffer_state = PREP_BUFFER_OWNED_BY_LOADER; // signal that prep buffer is ready } diff --git a/g2core/stepper.h b/g2core/stepper.h index 1c185796..eb585f59 100644 --- a/g2core/stepper.h +++ b/g2core/stepper.h @@ -26,13 +26,15 @@ * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* + * --- Stepper Operation Overview --- + * * Coordinated motion (line drawing) is performed using a classic Bresenham DDA. - * A number of additional steps are taken to optimize interpolation and pulse train - * timing accuracy to minimize pulse jitter and make for very smooth motion and surface + * Additional steps are taken to optimize interpolation and pulse train timing + * accuracy to minimize pulse jitter and produce very smooth motion and surface * finish. * * - The DDA is not used as a ramp for acceleration management. Acceleration is computed - * upstream in the motion planner as 5th order (linear snap) equations. These + * upstream in the motion planner as 6th order (linear pop) equations. These * generate accel/decel *segments* that are passed to the DDA for step output. * * - The DDA accepts and processes fractional motor steps as floating point numbers @@ -379,7 +381,8 @@ typedef struct stRunMotor { // one per controlled motor typedef struct stRunSingleton { // Stepper static values and axis parameters magic_t magic_start; // magic number to test memory integrity - uint32_t dda_ticks_downcount; // tick down-counter (unscaled) + uint32_t dda_ticks_downcount; // dda tick down-counter (unscaled) + uint32_t dwell_ticks_downcount; // dwell tick down-counter (unscaled) uint32_t dda_ticks_X_substeps; // ticks multiplied by scaling factor stRunMotor_t mot[MOTORS]; // runtime motor structures magic_t magic_end; @@ -413,8 +416,8 @@ typedef struct stPrepSingleton { struct mpBuffer *bf; // static pointer to relevant buffer blockType block_type; // move type (requires planner.h) - //uint16_t dda_period; // DDA or dwell clock period setting (No longer used) - uint32_t dda_ticks; // DDA or dwell ticks for the move + uint32_t dda_ticks; // DDA ticks for the move + uint32_t dwell_ticks; // dwell ticks remaining uint32_t dda_ticks_X_substeps; // DDA ticks scaled by substep factor stPrepMotor_t mot[MOTORS]; // prep time motor structs magic_t magic_end; @@ -566,7 +569,7 @@ stat_t st_clc(nvObj_t *nv); void st_set_motor_power(const uint8_t motor); stat_t st_motor_power_callback(void); -void st_request_plan_move(void); +void st_request_forward_plan(void); void st_request_exec_move(void); void st_request_load_move(void); void st_prep_null(void); diff --git a/g2core/xio.cpp b/g2core/xio.cpp index 1b94aea7..cc9dc874 100755 --- a/g2core/xio.cpp +++ b/g2core/xio.cpp @@ -38,6 +38,7 @@ #include "report.h" #include "controller.h" #include "util.h" +#include "settings.h" #include "board_xio.h" @@ -81,7 +82,7 @@ using Motate::TXBuffer; /**** Structures ****/ -// We need a buffer to hold single character commands, like !~% +// We need a buffer to hold single character commands, like !~%, ^x, etc. // We also want it to have a NULL character, so we make it two characters. char single_char_buffer[2] = " "; @@ -100,11 +101,11 @@ struct xioDeviceWrapperBase { // C++ base class for device primit // connection and device management uint8_t caps; // bitfield for capabilities flags (these are persistent) devflags_t flags; // bitfield for device state flags (these are not) - devflags_t next_flags; // bitfield for next-state transitions + devflags_t next_flags; // bitfield for next-state transitions // line reader functions // uint16_t read_index; // index into line being read -// const uint16_t read_buf_size; // static variable set at init time +// const uint16_t read_buf_size; // static variable set at init time // char read_buf[USB_LINE_BUFFER_SIZE]; // buffer for reading lines // Internal use only: @@ -223,16 +224,16 @@ struct xio_t { /* * write() - write a block to a device + * + * There are a few issues with this function that I don't know how to resolve right now: + * 1) If a device fails to write the data, or all the data, then it's ignored + * 2) Only the amount written by the *last* device to match (CTRL|ACTIVE) is returned. + * + * In the current environment, these are not foreseen to cause trouble since these + * are blocking writes and we expect to only really be writing to one device. */ size_t write(const char *buffer, size_t size) { - // There are a few issues with this function that I don't know how to resolve right now: - // 1) If a device fails to write the data, or all the data, then it's ignored - // 2) Only the amount written by the *last* device to match (CTRL|ACTIVE) is returned. - // - // In the current environment, these are not foreseen to cause trouble, - // since these are blocking writes and we expect to only really be writing to one device. - size_t total_written = -1; for (int8_t i = 0; i < _dev_count; ++i) { if (DeviceWrappers[i]->isCtrlAndActive()) { @@ -297,10 +298,10 @@ struct xio_t { * DEV_IS_DATA bits in the device flag field. 'Flags' is loaded with the flags of * the channel that was read on return, or 0 (DEV_FLAGS_CLEAR) if no line was returned. * - * size - Returns the size of the completed buffer, including the NUL termination character. - * Lines may be returned truncated to the length of the serial input buffer if the text - * from the physical device is longer than the read buffer for the device. The size value - * provided as a calling argument is ignored (size doesn't matter). + * size - Returns the size of the completed buffer, including the NUL termination character. + * Lines may be returned truncated to the length of the serial input buffer if the text + * from the physical device is longer than the read buffer for the device. The size value + * provided as a calling argument is ignored (size doesn't matter). * * char * Returns a pointer to the buffer containing the line, or NULL (*0) if no text */ @@ -352,7 +353,7 @@ struct xio_t { uint16_t magic_end; }; -// Declare (but don't define) the xio singelton object now, define it later +// Declare (but don't define) the xio singleton object now, define it later // Why? xioDeviceWrapper uses it, but we need to define it to contain xioDeviceWrapper objects. extern xio_t xio; @@ -362,42 +363,12 @@ extern xio_t xio; // See here for a discussion of what this means if you are not familiar with C++ // https://github.com/synthetos/g2/wiki/Dual-Endpoint-USB-Internals#c-classes-virtual-functions-and-inheritance - // LineRXBuffer takes the Motate RXBuffer (which handles "transfers", usually DMA), and adds G2 line-reading // semantics to it. template -struct LineRXBuffer : RXBuffer<_size, owner_type, char> { // reserve size of 128bytes +struct LineRXBuffer : RXBuffer<_size, owner_type, char> { typedef RXBuffer<_size, owner_type, char> parent_type; - // SUPPORTING STRUCTURES - enum _LinesHeaderStatus_t { - HEADER_FREE, - HEADER_PREPPED, - HEADER_FILLING, - HEADER_FULL - }; - - struct _LinesHeader { - _LinesHeaderStatus_t _status; - bool _is_control; - bool _is_processing; - - int16_t _line_count; // number of lines in this group of lines - int16_t _read_offset; // start of the next line to read (first char past PROCESSING line) - - uint16_t _get_next_read_offset() { return ((_read_offset + 1) & (_size-1)); }; - - - // Convenience function for reset - void reset() { - _status = HEADER_FREE; - _is_control = false; - _line_count = 0; - _read_offset = 0; - }; - }; - - // Let's help the compiler clarify what we mean by a few things: // (This is because of the templating, it needs a little extra clarification.) using parent_type::_data; @@ -412,80 +383,95 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> { // reserve size of 128 // START OF LineRXBuffer PROPER static_assert(((_header_count-1)&_header_count)==0, "_header_count must be 2^N"); - char _line_buffer[_line_buffer_size]; // hold excatly one line to return + char _line_buffer[_line_buffer_size]; // hold exactly one line to return uint32_t _line_end_guard = 0xBEEF; // General term usage: // * "index" indicates it's in to _headers array // * "offset" means it's a character in the _data array - - _LinesHeader _headers[_header_count]; // and array that we'll use as a ring buffer of _LinesHeaders - uint8_t _first_header_index; // index into the array of the (current) first item of _headers - uint8_t _write_header_index; // index into the array of the item of _headers we are writing too (unless it's FULL) - uint16_t _scan_offset; // offset into data of the last character scanned uint16_t _line_start_offset; // offset into first character of the line bool _at_start_of_line; // true if the last character scanned was the end of a line + uint16_t _lines_found; // count of complete non-control lines that were found during scanning. + volatile uint16_t _last_scan_offset; // DEBUGGING LineRXBuffer(owner_type owner) : parent_type{owner} {}; - void init() { parent_type::init(); }; - - uint8_t _get_next_write_header_index() { return ((_write_header_index + 1) & (_header_count-1)); }; - uint8_t _get_next_first_header_index() { return ((_first_header_index + 1) & (_header_count-1)); }; - uint8_t _get_next_header_index(uint8_t indx) { return ((indx + 1) & (_header_count-1)); }; - - void _free_unused_space() { - // Headers that were processing OR are now completely empty are now safe to clear,m - // but only in order. - auto _first_header = &_headers[_first_header_index]; - while ((_first_header->_is_processing) || ((_first_header->_status == HEADER_FULL) && (_first_header->_line_count == 0))) { - _read_offset = _first_header->_read_offset; - _first_header->_is_processing = false; - - if ((_first_header->_status == HEADER_FULL) && (_first_header->_line_count == 0)) { - _first_header->reset(); - _first_header_index = _get_next_first_header_index(); - - // Point _first_header to the new first header - _first_header = &_headers[_first_header_index]; - } else { - // We can only clear into the next one if we completely clear this one - break; - } - } - - if ((_write_header_index == _first_header_index) && (_first_header->_status == HEADER_FREE)) { - // PREP it - _first_header->_status = HEADER_PREPPED; - - _at_start_of_line = true; - _first_header->_read_offset = _line_start_offset; - - _restartTransfer(); - } + void init() { + parent_type::init(); + _at_start_of_line = true; }; - bool _check_write_header() { - // _status cannot be PROCESSING, since we already cleared those in _free_unused_space() - if (_headers[_write_header_index]._status == HEADER_FULL) { - uint8_t _next_write_header_index = _get_next_write_header_index(); - if (_next_write_header_index == _first_header_index) { // we're full full - return false; - } - _write_header_index = _next_write_header_index; - auto _write_header = &_headers[_write_header_index]; - _write_header->_status = HEADER_PREPPED; - _at_start_of_line = true; - _write_header->_read_offset = _line_start_offset; - } - return true; + struct SkipSections { + struct SkipSection { + uint16_t start_offset; // the offset of the first character to skip + uint16_t end_offset; // the offset of the next character to read after skipping + }; + + static constexpr uint16_t _section_count = 16; + SkipSection _sections[_section_count]; + + uint8_t read_section_idx; // index of the first skip section to skip + uint8_t write_section_idx; // index of the next skip section to populate + + bool is_full() { + return ((write_section_idx+1)&(_section_count-1)) == read_section_idx; + }; + bool is_empty() { + return (write_section_idx == read_section_idx); + }; + + void add_skip(uint16_t start_offset, uint16_t end_offset) { + if (!is_empty()) { + uint8_t last_write_section_idx = write_section_idx; + if (write_section_idx == 0) { + last_write_section_idx = _section_count-1; + } else { + last_write_section_idx--; + } + + if (_sections[last_write_section_idx].end_offset == start_offset) { + _sections[last_write_section_idx].end_offset = end_offset; + return; + } + } + _sections[write_section_idx].start_offset = start_offset; + _sections[write_section_idx].end_offset = end_offset; + write_section_idx = ((write_section_idx+1)&(_section_count-1)); + }; + + void pop_skip() { + _sections[read_section_idx].start_offset = 0; + _sections[read_section_idx].end_offset = 0; + + read_section_idx = ((read_section_idx+1)&(_section_count-1)); + }; + + bool skip(volatile uint16_t &from) { + if (!is_empty()) { + SkipSection &next_skip = _sections[read_section_idx]; + + if (next_skip.start_offset == from) { + from = next_skip.end_offset; + + pop_skip(); + return true; + } + } + return false; + }; + +// const SkipSection& next_skip() { +// return _sections[read_section_idx]; +// } }; + SkipSections _skip_sections; + uint16_t _get_next_scan_offset() { return ((_scan_offset + 1) & (_size-1)); } @@ -494,103 +480,101 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> { // reserve size of 128 return _canBeRead(_scan_offset); }; -// // This function skips the "whitespace" at the BEGINNING of a line. -// // This assumes we've already located the end of a line. -// void _scan_past_line_start() { -// while (_is_more_to_scan()) { -// char c = _data[_scan_offset]; -// if (c == '\r' || -// c == '\n' || -// c == '\t' || -// c == ' ') { -// _scan_offset = _get_next_scan_offset(); -// } else { -// break; -// } -// } // end _skipping whitespace -// }; + /* + * _scan_buffer() + * + * Make a pass through the RX DMA buffer to locate any control lines, and count lines. + * Single character controls, like !, ~, %, and ^x are also considered control "lines" + * + * _scan_buffer() is called at the beginning of readline, and is effectively the first + * "phase" of readline. + * + * This function is designed to be able to exit from almost any point, and + * come back in and resume where it left off. This allows it to scan to the + * end of the buffer then exit. When the function is called next it picks up + * where it left off - i.e. avoiding rescanning the entire buffer multiple times. + * + * _scan_buffer() returns true if it finds a control line. + * The control line starts at the character at _line_start_offset and includes + * the characters up to _scan_offset-1. If there are multiple line-ending chars + * ("\r\n" for example) _scan_offset will point to the *first* one. + * + * With ASCII art (where "." means "invalid data" or "don't care"): + * + * Example 1 of _scan_buffer() == true: + * _data = "G0X10\n{jvm:5}\n{xvm:1200}\nG0Y10\nG1Z......" + * ^ ^ + * | | + * _line_start_offset | + * _scan_offset + * + * Example 2 of _scan_buffer() == true: + * _data = "G0X10\n.........{xvm:1200}\nG0Y10\nG1Z......" + * ^ ^ + * | | + * _line_start_offset | + * _scan_offset + * + * Example 2 of _scan_buffer() == true: + * _data = "G0X10\n!......" + * ^^ + * || + * _line_start_offset| + * _scan_offset + * + * For _scan_buffer() == false, IGNORE _line_start_offset and _scan_offset!!! + * Only use _read_offset, and use _lines_found>0 to determine if _data contains a line to return. + * Also note that _read_offset needs to be moved once the data is copied to _line_buffer! + */ + /* Explanation of cases and how we handle it. + * + * Our first task in this loop is two-fold (done at the same time): + * A) Scan the RX DMA buffer for the next complete line, then classify the line. + * B) Scan for a single-character command (!~% ^D, etc), then classify as a control line. + * + * If we find a line that classifies as "control" then we return true and stop scanning. + * + * We also have a constraint that we may run out of characters at any time. This is OK, + * and enough state is kept that we can enter the function at any point with new + * characters added to the RX DMA buffer and get the same results. + * + * Another constraint is that lines MAY have single character commands embedded in them. + * In this case we need to un-embed them. Since we may not have the end of the line yet, + * we need to move the command to the beginning of the line. + * + * Note that _at_start_of_line means that we *just* parsed a character that is *at* the end of the line. + * So, for a \r\n sequence, _at_start_of_line will go true of the \r, and we'll see the \n and it'll stay + * true, then the first non \r or \n char will set it to false, and *then* start the next line. + */ - - // Make a pass through the buffer to create headers for what has been read. - - // This function is designed to be able to exit from almost any point, and - // come back in and resume where it left off. This allows it to scan to the - // end of the buffer, then exit. - void _scan_buffer() { - _free_unused_space(); - - if (!_check_write_header()) { return; } - - /* Explanation of cases and how we handle it. - * - * Our first task in this loop is two fold: - * A) Scan for the next complete line, then classify the line. - * B) Scan for a single-character command (!~% ^D, etc), then classify that as a line. - * - * Out next task is to then to manage the headers with this new information. We either: - * 1) Add the line to the header, if the write header is FILLING and has the same classification. - * 2) Add the line to the header, and classify it, if the write header is PENDING. - * 3) Mark the current write header as FULL, and then (2) on the next one. - * - * We also have a constraint that we may run out of character at any time. This is okay, and enough - * state is kept that we can enter the function at any point with new characters and get the same results. - * - * Another constraint is that lines MAY have single character commands embedded in them. In this case, - * we need to un-embed them. Since we may not have the end of the line yet, we need to move the command - * to the beginning of the line. - * - * Note that _at_start_of_line means that we *just* parsed a character that is *at* the end of the line. - * So, for a \r\n sequence, _at_start_of_line will go true of the \r, and we'll see the \n and it'll stay - * true, then the first non \r or \n char will set it to false, and *then* start the next line. - * - */ + bool _scan_buffer() { _last_scan_offset = _scan_offset; while (_is_more_to_scan()) { - auto write_header = &_headers[_write_header_index]; - bool ends_line = false; bool is_control = false; - // Look for line endings - // Classify the line char c = _data[_scan_offset]; if (c == 0) { _debug_trap("scan ran into NULL"); } - if (c == '\r' || - c == '\n' - ) { - - // We only mark ends_line for the first end-line char, and if - // _at_start_of_line is already true, this is not the first. - if (!_at_start_of_line) { - ends_line = true; + // Look for line endings + if (c == '\r' || c == '\n') { + if (!_at_start_of_line) { // We only mark ends_line for the first end-line char, and if + ends_line = true; // _at_start_of_line is already true, this is not the first. } } + // Classify the line if it's a single character else - if ((c == '!') || - (c == '~') || - (c == ENQ) || // request ENQ/ack - (c == CHAR_RESET) || // ^X - reset (aka cancel, terminate) - (c == CHAR_ALARM) || // ^D - request job kill (end of transmission) - (cm_has_hold() && c == '%') // flush (only in feedhold) - ) { - - // Special case: if we're NOT _at_start_of_line, we need to move the - // character to _line_start_offset. That means moving every character - // forward one. THEN we back-track _scan_offset to this new start of line. - if (!_at_start_of_line) { - uint16_t copy_offset = _line_start_offset; - while (copy_offset != _scan_offset) { - uint16_t next_copy_offset = (copy_offset+1)&(_size-1); - _data[next_copy_offset] = _data[copy_offset]; - copy_offset = next_copy_offset; - } - // Copy the single character to the first character - _data[_line_start_offset] = c; - } + if (_at_start_of_line && + ((c == '!') || + (c == '~') || + (c == ENQ) || // request ENQ/ack + (c == CHAR_RESET) || // ^X - reset (aka cancel, terminate) + (c == CHAR_ALARM) || // ^D - request job kill (end of transmission) + (c == '%' && cm_has_hold()) // flush (only in feedhold or part of control header) + )) { _line_start_offset = _scan_offset; @@ -606,7 +590,14 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> { // reserve size of 128 _at_start_of_line = false; } + // bump the _scan_offset + _scan_offset = _get_next_scan_offset(); + if (ends_line) { + // _scan_offset is now one past the end of the line, + // which means it is at the start of a new line + _at_start_of_line = true; + // Here we classify the line. // If we are is_control is already true, it's an already classified // single-character command. @@ -620,149 +611,168 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> { // reserve size of 128 // TODO --- } - - if (write_header->_status == HEADER_PREPPED) { - write_header->_is_control = is_control; - write_header->_status = HEADER_FILLING; - } - else if (write_header->_is_control != is_control) - { - // This line goes into the next header. - // Now we have to end this _write_header and grab another. - - write_header->_status = HEADER_FULL; - if (!_check_write_header()) { - // We just bail if there's not another header available. - return; + if (is_control) { // we found a control + // Quick check for single-character with a \n after it + while (_is_more_to_scan() && + ((_data[_scan_offset] == '\n') || + (_data[_scan_offset] == '\r')) + ) + { + _scan_offset = _get_next_scan_offset(); } - - // Update the pointer - write_header = &_headers[_write_header_index]; - write_header->_is_control = is_control; - write_header->_status = HEADER_FILLING; + return true; + } else { // we did find one more line, though. + _lines_found++; } - - write_header->_line_count++; - _at_start_of_line = true; - } - - // We do this LAST. If we had to exit before this point, - // we will evaluate the same character again. - _scan_offset = _get_next_scan_offset(); + } // if ends_line } //while (_is_more_to_scan()) + return false; // no control was found }; - - - // This is the ONLY external interface in this class + /* + * readline() + * + * This is the ONLY external interface in this class + * + * Exit condition when a control is found: _line_start_offset and _scan_offset should be the same. + * If the control was the first char of the buffer it also moves the _data_offset, marking it as read + */ char *readline(bool control_only, uint16_t &line_size) { - _scan_buffer(); + // This is tricky: if we don't have room for more skip_sections, then we + // can't scan any more for controls. So we don't scan, amd hope some lines are read. + bool found_control = _skip_sections.is_full() ? false : _scan_buffer(); + _restartTransfer(); - uint8_t search_header_index = _first_header_index; - auto search_header = &_headers[search_header_index]; - bool found_control = false; - do { - if ((search_header->_status >= HEADER_FILLING) && - search_header->_is_control && - (search_header->_line_count > 0)) { - - found_control = true; - break; - } - if (search_header_index == _write_header_index) - { - break; - } - - search_header_index = _get_next_header_index(search_header_index); - search_header = &_headers[search_header_index]; - } while (1); - - - if (found_control) { - - // When we get here, search_header points to a valid header that we want to either: - // A) Get a single-character command from and return it, OR - // B) Get a full line from and return it. - - // For B, we handle that like any line. But the single chars have to have special - // attention. - - - char c = _data[search_header->_read_offset]; - if ((c == '!') || - (c == '~') || - (c == ENQ) || // request ENQ/ack - (c == CHAR_RESET) || // ^X - reset (aka cancel, terminate) - (c == CHAR_ALARM) || // ^D - request job kill (end of transmission) - (cm_has_hold() && c == '%') // flush (only in feedhold) - ) { - line_size = 1; - - search_header->_read_offset = search_header->_get_next_read_offset(); - search_header->_line_count--; - search_header->_is_processing = true; - - single_char_buffer[0] = c; - single_char_buffer[1] = 0; - - return single_char_buffer; - } - - // fall through to finding the end of the line in search_header - - - } // end if (found_control) - else { - - // Logic to determine that we can safely look at ONLY the first header: - // • We always read all of the command lines first. - // • We have already called _free_unused_space(). - - search_header_index = _first_header_index; - search_header = &_headers[search_header_index]; - - if (control_only || search_header->_is_control || (search_header->_line_count == 0)) { - if ((search_header->_line_count == 0)) { - _restartTransfer(); - } - line_size = 0; - return nullptr; - } - - } // end if (!found_control) - - - - // By the time we get here, search_header points to a valid header that we want to pull the first - // full line from and return it. - - - uint16_t read_offset = search_header->_read_offset; char *dst_ptr = _line_buffer; line_size = 0; - if (_data[read_offset] == 0) { + if (found_control) { + // Optimization: if the control was found at the beginning of _data, we note that now + // and update the _read_offset when we update _line_start_offset + bool ctrl_is_at_beginning_of_data = (_line_start_offset == _read_offset); + if (!ctrl_is_at_beginning_of_data) { + _skip_sections.add_skip(_line_start_offset, _scan_offset); + } + + // When we get here, _line_start_offset points to either: + // A) A single-character command, OR + // B) A full line. + // Either way, _scan_offset is one past the end, so we don't care which. + + if (_data[_line_start_offset] == 0) { + _debug_trap("read ran into NULL"); + } + + // scan past any leftover CR or LF from the previous line + while ((_data[_line_start_offset] == '\n') || (_data[_line_start_offset] == '\r')) { + _line_start_offset = (_line_start_offset+1)&(_size-1); + if (_scan_offset == _line_start_offset) { + _debug_trap("read ran into scan (1)"); + } + } + + while ((_scan_offset != _line_start_offset) && + (line_size < (_line_buffer_size - 2))) { +// if (!_canBeRead(read_offset)) { // This test should NEVER fail. +// _debug_trap("readline hit unreadable and shouldn't have!"); +// } + + // copy the charater to _line_buffer + char c = _data[_line_start_offset]; + *dst_ptr = c; + + // update the line_size + line_size++; + + // update read/write positions + dst_ptr++; + _line_start_offset = (_line_start_offset+1)&(_size-1); + } + + // null-terminate the string + *dst_ptr = 0; + + if (ctrl_is_at_beginning_of_data) { + _read_offset = _scan_offset; + } else { + // special case: if the return value is '%' + // then we actually consider everything before it to be read + + if ('%' == _line_buffer[0]) { + // Things that must be managed here: + // * _read_offset -- we're skipping data + // * _lines_found -- we shouldn't have any lines "left" + // * _skip_sections -- there's nothing to skip, we just did + + // Things that won't be changed (further): + // * _scan_offset -- we're not changing past where it's scanned + // * _line_start_offset -- we've already adjusted it + // * _at_start_of_line -- should always be true when we're here + + // move the read buffer up to where we're scanning + _read_offset = _scan_offset; + + // record that we have 0 lines (of data) in the buffer + _lines_found = 0; + + // and clear out any skip sections we have + while (!_skip_sections.is_empty()) { + _skip_sections.pop_skip(); + } + } + } + +// if (ctrl_is_at_beginning_of_data) { +// // attempt to request more data +// _restartTransfer(); +// } + + return _line_buffer; + } // end if (found_control) + + if (control_only) { + line_size = 0; + return nullptr; + } + + if (_lines_found == 0) { + // nothing to return + line_size = 0; + return nullptr; + } + + + // By the time we get here, we know we have at least one line in _data. + + + if (_data[_read_offset] == 0) { _debug_trap("read ran into NULL"); } + // skip sections will always start at the beginning of a line + _skip_sections.skip(_read_offset); + // scan past any leftover CR or LF from the previous line - while ((_data[read_offset] == '\n') || (_data[read_offset] == '\r')) { - read_offset = (read_offset+1)&(_size-1); - if (_scan_offset == read_offset) { - _debug_trap("read ran into scan (1)"); + char c = _data[_read_offset]; + while ((c == '\n') || (c == '\r')) { + _read_offset = (_read_offset+1)&(_size-1); + if (_scan_offset == _read_offset) { + _debug_trap("read ran into scan (2)"); } + // this also counts as the beginning of a line + _skip_sections.skip(_read_offset); + c = _data[_read_offset]; } while (line_size < (_line_buffer_size - 2)) { - if (!_canBeRead(read_offset)) { // This test should NEVER fail. - _debug_trap("readline hit unreadable and shouldn't have!"); - } - char c = _data[read_offset]; +// if (!_canBeRead(read_offset)) { // This test should NEVER fail. +// _debug_trap("readline hit unreadable and shouldn't have!"); +// } - if ( - c == '\r' || + _read_offset = (_read_offset+1)&(_size-1); + + if ( c == '\r' || c == '\n' ) { @@ -774,31 +784,46 @@ struct LineRXBuffer : RXBuffer<_size, owner_type, char> { // reserve size of 128 // update read/write positions dst_ptr++; - read_offset = (read_offset+1)&(_size-1); - if (_scan_offset == read_offset) { - _debug_trap("read ran into scan (2)"); - } + + c = _data[_read_offset]; } - // previous character was last one of the line - // update the header's next read position - search_header->_read_offset = (read_offset+1)&(_size-1); - // and line count - search_header->_line_count--; - // and processing flag - search_header->_is_processing = true; + --_lines_found; + _restartTransfer(); + + // null-terminate the string *dst_ptr = 0; return _line_buffer; - }; -}; + }; // readline + // this is called from flushRead() + void flush() { + parent_type::flush(); + _scan_offset = _read_offset; + + // This is similar to the % "queue flush" handling above, except we flush + // the scan to the to the read (which was just set tot he write by the parent), + // not the other way around. + + // record that we have 0 lines (of data) in the buffer + _lines_found = 0; + + // and clear out any skip sections we have + while (!_skip_sections.is_empty()) { + _skip_sections.pop_skip(); + } + }; // flush + +}; // LineRXBuffer template struct xioDeviceWrapper : xioDeviceWrapperBase { // describes a device for reading and writing Device _dev; - LineRXBuffer<512, Device> _rx_buffer; - TXBuffer<512, Device> _tx_buffer; + + // TODO - make _buffer_size, _header_count, and _line_buffer_size configurable + LineRXBuffer<1024, Device> _rx_buffer; + TXBuffer<1024, Device> _tx_buffer; xioDeviceWrapper(Device dev, uint8_t _caps) : xioDeviceWrapperBase(_caps), _dev{dev}, _rx_buffer{_dev}, _tx_buffer{_dev} { @@ -928,7 +953,7 @@ struct xioDeviceWrapper : xioDeviceWrapperBase { // describes a device for re } // flags & DEV_IS_CONNECTED } }; - }; +}; // ALLOCATIONS // Declare a device wrapper class for SerialUSB and SerialUSB1 @@ -937,10 +962,12 @@ xioDeviceWrapper serialUSB0Wrapper { &SerialUSB, (DEV_CAN_READ | DEV_CAN_WRITE | DEV_CAN_BE_CTRL | DEV_CAN_BE_DATA) }; +#if USB_SERIAL_PORTS_EXPOSED == 2 xioDeviceWrapper serialUSB1Wrapper { &SerialUSB1, (DEV_CAN_READ | DEV_CAN_WRITE | DEV_CAN_BE_CTRL | DEV_CAN_BE_DATA) }; +#endif #endif // XIO_HAS_USB #if XIO_HAS_UART==1 xioDeviceWrapper serial0Wrapper { @@ -954,7 +981,9 @@ xioDeviceWrapper serial0Wrapper { xio_t xio = { #if XIO_HAS_USB == 1 &serialUSB0Wrapper, +#if USB_SERIAL_PORTS_EXPOSED == 2 &serialUSB1Wrapper, +#endif #endif // XIO_HAS_USB #if XIO_HAS_UART == 1 &serial0Wrapper @@ -982,8 +1011,10 @@ void xio_init() #if XIO_HAS_USB == 1 serialUSB0Wrapper.init(); +#if USB_SERIAL_PORTS_EXPOSED == 2 serialUSB1Wrapper.init(); #endif +#endif #if XIO_HAS_UART == 1 serial0Wrapper.init(); #endif @@ -1009,7 +1040,6 @@ size_t xio_write(const char *buffer, size_t size) /* * xio_readline() - read a complete line from a device * xio_writeline() - write a complete line to control device - * xio_flush_read() - flush read buffers * * Defers to xio.readline(), etc. */ @@ -1024,11 +1054,6 @@ int16_t xio_writeline(const char *buffer) return xio.writeline(buffer); } -void xio_flush_read() -{ - return xio.flushRead(); -} - bool xio_connected() { return xio.connected(); diff --git a/g2core/xio.h b/g2core/xio.h index 671ba905..0369af21 100755 --- a/g2core/xio.h +++ b/g2core/xio.h @@ -113,7 +113,6 @@ enum xioSPIMode { void xio_init(void); stat_t xio_test_assertions(void); -void xio_flush_read(); size_t xio_write(const uint8_t *buffer, size_t size); char *xio_readline(devflags_t &flags, uint16_t &size); int16_t xio_writeline(const char *buffer);