Browse Source

Refactor serial class with templates (#20783)

X-Ryl669 3 years ago
parent
commit
3f01b222b2
No account linked to committer's email address
64 changed files with 784 additions and 950 deletions
  1. 7
    0
      Marlin/src/HAL/AVR/HAL.cpp
  2. 9
    1
      Marlin/src/HAL/AVR/HAL.h
  3. 14
    181
      Marlin/src/HAL/AVR/MarlinSerial.cpp
  4. 33
    62
      Marlin/src/HAL/AVR/MarlinSerial.h
  5. 7
    0
      Marlin/src/HAL/DUE/HAL.cpp
  6. 13
    2
      Marlin/src/HAL/DUE/HAL.h
  7. 7
    159
      Marlin/src/HAL/DUE/MarlinSerial.cpp
  8. 6
    37
      Marlin/src/HAL/DUE/MarlinSerial.h
  9. 6
    151
      Marlin/src/HAL/DUE/MarlinSerialUSB.cpp
  10. 6
    41
      Marlin/src/HAL/DUE/MarlinSerialUSB.h
  11. 2
    2
      Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp
  12. 1
    4
      Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp
  13. 3
    4
      Marlin/src/HAL/ESP32/FlushableHardwareSerial.h
  14. 4
    0
      Marlin/src/HAL/ESP32/HAL.cpp
  15. 3
    1
      Marlin/src/HAL/ESP32/HAL.h
  16. 1
    5
      Marlin/src/HAL/ESP32/WebSocketSerial.cpp
  17. 3
    4
      Marlin/src/HAL/ESP32/WebSocketSerial.h
  18. 1
    1
      Marlin/src/HAL/LINUX/HAL.cpp
  19. 1
    1
      Marlin/src/HAL/LINUX/HAL.h
  20. 6
    96
      Marlin/src/HAL/LINUX/include/serial.h
  21. 2
    0
      Marlin/src/HAL/LPC1768/HAL.cpp
  22. 7
    4
      Marlin/src/HAL/LPC1768/HAL.h
  23. 4
    4
      Marlin/src/HAL/LPC1768/MarlinSerial.cpp
  24. 8
    14
      Marlin/src/HAL/LPC1768/MarlinSerial.h
  25. 5
    0
      Marlin/src/HAL/SAMD51/HAL.cpp
  26. 9
    5
      Marlin/src/HAL/SAMD51/HAL.h
  27. 3
    3
      Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp
  28. 7
    3
      Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h
  29. 4
    0
      Marlin/src/HAL/STM32/HAL.cpp
  30. 7
    4
      Marlin/src/HAL/STM32/HAL.h
  31. 1
    1
      Marlin/src/HAL/STM32/MarlinSerial.cpp
  32. 15
    23
      Marlin/src/HAL/STM32/MarlinSerial.h
  33. 1
    0
      Marlin/src/HAL/STM32F1/HAL.cpp
  34. 4
    1
      Marlin/src/HAL/STM32F1/HAL.h
  35. 10
    10
      Marlin/src/HAL/STM32F1/MarlinSerial.cpp
  36. 10
    23
      Marlin/src/HAL/STM32F1/MarlinSerial.h
  37. 1
    1
      Marlin/src/HAL/STM32F1/msc_sd.cpp
  38. 2
    18
      Marlin/src/HAL/STM32F1/msc_sd.h
  39. 3
    0
      Marlin/src/HAL/TEENSY31_32/HAL.cpp
  40. 9
    3
      Marlin/src/HAL/TEENSY31_32/HAL.h
  41. 3
    0
      Marlin/src/HAL/TEENSY35_36/HAL.cpp
  42. 9
    3
      Marlin/src/HAL/TEENSY35_36/HAL.h
  43. 3
    0
      Marlin/src/HAL/TEENSY40_41/HAL.cpp
  44. 12
    2
      Marlin/src/HAL/TEENSY40_41/HAL.h
  45. 2
    2
      Marlin/src/MarlinCore.cpp
  46. 26
    0
      Marlin/src/core/macros.h
  47. 16
    1
      Marlin/src/core/serial.cpp
  48. 12
    22
      Marlin/src/core/serial.h
  49. 146
    0
      Marlin/src/core/serial_base.h
  50. 230
    0
      Marlin/src/core/serial_hook.h
  51. 3
    15
      Marlin/src/feature/binary_stream.h
  52. 5
    5
      Marlin/src/feature/host_actions.cpp
  53. 2
    1
      Marlin/src/gcode/feature/network/M552-M554.cpp
  54. 3
    1
      Marlin/src/gcode/gcode.cpp
  55. 3
    10
      Marlin/src/gcode/host/M118.cpp
  56. 6
    6
      Marlin/src/gcode/queue.cpp
  57. 1
    1
      Marlin/src/gcode/sd/M1001.cpp
  58. 1
    0
      Marlin/src/inc/Conditionals_LCD.h
  59. 2
    2
      Marlin/src/lcd/extui/malyan_lcd.cpp
  60. 2
    2
      Marlin/src/module/temperature.cpp
  61. 6
    6
      Marlin/src/sd/cardreader.cpp
  62. 1
    1
      Marlin/src/sd/cardreader.h
  63. 1
    1
      buildroot/tests/run_tests
  64. 44
    0
      docs/Serial.md

+ 7
- 0
Marlin/src/HAL/AVR/HAL.cpp View File

24
 #include "../../inc/MarlinConfig.h"
24
 #include "../../inc/MarlinConfig.h"
25
 #include "HAL.h"
25
 #include "HAL.h"
26
 
26
 
27
+#ifdef USBCON
28
+  DefaultSerial MSerial(false, Serial);
29
+  #ifdef BLUETOOTH
30
+    BTSerial btSerial(false, bluetoothSerial);
31
+  #endif
32
+#endif
33
+
27
 // ------------------------
34
 // ------------------------
28
 // Public Variables
35
 // Public Variables
29
 // ------------------------
36
 // ------------------------

+ 9
- 1
Marlin/src/HAL/AVR/HAL.h View File

82
 
82
 
83
 // Serial ports
83
 // Serial ports
84
 #ifdef USBCON
84
 #ifdef USBCON
85
-  #define MYSERIAL0 TERN(BLUETOOTH, bluetoothSerial, Serial)
85
+  #include "../../core/serial_hook.h" 
86
+  typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
87
+  extern DefaultSerial MSerial;
88
+  #ifdef BLUETOOTH
89
+    typedef ForwardSerial0Type< decltype(bluetoothSerial) > BTSerial;
90
+    extern BTSerial btSerial;
91
+  #endif
92
+  
93
+  #define MYSERIAL0 TERN(BLUETOOTH, btSerial, MSerial)
86
 #else
94
 #else
87
   #if !WITHIN(SERIAL_PORT, -1, 3)
95
   #if !WITHIN(SERIAL_PORT, -1, 3)
88
     #error "SERIAL_PORT must be from -1 to 3. Please update your configuration."
96
     #error "SERIAL_PORT must be from -1 to 3. Please update your configuration."

+ 14
- 181
Marlin/src/HAL/AVR/MarlinSerial.cpp View File

454
 }
454
 }
455
 
455
 
456
 template<typename Cfg>
456
 template<typename Cfg>
457
-void MarlinSerial<Cfg>::write(const uint8_t c) {
457
+size_t MarlinSerial<Cfg>::write(const uint8_t c) {
458
   if (Cfg::TX_SIZE == 0) {
458
   if (Cfg::TX_SIZE == 0) {
459
 
459
 
460
     _written = true;
460
     _written = true;
480
       // location". This makes sure flush() won't return until the bytes
480
       // location". This makes sure flush() won't return until the bytes
481
       // actually got written
481
       // actually got written
482
       B_TXC = 1;
482
       B_TXC = 1;
483
-      return;
483
+      return 1;
484
     }
484
     }
485
 
485
 
486
     const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
486
     const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
510
     // Enable TX ISR - Non atomic, but it will eventually enable TX ISR
510
     // Enable TX ISR - Non atomic, but it will eventually enable TX ISR
511
     B_UDRIE = 1;
511
     B_UDRIE = 1;
512
   }
512
   }
513
+  return 1;
513
 }
514
 }
514
 
515
 
515
 template<typename Cfg>
516
 template<typename Cfg>
556
   }
557
   }
557
 }
558
 }
558
 
559
 
559
-/**
560
- * Imports from print.h
561
- */
562
-
563
-template<typename Cfg>
564
-void MarlinSerial<Cfg>::print(char c, int base) {
565
-  print((long)c, base);
566
-}
567
-
568
-template<typename Cfg>
569
-void MarlinSerial<Cfg>::print(unsigned char b, int base) {
570
-  print((unsigned long)b, base);
571
-}
572
-
573
-template<typename Cfg>
574
-void MarlinSerial<Cfg>::print(int n, int base) {
575
-  print((long)n, base);
576
-}
577
-
578
-template<typename Cfg>
579
-void MarlinSerial<Cfg>::print(unsigned int n, int base) {
580
-  print((unsigned long)n, base);
581
-}
582
-
583
-template<typename Cfg>
584
-void MarlinSerial<Cfg>::print(long n, int base) {
585
-  if (base == 0) write(n);
586
-  else if (base == 10) {
587
-    if (n < 0) { print('-'); n = -n; }
588
-    printNumber(n, 10);
589
-  }
590
-  else
591
-    printNumber(n, base);
592
-}
593
-
594
-template<typename Cfg>
595
-void MarlinSerial<Cfg>::print(unsigned long n, int base) {
596
-  if (base == 0) write(n);
597
-  else printNumber(n, base);
598
-}
599
-
600
-template<typename Cfg>
601
-void MarlinSerial<Cfg>::print(double n, int digits) {
602
-  printFloat(n, digits);
603
-}
604
-
605
-template<typename Cfg>
606
-void MarlinSerial<Cfg>::println() {
607
-  print('\r');
608
-  print('\n');
609
-}
610
-
611
-template<typename Cfg>
612
-void MarlinSerial<Cfg>::println(const String& s) {
613
-  print(s);
614
-  println();
615
-}
616
-
617
-template<typename Cfg>
618
-void MarlinSerial<Cfg>::println(const char c[]) {
619
-  print(c);
620
-  println();
621
-}
622
-
623
-template<typename Cfg>
624
-void MarlinSerial<Cfg>::println(char c, int base) {
625
-  print(c, base);
626
-  println();
627
-}
628
-
629
-template<typename Cfg>
630
-void MarlinSerial<Cfg>::println(unsigned char b, int base) {
631
-  print(b, base);
632
-  println();
633
-}
634
-
635
-template<typename Cfg>
636
-void MarlinSerial<Cfg>::println(int n, int base) {
637
-  print(n, base);
638
-  println();
639
-}
640
-
641
-template<typename Cfg>
642
-void MarlinSerial<Cfg>::println(unsigned int n, int base) {
643
-  print(n, base);
644
-  println();
645
-}
646
-
647
-template<typename Cfg>
648
-void MarlinSerial<Cfg>::println(long n, int base) {
649
-  print(n, base);
650
-  println();
651
-}
652
-
653
-template<typename Cfg>
654
-void MarlinSerial<Cfg>::println(unsigned long n, int base) {
655
-  print(n, base);
656
-  println();
657
-}
658
-
659
-template<typename Cfg>
660
-void MarlinSerial<Cfg>::println(double n, int digits) {
661
-  print(n, digits);
662
-  println();
663
-}
664
-
665
-// Private Methods
666
-
667
-template<typename Cfg>
668
-void MarlinSerial<Cfg>::printNumber(unsigned long n, uint8_t base) {
669
-  if (n) {
670
-    unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
671
-    int8_t i = 0;
672
-    while (n) {
673
-      buf[i++] = n % base;
674
-      n /= base;
675
-    }
676
-    while (i--)
677
-      print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
678
-  }
679
-  else
680
-    print('0');
681
-}
682
-
683
-template<typename Cfg>
684
-void MarlinSerial<Cfg>::printFloat(double number, uint8_t digits) {
685
-  // Handle negative numbers
686
-  if (number < 0.0) {
687
-    print('-');
688
-    number = -number;
689
-  }
690
-
691
-  // Round correctly so that print(1.999, 2) prints as "2.00"
692
-  double rounding = 0.5;
693
-  LOOP_L_N(i, digits) rounding *= 0.1;
694
-  number += rounding;
695
-
696
-  // Extract the integer part of the number and print it
697
-  unsigned long int_part = (unsigned long)number;
698
-  double remainder = number - (double)int_part;
699
-  print(int_part);
700
-
701
-  // Print the decimal point, but only if there are digits beyond
702
-  if (digits) {
703
-    print('.');
704
-    // Extract digits from the remainder one at a time
705
-    while (digits--) {
706
-      remainder *= 10.0;
707
-      int toPrint = int(remainder);
708
-      print(toPrint);
709
-      remainder -= toPrint;
710
-    }
711
-  }
712
-}
713
-
714
 // Hookup ISR handlers
560
 // Hookup ISR handlers
715
 ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
561
 ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
716
   MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char();
562
   MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char();
720
   MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
566
   MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::_tx_udr_empty_irq();
721
 }
567
 }
722
 
568
 
723
-// Preinstantiate
724
-template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>;
725
-
726
-// Instantiate
727
-MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
569
+// Because of the template definition above, it's required to instantiate the template to have all method generated
570
+template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
571
+MSerialT customizedSerial1(MSerialT::HasEmergencyParser);
728
 
572
 
729
 #ifdef SERIAL_PORT_2
573
 #ifdef SERIAL_PORT_2
730
 
574
 
737
     MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::_tx_udr_empty_irq();
581
     MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>::_tx_udr_empty_irq();
738
   }
582
   }
739
 
583
 
740
-  // Preinstantiate
741
-  template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>;
742
-
743
-  // Instantiate
744
-  MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2;
745
-
584
+  template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
585
+  MSerialT2 customizedSerial2(MSerialT2::HasEmergencyParser);
746
 #endif
586
 #endif
747
 
587
 
748
 #ifdef MMU2_SERIAL_PORT
588
 #ifdef MMU2_SERIAL_PORT
755
     MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq();
595
     MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>::_tx_udr_empty_irq();
756
   }
596
   }
757
 
597
 
758
-  // Preinstantiate
759
-  template class MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>>;
760
-
761
-  // Instantiate
762
-  MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>> mmuSerial;
763
-
598
+  template class MarlinSerial< MarlinSerialCfg<MMU2_SERIAL_PORT> >;
599
+  MSerialT3 mmuSerial(MSerialT3::HasEmergencyParser);
764
 #endif
600
 #endif
765
 
601
 
766
 #ifdef LCD_SERIAL_PORT
602
 #ifdef LCD_SERIAL_PORT
773
     MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::_tx_udr_empty_irq();
609
     MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>::_tx_udr_empty_irq();
774
   }
610
   }
775
 
611
 
776
-  // Preinstantiate
777
-  template class MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>>;
778
-
779
-  // Instantiate
780
-  MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>> lcdSerial;
781
-
612
+  template class MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> >;
613
+  MSerialT4 lcdSerial(MSerialT4::HasEmergencyParser);
614
+ 
782
   #if HAS_DGUS_LCD
615
   #if HAS_DGUS_LCD
783
     template<typename Cfg>
616
     template<typename Cfg>
784
     typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
617
     typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
796
 
629
 
797
 // For AT90USB targets use the UART for BT interfacing
630
 // For AT90USB targets use the UART for BT interfacing
798
 #if defined(USBCON) && ENABLED(BLUETOOTH)
631
 #if defined(USBCON) && ENABLED(BLUETOOTH)
799
-  HardwareSerial bluetoothSerial;
632
+  MSerialT5 bluetoothSerial(false);
800
 #endif
633
 #endif
801
 
634
 
802
 #endif // __AVR__
635
 #endif // __AVR__

+ 33
- 62
Marlin/src/HAL/AVR/MarlinSerial.h View File

34
 #include <WString.h>
34
 #include <WString.h>
35
 
35
 
36
 #include "../../inc/MarlinConfigPre.h"
36
 #include "../../inc/MarlinConfigPre.h"
37
+#include "../../core/serial_hook.h"
37
 
38
 
38
 #ifndef SERIAL_PORT
39
 #ifndef SERIAL_PORT
39
   #define SERIAL_PORT 0
40
   #define SERIAL_PORT 0
135
     UART_DECL(3);
136
     UART_DECL(3);
136
   #endif
137
   #endif
137
 
138
 
138
-  #define DEC 10
139
-  #define HEX 16
140
-  #define OCT 8
141
-  #define BIN 2
142
   #define BYTE 0
139
   #define BYTE 0
143
 
140
 
144
   // Templated type selector
141
   // Templated type selector
202
     static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value);
199
     static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value);
203
     static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail();
200
     static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail();
204
 
201
 
205
-    public:
206
-
202
+  public:
207
     FORCE_INLINE static void store_rxd_char();
203
     FORCE_INLINE static void store_rxd_char();
208
     FORCE_INLINE static void _tx_udr_empty_irq();
204
     FORCE_INLINE static void _tx_udr_empty_irq();
209
 
205
 
