update code base to Marlin 2.0.9.2

This commit is contained in:
Stefan Kalscheuer
2021-10-03 18:57:12 +02:00
parent b9d7ba838e
commit 7077da3591
2617 changed files with 332093 additions and 103438 deletions

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -56,55 +56,68 @@
#define BOARD_3DRAG 1100 // 3Drag Controller
#define BOARD_K8200 1101 // Velleman K8200 Controller (derived from 3Drag Controller)
#define BOARD_K8400 1102 // Velleman K8400 Controller (derived from 3Drag Controller)
#define BOARD_BAM_DICE 1103 // 2PrintBeta BAM&DICE with STK drivers
#define BOARD_BAM_DICE_DUE 1104 // 2PrintBeta BAM&DICE Due with STK drivers
#define BOARD_MKS_BASE 1105 // MKS BASE v1.0
#define BOARD_MKS_BASE_14 1106 // MKS BASE v1.4 with Allegro A4982 stepper drivers
#define BOARD_MKS_BASE_15 1107 // MKS BASE v1.5 with Allegro A4982 stepper drivers
#define BOARD_MKS_BASE_16 1108 // MKS BASE v1.6 with Allegro A4982 stepper drivers
#define BOARD_MKS_BASE_HEROIC 1109 // MKS BASE 1.0 with Heroic HR4982 stepper drivers
#define BOARD_MKS_GEN_13 1110 // MKS GEN v1.3 or 1.4
#define BOARD_MKS_GEN_L 1111 // MKS GEN L
#define BOARD_KFB_2 1112 // BigTreeTech or BIQU KFB2.0
#define BOARD_ZRIB_V20 1113 // zrib V2.0 control board (Chinese knock off RAMPS replica)
#define BOARD_FELIX2 1114 // Felix 2.0+ Electronics Board (RAMPS like)
#define BOARD_RIGIDBOARD 1115 // Invent-A-Part RigidBoard
#define BOARD_RIGIDBOARD_V2 1116 // Invent-A-Part RigidBoard V2
#define BOARD_SAINSMART_2IN1 1117 // Sainsmart 2-in-1 board
#define BOARD_ULTIMAKER 1118 // Ultimaker
#define BOARD_ULTIMAKER_OLD 1119 // Ultimaker (Older electronics. Pre 1.5.4. This is rare)
#define BOARD_AZTEEG_X3 1120 // Azteeg X3
#define BOARD_AZTEEG_X3_PRO 1121 // Azteeg X3 Pro
#define BOARD_ULTIMAIN_2 1122 // Ultimainboard 2.x (Uses TEMP_SENSOR 20)
#define BOARD_RUMBA 1123 // Rumba
#define BOARD_RUMBA_RAISE3D 1124 // Raise3D N series Rumba derivative
#define BOARD_RL200 1125 // Rapide Lite 200 (v1, low-cost RUMBA clone with drv)
#define BOARD_FORMBOT_TREX2PLUS 1126 // Formbot T-Rex 2 Plus
#define BOARD_FORMBOT_TREX3 1127 // Formbot T-Rex 3
#define BOARD_FORMBOT_RAPTOR 1128 // Formbot Raptor
#define BOARD_FORMBOT_RAPTOR2 1129 // Formbot Raptor 2
#define BOARD_BQ_ZUM_MEGA_3D 1130 // bq ZUM Mega 3D
#define BOARD_MAKEBOARD_MINI 1131 // MakeBoard Mini v2.1.2 is a control board sold by MicroMake
#define BOARD_TRIGORILLA_13 1132 // TriGorilla Anycubic version 1.3-based on RAMPS EFB
#define BOARD_TRIGORILLA_14 1133 // ... Ver 1.4
#define BOARD_TRIGORILLA_14_11 1134 // ... Rev 1.1 (new servo pin order)
#define BOARD_RAMPS_ENDER_4 1135 // Creality: Ender-4, CR-8
#define BOARD_RAMPS_CREALITY 1136 // Creality: CR10S, CR20, CR-X
#define BOARD_RAMPS_DAGOMA 1137 // Dagoma F5
#define BOARD_FYSETC_F6_13 1138 // FYSETC F6 1.3
#define BOARD_FYSETC_F6_14 1139 // FYSETC F6 1.4
#define BOARD_DUPLICATOR_I3_PLUS 1140 // Wanhao Duplicator i3 Plus
#define BOARD_VORON 1141 // VORON Design
#define BOARD_TRONXY_V3_1_0 1142 // Tronxy TRONXY-V3-1.0
#define BOARD_Z_BOLT_X_SERIES 1143 // Z-Bolt X Series
#define BOARD_TT_OSCAR 1144 // TT OSCAR
#define BOARD_OVERLORD 1145 // Overlord/Overlord Pro
#define BOARD_HJC2560C_REV1 1146 // ADIMLab Gantry v1
#define BOARD_HJC2560C_REV2 1147 // ADIMLab Gantry v2
#define BOARD_TANGO 1148 // BIQU Tango V1
#define BOARD_MKS_GEN_L_V2 1149 // MKS GEN L V2
#define BOARD_COPYMASTER_3D 1150 // Copymaster 3D
#define BOARD_TRIGORILLA_CHIRON 1151 // TriGorilla Anycubic version 1.4 based on RAMPS EFB for Chiron
#define BOARD_K8600 1103 // Velleman K8600 Controller (Vertex Nano)
#define BOARD_K8800 1104 // Velleman K8800 Controller (Vertex Delta)
#define BOARD_BAM_DICE 1105 // 2PrintBeta BAM&DICE with STK drivers
#define BOARD_BAM_DICE_DUE 1106 // 2PrintBeta BAM&DICE Due with STK drivers
#define BOARD_MKS_BASE 1107 // MKS BASE v1.0
#define BOARD_MKS_BASE_14 1108 // MKS BASE v1.4 with Allegro A4982 stepper drivers
#define BOARD_MKS_BASE_15 1109 // MKS BASE v1.5 with Allegro A4982 stepper drivers
#define BOARD_MKS_BASE_16 1110 // MKS BASE v1.6 with Allegro A4982 stepper drivers
#define BOARD_MKS_BASE_HEROIC 1111 // MKS BASE 1.0 with Heroic HR4982 stepper drivers
#define BOARD_MKS_GEN_13 1112 // MKS GEN v1.3 or 1.4
#define BOARD_MKS_GEN_L 1113 // MKS GEN L
#define BOARD_KFB_2 1114 // BigTreeTech or BIQU KFB2.0
#define BOARD_ZRIB_V20 1115 // zrib V2.0 (Chinese RAMPS replica)
#define BOARD_ZRIB_V52 1116 // zrib V5.2 (Chinese RAMPS replica)
#define BOARD_FELIX2 1117 // Felix 2.0+ Electronics Board (RAMPS like)
#define BOARD_RIGIDBOARD 1118 // Invent-A-Part RigidBoard
#define BOARD_RIGIDBOARD_V2 1119 // Invent-A-Part RigidBoard V2
#define BOARD_SAINSMART_2IN1 1120 // Sainsmart 2-in-1 board
#define BOARD_ULTIMAKER 1121 // Ultimaker
#define BOARD_ULTIMAKER_OLD 1122 // Ultimaker (Older electronics. Pre 1.5.4. This is rare)
#define BOARD_AZTEEG_X3 1123 // Azteeg X3
#define BOARD_AZTEEG_X3_PRO 1124 // Azteeg X3 Pro
#define BOARD_ULTIMAIN_2 1125 // Ultimainboard 2.x (Uses TEMP_SENSOR 20)
#define BOARD_RUMBA 1126 // Rumba
#define BOARD_RUMBA_RAISE3D 1127 // Raise3D N series Rumba derivative
#define BOARD_RL200 1128 // Rapide Lite 200 (v1, low-cost RUMBA clone with drv)
#define BOARD_FORMBOT_TREX2PLUS 1129 // Formbot T-Rex 2 Plus
#define BOARD_FORMBOT_TREX3 1130 // Formbot T-Rex 3
#define BOARD_FORMBOT_RAPTOR 1131 // Formbot Raptor
#define BOARD_FORMBOT_RAPTOR2 1132 // Formbot Raptor 2
#define BOARD_BQ_ZUM_MEGA_3D 1133 // bq ZUM Mega 3D
#define BOARD_MAKEBOARD_MINI 1134 // MakeBoard Mini v2.1.2 by MicroMake
#define BOARD_TRIGORILLA_13 1135 // TriGorilla Anycubic version 1.3-based on RAMPS EFB
#define BOARD_TRIGORILLA_14 1136 // ... Ver 1.4
#define BOARD_TRIGORILLA_14_11 1137 // ... Rev 1.1 (new servo pin order)
#define BOARD_RAMPS_ENDER_4 1138 // Creality: Ender-4, CR-8
#define BOARD_RAMPS_CREALITY 1139 // Creality: CR10S, CR20, CR-X
#define BOARD_DAGOMA_F5 1140 // Dagoma F5
#define BOARD_FYSETC_F6_13 1141 // FYSETC F6 1.3
#define BOARD_FYSETC_F6_14 1142 // FYSETC F6 1.4
#define BOARD_DUPLICATOR_I3_PLUS 1143 // Wanhao Duplicator i3 Plus
#define BOARD_VORON 1144 // VORON Design
#define BOARD_TRONXY_V3_1_0 1145 // Tronxy TRONXY-V3-1.0
#define BOARD_Z_BOLT_X_SERIES 1146 // Z-Bolt X Series
#define BOARD_TT_OSCAR 1147 // TT OSCAR
#define BOARD_OVERLORD 1148 // Overlord/Overlord Pro
#define BOARD_HJC2560C_REV1 1149 // ADIMLab Gantry v1
#define BOARD_HJC2560C_REV2 1150 // ADIMLab Gantry v2
#define BOARD_TANGO 1151 // BIQU Tango V1
#define BOARD_MKS_GEN_L_V2 1152 // MKS GEN L V2
#define BOARD_MKS_GEN_L_V21 1153 // MKS GEN L V2.1
#define BOARD_COPYMASTER_3D 1154 // Copymaster 3D
#define BOARD_ORTUR_4 1155 // Ortur 4
#define BOARD_TENLOG_D3_HERO 1156 // Tenlog D3 Hero IDEX printer
#define BOARD_RAMPS_S_12_EEFB 1157 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Fan, Bed)
#define BOARD_RAMPS_S_12_EEEB 1158 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend0, Hotend1, Hotend2, Bed)
#define BOARD_RAMPS_S_12_EFFB 1159 // Ramps S 1.2 by Sakul.cz (Power outputs: Hotend, Fan0, Fan1, Bed)
#define BOARD_LONGER3D_LK1_PRO 1160 // Longer LK1 PRO / Alfawise U20 Pro (PRO version)
#define BOARD_LONGER3D_LKx_PRO 1161 // Longer LKx PRO / Alfawise Uxx Pro (PRO version)
// PATCH START: Knutwurst
#define BOARD_TRIGORILLA_CHIRON 1162 // TriGorilla Anycubic version 1.4 based on RAMPS EFB for Chiron
// PATCH END: Knutwurst
//
// RAMBo and derivatives
@@ -135,17 +148,22 @@
#define BOARD_ELEFU_3 1311 // Elefu Ra Board (v3)
#define BOARD_LEAPFROG 1312 // Leapfrog
#define BOARD_MEGACONTROLLER 1313 // Mega controller
#define BOARD_GT2560_REV_A 1314 // Geeetech GT2560 Rev. A
#define BOARD_GT2560_REV_A_PLUS 1315 // Geeetech GT2560 Rev. A+ (with auto level probe)
#define BOARD_GT2560_V3 1316 // Geeetech GT2560 Rev B for A10(M/D)
#define BOARD_GT2560_V3_MC2 1317 // Geeetech GT2560 Rev B for Mecreator2
#define BOARD_GT2560_V3_A20 1318 // Geeetech GT2560 Rev B for A20(M/D)
#define BOARD_EINSTART_S 1319 // Einstart retrofit
#define BOARD_WANHAO_ONEPLUS 1320 // Wanhao 0ne+ i3 Mini
#define BOARD_LEAPFROG_XEED2015 1321 // Leapfrog Xeed 2015
#define BOARD_PICA_REVB 1322 // PICA Shield (original version)
#define BOARD_PICA 1323 // PICA Shield (rev C or later)
#define BOARD_INTAMSYS40 1324 // Intamsys 4.0 (Funmat HT)
#define BOARD_GT2560_REV_A 1314 // Geeetech GT2560 Rev A
#define BOARD_GT2560_REV_A_PLUS 1315 // Geeetech GT2560 Rev A+ (with auto level probe)
#define BOARD_GT2560_REV_B 1316 // Geeetech GT2560 Rev B
#define BOARD_GT2560_V3 1317 // Geeetech GT2560 Rev B for A10(M/T/D)
#define BOARD_GT2560_V4 1318 // Geeetech GT2560 Rev B for A10(M/T/D)
#define BOARD_GT2560_V3_MC2 1319 // Geeetech GT2560 Rev B for Mecreator2
#define BOARD_GT2560_V3_A20 1320 // Geeetech GT2560 Rev B for A20(M/T/D)
#define BOARD_EINSTART_S 1321 // Einstart retrofit
#define BOARD_WANHAO_ONEPLUS 1322 // Wanhao 0ne+ i3 Mini
#define BOARD_LEAPFROG_XEED2015 1323 // Leapfrog Xeed 2015
#define BOARD_PICA_REVB 1324 // PICA Shield (original version)
#define BOARD_PICA 1325 // PICA Shield (rev C or later)
#define BOARD_INTAMSYS40 1326 // Intamsys 4.0 (Funmat HT)
#define BOARD_MALYAN_M180 1327 // Malyan M180 Mainboard Version 2 (no display function, direct gcode only)
#define BOARD_GT2560_V4_A20 1328 // Geeetech GT2560 Rev B for A20(M/T/D)
#define BOARD_PROTONEER_CNC_SHIELD_V3 1329 // Mega controller & Protoneer CNC Shield V3.00
//
// ATmega1281, ATmega2561
@@ -161,13 +179,15 @@
#define BOARD_SANGUINOLOLU_11 1500 // Sanguinololu < 1.2
#define BOARD_SANGUINOLOLU_12 1501 // Sanguinololu 1.2 and above
#define BOARD_MELZI 1502 // Melzi
#define BOARD_MELZI_MAKR3D 1503 // Melzi with ATmega1284 (MaKr3d version)
#define BOARD_MELZI_CREALITY 1504 // Melzi Creality3D board (for CR-10 etc)
#define BOARD_MELZI_MALYAN 1505 // Melzi Malyan M150 board
#define BOARD_MELZI_TRONXY 1506 // Tronxy X5S
#define BOARD_STB_11 1507 // STB V1.1
#define BOARD_AZTEEG_X1 1508 // Azteeg X1
#define BOARD_ANET_10 1509 // Anet 1.0 (Melzi clone)
#define BOARD_MELZI_V2 1503 // Melzi V2
#define BOARD_MELZI_MAKR3D 1504 // Melzi with ATmega1284 (MaKr3d version)
#define BOARD_MELZI_CREALITY 1505 // Melzi Creality3D (for CR-10 etc)
#define BOARD_MELZI_MALYAN 1506 // Melzi Malyan M150
#define BOARD_MELZI_TRONXY 1507 // Tronxy X5S
#define BOARD_STB_11 1508 // STB V1.1
#define BOARD_AZTEEG_X1 1509 // Azteeg X1
#define BOARD_ANET_10 1510 // Anet 1.0 (Melzi clone)
#define BOARD_ZMIB_V2 1511 // ZoneStar ZMIB V2
//
// Other ATmega644P, ATmega644, ATmega1284P
@@ -177,12 +197,12 @@
#define BOARD_GEN3_PLUS 1601 // Gen3+
#define BOARD_GEN6 1602 // Gen6
#define BOARD_GEN6_DELUXE 1603 // Gen6 deluxe
#define BOARD_GEN7_CUSTOM 1604 // Gen7 custom (Alfons3 Version) "https://github.com/Alfons3/Generation_7_Electronics"
#define BOARD_GEN7_CUSTOM 1604 // Gen7 custom (Alfons3 Version) https://github.com/Alfons3/Generation_7_Electronics
#define BOARD_GEN7_12 1605 // Gen7 v1.1, v1.2
#define BOARD_GEN7_13 1606 // Gen7 v1.3
#define BOARD_GEN7_14 1607 // Gen7 v1.4
#define BOARD_OMCA_A 1608 // Alpha OMCA board
#define BOARD_OMCA 1609 // Final OMCA board
#define BOARD_OMCA_A 1608 // Alpha OMCA
#define BOARD_OMCA 1609 // Final OMCA
#define BOARD_SETHI 1610 // Sethi 3D_1
//
@@ -213,7 +233,7 @@
#define BOARD_SELENA_COMPACT 2008 // Selena Compact (Power outputs: Hotend0, Hotend1, Bed0, Bed1, Fan0, Fan1)
#define BOARD_BIQU_B300_V1_0 2009 // BIQU B300_V1.0 (Power outputs: Hotend0, Fan, Bed, SPI Driver)
#define BOARD_MKS_SGEN_L 2010 // MKS-SGen-L (Power outputs: Hotend0, Hotend1, Bed, Fan)
#define BOARD_GMARSH_X6_REV1 2011 // GMARSH X6 board, revision 1 prototype
#define BOARD_GMARSH_X6_REV1 2011 // GMARSH X6, revision 1 prototype
#define BOARD_BTT_SKR_V1_1 2012 // BigTreeTech SKR v1.1 (Power outputs: Hotend0, Hotend1, Fan, Bed)
#define BOARD_BTT_SKR_V1_3 2013 // BigTreeTech SKR v1.3 (Power outputs: Hotend0, Hotend1, Fan, Bed)
#define BOARD_BTT_SKR_V1_4 2014 // BigTreeTech SKR v1.4 (Power outputs: Hotend0, Hotend1, Fan, Bed)
@@ -231,6 +251,9 @@
#define BOARD_SMOOTHIEBOARD 2506 // Smoothieboard
#define BOARD_TH3D_EZBOARD 2507 // TH3D EZBoard v1.0
#define BOARD_BTT_SKR_V1_4_TURBO 2508 // BigTreeTech SKR v1.4 TURBO (Power outputs: Hotend0, Hotend1, Fan, Bed)
#define BOARD_MKS_SGEN_L_V2 2509 // MKS SGEN_L V2 (Power outputs: Hotend0, Hotend1, Bed, Fan)
#define BOARD_BTT_SKR_E3_TURBO 2510 // BigTreeTech SKR E3 Turbo (Power outputs: Hotend0, Hotend1, Bed, Fan0, Fan1)
#define BOARD_FLY_CDY 2511 // FLYmaker FLY CDY (Power outputs: Hotend0, Hotend1, Hotend2, Bed, Fan0, Fan1, Fan2)
//
// SAM3X8E ARM Cortex M3
@@ -263,6 +286,7 @@
#define BOARD_ARCHIM2 3024 // UltiMachine Archim2 (with TMC2130 drivers)
#define BOARD_ALLIGATOR 3025 // Alligator Board R2
#define BOARD_CNCONTROLS_15D 3026 // Cartesio CN Controls V15 on DUE
#define BOARD_KRATOS32 3027 // K.3D Kratos32 (Arduino Due Shield)
//
// SAM3X8C ARM Cortex M3
@@ -275,30 +299,64 @@
// STM32 ARM Cortex-M3
//
#define BOARD_STM32F103RE 4000 // STM32F103RE Libmaple-based STM32F1 controller
#define BOARD_MALYAN_M200 4001 // STM32C8T6 Libmaple-based STM32F1 controller
#define BOARD_STM3R_MINI 4002 // STM32F103RE Libmaple-based STM32F1 controller
#define BOARD_GTM32_PRO_VB 4003 // STM32F103VET6 controller
#define BOARD_MORPHEUS 4004 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller
#define BOARD_CHITU3D 4005 // Chitu3D (STM32F103RET6)
#define BOARD_MKS_ROBIN 4006 // MKS Robin (STM32F103ZET6)
#define BOARD_MKS_ROBIN_MINI 4007 // MKS Robin Mini (STM32F103VET6)
#define BOARD_MKS_ROBIN_NANO 4008 // MKS Robin Nano (STM32F103VET6)
#define BOARD_MKS_ROBIN_LITE 4009 // MKS Robin Lite/Lite2 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_LITE3 4010 // MKS Robin Lite3 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_PRO 4011 // MKS Robin Pro (STM32F103ZET6)
#define BOARD_BTT_SKR_MINI_V1_1 4012 // BigTreeTech SKR Mini v1.1 (STM32F103RC)
#define BOARD_BTT_SKR_MINI_E3_V1_0 4013 // BigTreeTech SKR Mini E3 (STM32F103RC)
#define BOARD_BTT_SKR_MINI_E3_V1_2 4014 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC)
#define BOARD_BTT_SKR_E3_DIP 4015 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE)
#define BOARD_JGAURORA_A5S_A1 4016 // JGAurora A5S A1 (STM32F103ZET6)
#define BOARD_FYSETC_AIO_II 4017 // FYSETC AIO_II
#define BOARD_FYSETC_CHEETAH 4018 // FYSETC Cheetah
#define BOARD_FYSETC_CHEETAH_V12 4019 // FYSETC Cheetah V1.2
#define BOARD_LONGER3D_LK 4020 // Alfawise U20/U20+/U30 (Longer3D LK1/2) / STM32F103VET6
#define BOARD_GTM32_MINI 4021 // STM32F103VET6 controller
#define BOARD_GTM32_MINI_A30 4022 // STM32F103VET6 controller
#define BOARD_GTM32_REV_B 4023 // STM32F103VET6 controller
#define BOARD_MALYAN_M200_V2 4000 // STM32F070CB controller
#define BOARD_MALYAN_M300 4001 // STM32F070-based delta
#define BOARD_STM32F103RE 4002 // STM32F103RE Libmaple-based STM32F1 controller
#define BOARD_MALYAN_M200 4003 // STM32C8T6 Libmaple-based STM32F1 controller
#define BOARD_STM3R_MINI 4004 // STM32F103RE Libmaple-based STM32F1 controller
#define BOARD_GTM32_PRO_VB 4005 // STM32F103VET6 controller
#define BOARD_GTM32_MINI 4006 // STM32F103VET6 controller
#define BOARD_GTM32_MINI_A30 4007 // STM32F103VET6 controller
#define BOARD_GTM32_REV_B 4008 // STM32F103VET6 controller
#define BOARD_MORPHEUS 4009 // STM32F103C8 / STM32F103CB Libmaple-based STM32F1 controller
#define BOARD_CHITU3D 4010 // Chitu3D (STM32F103RET6)
#define BOARD_MKS_ROBIN 4011 // MKS Robin (STM32F103ZET6)
#define BOARD_MKS_ROBIN_MINI 4012 // MKS Robin Mini (STM32F103VET6)
#define BOARD_MKS_ROBIN_NANO 4013 // MKS Robin Nano (STM32F103VET6)
#define BOARD_MKS_ROBIN_NANO_V2 4014 // MKS Robin Nano V2 (STM32F103VET6)
#define BOARD_MKS_ROBIN_LITE 4015 // MKS Robin Lite/Lite2 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_LITE3 4016 // MKS Robin Lite3 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_PRO 4017 // MKS Robin Pro (STM32F103ZET6)
#define BOARD_MKS_ROBIN_E3 4018 // MKS Robin E3 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_E3_V1_1 4019 // MKS Robin E3 V1.1 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_E3D 4020 // MKS Robin E3D (STM32F103RCT6)
#define BOARD_MKS_ROBIN_E3D_V1_1 4021 // MKS Robin E3D V1.1 (STM32F103RCT6)
#define BOARD_MKS_ROBIN_E3P 4022 // MKS Robin E3p (STM32F103VET6)
#define BOARD_BTT_SKR_MINI_V1_1 4023 // BigTreeTech SKR Mini v1.1 (STM32F103RC)
#define BOARD_BTT_SKR_MINI_E3_V1_0 4024 // BigTreeTech SKR Mini E3 (STM32F103RC)
#define BOARD_BTT_SKR_MINI_E3_V1_2 4025 // BigTreeTech SKR Mini E3 V1.2 (STM32F103RC)
#define BOARD_BTT_SKR_MINI_E3_V2_0 4026 // BigTreeTech SKR Mini E3 V2.0 (STM32F103RC / STM32F103RE)
#define BOARD_BTT_SKR_MINI_MZ_V1_0 4027 // BigTreeTech SKR Mini MZ V1.0 (STM32F103RC)
#define BOARD_BTT_SKR_E3_DIP 4028 // BigTreeTech SKR E3 DIP V1.0 (STM32F103RC / STM32F103RE)
#define BOARD_BTT_SKR_CR6 4029 // BigTreeTech SKR CR6 v1.0 (STM32F103RE)
#define BOARD_JGAURORA_A5S_A1 4030 // JGAurora A5S A1 (STM32F103ZET6)
#define BOARD_FYSETC_AIO_II 4031 // FYSETC AIO_II
#define BOARD_FYSETC_CHEETAH 4032 // FYSETC Cheetah
#define BOARD_FYSETC_CHEETAH_V12 4033 // FYSETC Cheetah V1.2
#define BOARD_LONGER3D_LK 4034 // Alfawise U20/U20+/U30 (Longer3D LK1/2) / STM32F103VET6
#define BOARD_CCROBOT_MEEB_3DP 4035 // ccrobot-online.com MEEB_3DP (STM32F103RC)
#define BOARD_CHITU3D_V5 4036 // Chitu3D TronXY X5SA V5 Board
#define BOARD_CHITU3D_V6 4037 // Chitu3D TronXY X5SA V6 Board
#define BOARD_CHITU3D_V9 4038 // Chitu3D TronXY X5SA V9 Board
#define BOARD_CREALITY_V4 4039 // Creality v4.x (STM32F103RE)
#define BOARD_CREALITY_V427 4040 // Creality v4.2.7 (STM32F103RE)
#define BOARD_CREALITY_V4210 4041 // Creality v4.2.10 (STM32F103RE) as found in the CR-30
#define BOARD_CREALITY_V431 4042 // Creality v4.3.1 (STM32F103RE)
#define BOARD_CREALITY_V431_A 4043 // Creality v4.3.1a (STM32F103RE)
#define BOARD_CREALITY_V431_B 4044 // Creality v4.3.1b (STM32F103RE)
#define BOARD_CREALITY_V431_C 4045 // Creality v4.3.1c (STM32F103RE)
#define BOARD_CREALITY_V431_D 4046 // Creality v4.3.1d (STM32F103RE)
#define BOARD_CREALITY_V452 4047 // Creality v4.5.2 (STM32F103RE)
#define BOARD_CREALITY_V453 4048 // Creality v4.5.3 (STM32F103RE)
#define BOARD_TRIGORILLA_PRO 4049 // Trigorilla Pro (STM32F103ZET6)
#define BOARD_FLY_MINI 4050 // FLYmaker FLY MINI (STM32F103RCT6)
#define BOARD_FLSUN_HISPEED 4051 // FLSUN HiSpeedV1 (STM32F103VET6)
#define BOARD_BEAST 4052 // STM32F103RET6 Libmaple-based controller
#define BOARD_MINGDA_MPX_ARM_MINI 4053 // STM32F103ZET6 Mingda MD-16
#define BOARD_GTM32_PRO_VD 4054 // STM32F103VET6 controller
#define BOARD_ZONESTAR_ZM3E2 4055 // Zonestar ZM3E2 (STM32F103RCT6)
#define BOARD_ZONESTAR_ZM3E4 4056 // Zonestar ZM3E4 V1 (STM32F103VCT6)
#define BOARD_ZONESTAR_ZM3E4V2 4057 // Zonestar ZM3E4 V2 (STM32F103VCT6)
//
// ARM Cortex-M4F
@@ -311,44 +369,74 @@
// STM32 ARM Cortex-M4F
//
#define BOARD_BEAST 4200 // STM32F4xxVxT6 Libmaple-based STM32F4 controller
#define BOARD_GENERIC_STM32F4 4201 // STM32 STM32GENERIC-based STM32F4 controller
#define BOARD_ARMED 4202 // Arm'ed STM32F4-based controller
#define BOARD_RUMBA32_AUS3D 4203 // RUMBA32 STM32F446VET6 based controller from Aus3D
#define BOARD_RUMBA32_MKS 4204 // RUMBA32 STM32F446VET6 based controller from Makerbase
#define BOARD_ARMED 4200 // Arm'ed STM32F4-based controller
#define BOARD_RUMBA32_V1_0 4201 // RUMBA32 STM32F446VET6 based controller from Aus3D
#define BOARD_RUMBA32_V1_1 4202 // RUMBA32 STM32F446VET6 based controller from Aus3D
#define BOARD_RUMBA32_MKS 4203 // RUMBA32 STM32F446VET6 based controller from Makerbase
#define BOARD_RUMBA32_BTT 4204 // RUMBA32 STM32F446VET6 based controller from BIGTREETECH
#define BOARD_BLACK_STM32F407VE 4205 // BLACK_STM32F407VE
#define BOARD_BLACK_STM32F407ZE 4206 // BLACK_STM32F407ZE
#define BOARD_STEVAL_3DP001V1 4207 // STEVAL-3DP001V1 3D PRINTER BOARD
#define BOARD_BTT_SKR_PRO_V1_1 4208 // BigTreeTech SKR Pro v1.1 (STM32F407ZG)
#define BOARD_BTT_BTT002_V1_0 4209 // BigTreeTech BTT002 v1.0 (STM32F407VE)
#define BOARD_BTT_GTR_V1_0 4210 // BigTreeTech GTR v1.0 (STM32F407IGT)
#define BOARD_LERDGE_K 4211 // Lerdge K (STM32F407ZG)
#define BOARD_LERDGE_X 4212 // Lerdge X (STM32F407VE)
#define BOARD_VAKE403D 4213 // VAkE 403D (STM32F446VET6)
#define BOARD_FYSETC_S6 4214 // FYSETC S6 board
#define BOARD_FLYF407ZG 4215 // FLYF407ZG board (STM32F407ZG)
#define BOARD_MKS_ROBIN2 4216 // MKS_ROBIN2 (STM32F407ZE)
#define BOARD_BTT_SKR_PRO_V1_1 4208 // BigTreeTech SKR Pro v1.1 (STM32F407ZGT6)
#define BOARD_BTT_SKR_PRO_V1_2 4209 // BigTreeTech SKR Pro v1.2 (STM32F407ZGT6)
#define BOARD_BTT_BTT002_V1_0 4210 // BigTreeTech BTT002 v1.0 (STM32F407VGT6)
#define BOARD_BTT_E3_RRF 4211 // BigTreeTech E3 RRF (STM32F407VGT6)
#define BOARD_BTT_SKR_V2_0_REV_A 4212 // BigTreeTech SKR v2.0 Rev A (STM32F407VGT6)
#define BOARD_BTT_SKR_V2_0_REV_B 4213 // BigTreeTech SKR v2.0 Rev B (STM32F407VGT6)
#define BOARD_BTT_GTR_V1_0 4214 // BigTreeTech GTR v1.0 (STM32F407IGT)
#define BOARD_BTT_OCTOPUS_V1_0 4215 // BigTreeTech Octopus v1.0 (STM32F446ZET6)
#define BOARD_BTT_OCTOPUS_V1_1 4216 // BigTreeTech Octopus v1.1 (STM32F446ZET6)
#define BOARD_LERDGE_K 4217 // Lerdge K (STM32F407ZG)
#define BOARD_LERDGE_S 4218 // Lerdge S (STM32F407VE)
#define BOARD_LERDGE_X 4219 // Lerdge X (STM32F407VE)
#define BOARD_VAKE403D 4220 // VAkE 403D (STM32F446VET6)
#define BOARD_FYSETC_S6 4221 // FYSETC S6 (STM32F446VET6)
#define BOARD_FYSETC_S6_V2_0 4222 // FYSETC S6 v2.0 (STM32F446VET6)
#define BOARD_FYSETC_SPIDER 4223 // FYSETC Spider (STM32F446VET6)
#define BOARD_FLYF407ZG 4224 // FLYmaker FLYF407ZG (STM32F407ZG)
#define BOARD_MKS_ROBIN2 4225 // MKS_ROBIN2 (STM32F407ZE)
#define BOARD_MKS_ROBIN_PRO_V2 4226 // MKS Robin Pro V2 (STM32F407VE)
#define BOARD_MKS_ROBIN_NANO_V3 4227 // MKS Robin Nano V3 (STM32F407VG)
#define BOARD_MKS_MONSTER8 4228 // MKS Monster8 (STM32F407VGT6)
#define BOARD_ANET_ET4 4229 // ANET ET4 V1.x (STM32F407VGT6)
#define BOARD_ANET_ET4P 4230 // ANET ET4P V1.x (STM32F407VGT6)
#define BOARD_FYSETC_CHEETAH_V20 4231 // FYSETC Cheetah V2.0
#define BOARD_TH3D_EZBOARD_LITE_V2 4232 // TH3D EZBoard Lite v2.0
#define BOARD_INDEX_REV03 4233 // Index PnP Controller REV03 (STM32F407VET6/VGT6)
#define BOARD_MKS_ROBIN_NANO_V1_3_F4 4234 // MKS Robin Nano V1.3 and MKS Robin Nano-S V1.3 (STM32F407VET6)
//
// ARM Cortex M7
//
#define BOARD_THE_BORG 5000 // THE-BORG (Power outputs: Hotend0, Hotend1, Bed, Fan)
#define BOARD_REMRAM_V1 5001 // RemRam v1
#define BOARD_REMRAM_V1 5000 // RemRam v1
#define BOARD_TEENSY41 5001 // Teensy 4.1
#define BOARD_T41U5XBB 5002 // T41U5XBB Teensy 4.1 breakout board
#define BOARD_NUCLEO_F767ZI 5003 // ST NUCLEO-F767ZI Dev Board
#define BOARD_BTT_SKR_SE_BX 5004 // BigTreeTech SKR SE BX (STM32H743II)
//
// Espressif ESP32 WiFi
//
#define BOARD_ESPRESSIF_ESP32 6000 // Generic ESP32
#define BOARD_MRR_ESPA 6001 // MRR ESPA board based on ESP32 (native pins only)
#define BOARD_MRR_ESPE 6002 // MRR ESPE board based on ESP32 (with I2S stepper stream)
#define BOARD_MRR_ESPA 6001 // MRR ESPA based on ESP32 (native pins only)
#define BOARD_MRR_ESPE 6002 // MRR ESPE based on ESP32 (with I2S stepper stream)
#define BOARD_E4D_BOX 6003 // E4d@BOX
#define BOARD_FYSETC_E4 6004 // FYSETC E4
//
// SAMD51 ARM Cortex M4
//
#define BOARD_AGCM4_RAMPS_144 6100 // RAMPS 1.4.4
//
// Custom board
//
#define BOARD_CUSTOM 9998 // Custom pins definition for development and/or rare boards
//
// Simulations
//
@@ -357,5 +445,3 @@
#define _MB_1(B) (defined(BOARD_##B) && MOTHERBOARD==BOARD_##B)
#define MB(V...) DO(MB,||,V)
#define IS_MELZI MB(MELZI, MELZI_CREALITY, MELZI_MAKR3D, MELZI_MALYAN, MELZI_TRONXY)

