Przeglądaj źródła

Refactor serial class with templates (#20783)

X-Ryl669 3 lat temu
rodzic
commit
3f01b222b2
No account linked to committer's email address
64 zmienionych plików z 784 dodań i 950 usunięć
  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 Wyświetl plik

@@ -24,6 +24,13 @@
24 24
 #include "../../inc/MarlinConfig.h"
25 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 35
 // Public Variables
29 36
 // ------------------------

+ 9
- 1
Marlin/src/HAL/AVR/HAL.h Wyświetl plik

@@ -82,7 +82,15 @@ typedef int8_t pin_t;
82 82
 
83 83
 // Serial ports
84 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 94
 #else
87 95
   #if !WITHIN(SERIAL_PORT, -1, 3)
88 96
     #error "SERIAL_PORT must be from -1 to 3. Please update your configuration."

+ 14
- 181
Marlin/src/HAL/AVR/MarlinSerial.cpp Wyświetl plik

@@ -454,7 +454,7 @@ void MarlinSerial<Cfg>::flush() {
454 454
 }
455 455
 
456 456
 template<typename Cfg>
457
-void MarlinSerial<Cfg>::write(const uint8_t c) {
457
+size_t MarlinSerial<Cfg>::write(const uint8_t c) {
458 458
   if (Cfg::TX_SIZE == 0) {
459 459
 
460 460
     _written = true;
@@ -480,7 +480,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
480 480
       // location". This makes sure flush() won't return until the bytes
481 481
       // actually got written
482 482
       B_TXC = 1;
483
-      return;
483
+      return 1;
484 484
     }
485 485
 
486 486
     const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
@@ -510,6 +510,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
510 510
     // Enable TX ISR - Non atomic, but it will eventually enable TX ISR
511 511
     B_UDRIE = 1;
512 512
   }
513
+  return 1;
513 514
 }
514 515
 
515 516
 template<typename Cfg>
@@ -556,161 +557,6 @@ void MarlinSerial<Cfg>::flushTX() {
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 560
 // Hookup ISR handlers
715 561
 ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _RX_vect)) {
716 562
   MarlinSerial<MarlinSerialCfg<SERIAL_PORT>>::store_rxd_char();
@@ -720,11 +566,9 @@ ISR(SERIAL_REGNAME(USART, SERIAL_PORT, _UDRE_vect)) {
720 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 573
 #ifdef SERIAL_PORT_2
730 574
 
@@ -737,12 +581,8 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
737 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 586
 #endif
747 587
 
748 588
 #ifdef MMU2_SERIAL_PORT
@@ -755,12 +595,8 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
755 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 600
 #endif
765 601
 
766 602
 #ifdef LCD_SERIAL_PORT
@@ -773,12 +609,9 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
773 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 615
   #if HAS_DGUS_LCD
783 616
     template<typename Cfg>
784 617
     typename MarlinSerial<Cfg>::ring_buffer_pos_t MarlinSerial<Cfg>::get_tx_buffer_free() {
@@ -796,7 +629,7 @@ MarlinSerial<MarlinSerialCfg<SERIAL_PORT>> customizedSerial1;
796 629
 
797 630
 // For AT90USB targets use the UART for BT interfacing
798 631
 #if defined(USBCON) && ENABLED(BLUETOOTH)
799
-  HardwareSerial bluetoothSerial;
632
+  MSerialT5 bluetoothSerial(false);
800 633
 #endif
801 634
 
802 635
 #endif // __AVR__

+ 33
- 62
Marlin/src/HAL/AVR/MarlinSerial.h Wyświetl plik

@@ -34,6 +34,7 @@
34 34
 #include <WString.h>
35 35
 
36 36
 #include "../../inc/MarlinConfigPre.h"
37
+#include "../../core/serial_hook.h"
37 38
 
38 39
 #ifndef SERIAL_PORT
39 40
   #define SERIAL_PORT 0
@@ -135,10 +136,6 @@
135 136
     UART_DECL(3);
136 137
   #endif
137 138
 
138
-  #define DEC 10
139
-  #define HEX 16
140
-  #define OCT 8
141
-  #define BIN 2
142 139
   #define BYTE 0
143 140
 
144 141
   // Templated type selector
@@ -202,60 +199,30 @@
202 199
     static FORCE_INLINE void atomic_set_rx_tail(ring_buffer_pos_t value);
203 200
     static FORCE_INLINE ring_buffer_pos_t atomic_read_rx_tail();
204 201
 
205
-    public:
206
-
202
+  public:
207 203
     FORCE_INLINE static void store_rxd_char();
208 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 228
   template <uint8_t serial>
@@ -270,12 +237,13 @@
270 237
     static constexpr bool RX_FRAMING_ERRORS = ENABLED(SERIAL_STATS_RX_FRAMING_ERRORS);
271 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 247
   #endif
280 248
 
281 249
 #endif // !USBCON
@@ -294,7 +262,8 @@
294 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 267
 #endif
299 268
 
300 269
 #ifdef LCD_SERIAL_PORT
@@ -322,11 +291,13 @@
322 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 297
 #endif
328 298
 
329 299
 // Use the UART for Bluetooth in AT90USB configurations
330 300
 #if defined(USBCON) && ENABLED(BLUETOOTH)
331
-  extern HardwareSerial bluetoothSerial;
301
+  typedef Serial0Type<HardwareSerial> MSerialT5;
302
+  extern MSerialT5 bluetoothSerial;
332 303
 #endif

+ 7
- 0
Marlin/src/HAL/DUE/HAL.cpp Wyświetl plik

@@ -102,4 +102,11 @@ uint16_t HAL_adc_get_result() {
102 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 112
 #endif // ARDUINO_ARCH_SAM

+ 13
- 2
Marlin/src/HAL/DUE/HAL.h Wyświetl plik

@@ -36,9 +36,20 @@
36 36
 
37 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 51
 #define MSERIAL(X) _MSERIAL(X)
41
-#define Serial0 Serial
52
+#define MSerial0 MSerial
42 53
 
43 54
 // Define MYSERIAL0/1 before MarlinSerial includes!
44 55
 #if SERIAL_PORT == -1 || ENABLED(EMERGENCY_PARSER)

+ 7
- 159
Marlin/src/HAL/DUE/MarlinSerial.cpp Wyświetl plik

@@ -382,7 +382,7 @@ void MarlinSerial<Cfg>::flush() {
382 382
 }
383 383
 
384 384
 template<typename Cfg>
385
-void MarlinSerial<Cfg>::write(const uint8_t c) {
385
+size_t MarlinSerial<Cfg>::write(const uint8_t c) {
386 386
   _written = true;
387 387
 
388 388
   if (Cfg::TX_SIZE == 0) {
@@ -400,7 +400,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
400 400
     // XOFF char at the RX isr, but it is properly handled there
401 401
     if (!(HWUART->UART_IMR & UART_IMR_TXRDY) && (HWUART->UART_SR & UART_SR_TXRDY)) {
402 402
       HWUART->UART_THR = c;
403
-      return;
403
+      return 1;
404 404
     }
405 405
 
406 406
     const uint8_t i = (tx_buffer.head + 1) & (Cfg::TX_SIZE - 1);
@@ -428,6 +428,7 @@ void MarlinSerial<Cfg>::write(const uint8_t c) {
428 428
     // Enable TX isr - Non atomic, but it will eventually enable TX isr
429 429
     HWUART->UART_IER = UART_IER_TXRDY;
430 430
   }
431
+  return 1;
431 432
 }
432 433
 
433 434
 template<typename Cfg>
@@ -473,169 +474,16 @@ void MarlinSerial<Cfg>::flushTX() {
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 478
 // If not using the USB port as serial port
631 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 482
 #endif
635 483
 
636 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 487
 #endif
640 488
 
641 489
 #endif // ARDUINO_ARCH_SAM

+ 6
- 37
Marlin/src/HAL/DUE/MarlinSerial.h Wyświetl plik

@@ -30,11 +30,7 @@
30 30
 #include <WString.h>
31 31
 
32 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 35
 // Define constants and variables for buffering incoming serial data.  We're
40 36
 // using a ring buffer (I think), in which rx_buffer_head is the index of the
@@ -119,7 +115,7 @@ public:
119 115
   static int read();
120 116
   static void flush();
121 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 119
   static void flushTX();
124 120
 
125 121
   static inline bool emergency_parser_enabled() { return Cfg::EMERGENCYPARSER; }
@@ -128,35 +124,6 @@ public:
128 124
   FORCE_INLINE static uint8_t buffer_overruns() { return Cfg::RX_OVERRUNS ? rx_buffer_overruns : 0; }
129 125
   FORCE_INLINE static uint8_t framing_errors() { return Cfg::RX_FRAMING_ERRORS ? rx_framing_errors : 0; }
130 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 129
 // Serial port configuration
@@ -174,9 +141,11 @@ struct MarlinSerialCfg {
174 141
 };
175 142
 
176 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 146
 #endif
179 147
 
180 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 151
 #endif

+ 6
- 151
Marlin/src/HAL/DUE/MarlinSerialUSB.cpp Wyświetl plik

@@ -50,10 +50,6 @@ extern "C" {
50 50
 // Pending character
51 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 53
 // Public Methods
58 54
 void MarlinSerialUSB::begin(const long) {}
59 55
 
@@ -111,13 +107,13 @@ bool MarlinSerialUSB::available() {
111 107
 void MarlinSerialUSB::flush() { }
112 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 112
   /* Do not even bother sending anything if USB CDC is not enumerated
117 113
      or not configured on the PC side or there is no program on the PC
118 114
      listening to our messages */
119 115
   if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
120
-    return;
116
+    return 0;
121 117
 
122 118
   /* Wait until the PC has read the pending to be sent data */
123 119
   while (usb_task_cdc_isenabled() &&
@@ -129,161 +125,20 @@ void MarlinSerialUSB::write(const uint8_t c) {
129 125
      or not configured on the PC side or there is no program on the PC
130 126
      listening to our messages at this point */
131 127
   if (!usb_task_cdc_isenabled() || !usb_task_cdc_dtr_active())
132
-    return;
128
+    return 0;
133 129
 
134 130
   // Fifo full
135 131
   //  udi_cdc_signal_overrun();
136 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 136
 // Preinstantiate
282 137
 #if SERIAL_PORT == -1
283
-  MarlinSerialUSB customizedSerial1;
138
+  MSerialT customizedSerial1(TERN0(EMERGENCY_PARSER, true));
284 139
 #endif
285 140
 #if SERIAL_PORT_2 == -1
286
-  MarlinSerialUSB customizedSerial2;
141
+  MSerialT customizedSerial2(TERN0(EMERGENCY_PARSER, true));
287 142
 #endif
288 143
 
289 144
 #endif // HAS_USB_SERIAL

+ 6
- 41
Marlin/src/HAL/DUE/MarlinSerialUSB.h Wyświetl plik

@@ -27,20 +27,13 @@
27 27
  */
28 28
 
29 29
 #include "../../inc/MarlinConfig.h"
30
-
31 30
 #if HAS_USB_SERIAL
32 31
 
33 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 37
   static void begin(const long);
45 38
   static void end();
46 39
   static int peek();
@@ -48,7 +41,7 @@ public:
48 41
   static void flush();
49 42
   static void flushTX();
50 43
   static bool available();
51
-  static void write(const uint8_t c);
44
+  static size_t write(const uint8_t c);
52 45
 
53 46
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
54 47
     FORCE_INLINE static uint32_t dropped() { return 0; }
@@ -57,43 +50,15 @@ public:
57 50
   #if ENABLED(SERIAL_STATS_MAX_RX_QUEUED)
58 51
     FORCE_INLINE static int rxMaxEnqueued() { return 0; }
59 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 56
 #if SERIAL_PORT == -1
92
-  extern MarlinSerialUSB customizedSerial1;
57
+  extern MSerialT customizedSerial1;
93 58
 #endif
94 59
 
95 60
 #if SERIAL_PORT_2 == -1
96
-  extern MarlinSerialUSB customizedSerial2;
61
+  extern MSerialT customizedSerial2;
97 62
 #endif
98 63
 
99 64
 #endif // HAS_USB_SERIAL

+ 2
- 2
Marlin/src/HAL/DUE/usb/sd_mmc_spi_mem.cpp Wyświetl plik

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

+ 1
- 4
Marlin/src/HAL/ESP32/FlushableHardwareSerial.cpp Wyświetl plik

@@ -24,10 +24,7 @@
24 24
 
25 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 30
 #endif // ARDUINO_ARCH_ESP32

+ 3
- 4
Marlin/src/HAL/ESP32/FlushableHardwareSerial.h Wyświetl plik

@@ -24,14 +24,13 @@
24 24
 #ifdef ARDUINO_ARCH_ESP32
25 25
 
26 26
 #include <HardwareSerial.h>
27
+#include "../../core/serial_hook.h"
27 28
 
28 29
 class FlushableHardwareSerial : public HardwareSerial {
29 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 36
 #endif // ARDUINO_ARCH_ESP32

+ 4
- 0
Marlin/src/HAL/ESP32/HAL.cpp Wyświetl plik

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

+ 3
- 1
Marlin/src/HAL/ESP32/HAL.h Wyświetl plik

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

+ 1
- 5
Marlin/src/HAL/ESP32/WebSocketSerial.cpp Wyświetl plik

@@ -29,7 +29,7 @@
29 29
 #include "wifi.h"
30 30
 #include <ESPAsyncWebServer.h>
31 31
 
32
-WebSocketSerial webSocketSerial;
32
+MSerialT webSocketSerial(false);
33 33
 AsyncWebSocket ws("/ws"); // TODO Move inside the class.
34 34
 
35 35
 // RingBuffer impl
@@ -144,9 +144,5 @@ size_t WebSocketSerial::write(const uint8_t* buffer, size_t size) {
144 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 147
 #endif // WIFISUPPORT
152 148
 #endif // ARDUINO_ARCH_ESP32

+ 3
- 4
Marlin/src/HAL/ESP32/WebSocketSerial.h Wyświetl plik

@@ -22,6 +22,7 @@
22 22
 #pragma once
23 23
 
24 24
 #include "../../inc/MarlinConfig.h"
25
+#include "../../core/serial_hook.h"
25 26
 
26 27
 #include <Stream.h>
27 28
 
@@ -68,12 +69,9 @@ public:
68 69
   int peek();
69 70
   int read();
70 71
   void flush();
71
-  void flushTX();
72 72
   size_t write(const uint8_t c);
73 73
   size_t write(const uint8_t* buffer, size_t size);
74 74
 
75
-  operator bool() { return true; }
76
-
77 75
   #if ENABLED(SERIAL_STATS_DROPPED_RX)
78 76
     FORCE_INLINE uint32_t dropped() { return 0; }
79 77
   #endif
@@ -83,4 +81,5 @@ public:
83 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 Wyświetl plik

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

+ 1
- 1
Marlin/src/HAL/LINUX/HAL.h Wyświetl plik

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

+ 6
- 96
Marlin/src/HAL/LINUX/include/serial.h Wyświetl plik

@@ -25,6 +25,7 @@
25 25
 #if ENABLED(EMERGENCY_PARSER)
26 26
   #include "../../../feature/e_parser.h"
27 27
 #endif
28
+#include "../../../core/serial_hook.h"
28 29
 
29 30
 #include <stdarg.h>
30 31
 #include <stdio.h>
@@ -73,19 +74,11 @@ private:
73 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 78
   HalSerial() { host_connected = true; }
85 79
 
86 80
   void begin(int32_t) {}
87
-
88
-  void end() {}
81
+  void end()          {}
89 82
 
90 83
   int peek() {
91 84
     uint8_t value;
@@ -100,7 +93,7 @@ public:
100 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 98
   uint16_t available() {
106 99
     return (uint16_t)receive_buffer.available();
@@ -117,92 +110,9 @@ public:
117 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 113
   volatile RingBuffer<uint8_t, 128> receive_buffer;
206 114
   volatile RingBuffer<uint8_t, 128> transmit_buffer;
207 115
   volatile bool host_connected;
208 116
 };
117
+
118
+typedef Serial0Type<HalSerial> MSerialT;

+ 2
- 0
Marlin/src/HAL/LPC1768/HAL.cpp Wyświetl plik

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

+ 7
- 4
Marlin/src/HAL/LPC1768/HAL.h Wyświetl plik

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

+ 4
- 4
Marlin/src/HAL/LPC1768/MarlinSerial.cpp Wyświetl plik

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

+ 8
- 14
Marlin/src/HAL/LPC1768/MarlinSerial.h Wyświetl plik

@@ -28,6 +28,7 @@
28 28
 #if ENABLED(EMERGENCY_PARSER)
29 29
   #include "../../feature/e_parser.h"
30 30
 #endif
31
+#include "../../core/serial_hook.h"
31 32
 
32 33
 #ifndef SERIAL_PORT
33 34
   #define SERIAL_PORT 0
@@ -41,27 +42,20 @@
41 42
 
42 43
 class MarlinSerial : public HardwareSerial<RX_BUFFER_SIZE, TX_BUFFER_SIZE> {
43 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 47
   void end() {}
52 48
 
53 49
   #if ENABLED(EMERGENCY_PARSER)
54 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 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 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 Wyświetl plik

@@ -24,6 +24,11 @@
24 24
 #include <Adafruit_ZeroDMA.h>
25 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 33
 // Local defines
29 34
 // ------------------------

+ 9
- 5
Marlin/src/HAL/SAMD51/HAL.h Wyświetl plik

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

+ 3
- 3
Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.cpp Wyświetl plik

@@ -28,7 +28,7 @@
28 28
 #include "../../inc/MarlinConfig.h"
29 29
 
30 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 32
   void SERCOM4_0_Handler() { Serial2.IrqHandler(); }
33 33
   void SERCOM4_1_Handler() { Serial2.IrqHandler(); }
34 34
   void SERCOM4_2_Handler() { Serial2.IrqHandler(); }
@@ -36,7 +36,7 @@
36 36
 #endif
37 37
 
38 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 40
   void SERCOM1_0_Handler() { Serial3.IrqHandler(); }
41 41
   void SERCOM1_1_Handler() { Serial3.IrqHandler(); }
42 42
   void SERCOM1_2_Handler() { Serial3.IrqHandler(); }
@@ -44,7 +44,7 @@
44 44
 #endif
45 45
 
46 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 48
   void SERCOM5_0_Handler() { Serial4.IrqHandler(); }
49 49
   void SERCOM5_1_Handler() { Serial4.IrqHandler(); }
50 50
   void SERCOM5_2_Handler() { Serial4.IrqHandler(); }

+ 7
- 3
Marlin/src/HAL/SAMD51/MarlinSerial_AGCM4.h Wyświetl plik

@@ -20,6 +20,10 @@
20 20
  */
21 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 Wyświetl plik

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

+ 7
- 4
Marlin/src/HAL/STM32/HAL.h Wyświetl plik

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

+ 1
- 1
Marlin/src/HAL/STM32/MarlinSerial.cpp Wyświetl plik

@@ -35,7 +35,7 @@
35 35
 
36 36
 #define DECLARE_SERIAL_PORT(ser_num) \
37 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 39
   void _rx_complete_irq_ ## ser_num (serial_t * obj) { MSerial ## ser_num ._rx_complete_irq(obj); }
40 40
 
41 41
 #define DECLARE_SERIAL_PORT_EXP(ser_num) DECLARE_SERIAL_PORT(ser_num)

+ 15
- 23
Marlin/src/HAL/STM32/MarlinSerial.h Wyświetl plik

@@ -24,21 +24,15 @@
24 24
   #include "../../feature/e_parser.h"
25 25
 #endif
26 26
 
27
+#include "../../core/serial_hook.h"
28
+
27 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 32
   MarlinSerial(void* peripheral, usart_rx_callback_t rx_callback) :
32 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 36
   void begin(unsigned long baud, uint8_t config);
43 37
   inline void begin(unsigned long baud) { begin(baud, SERIAL_8N1); }
44 38
 
@@ -46,19 +40,17 @@ public:
46 40
 
47 41
 protected:
48 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 Wyświetl plik

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

+ 4
- 1
Marlin/src/HAL/STM32F1/HAL.h Wyświetl plik

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

+ 10
- 10
Marlin/src/HAL/STM32F1/MarlinSerial.cpp Wyświetl plik

@@ -28,7 +28,7 @@
28 28
 
29 29
 // Copied from ~/.platformio/packages/framework-arduinoststm32-maple/STM32F1/system/libmaple/usart_private.h
30 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 32
  /* Handle RXNEIE and TXEIE interrupts.
33 33
   * RXNE signifies availability of a byte in DR.
34 34
   *
@@ -90,20 +90,20 @@ constexpr bool serial_handles_emergency(int port) {
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 99
     my_usart_irq(USART##n->rb, USART##n->wb, USART##n##_BASE, MSerial##n); \
100 100
   }
101 101
 
102 102
 #define DEFINE_HWSERIAL_UART_MARLIN(name, n) \
103
-  MarlinSerial name(UART##n,                 \
103
+  MSerialT name(serial_handles_emergency(n), \
104
+          UART##n,                           \
104 105
           BOARD_USART##n##_TX_PIN,           \
105
-          BOARD_USART##n##_RX_PIN,           \
106
-          serial_handles_emergency(n));      \
106
+          BOARD_USART##n##_RX_PIN);          \
107 107
   extern "C" void __irq_usart##n(void) {     \
108 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 Wyświetl plik

@@ -26,28 +26,13 @@
26 26
 #include <WString.h>
27 27
 
28 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 31
 // Increase priority of serial interrupts, to reduce overflow errors
34 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 37
   #ifdef UART_IRQ_PRIO
53 38
     // Shadow the parent methods to set IRQ priority after begin()
@@ -62,10 +47,12 @@ public:
62 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 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 58
 #endif

+ 1
- 1
Marlin/src/HAL/STM32F1/msc_sd.cpp Wyświetl plik

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

+ 2
- 18
Marlin/src/HAL/STM32F1/msc_sd.h Wyświetl plik

@@ -18,25 +18,9 @@
18 18
 #include <USBComposite.h>
19 19
 
20 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 23
 extern USBMassStorage MarlinMSC;
40
-extern MarlinUSBCompositeSerial MarlinCompositeSerial;
24
+extern Serial0Type<USBCompositeSerial> MarlinCompositeSerial;
41 25
 
42 26
 void MSC_SD_init();

+ 3
- 0
Marlin/src/HAL/TEENSY31_32/HAL.cpp Wyświetl plik

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

+ 9
- 3
Marlin/src/HAL/TEENSY31_32/HAL.h Wyświetl plik

@@ -50,12 +50,18 @@
50 50
   #define IS_TEENSY32 1
51 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 60
 #define MSERIAL(X) _MSERIAL(X)
55
-#define Serial0 Serial
61
+#define MSerial0 MSerial
56 62
 
57 63
 #if SERIAL_PORT == -1
58
-  #define MYSERIAL0 SerialUSB
64
+  #define MYSERIAL0 USBSerial
59 65
 #elif WITHIN(SERIAL_PORT, 0, 3)
60 66
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
61 67
 #endif

+ 3
- 0
Marlin/src/HAL/TEENSY35_36/HAL.cpp Wyświetl plik

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

+ 9
- 3
Marlin/src/HAL/TEENSY35_36/HAL.h Wyświetl plik

@@ -53,12 +53,18 @@
53 53
   #define IS_TEENSY35 1
54 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 63
 #define MSERIAL(X) _MSERIAL(X)
58
-#define Serial0 Serial
64
+#define MSerial0 MSerial
59 65
 
60 66
 #if SERIAL_PORT == -1
61
-  #define MYSERIAL0 SerialUSB
67
+  #define MYSERIAL0 USBSerial
62 68
 #elif WITHIN(SERIAL_PORT, 0, 3)
63 69
   #define MYSERIAL0 MSERIAL(SERIAL_PORT)
64 70
 #endif

+ 3
- 0
Marlin/src/HAL/TEENSY40_41/HAL.cpp Wyświetl plik

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

+ 12
- 2
Marlin/src/HAL/TEENSY40_41/HAL.h Wyświetl plik

@@ -37,6 +37,10 @@
37 37
 #include <stdint.h>
38 38
 #include <util/atomic.h>
39 39
 
40
+#if HAS_ETHERNET
41
+  #include "../../feature/ethernet.h"
42
+#endif
43
+
40 44
 //#define ST7920_DELAY_1 DELAY_NS(600)
41 45
 //#define ST7920_DELAY_2 DELAY_NS(750)
42 46
 //#define ST7920_DELAY_3 DELAY_NS(750)
@@ -51,9 +55,15 @@
51 55
   #define IS_TEENSY41 1
52 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 65
 #define MSERIAL(X) _MSERIAL(X)
56
-#define Serial0 Serial
66
+#define MSerial0 MSerial
57 67
 
58 68
 #if SERIAL_PORT == -1
59 69
   #define MYSERIAL0 SerialUSB

+ 2
- 2
Marlin/src/MarlinCore.cpp Wyświetl plik

@@ -920,12 +920,12 @@ void setup() {
920 920
 
921 921
   MYSERIAL0.begin(BAUDRATE);
922 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 925
   #if HAS_MULTI_SERIAL && !HAS_ETHERNET
926 926
     MYSERIAL1.begin(BAUDRATE);
927 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 929
   #endif
930 930
   SERIAL_ECHOLNPGM("start");
931 931
 

+ 26
- 0
Marlin/src/core/macros.h Wyświetl plik

@@ -314,6 +314,32 @@
314 314
 
315 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 343
 #else
318 344
 
319 345
   #define MIN_2(a,b)      ((a)<(b)?(a):(b))

+ 16
- 1
Marlin/src/core/serial.cpp Wyświetl plik

@@ -23,6 +23,10 @@
23 23
 #include "serial.h"
24 24
 #include "../inc/MarlinConfig.h"
25 25
 
26
+#if HAS_ETHERNET
27
+  #include "../feature/ethernet.h"
28
+#endif
29
+
26 30
 uint8_t marlin_debug_flags = MARLIN_DEBUG_NONE;
27 31
 
28 32
 // Commonly-used strings in serial output
@@ -34,7 +38,18 @@ PGMSTR(SP_X_STR, " X");  PGMSTR(SP_Y_STR, " Y");  PGMSTR(SP_Z_STR, " Z");  PGMST
34 38
 PGMSTR(SP_X_LBL, " X:"); PGMSTR(SP_Y_LBL, " Y:"); PGMSTR(SP_Z_LBL, " Z:"); PGMSTR(SP_E_LBL, " E:");
35 39
 
36 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 53
 #endif
39 54
 
40 55
 void serialprintPGM(PGM_P str) {

+ 12
- 22
Marlin/src/core/serial.h Wyświetl plik

@@ -22,10 +22,7 @@
22 22
 #pragma once
23 23
 
24 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 27
 // Commonly-used strings in serial output
31 28
 extern const char NUL_STR[], SP_P_STR[], SP_T_STR[],
@@ -62,40 +59,33 @@ extern uint8_t marlin_debug_flags;
62 59
 // Serial redirection
63 60
 //
64 61
 typedef int8_t serial_index_t;
65
-#define SERIAL_BOTH 0x7F
66
-
62
+#define SERIAL_ALL 0x7F
67 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 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 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 70
   #endif
81
-
82
-  #define SERIAL_ASSERT(P)      if(serial_port_index!=(P)){ debugger(); }
71
+  extern SerialOutputT          multiSerial;
72
+  #define SERIAL_IMPL           multiSerial
83 73
 #else
84 74
   #define _PORT_REDIRECT(n,p)   NOOP
85
-  #define _PORT_RESTORE(n)      NOOP
86
-  #define SERIAL_OUT(WHAT, V...) (void)MYSERIAL0.WHAT(V)
87 75
   #define SERIAL_ASSERT(P)      NOOP
76
+  #define SERIAL_IMPL           MYSERIAL0
88 77
 #endif
89 78
 
79
+#define SERIAL_OUT(WHAT, V...)  (void)SERIAL_IMPL.WHAT(V)
80
+
90 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 84
 #define SERIAL_ECHO(x)          SERIAL_OUT(print, x)
94 85
 #define SERIAL_ECHO_F(V...)     SERIAL_OUT(print, V)
95 86
 #define SERIAL_ECHOLN(x)        SERIAL_OUT(println, x)
96 87
 #define SERIAL_PRINT(x,b)       SERIAL_OUT(print, x, b)
97 88
 #define SERIAL_PRINTLN(x,b)     SERIAL_OUT(println, x, b)
98
-#define SERIAL_PRINTF(V...)     SERIAL_OUT(printf, V)
99 89
 #define SERIAL_FLUSH()          SERIAL_OUT(flush)
100 90
 
101 91
 #ifdef ARDUINO_ARCH_STM32

+ 146
- 0
Marlin/src/core/serial_base.h Wyświetl plik

@@ -0,0 +1,146 @@
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 Wyświetl plik

@@ -0,0 +1,230 @@
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 Wyświetl plik

@@ -30,23 +30,11 @@
30 30
 #endif
31 31
 
32 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 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 40
 #if ENABLED(BINARY_STREAM_COMPRESSION)
@@ -297,7 +285,7 @@ public:
297 285
     millis_t transfer_window = millis() + RX_TIMESLICE;
298 286
 
299 287
     #if ENABLED(SDSUPPORT)
300
-      PORT_REDIRECT(card.transfer_port_index);
288
+      PORT_REDIRECT(SERIAL_PORTMASK(card.transfer_port_index));
301 289
     #endif
302 290
 
303 291
     #pragma GCC diagnostic push

+ 5
- 5
Marlin/src/feature/host_actions.cpp Wyświetl plik

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

+ 2
- 1
Marlin/src/gcode/feature/network/M552-M554.cpp Wyświetl plik

@@ -47,7 +47,8 @@ void MAC_report() {
47 47
     Ethernet.MACAddress(mac);
48 48
     SERIAL_ECHOPGM("  MAC: ");
49 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 52
       if (i < 5) SERIAL_CHAR(':');
52 53
     }
53 54
   }

+ 3
- 1
Marlin/src/gcode/gcode.cpp Wyświetl plik

@@ -986,6 +986,8 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
986 986
   }
987 987
 
988 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,7 +997,7 @@ void GcodeSuite::process_parsed_command(const bool no_ok/*=false*/) {
995 997
 void GcodeSuite::process_next_command() {
996 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 1002
   #if ENABLED(POWER_LOSS_RECOVERY)
1001 1003
     recovery.queue_index_r = queue.index_r;

+ 3
- 10
Marlin/src/gcode/host/M118.cpp Wyświetl plik

@@ -53,21 +53,14 @@ void GcodeSuite::M118() {
53 53
   }
54 54
 
55 55
   #if HAS_MULTI_SERIAL
56
-    const serial_index_t old_serial = serial_port_index;
56
+    const int8_t old_serial = multiSerial.portMask;
57 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 59
   #endif
67 60
 
68 61
   if (hasE) SERIAL_ECHO_START();
69 62
   if (hasA) SERIAL_ECHOPGM("//");
70 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 Wyświetl plik

@@ -290,8 +290,8 @@ void GCodeQueue::enqueue_now_P(PGM_P const pgcode) {
290 290
 void GCodeQueue::ok_to_send() {
291 291
   #if HAS_MULTI_SERIAL
292 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 295
   #endif
296 296
   if (!send_ok[index_r]) return;
297 297
   SERIAL_ECHOPGM(STR_OK);
@@ -317,7 +317,7 @@ void GCodeQueue::flush_and_request_resend() {
317 317
   const serial_index_t serial_ind = command_port();
318 318
   #if HAS_MULTI_SERIAL
319 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 321
   #endif
322 322
   SERIAL_FLUSH();
323 323
   SERIAL_ECHOPGM(STR_RESEND);
@@ -349,11 +349,11 @@ inline int read_serial(const uint8_t index) {
349 349
 }
350 350
 
351 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 353
   SERIAL_ERROR_START();
354 354
   serialprintPGM(err);
355 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 357
   flush_and_request_resend();
358 358
   serial_count[serial_ind] = 0;
359 359
 }
@@ -547,7 +547,7 @@ void GCodeQueue::get_serial_commands() {
547 547
                 #if ENABLED(BEZIER_CURVE_SUPPORT)
548 548
                   case 5:
549 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 551
                   SERIAL_ECHOLNPGM(STR_ERR_STOPPED);
552 552
                   LCD_MESSAGEPGM(MSG_STOPPED);
553 553
                   break;

+ 1
- 1
Marlin/src/gcode/sd/M1001.cpp Wyświetl plik

@@ -82,7 +82,7 @@ void GcodeSuite::M1001() {
82 82
 
83 83
   // Announce SD file completion
84 84
   {
85
-    PORT_REDIRECT(SERIAL_BOTH);
85
+    PORT_REDIRECT(SERIAL_ALL);
86 86
     SERIAL_ECHOLNPGM(STR_FILE_PRINTED);
87 87
   }
88 88
 

+ 1
- 0
Marlin/src/inc/Conditionals_LCD.h Wyświetl plik

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

+ 2
- 2
Marlin/src/lcd/extui/malyan_lcd.cpp Wyświetl plik

@@ -414,8 +414,8 @@ void update_usb_status(const bool forceUpdate) {
414 414
   // This is mildly different than stock, which
415 415
   // appears to use the usb discovery status.
416 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 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 Wyświetl plik

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

+ 6
- 6
Marlin/src/sd/cardreader.cpp Wyświetl plik

@@ -550,12 +550,11 @@ void openFailed(const char * const fname) {
550 550
 
551 551
 void announceOpen(const uint8_t doing, const char * const path) {
552 552
   if (doing) {
553
-    PORT_REDIRECT(SERIAL_BOTH);
553
+    PORT_REDIRECT(SERIAL_ALL);
554 554
     SERIAL_ECHO_START();
555 555
     SERIAL_ECHOPGM("Now ");
556 556
     serialprintPGM(doing == 1 ? PSTR("doing") : PSTR("fresh"));
557 557
     SERIAL_ECHOLNPAIR(" file: ", path);
558
-    PORT_RESTORE();
559 558
   }
560 559
 }
561 560
 
@@ -617,10 +616,11 @@ void CardReader::openFileRead(char * const path, const uint8_t subcall_type/*=0*
617 616
     filesize = file.fileSize();
618 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 625
     selectFileByName(fname);
626 626
     ui.set_status(longFilename[0] ? longFilename : fname);

+ 1
- 1
Marlin/src/sd/cardreader.h Wyświetl plik

@@ -174,7 +174,7 @@ public:
174 174
   #if ENABLED(AUTO_REPORT_SD_STATUS)
175 175
     static void auto_report_sd_status();
176 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 178
       NOMORE(v, 60);
179 179
       auto_report_sd_interval = v;
180 180
       next_sd_report_ms = millis() + 1000UL * v;

+ 1
- 1
buildroot/tests/run_tests Wyświetl plik

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

+ 44
- 0
docs/Serial.md Wyświetl plik

@@ -0,0 +1,44 @@
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)*

Ładowanie…
Anuluj
Zapisz