210
-    public:
211
-      MarlinSerial() {};
212
-      static void begin(const long);
213
-      static void end();
214
-      static int peek();
215
-      static int read();
216
-      static void flush();
217
-      static ring_buffer_pos_t available();
218
-      static void write(const uint8_t c);
219
-      static void flushTX();
220
-      #if HAS_DGUS_LCD
221
-        static ring_buffer_pos_t get_tx_buffer_free();
222
-      #endif
223
-
224
-      static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
225
-
226
-      FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
227
-      FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
228
-      FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
229
-      FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
230
-
231
-      FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
232
-      FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
233
-      FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
234
-      FORCE_INLINE static void print(const char* str) { write(str); }
235
-
236
-      static void print(char, int = BYTE);
237
-      static void print(unsigned char, int = BYTE);
238
-      static void print(int, int = DEC);
239
-      static void print(unsigned int, int = DEC);
240
-      static void print(long, int = DEC);
241
-      static void print(unsigned long, int = DEC);
242
-      static void print(double, int = 2);
243
-
244
-      static void println(const String& s);
245
-      static void println(const char[]);
246
-      static void println(char, int = BYTE);
247
-      static void println(unsigned char, int = BYTE);
248
-      static void println(int, int = DEC);
249
-      static void println(unsigned int, int = DEC);
250
-      static void println(long, int = DEC);
251
-      static void println(unsigned long, int = DEC);
252
-      static void println(double, int = 2);
253
-      static void println();
254
-      operator bool() { return true; }
255
-
256
-    private:
257
-      static void printNumber(unsigned long, const uint8_t);
258
-      static void printFloat(double, uint8_t);
206
+  public:
207
+    static void begin(const long);
208
+    static void end();
209
+    static int peek();
210
+    static int read();
211
+    static void flush();
212
+    static ring_buffer_pos_t available();
213
+    static size_t write(const uint8_t c);
214
+    static void flushTX();
215
+    #if HAS_DGUS_LCD
216
+      static ring_buffer_pos_t get_tx_buffer_free();
217
+    #endif
218
+
219
+    enum { HasEmergencyParser = Cfg::EMERGENCYPARSER };
220
+    static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
221
+
222
+    FORCE_INLINE static uint8_t dropped() { return Cfg::DROPPED_RX ? rx_dropped_bytes : 0; }
223
+    FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
224
+    FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
225
+    FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
259
   };
226
   };
260
 
227
 
261
   template <uint8_t serial>
228
   template <uint8_t serial>
270
     static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
237
     static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
271
     static constexpr bool MAX_RX_QUEUED     = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
238
     static constexpr bool MAX_RX_QUEUED     = ENABLED(SERIAL_STATS_MAX_RX_QUEUED);
272
   };
239
   };
273
-  extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
274
-
275
-  #ifdef SERIAL_PORT_2
276
 
240
 
277
-    extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2;
241
+  typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT; 
242
+  extern MSerialT customizedSerial1;
278
 
243
 
244
+  #ifdef SERIAL_PORT_2
245
+    typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2; 
246
+    extern MSerialT2 customizedSerial2;
279
   #endif
247
   #endif
280
 
248
 
281
 #endif // !USBCON
249
 #endif // !USBCON
294
     static constexpr bool RX_OVERRUNS       = false;
262
     static constexpr bool RX_OVERRUNS       = false;
295
   };
263
   };
296
 
264
 
297
-  extern MarlinSerial<MMU2SerialCfg<MMU2_SERIAL_PORT>> mmuSerial;
265
+  typedef Serial0Type< MarlinSerial< MMU2SerialCfg<MMU2_SERIAL_PORT> > > MSerialT3; 
266
+  extern MSerial3 mmuSerial;
298
 #endif
267
 #endif
299
 
268
 
300
 #ifdef LCD_SERIAL_PORT
269
 #ifdef LCD_SERIAL_PORT
322
     #endif
291
     #endif
323
   };
292
   };
324
 
293
 
325
-  extern MarlinSerial<LCDSerialCfg<LCD_SERIAL_PORT>> lcdSerial;
326
 
294
 
295
+  typedef Serial0Type< MarlinSerial< LCDSerialCfg<LCD_SERIAL_PORT> > > MSerialT4; 
296
+  extern MSerialT4 lcdSerial;
327
 #endif
297
 #endif
328
 
298
 
329
 // Use the UART for Bluetooth in AT90USB configurations
299
 // Use the UART for Bluetooth in AT90USB configurations
330
 #if defined(USBCON) && ENABLED(BLUETOOTH)
300
 #if defined(USBCON) && ENABLED(BLUETOOTH)
331
-  extern HardwareSerial bluetoothSerial;
301
+  typedef Serial0Type<HardwareSerial> MSerialT5;
302
+  extern MSerialT5 bluetoothSerial;
332
 #endif
303
 #endif

+ 7
- 0
Marlin/src/HAL/DUE/HAL.cpp View File

102
   return HAL_adc_result;
102
   return HAL_adc_result;
103
 }
103
 }
104
 
104
 
105
+// Forward the default serial port
106
+DefaultSerial MSerial(false, Serial);
107
+
108
+DefaultSerial1 MSerial1(false, Serial1);
109
+DefaultSerial2 MSerial2(false, Serial2);
110
+DefaultSerial3 MSerial3(false, Serial3);
111
+
105
 #endif // ARDUINO_ARCH_SAM
112
 #endif // ARDUINO_ARCH_SAM

+ 13
- 2
Marlin/src/HAL/DUE/HAL.h View File

36
 
36
 
37
 #include <stdint.h>
37
 #include <stdint.h>
38
 
38
 
39
-#define _MSERIAL(X) Serial##X
39
+#include "../../core/serial_hook.h"
40
+typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
41
+extern DefaultSerial MSerial;
42
+
43
+typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
44
+typedef ForwardSerial0Type< decltype(Serial2) > DefaultSerial2;
45
+typedef ForwardSerial0Type< decltype(Serial3) > DefaultSerial3;
46
+extern DefaultSerial1 MSerial1;
47
+extern DefaultSerial2 MSerial2;
48
+extern DefaultSerial3 MSerial3;
49
+
50
+#define _MSERIAL(X) MSerial##X
40
 #define MSERIAL(X) _MSERIAL(X)
51
 #define MSERIAL(X) _MSERIAL(X)
41
-#define Serial0 Serial
52
+#define MSerial0 MSerial
42
 
53
 
43
 // Define MYSERIAL0/1 before MarlinSerial includes!
54
 // Define MYSERIAL0/1 before MarlinSerial includes!
44
 #if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)
55
 #if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)

+ 7
- 159
Marlin/src/HAL/DUE/MarlinSerial.cpp View File

382
 }
382
 }
383
 
383
 
384
 template<typename Cfg>
384
 template<typename Cfg>
385
-void MarlinSerial<Cfg>::write(const uint8_t c) {
385
+size_t MarlinSerial<Cfg>::write(const uint8_t c) {
386
   _written = true;
386
   _written = true;
387
 
387
 
388
   if (Cfg::TX_SIZE == 0) {
388
   if (Cfg::TX_SIZE == 0) {
400
     // XOFF char at the RX isr, but it is properly handled there
400
     // XOFF char at the RX isr, but it is properly handled there
401
     if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
401
     if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
402
       HWUART->UART_THR = c;
402
       HWUART->UART_THR = c;
403
-      return;
403
+      return 1;
404
     }
404
     }
405
 
405
 
406
     const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
406
     const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
428
     // Enable TX isr - Non atomic, but it will eventually enable TX isr
428
     // Enable TX isr - Non atomic, but it will eventually enable TX isr
429
     HWUART->UART_IER = UART_IER_TXRDY;
429
     HWUART->UART_IER = UART_IER_TXRDY;
430
   }
430
   }
431
+  return 1;
431
 }
432
 }
432
 
433
 
433
 template<typename Cfg>
434
 template<typename Cfg>
473
   }
474
   }
474
 }
475
 }
475
 
476
 
476
-/**
477
- * Imports from print.h
478
- */
479
-
480
-template<typename Cfg>
481
-void MarlinSerial<Cfg>::print(char c, int base) {
482
-  print((long)c, base);
483
-}
484
-
485
-template<typename Cfg>
486
-void MarlinSerial<Cfg>::print(unsigned char b, int base) {
487
-  print((unsigned long)b, base);
488
-}
489
-
490
-template<typename Cfg>
491
-void MarlinSerial<Cfg>::print(int n, int base) {
492
-  print((long)n, base);
493
-}
494
-
495
-template<typename Cfg>
496
-void MarlinSerial<Cfg>::print(unsigned int n, int base) {
497
-  print((unsigned long)n, base);
498
-}
499
-
500
-template<typename Cfg>
501
-void MarlinSerial<Cfg>::print(long n, int base) {
502
-  if (base == 0) write(n);
503
-  else if (base == 10) {
504
-    if (n < 0) { print('-'); n = -n; }
505
-    printNumber(n, 10);
506
-  }
507
-  else
508
-    printNumber(n, base);
509
-}
510
-
511
-template<typename Cfg>
512
-void MarlinSerial<Cfg>::print(unsigned long n, int base) {
513
-  if (base == 0) write(n);
514
-  else printNumber(n, base);
515
-}
516
-
517
-template<typename Cfg>
518
-void MarlinSerial<Cfg>::print(double n, int digits) {
519
-  printFloat(n, digits);
520
-}
521
-
522
-template<typename Cfg>
523
-void MarlinSerial<Cfg>::println() {
524
-  print('\r');
525
-  print('\n');
526
-}
527
-
528
-template<typename Cfg>
529
-void MarlinSerial<Cfg>::println(const String& s) {
530
-  print(s);
531
-  println();
532
-}
533
-
534
-template<typename Cfg>
535
-void MarlinSerial<Cfg>::println(const char c[]) {
536
-  print(c);
537
-  println();
538
-}
539
-
540
-template<typename Cfg>
541
-void MarlinSerial<Cfg>::println(char c, int base) {
542
-  print(c, base);
543
-  println();
544
-}
545
-
546
-template<typename Cfg>
547
-void MarlinSerial<Cfg>::println(unsigned char b, int base) {
548
-  print(b, base);
549
-  println();
550
-}
551
-
552
-template<typename Cfg>
553
-void MarlinSerial<Cfg>::println(int n, int base) {
554
-  print(n, base);
555
-  println();
556
-}
557
-
558
-template<typename Cfg>
559
-void MarlinSerial<Cfg>::println(unsigned int n, int base) {
560
-  print(n, base);
561
-  println();
562
-}
563
-
564
-template<typename Cfg>
565
-void MarlinSerial<Cfg>::println(long n, int base) {
566
-  print(n, base);
567
-  println();
568
-}
569
-
570
-template<typename Cfg>
571
-void MarlinSerial<Cfg>::println(unsigned long n, int base) {
572
-  print(n, base);
573
-  println();
574
-}
575
-
576
-template<typename Cfg>
577
-void MarlinSerial<Cfg>::println(double n, int digits) {
578
-  print(n, digits);
579
-  println();
580
-}
581
-
582
-// Private Methods
583
-template<typename Cfg>
584
-void MarlinSerial<Cfg>::printNumber(unsigned long n, uint8_t base) {
585
-  if (n) {
586
-    unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
587
-    int8_t i = 0;
588
-    while (n) {
589
-      buf[i++] = n % base;
590
-      n /= base;
591
-    }
592
-    while (i--)
593
-      print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
594
-  }
595
-  else
596
-    print('0');
597
-}
598
-
599
-template<typename Cfg>
600
-void MarlinSerial<Cfg>::printFloat(double number, uint8_t digits) {
601
-  // Handle negative numbers
602
-  if (number < 0.0) {
603
-    print('-');
604
-    number = -number;
605
-  }
606
-
607
-  // Round correctly so that print(1.999, 2) prints as "2.00"
608
-  double rounding = 0.5;
609
-  LOOP_L_N(i, digits) rounding *= 0.1;
610
-  number += rounding;
611
-
612
-  // Extract the integer part of the number and print it
613
-  unsigned long int_part = (unsigned long)number;
614
-  double remainder = number - (double)int_part;
615
-  print(int_part);
616
-
617
-  // Print the decimal point, but only if there are digits beyond
618
-  if (digits) {
619
-    print('.');
620
-    // Extract digits from the remainder one at a time
621
-    while (digits--) {
622
-      remainder *= 10.0;
623
-      int toPrint = int(remainder);
624
-      print(toPrint);
625
-      remainder -= toPrint;
626
-    }
627
-  }
628
-}
629
 
477
 
630
 // If not using the USB port as serial port
478
 // If not using the USB port as serial port
631
 #if SERIAL_PORT >= 0
479
 #if SERIAL_PORT >= 0
632
-  template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>;      // Define
633
-  MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;   // Instantiate
480
+  template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT> >;
481
+  MSerialT customizedSerial1(MarlinSerialCfg<SERIAL_PORT>::EMERGENCYPARSER);
634
 #endif
482
 #endif
635
 
483
 
636
 #if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
484
 #if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
637
-  template class MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>>;    // Define
638
-  MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2; // Instantiate
485
+  template class MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> >;
486
+  MSerialT2 customizedSerial2(MarlinSerialCfg<SERIAL_PORT_2>::EMERGENCYPARSER);
639
 #endif
487
 #endif
640
 
488
 
641
 #endif // ARDUINO_ARCH_SAM
489
 #endif // ARDUINO_ARCH_SAM

+ 6
- 37
Marlin/src/HAL/DUE/MarlinSerial.h View File

30
 #include <WString.h>
30
 #include <WString.h>
31
 
31
 
32
 #include "../../inc/MarlinConfigPre.h"
32
 #include "../../inc/MarlinConfigPre.h"
33
-
34
-#define DEC 10
35
-#define HEX 16
36
-#define OCT 8
37
-#define BIN 2
33
+#include "../../core/serial_hook.h"
38
 
34
 
39
 // Define constants and variables for buffering incoming serial data.  We're
35
 // Define constants and variables for buffering incoming serial data.  We're
40
 // using a ring buffer (I think), in which rx_buffer_head is the index of the
36
 // using a ring buffer (I think), in which rx_buffer_head is the index of the
119
   static int read();
115
   static int read();
120
   static void flush();
116
   static void flush();
121
   static ring_buffer_pos_t available();
117
   static ring_buffer_pos_t available();
122
-  static void write(const uint8_t c);
118
+  static size_t write(const uint8_t c);
123
   static void flushTX();
119
   static void flushTX();
124
 
120
 
125
   static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
121
   static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
128
   FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
124
   FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
129
   FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
125
   FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
130
   FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
126
   FORCE_INLINE static ring_buffer_pos_t rxMaxEnqueued() { return Cfg::MAX_RX_QUEUED ? rx_max_enqueued : 0; }
131
-
132
-  FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
133
-  FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
134
-  FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
135
-  FORCE_INLINE static void print(const char* str) { write(str); }
136
-
137
-  static void print(char, int = 0);
138
-  static void print(unsigned char, int = 0);
139
-  static void print(int, int = DEC);
140
-  static void print(unsigned int, int = DEC);
141
-  static void print(long, int = DEC);
142
-  static void print(unsigned long, int = DEC);
143
-  static void print(double, int = 2);
144
-
145
-  static void println(const String& s);
146
-  static void println(const char[]);
147
-  static void println(char, int = 0);
148
-  static void println(unsigned char, int = 0);
149
-  static void println(int, int = DEC);
150
-  static void println(unsigned int, int = DEC);
151
-  static void println(long, int = DEC);
152
-  static void println(unsigned long, int = DEC);
153
-  static void println(double, int = 2);
154
-  static void println();
155
-  operator bool() { return true; }
156
-
157
-private:
158
-  static void printNumber(unsigned long, const uint8_t);
159
-  static void printFloat(double, uint8_t);
160
 };
127
 };
161
 
128
 
162
 // Serial port configuration
129
 // Serial port configuration
174
 };
141
 };
175
 
142
 
176
 #if SERIAL_PORT >= 0
143
 #if SERIAL_PORT >= 0
177
-  extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
144
+  typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT> > > MSerialT;
145
+  extern MSerialT customizedSerial1;
178
 #endif
146
 #endif
179
 
147
 
180
 #if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
148
 #if defined(SERIAL_PORT_2) && SERIAL_PORT_2 >= 0
181
-  extern MarlinSerial<MarlinSerialCfg<SERIAL_PORT_2>> customizedSerial2;
149
+  typedef Serial0Type< MarlinSerial< MarlinSerialCfg<SERIAL_PORT_2> > > MSerialT2;
150
+  extern MSerialT2 customizedSerial2;
182
 #endif
151
 #endif

+ 6
- 151
Marlin/src/HAL/DUE/MarlinSerialUSB.cpp View File

50
 // Pending character
50
 // Pending character
51
 static int pending_char = -1;
51
 static int pending_char = -1;
52
 
52
 
53
-#if ENABLED(EMERGENCY_PARSER)
54
-  static EmergencyParser::State emergency_state; // = EP_RESET
55
-#endif
56
-
57
 // Public Methods
53
 // Public Methods
58
 void MarlinSerialUSB::begin(const long) {}
54
 void MarlinSerialUSB::begin(const long) {}
59
 
55
 
111
 void MarlinSerialUSB::flush() { }
107
 void MarlinSerialUSB::flush() { }
112
 void MarlinSerialUSB::flushTX() { }
108
 void MarlinSerialUSB::flushTX() { }
113
 
109
 