39
Marlin/src/core/bug_on.h Normal file
View File

@@ -0,0 +1,39 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Copyright (c) 2021 X-Ryl669 [https://blog.cyril.by]
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
// We need SERIAL_ECHOPGM and macros.h
#include "serial.h"
#if ENABLED(POSTMORTEM_DEBUGGING)
// Useful macro for stopping the CPU on an unexpected condition
// This is used like SERIAL_ECHOPGM, that is: a key-value call of the local variables you want
// to dump to the serial port before stopping the CPU.
// \/ Don't replace by SERIAL_ECHOPGM since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building
#define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": "); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); *(char*)0 = 42; } while(0)
#elif ENABLED(MARLIN_DEV_MODE)
// Don't stop the CPU here, but at least dump the bug on the serial port
// \/ Don't replace by SERIAL_ECHOPGM since ONLY_FILENAME cannot be transformed to a PGM string on Arduino and it breaks building
#define BUG_ON(V...) do { SERIAL_ECHO(ONLY_FILENAME); SERIAL_ECHO(__LINE__); SERIAL_ECHOLNPGM(": BUG!"); SERIAL_ECHOLNPGM(V); SERIAL_FLUSHTX(); } while(0)
#else
// Release mode, let's ignore the bug
#define BUG_ON(V...) NOOP
#endif

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -26,78 +26,89 @@
// (or not) in a given .cpp file
//
#undef DEBUG_PRINT_P
#undef DEBUG_SECTION
#undef DEBUG_ECHO_START
#undef DEBUG_ERROR_START
#undef DEBUG_CHAR
#undef DEBUG_ECHO
#undef DEBUG_DECIMAL
#undef DEBUG_ECHO_F
#undef DEBUG_ECHOLN
#undef DEBUG_ECHOPGM
#undef DEBUG_ECHOLNPGM
#undef DEBUG_ECHOPAIR
#undef DEBUG_ECHOPAIR_P
#undef DEBUG_ECHOPGM_P
#undef DEBUG_ECHOLNPGM_P
#undef DEBUG_ECHOPAIR_F
#undef DEBUG_ECHOPAIR_F_P
#undef DEBUG_ECHOLNPAIR
#undef DEBUG_ECHOLNPAIR_P
#undef DEBUG_ECHOLNPAIR_F
#undef DEBUG_ECHOLNPAIR_F_P
#undef DEBUG_ECHO_MSG
#undef DEBUG_ERROR_MSG
#undef DEBUG_EOL
#undef DEBUG_FLUSH
#undef DEBUG_POS
#undef DEBUG_XYZ
#undef DEBUG_DELAY
#undef DEBUG_SYNCHRONIZE
#if DEBUG_OUT
#define DEBUG_PRINT_P(P) serialprintPGM(P)
#include "debug_section.h"
#define DEBUG_SECTION(N,S,D) SectionLog N(PSTR(S),D)
#define DEBUG_ECHO_START SERIAL_ECHO_START
#define DEBUG_ERROR_START SERIAL_ERROR_START
#define DEBUG_CHAR SERIAL_CHAR
#define DEBUG_ECHO SERIAL_ECHO
#define DEBUG_DECIMAL SERIAL_DECIMAL
#define DEBUG_ECHO_F SERIAL_ECHO_F
#define DEBUG_ECHOLN SERIAL_ECHOLN
#define DEBUG_ECHOPGM SERIAL_ECHOPGM
#define DEBUG_ECHOLNPGM SERIAL_ECHOLNPGM
#define DEBUG_ECHOPAIR SERIAL_ECHOPAIR
#define DEBUG_ECHOPAIR_P SERIAL_ECHOPAIR_P
#define DEBUG_ECHOPGM SERIAL_ECHOPGM
#define DEBUG_ECHOPGM_P SERIAL_ECHOPGM_P
#define DEBUG_ECHOPAIR_F SERIAL_ECHOPAIR_F
#define DEBUG_ECHOPAIR_F_P SERIAL_ECHOPAIR_F_P
#define DEBUG_ECHOLNPAIR SERIAL_ECHOLNPAIR
#define DEBUG_ECHOLNPAIR_P SERIAL_ECHOLNPAIR_P
#define DEBUG_ECHOLNPGM SERIAL_ECHOLNPGM
#define DEBUG_ECHOLNPGM_P SERIAL_ECHOLNPGM_P
#define DEBUG_ECHOLNPAIR_F SERIAL_ECHOLNPAIR_F
#define DEBUG_ECHOLNPAIR_F_P SERIAL_ECHOLNPAIR_F_P
#define DEBUG_ECHO_MSG SERIAL_ECHO_MSG
#define DEBUG_ERROR_MSG SERIAL_ERROR_MSG
#define DEBUG_EOL SERIAL_EOL
#define DEBUG_FLUSH SERIAL_FLUSH
#define DEBUG_POS SERIAL_POS
#define DEBUG_XYZ SERIAL_XYZ
#define DEBUG_DELAY(ms) serial_delay(ms)
#define DEBUG_SYNCHRONIZE() planner.synchronize()
#else
#define DEBUG_PRINT_P(P) NOOP
#define DEBUG_SECTION(...) NOOP
#define DEBUG_ECHO_START() NOOP
#define DEBUG_ERROR_START() NOOP
#define DEBUG_CHAR(...) NOOP
#define DEBUG_ECHO(...) NOOP
#define DEBUG_DECIMAL(...) NOOP
#define DEBUG_ECHO_F(...) NOOP
#define DEBUG_ECHOLN(...) NOOP
#define DEBUG_ECHOPGM(...) NOOP
#define DEBUG_ECHOLNPGM(...) NOOP
#define DEBUG_ECHOPAIR(...) NOOP
#define DEBUG_ECHOPAIR_P(...) NOOP
#define DEBUG_ECHOPGM_P(...) NOOP
#define DEBUG_ECHOLNPGM_P(...) NOOP
#define DEBUG_ECHOPAIR_F(...) NOOP
#define DEBUG_ECHOPAIR_F_P(...) NOOP
#define DEBUG_ECHOLNPAIR(...) NOOP
#define DEBUG_ECHOLNPAIR_P(...) NOOP
#define DEBUG_ECHOLNPAIR_F(...) NOOP
#define DEBUG_ECHOLNPAIR_F_P(...) NOOP
#define DEBUG_ECHO_MSG(...) NOOP
#define DEBUG_ERROR_MSG(...) NOOP
#define DEBUG_EOL() NOOP
#define DEBUG_FLUSH() NOOP
#define DEBUG_POS(...) NOOP
#define DEBUG_XYZ(...) NOOP
#define DEBUG_DELAY(...) NOOP
#define DEBUG_SYNCHRONIZE() NOOP
#endif
#undef DEBUG_OUT

View File

@@ -0,0 +1,49 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "serial.h"
#include "../module/motion.h"
class SectionLog {
public:
SectionLog(PGM_P const msg=nullptr, bool inbug=true) {
the_msg = msg;
if ((debug = inbug)) echo_msg(PSTR(">>>"));
}
~SectionLog() { if (debug) echo_msg(PSTR("<<<")); }
private:
PGM_P the_msg;
bool debug;
void echo_msg(PGM_P const pre) {
SERIAL_ECHOPGM_P(pre);
if (the_msg) {
SERIAL_CHAR(' ');
SERIAL_ECHOPGM_P(the_msg);
}
SERIAL_CHAR(' ');
print_pos(current_position);
}
};

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -60,6 +60,9 @@
#define AXIS_DRIVER_TYPE_X(T) _AXIS_DRIVER_TYPE(X,T)
#define AXIS_DRIVER_TYPE_Y(T) _AXIS_DRIVER_TYPE(Y,T)
#define AXIS_DRIVER_TYPE_Z(T) _AXIS_DRIVER_TYPE(Z,T)
#define AXIS_DRIVER_TYPE_I(T) _AXIS_DRIVER_TYPE(I,T)
#define AXIS_DRIVER_TYPE_J(T) _AXIS_DRIVER_TYPE(J,T)
#define AXIS_DRIVER_TYPE_K(T) _AXIS_DRIVER_TYPE(K,T)
#define AXIS_DRIVER_TYPE_X2(T) (EITHER(X_DUAL_STEPPER_DRIVERS, DUAL_X_CARRIAGE) && _AXIS_DRIVER_TYPE(X2,T))
#define AXIS_DRIVER_TYPE_Y2(T) (ENABLED(Y_DUAL_STEPPER_DRIVERS) && _AXIS_DRIVER_TYPE(Y2,T))
@@ -83,9 +86,14 @@
#define HAS_E_DRIVER(T) (0 RREPEAT2(E_STEPPERS, _OR_ADTE, T))
#define HAS_DRIVER(T) ( AXIS_DRIVER_TYPE_X(T) || AXIS_DRIVER_TYPE_Y(T) || AXIS_DRIVER_TYPE_Z(T) \
|| AXIS_DRIVER_TYPE_I(T) || AXIS_DRIVER_TYPE_J(T) || AXIS_DRIVER_TYPE_K(T) \
|| AXIS_DRIVER_TYPE_X2(T) || AXIS_DRIVER_TYPE_Y2(T) || AXIS_DRIVER_TYPE_Z2(T) \
|| AXIS_DRIVER_TYPE_Z3(T) || AXIS_DRIVER_TYPE_Z4(T) || HAS_E_DRIVER(T) )
//
// Trinamic Stepper Drivers
//
// Test for supported TMC drivers that require advanced configuration
// Does not match standalone configurations
#if ( HAS_DRIVER(TMC2130) || HAS_DRIVER(TMC2160) \
@@ -127,6 +135,7 @@
#define AXIS_HAS_RXTX AXIS_HAS_UART
#define AXIS_HAS_HW_SERIAL(A) ( AXIS_HAS_UART(A) && defined(A##_HARDWARE_SERIAL) )
#define AXIS_HAS_SW_SERIAL(A) ( AXIS_HAS_UART(A) && !defined(A##_HARDWARE_SERIAL) )
#define AXIS_HAS_STALLGUARD(A) ( AXIS_DRIVER_TYPE(A,TMC2130) || AXIS_DRIVER_TYPE(A,TMC2160) \
@@ -148,9 +157,11 @@
#define _OR_EAH(N,T) || AXIS_HAS_##T(E##N)
#define E_AXIS_HAS(T) (0 _OR_EAH(0,T) _OR_EAH(1,T) _OR_EAH(2,T) _OR_EAH(3,T) _OR_EAH(4,T) _OR_EAH(5,T) _OR_EAH(6,T) _OR_EAH(7,T))
#define ANY_AXIS_HAS(T) ( AXIS_HAS_##T(X) || AXIS_HAS_##T(Y) || AXIS_HAS_##T(Z) \
|| AXIS_HAS_##T(X2) || AXIS_HAS_##T(Y2) || AXIS_HAS_##T(Z2) \
|| AXIS_HAS_##T(Z3) || AXIS_HAS_##T(Z4) || E_AXIS_HAS(T) )
#define ANY_AXIS_HAS(T) ( AXIS_HAS_##T(X) || AXIS_HAS_##T(X2) \
|| AXIS_HAS_##T(Y) || AXIS_HAS_##T(Y2) \
|| AXIS_HAS_##T(Z) || AXIS_HAS_##T(Z2) || AXIS_HAS_##T(Z3) || AXIS_HAS_##T(Z4) \
|| AXIS_HAS_##T(I) || AXIS_HAS_##T(J) || AXIS_HAS_##T(K) \
|| E_AXIS_HAS(T) )
#if ANY_AXIS_HAS(STEALTHCHOP)
#define HAS_STEALTHCHOP 1
@@ -171,17 +182,16 @@
#define HAS_TMC_SPI 1
#endif
// Defines that can't be evaluated now
#define HAS_TMC_SW_SERIAL ANY_AXIS_HAS(SW_SERIAL)
//
// TMC26XX Stepper Drivers
//
#if HAS_DRIVER(TMC26X)
#define HAS_TMC26X 1
#endif
//
// Stretching 'drivers.h' to include LPC/SAMD51 SD options
// L64XX Stepper Drivers
//
#define _SDCARD_LCD 1
#define _SDCARD_ONBOARD 2
#define _SDCARD_CUSTOM_CABLE 3
#define _SDCARD_ID(V) _CAT(_SDCARD_, V)
#define SD_CONNECTION_IS(V) (_SDCARD_ID(SDCARD_CONNECTION) == _SDCARD_ID(V))
#if HAS_DRIVER(L6470) || HAS_DRIVER(L6474) || HAS_DRIVER(L6480) || HAS_DRIVER(POWERSTEP01)
#define HAS_L64XX 1

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -39,7 +39,7 @@
//
// ==> ALWAYS TRY TO COMPILE MARLIN WITH/WITHOUT "ULTIPANEL" / "ULTRA_LCD" / "SDSUPPORT" #define IN "Configuration.h"
// ==> ALSO TRY ALL AVAILABLE LANGUAGE OPTIONS
// See also http://marlinfw.org/docs/development/lcd_language.html
// See also https://marlinfw.org/docs/development/lcd_language.html
// Languages
// an Aragonese
@@ -48,8 +48,8 @@
// cz Czech
// da Danish
// de German
// el Greek
// el_gr Greek (Greece)
// el Greek (Greece)
// el_CY Greek (Cyprus)
// en English
// es Spanish
// eu Basque-Euskera
@@ -57,6 +57,7 @@
// fr French
// gl Galician
// hr Croatian
// hu Hungarian
// it Italian
// jp_kana Japanese
// ko_KR Korean (South Korea)
@@ -64,8 +65,10 @@
// pl Polish
// pt Portuguese
// pt_br Portuguese (Brazilian)
// ro Romanian
// ru Russian
// sk Slovak
// sv Swedish
// tr Turkish
// uk Ukrainian
// vi Vietnamese
@@ -80,18 +83,16 @@
#ifdef CUSTOM_MACHINE_NAME
#undef MACHINE_NAME
#define MACHINE_NAME CUSTOM_MACHINE_NAME
#else
#ifdef DEFAULT_MACHINE_NAME
#undef MACHINE_NAME
#define MACHINE_NAME DEFAULT_MACHINE_NAME
#endif
#elif defined(DEFAULT_MACHINE_NAME)
#undef MACHINE_NAME
#define MACHINE_NAME DEFAULT_MACHINE_NAME
#endif
#ifndef MACHINE_UUID
#define MACHINE_UUID DEFAULT_MACHINE_UUID
#endif
#define MARLIN_WEBSITE_URL "http://marlinfw.org"
#define MARLIN_WEBSITE_URL "marlinfw.org"
//#if !defined(STRING_SPLASH_LINE3) && defined(WEBSITE_URL)
// #define STRING_SPLASH_LINE3 WEBSITE_URL
@@ -108,8 +109,6 @@
#define STR_BROWNOUT_RESET " Brown out Reset"
#define STR_WATCHDOG_RESET " Watchdog Reset"
#define STR_SOFTWARE_RESET " Software Reset"
#define STR_AUTHOR " | Author: "
#define STR_CONFIGURATION_VER " Last Updated: "
#define STR_FREE_MEMORY " Free Memory: "
#define STR_PLANNER_BUFFER_BYTES " PlannerBufferBytes: "
#define STR_OK "ok"
@@ -120,19 +119,20 @@
#define STR_ERR_CHECKSUM_MISMATCH "checksum mismatch, Last Line: "
#define STR_ERR_NO_CHECKSUM "No Checksum with line number, Last Line: "
#define STR_FILE_PRINTED "Done printing file"
#define STR_NO_MEDIA "No media"
#define STR_BEGIN_FILE_LIST "Begin file list"
#define STR_END_FILE_LIST "End file list"
#define STR_INVALID_EXTRUDER "Invalid extruder"
#define STR_INVALID_E_STEPPER "Invalid E stepper"
#define STR_E_STEPPER_NOT_SPECIFIED "E stepper not specified"
#define STR_INVALID_SOLENOID "Invalid solenoid"
#define STR_M115_REPORT "FIRMWARE_NAME:Marlin " DETAILED_BUILD_VERSION " KNUTWURST_AI3M_VERSION:" CUSTOM_BUILD_VERSION " DISTRIBUTION_DATE:" STRING_DISTRIBUTION_DATE " SOURCE_CODE_URL:" SOURCE_CODE_URL " PROTOCOL_VERSION:" PROTOCOL_VERSION " MACHINE_TYPE:" MACHINE_NAME " EXTRUDER_COUNT:" STRINGIFY(EXTRUDERS) " UUID:" MACHINE_UUID
#define STR_MARLIN_AI3M "Marlin-AI3M"
#define STR_COUNT_X " Count X:"
#define STR_COUNT_A " Count A:"
#define STR_WATCHDOG_FIRED "Watchdog timeout. Reset required."
#define STR_ERR_KILLED "Printer halted. kill() called!"
#define STR_FLOWMETER_FAULT "Coolant flow fault. Flowmeter safety is active. Attention required."
#define STR_ERR_STOPPED "Printer stopped due to errors. Fix the error and use M999 to restart. (Temperature is reset. Set it after restarting)"
#define STR_ERR_SERIAL_MISMATCH "Serial status mismatch"
#define STR_BUSY_PROCESSING "busy: processing"
#define STR_BUSY_PAUSED_FOR_USER "busy: paused for user"
#define STR_BUSY_PAUSED_FOR_INPUT "busy: paused for input"
@@ -140,31 +140,14 @@
#define STR_RESEND "Resend: "
#define STR_UNKNOWN_COMMAND "Unknown command: \""
#define STR_ACTIVE_EXTRUDER "Active Extruder: "
#define STR_X_MIN "x_min"
#define STR_X_MAX "x_max"
#define STR_X2_MIN "x2_min"
#define STR_X2_MAX "x2_max"
#define STR_Y_MIN "y_min"
#define STR_Y_MAX "y_max"
#define STR_Y2_MIN "y2_min"
#define STR_Y2_MAX "y2_max"
#define STR_Z_MIN "z_min"
#define STR_Z_MAX "z_max"
#define STR_Z2_MIN "z2_min"
#define STR_Z2_MAX "z2_max"
#define STR_Z3_MIN "z3_min"
#define STR_Z3_MAX "z3_max"
#define STR_Z4_MIN "z4_min"
#define STR_Z4_MAX "z4_max"
#define STR_Z_PROBE "z_probe"
#define STR_FILAMENT_RUNOUT_SENSOR "filament"
#define STR_PROBE_OFFSET "Probe Offset"
#define STR_SKEW_MIN "min_skew_factor: "
#define STR_SKEW_MAX "max_skew_factor: "
#define STR_ERR_MATERIAL_INDEX "M145 S<index> out of range (0-1)"
#define STR_ERR_M421_PARAMETERS "M421 incorrect parameter usage"
#define STR_ERR_BAD_PLANE_MODE "G5 requires XY plane mode"
#define STR_ERR_MESH_XY "Mesh point cannot be resolved"
#define STR_ERR_MESH_XY "Mesh point out of range"
#define STR_ERR_ARC_ARGS "G2/G3 bad parameters"
#define STR_ERR_PROTECTED_PIN "Protected Pin"
#define STR_ERR_M420_FAILED "Failed to enable Bed Leveling"
@@ -175,18 +158,17 @@
#define STR_OFF "OFF"
#define STR_ENDSTOP_HIT "TRIGGERED"
#define STR_ENDSTOP_OPEN "open"
#define STR_HOTEND_OFFSET "Hotend offsets:"
#define STR_DUPLICATION_MODE "Duplication mode: "
#define STR_SOFT_ENDSTOPS "Soft endstops: "
#define STR_SOFT_MIN " Min: "
#define STR_SOFT_MAX " Max: "
#define STR_SAVED_POS "Position saved"
#define STR_RESTORING_POS "Restoring position"
#define STR_INVALID_POS_SLOT "Invalid slot. Total: "
#define STR_DONE "Done."
#define STR_SD_CANT_OPEN_SUBDIR "Cannot open subdir "
#define STR_SD_INIT_FAIL "SD init fail"
#define STR_SD_INIT_FAIL "No SD card"
#define STR_SD_VOL_INIT_FAIL "volume.init failed"
#define STR_SD_OPENROOT_FAIL "openRoot failed"
#define STR_SD_CARD_OK "SD card ok"
@@ -206,7 +188,6 @@
#define STR_ERR_COLD_EXTRUDE_STOP " cold extrusion prevented"
#define STR_ERR_LONG_EXTRUDE_STOP " too long extrusion prevented"
#define STR_ERR_HOTEND_TOO_COLD "Hotend too cold"
#define STR_ERR_Z_HOMING_SER "Home XY first"
#define STR_ERR_EEPROM_WRITE "Error writing to EEPROM!"
#define STR_FILAMENT_CHANGE_HEAT_LCD "Press button to heat nozzle"
@@ -222,12 +203,10 @@
#define STR_KILL_BUTTON "!! KILL caused by KILL button/pin"
// temperature.cpp strings
#define STR_PID_AUTOTUNE_PREFIX "PID Autotune"
#define STR_PID_AUTOTUNE_START STR_PID_AUTOTUNE_PREFIX " start"
#define STR_PID_AUTOTUNE_FAILED STR_PID_AUTOTUNE_PREFIX " failed!"
#define STR_PID_BAD_EXTRUDER_NUM STR_PID_AUTOTUNE_FAILED " Bad extruder number"
#define STR_PID_TEMP_TOO_HIGH STR_PID_AUTOTUNE_FAILED " Temperature too high"
#define STR_PID_TIMEOUT STR_PID_AUTOTUNE_FAILED " timeout"
#define STR_PID_AUTOTUNE_START "PID Autotune start"
#define STR_PID_BAD_HEATER_ID "PID Autotune failed! Bad heater id"
#define STR_PID_TEMP_TOO_HIGH "PID Autotune failed! Temperature too high"
#define STR_PID_TIMEOUT "PID Autotune failed! timeout"
#define STR_BIAS " bias: "
#define STR_D_COLON " d: "
#define STR_T_MIN " min: "
@@ -238,7 +217,7 @@
#define STR_KP " Kp: "
#define STR_KI " Ki: "
#define STR_KD " Kd: "
#define STR_PID_AUTOTUNE_FINISHED STR_PID_AUTOTUNE_PREFIX " finished! Put the last Kp, Ki and Kd constants from below into Configuration.h"
#define STR_PID_AUTOTUNE_FINISHED "PID Autotune finished! Put the last Kp, Ki and Kd constants from below into Configuration.h"
#define STR_PID_DEBUG " PID_DEBUG "
#define STR_PID_DEBUG_INPUT ": Input "
#define STR_PID_DEBUG_OUTPUT " Output "
@@ -250,6 +229,11 @@
#define STR_HEATER_BED "bed"
#define STR_HEATER_CHAMBER "chamber"
#define STR_COOLER "cooler"
#define STR_MOTHERBOARD "motherboard"
#define STR_PROBE "probe"
#define STR_REDUNDANT "redundant "
#define STR_LASER_TEMP "laser temperature"
#define STR_STOPPED_HEATER ", system stopped! Heater_ID: "
#define STR_REDUNDANCY "Heater switched off. Temperature difference between temp sensors is too high !"
@@ -270,17 +254,94 @@
#define STR_DEBUG_COMMUNICATION "COMMUNICATION"
#define STR_DEBUG_LEVELING "LEVELING"
// LCD Menu Messages
#define STR_PRINTER_LOCKED "Printer locked! (Unlock with M511 or LCD)"
#define STR_WRONG_PASSWORD "Incorrect Password"
#define STR_PASSWORD_TOO_LONG "Password too long"
#define STR_PASSWORD_REMOVED "Password removed"
#define STR_REMINDER_SAVE_SETTINGS "Remember to save!"
#define STR_PASSWORD_SET "Password is "
#define LANGUAGE_DATA_INCL_(M) STRINGIFY_(fontdata/langdata_##M.h)
#define LANGUAGE_DATA_INCL(M) LANGUAGE_DATA_INCL_(M)
// Settings Report Strings
#define STR_Z_AUTO_ALIGN "Z Auto-Align"
#define STR_BACKLASH_COMPENSATION "Backlash compensation"
#define STR_S_SEG_PER_SEC "S<seg-per-sec>"
#define STR_DELTA_SETTINGS "Delta (L<diagonal-rod> R<radius> H<height> S<seg-per-sec> XYZ<tower-angle-trim> ABC<rod-trim>)"
#define STR_SCARA_SETTINGS "SCARA"
#define STR_POLARGRAPH_SETTINGS "Polargraph"
#define STR_SCARA_P_T_Z "P<theta-psi-offset> T<theta-offset> Z<home-offset>"
#define STR_ENDSTOP_ADJUSTMENT "Endstop adjustment"
#define STR_SKEW_FACTOR "Skew Factor"
#define STR_FILAMENT_SETTINGS "Filament settings"
#define STR_MAX_ACCELERATION "Max Acceleration (units/s2)"
#define STR_MAX_FEEDRATES "Max feedrates (units/s)"
#define STR_ACCELERATION_P_R_T "Acceleration (units/s2) (P<print-accel> R<retract-accel> T<travel-accel>)"
#define STR_TOOL_CHANGING "Tool-changing"
#define STR_HOTEND_OFFSETS "Hotend offsets"
#define STR_SERVO_ANGLES "Servo Angles"
#define STR_HOTEND_PID "Hotend PID"
#define STR_BED_PID "Bed PID"
#define STR_CHAMBER_PID "Chamber PID"
#define STR_STEPS_PER_UNIT "Steps per unit"
#define STR_LINEAR_ADVANCE "Linear Advance"
#define STR_CONTROLLER_FAN "Controller Fan"
#define STR_STEPPER_MOTOR_CURRENTS "Stepper motor currents"
#define STR_RETRACT_S_F_Z "Retract (S<length> F<feedrate> Z<lift>)"
#define STR_RECOVER_S_F "Recover (S<length> F<feedrate>)"
#define STR_AUTO_RETRACT_S "Auto-Retract (S<enable>)"
#define STR_FILAMENT_LOAD_UNLOAD "Filament load/unload"
#define STR_POWER_LOSS_RECOVERY "Power-loss recovery"
#define STR_FILAMENT_RUNOUT_SENSOR "Filament runout sensor"
#define STR_DRIVER_STEPPING_MODE "Driver stepping mode"
#define STR_STEPPER_DRIVER_CURRENT "Stepper driver current"
#define STR_HYBRID_THRESHOLD "Hybrid Threshold"
#define STR_STALLGUARD_THRESHOLD "StallGuard threshold"
#define STR_HOME_OFFSET "Home offset"
#define STR_SOFT_ENDSTOPS "Soft endstops"
#define STR_MATERIAL_HEATUP "Material heatup parameters"
#define STR_LCD_CONTRAST "LCD Contrast"
#define STR_LCD_BRIGHTNESS "LCD Brightness"
#define STR_UI_LANGUAGE "UI Language"
#define STR_Z_PROBE_OFFSET "Z-Probe Offset"
#define STR_TEMPERATURE_UNITS "Temperature Units"
#define STR_USER_THERMISTORS "User thermistors"
#define LANGUAGE_INCL_(M) STRINGIFY_(../lcd/language/language_##M.h)
#define LANGUAGE_INCL(M) LANGUAGE_INCL_(M)
//
// Endstop Names used by Endstops::report_states
//
#define STR_X_MIN "x_min"
#define STR_X_MAX "x_max"
#define STR_X2_MIN "x2_min"
#define STR_X2_MAX "x2_max"
#if HAS_Y_AXIS
#define STR_Y_MIN "y_min"
#define STR_Y_MAX "y_max"
#define STR_Y2_MIN "y2_min"
#define STR_Y2_MAX "y2_max"
#endif
#if HAS_Z_AXIS
#define STR_Z_MIN "z_min"
#define STR_Z_MAX "z_max"
#define STR_Z2_MIN "z2_min"
#define STR_Z2_MAX "z2_max"
#define STR_Z3_MIN "z3_min"
#define STR_Z3_MAX "z3_max"
#define STR_Z4_MIN "z4_min"
#define STR_Z4_MAX "z4_max"
#endif
#define STR_Z_PROBE "z_probe"
#define STR_PROBE_EN "probe_en"
#define STR_FILAMENT "filament"
// General axis names
#define STR_X "X"
#define STR_Y "Y"
#define STR_Z "Z"
#define STR_I AXIS4_STR
#define STR_J AXIS5_STR
#define STR_K AXIS6_STR
#define STR_E "E"
#if IS_KINEMATIC
#define STR_A "A"
@@ -300,9 +361,115 @@
#define LCD_STR_A STR_A
#define LCD_STR_B STR_B
#define LCD_STR_C STR_C
#define LCD_STR_I STR_I
#define LCD_STR_J STR_J
#define LCD_STR_K STR_K
#define LCD_STR_E STR_E
#if HAS_CHARACTER_LCD
// Extra Axis and Endstop Names
#if LINEAR_AXES >= 4
#if AXIS4_NAME == 'A'
#define AXIS4_STR "A"
#define STR_I_MIN "a_min"
#define STR_I_MAX "a_max"
#elif AXIS4_NAME == 'B'
#define AXIS4_STR "B"
#define STR_I_MIN "b_min"
#define STR_I_MAX "b_max"
#elif AXIS4_NAME == 'C'
#define AXIS4_STR "C"
#define STR_I_MIN "c_min"
#define STR_I_MAX "c_max"
#elif AXIS4_NAME == 'U'
#define AXIS4_STR "U"
#define STR_I_MIN "u_min"
#define STR_I_MAX "u_max"
#elif AXIS4_NAME == 'V'
#define AXIS4_STR "V"
#define STR_I_MIN "v_min"
#define STR_I_MAX "v_max"
#elif AXIS4_NAME == 'W'
#define AXIS4_STR "W"
#define STR_I_MIN "w_min"
#define STR_I_MAX "w_max"
#else
#define AXIS4_STR "A"
#define STR_I_MIN "a_min"
#define STR_I_MAX "a_max"
#endif
#else
#define AXIS4_STR ""
#endif
#if LINEAR_AXES >= 5
#if AXIS5_NAME == 'A'
#define AXIS5_STR "A"
#define STR_J_MIN "a_min"
#define STR_J_MAX "a_max"
#elif AXIS5_NAME == 'B'
#define AXIS5_STR "B"
#define STR_J_MIN "b_min"
#define STR_J_MAX "b_max"
#elif AXIS5_NAME == 'C'
#define AXIS5_STR "C"
#define STR_J_MIN "c_min"
#define STR_J_MAX "c_max"
#elif AXIS5_NAME == 'U'
#define AXIS5_STR "U"
#define STR_J_MIN "u_min"
#define STR_J_MAX "u_max"
#elif AXIS5_NAME == 'V'
#define AXIS5_STR "V"
#define STR_J_MIN "v_min"
#define STR_J_MAX "v_max"
#elif AXIS5_NAME == 'W'
#define AXIS5_STR "W"
#define STR_J_MIN "w_min"
#define STR_J_MAX "w_max"
#else
#define AXIS5_STR "B"
#define STR_J_MIN "b_min"
#define STR_J_MAX "b_max"
#endif
#else
#define AXIS5_STR ""
#endif
#if LINEAR_AXES >= 6
#if AXIS6_NAME == 'A'
#define AXIS6_STR "A"
#define STR_K_MIN "a_min"
#define STR_K_MAX "a_max"
#elif AXIS6_NAME == 'B'
#define AXIS6_STR "B"
#define STR_K_MIN "b_min"
#define STR_K_MAX "b_max"
#elif AXIS6_NAME == 'C'
#define AXIS6_STR "C"
#define STR_K_MIN "c_min"
#define STR_K_MAX "c_max"
#elif AXIS6_NAME == 'U'
#define AXIS6_STR "U"
#define STR_K_MIN "u_min"
#define STR_K_MAX "u_max"
#elif AXIS6_NAME == 'V'
#define AXIS6_STR "V"
#define STR_K_MIN "v_min"
#define STR_K_MAX "v_max"
#elif AXIS6_NAME == 'W'
#define AXIS6_STR "W"
#define STR_K_MIN "w_min"
#define STR_K_MAX "w_max"
#else
#define AXIS6_STR "C"
#define STR_K_MIN "c_min"
#define STR_K_MAX "c_max"
#endif
#else
#define AXIS6_STR ""
#endif
#if EITHER(HAS_MARLINUI_HD44780, IS_TFTGLCD_PANEL)
// Custom characters defined in the first 8 characters of the LCD
#define LCD_STR_BEDTEMP "\x00" // Print only as a char. This will have 'unexpected' results when used in a string!
@@ -347,10 +514,9 @@
* However, internal to Marlin E0/T0 is the first tool, and
* most board silkscreens say "E0." Zero-based labels will
* make these indexes consistent but this defies expectation.
*
*/
#if ENABLED(NUMBER_TOOLS_FROM_0)
#define LCD_FIRST_TOOL '0'
#define LCD_FIRST_TOOL 0
#define LCD_STR_N0 "0"
#define LCD_STR_N1 "1"
#define LCD_STR_N2 "2"
@@ -360,7 +526,7 @@
#define LCD_STR_N6 "6"
#define LCD_STR_N7 "7"
#else
#define LCD_FIRST_TOOL '1'
#define LCD_FIRST_TOOL 1
#define LCD_STR_N0 "1"
#define LCD_STR_N1 "2"
#define LCD_STR_N2 "3"
@@ -380,6 +546,18 @@
#define LCD_STR_E6 "E" LCD_STR_N6
#define LCD_STR_E7 "E" LCD_STR_N7
// Include localized LCD Menu Messages
#define LANGUAGE_DATA_INCL_(M) STRINGIFY_(fontdata/langdata_##M.h)
#define LANGUAGE_DATA_INCL(M) LANGUAGE_DATA_INCL_(M)
#define LANGUAGE_INCL_(M) STRINGIFY_(../lcd/language/language_##M.h)
#define LANGUAGE_INCL(M) LANGUAGE_INCL_(M)
// Use superscripts, if possible. Evaluated at point of use.
#define SUPERSCRIPT_TWO TERN(NOT_EXTENDED_ISO10646_1_5X7, "^2", "²")
#define SUPERSCRIPT_THREE TERN(NOT_EXTENDED_ISO10646_1_5X7, "^3", "³")
#include "multi_language.h" // Allow multiple languages
#include "../lcd/language/language_en.h"

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -33,26 +33,36 @@
#define _AXIS(A) (A##_AXIS)
#define _XMIN_ 100
#define _YMIN_ 200
#define _ZMIN_ 300
#define _XMAX_ 101
#define _YMAX_ 201
#define _ZMAX_ 301
#define _XDIAG_ 102
#define _YDIAG_ 202
#define _ZDIAG_ 302
#define _E0DIAG_ 400
#define _E1DIAG_ 401
#define _E2DIAG_ 402
#define _E3DIAG_ 403
#define _E4DIAG_ 404
#define _E5DIAG_ 405
#define _E6DIAG_ 406
#define _E7DIAG_ 407
#define _XMIN_ 0x11
#define _YMIN_ 0x12
#define _ZMIN_ 0x13
#define _IMIN_ 0x14
#define _JMIN_ 0x15
#define _KMIN_ 0x16
#define _XMAX_ 0x21
#define _YMAX_ 0x22
#define _ZMAX_ 0x23
#define _IMAX_ 0x24
#define _JMAX_ 0x25
#define _KMAX_ 0x26
#define _XDIAG_ 0x31
#define _YDIAG_ 0x32
#define _ZDIAG_ 0x33
#define _IDIAG_ 0x34
#define _JDIAG_ 0x35
#define _KDIAG_ 0x36
#define _E0DIAG_ 0xE0
#define _E1DIAG_ 0xE1
#define _E2DIAG_ 0xE2
#define _E3DIAG_ 0xE3
#define _E4DIAG_ 0xE4
#define _E5DIAG_ 0xE5
#define _E6DIAG_ 0xE6
#define _E7DIAG_ 0xE7
#define _FORCE_INLINE_ __attribute__((__always_inline__)) __inline__
#define FORCE_INLINE __attribute__((always_inline)) inline
#define NO_INLINE __attribute__((noinline))
#define _UNUSED __attribute__((unused))
#define _O0 __attribute__((optimize("O0")))
#define _Os __attribute__((optimize("Os")))
@@ -60,12 +70,10 @@
#define _O2 __attribute__((optimize("O2")))
#define _O3 __attribute__((optimize("O3")))
#define IS_CONSTEXPR(...) __builtin_constant_p(__VA_ARGS__) // Only valid solution with C++14. Should use std::is_constant_evaluated() in C++20 instead
#ifndef UNUSED
#if defined(ARDUINO_ARCH_STM32) && !defined(STM32GENERIC)
#define UNUSED(X) (void)X
#else
#define UNUSED(x) ((void)(x))
#endif
#define UNUSED(x) ((void)(x))
#endif
// Clock speed factors
@@ -76,13 +84,6 @@
// Nanoseconds per cycle
#define NANOSECONDS_PER_CYCLE (1000000000.0 / F_CPU)
// Macros to make sprintf_P read from PROGMEM (AVR extension)
#ifdef __AVR__
#define S_FMT "%S"
#else
#define S_FMT "%s"
#endif
// Macros to make a string from a macro
#define STRINGIFY_(M) #M
#define STRINGIFY(M) STRINGIFY_(M)
@@ -95,29 +96,29 @@
#define _BV(n) (1<<(n))
#define TEST(n,b) (!!((n)&_BV(b)))
#define SET_BIT_TO(N,B,TF) do{ if (TF) SBI(N,B); else CBI(N,B); }while(0)
#ifndef SBI
#define SBI(A,B) (A |= (1 << (B)))
#define SBI(A,B) (A |= _BV(B))
#endif
#ifndef CBI
#define CBI(A,B) (A &= ~(1 << (B)))
#define CBI(A,B) (A &= ~_BV(B))
#endif
#define TBI(N,B) (N ^= _BV(B))
#define _BV32(b) (1UL << (b))
#define TEST32(n,b) !!((n)&_BV32(b))
#define SBI32(n,b) (n |= _BV32(b))
#define CBI32(n,b) (n &= ~_BV32(b))
#define TBI32(N,B) (N ^= _BV32(B))
#define cu(x) ((x)*(x)*(x))
#define cu(x) ({__typeof__(x) _x = (x); (_x)*(_x)*(_x);})
#define RADIANS(d) ((d)*float(M_PI)/180.0f)
#define DEGREES(r) ((r)*180.0f/float(M_PI))
#define HYPOT2(x,y) (sq(x)+sq(y))
#define NORMSQ(x,y,z) (sq(x)+sq(y)+sq(z))
#define CIRCLE_AREA(R) (float(M_PI) * sq(float(R)))
#define CIRCLE_CIRC(R) (2 * float(M_PI) * float(R))
#define SIGN(a) ((a>0)-(a<0))
#define SIGN(a) ({__typeof__(a) _a = (a); (_a>0)-(_a<0);})
#define IS_POWER_OF_2(x) ((x) && !((x) & ((x) - 1)))
// Macros to constrain values
@@ -137,31 +138,29 @@
#else
// Using GCC extensions, but Travis GCC version does not like it and gives
// "error: statement-expressions are not allowed outside functions nor in template-argument lists"
#define NOLESS(v, n) \
do{ \
__typeof__(n) _n = (n); \
__typeof__(v) _n = (n); \
if (_n > v) v = _n; \
}while(0)
#define NOMORE(v, n) \
do{ \
__typeof__(n) _n = (n); \
__typeof__(v) _n = (n); \
if (_n < v) v = _n; \
}while(0)
#define LIMIT(v, n1, n2) \
do{ \
__typeof__(n1) _n1 = (n1); \
__typeof__(n2) _n2 = (n2); \
__typeof__(v) _n1 = (n1); \
__typeof__(v) _n2 = (n2); \
if (_n1 > v) v = _n1; \
else if (_n2 < v) v = _n2; \
}while(0)
#endif
// Macros to chain up to 12 conditions
// Macros to chain up to 14 conditions
#define _DO_1(W,C,A) (_##W##_1(A))
#define _DO_2(W,C,A,B) (_##W##_1(A) C _##W##_1(B))
#define _DO_3(W,C,A,V...) (_##W##_1(A) C _DO_2(W,C,V))
@@ -174,9 +173,12 @@
#define _DO_10(W,C,A,V...) (_##W##_1(A) C _DO_9(W,C,V))
#define _DO_11(W,C,A,V...) (_##W##_1(A) C _DO_10(W,C,V))
#define _DO_12(W,C,A,V...) (_##W##_1(A) C _DO_11(W,C,V))
#define _DO_13(W,C,A,V...) (_##W##_1(A) C _DO_12(W,C,V))
#define _DO_14(W,C,A,V...) (_##W##_1(A) C _DO_13(W,C,V))
#define _DO_15(W,C,A,V...) (_##W##_1(A) C _DO_14(W,C,V))
#define __DO_N(W,C,N,V...) _DO_##N(W,C,V)
#define _DO_N(W,C,N,V...) __DO_N(W,C,N,V)
#define DO(W,C,V...) _DO_N(W,C,NUM_ARGS(V),V)
#define DO(W,C,V...) (_DO_N(W,C,NUM_ARGS(V),V))
// Macros to support option testing
#define _CAT(a,V...) a##V
@@ -192,20 +194,37 @@
#define _DIS_1(O) NOT(_ENA_1(O))
#define ENABLED(V...) DO(ENA,&&,V)
#define DISABLED(V...) DO(DIS,&&,V)
#define COUNT_ENABLED(V...) DO(ENA,+,V)
#define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION converted to '0' or '1'
#define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION converted to A or '0'
#define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION converted to A or '1'
#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION converted to A or '<nul>'
#define TERN(O,A,B) _TERN(_ENA_1(O),B,A) // OPTION ? 'A' : 'B'
#define TERN0(O,A) _TERN(_ENA_1(O),0,A) // OPTION ? 'A' : '0'
#define TERN1(O,A) _TERN(_ENA_1(O),1,A) // OPTION ? 'A' : '1'
#define TERN_(O,A) _TERN(_ENA_1(O),,A) // OPTION ? 'A' : '<nul>'
#define _TERN(E,V...) __TERN(_CAT(T_,E),V) // Prepend 'T_' to get 'T_0' or 'T_1'
#define __TERN(T,V...) ___TERN(_CAT(_NO,T),V) // Prepend '_NO' to get '_NOT_0' or '_NOT_1'
#define ___TERN(P,V...) THIRD(P,V) // If first argument has a comma, A. Else B.
#define _OPTARG(A...) , A
#define OPTARG(O,A...) TERN_(O,DEFER4(_OPTARG)(A))
#define _OPTCODE(A) A;
#define OPTCODE(O,A) TERN_(O,DEFER4(_OPTCODE)(A))
// Macros to avoid 'f + 0.0' which is not always optimized away. Minus included for symmetry.
// Compiler flags -fno-signed-zeros -ffinite-math-only also cover 'f * 1.0', 'f - f', etc.
#define PLUS_TERN0(O,A) _TERN(_ENA_1(O),,+ (A)) // OPTION ? '+ (A)' : '<nul>'
#define MINUS_TERN0(O,A) _TERN(_ENA_1(O),,- (A)) // OPTION ? '- (A)' : '<nul>'
#define SUM_TERN(O,B,A) ((B) PLUS_TERN0(O,A)) // ((B) (OPTION ? '+ (A)' : '<nul>'))
#define DIFF_TERN(O,B,A) ((B) MINUS_TERN0(O,A)) // ((B) (OPTION ? '- (A)' : '<nul>'))
#define IF_ENABLED TERN_
#define IF_DISABLED(O,A) TERN(O,,A)
#define ANY(V...) !DISABLED(V)
#define NONE(V...) DISABLED(V)
#define ALL(V...) ENABLED(V)
#define BOTH(V1,V2) ALL(V1,V2)
#define EITHER(V1,V2) ANY(V1,V2)
#define MANY(V...) (COUNT_ENABLED(V) > 1)
// Macros to support pins/buttons exist testing
#define PIN_EXISTS(PN) (defined(PN##_PIN) && PN##_PIN >= 0)
@@ -219,8 +238,10 @@
#define ANY_BUTTON(V...) DO(BTNEX,||,V)
#define WITHIN(N,L,H) ((N) >= (L) && (N) <= (H))
#define ISEOL(C) ((C) == '\n' || (C) == '\r')
#define NUMERIC(a) WITHIN(a, '0', '9')
#define DECIMAL(a) (NUMERIC(a) || a == '.')
#define HEXCHR(a) (NUMERIC(a) ? (a) - '0' : WITHIN(a, 'a', 'f') ? ((a) - 'a' + 10) : WITHIN(a, 'A', 'F') ? ((a) - 'A' + 10) : -1)
#define NUMERIC_SIGNED(a) (NUMERIC(a) || (a) == '-' || (a) == '+')
#define DECIMAL_SIGNED(a) (DECIMAL(a) || (a) == '-' || (a) == '+')
#define COUNT(a) (sizeof(a)/sizeof(*a))
@@ -230,7 +251,47 @@
memcpy(&a[0],&b[0],_MIN(sizeof(a),sizeof(b))); \
}while(0)
#define CODE_11( A,B,C,D,E,F,G,H,I,J,K,...) A; B; C; D; E; F; G; H; I; J; K
#define CODE_10( A,B,C,D,E,F,G,H,I,J,...) A; B; C; D; E; F; G; H; I; J
#define CODE_9( A,B,C,D,E,F,G,H,I,...) A; B; C; D; E; F; G; H; I
#define CODE_8( A,B,C,D,E,F,G,H,...) A; B; C; D; E; F; G; H
#define CODE_7( A,B,C,D,E,F,G,...) A; B; C; D; E; F; G
#define CODE_6( A,B,C,D,E,F,...) A; B; C; D; E; F
#define CODE_5( A,B,C,D,E,...) A; B; C; D; E
#define CODE_4( A,B,C,D,...) A; B; C; D
#define CODE_3( A,B,C,...) A; B; C
#define CODE_2( A,B,...) A; B
#define CODE_1( A,...) A
#define CODE_0(...)
#define _CODE_N(N,V...) CODE_##N(V)
#define CODE_N(N,V...) _CODE_N(N,V)
#define GANG_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A B C D E F G H I J K L M N O P
#define GANG_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A B C D E F G H I J K L M N O
#define GANG_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A B C D E F G H I J K L M N
#define GANG_13(A,B,C,D,E,F,G,H,I,J,K,L,M...) A B C D E F G H I J K L M
#define GANG_12(A,B,C,D,E,F,G,H,I,J,K,L...) A B C D E F G H I J K L
#define GANG_11(A,B,C,D,E,F,G,H,I,J,K,...) A B C D E F G H I J K
#define GANG_10(A,B,C,D,E,F,G,H,I,J,...) A B C D E F G H I J
#define GANG_9( A,B,C,D,E,F,G,H,I,...) A B C D E F G H I
#define GANG_8( A,B,C,D,E,F,G,H,...) A B C D E F G H
#define GANG_7( A,B,C,D,E,F,G,...) A B C D E F G
#define GANG_6( A,B,C,D,E,F,...) A B C D E F
#define GANG_5( A,B,C,D,E,...) A B C D E
#define GANG_4( A,B,C,D,...) A B C D
#define GANG_3( A,B,C,...) A B C
#define GANG_2( A,B,...) A B
#define GANG_1( A,...) A
#define GANG_0(...)
#define _GANG_N(N,V...) GANG_##N(V)
#define GANG_N(N,V...) _GANG_N(N,V)
#define GANG_N_1(N,K) _GANG_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K)
// Macros for initializing arrays
#define LIST_20(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T
#define LIST_19(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S
#define LIST_18(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R
#define LIST_17(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q
#define LIST_16(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P
#define LIST_15(A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N,O
#define LIST_14(A,B,C,D,E,F,G,H,I,J,K,L,M,N,...) A,B,C,D,E,F,G,H,I,J,K,L,M,N
@@ -247,10 +308,13 @@
#define LIST_3( A,B,C,...) A,B,C
#define LIST_2( A,B,...) A,B
#define LIST_1( A,...) A
#define LIST_0(...)
#define _LIST_N(N,V...) LIST_##N(V)
#define LIST_N(N,V...) _LIST_N(N,V)
#define LIST_N_1(N,K) _LIST_N(N,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K)
#define ARRAY_N(N,V...) { _LIST_N(N,V) }
#define ARRAY_N_1(N,K) { LIST_N_1(N,K) }
#define _JOIN_1(O) (O)
#define JOIN_N(N,C,V...) (DO(JOIN,C,LIST_N(N,V)))
@@ -276,7 +340,7 @@
#define NEAR(x,y) NEAR_ZERO((x)-(y))
#define RECIPROCAL(x) (NEAR_ZERO(x) ? 0 : (1 / float(x)))
#define FIXFLOAT(f) (f + (f < 0 ? -0.00005f : 0.00005f))
#define FIXFLOAT(f) ({__typeof__(f) _f = (f); _f + (_f < 0 ? -0.0000005f : 0.0000005f);})
//
// Maths macros that can be overridden by HAL
@@ -288,19 +352,18 @@
#define RSQRT(x) (1.0f / sqrtf(x))
#define CEIL(x) ceilf(x)
#define FLOOR(x) floorf(x)
#define TRUNC(x) truncf(x)
#define LROUND(x) lroundf(x)
#define FMOD(x, y) fmodf(x, y)
#define HYPOT(x,y) SQRT(HYPOT2(x,y))
#ifdef TARGET_LPC1768
#define I2C_ADDRESS(A) ((A) << 1)
#else
#define I2C_ADDRESS(A) A
#endif
// Use NUM_ARGS(__VA_ARGS__) to get the number of variadic arguments
#define _NUM_ARGS(_,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
#define NUM_ARGS(V...) _NUM_ARGS(0,V,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
#define _NUM_ARGS(_,n,m,l,k,j,i,h,g,f,e,d,c,b,a,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
#define NUM_ARGS(V...) _NUM_ARGS(0,V,40,39,38,37,36,35,34,33,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)
// Use TWO_ARGS(__VA_ARGS__) to get whether there are 1, 2, or >2 arguments
#define _TWO_ARGS(_,n,m,l,k,j,i,h,g,f,e,d,c,b,a,Z,Y,X,W,V,U,T,S,R,Q,P,O,N,M,L,K,J,I,H,G,F,E,D,C,B,A,OUT,...) OUT
#define TWO_ARGS(V...) _TWO_ARGS(0,V,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,0)
#ifdef __cplusplus
@@ -323,46 +386,133 @@
#endif
// Allow manipulating enumeration value like flags without ugly cast everywhere
#define ENUM_FLAGS(T) \
FORCE_INLINE constexpr T operator&(T x, T y) { return static_cast<T>(static_cast<int>(x) & static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator|(T x, T y) { return static_cast<T>(static_cast<int>(x) | static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator^(T x, T y) { return static_cast<T>(static_cast<int>(x) ^ static_cast<int>(y)); } \
FORCE_INLINE constexpr T operator~(T x) { return static_cast<T>(~static_cast<int>(x)); } \
FORCE_INLINE T & operator&=(T &x, T y) { return x &= y; } \
FORCE_INLINE T & operator|=(T &x, T y) { return x |= y; } \
FORCE_INLINE T & operator^=(T &x, T y) { return x ^= y; }
// C++11 solution that is standard compliant. <type_traits> is not available on all platform
namespace Private {
template<bool, typename _Tp = void> struct enable_if { };
template<typename _Tp> struct enable_if<true, _Tp> { typedef _Tp type; };
template<typename T, typename U> struct is_same { enum { value = false }; };
template<typename T> struct is_same<T, T> { enum { value = true }; };
template <typename T, typename ... Args> struct first_type_of { typedef T type; };
template <typename T> struct first_type_of<T> { typedef T type; };
}
// C++11 solution using SFINAE to detect the existence of a member in a class at compile time.
// It creates a HasMember<Type> structure containing 'value' set to true if the member exists
#define HAS_MEMBER_IMPL(Member) \
namespace Private { \
template <typename Type, typename Yes=char, typename No=long> struct HasMember_ ## Member { \
template <typename C> static Yes& test( decltype(&C::Member) ) ; \
template <typename C> static No& test(...); \
enum { value = sizeof(test<Type>(0)) == sizeof(Yes) }; }; \
}
// Call the method if it exists, but do nothing if it does not. The method is detected at compile time.
// If the method exists, this is inlined and does not cost anything. Else, an "empty" wrapper is created, returning a default value
#define CALL_IF_EXISTS_IMPL(Return, Method, ...) \
HAS_MEMBER_IMPL(Method) \
namespace Private { \
template <typename T, typename ... Args> FORCE_INLINE typename enable_if<HasMember_ ## Method <T>::value, Return>::type Call_ ## Method(T * t, Args... a) { return static_cast<Return>(t->Method(a...)); } \
_UNUSED static Return Call_ ## Method(...) { return __VA_ARGS__; } \
}
#define CALL_IF_EXISTS(Return, That, Method, ...) \
static_cast<Return>(Private::Call_ ## Method(That, ##__VA_ARGS__))
// Compile-time string manipulation
namespace CompileTimeString {
// Simple compile-time parser to find the position of the end of a string
constexpr const char* findStringEnd(const char *str) {
return *str ? findStringEnd(str + 1) : str;
}
// Check whether a string contains a specific character
constexpr bool contains(const char *str, const char ch) {
return *str == ch ? true : (*str ? contains(str + 1, ch) : false);
}
// Find the last position of the specific character (should be called with findStringEnd)
constexpr const char* findLastPos(const char *str, const char ch) {
return *str == ch ? (str + 1) : findLastPos(str - 1, ch);
}
// Compile-time evaluation of the last part of a file path
// Typically used to shorten the path to file in compiled strings
// CompileTimeString::baseName(__FILE__) returns "macros.h" and not /path/to/Marlin/src/core/macros.h
constexpr const char* baseName(const char *str) {
return contains(str, '/') ? findLastPos(findStringEnd(str), '/') : str;
}
// Find the first occurrence of a character in a string (or return the last position in the string)
constexpr const char* findFirst(const char *str, const char ch) {
return *str == ch || *str == 0 ? (str + 1) : findFirst(str + 1, ch);
}
// Compute the string length at compile time
constexpr unsigned stringLen(const char *str) {
return *str == 0 ? 0 : 1 + stringLen(str + 1);
}
}
#define ONLY_FILENAME CompileTimeString::baseName(__FILE__)
/** Get the templated type name. This does not depends on RTTI, but on the preprocessor, so it should be quite safe to use even on old compilers.
WARNING: DO NOT RENAME THIS FUNCTION (or change the text inside the function to match what the preprocessor will generate)
The name is chosen very short since the binary will store "const char* gtn(T*) [with T = YourTypeHere]" so avoid long function name here */
template <typename T>
inline const char* gtn(T*) {
// It works on GCC by instantiating __PRETTY_FUNCTION__ and parsing the result. So the syntax here is very limited to GCC output
constexpr unsigned verboseChatLen = sizeof("const char* gtn(T*) [with T = ") - 1;
static char templateType[sizeof(__PRETTY_FUNCTION__) - verboseChatLen] = {};
__builtin_memcpy(templateType, __PRETTY_FUNCTION__ + verboseChatLen, sizeof(__PRETTY_FUNCTION__) - verboseChatLen - 2);
return templateType;
}
#else
#define MIN_2(a,b) ((a)<(b)?(a):(b))
#define MIN_3(a,V...) MIN_2(a,MIN_2(V))
#define MIN_4(a,V...) MIN_2(a,MIN_3(V))
#define MIN_5(a,V...) MIN_2(a,MIN_4(V))
#define MIN_6(a,V...) MIN_2(a,MIN_5(V))
#define MIN_7(a,V...) MIN_2(a,MIN_6(V))
#define MIN_8(a,V...) MIN_2(a,MIN_7(V))
#define MIN_9(a,V...) MIN_2(a,MIN_8(V))
#define MIN_10(a,V...) MIN_2(a,MIN_9(V))
#define __MIN_N(N,V...) MIN_##N(V)
#define _MIN_N(N,V...) __MIN_N(N,V)
#define _MIN(V...) _MIN_N(NUM_ARGS(V), V)
#define _MIN_N_REF() _MIN_N
#define _MIN(V...) EVAL(_MIN_N(TWO_ARGS(V),V))
#define MIN_2(a,b) ((a)<(b)?(a):(b))
#define MIN_3(a,V...) MIN_2(a,DEFER2(_MIN_N_REF)()(TWO_ARGS(V),V))
#define MAX_2(a,b) ((a)>(b)?(a):(b))
#define MAX_3(a,V...) MAX_2(a,MAX_2(V))
#define MAX_4(a,V...) MAX_2(a,MAX_3(V))
#define MAX_5(a,V...) MAX_2(a,MAX_4(V))
#define MAX_6(a,V...) MAX_2(a,MAX_5(V))
#define MAX_7(a,V...) MAX_2(a,MAX_6(V))
#define MAX_8(a,V...) MAX_2(a,MAX_7(V))
#define MAX_9(a,V...) MAX_2(a,MAX_8(V))
#define MAX_10(a,V...) MAX_2(a,MAX_9(V))
#define __MAX_N(N,V...) MAX_##N(V)
#define _MAX_N(N,V...) __MAX_N(N,V)
#define _MAX(V...) _MAX_N(NUM_ARGS(V), V)
#define _MAX_N_REF() _MAX_N
#define _MAX(V...) EVAL(_MAX_N(TWO_ARGS(V),V))
#define MAX_2(a,b) ((a)>(b)?(a):(b))
#define MAX_3(a,V...) MAX_2(a,DEFER2(_MAX_N_REF)()(TWO_ARGS(V),V))
#endif
// Macros for adding
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define INC_5 6
#define INC_6 7
#define INC_7 8
#define INC_8 9
#define INC_9 10
#define INC_10 11
#define INC_11 12
#define INC_12 13
#define INC_13 14
#define INC_14 15
#define INC_15 16
#define INC_16 17
#define INC_17 18
#define INC_18 19
#define INC_19 20
#define INC_20 21
#define INCREMENT_(n) INC_##n
#define INCREMENT(n) INCREMENT_(n)
@@ -377,18 +527,27 @@
#define ADD8(N) ADD4(ADD4(N))
#define ADD9(N) ADD4(ADD5(N))
#define ADD10(N) ADD5(ADD5(N))
#define SUM(A,B) _CAT(ADD,A)(B)
#define DOUBLE_(n) ADD##n(n)
#define DOUBLE(n) DOUBLE_(n)
// Macros for subtracting
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define DEC_6 5
#define DEC_7 6
#define DEC_8 7
#define DEC_9 8
#define DEC_10 9
#define DEC_11 10
#define DEC_12 11
#define DEC_13 12
#define DEC_14 13
#define DEC_15 14
#define DECREMENT_(n) DEC_##n
#define DECREMENT(n) DECREMENT_(n)
@@ -450,6 +609,12 @@
#define HAS_ARGS(V...) _BOOL(FIRST(_END_OF_ARGUMENTS_ V)())
#define _END_OF_ARGUMENTS_() 0
// Simple Inline IF Macros, friendly to use in other macro definitions
#define IF(O, A, B) ((O) ? (A) : (B))
#define IF_0(O, A) IF(O, A, 0)
#define IF_1(O, A) IF(O, A, 1)
//
// REPEAT core macros. Recurse N times with ascending I.
//
@@ -473,6 +638,7 @@
// Repeat a macro passing S...N-1.
#define REPEAT_S(S,N,OP) EVAL(_REPEAT(S,SUB##S(N),OP))
#define REPEAT(N,OP) REPEAT_S(0,N,OP)
#define REPEAT_1(N,OP) REPEAT_S(1,INCREMENT(N),OP)
// Repeat a macro passing 0...N-1 plus additional arguments.
#define REPEAT2_S(S,N,OP,V...) EVAL(_REPEAT2(S,SUB##S(N),OP,V))
@@ -495,3 +661,14 @@
#define RREPEAT(N,OP) RREPEAT_S(0,N,OP)
#define RREPEAT2_S(S,N,OP,V...) EVAL1024(_RREPEAT2(S,SUB##S(N),OP,V))
#define RREPEAT2(N,OP,V...) RREPEAT2_S(0,N,OP,V)
// See https://github.com/swansontec/map-macro
#define MAP_OUT
#define MAP_END(...)
#define MAP_GET_END() 0, MAP_END
#define MAP_NEXT0(test, next, ...) next MAP_OUT
#define MAP_NEXT1(test, next) MAP_NEXT0 (test, next, 0)
#define MAP_NEXT(test, next) MAP_NEXT1 (MAP_GET_END test, next)
#define MAP0(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP1) (f, peek, __VA_ARGS__)
#define MAP1(f, x, peek, ...) f(x) MAP_NEXT (peek, MAP0) (f, peek, __VA_ARGS__)
#define MAP(f, ...) EVAL512 (MAP1 (f, __VA_ARGS__, (), 0))

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -25,5 +25,9 @@
typedef uint32_t millis_t;
#define SEC_TO_MS(N) millis_t((N)*1000UL)
#define MIN_TO_MS(N) SEC_TO_MS((N)*60UL)
#define MS_TO_SEC(N) millis_t((N)/1000UL)
#define PENDING(NOW,SOON) ((int32_t)(NOW-(SOON))<0)
#define ELAPSED(NOW,SOON) (!PENDING(NOW,SOON))

View File

@@ -1,28 +1,37 @@
/********************
* multi_language.h *
********************/
/****************************************************************************
* Written By Marcio Teixeira 2019 - Aleph Objects, Inc. *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <http://www.gnu.org/licenses/>. *
****************************************************************************/
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
typedef const char Language_Str[];
/*******************************************************
* multi_language.h *
* By Marcio Teixeira 2019 for Aleph Objects *
*******************************************************/
#if defined(LCD_LANGUAGE_5)
#include "../inc/MarlinConfigPre.h"
typedef const char Language_Str[];
#define LSTR PROGMEM Language_Str
#ifdef LCD_LANGUAGE_5
#define NUM_LANGUAGES 5
#elif defined(LCD_LANGUAGE_4)
#define NUM_LANGUAGES 4
@@ -34,21 +43,17 @@ typedef const char Language_Str[];
#define NUM_LANGUAGES 1
#endif
// Setting the unused languages equal to each other allows
// the compiler to optimize away the conditionals
// Set unused languages equal to each other so the
// compiler can optimize away the conditionals.
#ifndef LCD_LANGUAGE_2
#define LCD_LANGUAGE_2 LCD_LANGUAGE
#endif
#ifndef LCD_LANGUAGE_3
#define LCD_LANGUAGE_3 LCD_LANGUAGE_2
#endif
#ifndef LCD_LANGUAGE_4
#define LCD_LANGUAGE_4 LCD_LANGUAGE_3
#endif
#ifndef LCD_LANGUAGE_5
#define LCD_LANGUAGE_5 LCD_LANGUAGE_4
#endif
@@ -57,23 +62,28 @@ typedef const char Language_Str[];
#define GET_LANG(LANG) _GET_LANG(LANG)
#if NUM_LANGUAGES > 1
extern uint8_t lang;
#define HAS_MULTI_LANGUAGE 1
#define GET_TEXT(MSG) ( \
lang == 0 ? GET_LANG(LCD_LANGUAGE)::MSG : \
lang == 1 ? GET_LANG(LCD_LANGUAGE_2)::MSG : \
lang == 2 ? GET_LANG(LCD_LANGUAGE_3)::MSG : \
lang == 3 ? GET_LANG(LCD_LANGUAGE_4)::MSG : \
GET_LANG(LCD_LANGUAGE_5)::MSG \
)
#define MAX_LANG_CHARSIZE _MAX(GET_LANG(LCD_LANGUAGE)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_2)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_3)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_4)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_5)::CHARSIZE)
ui.language == 4 ? GET_LANG(LCD_LANGUAGE_5)::MSG : \
ui.language == 3 ? GET_LANG(LCD_LANGUAGE_4)::MSG : \
ui.language == 2 ? GET_LANG(LCD_LANGUAGE_3)::MSG : \
ui.language == 1 ? GET_LANG(LCD_LANGUAGE_2)::MSG : \
GET_LANG(LCD_LANGUAGE )::MSG )
#define MAX_LANG_CHARSIZE _MAX(GET_LANG(LCD_LANGUAGE )::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_2)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_3)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_4)::CHARSIZE, \
GET_LANG(LCD_LANGUAGE_5)::CHARSIZE )
#else
#define GET_TEXT(MSG) GET_LANG(LCD_LANGUAGE)::MSG
#define MAX_LANG_CHARSIZE GET_LANG(LCD_LANGUAGE)::CHARSIZE
#define MAX_LANG_CHARSIZE LANG_CHARSIZE
#endif
#define GET_TEXT_F(MSG) (const __FlashStringHelper*)GET_TEXT(MSG)
#define GET_TEXT_F(MSG) FPSTR(GET_TEXT(MSG))
#define MSG_CONCAT(A,B) pgm_p_pair_t(GET_TEXT(A),GET_TEXT(B))
#define GET_LANGUAGE_NAME(INDEX) GET_LANG(LCD_LANGUAGE_##INDEX)::LANGUAGE
#define LANG_CHARSIZE GET_TEXT(CHARSIZE)
#define USE_WIDE_GLYPH (LANG_CHARSIZE > 2)
#define MSG_1_LINE(A) A "\0" "\0"
#define MSG_2_LINE(A,B) A "\0" B "\0"
#define MSG_3_LINE(A,B,C) A "\0" B "\0" C

View File

@@ -16,36 +16,65 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "serial.h"
#include "language.h"
#include "../inc/MarlinConfig.h"
#if HAS_ETHERNET
#include "../feature/ethernet.h"
#endif
uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
static const char errormagic[] PROGMEM = "Error:";
static const char echomagic[] PROGMEM = "echo:";
// Commonly-used strings in serial output
PGMSTR(NUL_STR, ""); PGMSTR(SP_P_STR, " P"); PGMSTR(SP_T_STR, " T");
PGMSTR(X_STR, "X"); PGMSTR(Y_STR, "Y"); PGMSTR(Z_STR, "Z"); PGMSTR(E_STR, "E");
PGMSTR(X_LBL, "X:"); PGMSTR(Y_LBL, "Y:"); PGMSTR(Z_LBL, "Z:"); PGMSTR(E_LBL, "E:");
PGMSTR(SP_A_STR, " A"); PGMSTR(SP_B_STR, " B"); PGMSTR(SP_C_STR, " C");
PGMSTR(SP_X_STR, " X"); PGMSTR(SP_Y_STR, " Y"); PGMSTR(SP_Z_STR, " Z"); PGMSTR(SP_E_STR, " E");
PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
PGMSTR(I_STR, AXIS4_STR); PGMSTR(J_STR, AXIS5_STR); PGMSTR(K_STR, AXIS6_STR);
PGMSTR(I_LBL, AXIS4_STR ":"); PGMSTR(J_LBL, AXIS5_STR ":"); PGMSTR(K_LBL, AXIS6_STR ":");
PGMSTR(SP_I_STR, " " AXIS4_STR); PGMSTR(SP_J_STR, " " AXIS5_STR); PGMSTR(SP_K_STR, " " AXIS6_STR);
PGMSTR(SP_I_LBL, " " AXIS4_STR ":"); PGMSTR(SP_J_LBL, " " AXIS5_STR ":"); PGMSTR(SP_K_LBL, " " AXIS6_STR ":");
// Hook Meatpack if it's enabled on the first leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_1)
SerialLeafT1 mpSerial1(false, _SERIAL_LEAF_1);
#endif
#if ENABLED(MEATPACK_ON_SERIAL_PORT_2)
SerialLeafT2 mpSerial2(false, _SERIAL_LEAF_2);
#endif
#if ENABLED(MEATPACK_ON_SERIAL_PORT_3)
SerialLeafT3 mpSerial3(false, _SERIAL_LEAF_3);
#endif
// Step 2: For multiserial, handle the second serial port as well
#if HAS_MULTI_SERIAL
#if HAS_ETHERNET
// We need a definition here
SerialLeafT2 msSerial2(ethernet.have_telnet_client, MYSERIAL2, false);
#endif
#define __S_LEAF(N) ,SERIAL_LEAF_##N
#define _S_LEAF(N) __S_LEAF(N)
SerialOutputT multiSerial( SERIAL_LEAF_1 REPEAT_S(2, INCREMENT(NUM_SERIAL), _S_LEAF) );
#undef __S_LEAF
#undef _S_LEAF
#if NUM_SERIAL > 1
serial_index_t serial_port_index = 0;
#endif
void serialprintPGM(PGM_P str) {
while (const char c = pgm_read_byte(str++)) SERIAL_CHAR(c);
}
void serial_echo_start() { serialprintPGM(echomagic); }
void serial_error_start() { serialprintPGM(errormagic); }
void serial_echopair_PGM(PGM_P const s_P, const char *v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, char v) { serialprintPGM(s_P); SERIAL_CHAR(v); }
void serial_echopair_PGM(PGM_P const s_P, int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, float v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, double v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned int v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echopair_PGM(PGM_P const s_P, unsigned long v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
void serial_echo_start() { static PGMSTR(echomagic, "echo:"); serialprintPGM(echomagic); }
void serial_error_start() { static PGMSTR(errormagic, "Error:"); serialprintPGM(errormagic); }
void serial_spaces(uint8_t count) { count *= (PROPORTIONAL_FONT_RATIO); while (count--) SERIAL_CHAR(' '); }
@@ -65,10 +94,10 @@ void print_bin(uint16_t val) {
}
}
extern const char SP_X_STR[], SP_Y_STR[], SP_Z_STR[];
void print_xyz(const float &x, const float &y, const float &z, PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/) {
serialprintPGM(prefix);
SERIAL_ECHOPAIR_P(SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z);
void print_pos(LINEAR_AXIS_ARGS(const_float_t), PGM_P const prefix/*=nullptr*/, PGM_P const suffix/*=nullptr*/) {
if (prefix) serialprintPGM(prefix);
SERIAL_ECHOPGM_P(
LIST_N(DOUBLE(LINEAR_AXES), SP_X_STR, x, SP_Y_STR, y, SP_Z_STR, z, SP_I_STR, i, SP_J_STR, j, SP_K_STR, k)
);
if (suffix) serialprintPGM(suffix); else SERIAL_EOL();
}

View File

@@ -16,16 +16,34 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../inc/MarlinConfig.h"
#include "serial_hook.h"
/**
* Define debug bit-masks
*/
#if HAS_MEATPACK
#include "../feature/meatpack.h"
#endif
// Commonly-used strings in serial output
extern const char NUL_STR[],
SP_X_STR[], SP_Y_STR[], SP_Z_STR[],
SP_A_STR[], SP_B_STR[], SP_C_STR[], SP_E_STR[],
SP_X_LBL[], SP_Y_LBL[], SP_Z_LBL[], SP_E_LBL[],
SP_I_STR[], SP_J_STR[], SP_K_STR[],
SP_I_LBL[], SP_J_LBL[], SP_K_LBL[],
SP_P_STR[], SP_T_STR[],
X_STR[], Y_STR[], Z_STR[], E_STR[],
I_STR[], J_STR[], K_STR[],
X_LBL[], Y_LBL[], Z_LBL[], E_LBL[],
I_LBL[], J_LBL[], K_LBL[];
//
// Debugging flags for use by M111
//
enum MarlinDebugFlags : uint8_t {
MARLIN_DEBUG_NONE = 0,
MARLIN_DEBUG_ECHO = _BV(0), ///< Echo commands in order as they are processed
@@ -45,210 +63,203 @@ enum MarlinDebugFlags : uint8_t {
extern uint8_t marlin_debug_flags;
#define DEBUGGING(F) (marlin_debug_flags & (MARLIN_DEBUG_## F))
typedef int8_t serial_index_t;
#define SERIAL_BOTH 0x7F
#if NUM_SERIAL > 1
extern serial_index_t serial_port_index;
#define _PORT_REDIRECT(n,p) REMEMBER(n,serial_port_index,p)
#define _PORT_RESTORE(n) RESTORE(n)
#define SERIAL_OUT(WHAT, V...) do{ \
if (!serial_port_index || serial_port_index == SERIAL_BOTH) (void)MYSERIAL0.WHAT(V); \
if ( serial_port_index) (void)MYSERIAL1.WHAT(V); \
}while(0)
#define SERIAL_ASSERT(P) if(serial_port_index!=(P)){ debugger(); }
//
// Serial redirection
//
// Step 1: Find out what the first serial leaf is
#if HAS_MULTI_SERIAL && defined(SERIAL_CATCHALL)
#define _SERIAL_LEAF_1 MYSERIAL
#else
#define _PORT_REDIRECT(n,p) NOOP
#define _PORT_RESTORE(n) NOOP
#define SERIAL_OUT(WHAT, V...) (void)MYSERIAL0.WHAT(V)
#define SERIAL_ASSERT(P) NOOP
#define _SERIAL_LEAF_1 MYSERIAL1
#endif
#define PORT_REDIRECT(p) _PORT_REDIRECT(1,p)
#define PORT_RESTORE() _PORT_RESTORE(1)
#define SERIAL_ECHO(x) SERIAL_OUT(print, x)
#define SERIAL_ECHO_F(V...) SERIAL_OUT(print, V)
#define SERIAL_ECHOLN(x) SERIAL_OUT(println, x)
#define SERIAL_PRINT(x,b) SERIAL_OUT(print, x, b)
#define SERIAL_PRINTLN(x,b) SERIAL_OUT(println, x, b)
#define SERIAL_PRINTF(V...) SERIAL_OUT(printf, V)
#define SERIAL_FLUSH() SERIAL_OUT(flush)
#ifdef ARDUINO_ARCH_STM32
#define SERIAL_FLUSHTX() SERIAL_OUT(flush)
#elif TX_BUFFER_SIZE > 0
#define SERIAL_FLUSHTX() SERIAL_OUT(flushTX)
// Hook Meatpack if it's enabled on the first leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_1)
typedef MeatpackSerial<decltype(_SERIAL_LEAF_1)> SerialLeafT1;
extern SerialLeafT1 mpSerial1;
#define SERIAL_LEAF_1 mpSerial1
#else
#define SERIAL_FLUSHTX()
#define SERIAL_LEAF_1 _SERIAL_LEAF_1
#endif
// Print up to 10 chars from a list
#define __CHAR_N(N,V...) _CHAR_##N(V)
#define _CHAR_N(N,V...) __CHAR_N(N,V)
#define _CHAR_1(c) SERIAL_OUT(write, c)
#define _CHAR_2(a,b) do{ _CHAR_1(a); _CHAR_1(b); }while(0)
#define _CHAR_3(a,V...) do{ _CHAR_1(a); _CHAR_2(V); }while(0)
#define _CHAR_4(a,V...) do{ _CHAR_1(a); _CHAR_3(V); }while(0)
#define _CHAR_5(a,V...) do{ _CHAR_1(a); _CHAR_4(V); }while(0)
#define _CHAR_6(a,V...) do{ _CHAR_1(a); _CHAR_5(V); }while(0)
#define _CHAR_7(a,V...) do{ _CHAR_1(a); _CHAR_6(V); }while(0)
#define _CHAR_8(a,V...) do{ _CHAR_1(a); _CHAR_7(V); }while(0)
#define _CHAR_9(a,V...) do{ _CHAR_1(a); _CHAR_8(V); }while(0)
#define _CHAR_10(a,V...) do{ _CHAR_1(a); _CHAR_9(V); }while(0)
// Step 2: For multiserial wrap all serial ports in a single
// interface with the ability to output to multiple serial ports.
#if HAS_MULTI_SERIAL
#define _PORT_REDIRECT(n,p) REMEMBER(n,multiSerial.portMask,p)
#define _PORT_RESTORE(n,p) RESTORE(n)
#define SERIAL_ASSERT(P) if (multiSerial.portMask!=(P)) { debugger(); }
// If we have a catchall, use that directly
#ifdef SERIAL_CATCHALL
#define _SERIAL_LEAF_2 SERIAL_CATCHALL
#elif HAS_ETHERNET
typedef ConditionalSerial<decltype(MYSERIAL2)> SerialLeafT2; // We need to create an instance here
extern SerialLeafT2 msSerial2;
#define _SERIAL_LEAF_2 msSerial2
#else
#define _SERIAL_LEAF_2 MYSERIAL2 // Don't create a useless instance here, directly use the existing instance
#endif
#define SERIAL_CHAR(V...) _CHAR_N(NUM_ARGS(V),V)
// Nothing complicated here
#define _SERIAL_LEAF_3 MYSERIAL3
// Print up to 12 pairs of values. Odd elements auto-wrapped in PSTR().
#define __SEP_N(N,V...) _SEP_##N(V)
#define _SEP_N(N,V...) __SEP_N(N,V)
#define _SEP_1(PRE) SERIAL_ECHOPGM(PRE)
#define _SEP_2(PRE,V) serial_echopair_PGM(PSTR(PRE),V)
#define _SEP_3(a,b,c) do{ _SEP_2(a,b); SERIAL_ECHOPGM(c); }while(0)
#define _SEP_4(a,b,V...) do{ _SEP_2(a,b); _SEP_2(V); }while(0)
#define _SEP_5(a,b,V...) do{ _SEP_2(a,b); _SEP_3(V); }while(0)
#define _SEP_6(a,b,V...) do{ _SEP_2(a,b); _SEP_4(V); }while(0)
#define _SEP_7(a,b,V...) do{ _SEP_2(a,b); _SEP_5(V); }while(0)
#define _SEP_8(a,b,V...) do{ _SEP_2(a,b); _SEP_6(V); }while(0)
#define _SEP_9(a,b,V...) do{ _SEP_2(a,b); _SEP_7(V); }while(0)
#define _SEP_10(a,b,V...) do{ _SEP_2(a,b); _SEP_8(V); }while(0)
#define _SEP_11(a,b,V...) do{ _SEP_2(a,b); _SEP_9(V); }while(0)
#define _SEP_12(a,b,V...) do{ _SEP_2(a,b); _SEP_10(V); }while(0)
#define _SEP_13(a,b,V...) do{ _SEP_2(a,b); _SEP_11(V); }while(0)
#define _SEP_14(a,b,V...) do{ _SEP_2(a,b); _SEP_12(V); }while(0)
#define _SEP_15(a,b,V...) do{ _SEP_2(a,b); _SEP_13(V); }while(0)
#define _SEP_16(a,b,V...) do{ _SEP_2(a,b); _SEP_14(V); }while(0)
#define _SEP_17(a,b,V...) do{ _SEP_2(a,b); _SEP_15(V); }while(0)
#define _SEP_18(a,b,V...) do{ _SEP_2(a,b); _SEP_16(V); }while(0)
#define _SEP_19(a,b,V...) do{ _SEP_2(a,b); _SEP_17(V); }while(0)
#define _SEP_20(a,b,V...) do{ _SEP_2(a,b); _SEP_18(V); }while(0)
#define _SEP_21(a,b,V...) do{ _SEP_2(a,b); _SEP_19(V); }while(0)
#define _SEP_22(a,b,V...) do{ _SEP_2(a,b); _SEP_20(V); }while(0)
#define _SEP_23(a,b,V...) do{ _SEP_2(a,b); _SEP_21(V); }while(0)
#define _SEP_24(a,b,V...) do{ _SEP_2(a,b); _SEP_22(V); }while(0)
// Hook Meatpack if it's enabled on the second leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_2)
typedef MeatpackSerial<decltype(_SERIAL_LEAF_2)> SerialLeafT2;
extern SerialLeafT2 mpSerial2;
#define SERIAL_LEAF_2 mpSerial2
#else
#define SERIAL_LEAF_2 _SERIAL_LEAF_2
#endif
#define SERIAL_ECHOPAIR(V...) _SEP_N(NUM_ARGS(V),V)
// Hook Meatpack if it's enabled on the third leaf
#if ENABLED(MEATPACK_ON_SERIAL_PORT_3)
typedef MeatpackSerial<decltype(_SERIAL_LEAF_3)> SerialLeafT3;
extern SerialLeafT3 mpSerial3;
#define SERIAL_LEAF_3 mpSerial3
#else
#define SERIAL_LEAF_3 _SERIAL_LEAF_3
#endif
// Print up to 12 pairs of values. Odd elements must be PSTR pointers.
#define __SEP_N_P(N,V...) _SEP_##N##_P(V)
#define _SEP_N_P(N,V...) __SEP_N_P(N,V)
#define _SEP_1_P(PRE) serialprintPGM(PRE)
#define _SEP_2_P(PRE,V) serial_echopair_PGM(PRE,V)
#define _SEP_3_P(a,b,c) do{ _SEP_2_P(a,b); serialprintPGM(c); }while(0)
#define _SEP_4_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_2_P(V); }while(0)
#define _SEP_5_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_3_P(V); }while(0)
#define _SEP_6_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_4_P(V); }while(0)
#define _SEP_7_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_5_P(V); }while(0)
#define _SEP_8_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_6_P(V); }while(0)
#define _SEP_9_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_7_P(V); }while(0)
#define _SEP_10_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_8_P(V); }while(0)
#define _SEP_11_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_9_P(V); }while(0)
#define _SEP_12_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_10_P(V); }while(0)
#define _SEP_13_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_11_P(V); }while(0)
#define _SEP_14_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_12_P(V); }while(0)
#define _SEP_15_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_13_P(V); }while(0)
#define _SEP_16_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_14_P(V); }while(0)
#define _SEP_17_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_15_P(V); }while(0)
#define _SEP_18_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_16_P(V); }while(0)
#define _SEP_19_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_17_P(V); }while(0)
#define _SEP_20_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_18_P(V); }while(0)
#define _SEP_21_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_19_P(V); }while(0)
#define _SEP_22_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_20_P(V); }while(0)
#define _SEP_23_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_21_P(V); }while(0)
#define _SEP_24_P(a,b,V...) do{ _SEP_2_P(a,b); _SEP_22_P(V); }while(0)
#define __S_MULTI(N) decltype(SERIAL_LEAF_##N),
#define _S_MULTI(N) __S_MULTI(N)
#define SERIAL_ECHOPAIR_P(V...) _SEP_N_P(NUM_ARGS(V),V)
typedef MultiSerial< REPEAT_1(NUM_SERIAL, _S_MULTI) 0> SerialOutputT;
// Print up to 12 pairs of values followed by newline
#define __SELP_N(N,V...) _SELP_##N(V)
#define _SELP_N(N,V...) __SELP_N(N,V)
#define _SELP_1(PRE) SERIAL_ECHOLNPGM(PRE)
#define _SELP_2(PRE,V) do{ serial_echopair_PGM(PSTR(PRE),V); SERIAL_EOL(); }while(0)
#define _SELP_3(a,b,c) do{ _SEP_2(a,b); SERIAL_ECHOLNPGM(c); }while(0)
#define _SELP_4(a,b,V...) do{ _SEP_2(a,b); _SELP_2(V); }while(0)
#define _SELP_5(a,b,V...) do{ _SEP_2(a,b); _SELP_3(V); }while(0)
#define _SELP_6(a,b,V...) do{ _SEP_2(a,b); _SELP_4(V); }while(0)
#define _SELP_7(a,b,V...) do{ _SEP_2(a,b); _SELP_5(V); }while(0)
#define _SELP_8(a,b,V...) do{ _SEP_2(a,b); _SELP_6(V); }while(0)
#define _SELP_9(a,b,V...) do{ _SEP_2(a,b); _SELP_7(V); }while(0)
#define _SELP_10(a,b,V...) do{ _SEP_2(a,b); _SELP_8(V); }while(0)
#define _SELP_11(a,b,V...) do{ _SEP_2(a,b); _SELP_9(V); }while(0)
#define _SELP_12(a,b,V...) do{ _SEP_2(a,b); _SELP_10(V); }while(0)
#define _SELP_13(a,b,V...) do{ _SEP_2(a,b); _SELP_11(V); }while(0)
#define _SELP_14(a,b,V...) do{ _SEP_2(a,b); _SELP_12(V); }while(0)
#define _SELP_15(a,b,V...) do{ _SEP_2(a,b); _SELP_13(V); }while(0)
#define _SELP_16(a,b,V...) do{ _SEP_2(a,b); _SELP_14(V); }while(0)
#define _SELP_17(a,b,V...) do{ _SEP_2(a,b); _SELP_15(V); }while(0)
#define _SELP_18(a,b,V...) do{ _SEP_2(a,b); _SELP_16(V); }while(0)
#define _SELP_19(a,b,V...) do{ _SEP_2(a,b); _SELP_17(V); }while(0)
#define _SELP_20(a,b,V...) do{ _SEP_2(a,b); _SELP_18(V); }while(0)
#define _SELP_21(a,b,V...) do{ _SEP_2(a,b); _SELP_19(V); }while(0)
#define _SELP_22(a,b,V...) do{ _SEP_2(a,b); _SELP_20(V); }while(0)
#define _SELP_23(a,b,V...) do{ _SEP_2(a,b); _SELP_21(V); }while(0)
#define _SELP_24(a,b,V...) do{ _SEP_2(a,b); _SELP_22(V); }while(0) // Eat two args, pass the rest up
#undef __S_MULTI
#undef _S_MULTI
#define SERIAL_ECHOLNPAIR(V...) _SELP_N(NUM_ARGS(V),V)
extern SerialOutputT multiSerial;
#define SERIAL_IMPL multiSerial
#else
#define _PORT_REDIRECT(n,p) NOOP
#define _PORT_RESTORE(n) NOOP
#define SERIAL_ASSERT(P) NOOP
#define SERIAL_IMPL SERIAL_LEAF_1
#endif
// Print up to 12 pairs of values followed by newline
#define __SELP_N_P(N,V...) _SELP_##N##_P(V)
#define _SELP_N_P(N,V...) __SELP_N_P(N,V)
#define _SELP_1_P(PRE) serialprintPGM(PRE)
#define _SELP_2_P(PRE,V) do{ serial_echopair_PGM(PRE,V); SERIAL_EOL(); }while(0)
#define _SELP_3_P(a,b,c) do{ _SEP_2_P(a,b); serialprintPGM(c); }while(0)
#define _SELP_4_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_2_P(V); }while(0)
#define _SELP_5_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_3_P(V); }while(0)
#define _SELP_6_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_4_P(V); }while(0)
#define _SELP_7_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_5_P(V); }while(0)
#define _SELP_8_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_6_P(V); }while(0)
#define _SELP_9_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_7_P(V); }while(0)
#define _SELP_10_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_8_P(V); }while(0)
#define _SELP_11_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_9_P(V); }while(0)
#define _SELP_12_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_10_P(V); }while(0)
#define _SELP_13_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_11_P(V); }while(0)
#define _SELP_14_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_12_P(V); }while(0)
#define _SELP_15_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_13_P(V); }while(0)
#define _SELP_16_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_14_P(V); }while(0)
#define _SELP_17_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_15_P(V); }while(0)
#define _SELP_18_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_16_P(V); }while(0)
#define _SELP_19_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_17_P(V); }while(0)
#define _SELP_20_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_18_P(V); }while(0)
#define _SELP_21_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_19_P(V); }while(0)
#define _SELP_22_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_20_P(V); }while(0)
#define _SELP_23_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_21_P(V); }while(0)
#define _SELP_24_P(a,b,V...) do{ _SEP_2_P(a,b); _SELP_22_P(V); }while(0) // Eat two args, pass the rest up
#define SERIAL_OUT(WHAT, V...) (void)SERIAL_IMPL.WHAT(V)
#define SERIAL_ECHOLNPAIR_P(V...) _SELP_N_P(NUM_ARGS(V),V)
#define PORT_REDIRECT(p) _PORT_REDIRECT(1,p)
#define PORT_RESTORE() _PORT_RESTORE(1)
#define SERIAL_PORTMASK(P) SerialMask::from(P)
// Print up to 20 comma-separated pairs of values
#define __SLST_N(N,V...) _SLST_##N(V)
#define _SLST_N(N,V...) __SLST_N(N,V)
#define _SLST_1(a) SERIAL_ECHO(a)
#define _SLST_2(a,b) do{ SERIAL_ECHO(a); SERIAL_ECHOPAIR(", ",b); }while(0)
#define _SLST_3(a,b,c) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_1(c); }while(0)
#define _SLST_4(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_2(V); }while(0)
#define _SLST_5(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_3(V); }while(0)
#define _SLST_6(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_4(V); }while(0)
#define _SLST_7(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_5(V); }while(0)
#define _SLST_8(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_6(V); }while(0)
#define _SLST_9(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_7(V); }while(0)
#define _SLST_10(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_8(V); }while(0)
#define _SLST_11(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_9(V); }while(0)
#define _SLST_12(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_10(V); }while(0)
#define _SLST_13(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_11(V); }while(0)
#define _SLST_14(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_12(V); }while(0)
#define _SLST_15(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_13(V); }while(0)
#define _SLST_16(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_14(V); }while(0)
#define _SLST_17(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_15(V); }while(0)
#define _SLST_18(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_16(V); }while(0)
#define _SLST_19(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_17(V); }while(0)
#define _SLST_20(a,b,V...) do{ SERIAL_ECHO(a); _SEP_2(", ",b); _SLST_18(V); }while(0) // Eat two args, pass the rest up
//
// SERIAL_CHAR - Print one or more individual chars
//
inline void SERIAL_CHAR(char a) { SERIAL_IMPL.write(a); }
template <typename ... Args>
void SERIAL_CHAR(char a, Args ... args) { SERIAL_IMPL.write(a); SERIAL_CHAR(args ...); }
#define SERIAL_ECHOLIST(pre,V...) do{ SERIAL_ECHOPGM(pre); _SLST_N(NUM_ARGS(V),V); }while(0)
#define SERIAL_ECHOLIST_N(N,V...) _SLST_N(N,LIST_N(N,V))
/**
* SERIAL_ECHO - Print a single string or value.
* Any numeric parameter (including char) is printed as a base-10 number.
* A string pointer or literal will be output as a string.
*
* NOTE: Use SERIAL_CHAR to print char as a single character.
*/
template <typename T>
void SERIAL_ECHO(T x) { SERIAL_IMPL.print(x); }
#define SERIAL_ECHO_P(P) (serialprintPGM(P))
// Wrapper for ECHO commands to interpret a char
typedef struct SerialChar { char c; SerialChar(char n) : c(n) { } } serial_char_t;
inline void SERIAL_ECHO(serial_char_t x) { SERIAL_IMPL.write(x.c); }
#define AS_CHAR(C) serial_char_t(C)
#define AS_DIGIT(C) AS_CHAR('0' + (C))
#define SERIAL_ECHOPGM(S) (SERIAL_ECHO_P(PSTR(S)))
#define SERIAL_ECHOLNPGM(S) (SERIAL_ECHO_P(PSTR(S "\n")))
// SERIAL_ECHO_F prints a floating point value with optional precision
inline void SERIAL_ECHO_F(EnsureDouble x, int digit=2) { SERIAL_IMPL.print(x, digit); }
template <typename T>
void SERIAL_ECHOLN(T x) { SERIAL_IMPL.println(x); }
// SERIAL_PRINT works like SERIAL_ECHO but allow to specify the encoding base of the number printed
template <typename T, typename U>
void SERIAL_PRINT(T x, U y) { SERIAL_IMPL.print(x, y); }
template <typename T>
void SERIAL_PRINTLN(T x, PrintBase y) { SERIAL_IMPL.println(x, y); }
// Flush the serial port
inline void SERIAL_FLUSH() { SERIAL_IMPL.flush(); }
inline void SERIAL_FLUSHTX() { SERIAL_IMPL.flushTX(); }
// Print a single PROGMEM string to serial
void serialprintPGM(PGM_P str);
//
// SERIAL_ECHOPGM... macros are used to output string-value pairs.
//
// Print up to 20 pairs of values. Odd elements must be literal strings.
#define __SEP_N(N,V...) _SEP_##N(V)
#define _SEP_N(N,V...) __SEP_N(N,V)
#define _SEP_N_REF() _SEP_N
#define _SEP_1(s) serialprintPGM(PSTR(s));
#define _SEP_2(s,v) serial_echopair_PGM(PSTR(s),v);
#define _SEP_3(s,v,V...) _SEP_2(s,v); DEFER2(_SEP_N_REF)()(TWO_ARGS(V),V);
#define SERIAL_ECHOPGM(V...) do{ EVAL(_SEP_N(TWO_ARGS(V),V)); }while(0)
// Print up to 20 pairs of values followed by newline. Odd elements must be literal strings.
#define __SELP_N(N,V...) _SELP_##N(V)
#define _SELP_N(N,V...) __SELP_N(N,V)
#define _SELP_N_REF() _SELP_N
#define _SELP_1(s) serialprintPGM(PSTR(s "\n"));
#define _SELP_2(s,v) serial_echopair_PGM(PSTR(s),v); SERIAL_EOL();
#define _SELP_3(s,v,V...) _SEP_2(s,v); DEFER2(_SELP_N_REF)()(TWO_ARGS(V),V);
#define SERIAL_ECHOLNPGM(V...) do{ EVAL(_SELP_N(TWO_ARGS(V),V)); }while(0)
// Print up to 20 pairs of values. Odd elements must be PSTR pointers.
#define __SEP_N_P(N,V...) _SEP_##N##_P(V)
#define _SEP_N_P(N,V...) __SEP_N_P(N,V)
#define _SEP_N_P_REF() _SEP_N_P
#define _SEP_1_P(p) serialprintPGM(p);
#define _SEP_2_P(p,v) serial_echopair_PGM(p,v);
#define _SEP_3_P(p,v,V...) _SEP_2_P(p,v); DEFER2(_SEP_N_P_REF)()(TWO_ARGS(V),V);
#define SERIAL_ECHOPGM_P(V...) do{ EVAL(_SEP_N_P(TWO_ARGS(V),V)); }while(0)
// Print up to 20 pairs of values followed by newline. Odd elements must be PSTR pointers.
#define __SELP_N_P(N,V...) _SELP_##N##_P(V)
#define _SELP_N_P(N,V...) __SELP_N_P(N,V)
#define _SELP_N_P_REF() _SELP_N_P
#define _SELP_1_P(p) { serialprintPGM(p); SERIAL_EOL(); }
#define _SELP_2_P(p,v) { serial_echopair_PGM(p,v); SERIAL_EOL(); }
#define _SELP_3_P(p,v,V...) { _SEP_2_P(p,v); DEFER2(_SELP_N_P_REF)()(TWO_ARGS(V),V); }
#define SERIAL_ECHOLNPGM_P(V...) do{ EVAL(_SELP_N_P(TWO_ARGS(V),V)); }while(0)
#ifdef AllowDifferentTypeInList
inline void SERIAL_ECHOLIST_IMPL() {}
template <typename T>
void SERIAL_ECHOLIST_IMPL(T && t) { SERIAL_IMPL.print(t); }
template <typename T, typename ... Args>
void SERIAL_ECHOLIST_IMPL(T && t, Args && ... args) {
SERIAL_IMPL.print(t);
serialprintPGM(PSTR(", "));
SERIAL_ECHOLIST_IMPL(args...);
}
template <typename ... Args>
void SERIAL_ECHOLIST(PGM_P const str, Args && ... args) {
SERIAL_IMPL.print(str);
SERIAL_ECHOLIST_IMPL(args...);
}
#else // Optimization if the listed type are all the same (seems to be the case in the codebase so use that instead)
template <typename ... Args>
void SERIAL_ECHOLIST(PGM_P const str, Args && ... args) {
serialprintPGM(str);
typename Private::first_type_of<Args...>::type values[] = { args... };
constexpr size_t argsSize = sizeof...(args);
for (size_t i = 0; i < argsSize; i++) {
if (i) serialprintPGM(PSTR(", "));
SERIAL_IMPL.print(values[i]);
}
}
#endif
#define SERIAL_ECHOPAIR_F_P(P,V...) do{ serialprintPGM(P); SERIAL_ECHO_F(V); }while(0)
#define SERIAL_ECHOLNPAIR_F_P(V...) do{ SERIAL_ECHOPAIR_F_P(V); SERIAL_EOL(); }while(0)
@@ -260,29 +271,35 @@ typedef int8_t serial_index_t;
#define SERIAL_ERROR_START() serial_error_start()
#define SERIAL_EOL() SERIAL_CHAR('\n')
#define SERIAL_ECHO_MSG(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPAIR(V); }while(0)
#define SERIAL_ERROR_MSG(V...) do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPAIR(V); }while(0)
#define SERIAL_ECHO_MSG(V...) do{ SERIAL_ECHO_START(); SERIAL_ECHOLNPGM(V); }while(0)
#define SERIAL_ERROR_MSG(V...) do{ SERIAL_ERROR_START(); SERIAL_ECHOLNPGM(V); }while(0)
#define SERIAL_ECHO_SP(C) serial_spaces(C)
#define SERIAL_ECHO_TERNARY(TF, PRE, ON, OFF, POST) serial_ternary(TF, PSTR(PRE), PSTR(ON), PSTR(OFF), PSTR(POST))
#if SERIAL_FLOAT_PRECISION
#define SERIAL_DECIMAL(V) SERIAL_PRINT(V, SERIAL_FLOAT_PRECISION)
#else
#define SERIAL_DECIMAL(V) SERIAL_ECHO(V)
#endif
//
// Functions for serial printing from PROGMEM. (Saves loads of SRAM.)
//
void serial_echopair_PGM(PGM_P const s_P, const char *v);
void serial_echopair_PGM(PGM_P const s_P, char v);
void serial_echopair_PGM(PGM_P const s_P, int v);
void serial_echopair_PGM(PGM_P const s_P, long v);
void serial_echopair_PGM(PGM_P const s_P, float v);
void serial_echopair_PGM(PGM_P const s_P, double v);
void serial_echopair_PGM(PGM_P const s_P, unsigned int v);
void serial_echopair_PGM(PGM_P const s_P, unsigned long v);
inline void serial_echopair_PGM(PGM_P const s_P, uint8_t v) { serial_echopair_PGM(s_P, (int)v); }
inline void serial_echopair_PGM(PGM_P const s_P, bool v) { serial_echopair_PGM(s_P, (int)v); }
inline void serial_echopair_PGM(PGM_P const s_P, void *v) { serial_echopair_PGM(s_P, (unsigned long)v); }
inline void serial_echopair_PGM(PGM_P const s_P, serial_char_t v) { serialprintPGM(s_P); SERIAL_CHAR(v.c); }
inline void serial_echopair_PGM(PGM_P const s_P, float v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
inline void serial_echopair_PGM(PGM_P const s_P, double v) { serialprintPGM(s_P); SERIAL_DECIMAL(v); }
inline void serial_echopair_PGM(PGM_P const s_P, const char *v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
// Default implementation for types without a specialization. Handles integers.
template <typename T>
void serial_echopair_PGM(PGM_P const s_P, T v) { serialprintPGM(s_P); SERIAL_ECHO(v); }
inline void serial_echopair_PGM(PGM_P const s_P, bool v) { serial_echopair_PGM(s_P, (int)v); }
inline void serial_echopair_PGM(PGM_P const s_P, void *v) { serial_echopair_PGM(s_P, (uintptr_t)v); }
void serialprintPGM(PGM_P str);
void serial_echo_start();
void serial_error_start();
void serial_ternary(const bool onoff, PGM_P const pre, PGM_P const on, PGM_P const off, PGM_P const post=nullptr);
@@ -292,11 +309,11 @@ void serialprint_truefalse(const bool tf);
void serial_spaces(uint8_t count);
void print_bin(const uint16_t val);
void print_xyz(const float &x, const float &y, const float &z, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr);
void print_pos(LINEAR_AXIS_ARGS(const_float_t), PGM_P const prefix=nullptr, PGM_P const suffix=nullptr);
inline void print_xyz(const xyz_pos_t &xyz, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr) {
print_xyz(xyz.x, xyz.y, xyz.z, prefix, suffix);
inline void print_pos(const xyz_pos_t &xyz, PGM_P const prefix=nullptr, PGM_P const suffix=nullptr) {
print_pos(LINEAR_AXIS_ELEM(xyz), prefix, suffix);
}
#define SERIAL_POS(SUFFIX,VAR) do { print_xyz(VAR, PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n")); }while(0)
#define SERIAL_XYZ(PREFIX,V...) do { print_xyz(V, PSTR(PREFIX), nullptr); }while(0)
#define SERIAL_POS(SUFFIX,VAR) do { print_pos(VAR, PSTR(" " STRINGIFY(VAR) "="), PSTR(" : " SUFFIX "\n")); }while(0)
#define SERIAL_XYZ(PREFIX,V...) do { print_pos(V, PSTR(PREFIX), nullptr); }while(0)

View File

@@ -0,0 +1,258 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "../inc/MarlinConfigPre.h"
#if ENABLED(EMERGENCY_PARSER)
#include "../feature/e_parser.h"
#endif
// Used in multiple places
// You can build it but not manipulate it.
// There are only few places where it's required to access the underlying member: GCodeQueue, SerialMask and MultiSerial
struct serial_index_t {
// A signed index, where -1 is a special case meaning no action (neither output or input)
int8_t index;
// Check if the index is within the range [a ... b]
constexpr inline bool within(const int8_t a, const int8_t b) const { return WITHIN(index, a, b); }
constexpr inline bool valid() const { return WITHIN(index, 0, 7); } // At most, 8 bits
// Construction is either from an index
constexpr serial_index_t(const int8_t index) : index(index) {}
// Default to "no index"
constexpr serial_index_t() : index(-1) {}
};
// In order to catch usage errors in code, we make the base to encode number explicit
// If given a number (and not this enum), the compiler will reject the overload, falling back to the (double, digit) version
// We don't want hidden conversion of the first parameter to double, so it has to be as hard to do for the compiler as creating this enum
enum class PrintBase {
Dec = 10,
Hex = 16,
Oct = 8,
Bin = 2
};
// A simple feature list enumeration
enum class SerialFeature {
None = 0x00,
MeatPack = 0x01, //!< Enabled when Meatpack is present
BinaryFileTransfer = 0x02, //!< Enabled for BinaryFile transfer support (in the future)
Virtual = 0x04, //!< Enabled for virtual serial port (like Telnet / Websocket / ...)
Hookable = 0x08, //!< Enabled if the serial class supports a setHook method
};
ENUM_FLAGS(SerialFeature);
// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
CALL_IF_EXISTS_IMPL(void, flushTX);
CALL_IF_EXISTS_IMPL(bool, connected, true);
CALL_IF_EXISTS_IMPL(SerialFeature, features, SerialFeature::None);
// A simple forward struct to prevent the compiler from selecting print(double, int) as a default overload
// for any type other than double/float. For double/float, a conversion exists so the call will be invisible.
struct EnsureDouble {
double a;
operator double() { return a; }
// If the compiler breaks on ambiguity here, it's likely because print(X, base) is called with X not a double/float, and
// a base that's not a PrintBase value. This code is made to detect the error. You MUST set a base explicitly like this:
// SERIAL_PRINT(v, PrintBase::Hex)
EnsureDouble(double a) : a(a) {}
EnsureDouble(float a) : a(a) {}
};
// Using Curiously-Recurring Template Pattern here to avoid virtual table cost when compiling.
// Since the real serial class is known at compile time, this results in the compiler writing
// a completely efficient code.
template <class Child>
struct SerialBase {
#if ENABLED(EMERGENCY_PARSER)
const bool ep_enabled;
EmergencyParser::State emergency_state;
inline bool emergency_parser_enabled() { return ep_enabled; }
SerialBase(bool ep_capable) : ep_enabled(ep_capable), emergency_state(EmergencyParser::State::EP_RESET) {}
#else
SerialBase(const bool) {}
#endif
#define SerialChild static_cast<Child*>(this)
// Static dispatch methods below:
// The most important method here is where it all ends to:
void write(uint8_t c) { SerialChild->write(c); }
// Called when the parser finished processing an instruction, usually build to nothing
void msgDone() const { SerialChild->msgDone(); }
// Called on initialization
void begin(const long baudRate) { SerialChild->begin(baudRate); }
// Called on destruction
void end() { SerialChild->end(); }
/** Check for available data from the port
@param index The port index, usually 0 */
int available(serial_index_t index=0) const { return SerialChild->available(index); }
/** Read a value from the port
@param index The port index, usually 0 */
int read(serial_index_t index=0) { return SerialChild->read(index); }
/** Combine the features of this serial instance and return it
@param index The port index, usually 0 */
SerialFeature features(serial_index_t index=0) const { return static_cast<const Child*>(this)->features(index); }
// Check if the serial port has a feature
bool has_feature(serial_index_t index, SerialFeature flag) const { return (features(index) & flag) != SerialFeature::None; }
// Check if the serial port is connected (usually bypassed)
bool connected() const { return SerialChild->connected(); }
// Redirect flush
void flush() { SerialChild->flush(); }
// Not all implementation have a flushTX, so let's call them only if the child has the implementation
void flushTX() { CALL_IF_EXISTS(void, SerialChild, flushTX); }
// Glue code here
void write(const char *str) { while (*str) write(*str++); }
void write(const uint8_t *buffer, size_t size) { while (size--) write(*buffer++); }
void print(char *str) { write(str); }
void print(const char *str) { write(str); }
// No default argument to avoid ambiguity
// Define print for every fundamental integer type, to ensure that all redirect properly
// to the correct underlying implementation.
// Prints are performed with a single size, to avoid needing multiple print functions.
// The fixed integer size used for prints will be the larger of long or a pointer.
#if __LONG_WIDTH__ >= __INTPTR_WIDTH__
typedef long int_fixed_print_t;
typedef unsigned long uint_fixed_print_t;
#else
typedef intptr_t int_fixed_print_t;
typedef uintptr_t uint_fixed_print_t;
FORCE_INLINE void print(intptr_t c, PrintBase base) { printNumber_signed(c, base); }
FORCE_INLINE void print(uintptr_t c, PrintBase base) { printNumber_unsigned(c, base); }
#endif
FORCE_INLINE void print(char c, PrintBase base) { printNumber_signed(c, base); }
FORCE_INLINE void print(short c, PrintBase base) { printNumber_signed(c, base); }
FORCE_INLINE void print(int c, PrintBase base) { printNumber_signed(c, base); }
FORCE_INLINE void print(long c, PrintBase base) { printNumber_signed(c, base); }
FORCE_INLINE void print(unsigned char c, PrintBase base) { printNumber_unsigned(c, base); }
FORCE_INLINE void print(unsigned short c, PrintBase base) { printNumber_unsigned(c, base); }
FORCE_INLINE void print(unsigned int c, PrintBase base) { printNumber_unsigned(c, base); }
FORCE_INLINE void print(unsigned long c, PrintBase base) { printNumber_unsigned(c, base); }
void print(EnsureDouble c, int digits) { printFloat(c, digits); }
// Forward the call to the former's method
// Default implementation for anything without a specialization
// This handles integers since they are the most common
template <typename T>
void print(T c) { print(c, PrintBase::Dec); }
void print(float c) { print(c, 2); }
void print(double c) { print(c, 2); }
void println(char *s) { print(s); println(); }
void println(const char *s) { print(s); println(); }
void println(float c, int digits) { print(c, digits); println(); }
void println(double c, int digits) { print(c, digits); println(); }
void println() { write('\r'); write('\n'); }
// Default implementations for types without a specialization. Handles integers.
template <typename T>
void println(T c, PrintBase base) { print(c, base); println(); }
template <typename T>
void println(T c) { println(c, PrintBase::Dec); }
// Forward the call to the former's method
void println(float c) { println(c, 2); }
void println(double c) { println(c, 2); }
// Print a number with the given base
NO_INLINE void printNumber_unsigned(uint_fixed_print_t n, PrintBase base) {
if (n) {
unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
int8_t i = 0;
while (n) {
buf[i++] = n % (uint_fixed_print_t)base;
n /= (uint_fixed_print_t)base;
}
while (i--) write((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
}
else write('0');
}
NO_INLINE void printNumber_signed(int_fixed_print_t n, PrintBase base) {
if (base == PrintBase::Dec && n < 0) {
n = -n; // This works because all platforms Marlin's builds on are using 2-complement encoding for negative number
// On such CPU, changing the sign of a number is done by inverting the bits and adding one, so if n = 0x80000000 = -2147483648 then
// -n = 0x7FFFFFFF + 1 => 0x80000000 = 2147483648 (if interpreted as unsigned) or -2147483648 if interpreted as signed.
// On non 2-complement CPU, there would be no possible representation for 2147483648.
write('-');
}
printNumber_unsigned((uint_fixed_print_t)n , base);
}
// Print a decimal number
NO_INLINE void printFloat(double number, uint8_t digits) {
// Handle negative numbers
if (number < 0.0) {
write('-');
number = -number;
}
// Round correctly so that print(1.999, 2) prints as "2.00"
double rounding = 0.5;
LOOP_L_N(i, digits) rounding *= 0.1;
number += rounding;
// Extract the integer part of the number and print it
unsigned long int_part = (unsigned long)number;
double remainder = number - (double)int_part;
printNumber_unsigned(int_part, PrintBase::Dec);
// Print the decimal point, but only if there are digits beyond
if (digits) {
write('.');
// Extract digits from the remainder one at a time
while (digits--) {
remainder *= 10.0;
unsigned long toPrint = (unsigned long)remainder;
printNumber_unsigned(toPrint, PrintBase::Dec);
remainder -= toPrint;
}
}
}
};
// All serial instances will be built by chaining the features required
// for the function in the form of a template type definition.

View File

@@ -0,0 +1,306 @@
/**
* Marlin 3D Printer Firmware
* Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
*
* Based on Sprinter and grbl.
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "serial_base.h"
// A mask containing a bitmap of the serial port to act upon
// This is written to ensure a serial index is never used as a serial mask
class SerialMask {
uint8_t mask;
// This constructor is private to ensure you can't convert an index to a mask
// The compiler will stop here if you are mixing index and mask in your code.
// If you need to, you'll have to use the explicit static "from" method here
SerialMask(const serial_index_t);
public:
inline constexpr bool enabled(const SerialMask PortMask) const { return mask & PortMask.mask; }
inline constexpr SerialMask combine(const SerialMask other) const { return SerialMask(mask | other.mask); }
inline constexpr SerialMask operator<< (const int offset) const { return SerialMask(mask << offset); }
static inline SerialMask from(const serial_index_t index) {
if (index.valid()) return SerialMask(_BV(index.index));
return SerialMask(0); // A invalid index mean no output
}
constexpr SerialMask(const uint8_t mask) : mask(mask) {}
constexpr SerialMask(const SerialMask & other) : mask(other.mask) {} // Can't use = default here since not all framework support this
static constexpr uint8_t All = 0xFF;
};
// The most basic serial class: it dispatch to the base serial class with no hook whatsoever. This will compile to nothing but the base serial class
template <class SerialT>
struct BaseSerial : public SerialBase< BaseSerial<SerialT> >, public SerialT {
typedef SerialBase< BaseSerial<SerialT> > BaseClassT;
// It's required to implement a write method here to help compiler disambiguate what method to call
using SerialT::write;
using SerialT::flush;
void msgDone() {}
// We don't care about indices here, since if one can call us, it's the right index anyway
int available(serial_index_t) { return (int)SerialT::available(); }
int read(serial_index_t) { return (int)SerialT::read(); }
bool connected() { return CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected);; }
void flushTX() { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
SerialFeature features(serial_index_t index) const { return CALL_IF_EXISTS(SerialFeature, static_cast<const SerialT*>(this), features, index); }
// Two implementations of the same method exist in both base classes so indicate the right one
using SerialT::available;
using SerialT::read;
using SerialT::begin;
using SerialT::end;
using BaseClassT::print;
using BaseClassT::println;
BaseSerial(const bool e) : BaseClassT(e) {}
// Forward constructor
template <typename... Args>
BaseSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...) {}
};
// A serial with a condition checked at runtime for its output
// A bit less efficient than static dispatching but since it's only used for ethernet's serial output right now, it's ok.
template <class SerialT>
struct ConditionalSerial : public SerialBase< ConditionalSerial<SerialT> > {
typedef SerialBase< ConditionalSerial<SerialT> > BaseClassT;
bool & condition;
SerialT & out;
NO_INLINE size_t write(uint8_t c) { if (condition) return out.write(c); return 0; }
void flush() { if (condition) out.flush(); }
void begin(long br) { out.begin(br); }
void end() { out.end(); }
void msgDone() {}
bool connected() { return CALL_IF_EXISTS(bool, &out, connected); }
void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); }
int available(serial_index_t) { return (int)out.available(); }
int read(serial_index_t) { return (int)out.read(); }
int available() { return (int)out.available(); }
int read() { return (int)out.read(); }
SerialFeature features(serial_index_t index) const { return CALL_IF_EXISTS(SerialFeature, &out, features, index); }
ConditionalSerial(bool & conditionVariable, SerialT & out, const bool e) : BaseClassT(e), condition(conditionVariable), out(out) {}
};
// A simple forward class that taking a reference to an existing serial instance (likely created in their respective framework)
template <class SerialT>
struct ForwardSerial : public SerialBase< ForwardSerial<SerialT> > {
typedef SerialBase< ForwardSerial<SerialT> > BaseClassT;
SerialT & out;
NO_INLINE size_t write(uint8_t c) { return out.write(c); }
void flush() { out.flush(); }
void begin(long br) { out.begin(br); }
void end() { out.end(); }
void msgDone() {}
// Existing instances implement Arduino's operator bool, so use that if it's available
bool connected() { return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
void flushTX() { CALL_IF_EXISTS(void, &out, flushTX); }
int available(serial_index_t) { return (int)out.available(); }
int read(serial_index_t) { return (int)out.read(); }
int available() { return (int)out.available(); }
int read() { return (int)out.read(); }
SerialFeature features(serial_index_t index) const { return CALL_IF_EXISTS(SerialFeature, &out, features, index); }
ForwardSerial(const bool e, SerialT & out) : BaseClassT(e), out(out) {}
};
// A class that can be hooked and unhooked at runtime, useful to capture the output of the serial interface
template <class SerialT>
struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public SerialT {
typedef SerialBase< RuntimeSerial<SerialT> > BaseClassT;
typedef void (*WriteHook)(void * userPointer, uint8_t c);
typedef void (*EndOfMessageHook)(void * userPointer);
WriteHook writeHook;
EndOfMessageHook eofHook;
void * userPointer;
NO_INLINE size_t write(uint8_t c) {
if (writeHook) writeHook(userPointer, c);
return SerialT::write(c);
}
NO_INLINE void msgDone() {
if (eofHook) eofHook(userPointer);
}
int available(serial_index_t) { return (int)SerialT::available(); }
int read(serial_index_t) { return (int)SerialT::read(); }
using SerialT::available;
using SerialT::read;
using SerialT::flush;
using SerialT::begin;
using SerialT::end;
using BaseClassT::print;
using BaseClassT::println;
// Underlying implementation might use Arduino's bool operator
bool connected() {
return Private::HasMember_connected<SerialT>::value
? CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected)
: static_cast<SerialT*>(this)->operator bool();
}
void flushTX() { CALL_IF_EXISTS(void, static_cast<SerialT*>(this), flushTX); }
// Append Hookable for this class
SerialFeature features(serial_index_t index) const { return SerialFeature::Hookable | CALL_IF_EXISTS(SerialFeature, static_cast<const SerialT*>(this), features, index); }
void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
// Order is important here as serial code can be called inside interrupts
// When setting a hook, the user pointer must be set first so if writeHook is called as soon as it's set, it'll be valid
if (userPointer) this->userPointer = userPointer;
this->writeHook = writeHook;
this->eofHook = eofHook;
// Order is important here because of asynchronous access here
// When unsetting a hook, the user pointer must be unset last so that any pending writeHook is still using the old pointer
if (!userPointer) this->userPointer = 0;
}
RuntimeSerial(const bool e) : BaseClassT(e), writeHook(0), eofHook(0), userPointer(0) {}
// Forward constructor
template <typename... Args>
RuntimeSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...), writeHook(0), eofHook(0), userPointer(0) {}
};
#define _S_CLASS(N) class Serial##N##T,
#define _S_NAME(N) Serial##N##T,
template < REPEAT(NUM_SERIAL, _S_CLASS) const uint8_t offset=0, const uint8_t step=1 >
struct MultiSerial : public SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > {
typedef SerialBase< MultiSerial< REPEAT(NUM_SERIAL, _S_NAME) offset, step > > BaseClassT;
#undef _S_CLASS
#undef _S_NAME
SerialMask portMask;
#define _S_DECLARE(N) Serial##N##T & serial##N;
REPEAT(NUM_SERIAL, _S_DECLARE);
#undef _S_DECLARE
static constexpr uint8_t Usage = _BV(step) - 1; // A bit mask containing 'step' bits
#define _OUT_PORT(N) (Usage << (offset + (step * N))),
static constexpr uint8_t output[] = { REPEAT(NUM_SERIAL, _OUT_PORT) };
#undef _OUT_PORT
#define _OUT_MASK(N) | output[N]
static constexpr uint8_t ALL = 0 REPEAT(NUM_SERIAL, _OUT_MASK);
#undef _OUT_MASK
NO_INLINE void write(uint8_t c) {
#define _S_WRITE(N) if (portMask.enabled(output[N])) serial##N.write(c);
REPEAT(NUM_SERIAL, _S_WRITE);
#undef _S_WRITE
}
NO_INLINE void msgDone() {
#define _S_DONE(N) if (portMask.enabled(output[N])) serial##N.msgDone();
REPEAT(NUM_SERIAL, _S_DONE);
#undef _S_DONE
}
int available(serial_index_t index) {
uint8_t pos = offset;
#define _S_AVAILABLE(N) if (index.within(pos, pos + step - 1)) return serial##N.available(index); else pos += step;
REPEAT(NUM_SERIAL, _S_AVAILABLE);
#undef _S_AVAILABLE
return false;
}
int read(serial_index_t index) {
uint8_t pos = offset;
#define _S_READ(N) if (index.within(pos, pos + step - 1)) return serial##N.read(index); else pos += step;
REPEAT(NUM_SERIAL, _S_READ);
#undef _S_READ
return -1;
}
void begin(const long br) {
#define _S_BEGIN(N) if (portMask.enabled(output[N])) serial##N.begin(br);
REPEAT(NUM_SERIAL, _S_BEGIN);
#undef _S_BEGIN
}
void end() {
#define _S_END(N) if (portMask.enabled(output[N])) serial##N.end();
REPEAT(NUM_SERIAL, _S_END);
#undef _S_END
}
bool connected() {
bool ret = true;
#define _S_CONNECTED(N) if (portMask.enabled(output[N]) && !CALL_IF_EXISTS(bool, &serial##N, connected)) ret = false;
REPEAT(NUM_SERIAL, _S_CONNECTED);
#undef _S_CONNECTED
return ret;
}
using BaseClassT::available;
using BaseClassT::read;
// Redirect flush
NO_INLINE void flush() {
#define _S_FLUSH(N) if (portMask.enabled(output[N])) serial##N.flush();
REPEAT(NUM_SERIAL, _S_FLUSH);
#undef _S_FLUSH
}
NO_INLINE void flushTX() {
#define _S_FLUSHTX(N) if (portMask.enabled(output[N])) CALL_IF_EXISTS(void, &serial0, flushTX);
REPEAT(NUM_SERIAL, _S_FLUSHTX);
#undef _S_FLUSHTX
}
// Forward feature queries
SerialFeature features(serial_index_t index) const {
uint8_t pos = offset;
#define _S_FEATURES(N) if (index.within(pos, pos + step - 1)) return serial##N.features(index); else pos += step;
REPEAT(NUM_SERIAL, _S_FEATURES);
#undef _S_FEATURES
return SerialFeature::None;
}
#define _S_REFS(N) Serial##N##T & serial##N,
#define _S_INIT(N) ,serial##N (serial##N)
MultiSerial(REPEAT(NUM_SERIAL, _S_REFS) const SerialMask mask = ALL, const bool e = false)
: BaseClassT(e), portMask(mask) REPEAT(NUM_SERIAL, _S_INIT) {}
};
// Build the actual serial object depending on current configuration
#define Serial1Class TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, BaseSerial)
#define ForwardSerial1Class TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, ForwardSerial)
#ifdef HAS_MULTI_SERIAL
#define Serial2Class ConditionalSerial
#if NUM_SERIAL >= 3
#define Serial3Class ConditionalSerial
#endif
#endif

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -27,35 +27,11 @@
#include "../inc/MarlinConfigPre.h"
class __FlashStringHelper;
typedef const __FlashStringHelper *progmem_str;
//
// Enumerated axis indices
//
// - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space
// - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians
// - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics
//
enum AxisEnum : uint8_t {
X_AXIS = 0, A_AXIS = 0,
Y_AXIS = 1, B_AXIS = 1,
Z_AXIS = 2, C_AXIS = 2,
E_AXIS = 3,
X_HEAD = 4, Y_HEAD = 5, Z_HEAD = 6,
E0_AXIS = 3,
E1_AXIS, E2_AXIS, E3_AXIS, E4_AXIS, E5_AXIS, E6_AXIS, E7_AXIS,
ALL_AXES = 0xFE, NO_AXIS = 0xFF
};
//
// Loop over XYZE axes
//
#define LOOP_XYZ(VAR) LOOP_S_LE_N(VAR, X_AXIS, Z_AXIS)
#define LOOP_XYZE(VAR) LOOP_S_LE_N(VAR, X_AXIS, E_AXIS)
#define LOOP_XYZE_N(VAR) LOOP_S_L_N(VAR, X_AXIS, XYZE_N)
#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS)
#define LOOP_ABCE(VAR) LOOP_S_LE_N(VAR, A_AXIS, E_AXIS)
#define LOOP_ABCE_N(VAR) LOOP_S_L_N(VAR, A_AXIS, XYZE_N)
typedef const __FlashStringHelper* FSTR_P;
#ifndef FPSTR
#define FPSTR(S) (reinterpret_cast<FSTR_P>(S))
#endif
#define FTOP(S) (reinterpret_cast<const char*>(S))
//
// Conditional type assignment magic. For example...
@@ -67,22 +43,120 @@ struct IF { typedef R type; };
template <class L, class R>
struct IF<true, L, R> { typedef L type; };
#define LINEAR_AXIS_GANG(V...) GANG_N(LINEAR_AXES, V)
#define LINEAR_AXIS_CODE(V...) CODE_N(LINEAR_AXES, V)
#define LINEAR_AXIS_LIST(V...) LIST_N(LINEAR_AXES, V)
#define LINEAR_AXIS_ARRAY(V...) { LINEAR_AXIS_LIST(V) }
#define LINEAR_AXIS_ARGS(T...) LINEAR_AXIS_LIST(T x, T y, T z, T i, T j, T k)
#define LINEAR_AXIS_ELEM(O) LINEAR_AXIS_LIST(O.x, O.y, O.z, O.i, O.j, O.k)
#define LINEAR_AXIS_DEFS(T,V) LINEAR_AXIS_LIST(T x=V, T y=V, T z=V, T i=V, T j=V, T k=V)
#define LOGICAL_AXIS_GANG(E,V...) LINEAR_AXIS_GANG(V) GANG_ITEM_E(E)
#define LOGICAL_AXIS_CODE(E,V...) LINEAR_AXIS_CODE(V) CODE_ITEM_E(E)
#define LOGICAL_AXIS_LIST(E,V...) LINEAR_AXIS_LIST(V) LIST_ITEM_E(E)
#define LOGICAL_AXIS_ARRAY(E,V...) { LOGICAL_AXIS_LIST(E,V) }
#define LOGICAL_AXIS_ARGS(T...) LOGICAL_AXIS_LIST(T e, T x, T y, T z, T i, T j, T k)
#define LOGICAL_AXIS_ELEM(O) LOGICAL_AXIS_LIST(O.e, O.x, O.y, O.z, O.i, O.j, O.k)
#define LOGICAL_AXIS_DECL(T,V) LOGICAL_AXIS_LIST(T e=V, T x=V, T y=V, T z=V, T i=V, T j=V, T k=V)
#define LOGICAL_AXES_STRING LOGICAL_AXIS_GANG("E", "X", "Y", "Z", AXIS4_STR, AXIS5_STR, AXIS6_STR)
#if HAS_EXTRUDERS
#define LIST_ITEM_E(N) , N
#define CODE_ITEM_E(N) ; N
#define GANG_ITEM_E(N) N
#else
#define LIST_ITEM_E(N)
#define CODE_ITEM_E(N)
#define GANG_ITEM_E(N)
#endif
//
// Enumerated axis indices
//
// - X_AXIS, Y_AXIS, and Z_AXIS should be used for axes in Cartesian space
// - A_AXIS, B_AXIS, and C_AXIS should be used for Steppers, corresponding to XYZ on Cartesians
// - X_HEAD, Y_HEAD, and Z_HEAD should be used for Steppers on Core kinematics
//
enum AxisEnum : uint8_t {
// Linear axes may be controlled directly or indirectly
LINEAR_AXIS_LIST(X_AXIS, Y_AXIS, Z_AXIS, I_AXIS, J_AXIS, K_AXIS)
// Extruder axes may be considered distinctly
#define _EN_ITEM(N) , E##N##_AXIS
REPEAT(EXTRUDERS, _EN_ITEM)
#undef _EN_ITEM
// Core also keeps toolhead directions
#if EITHER(IS_CORE, MARKFORGED_XY)
, X_HEAD, Y_HEAD, Z_HEAD
#endif
// Distinct axes, including all E and Core
, NUM_AXIS_ENUMS
// Most of the time we refer only to the single E_AXIS
#if HAS_EXTRUDERS
, E_AXIS = E0_AXIS
#endif
// A, B, and C are for DELTA, SCARA, etc.
, A_AXIS = X_AXIS
#if LINEAR_AXES >= 2
, B_AXIS = Y_AXIS
#endif
#if LINEAR_AXES >= 3
, C_AXIS = Z_AXIS
#endif
// To refer to all or none
, ALL_AXES_ENUM = 0xFE, NO_AXIS_ENUM = 0xFF
};
typedef IF<(NUM_AXIS_ENUMS > 8), uint16_t, uint8_t>::type axis_bits_t;
//
// Loop over axes
//
#define LOOP_ABC(VAR) LOOP_S_LE_N(VAR, A_AXIS, C_AXIS)
#define LOOP_LINEAR_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LINEAR_AXES)
#define LOOP_LOGICAL_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, LOGICAL_AXES)
#define LOOP_DISTINCT_AXES(VAR) LOOP_S_L_N(VAR, X_AXIS, DISTINCT_AXES)
//
// feedRate_t is just a humble float
//
typedef float feedRate_t;
//
// celsius_t is the native unit of temperature. Signed to handle a disconnected thermistor value (-14).
// For more resolition (e.g., for a chocolate printer) this may later be changed to Celsius x 100
//
typedef int16_t celsius_t;
typedef float celsius_float_t;
//
// On AVR pointers are only 2 bytes so use 'const float &' for 'const float'
//
#ifdef __AVR__
typedef const float & const_float_t;
#else
typedef const float const_float_t;
#endif
typedef const_float_t const_feedRate_t;
typedef const_float_t const_celsius_float_t;
// Conversion macros
#define MMM_TO_MMS(MM_M) feedRate_t(float(MM_M) / 60.0f)
#define MMS_TO_MMM(MM_S) (float(MM_S) * 60.0f)
#define MMS_SCALED(V) ((V) * 0.01f * feedrate_percentage)
#define MMM_TO_MMS(MM_M) feedRate_t(static_cast<float>(MM_M) / 60.0f)
#define MMS_TO_MMM(MM_S) (static_cast<float>(MM_S) * 60.0f)
//
// Coordinates structures for XY, XYZ, XYZE...
//
// Helpers
#define _RECIP(N) ((N) ? 1.0f / float(N) : 0.0f)
#define _RECIP(N) ((N) ? 1.0f / static_cast<float>(N) : 0.0f)
#define _ABS(N) ((N) < 0 ? -(N) : (N))
#define _LS(N) (N = (T)(uint32_t(N) << v))
#define _RS(N) (N = (T)(uint32_t(N) >> v))
@@ -170,7 +244,7 @@ void toNative(xyz_pos_t &raw);
void toNative(xyze_pos_t &raw);
//
// XY coordinates, counters, etc.
// Paired XY coordinates, counters, flags, etc.
//
template<typename T>
struct XYval {
@@ -179,18 +253,34 @@ struct XYval {
struct { T a, b; };
T pos[2];
};
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; }
#if XYZE_N > XYZE
FI void set(const T (&arr)[XYZE_N]) { x = arr[0]; y = arr[1]; }
#endif
// Set all to 0
FI void reset() { x = y = 0; }
// Setters taking struct types and arrays
FI void set(const T px) { x = px; }
#if HAS_Y_AXIS
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
#endif
#if LINEAR_AXES > XY
FI void set(const T (&arr)[LINEAR_AXES]) { x = arr[0]; y = arr[1]; }
#endif
#if LOGICAL_AXES > LINEAR_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { x = arr[0]; y = arr[1]; }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { x = arr[0]; y = arr[1]; }
#endif
#endif
// Length reduced to one dimension
FI T magnitude() const { return (T)sqrtf(x*x + y*y); }
// Pointer to the data as a simple array
FI operator T* () { return pos; }
// If any element is true then it's true
FI operator bool() { return x || y; }
// Explicit copy and copies with conversion
FI XYval<T> copy() const { return *this; }
FI XYval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)) }; }
FI XYval<int16_t> asInt() { return { int16_t(x), int16_t(y) }; }
@@ -199,20 +289,30 @@ struct XYval {
FI XYval<int32_t> asLong() const { return { int32_t(x), int32_t(y) }; }
FI XYval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
FI XYval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)) }; }
FI XYval<float> asFloat() { return { float(x), float(y) }; }
FI XYval<float> asFloat() const { return { float(x), float(y) }; }
FI XYval<float> asFloat() { return { static_cast<float>(x), static_cast<float>(y) }; }
FI XYval<float> asFloat() const { return { static_cast<float>(x), static_cast<float>(y) }; }
FI XYval<float> reciprocal() const { return { _RECIP(x), _RECIP(y) }; }
// Marlin workspace shifting is done with G92 and M206
FI XYval<float> asLogical() const { XYval<float> o = asFloat(); toLogical(o); return o; }
FI XYval<float> asNative() const { XYval<float> o = asFloat(); toNative(o); return o; }
// Cast to a type with more fields by making a new object
FI operator XYZval<T>() { return { x, y }; }
FI operator XYZval<T>() const { return { x, y }; }
FI operator XYZEval<T>() { return { x, y }; }
FI operator XYZEval<T>() const { return { x, y }; }
FI T& operator[](const int i) { return pos[i]; }
FI const T& operator[](const int i) const { return pos[i]; }
// Accessor via an AxisEnum (or any integer) [index]
FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int n) const { return pos[n]; }
// Assignment operator overrides do the expected thing
FI XYval<T>& operator= (const T v) { set(v, v ); return *this; }
FI XYval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y); return *this; }
FI XYval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y); return *this; }
// Override other operators to get intuitive behaviors
FI XYval<T> operator+ (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYval<T> operator+ (const XYval<T> &rs) { XYval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYval<T> operator- (const XYval<T> &rs) const { XYval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
@@ -249,6 +349,10 @@ struct XYval {
FI XYval<T> operator>>(const int &v) { XYval<T> ls = *this; _RS(ls.x); _RS(ls.y); return ls; }
FI XYval<T> operator<<(const int &v) const { XYval<T> ls = *this; _LS(ls.x); _LS(ls.y); return ls; }
FI XYval<T> operator<<(const int &v) { XYval<T> ls = *this; _LS(ls.x); _LS(ls.y); return ls; }
FI const XYval<T> operator-() const { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
FI XYval<T> operator-() { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
// Modifier operators
FI XYval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
FI XYval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
FI XYval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
@@ -262,6 +366,8 @@ struct XYval {
FI XYval<T>& operator*=(const int &v) { x *= v; y *= v; return *this; }
FI XYval<T>& operator>>=(const int &v) { _RS(x); _RS(y); return *this; }
FI XYval<T>& operator<<=(const int &v) { _LS(x); _LS(y); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYval<T> &rs) { return x == rs.x && y == rs.y; }
FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y; }
FI bool operator==(const XYZEval<T> &rs) { return x == rs.x && y == rs.y; }
@@ -274,224 +380,291 @@ struct XYval {
FI bool operator!=(const XYval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
FI XYval<T> operator-() { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
FI const XYval<T> operator-() const { XYval<T> o = *this; o.x = -x; o.y = -y; return o; }
};
//
// XYZ coordinates, counters, etc.
// Linear Axes coordinates, counters, flags, etc.
//
template<typename T>
struct XYZval {
union {
struct { T x, y, z; };
struct { T a, b, c; };
T pos[3];
struct { T LINEAR_AXIS_ARGS(); };
struct { T LINEAR_AXIS_LIST(a, b, c, u, v, w); };
T pos[LINEAR_AXES];
};
// Set all to 0
FI void reset() { LINEAR_AXIS_GANG(x =, y =, z =, i =, j =, k =) 0; }
// Setters taking struct types and arrays
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
FI void set(const XYval<T> pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; }
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYval<T> pxy, const T pz) { LINEAR_AXIS_CODE(x = pxy.x, y = pxy.y, z = pz, NOOP, NOOP, NOOP); }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; }
FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; }
#if XYZE_N > XYZE
FI void set(const T (&arr)[XYZE_N]) { x = arr[0]; y = arr[1]; z = arr[2]; }
#if HAS_Z_AXIS
FI void set(const T (&arr)[LINEAR_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); }
#endif
FI void reset() { x = y = z = 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z); }
#if LOGICAL_AXES > LINEAR_AXES
FI void set(const T (&arr)[LOGICAL_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
FI void set(LOGICAL_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k ); }
#if DISTINCT_AXES > LOGICAL_AXES
FI void set(const T (&arr)[DISTINCT_AXES]) { LINEAR_AXIS_CODE(x = arr[0], y = arr[1], z = arr[2], i = arr[3], j = arr[4], k = arr[5]); }
#endif
#endif
#if LINEAR_AXES >= 4
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
#endif
#if LINEAR_AXES >= 5
FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; }
#endif
#if LINEAR_AXES >= 6
FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; }
#endif
// Length reduced to one dimension
FI T magnitude() const { return (T)sqrtf(LINEAR_AXIS_GANG(x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); }
// Pointer to the data as a simple array
FI operator T* () { return pos; }
FI operator bool() { return z || x || y; }
// If any element is true then it's true
FI operator bool() { return LINEAR_AXIS_GANG(x, || y, || z, || i, || j, || k); }
// Explicit copy and copies with conversion
FI XYZval<T> copy() const { XYZval<T> o = *this; return o; }
FI XYZval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)) }; }
FI XYZval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z) }; }
FI XYZval<int16_t> asInt() const { return { int16_t(x), int16_t(y), int16_t(z) }; }
FI XYZval<int32_t> asLong() { return { int32_t(x), int32_t(y), int32_t(z) }; }
FI XYZval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z) }; }
FI XYZval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; }
FI XYZval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)) }; }
FI XYZval<float> asFloat() { return { float(x), float(y), float(z) }; }
FI XYZval<float> asFloat() const { return { float(x), float(y), float(z) }; }
FI XYZval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z) }; }
FI XYZval<T> ABS() const { return LINEAR_AXIS_ARRAY(T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); }
FI XYZval<int16_t> asInt() { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); }
FI XYZval<int16_t> asInt() const { return LINEAR_AXIS_ARRAY(int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); }
FI XYZval<int32_t> asLong() { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); }
FI XYZval<int32_t> asLong() const { return LINEAR_AXIS_ARRAY(int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); }
FI XYZval<int32_t> ROUNDL() { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); }
FI XYZval<int32_t> ROUNDL() const { return LINEAR_AXIS_ARRAY(int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); }
FI XYZval<float> asFloat() { return LINEAR_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); }
FI XYZval<float> asFloat() const { return LINEAR_AXIS_ARRAY(static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); }
FI XYZval<float> reciprocal() const { return LINEAR_AXIS_ARRAY(_RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); }
// Marlin workspace shifting is done with G92 and M206
FI XYZval<float> asLogical() const { XYZval<float> o = asFloat(); toLogical(o); return o; }
FI XYZval<float> asNative() const { XYZval<float> o = asFloat(); toNative(o); return o; }
// In-place cast to types having fewer fields
FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZEval<T>() const { return { x, y, z }; }
FI T& operator[](const int i) { return pos[i]; }
FI const T& operator[](const int i) const { return pos[i]; }
FI XYZval<T>& operator= (const T v) { set(v, v, v ); return *this; }
// Cast to a type with more fields by making a new object
FI operator XYZEval<T>() const { return LINEAR_AXIS_ARRAY(x, y, z, i, j, k); }
// Accessor via an AxisEnum (or any integer) [index]
FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int n) const { return pos[n]; }
// Assignment operator overrides do the expected thing
FI XYZval<T>& operator= (const T v) { set(ARRAY_N_1(LINEAR_AXES, v)); return *this; }
FI XYZval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y ); return *this; }
FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(rs.x, rs.y, rs.z); return *this; }
FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; return ls; }
FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; return ls; }
FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; }
FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); return ls; }
FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; }
FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); return ls; }
FI XYZval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
FI XYZval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
FI XYZval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
FI XYZval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
FI XYZval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; }
FI XYZval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; }
FI XYZval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; }
FI XYZval<T>& operator/=(const XYZval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; }
FI XYZval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; }
FI XYZval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; }
FI XYZval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; }
FI XYZval<T>& operator/=(const XYZEval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; }
FI XYZval<T>& operator*=(const float &v) { x *= v; y *= v; z *= v; return *this; }
FI XYZval<T>& operator*=(const int &v) { x *= v; y *= v; z *= v; return *this; }
FI XYZval<T>& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); return *this; }
FI XYZval<T>& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); return *this; }
FI bool operator==(const XYZEval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; }
FI XYZval<T>& operator= (const XYZEval<T> &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; }
// Override other operators to get intuitive behaviors
FI XYZval<T> operator+ (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator+ (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator- (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator* (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator/ (const XYval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, NOOP , NOOP , NOOP , NOOP ); return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator+ (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator- (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator* (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator/ (const XYZEval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZval<T> operator* (const float &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator* (const float &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator* (const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator* (const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZval<T> operator/ (const float &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator/ (const float &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator/ (const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator/ (const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZval<T> operator>>(const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; }
FI XYZval<T> operator>>(const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; }
FI XYZval<T> operator<<(const int &v) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; }
FI XYZval<T> operator<<(const int &v) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(_LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; }
FI const XYZval<T> operator-() const { XYZval<T> o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; }
FI XYZval<T> operator-() { XYZval<T> o = *this; LINEAR_AXIS_CODE(o.x = -x, o.y = -y, o.z = -z, o.i = -i, o.j = -j, o.k = -k); return o; }
// Modifier operators
FI XYZval<T>& operator+=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator-=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator*=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator/=(const XYval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, NOOP, NOOP, NOOP, NOOP ); return *this; }
FI XYZval<T>& operator+=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZval<T>& operator-=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZval<T>& operator*=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZval<T>& operator/=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZval<T>& operator+=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZval<T>& operator-=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZval<T>& operator*=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZval<T>& operator/=(const XYZEval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZval<T>& operator*=(const float &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; }
FI XYZval<T>& operator*=(const int &v) { LINEAR_AXIS_CODE(x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; }
FI XYZval<T>& operator>>=(const int &v) { LINEAR_AXIS_CODE(_RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; }
FI XYZval<T>& operator<<=(const int &v) { LINEAR_AXIS_CODE(_LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYZEval<T> &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator==(const XYZEval<T> &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator!=(const XYZEval<T> &rs) { return !operator==(rs); }
FI bool operator==(const XYZEval<T> &rs) const { return x == rs.x && y == rs.y && z == rs.z; }
FI bool operator!=(const XYZEval<T> &rs) const { return !operator==(rs); }
FI XYZval<T> operator-() { XYZval<T> o = *this; o.x = -x; o.y = -y; o.z = -z; return o; }
FI const XYZval<T> operator-() const { XYZval<T> o = *this; o.x = -x; o.y = -y; o.z = -z; return o; }
};
//
// XYZE coordinates, counters, etc.
// Logical Axes coordinates, counters, etc.
//
template<typename T>
struct XYZEval {
union {
struct{ T x, y, z, e; };
struct{ T a, b, c; };
T pos[4];
struct { T LOGICAL_AXIS_ARGS(); };
struct { T LOGICAL_AXIS_LIST(_e, a, b, c, u, v, w); };
T pos[LOGICAL_AXES];
};
FI void reset() { x = y = z = e = 0; }
FI T magnitude() const { return (T)sqrtf(x*x + y*y + z*z + e*e); }
FI operator T* () { return pos; }
FI operator bool() { return e || z || x || y; }
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
FI void set(const T px, const T py, const T pz, const T pe) { x = px; y = py; z = pz; e = pe; }
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYval<T> pxy, const T pz) { x = pxy.x; y = pxy.y; z = pz; }
FI void set(const XYZval<T> pxyz) { x = pxyz.x; y = pxyz.y; z = pxyz.z; }
FI void set(const XYval<T> pxy, const T pz, const T pe) { x = pxy.x; y = pxy.y; z = pz; e = pe; }
FI void set(const XYval<T> pxy, const XYval<T> pze) { x = pxy.x; y = pxy.y; z = pze.z; e = pze.e; }
FI void set(const XYZval<T> pxyz, const T pe) { x = pxyz.x; y = pxyz.y; z = pxyz.z; e = pe; }
FI void set(const T (&arr)[XY]) { x = arr[0]; y = arr[1]; }
FI void set(const T (&arr)[XYZ]) { x = arr[0]; y = arr[1]; z = arr[2]; }
FI void set(const T (&arr)[XYZE]) { x = arr[0]; y = arr[1]; z = arr[2]; e = arr[3]; }
#if XYZE_N > XYZE
FI void set(const T (&arr)[XYZE_N]) { x = arr[0]; y = arr[1]; z = arr[2]; e = arr[3]; }
// Reset all to 0
FI void reset() { LOGICAL_AXIS_GANG(e =, x =, y =, z =, i =, j =, k =) 0; }
// Setters taking struct types and arrays
FI void set(const T px) { x = px; }
FI void set(const T px, const T py) { x = px; y = py; }
FI void set(const XYval<T> pxy) { x = pxy.x; y = pxy.y; }
FI void set(const XYZval<T> pxyz) { set(LINEAR_AXIS_ELEM(pxyz)); }
#if HAS_Z_AXIS
FI void set(LINEAR_AXIS_ARGS(const T)) { LINEAR_AXIS_CODE(a = x, b = y, c = z, u = i, v = j, w = k); }
#endif
FI XYZEval<T> copy() const { return *this; }
FI XYZEval<T> ABS() const { return { T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(e)) }; }
FI XYZEval<int16_t> asInt() { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; }
FI XYZEval<int16_t> asInt() const { return { int16_t(x), int16_t(y), int16_t(z), int16_t(e) }; }
FI XYZEval<int32_t> asLong() { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; }
FI XYZEval<int32_t> asLong() const { return { int32_t(x), int32_t(y), int32_t(z), int32_t(e) }; }
FI XYZEval<int32_t> ROUNDL() { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; }
FI XYZEval<int32_t> ROUNDL() const { return { int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(e)) }; }
FI XYZEval<float> asFloat() { return { float(x), float(y), float(z), float(e) }; }
FI XYZEval<float> asFloat() const { return { float(x), float(y), float(z), float(e) }; }
FI XYZEval<float> reciprocal() const { return { _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(e) }; }
FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; }
FI T& operator[](const int i) { return pos[i]; }
FI const T& operator[](const int i) const { return pos[i]; }
FI XYZEval<T>& operator= (const T v) { set(v, v, v, v); return *this; }
FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; }
FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(rs.x, rs.y, rs.z); return *this; }
FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZEval<T> operator+ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZEval<T> operator- (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZEval<T> operator- (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZEval<T> operator* (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; ls.z += rs.z; ls.e += rs.e; return ls; }
FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; }
FI XYZEval<T> operator- (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; ls.z -= rs.z; ls.e -= rs.e; return ls; }
FI XYZEval<T> operator* (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; }
FI XYZEval<T> operator* (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; ls.z *= rs.z; ls.e *= rs.e; return ls; }
FI XYZEval<T> operator/ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; }
FI XYZEval<T> operator/ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; ls.z /= rs.z; ls.e /= rs.e; return ls; }
FI XYZEval<T> operator* (const float &v) const { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
FI XYZEval<T> operator* (const float &v) { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
FI XYZEval<T> operator* (const int &v) const { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
FI XYZEval<T> operator* (const int &v) { XYZEval<T> ls = *this; ls.x *= v; ls.y *= v; ls.z *= v; ls.e *= v; return ls; }
FI XYZEval<T> operator/ (const float &v) const { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
FI XYZEval<T> operator/ (const float &v) { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
FI XYZEval<T> operator/ (const int &v) const { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
FI XYZEval<T> operator/ (const int &v) { XYZEval<T> ls = *this; ls.x /= v; ls.y /= v; ls.z /= v; ls.e /= v; return ls; }
FI XYZEval<T> operator>>(const int &v) const { XYZEval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; }
FI XYZEval<T> operator>>(const int &v) { XYZEval<T> ls = *this; _RS(ls.x); _RS(ls.y); _RS(ls.z); _RS(ls.e); return ls; }
FI XYZEval<T> operator<<(const int &v) const { XYZEval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; }
FI XYZEval<T> operator<<(const int &v) { XYZEval<T> ls = *this; _LS(ls.x); _LS(ls.y); _LS(ls.z); _LS(ls.e); return ls; }
FI XYZEval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
FI XYZEval<T>& operator+=(const XYZval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; return *this; }
FI XYZEval<T>& operator-=(const XYZval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; return *this; }
FI XYZEval<T>& operator*=(const XYZval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; return *this; }
FI XYZEval<T>& operator/=(const XYZval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; return *this; }
FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { x += rs.x; y += rs.y; z += rs.z; e += rs.e; return *this; }
FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { x -= rs.x; y -= rs.y; z -= rs.z; e -= rs.e; return *this; }
FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { x *= rs.x; y *= rs.y; z *= rs.z; e *= rs.e; return *this; }
FI XYZEval<T>& operator/=(const XYZEval<T> &rs) { x /= rs.x; y /= rs.y; z /= rs.z; e /= rs.e; return *this; }
FI XYZEval<T>& operator*=(const T &v) { x *= v; y *= v; z *= v; e *= v; return *this; }
FI XYZEval<T>& operator>>=(const int &v) { _RS(x); _RS(y); _RS(z); _RS(e); return *this; }
FI XYZEval<T>& operator<<=(const int &v) { _LS(x); _LS(y); _LS(z); _LS(e); return *this; }
FI bool operator==(const XYZval<T> &rs) { return x == rs.x && y == rs.y && z == rs.z; }
FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
FI bool operator==(const XYZval<T> &rs) const { return x == rs.x && y == rs.y && z == rs.z; }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
FI XYZEval<T> operator-() { return { -x, -y, -z, -e }; }
FI const XYZEval<T> operator-() const { return { -x, -y, -z, -e }; }
#if LOGICAL_AXES > LINEAR_AXES
FI void set(const XYval<T> pxy, const T pe) { set(pxy); e = pe; }
FI void set(const XYZval<T> pxyz, const T pe) { set(pxyz); e = pe; }
FI void set(LOGICAL_AXIS_ARGS(const T)) { LOGICAL_AXIS_CODE(_e = e, a = x, b = y, c = z, u = i, v = j, w = k); }
#endif
#if LINEAR_AXES >= 4
FI void set(const T px, const T py, const T pz) { x = px; y = py; z = pz; }
#endif
#if LINEAR_AXES >= 5
FI void set(const T px, const T py, const T pz, const T pi) { x = px; y = py; z = pz; i = pi; }
#endif
#if LINEAR_AXES >= 6
FI void set(const T px, const T py, const T pz, const T pi, const T pj) { x = px; y = py; z = pz; i = pi; j = pj; }
#endif
// Length reduced to one dimension
FI T magnitude() const { return (T)sqrtf(LOGICAL_AXIS_GANG(+ e*e, + x*x, + y*y, + z*z, + i*i, + j*j, + k*k)); }
// Pointer to the data as a simple array
FI operator T* () { return pos; }
// If any element is true then it's true
FI operator bool() { return 0 LOGICAL_AXIS_GANG(|| e, || x, || y, || z, || i, || j, || k); }
// Explicit copy and copies with conversion
FI XYZEval<T> copy() const { XYZEval<T> o = *this; return o; }
FI XYZEval<T> ABS() const { return LOGICAL_AXIS_ARRAY(T(_ABS(e)), T(_ABS(x)), T(_ABS(y)), T(_ABS(z)), T(_ABS(i)), T(_ABS(j)), T(_ABS(k))); }
FI XYZEval<int16_t> asInt() { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); }
FI XYZEval<int16_t> asInt() const { return LOGICAL_AXIS_ARRAY(int16_t(e), int16_t(x), int16_t(y), int16_t(z), int16_t(i), int16_t(j), int16_t(k)); }
FI XYZEval<int32_t> asLong() { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); }
FI XYZEval<int32_t> asLong() const { return LOGICAL_AXIS_ARRAY(int32_t(e), int32_t(x), int32_t(y), int32_t(z), int32_t(i), int32_t(j), int32_t(k)); }
FI XYZEval<int32_t> ROUNDL() { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); }
FI XYZEval<int32_t> ROUNDL() const { return LOGICAL_AXIS_ARRAY(int32_t(LROUND(e)), int32_t(LROUND(x)), int32_t(LROUND(y)), int32_t(LROUND(z)), int32_t(LROUND(i)), int32_t(LROUND(j)), int32_t(LROUND(k))); }
FI XYZEval<float> asFloat() { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); }
FI XYZEval<float> asFloat() const { return LOGICAL_AXIS_ARRAY(static_cast<float>(e), static_cast<float>(x), static_cast<float>(y), static_cast<float>(z), static_cast<float>(i), static_cast<float>(j), static_cast<float>(k)); }
FI XYZEval<float> reciprocal() const { return LOGICAL_AXIS_ARRAY(_RECIP(e), _RECIP(x), _RECIP(y), _RECIP(z), _RECIP(i), _RECIP(j), _RECIP(k)); }
// Marlin workspace shifting is done with G92 and M206
FI XYZEval<float> asLogical() const { XYZEval<float> o = asFloat(); toLogical(o); return o; }
FI XYZEval<float> asNative() const { XYZEval<float> o = asFloat(); toNative(o); return o; }
// In-place cast to types having fewer fields
FI operator XYval<T>&() { return *(XYval<T>*)this; }
FI operator const XYval<T>&() const { return *(const XYval<T>*)this; }
FI operator XYZval<T>&() { return *(XYZval<T>*)this; }
FI operator const XYZval<T>&() const { return *(const XYZval<T>*)this; }
// Accessor via an AxisEnum (or any integer) [index]
FI T& operator[](const int n) { return pos[n]; }
FI const T& operator[](const int n) const { return pos[n]; }
// Assignment operator overrides do the expected thing
FI XYZEval<T>& operator= (const T v) { set(LIST_N_1(LINEAR_AXES, v)); return *this; }
FI XYZEval<T>& operator= (const XYval<T> &rs) { set(rs.x, rs.y); return *this; }
FI XYZEval<T>& operator= (const XYZval<T> &rs) { set(LINEAR_AXIS_ELEM(rs)); return *this; }
// Override other operators to get intuitive behaviors
FI XYZEval<T> operator+ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZEval<T> operator+ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x += rs.x; ls.y += rs.y; return ls; }
FI XYZEval<T> operator- (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZEval<T> operator- (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x -= rs.x; ls.y -= rs.y; return ls; }
FI XYZEval<T> operator* (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator* (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x *= rs.x; ls.y *= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) const { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator/ (const XYval<T> &rs) { XYZEval<T> ls = *this; ls.x /= rs.x; ls.y /= rs.y; return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator+ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZEval<T> operator- (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZEval<T> operator* (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) const { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZEval<T> operator/ (const XYZval<T> &rs) { XYZval<T> ls = *this; LINEAR_AXIS_CODE(ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator+ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e += rs.e, ls.x += rs.x, ls.y += rs.y, ls.z += rs.z, ls.i += rs.i, ls.j += rs.j, ls.k += rs.k); return ls; }
FI XYZEval<T> operator- (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZEval<T> operator- (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e -= rs.e, ls.x -= rs.x, ls.y -= rs.y, ls.z -= rs.z, ls.i -= rs.i, ls.j -= rs.j, ls.k -= rs.k); return ls; }
FI XYZEval<T> operator* (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZEval<T> operator* (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= rs.e, ls.x *= rs.x, ls.y *= rs.y, ls.z *= rs.z, ls.i *= rs.i, ls.j *= rs.j, ls.k *= rs.k); return ls; }
FI XYZEval<T> operator/ (const XYZEval<T> &rs) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZEval<T> operator/ (const XYZEval<T> &rs) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= rs.e, ls.x /= rs.x, ls.y /= rs.y, ls.z /= rs.z, ls.i /= rs.i, ls.j /= rs.j, ls.k /= rs.k); return ls; }
FI XYZEval<T> operator* (const float &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZEval<T> operator* (const float &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZEval<T> operator* (const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZEval<T> operator* (const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e *= v, ls.x *= v, ls.y *= v, ls.z *= v, ls.i *= v, ls.j *= v, ls.k *= v ); return ls; }
FI XYZEval<T> operator/ (const float &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZEval<T> operator/ (const float &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZEval<T> operator/ (const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZEval<T> operator/ (const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(ls.e /= v, ls.x /= v, ls.y /= v, ls.z /= v, ls.i /= v, ls.j /= v, ls.k /= v ); return ls; }
FI XYZEval<T> operator>>(const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; }
FI XYZEval<T> operator>>(const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_RS(ls.e), _RS(ls.x), _RS(ls.y), _RS(ls.z), _RS(ls.i), _RS(ls.j), _RS(ls.k) ); return ls; }
FI XYZEval<T> operator<<(const int &v) const { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; }
FI XYZEval<T> operator<<(const int &v) { XYZEval<T> ls = *this; LOGICAL_AXIS_CODE(_LS(ls.e), _LS(ls.x), _LS(ls.y), _LS(ls.z), _LS(ls.i), _LS(ls.j), _LS(ls.k) ); return ls; }
FI const XYZEval<T> operator-() const { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k); }
FI XYZEval<T> operator-() { return LOGICAL_AXIS_ARRAY(-e, -x, -y, -z, -i, -j, -k); }
// Modifier operators
FI XYZEval<T>& operator+=(const XYval<T> &rs) { x += rs.x; y += rs.y; return *this; }
FI XYZEval<T>& operator-=(const XYval<T> &rs) { x -= rs.x; y -= rs.y; return *this; }
FI XYZEval<T>& operator*=(const XYval<T> &rs) { x *= rs.x; y *= rs.y; return *this; }
FI XYZEval<T>& operator/=(const XYval<T> &rs) { x /= rs.x; y /= rs.y; return *this; }
FI XYZEval<T>& operator+=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZEval<T>& operator-=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZEval<T>& operator*=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZEval<T>& operator/=(const XYZval<T> &rs) { LINEAR_AXIS_CODE(x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZEval<T>& operator+=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e += rs.e, x += rs.x, y += rs.y, z += rs.z, i += rs.i, j += rs.j, k += rs.k); return *this; }
FI XYZEval<T>& operator-=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e -= rs.e, x -= rs.x, y -= rs.y, z -= rs.z, i -= rs.i, j -= rs.j, k -= rs.k); return *this; }
FI XYZEval<T>& operator*=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e *= rs.e, x *= rs.x, y *= rs.y, z *= rs.z, i *= rs.i, j *= rs.j, k *= rs.k); return *this; }
FI XYZEval<T>& operator/=(const XYZEval<T> &rs) { LOGICAL_AXIS_CODE(e /= rs.e, x /= rs.x, y /= rs.y, z /= rs.z, i /= rs.i, j /= rs.j, k /= rs.k); return *this; }
FI XYZEval<T>& operator*=(const T &v) { LOGICAL_AXIS_CODE(e *= v, x *= v, y *= v, z *= v, i *= v, j *= v, k *= v); return *this; }
FI XYZEval<T>& operator>>=(const int &v) { LOGICAL_AXIS_CODE(_RS(e), _RS(x), _RS(y), _RS(z), _RS(i), _RS(j), _RS(k)); return *this; }
FI XYZEval<T>& operator<<=(const int &v) { LOGICAL_AXIS_CODE(_LS(e), _LS(x), _LS(y), _LS(z), _LS(i), _LS(j), _LS(k)); return *this; }
// Exact comparisons. For floats a "NEAR" operation may be better.
FI bool operator==(const XYZval<T> &rs) { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator==(const XYZval<T> &rs) const { return true LINEAR_AXIS_GANG(&& x == rs.x, && y == rs.y, && z == rs.z, && i == rs.i, && j == rs.j, && k == rs.k); }
FI bool operator!=(const XYZval<T> &rs) { return !operator==(rs); }
FI bool operator!=(const XYZval<T> &rs) const { return !operator==(rs); }
};
#undef _RECIP
@@ -499,6 +672,3 @@ struct XYZEval {
#undef _LS
#undef _RS
#undef FI
const xyze_char_t axis_codes { 'X', 'Y', 'Z', 'E' };
#define XYZ_CHAR(A) ('X' + char(A))

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
@@ -57,30 +57,31 @@ void safe_delay(millis_t ms) {
void log_machine_info() {
SERIAL_ECHOLNPGM("Machine Type: "
TERN(DELTA, "Delta", "")
TERN(IS_SCARA, "SCARA", "")
TERN(IS_CORE, "Core", "")
TERN(IS_CARTESIAN, "Cartesian", "")
TERN_(DELTA, "Delta")
TERN_(IS_SCARA, "SCARA")
TERN_(IS_CORE, "Core")
TERN_(MARKFORGED_XY, "MarkForged")
TERN_(IS_CARTESIAN, "Cartesian")
);
SERIAL_ECHOLNPGM("Probe: "
TERN(PROBE_MANUALLY, "PROBE_MANUALLY", "")
TERN(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE", "")
TERN(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE", "")
TERN(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE"), "")
TERN(TOUCH_MI_PROBE, "TOUCH_MI_PROBE", "")
TERN(Z_PROBE_SLED, "Z_PROBE_SLED", "")
TERN(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY", "")
TERN(SOLENOID_PROBE, "SOLENOID_PROBE", "")
TERN_(PROBE_MANUALLY, "PROBE_MANUALLY")
TERN_(NOZZLE_AS_PROBE, "NOZZLE_AS_PROBE")
TERN_(FIX_MOUNTED_PROBE, "FIX_MOUNTED_PROBE")
TERN_(HAS_Z_SERVO_PROBE, TERN(BLTOUCH, "BLTOUCH", "SERVO PROBE"))
TERN_(TOUCH_MI_PROBE, "TOUCH_MI_PROBE")
TERN_(Z_PROBE_SLED, "Z_PROBE_SLED")
TERN_(Z_PROBE_ALLEN_KEY, "Z_PROBE_ALLEN_KEY")
TERN_(SOLENOID_PROBE, "SOLENOID_PROBE")
TERN(PROBE_SELECTED, "", "NONE")
);
#if HAS_BED_PROBE
#if !HAS_PROBE_XY_OFFSET
SERIAL_ECHOPAIR("Probe Offset X0 Y0 Z", probe.offset.z, " (");
SERIAL_ECHOPGM("Probe Offset X0 Y0 Z", probe.offset.z, " (");
#else
SERIAL_ECHOPAIR_P(PSTR("Probe Offset X"), probe.offset_xy.x, SP_Y_STR, probe.offset_xy.y, SP_Z_STR, probe.offset.z);
SERIAL_ECHOPGM_P(PSTR("Probe Offset X"), probe.offset_xy.x, SP_Y_STR, probe.offset_xy.y, SP_Z_STR, probe.offset.z);
if (probe.offset_xy.x > 0)
SERIAL_ECHOPGM(" (Right");
else if (probe.offset_xy.x < 0)
@@ -91,9 +92,9 @@ void safe_delay(millis_t ms) {
SERIAL_ECHOPGM(" (Aligned With");
if (probe.offset_xy.y > 0)
serialprintPGM(ENABLED(IS_SCARA) ? PSTR("-Distal") : PSTR("-Back"));
SERIAL_ECHOPGM_P(ENABLED(IS_SCARA) ? PSTR("-Distal") : PSTR("-Back"));
else if (probe.offset_xy.y < 0)
serialprintPGM(ENABLED(IS_SCARA) ? PSTR("-Proximal") : PSTR("-Front"));
SERIAL_ECHOPGM_P(ENABLED(IS_SCARA) ? PSTR("-Proximal") : PSTR("-Front"));
else if (probe.offset_xy.x != 0)
SERIAL_ECHOPGM("-Center");
@@ -101,32 +102,32 @@ void safe_delay(millis_t ms) {
#endif
serialprintPGM(probe.offset.z < 0 ? PSTR("Below") : probe.offset.z > 0 ? PSTR("Above") : PSTR("Same Z as"));
SERIAL_ECHOPGM_P(probe.offset.z < 0 ? PSTR("Below") : probe.offset.z > 0 ? PSTR("Above") : PSTR("Same Z as"));
SERIAL_ECHOLNPGM(" Nozzle)");
#endif
#if HAS_ABL_OR_UBL
SERIAL_ECHOPGM("Auto Bed Leveling: "
TERN(AUTO_BED_LEVELING_LINEAR, "LINEAR", "")
TERN(AUTO_BED_LEVELING_BILINEAR, "BILINEAR", "")
TERN(AUTO_BED_LEVELING_3POINT, "3POINT", "")
TERN(AUTO_BED_LEVELING_UBL, "UBL", "")
TERN_(AUTO_BED_LEVELING_LINEAR, "LINEAR")
TERN_(AUTO_BED_LEVELING_BILINEAR, "BILINEAR")
TERN_(AUTO_BED_LEVELING_3POINT, "3POINT")
TERN_(AUTO_BED_LEVELING_UBL, "UBL")
);
if (planner.leveling_active) {
SERIAL_ECHOLNPGM(" (enabled)");
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
if (planner.z_fade_height)
SERIAL_ECHOLNPAIR("Z Fade: ", planner.z_fade_height);
SERIAL_ECHOLNPGM("Z Fade: ", planner.z_fade_height);
#endif
#if ABL_PLANAR
SERIAL_ECHOPGM("ABL Adjustment X");
LOOP_XYZ(a) {
float v = planner.get_axis_position_mm(AxisEnum(a)) - current_position[a];
SERIAL_CHAR(' ', XYZ_CHAR(a));
SERIAL_ECHOPGM("ABL Adjustment");
LOOP_LINEAR_AXES(a) {
const float v = planner.get_axis_position_mm(AxisEnum(a)) - current_position[a];
SERIAL_CHAR(' ', AXIS_CHAR(a));
if (v > 0) SERIAL_CHAR('+');
SERIAL_ECHO(v);
SERIAL_DECIMAL(v);
}
#else
#if ENABLED(AUTO_BED_LEVELING_UBL)
@@ -139,7 +140,7 @@ void safe_delay(millis_t ms) {
SERIAL_ECHO(ftostr43sign(rz, '+'));
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
if (planner.z_fade_height) {
SERIAL_ECHOPAIR(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+'));
SERIAL_ECHOPGM(" (", ftostr43sign(rz * planner.fade_scaling_factor_for_z(current_position.z), '+'));
SERIAL_CHAR(')');
}
#endif
@@ -155,10 +156,10 @@ void safe_delay(millis_t ms) {
SERIAL_ECHOPGM("Mesh Bed Leveling");
if (planner.leveling_active) {
SERIAL_ECHOLNPGM(" (enabled)");
SERIAL_ECHOPAIR("MBL Adjustment Z", ftostr43sign(mbl.get_z(current_position), '+'));
SERIAL_ECHOPGM("MBL Adjustment Z", ftostr43sign(mbl.get_z(current_position), '+'));
#if ENABLED(ENABLE_LEVELING_FADE_HEIGHT)
if (planner.z_fade_height) {
SERIAL_ECHOPAIR(" (", ftostr43sign(
SERIAL_ECHOPGM(" (", ftostr43sign(
mbl.get_z(current_position, planner.fade_scaling_factor_for_z(current_position.z)), '+'
));
SERIAL_CHAR(')');

View File

@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#pragma once
@@ -25,8 +25,7 @@
#include "../core/types.h"
#include "../core/millis_t.h"
// Delay that ensures heaters and watchdog are kept alive
void safe_delay(millis_t ms);
void safe_delay(millis_t ms); // Delay ensuring that temperatures are updated and the watchdog is kept alive.
#if ENABLED(SERIAL_OVERRUN_PROTECTION)
void serial_delay(const millis_t ms);
@@ -34,7 +33,7 @@ void safe_delay(millis_t ms);
inline void serial_delay(const millis_t) {}
#endif
#if GRID_MAX_POINTS_X && GRID_MAX_POINTS_Y
#if (GRID_MAX_POINTS_X) && (GRID_MAX_POINTS_Y)
// 16x16 bit arrays
template <int W, int H>
@@ -71,9 +70,17 @@ public:
inline void restore() { ref_ = val_; }
};
#define REMEMBER(N,X,V...) restorer<typeof(X)> restorer_##N(X, ##V)
#define REMEMBER(N,X,V...) restorer<__typeof__(X)> restorer_##N(X, ##V)
#define RESTORE(N) restorer_##N.restore()
// Converts from an uint8_t in the range of 0-255 to an uint8_t
// in the range 0-100 while avoiding rounding artifacts
constexpr uint8_t ui8_to_percent(const uint8_t i) { return (int(i) * 100 + 127) / 255; }
const xyze_char_t axis_codes LOGICAL_AXIS_ARRAY('E', 'X', 'Y', 'Z', AXIS4_NAME, AXIS5_NAME, AXIS6_NAME);
#if LINEAR_AXES <= XYZ
#define AXIS_CHAR(A) ((char)('X' + A))
#else
#define AXIS_CHAR(A) axis_codes[A]
#endif