114
-void MarlinSerialUSB::write(const uint8_t c) {
110
+size_t MarlinSerialUSB::write(const uint8_t c) {
115
 
111
 
116
   /* Do not even bother sending anything if USB CDC is not enumerated
112
   /* Do not even bother sending anything if USB CDC is not enumerated
117
      or not configured on the PC side or there is no program on the PC
113
      or not configured on the PC side or there is no program on the PC
118
      listening to our messages */
114
      listening to our messages */
119
   if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
115
   if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
120
-    return;
116
+    return 0;
121
 
117
 
122
   /* Wait until the PC has read the pending to be sent data */
118
   /* Wait until the PC has read the pending to be sent data */
123
   while (usb_task_cdc_isenabled() &&
119
   while (usb_task_cdc_isenabled() &&
129
      or not configured on the PC side or there is no program on the PC
125
      or not configured on the PC side or there is no program on the PC
130
      listening to our messages at this point */
126
      listening to our messages at this point */
131
   if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
127
   if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
132
-    return;
128
+    return 0;
133
 
129
 
134
   // Fifo full
130
   // Fifo full
135
   //  udi_cdc_signal_overrun();
131
   //  udi_cdc_signal_overrun();
136
   udi_cdc_putc(c);
132
   udi_cdc_putc(c);
137
-}
138
-
139
-/**
140
- * Imports from print.h
141
- */
142
-
143
-void MarlinSerialUSB::print(char c, int base) {
144
-  print((long)c, base);
145
-}
146
-
147
-void MarlinSerialUSB::print(unsigned char b, int base) {
148
-  print((unsigned long)b, base);
149
-}
150
-
151
-void MarlinSerialUSB::print(int n, int base) {
152
-  print((long)n, base);
153
-}
154
-
155
-void MarlinSerialUSB::print(unsigned int n, int base) {
156
-  print((unsigned long)n, base);
157
-}
158
-
159
-void MarlinSerialUSB::print(long n, int base) {
160
-  if (base == 0)
161
-    write(n);
162
-  else if (base == 10) {
163
-    if (n < 0) {
164
-      print('-');
165
-      n = -n;
166
-    }
167
-    printNumber(n, 10);
168
-  }
169
-  else
170
-    printNumber(n, base);
171
-}
172
-
173
-void MarlinSerialUSB::print(unsigned long n, int base) {
174
-  if (base == 0) write(n);
175
-  else printNumber(n, base);
176
-}
177
-
178
-void MarlinSerialUSB::print(double n, int digits) {
179
-  printFloat(n, digits);
180
-}
181
-
182
-void MarlinSerialUSB::println() {
183
-  print('\r');
184
-  print('\n');
185
-}
186
-
187
-void MarlinSerialUSB::println(const String& s) {
188
-  print(s);
189
-  println();
190
-}
191
-
192
-void MarlinSerialUSB::println(const char c[]) {
193
-  print(c);
194
-  println();
195
-}
196
-
197
-void MarlinSerialUSB::println(char c, int base) {
198
-  print(c, base);
199
-  println();
200
-}
201
-
202
-void MarlinSerialUSB::println(unsigned char b, int base) {
203
-  print(b, base);
204
-  println();
205
-}
206
-
207
-void MarlinSerialUSB::println(int n, int base) {
208
-  print(n, base);
209
-  println();
210
-}
211
-
212
-void MarlinSerialUSB::println(unsigned int n, int base) {
213
-  print(n, base);
214
-  println();
215
-}
216
-
217
-void MarlinSerialUSB::println(long n, int base) {
218
-  print(n, base);
219
-  println();
220
-}
221
-
222
-void MarlinSerialUSB::println(unsigned long n, int base) {
223
-  print(n, base);
224
-  println();
225
-}
226
-
227
-void MarlinSerialUSB::println(double n, int digits) {
228
-  print(n, digits);
229
-  println();
230
-}
231
-
232
-// Private Methods
233
-
234
-void MarlinSerialUSB::printNumber(unsigned long n, uint8_t base) {
235
-  if (n) {
236
-    unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
237
-    int8_t i = 0;
238
-    while (n) {
239
-      buf[i++] = n % base;
240
-      n /= base;
241
-    }
242
-    while (i--)
243
-      print((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
244
-  }
245
-  else
246
-    print('0');
247
-}
248
-
249
-void MarlinSerialUSB::printFloat(double number, uint8_t digits) {
250
-  // Handle negative numbers
251
-  if (number < 0.0) {
252
-    print('-');
253
-    number = -number;
254
-  }
255
-
256
-  // Round correctly so that print(1.999, 2) prints as "2.00"
257
-  double rounding = 0.5;
258
-  LOOP_L_N(i, digits)
259
-    rounding *= 0.1;
260
-
261
-  number += rounding;
262
-
263
-  // Extract the integer part of the number and print it
264
-  unsigned long int_part = (unsigned long)number;
265
-  double remainder = number - (double)int_part;
266
-  print(int_part);
267
-
268
-  // Print the decimal point, but only if there are digits beyond
269
-  if (digits) {
270
-    print('.');
271
-    // Extract digits from the remainder one at a time
272
-    while (digits--) {
273
-      remainder *= 10.0;
274
-      int toPrint = int(remainder);
275
-      print(toPrint);
276
-      remainder -= toPrint;
277
-    }
278
-  }
133
+  return 1;
279
 }
134
 }
280
 
135
 
281
 // Preinstantiate
136
 // Preinstantiate
282
 #if SERIAL_PORT == -1
137
 #if SERIAL_PORT == -1
283
-  MarlinSerialUSB customizedSerial1;
138
+  MSerialT customizedSerial1(TERN0(EMERGENCY_PARSER, true));
284
 #endif
139
 #endif
285
 #if SERIAL_PORT_2 == -1
140
 #if SERIAL_PORT_2 == -1
286
-  MarlinSerialUSB customizedSerial2;
141
+  MSerialT customizedSerial2(TERN0(EMERGENCY_PARSER, true));
287
 #endif
142
 #endif
288
 
143
 
289
 #endif // HAS_USB_SERIAL
144
 #endif // HAS_USB_SERIAL

+ 6
- 41
Marlin/src/HAL/DUE/MarlinSerialUSB.h View File

27
  */
27
  */
28
 
28
 
29
 #include "../../inc/MarlinConfig.h"
29
 #include "../../inc/MarlinConfig.h"
30
-
31
 #if HAS_USB_SERIAL
30
 #if HAS_USB_SERIAL
32
 
31
 
33
 #include <WString.h>
32
 #include <WString.h>
33
+#include "../../core/serial_hook.h"
34
 
34
 
35
-#define DEC 10
36
-#define HEX 16
37
-#define OCT 8
38
-#define BIN 2
39
-
40
-class MarlinSerialUSB {
41
 
35
 
42
-public:
43
-  MarlinSerialUSB() {};
36
+struct MarlinSerialUSB {
44
   static void begin(const long);
37
   static void begin(const long);
45
   static void end();
38
   static void end();
46
   static int peek();
39
   static int peek();
48
   static void flush();
41
   static void flush();
49
   static void flushTX();
42
   static void flushTX();
50
   static bool available();
43
   static bool available();
51
-  static void write(const uint8_t c);
44
+  static size_t write(const uint8_t c);
52
 
45
 
53
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
46
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
54
     FORCE_INLINE static uint32_t dropped() { return 0; }
47
     FORCE_INLINE static uint32_t dropped() { return 0; }
57
   #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
50
   #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
58
     FORCE_INLINE static int rxMaxEnqueued() { return 0; }
51
     FORCE_INLINE static int rxMaxEnqueued() { return 0; }
59
   #endif
52
   #endif
60
-
61
-  FORCE_INLINE static void write(const char* str) { while (*str) write(*str++); }
62
-  FORCE_INLINE static void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
63
-  FORCE_INLINE static void print(const String& s) { for (int i = 0; i < (int)s.length(); i++) write(s[i]); }
64
-  FORCE_INLINE static void print(const char* str) { write(str); }
65
-
66
-  static void print(char, int = 0);
67
-  static void print(unsigned char, int = 0);
68
-  static void print(int, int = DEC);
69
-  static void print(unsigned int, int = DEC);
70
-  static void print(long, int = DEC);
71
-  static void print(unsigned long, int = DEC);
72
-  static void print(double, int = 2);
73
-
74
-  static void println(const String& s);
75
-  static void println(const char[]);
76
-  static void println(char, int = 0);
77
-  static void println(unsigned char, int = 0);
78
-  static void println(int, int = DEC);
79
-  static void println(unsigned int, int = DEC);
80
-  static void println(long, int = DEC);
81
-  static void println(unsigned long, int = DEC);
82
-  static void println(double, int = 2);
83
-  static void println();
84
-  operator bool() { return true; }
85
-
86
-private:
87
-  static void printNumber(unsigned long, const uint8_t);
88
-  static void printFloat(double, uint8_t);
89
 };
53
 };
54
+typedef Serial0Type<MarlinSerialUSB> MSerialT;
90
 
55
 
91
 #if SERIAL_PORT == -1
56
 #if SERIAL_PORT == -1
92
-  extern MarlinSerialUSB customizedSerial1;
57
+  extern MSerialT customizedSerial1;
93
 #endif
58
 #endif
94
 
59
 
95
 #if SERIAL_PORT_2 == -1
60
 #if SERIAL_PORT_2 == -1
96
-  extern MarlinSerialUSB customizedSerial2;
61
+  extern MSerialT customizedSerial2;
97
 #endif
62
 #endif
98
 
63
 
99
 #endif // HAS_USB_SERIAL
64
 #endif // HAS_USB_SERIAL

+ 2
- 2
Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp View File

68
   {
68
   {
69
     char buffer[80];
69
     char buffer[80];
70
     sprintf_P(buffer, PSTR("SDRD: %d @ 0x%08x\n"), nb_sector, addr);
70
     sprintf_P(buffer, PSTR("SDRD: %d @ 0x%08x\n"), nb_sector, addr);
71
-    PORT_REDIRECT(0);
71
+    PORT_REDIRECT(SERIAL_PORTMASK(0));
72
     SERIAL_ECHO(buffer);
72
     SERIAL_ECHO(buffer);
73
   }
73
   }
74
   #endif
74
   #endif
108
   {
108
   {
109
     char buffer[80];
109
     char buffer[80];
110
     sprintf_P(buffer, PSTR("SDWR: %d @ 0x%08x\n"), nb_sector, addr);
110
     sprintf_P(buffer, PSTR("SDWR: %d @ 0x%08x\n"), nb_sector, addr);
111
-    PORT_REDIRECT(0);
111
+    PORT_REDIRECT(SERIAL_PORTMASK(0));
112
     SERIAL_ECHO(buffer);
112
     SERIAL_ECHO(buffer);
113
   }
113
   }
114
   #endif
114
   #endif

+ 1
- 4
Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp View File

24
 
24
 
25
 #ifdef ARDUINO_ARCH_ESP32
25
 #ifdef ARDUINO_ARCH_ESP32
26
 
26
 
27
-FlushableHardwareSerial::FlushableHardwareSerial(int uart_nr)
28
-    : HardwareSerial(uart_nr)
29
-{}
30
 
27
 
31
-FlushableHardwareSerial flushableSerial(0);
28
+Serial0Type<FlushableHardwareSerial> flushableSerial(false, 0);
32
 
29
 
33
 #endif // ARDUINO_ARCH_ESP32
30
 #endif // ARDUINO_ARCH_ESP32

+ 3
- 4
Marlin/src/HAL/ESP32/FlushableHardwareSerial.h View File

24
 #ifdef ARDUINO_ARCH_ESP32
24
 #ifdef ARDUINO_ARCH_ESP32
25
 
25
 
26
 #include <HardwareSerial.h>
26
 #include <HardwareSerial.h>
27
+#include "../../core/serial_hook.h"
27
 
28
 
28
 class FlushableHardwareSerial : public HardwareSerial {
29
 class FlushableHardwareSerial : public HardwareSerial {
29
 public:
30
 public:
30
-  FlushableHardwareSerial(int uart_nr);
31
-
32
-  inline void flushTX() { /* No need to flush the hardware serial, but defined here for compatibility. */ }
31
+  FlushableHardwareSerial(int uart_nr) : HardwareSerial(uart_nr) {}
33
 };
32
 };
34
 
33
 
35
-extern FlushableHardwareSerial flushableSerial;
34
+extern Serial0Type<FlushableHardwareSerial> flushableSerial;
36
 
35
 
37
 #endif // ARDUINO_ARCH_ESP32
36
 #endif // ARDUINO_ARCH_ESP32

+ 4
- 0
Marlin/src/HAL/ESP32/HAL.cpp View File

40
   #endif
40
   #endif
41
 #endif
41
 #endif
42
 
42
 
43
+#if ENABLED(ESP3D_WIFISUPPORT)
44
+  DefaultSerial MSerial(false, Serial2Socket);
45
+#endif
46
+
43
 // ------------------------
47
 // ------------------------
44
 // Externs
48
 // Externs
45
 // ------------------------
49
 // ------------------------

+ 3
- 1
Marlin/src/HAL/ESP32/HAL.h View File

55
 
55
 
56
 #if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT)
56
 #if EITHER(WIFISUPPORT, ESP3D_WIFISUPPORT)
57
   #if ENABLED(ESP3D_WIFISUPPORT)
57
   #if ENABLED(ESP3D_WIFISUPPORT)
58
-    #define MYSERIAL1 Serial2Socket
58
+    typedef ForwardSerial0Type< decltype(Serial2Socket) > DefaultSerial;
59
+    extern DefaultSerial MSerial;
60
+    #define MYSERIAL1 MSerial
59
   #else
61
   #else
60
     #define MYSERIAL1 webSocketSerial
62
     #define MYSERIAL1 webSocketSerial
61
   #endif
63
   #endif

+ 1
- 5
Marlin/src/HAL/ESP32/WebSocketSerial.cpp View File

29
 #include "wifi.h"
29
 #include "wifi.h"
30
 #include <ESPAsyncWebServer.h>
30
 #include <ESPAsyncWebServer.h>
31
 
31
 
32
-WebSocketSerial webSocketSerial;
32
+MSerialT webSocketSerial(false);
33
 AsyncWebSocket ws("/ws"); // TODO Move inside the class.
33
 AsyncWebSocket ws("/ws"); // TODO Move inside the class.
34
 
34
 
35
 // RingBuffer impl
35
 // RingBuffer impl
144
   return written;
144
   return written;
145
 }
145
 }
146
 
146
 
147
-void WebSocketSerial::flushTX() {
148
-  // No need to do anything as there's no benefit to sending partial lines over the websocket connection.
149
-}
150
-
151
 #endif // WIFISUPPORT
147
 #endif // WIFISUPPORT
152
 #endif // ARDUINO_ARCH_ESP32
148
 #endif // ARDUINO_ARCH_ESP32

+ 3
- 4
Marlin/src/HAL/ESP32/WebSocketSerial.h View File

22
 #pragma once
22
 #pragma once
23
 
23
 
24
 #include "../../inc/MarlinConfig.h"
24
 #include "../../inc/MarlinConfig.h"
25
+#include "../../core/serial_hook.h"
25
 
26
 
26
 #include <Stream.h>
27
 #include <Stream.h>
27
 
28
 
68
   int peek();
69
   int peek();
69
   int read();
70
   int read();
70
   void flush();
71
   void flush();
71
-  void flushTX();
72
   size_t write(const uint8_t c);
72
   size_t write(const uint8_t c);
73
   size_t write(const uint8_t* buffer, size_t size);
73
   size_t write(const uint8_t* buffer, size_t size);
74
 
74
 
75
-  operator bool() { return true; }
76
-
77
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
75
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
78
     FORCE_INLINE uint32_t dropped() { return 0; }
76
     FORCE_INLINE uint32_t dropped() { return 0; }
79
   #endif
77
   #endif
83
   #endif
81
   #endif
84
 };
82
 };
85
 
83
 
86
-extern WebSocketSerial webSocketSerial;
84
+typedef Serial0Type<WebSocketSerial> MSerialT;
85
+extern MSerialT webSocketSerial;

+ 1
- 1
Marlin/src/HAL/LINUX/HAL.cpp View File

24
 #include "../../inc/MarlinConfig.h"
24
 #include "../../inc/MarlinConfig.h"
25
 #include "../shared/Delay.h"
25
 #include "../shared/Delay.h"
26
 
26
 
27
-HalSerial usb_serial;
27
+MSerialT usb_serial(TERN0(EMERGENCY_PARSER, true));
28
 
28
 
29
 // U8glib required functions
29
 // U8glib required functions
30
 extern "C" {
30
 extern "C" {

+ 1
- 1
Marlin/src/HAL/LINUX/HAL.h View File

60
 
60
 
61
 #define SHARED_SERVOS HAS_SERVOS
61
 #define SHARED_SERVOS HAS_SERVOS
62
 
62
 
63
-extern HalSerial usb_serial;
63
+extern MSerialT usb_serial;
64
 #define MYSERIAL0 usb_serial
64
 #define MYSERIAL0 usb_serial
65
 
65
 
66
 #define ST7920_DELAY_1 DELAY_NS(600)
66
 #define ST7920_DELAY_1 DELAY_NS(600)

+ 6
- 96
Marlin/src/HAL/LINUX/include/serial.h View File

25
 #if ENABLED(EMERGENCY_PARSER)
25
 #if ENABLED(EMERGENCY_PARSER)
26
   #include "../../../feature/e_parser.h"
26
   #include "../../../feature/e_parser.h"
27
 #endif
27
 #endif
28
+#include "../../../core/serial_hook.h"
28
 
29
 
29
 #include <stdarg.h>
30
 #include <stdarg.h>
30
 #include <stdio.h>
31
 #include <stdio.h>
73
   volatile uint32_t index_read;
74
   volatile uint32_t index_read;
74
 };
75
 };
75
 
76
 
76
-class HalSerial {
77
-public:
78
-
79
-  #if ENABLED(EMERGENCY_PARSER)
80
-    EmergencyParser::State emergency_state;
81
-    static inline bool emergency_parser_enabled() { return true; }
82
-  #endif
83
-
77
+struct HalSerial {
84
   HalSerial() { host_connected = true; }
78
   HalSerial() { host_connected = true; }
85
 
79
 
86
   void begin(int32_t) {}
80
   void begin(int32_t) {}
87
-
88
-  void end() {}
81
+  void end()          {}
89
 
82
 
90
   int peek() {
83
   int peek() {
91
     uint8_t value;
84
     uint8_t value;
100
     return transmit_buffer.write(c);
93
     return transmit_buffer.write(c);
101
   }
94
   }
102
 
95
 
103
-  operator bool() { return host_connected; }
96
+  bool connected() { return host_connected; }
104
 
97
 
105
   uint16_t available() {
98
   uint16_t available() {
106
     return (uint16_t)receive_buffer.available();
99
     return (uint16_t)receive_buffer.available();
117
       while (transmit_buffer.available()) { /* nada */ }
110
       while (transmit_buffer.available()) { /* nada */ }
118
   }
111
   }
119
 
112
 
120
-  void printf(const char *format, ...) {
121
-    static char buffer[256];
122
-    va_list vArgs;
123
-    va_start(vArgs, format);
124
-    int length = vsnprintf((char *) buffer, 256, (char const *) format, vArgs);
125
-    va_end(vArgs);
126
-    if (length > 0 && length < 256) {
127
-      if (host_connected) {
128
-        for (int i = 0; i < length;) {
129
-          if (transmit_buffer.write(buffer[i])) {
130
-            ++i;
131
-          }
132
-        }
133
-      }
134
-    }
135
-  }
136
-
137
-  #define DEC 10
138
-  #define HEX 16
139
-  #define OCT 8
140
-  #define BIN 2
141
-
142
-  void print_bin(uint32_t value, uint8_t num_digits) {
143
-    uint32_t mask = 1 << (num_digits -1);
144
-    for (uint8_t i = 0; i < num_digits; i++) {
145
-      if (!(i %  4) && i) write(' ');
146
-      if (!(i % 16) && i) write(' ');
147
-      if (value & mask)   write('1');
148
-      else                write('0');
149
-      value <<= 1;
150
-    }
151
-  }
152
-
153
-  void print(const char value[]) { printf("%s" , value); }
154
-  void print(char value, int nbase = 0) {
155
-    if (nbase == BIN) print_bin(value, 8);
156
-    else if (nbase == OCT) printf("%3o", value);
157
-    else if (nbase == HEX) printf("%2X", value);
158
-    else if (nbase == DEC ) printf("%d", value);
159
-    else printf("%c" , value);
160
-  }
161
-  void print(unsigned char value, int nbase = 0) {
162
-    if (nbase == BIN) print_bin(value, 8);
163
-    else if (nbase == OCT) printf("%3o", value);
164
-    else if (nbase == HEX) printf("%2X", value);
165
-    else printf("%u" , value);
166
-  }
167
-  void print(int value, int nbase = 0) {
168
-    if (nbase == BIN) print_bin(value, 16);
169
-    else if (nbase == OCT) printf("%6o", value);
170
-    else if (nbase == HEX) printf("%4X", value);
171
-    else printf("%d", value);
172
-  }
173
-  void print(unsigned int value, int nbase = 0) {
174
-    if (nbase == BIN) print_bin(value, 16);
175
-    else if (nbase == OCT) printf("%6o", value);
176
-    else if (nbase == HEX) printf("%4X", value);
177
-    else printf("%u" , value);
178
-  }
179
-  void print(long value, int nbase = 0) {
180
-    if (nbase == BIN) print_bin(value, 32);
181
-    else if (nbase == OCT) printf("%11o", value);
182
-    else if (nbase == HEX) printf("%8X", value);
183
-    else printf("%ld" , value);
184
-  }
185
-  void print(unsigned long value, int nbase = 0) {
186
-    if (nbase == BIN) print_bin(value, 32);
187
-    else if (nbase == OCT) printf("%11o", value);
188
-    else if (nbase == HEX) printf("%8X", value);
189
-    else printf("%lu" , value);
190
-  }
191
-  void print(float value, int round = 6)  { printf("%f" , value); }
192
-  void print(double value, int round = 6) { printf("%f" , value); }
193
-
194
-  void println(const char value[]) { printf("%s\n" , value); }
195
-  void println(char value, int nbase = 0) { print(value, nbase); println(); }
196
-  void println(unsigned char value, int nbase = 0) { print(value, nbase); println(); }
197
-  void println(int value, int nbase = 0) { print(value, nbase); println(); }
198
-  void println(unsigned int value, int nbase = 0) { print(value, nbase); println(); }
199
-  void println(long value, int nbase = 0) { print(value, nbase); println(); }
200
-  void println(unsigned long value, int nbase = 0) { print(value, nbase); println(); }
201
-  void println(float value, int round = 6) { printf("%f\n" , value); }
202
-  void println(double value, int round = 6) { printf("%f\n" , value); }
203
-  void println() { print('\n'); }
204
-
205
   volatile RingBuffer<uint8_t, 128> receive_buffer;
113
   volatile RingBuffer<uint8_t, 128> receive_buffer;
206
   volatile RingBuffer<uint8_t, 128> transmit_buffer;
114
   volatile RingBuffer<uint8_t, 128> transmit_buffer;
207
   volatile bool host_connected;
115
   volatile bool host_connected;
208
 };
116
 };
117
+
118
+typedef Serial0Type<HalSerial> MSerialT;

+ 2
- 0
Marlin/src/HAL/LPC1768/HAL.cpp View File

29
   #include "watchdog.h"
29
   #include "watchdog.h"
30
 #endif
30
 #endif
31
 
31
 
32
+DefaultSerial USBSerial(false, UsbSerial);
33
+
32
 uint32_t HAL_adc_reading = 0;
34
 uint32_t HAL_adc_reading = 0;
33
 
35
 
34
 // U8glib required functions
36
 // U8glib required functions

+ 7
- 4
Marlin/src/HAL/LPC1768/HAL.h View File

60
   #define ST7920_DELAY_3 DELAY_NS(750)
60
   #define ST7920_DELAY_3 DELAY_NS(750)
61
 #endif
61
 #endif
62
 
62
 
63
+typedef ForwardSerial0Type< decltype(UsbSerial) > DefaultSerial;
64
+extern DefaultSerial USBSerial;
65
+
63
 #define _MSERIAL(X) MSerial##X
66
 #define _MSERIAL(X) MSerial##X
64
 #define MSERIAL(X) _MSERIAL(X)
67
 #define MSERIAL(X) _MSERIAL(X)
65
 #define MSerial0 MSerial
68
 #define MSerial0 MSerial
66
 
69
 
67
 #if SERIAL_PORT == -1
70
 #if SERIAL_PORT == -1
68
-  #define MYSERIAL0 UsbSerial
71
+  #define MYSERIAL0 USBSerial
69
 #elif WITHIN(SERIAL_PORT, 0, 3)
72
 #elif WITHIN(SERIAL_PORT, 0, 3)
70
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
73
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
71
 #else
74
 #else
74
 
77
 
75
 #ifdef SERIAL_PORT_2
78
 #ifdef SERIAL_PORT_2
76
   #if SERIAL_PORT_2 == -1
79
   #if SERIAL_PORT_2 == -1
77
-    #define MYSERIAL1 UsbSerial
80
+    #define MYSERIAL1 USBSerial
78
   #elif WITHIN(SERIAL_PORT_2, 0, 3)
81
   #elif WITHIN(SERIAL_PORT_2, 0, 3)
79
     #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
82
     #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
80
   #else
83
   #else
84
 
87
 
85
 #ifdef MMU2_SERIAL_PORT
88
 #ifdef MMU2_SERIAL_PORT
86
   #if MMU2_SERIAL_PORT == -1
89
   #if MMU2_SERIAL_PORT == -1
87
-    #define MMU2_SERIAL UsbSerial
90
+    #define MMU2_SERIAL USBSerial
88
   #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
91
   #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
89
     #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
92
     #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
90
   #else
93
   #else
94
 
97
 
95
 #ifdef LCD_SERIAL_PORT
98
 #ifdef LCD_SERIAL_PORT
96
   #if LCD_SERIAL_PORT == -1
99
   #if LCD_SERIAL_PORT == -1
97
-    #define LCD_SERIAL UsbSerial
100
+    #define LCD_SERIAL USBSerial
98
   #elif WITHIN(LCD_SERIAL_PORT, 0, 3)
101
   #elif WITHIN(LCD_SERIAL_PORT, 0, 3)
99
     #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
102
     #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
100
   #else
103
   #else

+ 4
- 4
Marlin/src/HAL/LPC1768/MarlinSerial.cpp View File

25
 #include "MarlinSerial.h"
25
 #include "MarlinSerial.h"
26
 
26
 
27
 #if USING_SERIAL_0
27
 #if USING_SERIAL_0
28
-  MarlinSerial MSerial(LPC_UART0);
28
+  MSerialT MSerial(true, LPC_UART0);
29
   extern "C" void UART0_IRQHandler() { MSerial.IRQHandler(); }
29
   extern "C" void UART0_IRQHandler() { MSerial.IRQHandler(); }
30
 #endif
30
 #endif
31
 #if USING_SERIAL_1
31
 #if USING_SERIAL_1
32
-  MarlinSerial MSerial1((LPC_UART_TypeDef *) LPC_UART1);
32
+  MSerialT MSerial1(true, (LPC_UART_TypeDef *) LPC_UART1);
33
   extern "C" void UART1_IRQHandler() { MSerial1.IRQHandler(); }
33
   extern "C" void UART1_IRQHandler() { MSerial1.IRQHandler(); }
34
 #endif
34
 #endif
35
 #if USING_SERIAL_2
35
 #if USING_SERIAL_2
36
-  MarlinSerial MSerial2(LPC_UART2);
36
+  MSerialT MSerial2(true, LPC_UART2);
37
   extern "C" void UART2_IRQHandler() { MSerial2.IRQHandler(); }
37
   extern "C" void UART2_IRQHandler() { MSerial2.IRQHandler(); }
38
 #endif
38
 #endif
39
 #if USING_SERIAL_3
39
 #if USING_SERIAL_3
40
-  MarlinSerial MSerial3(LPC_UART3);
40
+  MSerialT MSerial3(true, LPC_UART3);
41
   extern "C" void UART3_IRQHandler() { MSerial3.IRQHandler(); }
41
   extern "C" void UART3_IRQHandler() { MSerial3.IRQHandler(); }
42
 #endif
42
 #endif
43
 
43
 

+ 8
- 14
Marlin/src/HAL/LPC1768/MarlinSerial.h View File

28
 #if ENABLED(EMERGENCY_PARSER)
28
 #if ENABLED(EMERGENCY_PARSER)
29
   #include "../../feature/e_parser.h"
29
   #include "../../feature/e_parser.h"
30
 #endif
30
 #endif
31
+#include "../../core/serial_hook.h"
31
 
32
 
32
 #ifndef SERIAL_PORT
33
 #ifndef SERIAL_PORT
33
   #define SERIAL_PORT 0
34
   #define SERIAL_PORT 0
41
 
42
 
42
 class MarlinSerial : public HardwareSerial<RX_BUFFER_SIZE, TX_BUFFER_SIZE> {
43
 class MarlinSerial : public HardwareSerial<RX_BUFFER_SIZE, TX_BUFFER_SIZE> {
43
 public:
44
 public:
44
-  MarlinSerial(LPC_UART_TypeDef *UARTx) :
45
-    HardwareSerial<RX_BUFFER_SIZE, TX_BUFFER_SIZE>(UARTx)
46
-    #if ENABLED(EMERGENCY_PARSER)
47
-      , emergency_state(EmergencyParser::State::EP_RESET)
48
-    #endif
49
-    { }
45
+  MarlinSerial(LPC_UART_TypeDef *UARTx) : HardwareSerial<RX_BUFFER_SIZE, TX_BUFFER_SIZE>(UARTx) { }
50
 
46
 
51
   void end() {}
47
   void end() {}
52
 
48
 
53
   #if ENABLED(EMERGENCY_PARSER)
49
   #if ENABLED(EMERGENCY_PARSER)
54
     bool recv_callback(const char c) override {
50
     bool recv_callback(const char c) override {
55
-      emergency_parser.update(emergency_state, c);
51
+      emergency_parser.update(static_cast<Serial0Type<MarlinSerial> *>(this)->emergency_state, c);
56
       return true; // do not discard character
52
       return true; // do not discard character
57
     }
53
     }
58
-
59
-    EmergencyParser::State emergency_state;
60
-    static inline bool emergency_parser_enabled() { return true; }
61
   #endif
54
   #endif
62
 };
55
 };
63
 
56
 
64
-extern MarlinSerial MSerial;
65
-extern MarlinSerial MSerial1;
66
-extern MarlinSerial MSerial2;
67
-extern MarlinSerial MSerial3;
57
+typedef Serial0Type<MarlinSerial> MSerialT;
58
+extern MSerialT MSerial;
59
+extern MSerialT MSerial1;
60
+extern MSerialT MSerial2;
61
+extern MSerialT MSerial3;

+ 5
- 0
Marlin/src/HAL/SAMD51/HAL.cpp View File

24
 #include <Adafruit_ZeroDMA.h>
24
 #include <Adafruit_ZeroDMA.h>
25
 #include <wiring_private.h>
25
 #include <wiring_private.h>
26
 
26
 
27
+#ifdef ADAFRUIT_GRAND_CENTRAL_M4
28
+  DefaultSerial MSerial(false, Serial);
29
+  DefaultSerial1 MSerial1(false, Serial1);
30
+#endif
31
+
27
 // ------------------------
32
 // ------------------------
28
 // Local defines
33
 // Local defines
29
 // ------------------------
34
 // ------------------------

+ 9
- 5
Marlin/src/HAL/SAMD51/HAL.h View File

32
   #include "MarlinSerial_AGCM4.h"
32
   #include "MarlinSerial_AGCM4.h"
33
 
33
 
34
   // Serial ports
34
   // Serial ports
35
+  typedef ForwardSerial0Type< decltype(Serial) > DefaultSerial;
36
+  extern DefaultSerial MSerial;
37
+  typedef ForwardSerial0Type< decltype(Serial1) > DefaultSerial1;
38
+  extern DefaultSerial1 MSerial1;
35
 
39
 
36
   // MYSERIAL0 required before MarlinSerial includes!
40
   // MYSERIAL0 required before MarlinSerial includes!
37
 
41
 
38
-  #define __MSERIAL(X) Serial##X
42
+  #define __MSERIAL(X) MSerial##X
39
   #define _MSERIAL(X) __MSERIAL(X)
43
   #define _MSERIAL(X) __MSERIAL(X)
40
   #define MSERIAL(X) _MSERIAL(INCREMENT(X))
44
   #define MSERIAL(X) _MSERIAL(INCREMENT(X))
41
 
45
 
42
   #if SERIAL_PORT == -1
46
   #if SERIAL_PORT == -1
43
-    #define MYSERIAL0 Serial
47
+    #define MYSERIAL0 MSerial
44
   #elif WITHIN(SERIAL_PORT, 0, 3)
48
   #elif WITHIN(SERIAL_PORT, 0, 3)
45
     #define MYSERIAL0 MSERIAL(SERIAL_PORT)
49
     #define MYSERIAL0 MSERIAL(SERIAL_PORT)
46
   #else
50
   #else
49
 
53
 
50
   #ifdef SERIAL_PORT_2
54
   #ifdef SERIAL_PORT_2
51
     #if SERIAL_PORT_2 == -1
55
     #if SERIAL_PORT_2 == -1
52
-      #define MYSERIAL1 Serial
56
+      #define MYSERIAL1 MSerial
53
     #elif WITHIN(SERIAL_PORT_2, 0, 3)
57
     #elif WITHIN(SERIAL_PORT_2, 0, 3)
54
       #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
58
       #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
55
     #else
59
     #else
59
 
63
 
60
   #ifdef MMU2_SERIAL_PORT
64
   #ifdef MMU2_SERIAL_PORT
61
     #if MMU2_SERIAL_PORT == -1
65
     #if MMU2_SERIAL_PORT == -1
62
-      #define MMU2_SERIAL Serial
66
+      #define MMU2_SERIAL MSerial
63
     #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
67
     #elif WITHIN(MMU2_SERIAL_PORT, 0, 3)
64
       #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
68
       #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
65
     #else
69
     #else
69
 
73
 
70
   #ifdef LCD_SERIAL_PORT
74
   #ifdef LCD_SERIAL_PORT
71
     #if LCD_SERIAL_PORT == -1
75
     #if LCD_SERIAL_PORT == -1
72
-      #define LCD_SERIAL Serial
76
+      #define LCD_SERIAL MSerial
73
     #elif WITHIN(LCD_SERIAL_PORT, 0, 3)
77
     #elif WITHIN(LCD_SERIAL_PORT, 0, 3)
74
       #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
78
       #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
75
     #else
79
     #else

+ 3
- 3
Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp View File

28
 #include "../../inc/MarlinConfig.h"
28
 #include "../../inc/MarlinConfig.h"
29
 
29
 
30
 #if USING_SERIAL_1
30
 #if USING_SERIAL_1
31
-  Uart Serial2(&sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
31
+  UartT Serial2(false, &sercom4, PIN_SERIAL2_RX, PIN_SERIAL2_TX, PAD_SERIAL2_RX, PAD_SERIAL2_TX);
32
   void SERCOM4_0_Handler() { Serial2.IrqHandler(); }
32
   void SERCOM4_0_Handler() { Serial2.IrqHandler(); }
33
   void SERCOM4_1_Handler() { Serial2.IrqHandler(); }
33
   void SERCOM4_1_Handler() { Serial2.IrqHandler(); }
34
   void SERCOM4_2_Handler() { Serial2.IrqHandler(); }
34
   void SERCOM4_2_Handler() { Serial2.IrqHandler(); }
36
 #endif
36
 #endif
37
 
37
 
38
 #if USING_SERIAL_2
38
 #if USING_SERIAL_2
39
-  Uart Serial3(&sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
39
+  UartT Serial3(false, &sercom1, PIN_SERIAL3_RX, PIN_SERIAL3_TX, PAD_SERIAL3_RX, PAD_SERIAL3_TX);
40
   void SERCOM1_0_Handler() { Serial3.IrqHandler(); }
40
   void SERCOM1_0_Handler() { Serial3.IrqHandler(); }
41
   void SERCOM1_1_Handler() { Serial3.IrqHandler(); }
41
   void SERCOM1_1_Handler() { Serial3.IrqHandler(); }
42
   void SERCOM1_2_Handler() { Serial3.IrqHandler(); }
42
   void SERCOM1_2_Handler() { Serial3.IrqHandler(); }
44
 #endif
44
 #endif
45
 
45
 
46
 #if USING_SERIAL_3
46
 #if USING_SERIAL_3
47
-  Uart Serial4(&sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
47
+  UartT Serial4(false, &sercom5, PIN_SERIAL4_RX, PIN_SERIAL4_TX, PAD_SERIAL4_RX, PAD_SERIAL4_TX);
48
   void SERCOM5_0_Handler() { Serial4.IrqHandler(); }
48
   void SERCOM5_0_Handler() { Serial4.IrqHandler(); }
49
   void SERCOM5_1_Handler() { Serial4.IrqHandler(); }
49
   void SERCOM5_1_Handler() { Serial4.IrqHandler(); }
50
   void SERCOM5_2_Handler() { Serial4.IrqHandler(); }
50
   void SERCOM5_2_Handler() { Serial4.IrqHandler(); }

+ 7
- 3
Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h View File

20
  */
20
  */
21
 #pragma once
21
 #pragma once
22
 
22
 
23
-extern Uart Serial2;
24
-extern Uart Serial3;
25
-extern Uart Serial4;
23
+#include "../../core/serial_hook.h"
24
+
25
+typedef Serial0Type<Uart> UartT;
26
+
27
+extern UartT Serial2;
28
+extern UartT Serial3;
29
+extern UartT Serial4;

+ 4
- 0
Marlin/src/HAL/STM32/HAL.cpp View File

28
 #include "../../inc/MarlinConfig.h"
28
 #include "../../inc/MarlinConfig.h"
29
 #include "../shared/Delay.h"
29
 #include "../shared/Delay.h"
30
 
30
 
31
+#ifdef USBCON
32
+  DefaultSerial MSerial(false, SerialUSB);
33
+#endif
34
+
31
 #if ENABLED(SRAM_EEPROM_EMULATION)
35
 #if ENABLED(SRAM_EEPROM_EMULATION)
32
   #if STM32F7xx
36
   #if STM32F7xx
33
     #include <stm32f7xx_ll_pwr.h>
37
     #include <stm32f7xx_ll_pwr.h>

+ 7
- 4
Marlin/src/HAL/STM32/HAL.h View File

39
 
39
 
40
 #ifdef USBCON
40
 #ifdef USBCON
41
   #include <USBSerial.h>
41
   #include <USBSerial.h>
42
+  #include "../../core/serial_hook.h" 
43
+  typedef ForwardSerial0Type< decltype(SerialUSB) > DefaultSerial;
44
+  extern DefaultSerial MSerial;
42
 #endif
45
 #endif
43
 
46
 
44
 // ------------------------
47
 // ------------------------
48
 #define MSERIAL(X) _MSERIAL(X)
51
 #define MSERIAL(X) _MSERIAL(X)
49
 
52
 
50
 #if SERIAL_PORT == -1
53
 #if SERIAL_PORT == -1
51
-  #define MYSERIAL0 SerialUSB
54
+  #define MYSERIAL0 MSerial
52
 #elif WITHIN(SERIAL_PORT, 1, 6)
55
 #elif WITHIN(SERIAL_PORT, 1, 6)
53
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
56
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
54
 #else
57
 #else
57
 
60
 
58
 #ifdef SERIAL_PORT_2
61
 #ifdef SERIAL_PORT_2
59
   #if SERIAL_PORT_2 == -1
62
   #if SERIAL_PORT_2 == -1
60
-    #define MYSERIAL1 SerialUSB
63
+    #define MYSERIAL1 MSerial
61
   #elif WITHIN(SERIAL_PORT_2, 1, 6)
64
   #elif WITHIN(SERIAL_PORT_2, 1, 6)
62
     #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
65
     #define MYSERIAL1 MSERIAL(SERIAL_PORT_2)
63
   #else
66
   #else
67
 
70
 
68
 #ifdef MMU2_SERIAL_PORT
71
 #ifdef MMU2_SERIAL_PORT
69
   #if MMU2_SERIAL_PORT == -1
72
   #if MMU2_SERIAL_PORT == -1
70
-    #define MMU2_SERIAL SerialUSB
73
+    #define MMU2_SERIAL MSerial
71
   #elif WITHIN(MMU2_SERIAL_PORT, 1, 6)
74
   #elif WITHIN(MMU2_SERIAL_PORT, 1, 6)
72
     #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
75
     #define MMU2_SERIAL MSERIAL(MMU2_SERIAL_PORT)
73
   #else
76
   #else
77
 
80
 
78
 #ifdef LCD_SERIAL_PORT
81
 #ifdef LCD_SERIAL_PORT
79
   #if LCD_SERIAL_PORT == -1
82
   #if LCD_SERIAL_PORT == -1
80
-    #define LCD_SERIAL SerialUSB
83
+    #define LCD_SERIAL MSerial
81
   #elif WITHIN(LCD_SERIAL_PORT, 1, 6)
84
   #elif WITHIN(LCD_SERIAL_PORT, 1, 6)
82
     #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
85
     #define LCD_SERIAL MSERIAL(LCD_SERIAL_PORT)
83
   #else
86
   #else

+ 1
- 1
Marlin/src/HAL/STM32/MarlinSerial.cpp View File

35
 
35
 
36
 #define DECLARE_SERIAL_PORT(ser_num) \
36
 #define DECLARE_SERIAL_PORT(ser_num) \
37
   void _rx_complete_irq_ ## ser_num (serial_t * obj); \
37
   void _rx_complete_irq_ ## ser_num (serial_t * obj); \
38
-  MarlinSerial MSerial ## ser_num (USART ## ser_num, &_rx_complete_irq_ ## ser_num); \
38
+  MSerialT MSerial ## ser_num (true, USART ## ser_num, &_rx_complete_irq_ ## ser_num); \
39
   void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); }
39
   void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); }
40
 
40
 
41
 #define DECLARE_SERIAL_PORT_EXP(ser_num) DECLARE_SERIAL_PORT(ser_num)
41
 #define DECLARE_SERIAL_PORT_EXP(ser_num) DECLARE_SERIAL_PORT(ser_num)

+ 15
- 23
Marlin/src/HAL/STM32/MarlinSerial.h View File

24
   #include "../../feature/e_parser.h"
24
   #include "../../feature/e_parser.h"
25
 #endif
25
 #endif
26
 
26
 
27
+#include "../../core/serial_hook.h"
28
+
27
 typedef void (*usart_rx_callback_t)(serial_t * obj);
29
 typedef void (*usart_rx_callback_t)(serial_t * obj);
28
 
30
 
29
-class MarlinSerial : public HardwareSerial {
30
-public:
31
+struct MarlinSerial : public HardwareSerial {
31
   MarlinSerial(void* peripheral, usart_rx_callback_t rx_callback) :
32
   MarlinSerial(void* peripheral, usart_rx_callback_t rx_callback) :
32
       HardwareSerial(peripheral), _rx_callback(rx_callback)
33
       HardwareSerial(peripheral), _rx_callback(rx_callback)
33
-      #if ENABLED(EMERGENCY_PARSER)
34
-        , emergency_state(EmergencyParser::State::EP_RESET)
35
-      #endif
36
   { }
34
   { }
37
 
35
 
38
-  #if ENABLED(EMERGENCY_PARSER)
39
-    static inline bool emergency_parser_enabled() { return true; }
40
-  #endif
41
-
42
   void begin(unsigned long baud, uint8_t config);
36
   void begin(unsigned long baud, uint8_t config);
43
   inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
37
   inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
44
 
38
 
46
 
40
 
47
 protected:
41
 protected:
48
   usart_rx_callback_t _rx_callback;
42
   usart_rx_callback_t _rx_callback;
49
-  #if ENABLED(EMERGENCY_PARSER)
50
-    EmergencyParser::State emergency_state;
51
-  #endif
52
 };
43
 };
53
 
44
 
54
-extern MarlinSerial MSerial1;
55
-extern MarlinSerial MSerial2;
56
-extern MarlinSerial MSerial3;
57
-extern MarlinSerial MSerial4;
58
-extern MarlinSerial MSerial5;
59
-extern MarlinSerial MSerial6;
60
-extern MarlinSerial MSerial7;
61
-extern MarlinSerial MSerial8;
62
-extern MarlinSerial MSerial9;
63
-extern MarlinSerial MSerial10;
64
-extern MarlinSerial MSerialLP1;
45
+typedef Serial0Type<MarlinSerial> MSerialT;
46
+extern MSerialT MSerial1;
47
+extern MSerialT MSerial2;
48
+extern MSerialT MSerial3;
49
+extern MSerialT MSerial4;
50
+extern MSerialT MSerial5;
51
+extern MSerialT MSerial6;
52
+extern MSerialT MSerial7;
53
+extern MSerialT MSerial8;
54
+extern MSerialT MSerial9;
55
+extern MSerialT MSerial10;
56
+extern MSerialT MSerialLP1;

+ 1
- 0
Marlin/src/HAL/STM32F1/HAL.cpp View File

84
 
84
 
85
 #if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE
85
 #if defined(SERIAL_USB) && !HAS_SD_HOST_DRIVE
86
   USBSerial SerialUSB;
86
   USBSerial SerialUSB;
87
+  DefaultSerial MSerial(false, SerialUSB);
87
 #endif
88
 #endif
88
 
89
 
89
 uint16_t HAL_adc_result;
90
 uint16_t HAL_adc_result;

+ 4
- 1
Marlin/src/HAL/STM32F1/HAL.h View File

61
 #endif
61
 #endif
62
 
62
 
63
 #ifdef SERIAL_USB
63
 #ifdef SERIAL_USB
64
+  typedef ForwardSerial0Type< USBSerial > DefaultSerial;
65
+  extern DefaultSerial MSerial;
66
+
64
   #if !HAS_SD_HOST_DRIVE
67
   #if !HAS_SD_HOST_DRIVE
65
-    #define UsbSerial Serial
68
+    #define UsbSerial MSerial
66
   #else
69
   #else
67
     #define UsbSerial MarlinCompositeSerial
70
     #define UsbSerial MarlinCompositeSerial
68
   #endif
71
   #endif

+ 10
- 10
Marlin/src/HAL/STM32F1/MarlinSerial.cpp View File

28
 
28
 
29
 // Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h
29
 // Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h
30
 // Changed to handle Emergency Parser
30
 // Changed to handle Emergency Parser
31
-static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MarlinSerial &serial) {
31
+static inline __always_inline void my_usart_irq(ring_buffer *rb, ring_buffer *wb, usart_reg_map *regs, MSerialT &serial) {
32
  /* Handle RXNEIE and TXEIE interrupts.
32
  /* Handle RXNEIE and TXEIE interrupts.
33
   * RXNE signifies availability of a byte in DR.
33
   * RXNE signifies availability of a byte in DR.
34
   *
34
   *
90
   ;
90
   ;
91
 }
91
 }
92
 
92
 
93
-#define DEFINE_HWSERIAL_MARLIN(name, n)   \
94
-  MarlinSerial name(USART##n,             \
95
-            BOARD_USART##n##_TX_PIN,      \
96
-            BOARD_USART##n##_RX_PIN,      \
97
-            serial_handles_emergency(n)); \
98
-  extern "C" void __irq_usart##n(void) {  \
93
+#define DEFINE_HWSERIAL_MARLIN(name, n)     \
94
+  MSerialT name(serial_handles_emergency(n),\
95
+            USART##n,                       \
96
+            BOARD_USART##n##_TX_PIN,        \
97
+            BOARD_USART##n##_RX_PIN);       \
98
+  extern "C" void __irq_usart##n(void) {    \
99
     my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \
99
     my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \
100
   }
100
   }
101
 
101
 
102
 #define DEFINE_HWSERIAL_UART_MARLIN(name, n) \
102
 #define DEFINE_HWSERIAL_UART_MARLIN(name, n) \
103
-  MarlinSerial name(UART##n,                 \
103
+  MSerialT name(serial_handles_emergency(n), \
104
+          UART##n,                           \
104
           BOARD_USART##n##_TX_PIN,           \
105
           BOARD_USART##n##_TX_PIN,           \
105
-          BOARD_USART##n##_RX_PIN,           \
106
-          serial_handles_emergency(n));      \
106
+          BOARD_USART##n##_RX_PIN);          \
107
   extern "C" void __irq_usart##n(void) {     \
107
   extern "C" void __irq_usart##n(void) {     \
108
     my_usart_irq(UART##n->rb, UART##n->wb, UART##n##_BASE, MSerial##n); \
108
     my_usart_irq(UART##n->rb, UART##n->wb, UART##n##_BASE, MSerial##n); \
109
   }
109
   }

+ 10
- 23
Marlin/src/HAL/STM32F1/MarlinSerial.h View File

26
 #include <WString.h>
26
 #include <WString.h>
27
 
27
 
28
 #include "../../inc/MarlinConfigPre.h"
28
 #include "../../inc/MarlinConfigPre.h"
29
-#if ENABLED(EMERGENCY_PARSER)
30
-  #include "../../feature/e_parser.h"
31
-#endif
29
+#include "../../core/serial_hook.h"
32
 
30
 
33
 // Increase priority of serial interrupts, to reduce overflow errors
31
 // Increase priority of serial interrupts, to reduce overflow errors
34
 #define UART_IRQ_PRIO 1
32
 #define UART_IRQ_PRIO 1
35
 
33
 
36
-class MarlinSerial : public HardwareSerial {
37
-public:
38
-  #if ENABLED(EMERGENCY_PARSER)
39
-    const bool ep_enabled;
40
-    EmergencyParser::State emergency_state;
41
-    inline bool emergency_parser_enabled() { return ep_enabled; }
42
-  #endif
43
-
44
-  MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin, bool TERN_(EMERGENCY_PARSER, ep_capable)) :
45
-    HardwareSerial(usart_device, tx_pin, rx_pin)
46
-    #if ENABLED(EMERGENCY_PARSER)
47
-      , ep_enabled(ep_capable)
48
-      , emergency_state(EmergencyParser::State::EP_RESET)
49
-    #endif
50
-    { }
34
+struct MarlinSerial : public HardwareSerial {
35
+  MarlinSerial(struct usart_dev *usart_device, uint8 tx_pin, uint8 rx_pin) : HardwareSerial(usart_device, tx_pin, rx_pin) { }
51
 
36
 
52
   #ifdef UART_IRQ_PRIO
37
   #ifdef UART_IRQ_PRIO
53
     // Shadow the parent methods to set IRQ priority after begin()
38
     // Shadow the parent methods to set IRQ priority after begin()
62
   #endif
47
   #endif
63
 };
48
 };
64
 
49
 
65
-extern MarlinSerial MSerial1;
66
-extern MarlinSerial MSerial2;
67
-extern MarlinSerial MSerial3;
50
+typedef Serial0Type<MarlinSerial> MSerialT;
51
+
52
+extern MSerialT MSerial1;
53
+extern MSerialT MSerial2;
54
+extern MSerialT MSerial3;
68
 #if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY)
55
 #if EITHER(STM32_HIGH_DENSITY, STM32_XL_DENSITY)
69
-  extern MarlinSerial MSerial4;
70
-  extern MarlinSerial MSerial5;
56
+  extern MSerialT MSerial4;
57
+  extern MSerialT MSerial5;
71
 #endif
58
 #endif

+ 1
- 1
Marlin/src/HAL/STM32F1/msc_sd.cpp View File

23
 #define PRODUCT_ID 0x29
23
 #define PRODUCT_ID 0x29
24
 
24
 
25
 USBMassStorage MarlinMSC;
25
 USBMassStorage MarlinMSC;
26
-MarlinUSBCompositeSerial MarlinCompositeSerial;
26
+Serial0Type<USBCompositeSerial> MarlinCompositeSerial(true);
27
 
27
 
28
 #include "../../inc/MarlinConfig.h"
28
 #include "../../inc/MarlinConfig.h"
29
 
29
 

+ 2
- 18
Marlin/src/HAL/STM32F1/msc_sd.h View File

18
 #include <USBComposite.h>
18
 #include <USBComposite.h>
19
 
19
 
20
 #include "../../inc/MarlinConfigPre.h"
20
 #include "../../inc/MarlinConfigPre.h"
21
-#if ENABLED(EMERGENCY_PARSER)
22
-  #include "../../feature/e_parser.h"
23
-#endif
24
-
25
-class MarlinUSBCompositeSerial : public USBCompositeSerial {
26
-public:
27
-  MarlinUSBCompositeSerial() : USBCompositeSerial()
28
-    #if ENABLED(EMERGENCY_PARSER)
29
-      , emergency_state(EmergencyParser::State::EP_RESET)
30
-    #endif
31
-    { }
32
-
33
-  #if ENABLED(EMERGENCY_PARSER)
34
-    EmergencyParser::State emergency_state;
35
-    inline bool emergency_parser_enabled() { return true; }
36
-  #endif
37
-};
21
+#include "../../core/serial_hook.h"
38
 
22
 
39
 extern USBMassStorage MarlinMSC;
23
 extern USBMassStorage MarlinMSC;
40
-extern MarlinUSBCompositeSerial MarlinCompositeSerial;
24
+extern Serial0Type<USBCompositeSerial> MarlinCompositeSerial;
41
 
25
 
42
 void MSC_SD_init();
26
 void MSC_SD_init();

+ 3
- 0
Marlin/src/HAL/TEENSY31_32/HAL.cpp View File

31
 
31
 
32
 #include <Wire.h>
32
 #include <Wire.h>
33
 
33
 
34
+DefaultSerial MSerial(false);
35
+USBSerialType USBSerial(false, SerialUSB);
36
+
34
 uint16_t HAL_adc_result;
37
 uint16_t HAL_adc_result;
35
 
38
 
36
 static const uint8_t pin2sc1a[] = {
39
 static const uint8_t pin2sc1a[] = {

+ 9
- 3
Marlin/src/HAL/TEENSY31_32/HAL.h View File

50
   #define IS_TEENSY32 1
50
   #define IS_TEENSY32 1
51
 #endif
51
 #endif
52
 
52
 
53
-#define _MSERIAL(X) Serial##X
53
+#include "../../core/serial_hook.h"
54
+typedef Serial0Type<decltype(Serial)> DefaultSerial;
55
+extern DefaultSerial MSerial;
56
+typedef ForwardSerial0Type<decltype(SerialUSB)> USBSerialType;
57
+extern USBSerialType USBSerial;
58
+
59
+#define _MSERIAL(X) MSerial##X
54
 #define MSERIAL(X) _MSERIAL(X)
60
 #define MSERIAL(X) _MSERIAL(X)
55
-#define Serial0 Serial
61
+#define MSerial0 MSerial
56
 
62
 
57
 #if SERIAL_PORT == -1
63
 #if SERIAL_PORT == -1
58
-  #define MYSERIAL0 SerialUSB
64
+  #define MYSERIAL0 USBSerial
59
 #elif WITHIN(SERIAL_PORT, 0, 3)
65
 #elif WITHIN(SERIAL_PORT, 0, 3)
60
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
66
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
61
 #endif
67
 #endif

+ 3
- 0
Marlin/src/HAL/TEENSY35_36/HAL.cpp View File

31
 
31
 
32
 #include <Wire.h>
32
 #include <Wire.h>
33
 
33
 
34
+DefaultSerial MSerial(false);
35
+USBSerialType USBSerial(false, SerialUSB);
36
+
34
 uint16_t HAL_adc_result, HAL_adc_select;
37
 uint16_t HAL_adc_result, HAL_adc_select;
35
 
38
 
36
 static const uint8_t pin2sc1a[] = {
39
 static const uint8_t pin2sc1a[] = {

+ 9
- 3
Marlin/src/HAL/TEENSY35_36/HAL.h View File

53
   #define IS_TEENSY35 1
53
   #define IS_TEENSY35 1
54
 #endif
54
 #endif
55
 
55
 
56
-#define _MSERIAL(X) Serial##X
56
+#include "../../core/serial_hook.h"
57
+typedef Serial0Type<decltype(Serial)> DefaultSerial;
58
+extern DefaultSerial MSerial;
59
+typedef ForwardSerial0Type<decltype(SerialUSB)> USBSerialType;
60
+extern USBSerialType USBSerial;
61
+
62
+#define _MSERIAL(X) MSerial##X
57
 #define MSERIAL(X) _MSERIAL(X)
63
 #define MSERIAL(X) _MSERIAL(X)
58
-#define Serial0 Serial
64
+#define MSerial0 MSerial
59
 
65
 
60
 #if SERIAL_PORT == -1
66
 #if SERIAL_PORT == -1
61
-  #define MYSERIAL0 SerialUSB
67
+  #define MYSERIAL0 USBSerial
62
 #elif WITHIN(SERIAL_PORT, 0, 3)
68
 #elif WITHIN(SERIAL_PORT, 0, 3)
63
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
69
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
64
 #endif
70
 #endif

+ 3
- 0
Marlin/src/HAL/TEENSY40_41/HAL.cpp View File

32
 
32
 
33
 #include <Wire.h>
33
 #include <Wire.h>
34
 
34
 
35
+DefaultSerial MSerial(false);
36
+USBSerialType USBSerial(false, SerialUSB);
37
+
35
 uint16_t HAL_adc_result, HAL_adc_select;
38
 uint16_t HAL_adc_result, HAL_adc_select;
36
 
39
 
37
 static const uint8_t pin2sc1a[] = {
40
 static const uint8_t pin2sc1a[] = {

+ 12
- 2
Marlin/src/HAL/TEENSY40_41/HAL.h View File

37
 #include <stdint.h>
37
 #include <stdint.h>
38
 #include <util/atomic.h>
38
 #include <util/atomic.h>
39
 
39
 
40
+#if HAS_ETHERNET
41
+  #include "../../feature/ethernet.h"
42
+#endif
43
+
40
 //#define ST7920_DELAY_1 DELAY_NS(600)
44
 //#define ST7920_DELAY_1 DELAY_NS(600)
41
 //#define ST7920_DELAY_2 DELAY_NS(750)
45
 //#define ST7920_DELAY_2 DELAY_NS(750)
42
 //#define ST7920_DELAY_3 DELAY_NS(750)
46
 //#define ST7920_DELAY_3 DELAY_NS(750)
51
   #define IS_TEENSY41 1
55
   #define IS_TEENSY41 1
52
 #endif
56
 #endif
53
 
57
 
54
-#define _MSERIAL(X) Serial##X
58
+#include "../../core/serial_hook.h"
59
+typedef Serial0Type<decltype(Serial)> DefaultSerial;
60
+extern DefaultSerial MSerial;
61
+typedef ForwardSerial0Type<decltype(SerialUSB)> USBSerialType;
62
+extern USBSerialType USBSerial;
63
+
64
+#define _MSERIAL(X) MSerial##X
55
 #define MSERIAL(X) _MSERIAL(X)
65
 #define MSERIAL(X) _MSERIAL(X)
56
-#define Serial0 Serial
66
+#define MSerial0 MSerial
57
 
67
 
58
 #if SERIAL_PORT == -1
68
 #if SERIAL_PORT == -1
59
   #define MYSERIAL0 SerialUSB
69
   #define MYSERIAL0 SerialUSB

+ 2
- 2
Marlin/src/MarlinCore.cpp View File

920
 
920
 
921
   MYSERIAL0.begin(BAUDRATE);
921
   MYSERIAL0.begin(BAUDRATE);
922
   millis_t serial_connect_timeout = millis() + 1000UL;
922
   millis_t serial_connect_timeout = millis() + 1000UL;
923
-  while (!MYSERIAL0 && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
923
+  while (!MYSERIAL0.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
924
 
924
 
925
   #if HAS_MULTI_SERIAL && !HAS_ETHERNET
925
   #if HAS_MULTI_SERIAL && !HAS_ETHERNET
926
     MYSERIAL1.begin(BAUDRATE);
926
     MYSERIAL1.begin(BAUDRATE);
927
     serial_connect_timeout = millis() + 1000UL;
927
     serial_connect_timeout = millis() + 1000UL;
928
-    while (!MYSERIAL1 && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
928
+    while (!MYSERIAL1.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
929
   #endif
929
   #endif
930
   SERIAL_ECHOLNPGM("start");
930
   SERIAL_ECHOLNPGM("start");
931
 
931
 

+ 26
- 0
Marlin/src/core/macros.h View File

314
 
314
 
315
   #endif
315
   #endif
316
 
316
 
317
+  // C++11 solution that is standard compliant. <type_traits> is not available on all platform
318
+  namespace Private {
319
+    template<bool, typename _Tp = void> struct enable_if { };
320
+    template<typename _Tp>              struct enable_if<true, _Tp> { typedef _Tp type; };
321
+  }
322
+  // C++11 solution using SFINAE to detect the existance of a member in a class at compile time. 
323
+  // It creates a HasMember<Type> structure containing 'value' set to true if the member exists  
324
+  #define HAS_MEMBER_IMPL(Member) \
325
+    namespace Private { \
326
+      template <typename Type, typename Yes=char, typename No=long> struct HasMember_ ## Member { \
327
+        template <typename C> static Yes& test( decltype(&C::Member) ) ; \
328
+        template <typename C> static No& test(...); \
329
+        enum { value = sizeof(test<Type>(0)) == sizeof(Yes) }; }; \
330
+    }
331
+
332
+  // Call the method if it exists, but do nothing if it does not. The method is detected at compile time.
333
+  // If the method exists, this is inlined and does not cost anything. Else, an "empty" wrapper is created, returning a default value
334
+  #define CALL_IF_EXISTS_IMPL(Return, Method, ...) \
335
+    HAS_MEMBER_IMPL(Method) \
336
+    namespace Private { \
337
+      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...)); } \
338
+                                                      _UNUSED static                                                  Return  Call_ ## Method(...) { return __VA_ARGS__; } \
339
+    }
340
+  #define CALL_IF_EXISTS(Return, That, Method, ...) \
341
+    static_cast<Return>(Private::Call_ ## Method(That, ##__VA_ARGS__))
342
+
317
 #else
343
 #else
318
 
344
 
319
   #define MIN_2(a,b)      ((a)<(b)?(a):(b))
345
   #define MIN_2(a,b)      ((a)<(b)?(a):(b))

+ 16
- 1
Marlin/src/core/serial.cpp View File

23
 #include "serial.h"
23
 #include "serial.h"
24
 #include "../inc/MarlinConfig.h"
24
 #include "../inc/MarlinConfig.h"
25
 
25
 
26
+#if HAS_ETHERNET
27
+  #include "../feature/ethernet.h"
28
+#endif
29
+
26
 uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
30
 uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
27
 
31
 
28
 // Commonly-used strings in serial output
32
 // Commonly-used strings in serial output
34
 PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
38
 PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
35
 
39
 
36
 #if HAS_MULTI_SERIAL
40
 #if HAS_MULTI_SERIAL
37
-  serial_index_t serial_port_index = 0;
41
+  #ifdef SERIAL_CATCHALL
42
+    SerialOutputT multiSerial(MYSERIAL, SERIAL_CATCHALL);
43
+  #else
44
+    #if HAS_ETHERNET
45
+      // Runtime checking of the condition variable
46
+      ConditionalSerial<decltype(MYSERIAL1)> serialOut1(ethernet.have_telnet_client, MYSERIAL1, false); // Takes reference here
47
+    #else
48
+      // Don't pay for runtime checking a true variable, instead use the output directly
49
+      #define serialOut1 MYSERIAL1
50
+    #endif
51
+    SerialOutputT multiSerial(MYSERIAL0, serialOut1);
52
+  #endif
38
 #endif
53
 #endif
39
 
54
 
40
 void serialprintPGM(PGM_P str) {
55
 void serialprintPGM(PGM_P str) {

+ 12
- 22
Marlin/src/core/serial.h View File

22
 #pragma once
22
 #pragma once
23
 
23
 
24
 #include "../inc/MarlinConfig.h"
24
 #include "../inc/MarlinConfig.h"
25
-
26
-#if HAS_ETHERNET
27
-  #include "../feature/ethernet.h"
28
-#endif
25
+#include "serial_hook.h"
29
 
26
 
30
 // Commonly-used strings in serial output
27
 // Commonly-used strings in serial output
31
 extern const char NUL_STR[], SP_P_STR[], SP_T_STR[],
28
 extern const char NUL_STR[], SP_P_STR[], SP_T_STR[],
62
 // Serial redirection
59
 // Serial redirection
63
 //
60
 //
64
 typedef int8_t serial_index_t;
61
 typedef int8_t serial_index_t;
65
-#define SERIAL_BOTH 0x7F
66
-
62
+#define SERIAL_ALL 0x7F
67
 #if HAS_MULTI_SERIAL
63
 #if HAS_MULTI_SERIAL
68
-  extern serial_index_t serial_port_index;
69
-  #define _PORT_REDIRECT(n,p)   REMEMBER(n,serial_port_index,p)
70
-  #define _PORT_RESTORE(n)      RESTORE(n)
71
-
64
+  #define _PORT_REDIRECT(n,p)   REMEMBER(n,multiSerial.portMask,p)
65
+  #define SERIAL_ASSERT(P)      if(multiSerial.portMask!=(P)){ debugger(); }
72
   #ifdef SERIAL_CATCHALL
66
   #ifdef SERIAL_CATCHALL
73
-    #define SERIAL_OUT(WHAT, V...) (void)CAT(MYSERIAL,SERIAL_CATCHALL).WHAT(V)
67
+    typedef MultiSerial<decltype(MYSERIAL), decltype(SERIAL_CATCHALL), 0> SerialOutputT;
74
   #else
68
   #else
75
-    #define SERIAL_OUT(WHAT, V...) do{ \
76
-      const bool port2_open = TERN1(HAS_ETHERNET, ethernet.have_telnet_client); \
77
-      if ( serial_port_index == 0 || serial_port_index == SERIAL_BOTH)                (void)MYSERIAL0.WHAT(V); \
78
-      if ((serial_port_index == 1 || serial_port_index == SERIAL_BOTH) && port2_open) (void)MYSERIAL1.WHAT(V); \
79
-    }while(0)
69
+    typedef MultiSerial<decltype(MYSERIAL0), TERN(HAS_ETHERNET, ConditionalSerial<decltype(MYSERIAL1)>, decltype(MYSERIAL1)), 0>      SerialOutputT;
80
   #endif
70
   #endif
81
-
82
-  #define SERIAL_ASSERT(P)      if(serial_port_index!=(P)){ debugger(); }
71
+  extern SerialOutputT          multiSerial;
72
+  #define SERIAL_IMPL           multiSerial
83
 #else
73
 #else
84
   #define _PORT_REDIRECT(n,p)   NOOP
74
   #define _PORT_REDIRECT(n,p)   NOOP
85
-  #define _PORT_RESTORE(n)      NOOP
86
-  #define SERIAL_OUT(WHAT, V...) (void)MYSERIAL0.WHAT(V)
87
   #define SERIAL_ASSERT(P)      NOOP
75
   #define SERIAL_ASSERT(P)      NOOP
76
+  #define SERIAL_IMPL           MYSERIAL0
88
 #endif
77
 #endif
89
 
78
 
79
+#define SERIAL_OUT(WHAT, V...)  (void)SERIAL_IMPL.WHAT(V)
80
+
90
 #define PORT_REDIRECT(p)        _PORT_REDIRECT(1,p)
81
 #define PORT_REDIRECT(p)        _PORT_REDIRECT(1,p)
91
-#define PORT_RESTORE()          _PORT_RESTORE(1)
82
+#define SERIAL_PORTMASK(P)      _BV(P)
92
 
83
 
93
 #define SERIAL_ECHO(x)          SERIAL_OUT(print, x)
84
 #define SERIAL_ECHO(x)          SERIAL_OUT(print, x)
94
 #define SERIAL_ECHO_F(V...)     SERIAL_OUT(print, V)
85
 #define SERIAL_ECHO_F(V...)     SERIAL_OUT(print, V)
95
 #define SERIAL_ECHOLN(x)        SERIAL_OUT(println, x)
86
 #define SERIAL_ECHOLN(x)        SERIAL_OUT(println, x)
96
 #define SERIAL_PRINT(x,b)       SERIAL_OUT(print, x, b)
87
 #define SERIAL_PRINT(x,b)       SERIAL_OUT(print, x, b)
97
 #define SERIAL_PRINTLN(x,b)     SERIAL_OUT(println, x, b)
88
 #define SERIAL_PRINTLN(x,b)     SERIAL_OUT(println, x, b)
98
-#define SERIAL_PRINTF(V...)     SERIAL_OUT(printf, V)
99
 #define SERIAL_FLUSH()          SERIAL_OUT(flush)
89
 #define SERIAL_FLUSH()          SERIAL_OUT(flush)
100
 
90
 
101
 #ifdef ARDUINO_ARCH_STM32
91
 #ifdef ARDUINO_ARCH_STM32

+ 146
- 0
Marlin/src/core/serial_base.h View File

1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+#include "../inc/MarlinConfigPre.h"
25
+
26
+#if ENABLED(EMERGENCY_PARSER)
27
+  #include "../feature/e_parser.h"
28
+#endif
29
+
30
+#ifndef DEC
31
+  #define DEC 10
32
+  #define HEX 16
33
+  #define OCT 8
34
+  #define BIN 2
35
+#endif
36
+
37
+// flushTX is not implemented in all HAL, so use SFINAE to call the method where it is.
38
+CALL_IF_EXISTS_IMPL(void, flushTX );
39
+CALL_IF_EXISTS_IMPL(bool, connected, true);
40
+
41
+// Using Curiously Recurring Template Pattern here to avoid virtual table cost when compiling.
42
+// Since the real serial class is known at compile time, this results in compiler writing a completely
43
+// efficient code
44
+template <class Child>
45
+struct SerialBase {
46
+  #if ENABLED(EMERGENCY_PARSER)
47
+    const bool ep_enabled;
48
+    EmergencyParser::State emergency_state;
49
+    inline bool emergency_parser_enabled() { return ep_enabled; }
50
+    SerialBase(bool ep_capable) : ep_enabled(ep_capable), emergency_state(EmergencyParser::State::EP_RESET) {}
51
+  #else
52
+    SerialBase(const bool) {}
53
+  #endif
54
+
55
+  // Static dispatch methods below:
56
+  // The most important method here is where it all ends to:
57
+  size_t write(uint8_t c)           { return static_cast<Child*>(this)->write(c); }
58
+  // Called when the parser finished processing an instruction, usually build to nothing
59
+  void msgDone()                    { static_cast<Child*>(this)->msgDone(); }
60
+  // Called upon initialization
61
+  void begin(const long baudRate)   { static_cast<Child*>(this)->begin(baudRate); }
62
+  // Called upon destruction
63
+  void end()                        { static_cast<Child*>(this)->end(); }
64
+  /** Check for available data from the port
65
+      @param index  The port index, usually 0 */
66
+  bool available(uint8_t index = 0) { return static_cast<Child*>(this)->available(index); }
67
+  /** Read a value from the port
68
+      @param index  The port index, usually 0 */
69
+  int  read(uint8_t index = 0)      { return static_cast<Child*>(this)->read(index); }
70
+  // Check if the serial port is connected (usually bypassed)
71
+  bool connected()                  { return static_cast<Child*>(this)->connected(); }
72
+  // Redirect flush
73
+  void flush()                      { static_cast<Child*>(this)->flush(); }
74
+  // Not all implementation have a flushTX, so let's call them only if the child has the implementation
75
+  void flushTX()                    { CALL_IF_EXISTS(void, static_cast<Child*>(this), flushTX); }
76
+
77
+  // Glue code here
78
+  FORCE_INLINE void write(const char* str)                    { while (*str) write(*str++); }
79
+  FORCE_INLINE void write(const uint8_t* buffer, size_t size) { while (size--) write(*buffer++); }
80
+  FORCE_INLINE void print(const char* str)                    { write(str); }
81
+  FORCE_INLINE void print(char c, int base = 0)               { print((long)c, base); }
82
+  FORCE_INLINE void print(unsigned char c, int base = 0)      { print((unsigned long)c, base); }
83
+  FORCE_INLINE void print(int c, int base = DEC)              { print((long)c, base); }
84
+  FORCE_INLINE void print(unsigned int c, int base = DEC)     { print((unsigned long)c, base); }
85
+  void print(long c, int base = DEC)            { if (!base) write(c); write((const uint8_t*)"-", c < 0); printNumber(c < 0 ? -c : c, base); }
86
+  void print(unsigned long c, int base = DEC)   { printNumber(c, base); }
87
+  void print(double c, int digits = 2)          { printFloat(c, digits); }
88
+
89
+  FORCE_INLINE void println(const char s[])                  { print(s); println(); }
90
+  FORCE_INLINE void println(char c, int base = 0)            { print(c, base); println(); }
91
+  FORCE_INLINE void println(unsigned char c, int base = 0)   { print(c, base); println(); }
92
+  FORCE_INLINE void println(int c, int base = DEC)           { print(c, base); println(); }
93
+  FORCE_INLINE void println(unsigned int c, int base = DEC)  { print(c, base); println(); }
94
+  FORCE_INLINE void println(long c, int base = DEC)          { print(c, base); println(); }
95
+  FORCE_INLINE void println(unsigned long c, int base = DEC) { print(c, base); println(); }
96
+  FORCE_INLINE void println(double c, int digits = 2)        { print(c, digits); println(); }
97
+  void println()                                { write("\r\n"); }
98
+
99
+  // Print a number with the given base
100
+  void printNumber(unsigned long n, const uint8_t base) {
101
+    if (n) {
102
+      unsigned char buf[8 * sizeof(long)]; // Enough space for base 2
103
+      int8_t i = 0;
104
+      while (n) {
105
+        buf[i++] = n % base;
106
+        n /= base;
107
+      }
108
+      while (i--) write((char)(buf[i] + (buf[i] < 10 ? '0' : 'A' - 10)));
109
+    }
110
+    else write('0');
111
+  }
112
+
113
+  // Print a decimal number
114
+  void printFloat(double number, uint8_t digits) {
115
+    // Handle negative numbers
116
+    if (number < 0.0) {
117
+      write('-');
118
+      number = -number;
119
+    }
120
+
121
+    // Round correctly so that print(1.999, 2) prints as "2.00"
122
+    double rounding = 0.5;
123
+    LOOP_L_N(i, digits) rounding *= 0.1;
124
+    number += rounding;
125
+
126
+    // Extract the integer part of the number and print it
127
+    unsigned long int_part = (unsigned long)number;
128
+    double remainder = number - (double)int_part;
129
+    printNumber(int_part, 10);
130
+
131
+    // Print the decimal point, but only if there are digits beyond
132
+    if (digits) {
133
+      write('.');
134
+      // Extract digits from the remainder one at a time
135
+      while (digits--) {
136
+        remainder *= 10.0;
137
+        int toPrint = int(remainder);
138
+        printNumber(toPrint, 10);
139
+        remainder -= toPrint;
140
+      }
141
+    }
142
+  }
143
+};
144
+
145
+// All serial instances will be built by chaining the features required for the function in a form of a template
146
+// type definition

+ 230
- 0
Marlin/src/core/serial_hook.h View File

1
+/**
2
+ * Marlin 3D Printer Firmware
3
+ * Copyright (c) 2020 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
4
+ *
5
+ * Based on Sprinter and grbl.
6
+ * Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
7
+ *
8
+ * This program is free software: you can redistribute it and/or modify
9
+ * it under the terms of the GNU General Public License as published by
10
+ * the Free Software Foundation, either version 3 of the License, or
11
+ * (at your option) any later version.
12
+ *
13
+ * This program is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
+ * GNU General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU General Public License
19
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20
+ *
21
+ */
22
+#pragma once
23
+
24
+#include "serial_base.h"
25
+
26
+// 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
27
+template <class SerialT>
28
+struct BaseSerial : public SerialBase< BaseSerial<SerialT> >, public SerialT {
29
+  typedef SerialBase< BaseSerial<SerialT> > BaseClassT;
30
+
31
+  // It's required to implement a write method here to help compiler disambiguate what method to call
32
+  using SerialT::write;
33
+  using SerialT::flush;
34
+
35
+  void msgDone() {}
36
+
37
+  bool available(uint8_t index) { return index == 0 && SerialT::available(); }
38
+  int read(uint8_t index)       { return index == 0 ? SerialT::read() : -1; }
39
+  bool connected()              { return CALL_IF_EXISTS(bool, static_cast<SerialT*>(this), connected);; }
40
+  // We have 2 implementation of the same method in both base class, let's say which one we want
41
+  using SerialT::available;
42
+  using SerialT::read;
43
+  using SerialT::begin;
44
+  using SerialT::end;
45
+
46
+  using BaseClassT::print;
47
+  using BaseClassT::println;
48
+
49
+  BaseSerial(const bool e) : BaseClassT(e) {}
50
+
51
+  // Forward constructor
52
+  template <typename... Args>
53
+  BaseSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...) {}
54
+};
55
+
56
+// A serial with a condition checked at runtime for its output
57
+// A bit less efficient than static dispatching but since it's only used for ethernet's serial output right now, it's ok.
58
+template <class SerialT>
59
+struct ConditionalSerial : public SerialBase< ConditionalSerial<SerialT> > {
60
+  typedef SerialBase< ConditionalSerial<SerialT> > BaseClassT;
61
+
62
+  bool    & condition;
63
+  SerialT & out;
64
+  size_t write(uint8_t c) { if (condition) return out.write(c); return 0; }
65
+  void flush()            { if (condition) out.flush();  }
66
+  void begin(long br)     { out.begin(br); }
67
+  void end()              { out.end(); }
68
+
69
+  void msgDone() {}
70
+  bool connected()              { return CALL_IF_EXISTS(bool, &out, connected); }
71
+
72
+  bool available(uint8_t index) { return index == 0 && out.available(); }
73
+  int read(uint8_t index)       { return index == 0 ? out.read() : -1; }
74
+  using BaseClassT::available;
75
+  using BaseClassT::read;
76
+
77
+  ConditionalSerial(bool & conditionVariable, SerialT & out, const bool e) : BaseClassT(e), condition(conditionVariable), out(out) {}
78
+};
79
+
80
+// A simple foward class that taking a reference to an existing serial instance (likely created in their respective framework)
81
+template <class SerialT>
82
+struct ForwardSerial : public SerialBase< ForwardSerial<SerialT> > {
83
+  typedef SerialBase< ForwardSerial<SerialT> > BaseClassT;
84
+
85
+  SerialT & out;
86
+  size_t write(uint8_t c) { return out.write(c); }
87
+  void flush()            { out.flush();  }
88
+  void begin(long br)     { out.begin(br); }
89
+  void end()              { out.end(); }
90
+
91
+  void msgDone() {}
92
+  // Existing instances implement Arduino's operator bool, so use that if it's available
93
+  bool connected()              { return Private::HasMember_connected<SerialT>::value ? CALL_IF_EXISTS(bool, &out, connected) : (bool)out; }
94
+
95
+  bool available(uint8_t index) { return index == 0 && out.available(); }
96
+  int read(uint8_t index)       { return index == 0 ? out.read() : -1; }
97
+  bool available()              { return out.available(); }
98
+  int read()                    { return out.read(); }
99
+
100
+  ForwardSerial(const bool e, SerialT & out) : BaseClassT(e), out(out) {}
101
+};
102
+
103
+// A class that's can be hooked and unhooked at runtime, useful to capturing the output of the serial interface
104
+template <class SerialT>
105
+struct RuntimeSerial : public SerialBase< RuntimeSerial<SerialT> >, public SerialT {
106
+  typedef SerialBase< RuntimeSerial<SerialT> > BaseClassT;
107
+  typedef void (*WriteHook)(void * userPointer, uint8_t c);
108
+  typedef void (*EndOfMessageHook)(void * userPointer);
109
+
110
+  WriteHook        writeHook;
111
+  EndOfMessageHook eofHook;
112
+  void *           userPointer;
113
+
114
+  size_t write(uint8_t c) {
115
+    if (writeHook) writeHook(userPointer, c);
116
+    return SerialT::write(c);
117
+  }
118
+
119
+  void msgDone() {
120
+    if (eofHook) eofHook(userPointer);
121
+  }
122
+
123
+  bool available(uint8_t index) { return index == 0 && SerialT::available(); }
124
+  int read(uint8_t index)       { return index == 0 ? SerialT::read() : -1; }
125
+  using SerialT::available;
126
+  using SerialT::read;
127
+  using SerialT::flush;
128
+  using SerialT::begin;
129
+  using SerialT::end;
130
+
131
+  using BaseClassT::print;
132
+  using BaseClassT::println;
133
+  
134
+
135
+  void setHook(WriteHook writeHook = 0, EndOfMessageHook eofHook = 0, void * userPointer = 0) {
136
+    // Order is important here as serial code can be called inside interrupts
137
+    // 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
138
+    if (userPointer) this->userPointer = userPointer;
139
+    this->writeHook = writeHook;
140
+    this->eofHook = eofHook;
141
+    // Order is important here because of asynchronous access here
142
+    // When unsetting a hook, the user pointer must be unset last so that any pending writeHook is still using the old pointer
143
+    if (!userPointer) this->userPointer = 0;
144
+  }
145
+
146
+  RuntimeSerial(const bool e) : BaseClassT(e), writeHook(0), eofHook(0), userPointer(0) {}
147
+
148
+  // Forward constructor
149
+  template <typename... Args>
150
+  RuntimeSerial(const bool e, Args... args) : BaseClassT(e), SerialT(args...) {}
151
+};
152
+
153
+// A class that's duplicating its output conditionally to 2 serial interface
154
+template <class Serial0T, class Serial1T, const uint8_t offset = 0>
155
+struct MultiSerial : public SerialBase< MultiSerial<Serial0T, Serial1T, offset> > {
156
+  typedef SerialBase< MultiSerial<Serial0T, Serial1T, offset> > BaseClassT;
157
+
158
+  uint8_t    portMask;
159
+  Serial0T & serial0;
160
+  Serial1T & serial1;
161
+
162
+  enum Masks {
163
+    FirstOutputMask   =  (1 << offset),
164
+    SecondOutputMask  =  (1 << (offset + 1)),
165
+    AllMask           = FirstOutputMask | SecondOutputMask,
166
+  };
167
+
168
+  size_t write(uint8_t c) {
169
+    size_t ret = 0;
170
+    if (portMask & FirstOutputMask)   ret = serial0.write(c);
171
+    if (portMask & SecondOutputMask)  ret = serial1.write(c) | ret;
172
+    return ret;
173
+  }
174
+  void msgDone() {
175
+    if (portMask & FirstOutputMask)   serial0.msgDone();
176
+    if (portMask & SecondOutputMask)  serial1.msgDone();
177
+  }
178
+  bool available(uint8_t index) {
179
+    switch(index) {
180
+      case 0 + offset: return serial0.available();
181
+      case 1 + offset: return serial1.available();
182
+      default: return false;
183
+    }
184
+  }
185
+  int read(uint8_t index) {
186
+    switch(index) {
187
+      case 0 + offset: return serial0.read();
188
+      case 1 + offset: return serial1.read();
189
+      default: return -1;
190
+    }
191
+  }
192
+  void begin(const long br) {
193
+    if (portMask & FirstOutputMask)   serial0.begin(br);
194
+    if (portMask & SecondOutputMask)  serial1.begin(br);
195
+  }
196
+  void end() {
197
+    if (portMask & FirstOutputMask)   serial0.end();
198
+    if (portMask & SecondOutputMask)  serial1.end();
199
+  }
200
+  bool connected() {
201
+    bool ret = true;
202
+    if (portMask & FirstOutputMask)   ret = CALL_IF_EXISTS(bool, &serial0, connected);
203
+    if (portMask & SecondOutputMask)  ret = ret && CALL_IF_EXISTS(bool, &serial1, connected);
204
+    return ret;
205
+  }
206
+
207
+  using BaseClassT::available;
208
+  using BaseClassT::read;
209
+
210
+  // Redirect flush
211
+  void flush()      {
212
+    if (portMask & FirstOutputMask)   serial0.flush();
213
+    if (portMask & SecondOutputMask)  serial1.flush();
214
+  }
215
+  void flushTX()    {
216
+    if (portMask & FirstOutputMask)   CALL_IF_EXISTS(void, &serial0, flushTX);
217
+    if (portMask & SecondOutputMask)  CALL_IF_EXISTS(void, &serial1, flushTX);
218
+  }
219
+
220
+  MultiSerial(Serial0T & serial0, Serial1T & serial1, int8_t mask = AllMask, const bool e = false) :
221
+    BaseClassT(e),
222
+    portMask(mask), serial0(serial0), serial1(serial1) {}
223
+};
224
+
225
+// Build the actual serial object depending on current configuration
226
+#define Serial0Type TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, BaseSerial)
227
+#define ForwardSerial0Type TERN(SERIAL_RUNTIME_HOOK, RuntimeSerial, ForwardSerial)
228
+#ifdef HAS_MULTI_SERIAL
229
+  #define Serial1Type ConditionalSerial
230
+#endif

+ 3
- 15
Marlin/src/feature/binary_stream.h View File

30
 #endif
30
 #endif
31
 
31
 
32
 inline bool bs_serial_data_available(const uint8_t index) {
32
 inline bool bs_serial_data_available(const uint8_t index) {
33
-  switch (index) {
34
-    case 0: return MYSERIAL0.available();
35
-    #if HAS_MULTI_SERIAL
36
-      case 1: return MYSERIAL1.available();
37
-    #endif
38
-  }
39
-  return false;
33
+  return SERIAL_IMPL.available(index);
40
 }
34
 }
41
 
35
 
42
 inline int bs_read_serial(const uint8_t index) {
36
 inline int bs_read_serial(const uint8_t index) {
43
-  switch (index) {
44
-    case 0: return MYSERIAL0.read();
45
-    #if HAS_MULTI_SERIAL
46
-      case 1: return MYSERIAL1.read();
47
-    #endif
48
-  }
49
-  return -1;
37
+  return SERIAL_IMPL.read(index);
50
 }
38
 }
51
 
39
 
52
 #if ENABLED(BINARY_STREAM_COMPRESSION)
40
 #if ENABLED(BINARY_STREAM_COMPRESSION)
297
     millis_t transfer_window = millis() + RX_TIMESLICE;
285
     millis_t transfer_window = millis() + RX_TIMESLICE;
298
 
286
 
299
     #if ENABLED(SDSUPPORT)
287
     #if ENABLED(SDSUPPORT)
300
-      PORT_REDIRECT(card.transfer_port_index);
288
+      PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index));
301
     #endif
289
     #endif
302
 
290
 
303
     #pragma GCC diagnostic push
291
     #pragma GCC diagnostic push

+ 5
- 5
Marlin/src/feature/host_actions.cpp View File

38
 #endif
38
 #endif
39
 
39
 
40
 void host_action(PGM_P const pstr, const bool eol) {
40
 void host_action(PGM_P const pstr, const bool eol) {
41
-  PORT_REDIRECT(SERIAL_BOTH);
41
+  PORT_REDIRECT(SERIAL_ALL);
42
   SERIAL_ECHOPGM("//action:");
42
   SERIAL_ECHOPGM("//action:");
43
   serialprintPGM(pstr);
43
   serialprintPGM(pstr);
44
   if (eol) SERIAL_EOL();
44
   if (eol) SERIAL_EOL();
78
   PromptReason host_prompt_reason = PROMPT_NOT_DEFINED;
78
   PromptReason host_prompt_reason = PROMPT_NOT_DEFINED;
79
 
79
 
80
   void host_action_notify(const char * const message) {
80
   void host_action_notify(const char * const message) {
81
-    PORT_REDIRECT(SERIAL_BOTH);
81
+    PORT_REDIRECT(SERIAL_ALL);
82
     host_action(PSTR("notification "), false);
82
     host_action(PSTR("notification "), false);
83
     SERIAL_ECHOLN(message);
83
     SERIAL_ECHOLN(message);
84
   }
84
   }
85
 
85
 
86
   void host_action_notify_P(PGM_P const message) {
86
   void host_action_notify_P(PGM_P const message) {
87
-    PORT_REDIRECT(SERIAL_BOTH);
87
+    PORT_REDIRECT(SERIAL_ALL);
88
     host_action(PSTR("notification "), false);
88
     host_action(PSTR("notification "), false);
89
     serialprintPGM(message);
89
     serialprintPGM(message);
90
     SERIAL_EOL();
90
     SERIAL_EOL();
91
   }
91
   }
92
 
92
 
93
   void host_action_prompt(PGM_P const ptype, const bool eol=true) {
93
   void host_action_prompt(PGM_P const ptype, const bool eol=true) {
94
-    PORT_REDIRECT(SERIAL_BOTH);
94
+    PORT_REDIRECT(SERIAL_ALL);
95
     host_action(PSTR("prompt_"), false);
95
     host_action(PSTR("prompt_"), false);
96
     serialprintPGM(ptype);
96
     serialprintPGM(ptype);
97
     if (eol) SERIAL_EOL();
97
     if (eol) SERIAL_EOL();
99
 
99
 
100
   void host_action_prompt_plus(PGM_P const ptype, PGM_P const pstr, const char extra_char='\0') {
100
   void host_action_prompt_plus(PGM_P const ptype, PGM_P const pstr, const char extra_char='\0') {
101
     host_action_prompt(ptype, false);
101
     host_action_prompt(ptype, false);
102
-    PORT_REDIRECT(SERIAL_BOTH);
102
+    PORT_REDIRECT(SERIAL_ALL);
103
     SERIAL_CHAR(' ');
103
     SERIAL_CHAR(' ');
104
     serialprintPGM(pstr);
104
     serialprintPGM(pstr);
105
     if (extra_char != '\0') SERIAL_CHAR(extra_char);
105
     if (extra_char != '\0') SERIAL_CHAR(extra_char);

+ 2
- 1
Marlin/src/gcode/feature/network/M552-M554.cpp View File

47
     Ethernet.MACAddress(mac);
47
     Ethernet.MACAddress(mac);
48
     SERIAL_ECHOPGM("  MAC: ");
48
     SERIAL_ECHOPGM("  MAC: ");
49
     LOOP_L_N(i, 6) {
49
     LOOP_L_N(i, 6) {
50
-      SERIAL_PRINTF("%02X", mac[i]);
50
+      if (mac[i] < 16) SERIAL_CHAR('0');
51
+      SERIAL_PRINT(mac[i], HEX);
51
       if (i < 5) SERIAL_CHAR(':');
52
       if (i < 5) SERIAL_CHAR(':');
52
     }
53
     }
53
   }
54
   }

+ 3
- 1
Marlin/src/gcode/gcode.cpp View File

986
   }
986
   }
987
 
987
 
988
   if (!no_ok) queue.ok_to_send();
988
   if (!no_ok) queue.ok_to_send();
989
+
990
+  SERIAL_OUT(msgDone); // Call the msgDone serial hook to signal command processing done
989
 }
991
 }
990
 
992
 
991
 /**
993
 /**
995
 void GcodeSuite::process_next_command() {
997
 void GcodeSuite::process_next_command() {
996
   char * const current_command = queue.command_buffer[queue.index_r];
998
   char * const current_command = queue.command_buffer[queue.index_r];
997
 
999
 
998
-  PORT_REDIRECT(queue.port[queue.index_r]);
1000
+  PORT_REDIRECT(SERIAL_PORTMASK(queue.port[queue.index_r]));
999
 
1001
 
1000
   #if ENABLED(POWER_LOSS_RECOVERY)
1002
   #if ENABLED(POWER_LOSS_RECOVERY)
1001
     recovery.queue_index_r = queue.index_r;
1003
     recovery.queue_index_r = queue.index_r;

+ 3
- 10
Marlin/src/gcode/host/M118.cpp View File

53
   }
53
   }
54
 
54
 
55
   #if HAS_MULTI_SERIAL
55
   #if HAS_MULTI_SERIAL
56
-    const serial_index_t old_serial = serial_port_index;
56
+    const int8_t old_serial = multiSerial.portMask;
57
     if (WITHIN(port, 0, NUM_SERIAL))
57
     if (WITHIN(port, 0, NUM_SERIAL))
58
-      serial_port_index = (
59
-        port == 0 ? SERIAL_BOTH
60
-        : port == 1 ? 0
61
-        #if HAS_MULTI_SERIAL
62
-          : port == 2 ? 1
63
-        #endif
64
-        : SERIAL_PORT
65
-      );
58
+      multiSerial.portMask = port ? _BV(port - 1) : SERIAL_ALL;
66
   #endif
59
   #endif
67
 
60
 
68
   if (hasE) SERIAL_ECHO_START();
61
   if (hasE) SERIAL_ECHO_START();
69
   if (hasA) SERIAL_ECHOPGM("//");
62
   if (hasA) SERIAL_ECHOPGM("//");
70
   SERIAL_ECHOLN(p);
63
   SERIAL_ECHOLN(p);
71
 
64
 
72
-  TERN_(HAS_MULTI_SERIAL, serial_port_index = old_serial);
65
+  TERN_(HAS_MULTI_SERIAL, multiSerial.portMask = old_serial);
73
 }
66
 }

+ 6
- 6
Marlin/src/gcode/queue.cpp View File

290
 void GCodeQueue::ok_to_send() {
290
 void GCodeQueue::ok_to_send() {
291
   #if HAS_MULTI_SERIAL
291
   #if HAS_MULTI_SERIAL
292
     const serial_index_t serial_ind = command_port();
292
     const serial_index_t serial_ind = command_port();
293
-    if (serial_ind < 0) return;                   // Never mind. Command came from SD or Flash Drive
294
-    PORT_REDIRECT(serial_ind);                    // Reply to the serial port that sent the command
293
+    if (serial_ind < 0) return;
294
+    PORT_REDIRECT(SERIAL_PORTMASK(serial_ind));   // Reply to the serial port that sent the command
295
   #endif
295
   #endif
296
   if (!send_ok[index_r]) return;
296
   if (!send_ok[index_r]) return;
297
   SERIAL_ECHOPGM(STR_OK);
297
   SERIAL_ECHOPGM(STR_OK);
317
   const serial_index_t serial_ind = command_port();
317
   const serial_index_t serial_ind = command_port();
318
   #if HAS_MULTI_SERIAL
318
   #if HAS_MULTI_SERIAL
319
     if (serial_ind < 0) return;                   // Never mind. Command came from SD or Flash Drive
319
     if (serial_ind < 0) return;                   // Never mind. Command came from SD or Flash Drive
320
-    PORT_REDIRECT(serial_ind);                    // Reply to the serial port that sent the command
320
+    PORT_REDIRECT(SERIAL_PORTMASK(serial_ind));   // Reply to the serial port that sent the command
321
   #endif
321
   #endif
322
   SERIAL_FLUSH();
322
   SERIAL_FLUSH();
323
   SERIAL_ECHOPGM(STR_RESEND);
323
   SERIAL_ECHOPGM(STR_RESEND);
349
 }
349
 }
350
 
350
 
351
 void GCodeQueue::gcode_line_error(PGM_P const err, const serial_index_t serial_ind) {
351
 void GCodeQueue::gcode_line_error(PGM_P const err, const serial_index_t serial_ind) {
352
-  PORT_REDIRECT(serial_ind);                      // Reply to the serial port that sent the command
352
+  PORT_REDIRECT(SERIAL_PORTMASK(serial_ind)); // Reply to the serial port that sent the command
353
   SERIAL_ERROR_START();
353
   SERIAL_ERROR_START();
354
   serialprintPGM(err);
354
   serialprintPGM(err);
355
   SERIAL_ECHOLN(last_N[serial_ind]);
355
   SERIAL_ECHOLN(last_N[serial_ind]);
356
-  while (read_serial(serial_ind) != -1);          // Clear out the RX buffer
356
+  while (read_serial(serial_ind) != -1);      // Clear out the RX buffer
357
   flush_and_request_resend();
357
   flush_and_request_resend();
358
   serial_count[serial_ind] = 0;
358
   serial_count[serial_ind] = 0;
359
 }
359
 }
547
                 #if ENABLED(BEZIER_CURVE_SUPPORT)
547
                 #if ENABLED(BEZIER_CURVE_SUPPORT)
548
                   case 5:
548
                   case 5:
549
                 #endif
549
                 #endif
550
-                  PORT_REDIRECT(p);                      // Reply to the serial port that sent the command
550
+                  PORT_REDIRECT(SERIAL_PORTMASK(p));     // Reply to the serial port that sent the command
551
                   SERIAL_ECHOLNPGM(STR_ERR_STOPPED);
551
                   SERIAL_ECHOLNPGM(STR_ERR_STOPPED);
552
                   LCD_MESSAGEPGM(MSG_STOPPED);
552
                   LCD_MESSAGEPGM(MSG_STOPPED);
553
                   break;
553
                   break;

+ 1
- 1
Marlin/src/gcode/sd/M1001.cpp View File

82
 
82
 
83
   // Announce SD file completion
83
   // Announce SD file completion
84
   {
84
   {
85
-    PORT_REDIRECT(SERIAL_BOTH);
85
+    PORT_REDIRECT(SERIAL_ALL);
86
     SERIAL_ECHOLNPGM(STR_FILE_PRINTED);
86
     SERIAL_ECHOLNPGM(STR_FILE_PRINTED);
87
   }
87
   }
88
 
88
 

+ 1
- 0
Marlin/src/inc/Conditionals_LCD.h View File

320
 // FSMC/SPI TFT Panels (LVGL)
320
 // FSMC/SPI TFT Panels (LVGL)
321
 #if ENABLED(TFT_LVGL_UI)
321
 #if ENABLED(TFT_LVGL_UI)
322
   #define HAS_TFT_LVGL_UI 1
322
   #define HAS_TFT_LVGL_UI 1
323
+  #define SERIAL_RUNTIME_HOOK 1
323
 #endif
324
 #endif
324
 
325
 
325
 // FSMC/SPI TFT Panels
326
 // FSMC/SPI TFT Panels

+ 2
- 2
Marlin/src/lcd/extui/malyan_lcd.cpp View File

414
   // This is mildly different than stock, which
414
   // This is mildly different than stock, which
415
   // appears to use the usb discovery status.
415
   // appears to use the usb discovery status.
416
   // This is more logical.
416
   // This is more logical.
417
-  if (last_usb_connected_status != MYSERIAL0 || forceUpdate) {
418
-    last_usb_connected_status = MYSERIAL0;
417
+  if (last_usb_connected_status != MYSERIAL0.connected() || forceUpdate) {
418
+    last_usb_connected_status = MYSERIAL0.connected();
419
     write_to_lcd_P(last_usb_connected_status ? PSTR("{R:UC}\r\n") : PSTR("{R:UD}\r\n"));
419
     write_to_lcd_P(last_usb_connected_status ? PSTR("{R:UC}\r\n") : PSTR("{R:UD}\r\n"));
420
   }
420
   }
421
 }
421
 }

+ 2
- 2
Marlin/src/module/temperature.cpp View File

253
      */
253
      */
254
     void Temperature::report_fan_speed(const uint8_t target) {
254
     void Temperature::report_fan_speed(const uint8_t target) {
255
       if (target >= FAN_COUNT) return;
255
       if (target >= FAN_COUNT) return;
256
-      PORT_REDIRECT(SERIAL_BOTH);
256
+      PORT_REDIRECT(SERIAL_ALL);
257
       SERIAL_ECHOLNPAIR("M106 P", target, " S", fan_speed[target]);
257
       SERIAL_ECHOLNPAIR("M106 P", target, " S", fan_speed[target]);
258
     }
258
     }
259
   #endif
259
   #endif
3130
     void Temperature::auto_report_temperatures() {
3130
     void Temperature::auto_report_temperatures() {
3131
       if (auto_report_temp_interval && ELAPSED(millis(), next_temp_report_ms)) {
3131
       if (auto_report_temp_interval && ELAPSED(millis(), next_temp_report_ms)) {
3132
         next_temp_report_ms = millis() + 1000UL * auto_report_temp_interval;
3132
         next_temp_report_ms = millis() + 1000UL * auto_report_temp_interval;
3133
-        PORT_REDIRECT(SERIAL_BOTH);
3133
+        PORT_REDIRECT(SERIAL_ALL);
3134
         print_heater_states(active_extruder);
3134
         print_heater_states(active_extruder);
3135
         SERIAL_EOL();
3135
         SERIAL_EOL();
3136
       }
3136
       }

+ 6
- 6
Marlin/src/sd/cardreader.cpp View File

550
 
550
 
551
 void announceOpen(const uint8_t doing, const char * const path) {
551
 void announceOpen(const uint8_t doing, const char * const path) {
552
   if (doing) {
552
   if (doing) {
553
-    PORT_REDIRECT(SERIAL_BOTH);
553
+    PORT_REDIRECT(SERIAL_ALL);
554
     SERIAL_ECHO_START();
554
     SERIAL_ECHO_START();
555
     SERIAL_ECHOPGM("Now ");
555
     SERIAL_ECHOPGM("Now ");
556
     serialprintPGM(doing == 1 ? PSTR("doing") : PSTR("fresh"));
556
     serialprintPGM(doing == 1 ? PSTR("doing") : PSTR("fresh"));
557
     SERIAL_ECHOLNPAIR(" file: ", path);
557
     SERIAL_ECHOLNPAIR(" file: ", path);
558
-    PORT_RESTORE();
559
   }
558
   }
560
 }
559
 }
561
 
560
 
617
     filesize = file.fileSize();
616
     filesize = file.fileSize();
618
     sdpos = 0;
617
     sdpos = 0;
619
 
618
 
620
-    PORT_REDIRECT(SERIAL_BOTH);
621
-    SERIAL_ECHOLNPAIR(STR_SD_FILE_OPENED, fname, STR_SD_SIZE, filesize);
622
-    SERIAL_ECHOLNPGM(STR_SD_FILE_SELECTED);
623
-    PORT_RESTORE();
619
+    { // Don't remove this block, as the PORT_REDIRECT is a RAII
620
+      PORT_REDIRECT(SERIAL_ALL);
621
+      SERIAL_ECHOLNPAIR(STR_SD_FILE_OPENED, fname, STR_SD_SIZE, filesize);
622
+      SERIAL_ECHOLNPGM(STR_SD_FILE_SELECTED);
623
+    }
624
 
624
 
625
     selectFileByName(fname);
625
     selectFileByName(fname);
626
     ui.set_status(longFilename[0] ? longFilename : fname);
626
     ui.set_status(longFilename[0] ? longFilename : fname);

+ 1
- 1
Marlin/src/sd/cardreader.h View File

174
   #if ENABLED(AUTO_REPORT_SD_STATUS)
174
   #if ENABLED(AUTO_REPORT_SD_STATUS)
175
     static void auto_report_sd_status();
175
     static void auto_report_sd_status();
176
     static inline void set_auto_report_interval(uint8_t v) {
176
     static inline void set_auto_report_interval(uint8_t v) {
177
-      TERN_(HAS_MULTI_SERIAL, auto_report_port = serial_port_index);
177
+      TERN_(HAS_MULTI_SERIAL, auto_report_port = serialHook.portMask);
178
       NOMORE(v, 60);
178
       NOMORE(v, 60);
179
       auto_report_sd_interval = v;
179
       auto_report_sd_interval = v;
180
       next_sd_report_ms = millis() + 1000UL * v;
180
       next_sd_report_ms = millis() + 1000UL * v;

+ 1
- 1
buildroot/tests/run_tests View File

20
   if [[ -z "$VERBOSE_PLATFORMIO" ]] ; then
20
   if [[ -z "$VERBOSE_PLATFORMIO" ]] ; then
21
     silent="--silent"
21
     silent="--silent"
22
   else
22
   else
23
-    silent=""
23
+    silent="-v"
24
   fi
24
   fi
25
   if platformio run --project-dir $1 -e $2 $silent; then
25
   if platformio run --project-dir $1 -e $2 $silent; then
26
     printf "\033[0;32mPassed\033[0m\n"
26
     printf "\033[0;32mPassed\033[0m\n"

+ 44
- 0
docs/Serial.md View File

1
+# Serial port architecture in Marlin
2
+
3
+Marlin is targeting a pletora of different CPU architecture and platforms. Each of these platforms has its own serial interface.
4
+While many provide a Arduino-like Serial class, it's not all of them, and the differences in the existing API create a very complex brain teaser for writing code that works more or less on each platform.
5
+
6
+Moreover, many platform have intrinsic needs about serial port (like forwarding the output on multiple serial port, providing a *serial-like* telnet server, mixing USB-based serial port with SD card emulation) that are difficult to handle cleanly in the other platform serial logic.
7
+
8
+
9
+Starting with version `2.0.9`, Marlin provides a common interface for its serial needs.
10
+
11
+## Common interface
12
+
13
+This interface is declared in `Marlin/src/core/serial_base.h` 
14
+Any implementation will need to follow this interface for being used transparently in Marlin's codebase.
15
+
16
+The implementation was written to prioritize performance over abstraction, so the base interface is not using virtual inheritance to avoid the cost of virtual dispatching while calling methods.
17
+Instead, the Curiously Recurring Template Pattern (**CRTP**) is used so that, upon compilation, the interface abstraction does not incur a performance cost.
18
+
19
+Because some platform do not follow the same interface, the missing method in the actual low-level implementation are detected via SFINAE and a wrapper is generated when such method are missing. See `CALL_IF_EXISTS` macro in `Marlin/src/core/macros.h` for the documentation of this technic.  
20
+
21
+## Composing the desired feature
22
+The different specificities for each architecture are provided by composing the serial type based on desired functionality.
23
+In the `Marlin/src/core/serial_hook.h` file, the different serial feature are declared and defined in each templated type:
24
+1. `BaseSerial` is a simple 1:1 wrapper to the underlying, Arduino compatible, `Serial`'s class. It derives from it. You'll use this if the platform does not do anything specific for the `Serial` object (for example, if an interrupt callback calls directly the serial **instance** in the platform's framework code, this is not the right class to use). This wrapper is completely inlined so that it does not generate any code upon compilation. `BaseSerial` constructor forwards any parameter to the platform's `Serial`'s constructor.
25
+2. `ForwardSerial` is a composing wrapper. It references an actual Arduino compatible `Serial` instance. You'll use this if the instance is declared in the platform's framework and is being referred directly in the framework. This is not as efficient as the `BaseSerial` implementation since static dereferencing is done for each method call (it'll still be faster than virtual dispatching)
26
+3. `ConditionalSerial` is working a bit like the `ForwardSerial` interface, but it checks a boolean condition before calling the referenced instance. You'll use it when the serial output can be switch off at runtime, for example in a *telnet* like serial output that should not emit any packet if no client is connected.
27
+4. `RuntimeSerial` is providing a runtime-modifiable hooking method for its `write` and `msgDone` method. You'll use it if you need to capture the serial output of Marlin, for example to display the G-Code parser's output on a GUI interface. The hooking interface is setup via the `setHook` method.
28
+5. `MultiSerial` is a runtime modifiable serial output multiplexer. It can output (*respectively input*) to 2 different interface based on a port *mask*. You'll use this if you need to output the same serial stream to multiple port. You can plug a `MultiSerial` to itself to duplicate to more than 2 ports. 
29
+
30
+## Plumbing
31
+Since all the types above are using CRTP, it's possible to combine them to get the appropriate functionality. 
32
+This is easily done via type definition of the feature. 
33
+
34
+For example, to present a serial interface that's outputting to 2 serial port, the first one being hooked at runtime and the second one connected to a runtime switchable telnet client, you'll declare the type to use as:
35
+```
36
+typedef MultiSerial< RuntimeSerial<Serial>, ConditionalSerial<TelnetClient> > Serial0Type;
37
+```
38
+
39
+## Emergency parser
40
+By default, the serial base interface provide an emergency parser that's only enable for serial classes that support it. 
41
+Because of this condition, all underlying type takes a first `bool emergencyParserEnabled` argument to their constructor. You must take into account this parameter when defining the actual type used. 
42
+
43
+
44
+*This document was written by [X-Ryl669](https://blog.cyril.by) and is under [CC-SA license](https://creativecommons.org/licenses/by-sa)*

Loading…
Cancel
Save